/* moiam .. program to compute internal rotation structural parameters */ #include #include #include #include "calpgm.h" #define NFT 21 #define CINC 12 #define C0 '\0' static double zero = 0.; static double rad, pi2; static char card[82]; int ftran(int nft, double *xpec, int pec, double *fc, int flg); static int rdinp(FILE * luin, int ndatm, int *nnatm, int *nx, double *wtx, double *dist, double *theta, double *phi, char *istau, char **xyztag); static int coords( /*@null@*/ FILE * lu, int noatm, double *coord, double *wt, int *nx, double *dist, double *theta, double *phi); static int gcalc(int natm, double *wt, double *coord, double *dcoord, /*@null@*/ double *gval, double *cval); static double determ(double *a, int ndd, int nr, int nc); static int iamsolv(double *cval, double *fc); static int pamsolv(int natm, double *x, double *gval, double *cval); static int micvt(double *tval, double *gval, double vmuz, double vmuy, int flg); static double xinterp(int n, double *tauval, double *xtrans); /*---------------------------------------------------------------------------- input file: name.inp first line => nstruct, angram, mu_top, mu_z, mu_y nstruct= number of structures vs tau nstruct= -2 means two structures, non-cyclic vibration angram = angle to rotate from IAS to RIAS (degrees) mu_top = dipole moment of top perpendicular to z mu_z = dipole moment parallel to z mu_y = dipole moment of frame perpendicular to z (where z is defined by the first two atoms and y is perpendicular to z in the plane of the third atom) second line => values of tau for structures for each of nstruct structures set of structure parameter lines blank line end for NSYM,MAXM,MAXV,NFT (parameters for first line of name.iam) n,Vn if NSYM <0 then ityp=17,18 parameters included if NSYM =0 then PAM found, rather than IAM, ityp=17,18,19 included structure parameter lines: cwt, n,na,nb,nc,dist,theta,phi,istau OR 'X', wt n,na,nb,nc,dist,theta,phi,istau cwt(up to 4 characters) => symbol for mass (C,O,C13,..) n= atom number (if atom number is in sequence, distances are calculated from dist, theta, phi, otherwise dist, theta, phi calculated from structure) na,nb,nc atoms defining refernce axes abs(dist) is length from atom n to atom na if (dist >0) then theta is the n-na-nb angle and phi is the dihedral angle from the na-nb-nc plane if (dist <0) then angles are defined from the nb-na-nc angle bisector theta is the n-na-bisector angle phi is the angle between the bisector and the projection of n-na into the na-nb-nc plane istau ne 0 if phi is linear in tau else if istau = 0 phi is assumed to br fourier series in tau NOTE: for best results the first three atoms should define the plane of symmetry of the trans state output file: name.iam first line => rho, NSYM,MAXM,MAXV other lines => ityp, nf, nm, value nf = coefficient in Fourier series in tau (negative for sin, positive for cosine) ityp, nm= 99,0 for V delta K=0 99,2 for F delta K=0 1099,0 for A - (B+C)/2 delta K=0 199,0 for (B+C)/2 delta K=0 40099,0 for (B-C)/4 delta K=2 210099,0 for D_bc delta K=2 410099,0 for D_ac delta K=1 610099,0 for D_ab delta K=1 1,0 for mu_a (top) delta K=0 2,0 for mu_b (top) delta K=1 3,0 for mu_c (top) delta K=1 200099,1 for Pa delta K=0 400099,1 for Pb (RAM) delta K=1 600099,1 for Pc (PAM) delta K=1 NOTE: frame z is the axis of the first two atoms, and the yz plane is the plane of the first three atoms ----------------------------------------------------------------------------*/ int main(argc, argv) int argc; char *argv[]; { #define NFILE 4 #define NDATM 50 #define ND3ATM (3 * NDATM) #define NDCON 20 static struct spar { int idv; char *labl; } sparv[] = { { 99, "Vp"}, { 99, "F"}, { 1099, "A-(B+C)/2"}, { 199, "(B+C)/2"}, { 40099, "(B-C)/4"}, { 210099, "D_bc"}, { 410099, "D_ac"}, { 610099, "D_ab"}, { 1, "mu_a(top)"}, { 2, "mu_b(top)"}, { 3, "mu_c(top)"}, { 1, "mu_a(z)"}, { 2, "mu_b(z)"}, { 3, "mu_c(z)"}, { 1, "mu_a(y)"}, { 2, "mu_b(y)"}, { 3, "mu_c(y)"}, { 200099, "P_a"}, { 400099, "P_b"}, { 600099, "P_c"}}; static const char *cext[NFILE] = { "inp", "iam", "moi", "xyz" }; enum efile {einp, eiam, emoi, exyz}; static char *cfil[NFILE+1]; static char fmtv[3] = "V0"; static double gder[2 * NFT], cval[CINC * NFT], gval[NDCON * NFT], tauval[NFT]; static double xcoord[ND3ATM * NFT], dcoord[ND3ATM * NFT], fc[2 * NFT], dval[5]; static double coord[ND3ATM], gtmp[NDCON], vpot[10]; static double wt[NDATM], dist[NDATM], theta[NDATM], phi[NDATM]; static char istau[NDATM]; static char *xyztag[NDATM]; static int nx[4 * NDATM]; FILE *luin, *luout, *lulist, *luxyz; double *pdbl; double ctau, dtau, stau, vmuy, vmuz, dtaud, angram, angorg; double vmutop, rho, tmp, cmp, xlintau; int iatm, k, mval, itau, nsym, n3atm, i, nnatm, noatm; int ia, ii, nval, nstruct, idpar, maxm, maxv, nft, nftc, nxyz; BOOL more, cyclic; rad = asin(1.) / 90.; pi2 = rad * 360.; rho = 0.; filget(argc, argv, NFILE, cfil, cext); luin = fopenq(cfil[einp], "r"); luout = fopenq(cfil[eiam], "w"); lulist = fopenq(cfil[emoi], "w"); luxyz = fopenq(cfil[exyz], "w"); // for (i = 0; i < NDATM; ++i) xyztag[i] = xyztag0; /* read: nstruct, angram, mutop, muz, muy */ dval[0] = 3; dval[1] = 0.; dval[2] = dval[3] = dval[4] = 1.; if (fgetstr(card, 82, luin) <= 0) exit(EXIT_FAILURE); pcard(card, dval, 5, NULL); nstruct = (int) dval[0]; cyclic = TRUE; nftc = NFT; if (nstruct == -2) { cyclic = FALSE; nftc = 2; nstruct = 2; fputs("non-cyclic vibration\n", lulist); } angram = dval[1]; vmutop = dval[2]; vmuz = dval[3]; vmuy = dval[4]; if (nstruct <= 0 || nstruct > NFT) { puts("bad nstruct"); exit(EXIT_FAILURE); } n3atm = 0; noatm = nstruct * ND3ATM; dcopy(noatm, &zero, 0, xcoord, 1); /* read: tau values */ i = 0; do { if (fgetstr(card, 82, luin) <= 0) exit(EXIT_FAILURE); ii = pcard(card, &tauval[i], nstruct - i, NULL); i += ii; } while (i < nstruct); /* solve for coordinate FT */ nnatm = NDATM; if (cyclic) { xlintau = xinterp(nstruct, tauval, dcoord); } else { tauval[0] = 0.; tauval[1] = 180.; xlintau = 0.; } pdbl = dcoord; for (i = 0; i < nstruct; ++i) { /* read in parameters */ fprintf(lulist,"coordinates for tau = %8.1f\n", tauval[i]); iatm = rdinp(luin, NDATM, &noatm, nx, wt, dist, theta, phi, istau, xyztag); if (iatm == 0) { printf("coordinate problem for tau = %8.1f\n", tauval[i]); exit(EXIT_FAILURE); } if (iatm < nnatm) nnatm = iatm; /* get coordinates */ coords(lulist, noatm, coord, wt, nx, dist, theta, phi); n3atm = 3 * nnatm; if (cyclic) { for (iatm = 3; iatm < n3atm; ++iatm) { ii = iatm / 3; k = iatm % 3; if (ii <= k) continue; if (k == 0) { tmp = dist[ii]; } else if (k == 1) { tmp = theta[ii]; } else { tmp = phi[ii]; if (istau[ii] != C0) { if (i == 0) xcoord[iatm] = tmp; tmp -= xcoord[iatm]; tmp -= 360. * floor(tmp / 360. + 0.5); xcoord[iatm + ND3ATM] += xlintau * tmp * (tauval[i] - tauval[0]); continue; } } daxpy(nstruct, tmp, pdbl, nstruct, &xcoord[iatm], ND3ATM); } ++pdbl; } else if (i == 0) { dcopy(n3atm, coord, 1, xcoord, 1); } else { for (iatm = 0; iatm < n3atm; ++iatm) dcoord[iatm] = xcoord[iatm] - coord[iatm]; dcopy(n3atm, coord, 1, &xcoord[ND3ATM], 1); dcopy(n3atm, dcoord, 1, &dcoord[ND3ATM], 1); } } nxyz = 0; for (i = 0; i < nnatm; ++i) if (wt[i] >= 0.5) ++nxyz; /* read: nsym, maxm, maxv, nft */ nsym = 1; maxm = 30; maxv = 3; nft = NFT; dval[0] = (double) nsym; dval[1] = (double) maxm; dval[2] = (double) maxv; dval[3] = (double) nft; do { more = (fgetstr(card, 82, luin) >= 0); if (more && pcard(card, dval, 4, NULL) > 0) { nsym = (int) dval[0]; maxm = (int) dval[1]; maxv = (int) dval[2]; nft = (int) dval[3]; break; } } while (more); dcopy(10, &zero, 0, vpot, 1); while (more) { if (fgetstr(card, 82, luin) <= 0) break; if (pcard(card, dval, 2, NULL) < 2) break; i = (int) dval[0]; if (i > 0 && i <= 9) vpot[i] += dval[1]; } fclose(luin); dtaud = 360. / (double) nftc; dtau = dtaud * rad; if (cyclic) { dcopy(NFT, &zero, 0, fc, 1); pdbl = xcoord; for (iatm = 0; iatm < n3atm; ++iatm) { ii = iatm / 3; if ((iatm % 3) == 2 && istau[ii] != C0) { cmp = pdbl[ND3ATM]; tmp = pdbl[0] - cmp * tauval[0]; cmp *= dtaud; pdbl[0] = tmp; k = NFT >> 1; for (itau = 1; itau < NFT; ++itau) { ii = itau; if (itau > k) ii -= NFT; /* setup linear phi */ pdbl[itau * ND3ATM] = tmp + cmp * ii; } } else { dcopy(nstruct, pdbl, ND3ATM, fc, 1); fc[nstruct] = 0.; ftran(NFT, pdbl, ND3ATM, fc, -1); /* synthesize dist, theta, or phi */ } ++pdbl; } pdbl = xcoord; for (itau = 0; itau < NFT; ++itau) { /* get coordinates */ /* fprintf(lulist,"coordinates for tau = %8.1f\n",itau * dtaud); */ dcopy(nnatm, pdbl, 3, dist, 1); dcopy(nnatm, pdbl + 1, 3, theta, 1); dcopy(nnatm, pdbl + 2, 3, phi, 1); coords(NULL, nnatm, pdbl, wt, nx, dist, theta, phi); pdbl += ND3ATM; } pdbl = xcoord; for (iatm = 0; iatm < n3atm; ++iatm) { ftran(NFT, pdbl, ND3ATM, fc, 0); /* analyze xcoord */ ftran(NFT, &dcoord[iatm], ND3ATM, fc, 1); /* synthesize derivative */ ++pdbl; } } /* get primitive constants vs tau */ ia = ii = iatm = 0; for (itau = 0; itau < nftc; ++itau) { gcalc(nnatm, wt, &xcoord[iatm], &dcoord[iatm], &gval[ii], &cval[ia]); dcopy(7, &zero, 0, &cval[ia + 4], 1); cval[ia + 3] = 1.; cval[ia + 7] = 1.; cval[ia + 11] = 1.; gval[ii + 8] = 0.; tmp = itau * dtau; gval[ii + 9] = cos(tmp) * vmutop; gval[ii + 10] = sin(tmp) * vmutop; ia += CINC; ii += NDCON; iatm += ND3ATM; } if (nsym == 0) { /* solve for PAS */ ia = ii = 0; for (itau = 0; itau < nftc; ++itau) { /* diagonalize inertial matrix */ iatm = itau * ND3ATM; pamsolv(nnatm, &xcoord[iatm], &gval[ii], &cval[ia + 3]); ia += CINC; ii += NDCON; } if (cyclic) { for (iatm = 0; iatm < n3atm; ++iatm) { /* get new derivatives */ ftran(NFT, &xcoord[iatm], ND3ATM, fc, 0); ftran(NFT, &dcoord[iatm], ND3ATM, fc, 1); } } else { for (iatm = 0; iatm < n3atm; ++iatm) { /* get new derivatives */ tmp = xcoord[iatm + ND3ATM] - xcoord[iatm]; dcoord[iatm] = tmp; dcoord[iatm + ND3ATM] = tmp; } } ia = iatm = 0; for (itau = 0; itau < nftc; ++itau) { /* get new values of C */ gcalc(nnatm, wt, &xcoord[iatm], &dcoord[iatm], NULL, &cval[ia]); ia += CINC; iatm += ND3ATM; } angram = 0.; } /* calculate pseudo potential terms */ if (cyclic) { ftran(NFT, gval, NDCON, fc, 0); ftran(NFT, gval, NDCON, fc, 1); ftran(NFT, gder, 1, fc, 1); ftran(NFT, &gval[1], NDCON, fc, 0); ftran(NFT, &gder[NFT], 1, fc, 1); } else { tmp = gval[NDCON] - gval[0]; gval[0] = tmp; gval[NDCON] = tmp; gder[0] = tmp; gder[1] = tmp; tmp = gval[NDCON + 1] - gval[1]; gder[NFT] = tmp; gder[NFT + 1] = tmp; } fputs(" tau, pseudo potential, G,", lulist); fputs(" Cz, Cy, Cx\n", lulist); ia = ii = 0; for (itau = 0; itau < nftc; ++itau) { tmp = gval[ii]; tmp = 0.25 * (gder[itau + NFT] * tmp + gval[ii + 1] * (gder[itau] + 0.25 * tmp * tmp)); gval[ii] = tmp; tmp = itau * dtaud; if (tmp > 180.) tmp -= 360.; fprintf(lulist, "%7.1f %14.6E %13.2f %9.6f %9.6f %9.6f\n", tmp, gval[ii], gval[ii + 1], cval[ia], cval[ia + 1], cval[ia + 2]); gval[ii] *= -2.; ii += NDCON; ia += CINC; } angorg = 0.; if (nsym != 0 && cyclic) { /* solve for IAS */ if (iamsolv(cval, fc) != 0) { strcpy(card, "iteration failed"); fputs(card, lulist); fputs(card, luout); fputs(card, stdout); exit(EXIT_FAILURE); } rho = cval[0]; if (rho < 0.) { angorg = 180.; rho = -rho; } } if (angram >= 360.) { dcopy(NDCON, gval, 1, gtmp, 1); /* transform moments of inertia to predict inertial direction */ micvt(cval, gtmp, vmuz, vmuy, nsym); tmp = 2. * gtmp[7] / (gtmp[2] - 2. * gtmp[4]); angram = 0.5 * atan(tmp) / rad; } angram += angorg; tmp = angram * rad; ctau = cos(tmp); if (ctau < 1.) { stau = sin(tmp); ia = NFT * (CINC / 3); drot(ia, cval, 3, &cval[1], 3, ctau, stau); fprintf(lulist, "%s %9.3f, Ca = %14.10f, Cb = %14.10f\n", "Rotation angle for ab plane =", angram, cval[0], cval[1]); } fprintf(lulist, "rho = %12.9f\n", rho); fputs(" tau, coordinates of Z,", lulist); fputs(" coordinates of Y\n", lulist); ia = 3; iatm = 0; for (itau = 0; itau < nftc; ++itau) { tmp = itau * dtaud; if (tmp > 180.) tmp -= 360.; fprintf(luxyz,"%d\n tau = %7.1f\n", nxyz, tmp); for (i = 0; i < nnatm; ++i) { if (wt[i] < 0.5) continue; pdbl = &xcoord[iatm + 3 * i]; for (ii = 0; ii < 3; ++ii) { dval[ii] = ddot(3, pdbl, 1, &cval[ia + ii], 3); } fprintf(luxyz,"%s %11.7f %11.7f %11.7f\n", xyztag[i], dval[2], dval[1], dval[0]); } fprintf(lulist, "%7.1f ", tmp); for (i = 0; i < 6; ++i) { fprintf(lulist, "%11.7f ", cval[ia + i]); } fputc('\n', lulist); ia += CINC; iatm += ND3ATM; } fclose(luxyz); fputs(" tau, A-(B+C)/2, (B+C)/2, (B-C)/4,", lulist); fputs(" Dbc, Dac, Dab\n", lulist); ii = ia = 0; for (itau = 0; itau < nftc; ++itau) { /* transform moments of inertia */ micvt(&cval[ia], &gval[ii], vmuz, vmuy, nsym); tmp = itau * dtaud; if (tmp > 180.) tmp -= 360.; fprintf(lulist, "%7.1f ", tmp); for (i = 2; i <= 7; ++i) { fprintf(lulist, "%11.2f ", gval[i + ii]); } fputc('\n', lulist); ii += NDCON; ia += CINC; } fclose(lulist); fprintf(luout, "%15.10f %4d %4d %4d %4d\n", cval[0], nsym, maxm, maxv, nft); /* output results */ tmp = ddot(10, vpot, 1, vpot, 1) + 1.e-6; cmp = (1.0e-7) * sqrt(tmp); for (ia = 0; ia < 10; ++ia) { if (fabs(vpot[ia]) > cmp) { fmtv[1] = '0' + (char) ia; fprintf(luout, "%8d %2d %2d %20.12E/ %s\n", 99, ia, 0, vpot[ia], fmtv); } } ia = NDCON; if (nsym != 0) { --ia; if (fabs(cval[1]) < 1e-10) --ia; } for (i = 0; i < ia; ++i) { ftran(nftc, &gval[i], NDCON, fc, 0); if (i == 0) fc[0] = 0.; if (i >= 17) { cmp = -2.; dscal(nftc, cmp, fc, 1); } cmp = (1.0e-7) * sqrt(ddot(nftc, fc, 1, fc, 1) + tmp); idpar = 0; for (ii = 0; ii < nftc; ++ii) { if (fabs(fc[ii]) > cmp) { mval = idpar; idpar = sparv[i].idv; if (mval != 0) idpar = -idpar; nval = (ii + 1) >> 1; if (ii != 0 && (ii & 1) == 0) nval = -nval; mval = 0; if (i == 1) mval = 2; if (i >= 17) mval = 1; fprintf(luout, "%8d %2d %2d %20.12E/ %s\n", idpar, nval, mval, fc[ii], sparv[i].labl); } } tmp = 1.e-6; } return 0; } /* MAIN */ int rdinp(luin, ndatm, natm, nx, wtx, dist, theta, phi, istau, xyztag) FILE *luin; int ndatm, *natm, *nx; double *wtx, *dist, *theta, *phi; char *istau; char **xyztag; { #define BLNK (' ') #define NCARD 9 static struct swt { /*@null@*/ char *symb; double wt; char *xyztag; } swtv[] = { {"C", 12.,"C "}, {"H", 1.00782,"H "}, {"O", 15.99491,"O "}, {"N", 14.00307,"N "}, {"F", 18.9984,"F "}, {"H2", 2.01409,"H "}, {"O18", 17.99915,"O "}, {"C13", 13.00335,"C "}, {"N15", 15.00011,"N "}, {"Cl", 34.96885,"Cl"}, {"Cl37", 36.96582,"Cl"}, {"Br79", 78.9183,"Br"}, {"Br81", 80.9163,"Br"}, {"S", 31.9722,"S "}, {"S34", 33.9688,"S "}, {"P", 30.9744,"P "}, {"I", 126.9004,"I "}, {"D", 2.0140,"H "}, {"X", -1.,"H "}, {" ", 0.,"H "}, {NULL, 0.," "}}; struct swt *pswt; int *nxx; char *pstr; double dvec[NCARD]; int ioff, k, noatm, nnatm, ich; noatm = nnatm = k = 0; nxx = nx; while (noatm < ndatm) { if (fgetstr(card, 82, luin) <= 0) { if (noatm != 0) break; continue; } for (pswt = swtv; (pstr = pswt->symb) != NULL; ++pswt) { for (k = 0; (ich = (int) pstr[k]) != 0 && ich == (int) card[k]; ++k); if (ich == 0 && card[k] == BLNK) break; /* match found */ } if (pstr == NULL) { puts(card); puts("Weight symbol is not defined. (zero used)"); pswt = swtv; k = 0; } pstr = &card[k]; for (k = 0; k < NCARD; ++k) dvec[k] = 0.; if (pcard(pstr, dvec, NCARD, NULL) <= 0) break; ioff = 0; if (pswt->wt < -0.5) { wtx[noatm] = dvec[ioff++]; } else { wtx[noatm] = pswt->wt; xyztag[noatm] = pswt->xyztag; } for (k = 0; k < 4; ++k) { nxx[k] = (int) dvec[ioff++]; if (k > noatm) nxx[k] = 0; if (k != 0 && nxx[k] > noatm) { puts(card); puts("Atom designations are out of order."); return 0; } } dist[noatm] = dvec[ioff++]; theta[noatm] = dvec[ioff++]; phi[noatm] = dvec[ioff++]; istau[noatm] = (char) dvec[ioff]; ++noatm; if (nxx[0] == noatm) nnatm = noatm; if (nxx[0] > noatm) return 0; nxx += 4; } *natm = noatm; return nnatm; } /* rdinp */ int coords(lu, noatm, coord, wt, nx, dist, theta, phi) FILE *lu; int noatm; double *coord, *wt; int *nx; double *dist, *theta, *phi; { double xcm[3], prcor[3], trans[9], xvectr[3], yvectr[3], cb, sb; double wtot, cth, rij, rik, ril, sth, tmp, sum, scale; int *nxx, i, j, iloop, ia, ib, ic, ii, iap, ibp, icp, ia3, ib3, ic3, ii3; nxx = nx; /* THE COORDINATES OF ATOM 1 ARE SET AS THE ORIGIN */ for (i = 0; i < 3; ++i) { coord[i] = 0.; coord[i + 3] = 0.; xcm[i] = 0.; } coord[3] = dist[1]; xcm[0] = wt[1] * dist[1]; wtot = wt[0] + wt[1]; ia = ib = ic = ia3 = ii3 = -1; /* THE X AND Y COORDINATE OF ATOM 3 ARE CALCULATED */ if (noatm > 2) { nxx += 8; ia = nxx[1] - 1; ia3 = 3 * ia; cth = cos(theta[2] * rad); if (ia == 1) cth = -cth; coord[6] = coord[ia3] + dist[2] * cth; coord[7] = coord[ia3 + 1] + dist[2] * sqrt(1. - cth * cth); coord[8] = 0.; xcm[0] += wt[2] * coord[6]; xcm[1] = wt[2] * coord[7]; wtot += wt[2]; ii3 = 9; } /* THE COORDINATES OF ALL THE OTHER ATOMS ARE CALCULATED */ ril = scale = 1.; for (iloop = 3; iloop < noatm; ++iloop) { iap = ia; ibp = ib; icp = ic; nxx += 4; ia = nxx[1] - 1; ib = nxx[2] - 1; ic = nxx[3] - 1; ia3 = 3 * ia; /* THE TRANSFORMATION MATRIX IS OBTAINED */ if (ia != iap || ib != ibp || ic != icp) { /* THE COMPONENTS OF THE X PRIME DIRECTION ARE OBTAINED */ rij = ril = 0.; ib3 = 3 * ib; ic3 = 3 * ic; for (i = 0; i < 3; ++i) { xvectr[i] = tmp = coord[i + ib3] - coord[i + ia3]; rij += tmp * tmp; yvectr[i] = tmp = coord[i + ic3] - coord[i + ia3]; ril += tmp * tmp; } rij = sqrt(rij); scale = 0.; for (i = 0; i < 3; ++i) { trans[i] = xvectr[i] / rij; scale += yvectr[i] * trans[i]; } /* THE COMPONENTS OF THE Y PRIME DIRECTION ARE OBTAINED */ rik = ril - scale * scale; if (rik < 1e-8) { /* Y PRIME PARALLEL TO X PRIME */ for (i = 0; i < 3; ++i) yvectr[i] = 0.; i = 1; if (fabs(trans[1]) > 0.71) i = 2; yvectr[i] = 1.; scale = trans[i]; ril = 1.; rik = ril - scale * scale; } rik = sqrt(rik); for (i = 0; i < 3; ++i) { trans[i + 3] = (yvectr[i] - scale * trans[i]) / rik; } /* THE COMPONENTS OF THE Z DIRECTION ARE OBTAINED */ trans[6] = trans[1] * trans[5] - trans[2] * trans[4]; trans[7] = trans[2] * trans[3] - trans[0] * trans[5]; trans[8] = trans[0] * trans[4] - trans[1] * trans[3]; } /* THE SPHERICAL COORDINATES ARE TRANSFORMED TO CARTESIAN COORDINATES IN THE PRIME SYSTEM */ if (nxx[0] == iloop + 1) { if (dist[iloop] < 0.) { tmp = dist[iloop] * cos(theta[iloop] * rad); cth = 4. * ril; cth = scale / sqrt(cth); sth = tmp * sqrt(0.5 - cth); cth = tmp * sqrt(cth + 0.5); sb = sin(phi[iloop] * rad); cb = cos(phi[iloop] * rad); prcor[0] = cth * cb - sth * sb; prcor[1] = sth * cb + cth * sb; prcor[2] = -dist[iloop] * sin(theta[iloop] * rad); } else { cth = cos(theta[iloop] * rad); tmp = dist[iloop] * sqrt(1. - cth * cth); prcor[0] = dist[iloop] * cth; prcor[1] = tmp * cos(phi[iloop] * rad); prcor[2] = tmp * sin(phi[iloop] * rad); } /* THE PRIME COORDINATES ARE TRANSLATED AND ROTATED TO THE COORDINATE SYSTEM DESIRED */ wtot += wt[iloop]; for (i = 0; i < 3; ++i) { sum = 0.; ii = i; for (j = 0; j < 3; ++j) { sum += trans[ii] * prcor[j]; ii += 3; } coord[ii3] = coord[i + ia3] + sum; xcm[i] += wt[iloop] * coord[ii3]; ++ii3; } } else { /* SPECIAL REVERSE CALCULATION OF DIST THETA AND PHI */ rij = 0.; ic3 = 3 * (nxx[0] - 1); ii = 0; for (i = 0; i < 3; ++i) { coord[ii3] = coord[i + ic3]; sum = 0.; for (j = 0; j < 3; ++j) { sum += trans[j + ii] * (coord[j + ic3] - coord[j + ia3]); } rij += sum * sum; prcor[i] = sum; ii += 3; ++ii3; } rij = sqrt(rij); phi[iloop] = 0.; if (dist[iloop] < 0.) { sth = prcor[2] / rij; dist[iloop] = -rij; theta[iloop] = asin(sth) / rad; if (fabs(sth) < 0.99999999999999) { cth = 4. * ril; sth = -sqrt(0.5 - cth); cth = -sqrt(cth + 0.5); sb = prcor[1] * cth - prcor[0] * sth; cb = prcor[0] * cth + prcor[1] * sth; phi[iloop] = atan2(sb, cb) / rad; } } else { dist[iloop] = rij; sth = prcor[0] / rij; theta[iloop] = acos(sth) / rad; if (fabs(sth) < 0.999999999999) { phi[iloop] = atan2(prcor[2], prcor[1]) / rad; } } } } if (wtot > 1.) { xcm[0] /= wtot; xcm[1] /= wtot; xcm[2] /= wtot; } ii3 = 0; for (iloop = 0; iloop < noatm; ++iloop) { for (i = 0; i < 3; ++i) { coord[ii3] -= xcm[i]; ++ii3; } } if (lu == NULL) return 0; fprintf(lu, "WT,N,NA,NB,NC,DIST,THETA,PHI,X, MASS= %10.6f\n", wtot); ii3 = 0; nxx = nx; for (iloop = 0; iloop < noatm; ++iloop) { fprintf(lu, "%10.6f", wt[iloop]); for (ii = 0; ii < 4; ++ii) { fprintf(lu, " %2d", *nxx); ++nxx; } fprintf(lu, " %8.4f %8.3f %8.3f", dist[iloop], theta[iloop], phi[iloop]); for (i = 0; i < 3; ++i) { fprintf(lu, " %9.5f", coord[ii3]); ++ii3; } fputc('\n', lu); } return 0; } /* coords */ int gcalc(natm, wt, coord, dcoord, gval, cval) int natm; double *wt, *coord, *dcoord, *gval, *cval; { static double tiny = 1.0e-30; static double conv = 505379.07; double mi[12], x[3], y, tmp; int iatm, i, ii, j, k, iatm3; y = tiny; dcopy(12, &zero, 0, mi, 1); iatm3 = 0; for (iatm = 0; iatm < natm; ++iatm) { /* z=0, y=1, x=2 */ ii = 0; for (i = 0; i < 3; ++i) { j = i - 1; if (j < 0) j = 2; k = i + 1; if (k > 2) k = 0; tmp = wt[iatm] * coord[iatm3 + i]; mi[k + 9] += tmp * dcoord[iatm3 + j]; mi[j + 9] -= tmp * dcoord[iatm3 + k]; for (j = 0; j < 3; ++j) { mi[ii] -= tmp * coord[iatm3 + j]; ++ii; } y += wt[iatm] * dcoord[iatm3 + i] * dcoord[iatm3 + i]; } iatm3 += 3; } dcopy(3, &mi[9], 1, x, 1); tmp = mi[0] + mi[4] + mi[8]; mi[0] -= tmp; mi[4] -= tmp; mi[8] -= tmp; tmp = determ(mi, 3, 3, 4); dcopy(3, &mi[9], 1, cval, 1); if (gval) { y -= ddot(3, cval, 1, x, 1); tmp *= y; if (tmp < tiny) tmp = tiny; gval[0] = log(tmp); gval[1] = conv / y; gval[2] = conv * mi[0]; gval[3] = conv * mi[4]; gval[4] = conv * mi[8]; gval[5] = conv * mi[5]; gval[6] = conv * mi[2]; gval[7] = conv * mi[1]; } return 0; } /* gcalc */ double determ(a, ndd, nr, nc) double *a; int ndd, nr, nc; { /* calculate inverse & determinant */ /* use dumb Gauss-Jordon method with pivot */ static double eps = 1.e-30; // static double aa[36]; static int nsav; /*@owned@*/ static int *iperm; double det, s; int i, ic, ir, iic, n, iswap; // n = ndd * nr; // dcopy(n, a, 1, aa, 1); n = (nc > nr) ? nr : nc; if (n > nsav) { if (nsav != 0) { free(iperm); iperm = NULL; } iperm = (int *) mallocq(n * sizeof(int)); nsav = n; iperm[0] = 0; } det = 1.; iic = 0; for (ic = 0; ic < n; ++ic) { i = ic + iic; iswap = ic + (int) idamax(n - ic, &a[i], 1); iperm[ic] = iswap; if (iswap != ic) { dswap(nr, &a[iic], 1, &a[iswap * ndd], 1); det = -det; } s = a[i]; a[i] = 1.; det *= s; if (fabs(s) < eps) { dcopy(nc, &zero, 0, &a[ic], ndd); } else { s = 1. / s; dscal(nc, s, &a[ic], ndd); } for (ir = 0; ir < nr; ++ir) { if (ir == ic) continue; i = ir + iic; s = -a[i]; a[i] = 0.; daxpy(nc, s, &a[ic], ndd, &a[ir], ndd); } iic += ndd; } for (ic = n - 2; ic >= 0; --ic) { iswap = iperm[ic]; if (iswap != ic) dswap(nc, &a[ic], ndd, &a[iswap], ndd); } /* test for (ic = 0; ic < nr; ++ic) { iic = 0; for (ir = 0; ir < nr; ++ir) { s = ddot(nr, &a[ic], ndd, &aa[iic], 1); if (ir == ic) s -= 1.; iic += ndd; } } */ return det; } /* determ */ int iamsolv(cval, fc) double *cval, *fc; { static double a[2 * NFT], ader[2 * NFT]; static double eps = 1e-20; double rho, rhosq, ang, rho0, z, r, s, c; double *fcx, *b, *bder; int itr, k, kk, kz, nab, nc, nt, pivot; BOOL done; fcx = fc + NFT; b = a + NFT; bder = ader + NFT; nab = 2 * NFT; nc = CINC / 3; nt = nc * NFT; rho0 = 0.; for (itr = 0; itr < 100; ++itr) { kz = 0; z = cval[0]; c = cval[1]; s = cval[2]; for (k = 1; k < NFT; ++k) { kz += CINC; z += cval[kz]; c += cval[kz + 1]; s += cval[kz + 2]; } /* apply tau-independent rotation */ rhosq = s * s + c * c; if (rhosq > eps) { r = sqrt(rhosq); if (c < 0.) r = -r; c /= r; if (c < 1.) { s /= r; drot(nt, &cval[1], 3, &cval[2], 3, c, s); } } else { r = 0.; } rhosq += z * z; rho = sqrt(rhosq); if (rhosq > eps) { if (z < 0.) rho = -rho; c = z / rho; if (c < 1.) { s = r / rho; drot(nt, cval, 3, &cval[1], 3, c, s); } } if (itr == 0) rho0 = rho / NFT; r = ddot(NFT, &cval[1], CINC, &cval[1], CINC) + ddot(NFT, &cval[2], CINC, &cval[2], CINC); done = (r < eps); /* analyze Cz */ ftran(NFT, cval, CINC, fc, 0); rho = fc[0]; r = rho; if (done) r -= rho0; r = floor(r + 0.5); pivot = (int) r; if (pivot == 0) { fc[0] = 0; if (ddot(NFT, fc, 1, fc, 1) > eps) pivot = 1; } if (pivot != 0) { /* rotate about z to make Cz constant */ rho -= r; r *= pi2 / NFT; ftran(NFT, a, 1, fc, 2); /* integrate Cz */ kz = 0; for (k = 0; k < NFT; ++k) { ang = a[k] + k * r; c = cos(ang); s = sin(ang); drot(nc, &cval[kz + 2], 3, &cval[kz + 1], 3, c, s); cval[kz] = rho; kz += CINC; } } if (done) return 0; /* analyze Cx, Cy */ ftran(NFT, &cval[1], CINC, fc, 0); ftran(NFT, &cval[2], CINC, fcx, 0); r = rho * rho + eps; fc[0] *= rho / r; fcx[0] *= -rho / r; k = 0; for (kk = 1; kk < NFT; kk += 2) { r -= kk; ++k; c = fc[kk]; s = fcx[kk + 1]; fc[kk] = (rho * c - k * s) / r; fcx[kk + 1] = (k * c - rho * s) / r; c = fcx[kk]; s = fc[kk + 1]; fc[kk + 1] = (rho * s + k * c) / r; fcx[kk] = -(k * s + rho * c) / r; } /* synthesize angles and derivatives */ ftran(NFT, a, 1, fc, -1); ftran(NFT, ader, 1, fc, 1); ftran(NFT, b, 1, fcx, -1); ftran(NFT, bder, 1, fcx, 1); k = (int) idamax(nab, a, 1); r = 8. * fabs(a[k]); if (r > 1.) { /* scale angles for linearity */ r = 1. / r; dscal(nab, r, a, 1); dscal(nab, r, ader, 1); } /* do rotations */ kz = 0; for (k = 0; k < NFT; ++k) { ang = a[k]; c = cos(ang); s = sin(ang); drot(nc, &cval[kz], 3, &cval[kz + 1], 3, c, s); cval[kz + 2] += ader[k]; ang = b[k]; c = cos(ang); s = sin(ang); drot(nc, &cval[kz + 2], 3, &cval[kz], 3, c, s); cval[kz + 1] += bder[k]; kz += CINC; } } return -1; } /* iamsolv */ int pamsolv(natm, x, gval, tval) int natm; double *x, *gval, *tval; { double mi[9], te[3], wk[3]; int j, k, m, itmp; short isblk[4], ipasgn[3], iqnsep[3]; for (j = 0; j < 4; ++j) { isblk[j] = (short) j; } for (k = 0; k < 3; ++k) { ipasgn[k] = 0; j = k - 1; if (j < 0) j = 2; m = k + 1; if (m > 2) m = 0; mi[j + k * 3] = gval[m + 5]; mi[k + j * 3] = gval[m + 5]; mi[k * 4] = gval[k + 2]; } /* diagonalize and find max overlap */ hdiag(3, 3, mi, te, wk, iqnsep); if ((ordblk(3, 3, iqnsep, mi, te, isblk, wk, ipasgn) & 1) != 0) { for (j = 6; j < 9; ++j) { /* make determinant positive */ mi[j] = -mi[j]; } } /* apply transformations */ itmp = 0; for (k = 0; k < natm; ++k) { dcopy(3, &x[itmp], 1, te, 1); for (j = 0; j < 3; ++j) { x[itmp] = ddot(3, &mi[j * 3], 1, te, 1); ++itmp; } } itmp = 0; for (j = 0; j < 3; ++j) { dcopy(3, &mi[itmp], 1, &tval[j], 3); itmp += 3; } return 0; } /* pamsolv */ int micvt(cval, gval, vmuz, vmuy, flg) double *cval, *gval, vmuz, vmuy; int flg; { double mi[9], tt[9], tv[3], tmp, ctmp, *mt; int j, k, m, itmp; ctmp = cval[0]; if (flg > 0) cval[0] = 0.; for (k = 0; k < 3; ++k) { j = k - 1; if (j < 0) j = 2; m = k + 1; if (m > 2) m = 0; mi[j + k * 3] = gval[m + 5]; mi[k + j * 3] = gval[m + 5]; mi[k * 4] = gval[k + 2]; tv[k] = gval[k + 8]; } mt = &cval[3]; for (j = 0; j < 3; ++j) { itmp = j; for (k = 0; k < 3; ++k) { tt[itmp] = ddot(3, &mi[j], 3, &mt[k], 3); itmp += 3; } } for (j = 0; j < 3; ++j) { itmp = 0; for (k = 0; k < 3; ++k) { mi[itmp + j] = ddot(3, &tt[itmp], 1, &mt[j], 3); itmp += 3; } } for (k = 0; k < 3; ++k) { j = k - 1; if (j < 0) j = 2; m = k + 1; if (m > 2) m = 0; tmp = gval[1] * cval[k]; gval[k + 2] = mi[k * 4] + tmp * cval[k]; gval[m + 5] = mi[j + k * 3] + tmp * cval[j]; gval[k + 8] = ddot(3, &mt[k], 3, tv, 1); gval[k + 11] = mt[k] * vmuz; gval[k + 14] = mt[k + 3] * vmuy; gval[k + 17] = tmp; } tmp = 0.5 * (gval[3] + gval[4]); gval[3] = tmp; gval[2] -= tmp; gval[4] = 0.5 * (tmp - gval[4]); cval[0] = ctmp; return 0; } /* micvt */ double xinterp(n, tauval, xtrans) int n; double *tauval, *xtrans; { double ang, ang1, tt; int i, k, ii; tt = 0.; ii = 0; for (i = 0; i < n; ++i) { ang1 = tauval[i] - tauval[0]; ang1 -= 360. * floor(ang1 / 360 + 0.5); tauval[i] = tauval[0] + ang1; ang = tauval[i]; tt += ang1 * ang1; xtrans[ii] = 1.; ang *= rad; ang1 = ang; for (k = 1; k < n; ++k) { ++ii; if ((k & 1) != 0) { xtrans[ii] = cos(ang); } else { xtrans[ii] = sin(ang); ang += ang1; } } ++ii; } ang1 = determ(xtrans, n, n, n); if (n < 2) tt = 1.; tt = 1. / tt; return tt; } /* xinterp */