int gmx_filter(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] performs frequency filtering on a trajectory.", "The filter shape is cos([GRK]pi[grk] t/A) + 1 from -A to +A, where A is given", "by the option [TT]-nf[tt] times the time step in the input trajectory.", "This filter reduces fluctuations with period A by 85%, with period", "2*A by 50% and with period 3*A by 17% for low-pass filtering.", "Both a low-pass and high-pass filtered trajectory can be written.[PAR]", "Option [TT]-ol[tt] writes a low-pass filtered trajectory.", "A frame is written every [TT]-nf[tt] input frames.", "This ratio of filter length and output interval ensures a good", "suppression of aliasing of high-frequency motion, which is useful for", "making smooth movies. Also averages of properties which are linear", "in the coordinates are preserved, since all input frames are weighted", "equally in the output.", "When all frames are needed, use the [TT]-all[tt] option.[PAR]", "Option [TT]-oh[tt] writes a high-pass filtered trajectory.", "The high-pass filtered coordinates are added to the coordinates", "from the structure file. When using high-pass filtering use [TT]-fit[tt]", "or make sure you use a trajectory that has been fitted on", "the coordinates in the structure file." }; static int nf = 10; static gmx_bool bNoJump = TRUE, bFit = FALSE, bLowAll = FALSE; t_pargs pa[] = { { "-nf", FALSE, etINT, {&nf}, "Sets the filter length as well as the output interval for low-pass filtering" }, { "-all", FALSE, etBOOL, {&bLowAll}, "Write all low-pass filtered frames" }, { "-nojump", FALSE, etBOOL, {&bNoJump}, "Remove jumps of atoms across the box" }, { "-fit", FALSE, etBOOL, {&bFit}, "Fit all frames to a reference structure" } }; const char *topfile, *lowfile, *highfile; gmx_bool bTop = FALSE; t_topology top; int ePBC = -1; rvec *xtop; matrix topbox, *box, boxf; char title[256], *grpname; int isize; atom_id *index; real *w_rls = NULL; t_trxstatus *in; t_trxstatus *outl, *outh; int nffr, i, fr, nat, j, d, m; atom_id *ind; real flen, *filt, sum, *t; rvec xcmtop, xcm, **x, *ptr, *xf, *xn, *xp, hbox; output_env_t oenv; gmx_rmpbc_t gpbc = NULL; #define NLEG asize(leg) t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efTRO, "-ol", "lowpass", ffOPTWR }, { efTRO, "-oh", "highpass", ffOPTWR } }; #define NFILE asize(fnm) if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } highfile = opt2fn_null("-oh", NFILE, fnm); if (highfile) { topfile = ftp2fn(efTPS, NFILE, fnm); lowfile = opt2fn_null("-ol", NFILE, fnm); } else { topfile = ftp2fn_null(efTPS, NFILE, fnm); lowfile = opt2fn("-ol", NFILE, fnm); } if (topfile) { bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), title, &top, &ePBC, &xtop, NULL, topbox, TRUE); if (bTop) { gpbc = gmx_rmpbc_init(&top.idef, ePBC, top.atoms.nr); gmx_rmpbc(gpbc, top.atoms.nr, topbox, xtop); } } clear_rvec(xcmtop); if (bFit) { fprintf(stderr, "Select group for least squares fit\n"); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &isize, &index, &grpname); /* Set the weight */ snew(w_rls, top.atoms.nr); for (i = 0; i < isize; i++) { w_rls[index[i]] = top.atoms.atom[index[i]].m; } calc_xcm(xtop, isize, index, top.atoms.atom, xcmtop, FALSE); for (j = 0; j < top.atoms.nr; j++) { rvec_dec(xtop[j], xcmtop); } } /* The actual filter length flen can actually be any real number */ flen = 2*nf; /* nffr is the number of frames that we filter over */ nffr = 2*nf - 1; snew(filt, nffr); sum = 0; for (i = 0; i < nffr; i++) { filt[i] = cos(2*M_PI*(i - nf + 1)/(real)flen) + 1; sum += filt[i]; } fprintf(stdout, "filter weights:"); for (i = 0; i < nffr; i++) { filt[i] /= sum; fprintf(stdout, " %5.3f", filt[i]); } fprintf(stdout, "\n"); snew(t, nffr); snew(x, nffr); snew(box, nffr); nat = read_first_x(oenv, &in, opt2fn("-f", NFILE, fnm), &(t[nffr - 1]), &(x[nffr - 1]), box[nffr - 1]); snew(ind, nat); for (i = 0; i < nat; i++) { ind[i] = i; } /* x[nffr - 1] was already allocated by read_first_x */ for (i = 0; i < nffr-1; i++) { snew(x[i], nat); } snew(xf, nat); if (lowfile) { outl = open_trx(lowfile, "w"); } else { outl = 0; } if (highfile) { outh = open_trx(highfile, "w"); } else { outh = 0; } fr = 0; do { xn = x[nffr - 1]; if (bNoJump && fr > 0) { xp = x[nffr - 2]; for (j = 0; j < nat; j++) { for (d = 0; d < DIM; d++) { hbox[d] = 0.5*box[nffr - 1][d][d]; } } for (i = 0; i < nat; i++) { for (m = DIM-1; m >= 0; m--) { if (hbox[m] > 0) { while (xn[i][m] - xp[i][m] <= -hbox[m]) { for (d = 0; d <= m; d++) { xn[i][d] += box[nffr - 1][m][d]; } } while (xn[i][m] - xp[i][m] > hbox[m]) { for (d = 0; d <= m; d++) { xn[i][d] -= box[nffr - 1][m][d]; } } } } } } if (bTop) { gmx_rmpbc(gpbc, nat, box[nffr - 1], xn); } if (bFit) { calc_xcm(xn, isize, index, top.atoms.atom, xcm, FALSE); for (j = 0; j < nat; j++) { rvec_dec(xn[j], xcm); } do_fit(nat, w_rls, xtop, xn); for (j = 0; j < nat; j++) { rvec_inc(xn[j], xcmtop); } } if (fr >= nffr && (outh || bLowAll || fr % nf == nf - 1)) { /* Lowpass filtering */ for (j = 0; j < nat; j++) { clear_rvec(xf[j]); } clear_mat(boxf); for (i = 0; i < nffr; i++) { for (j = 0; j < nat; j++) { for (d = 0; d < DIM; d++) { xf[j][d] += filt[i]*x[i][j][d]; } } for (j = 0; j < DIM; j++) { for (d = 0; d < DIM; d++) { boxf[j][d] += filt[i]*box[i][j][d]; } } } if (outl && (bLowAll || fr % nf == nf - 1)) { write_trx(outl, nat, ind, topfile ? &(top.atoms) : NULL, 0, t[nf - 1], bFit ? topbox : boxf, xf, NULL, NULL); } if (outh) { /* Highpass filtering */ for (j = 0; j < nat; j++) { for (d = 0; d < DIM; d++) { xf[j][d] = xtop[j][d] + x[nf - 1][j][d] - xf[j][d]; } } if (bFit) { for (j = 0; j < nat; j++) { rvec_inc(xf[j], xcmtop); } } for (j = 0; j < DIM; j++) { for (d = 0; d < DIM; d++) { boxf[j][d] = topbox[j][d] + box[nf - 1][j][d] - boxf[j][d]; } } write_trx(outh, nat, ind, topfile ? &(top.atoms) : NULL, 0, t[nf - 1], bFit ? topbox : boxf, xf, NULL, NULL); } } /* Cycle all the pointer and the box by one */ ptr = x[0]; for (i = 0; i < nffr-1; i++) { t[i] = t[i+1]; x[i] = x[i+1]; copy_mat(box[i+1], box[i]); } x[nffr - 1] = ptr; fr++; } while (read_next_x(oenv, in, &(t[nffr - 1]), x[nffr - 1], box[nffr - 1])); if (bTop) { gmx_rmpbc_done(gpbc); } if (outh) { close_trx(outh); } if (outl) { close_trx(outl); } close_trx(in); return 0; }
static void predict_shells(FILE *fplog,rvec x[],rvec v[],real dt, int ns,t_shell s[], real mass[],gmx_mtop_t *mtop,gmx_bool bInit) { int i,m,s1,n1,n2,n3; real dt_1,dt_2,dt_3,fudge,tm,m1,m2,m3; rvec *ptr; t_atom *atom; /* We introduce a fudge factor for performance reasons: with this choice * the initial force on the shells is about a factor of two lower than * without */ fudge = 1.0; if (bInit) { if (fplog) fprintf(fplog,"RELAX: Using prediction for initial shell placement\n"); ptr = x; dt_1 = 1; } else { ptr = v; dt_1 = fudge*dt; } for(i=0; (i<ns); i++) { s1 = s[i].shell; if (bInit) clear_rvec(x[s1]); switch (s[i].nnucl) { case 1: n1 = s[i].nucl1; for(m=0; (m<DIM); m++) x[s1][m]+=ptr[n1][m]*dt_1; break; case 2: n1 = s[i].nucl1; n2 = s[i].nucl2; if (mass) { m1 = mass[n1]; m2 = mass[n2]; } else { /* Not the correct masses with FE, but it is just a prediction... */ m1 = atom[n1].m; m2 = atom[n2].m; } tm = dt_1/(m1+m2); for(m=0; (m<DIM); m++) x[s1][m]+=(m1*ptr[n1][m]+m2*ptr[n2][m])*tm; break; case 3: n1 = s[i].nucl1; n2 = s[i].nucl2; n3 = s[i].nucl3; if (mass) { m1 = mass[n1]; m2 = mass[n2]; m3 = mass[n3]; } else { /* Not the correct masses with FE, but it is just a prediction... */ gmx_mtop_atomnr_to_atom(mtop,n1,&atom); m1 = atom->m; gmx_mtop_atomnr_to_atom(mtop,n2,&atom); m2 = atom->m; gmx_mtop_atomnr_to_atom(mtop,n3,&atom); m3 = atom->m; } tm = dt_1/(m1+m2+m3); for(m=0; (m<DIM); m++) x[s1][m]+=(m1*ptr[n1][m]+m2*ptr[n2][m]+m3*ptr[n3][m])*tm; break; default: gmx_fatal(FARGS,"Shell %d has %d nuclei!",i,s[i].nnucl); } } }
static void calc_axes(rvec x[], t_atom atom[], int gnx[], atom_id *index[], gmx_bool bRot, t_bundle *bun) { int end, i, div, d; real *mtot, m; rvec axis[MAX_ENDS], cent; snew(mtot, bun->n); for (end = 0; end < bun->nend; end++) { for (i = 0; i < bun->n; i++) { clear_rvec(bun->end[end][i]); mtot[i] = 0; } div = gnx[end]/bun->n; for (i = 0; i < gnx[end]; i++) { m = atom[index[end][i]].m; for (d = 0; d < DIM; d++) { bun->end[end][i/div][d] += m*x[index[end][i]][d]; } mtot[i/div] += m; } clear_rvec(axis[end]); for (i = 0; i < bun->n; i++) { svmul(1.0/mtot[i], bun->end[end][i], bun->end[end][i]); rvec_inc(axis[end], bun->end[end][i]); } svmul(1.0/bun->n, axis[end], axis[end]); } sfree(mtot); rvec_add(axis[0], axis[1], cent); svmul(0.5, cent, cent); /* center the bundle on the origin */ for (end = 0; end < bun->nend; end++) { rvec_dec(axis[end], cent); for (i = 0; i < bun->n; i++) { rvec_dec(bun->end[end][i], cent); } } if (bRot) { /* rotate the axis parallel to the z-axis */ rotate_ends(bun, axis[0], YY, ZZ); rotate_ends(bun, axis[0], XX, ZZ); } for (i = 0; i < bun->n; i++) { rvec_add(bun->end[0][i], bun->end[1][i], bun->mid[i]); svmul(0.5, bun->mid[i], bun->mid[i]); rvec_sub(bun->end[0][i], bun->end[1][i], bun->dir[i]); bun->len[i] = norm(bun->dir[i]); unitv(bun->dir[i], bun->dir[i]); } }
static real ekrot(rvec x[], rvec v[], real mass[], int isize, atom_id index[]) { static real **TCM = NULL, **L; double tm, m0, lxx, lxy, lxz, lyy, lyz, lzz, ekrot; rvec a0, ocm; dvec dx, b0; dvec xcm, vcm, acm; int i, j, m, n; if (TCM == NULL) { snew(TCM, DIM); for (i = 0; i < DIM; i++) { snew(TCM[i], DIM); } snew(L, DIM); for (i = 0; i < DIM; i++) { snew(L[i], DIM); } } clear_dvec(xcm); clear_dvec(vcm); clear_dvec(acm); tm = 0.0; for (i = 0; i < isize; i++) { j = index[i]; m0 = mass[j]; tm += m0; cprod(x[j], v[j], a0); for (m = 0; (m < DIM); m++) { xcm[m] += m0*x[j][m]; /* c.o.m. position */ vcm[m] += m0*v[j][m]; /* c.o.m. velocity */ acm[m] += m0*a0[m]; /* rotational velocity around c.o.m. */ } } dcprod(xcm, vcm, b0); for (m = 0; (m < DIM); m++) { xcm[m] /= tm; vcm[m] /= tm; acm[m] -= b0[m]/tm; } lxx = lxy = lxz = lyy = lyz = lzz = 0.0; for (i = 0; i < isize; i++) { j = index[i]; m0 = mass[j]; for (m = 0; m < DIM; m++) { dx[m] = x[j][m] - xcm[m]; } lxx += dx[XX]*dx[XX]*m0; lxy += dx[XX]*dx[YY]*m0; lxz += dx[XX]*dx[ZZ]*m0; lyy += dx[YY]*dx[YY]*m0; lyz += dx[YY]*dx[ZZ]*m0; lzz += dx[ZZ]*dx[ZZ]*m0; } L[XX][XX] = lyy + lzz; L[YY][XX] = -lxy; L[ZZ][XX] = -lxz; L[XX][YY] = -lxy; L[YY][YY] = lxx + lzz; L[ZZ][YY] = -lyz; L[XX][ZZ] = -lxz; L[YY][ZZ] = -lyz; L[ZZ][ZZ] = lxx + lyy; m_inv_gen(L, DIM, TCM); /* Compute omega (hoeksnelheid) */ clear_rvec(ocm); ekrot = 0; for (m = 0; m < DIM; m++) { for (n = 0; n < DIM; n++) { ocm[m] += TCM[m][n]*acm[n]; } ekrot += 0.5*ocm[m]*acm[m]; } return ekrot; }
int gmx_gyrate(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the radius of gyration of a molecule", "and the radii of gyration about the [IT]x[it]-, [IT]y[it]- and [IT]z[it]-axes,", "as a function of time. The atoms are explicitly mass weighted.[PAR]", "The axis components corresponds to the mass-weighted root-mean-square", "of the radii components orthogonal to each axis, for example:[PAR]", "Rg(x) = sqrt((sum_i m_i (R_i(y)^2 + R_i(z)^2))/(sum_i m_i)).[PAR]", "With the [TT]-nmol[tt] option the radius of gyration will be calculated", "for multiple molecules by splitting the analysis group in equally", "sized parts.[PAR]", "With the option [TT]-nz[tt] 2D radii of gyration in the [IT]x-y[it] plane", "of slices along the [IT]z[it]-axis are calculated." }; static int nmol = 1, nz = 0; static gmx_bool bQ = FALSE, bRot = FALSE, bMOI = FALSE; t_pargs pa[] = { { "-nmol", FALSE, etINT, {&nmol}, "The number of molecules to analyze" }, { "-q", FALSE, etBOOL, {&bQ}, "Use absolute value of the charge of an atom as weighting factor instead of mass" }, { "-p", FALSE, etBOOL, {&bRot}, "Calculate the radii of gyration about the principal axes." }, { "-moi", FALSE, etBOOL, {&bMOI}, "Calculate the moments of inertia (defined by the principal axes)." }, { "-nz", FALSE, etINT, {&nz}, "Calculate the 2D radii of gyration of this number of slices along the z-axis" }, }; FILE *out; t_trxstatus *status; t_topology top; int ePBC; rvec *x, *x_s; rvec xcm, gvec, gvec1; matrix box, trans; gmx_bool bACF; real **moi_trans = NULL; int max_moi = 0, delta_moi = 100; rvec d, d1; /* eigenvalues of inertia tensor */ real t, t0, tm, gyro; int natoms; char *grpname; int j, m, gnx, nam, mol; int *index; gmx_output_env_t *oenv; gmx_rmpbc_t gpbc = NULL; const char *leg[] = { "Rg", "Rg\\sX\\N", "Rg\\sY\\N", "Rg\\sZ\\N" }; const char *legI[] = { "Itot", "I1", "I2", "I3" }; #define NLEG asize(leg) t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, NULL, "gyrate", ffWRITE }, { efXVG, "-acf", "moi-acf", ffOPTWR }, }; #define NFILE asize(fnm) int npargs; t_pargs *ppa; npargs = asize(pa); ppa = add_acf_pargs(&npargs, pa); if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } bACF = opt2bSet("-acf", NFILE, fnm); if (bACF && nmol != 1) { gmx_fatal(FARGS, "Can only do acf with nmol=1"); } bRot = bRot || bMOI || bACF; /* if (nz > 0) bMOI = TRUE; */ if (bRot) { printf("Will rotate system along principal axes\n"); snew(moi_trans, DIM); } if (bMOI) { printf("Will print moments of inertia\n"); bQ = FALSE; } if (bQ) { printf("Will print radius normalised by charge\n"); } read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &x, NULL, box, TRUE); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); if (nmol > gnx || gnx % nmol != 0) { gmx_fatal(FARGS, "The number of atoms in the group (%d) is not a multiple of nmol (%d)", gnx, nmol); } nam = gnx/nmol; natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); snew(x_s, natoms); j = 0; t0 = t; if (bQ) { out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Radius of Charge (total and around axes)", "Time (ps)", "Rg (nm)", oenv); } else if (bMOI) { out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Moments of inertia (total and around axes)", "Time (ps)", "I (a.m.u. nm\\S2\\N)", oenv); } else { out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Radius of gyration (total and around axes)", "Time (ps)", "Rg (nm)", oenv); } if (bMOI) { xvgr_legend(out, NLEG, legI, oenv); } else { if (bRot) { if (output_env_get_print_xvgr_codes(oenv)) { fprintf(out, "@ subtitle \"Axes are principal component axes\"\n"); } } xvgr_legend(out, NLEG, leg, oenv); } if (nz == 0) { gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms); } do { if (nz == 0) { gmx_rmpbc_copy(gpbc, natoms, box, x, x_s); } gyro = 0; clear_rvec(gvec); clear_rvec(gvec1); clear_rvec(d); clear_rvec(d1); for (mol = 0; mol < nmol; mol++) { tm = sub_xcm(nz == 0 ? x_s : x, nam, index+mol*nam, top.atoms.atom, xcm, bQ); if (nz == 0) { gyro += calc_gyro(x_s, nam, index+mol*nam, top.atoms.atom, tm, gvec1, d1, bQ, bRot, bMOI, trans); } else { calc_gyro_z(x, box, nam, index+mol*nam, top.atoms.atom, nz, t, out); } rvec_inc(gvec, gvec1); rvec_inc(d, d1); } if (nmol > 0) { gyro /= nmol; svmul(1.0/nmol, gvec, gvec); svmul(1.0/nmol, d, d); } if (nz == 0) { if (bRot) { if (j >= max_moi) { max_moi += delta_moi; for (m = 0; (m < DIM); m++) { srenew(moi_trans[m], max_moi*DIM); } } for (m = 0; (m < DIM); m++) { copy_rvec(trans[m], moi_trans[m]+DIM*j); } fprintf(out, "%10g %10g %10g %10g %10g\n", t, gyro, d[XX], d[YY], d[ZZ]); } else { fprintf(out, "%10g %10g %10g %10g %10g\n", t, gyro, gvec[XX], gvec[YY], gvec[ZZ]); } } j++; } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); if (nz == 0) { gmx_rmpbc_done(gpbc); } xvgrclose(out); if (bACF) { int mode = eacVector; do_autocorr(opt2fn("-acf", NFILE, fnm), oenv, "Moment of inertia vector ACF", j, 3, moi_trans, (t-t0)/j, mode, FALSE); do_view(oenv, opt2fn("-acf", NFILE, fnm), "-nxy"); } do_view(oenv, ftp2fn(efXVG, NFILE, fnm), "-nxy"); return 0; }
double do_tpi(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[], const output_env_t oenv, gmx_bool bVerbose, gmx_bool gmx_unused bCompact, int gmx_unused nstglobalcomm, gmx_vsite_t gmx_unused *vsite, gmx_constr_t gmx_unused constr, int gmx_unused stepout, t_inputrec *inputrec, gmx_mtop_t *top_global, t_fcdata *fcd, t_state *state, t_mdatoms *mdatoms, t_nrnb *nrnb, gmx_wallcycle_t wcycle, gmx_edsam_t gmx_unused ed, t_forcerec *fr, int gmx_unused repl_ex_nst, int gmx_unused repl_ex_nex, int gmx_unused repl_ex_seed, gmx_membed_t gmx_unused membed, real gmx_unused cpt_period, real gmx_unused max_hours, const char gmx_unused *deviceOptions, unsigned long gmx_unused Flags, gmx_runtime_t *runtime) { const char *TPI = "Test Particle Insertion"; gmx_localtop_t *top; gmx_groups_t *groups; gmx_enerdata_t *enerd; rvec *f; real lambda, t, temp, beta, drmax, epot; double embU, sum_embU, *sum_UgembU, V, V_all, VembU_all; t_trxstatus *status; t_trxframe rerun_fr; gmx_bool bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS, bOurStep; tensor force_vir, shake_vir, vir, pres; int cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e; rvec *x_mol; rvec mu_tot, x_init, dx, x_tp; int nnodes, frame, nsteps, step; int i, start, end; gmx_rng_t tpi_rand; FILE *fp_tpi = NULL; char *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN]; double dbl, dump_ener; gmx_bool bCavity; int nat_cavity = 0, d; real *mass_cavity = NULL, mass_tot; int nbin; double invbinw, *bin, refvolshift, logV, bUlogV; real dvdl, prescorr, enercorr, dvdlcorr; gmx_bool bEnergyOutOfBounds; const char *tpid_leg[2] = {"direct", "reweighted"}; /* Since there is no upper limit to the insertion energies, * we need to set an upper limit for the distribution output. */ real bU_bin_limit = 50; real bU_logV_bin_limit = bU_bin_limit + 10; nnodes = cr->nnodes; top = gmx_mtop_generate_local_top(top_global, inputrec); groups = &top_global->groups; bCavity = (inputrec->eI == eiTPIC); if (bCavity) { ptr = getenv("GMX_TPIC_MASSES"); if (ptr == NULL) { nat_cavity = 1; } else { /* Read (multiple) masses from env var GMX_TPIC_MASSES, * The center of mass of the last atoms is then used for TPIC. */ nat_cavity = 0; while (sscanf(ptr, "%lf%n", &dbl, &i) > 0) { srenew(mass_cavity, nat_cavity+1); mass_cavity[nat_cavity] = dbl; fprintf(fplog, "mass[%d] = %f\n", nat_cavity+1, mass_cavity[nat_cavity]); nat_cavity++; ptr += i; } if (nat_cavity == 0) { gmx_fatal(FARGS, "Found %d masses in GMX_TPIC_MASSES", nat_cavity); } } } /* init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot, state->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/ /* We never need full pbc for TPI */ fr->ePBC = epbcXYZ; /* Determine the temperature for the Boltzmann weighting */ temp = inputrec->opts.ref_t[0]; if (fplog) { for (i = 1; (i < inputrec->opts.ngtc); i++) { if (inputrec->opts.ref_t[i] != temp) { fprintf(fplog, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); fprintf(stderr, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); } } fprintf(fplog, "\n The temperature for test particle insertion is %.3f K\n\n", temp); } beta = 1.0/(BOLTZ*temp); /* Number of insertions per frame */ nsteps = inputrec->nsteps; /* Use the same neighborlist with more insertions points * in a sphere of radius drmax around the initial point */ /* This should be a proper mdp parameter */ drmax = inputrec->rtpi; /* An environment variable can be set to dump all configurations * to pdb with an insertion energy <= this value. */ dump_pdb = getenv("GMX_TPI_DUMP"); dump_ener = 0; if (dump_pdb) { sscanf(dump_pdb, "%lf", &dump_ener); } atoms2md(top_global, inputrec, 0, NULL, 0, top_global->natoms, mdatoms); update_mdatoms(mdatoms, inputrec->fepvals->init_lambda); snew(enerd, 1); init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd); snew(f, top_global->natoms); /* Print to log file */ runtime_start(runtime); print_date_and_time(fplog, cr->nodeid, "Started Test Particle Insertion", runtime); wallcycle_start(wcycle, ewcRUN); /* The last charge group is the group to be inserted */ cg_tp = top->cgs.nr - 1; a_tp0 = top->cgs.index[cg_tp]; a_tp1 = top->cgs.index[cg_tp+1]; if (debug) { fprintf(debug, "TPI cg %d, atoms %d-%d\n", cg_tp, a_tp0, a_tp1); } if (a_tp1 - a_tp0 > 1 && (inputrec->rlist < inputrec->rcoulomb || inputrec->rlist < inputrec->rvdw)) { gmx_fatal(FARGS, "Can not do TPI for multi-atom molecule with a twin-range cut-off"); } snew(x_mol, a_tp1-a_tp0); bDispCorr = (inputrec->eDispCorr != edispcNO); bCharge = FALSE; for (i = a_tp0; i < a_tp1; i++) { /* Copy the coordinates of the molecule to be insterted */ copy_rvec(state->x[i], x_mol[i-a_tp0]); /* Check if we need to print electrostatic energies */ bCharge |= (mdatoms->chargeA[i] != 0 || (mdatoms->chargeB && mdatoms->chargeB[i] != 0)); } bRFExcl = (bCharge && EEL_RF(fr->eeltype) && fr->eeltype != eelRF_NEC); calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state->x, fr->cg_cm); if (bCavity) { if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog) { fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); fprintf(stderr, "WARNING: Your TPI molecule is not centered at 0,0,0\n"); } } else { /* Center the molecule to be inserted at zero */ for (i = 0; i < a_tp1-a_tp0; i++) { rvec_dec(x_mol[i], fr->cg_cm[cg_tp]); } } if (fplog) { fprintf(fplog, "\nWill insert %d atoms %s partial charges\n", a_tp1-a_tp0, bCharge ? "with" : "without"); fprintf(fplog, "\nWill insert %d times in each frame of %s\n", nsteps, opt2fn("-rerun", nfile, fnm)); } if (!bCavity) { if (inputrec->nstlist > 1) { if (drmax == 0 && a_tp1-a_tp0 == 1) { gmx_fatal(FARGS, "Re-using the neighborlist %d times for insertions of a single atom in a sphere of radius %f does not make sense", inputrec->nstlist, drmax); } if (fplog) { fprintf(fplog, "Will use the same neighborlist for %d insertions in a sphere of radius %f\n", inputrec->nstlist, drmax); } } } else { if (fplog) { fprintf(fplog, "Will insert randomly in a sphere of radius %f around the center of the cavity\n", drmax); } } ngid = groups->grps[egcENER].nr; gid_tp = GET_CGINFO_GID(fr->cginfo[cg_tp]); nener = 1 + ngid; if (bDispCorr) { nener += 1; } if (bCharge) { nener += ngid; if (bRFExcl) { nener += 1; } if (EEL_FULL(fr->eeltype)) { nener += 1; } } snew(sum_UgembU, nener); /* Initialize random generator */ tpi_rand = gmx_rng_init(inputrec->ld_seed); if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm), "TPI energies", "Time (ps)", "(kJ mol\\S-1\\N) / (nm\\S3\\N)", oenv); xvgr_subtitle(fp_tpi, "f. are averages over one frame", oenv); snew(leg, 4+nener); e = 0; sprintf(str, "-kT log(<Ve\\S-\\betaU\\N>/<V>)"); leg[e++] = strdup(str); sprintf(str, "f. -kT log<e\\S-\\betaU\\N>"); leg[e++] = strdup(str); sprintf(str, "f. <e\\S-\\betaU\\N>"); leg[e++] = strdup(str); sprintf(str, "f. V"); leg[e++] = strdup(str); sprintf(str, "f. <Ue\\S-\\betaU\\N>"); leg[e++] = strdup(str); for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = strdup(str); } if (bDispCorr) { sprintf(str, "f. <U\\sdisp c\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } if (bCharge) { for (i = 0; i < ngid; i++) { sprintf(str, "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>", *(groups->grpname[groups->grps[egcENER].nm_ind[i]])); leg[e++] = strdup(str); } if (bRFExcl) { sprintf(str, "f. <U\\sRF excl\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } if (EEL_FULL(fr->eeltype)) { sprintf(str, "f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>"); leg[e++] = strdup(str); } } xvgr_legend(fp_tpi, 4+nener, (const char**)leg, oenv); for (i = 0; i < 4+nener; i++) { sfree(leg[i]); } sfree(leg); } clear_rvec(x_init); V_all = 0; VembU_all = 0; invbinw = 10; nbin = 10; snew(bin, nbin); bNotLastFrame = read_first_frame(oenv, &status, opt2fn("-rerun", nfile, fnm), &rerun_fr, TRX_NEED_X); frame = 0; if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) != mdatoms->nr - (a_tp1 - a_tp0)) { gmx_fatal(FARGS, "Number of atoms in trajectory (%d)%s " "is not equal the number in the run input file (%d) " "minus the number of atoms to insert (%d)\n", rerun_fr.natoms, bCavity ? " minus one" : "", mdatoms->nr, a_tp1-a_tp0); } refvolshift = log(det(rerun_fr.box)); #ifdef GMX_X86_SSE2 /* Make sure we don't detect SSE overflow generated before this point */ gmx_mm_check_and_reset_overflow(); #endif while (bNotLastFrame) { lambda = rerun_fr.lambda; t = rerun_fr.time; sum_embU = 0; for (e = 0; e < nener; e++) { sum_UgembU[e] = 0; } /* Copy the coordinates from the input trajectory */ for (i = 0; i < rerun_fr.natoms; i++) { copy_rvec(rerun_fr.x[i], state->x[i]); } copy_mat(rerun_fr.box, state->box); V = det(state->box); logV = log(V); bStateChanged = TRUE; bNS = TRUE; for (step = 0; step < nsteps; step++) { /* In parallel all nodes generate all random configurations. * In that way the result is identical to a single cpu tpi run. */ if (!bCavity) { /* Random insertion in the whole volume */ bNS = (step % inputrec->nstlist == 0); if (bNS) { /* Generate a random position in the box */ x_init[XX] = gmx_rng_uniform_real(tpi_rand)*state->box[XX][XX]; x_init[YY] = gmx_rng_uniform_real(tpi_rand)*state->box[YY][YY]; x_init[ZZ] = gmx_rng_uniform_real(tpi_rand)*state->box[ZZ][ZZ]; } if (inputrec->nstlist == 1) { copy_rvec(x_init, x_tp); } else { /* Generate coordinates within |dx|=drmax of x_init */ do { dx[XX] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax; dx[YY] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax; dx[ZZ] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax; } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } } else { /* Random insertion around a cavity location * given by the last coordinate of the trajectory. */ if (step == 0) { if (nat_cavity == 1) { /* Copy the location of the cavity */ copy_rvec(rerun_fr.x[rerun_fr.natoms-1], x_init); } else { /* Determine the center of mass of the last molecule */ clear_rvec(x_init); mass_tot = 0; for (i = 0; i < nat_cavity; i++) { for (d = 0; d < DIM; d++) { x_init[d] += mass_cavity[i]*rerun_fr.x[rerun_fr.natoms-nat_cavity+i][d]; } mass_tot += mass_cavity[i]; } for (d = 0; d < DIM; d++) { x_init[d] /= mass_tot; } } } /* Generate coordinates within |dx|=drmax of x_init */ do { dx[XX] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax; dx[YY] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax; dx[ZZ] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax; } while (norm2(dx) > drmax*drmax); rvec_add(x_init, dx, x_tp); } if (a_tp1 - a_tp0 == 1) { /* Insert a single atom, just copy the insertion location */ copy_rvec(x_tp, state->x[a_tp0]); } else { /* Copy the coordinates from the top file */ for (i = a_tp0; i < a_tp1; i++) { copy_rvec(x_mol[i-a_tp0], state->x[i]); } /* Rotate the molecule randomly */ rotate_conf(a_tp1-a_tp0, state->x+a_tp0, NULL, 2*M_PI*gmx_rng_uniform_real(tpi_rand), 2*M_PI*gmx_rng_uniform_real(tpi_rand), 2*M_PI*gmx_rng_uniform_real(tpi_rand)); /* Shift to the insertion location */ for (i = a_tp0; i < a_tp1; i++) { rvec_inc(state->x[i], x_tp); } } /* Check if this insertion belongs to this node */ bOurStep = TRUE; if (PAR(cr)) { switch (inputrec->eI) { case eiTPI: bOurStep = ((step / inputrec->nstlist) % nnodes == cr->nodeid); break; case eiTPIC: bOurStep = (step % nnodes == cr->nodeid); break; default: gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]); } } if (bOurStep) { /* Clear some matrix variables */ clear_mat(force_vir); clear_mat(shake_vir); clear_mat(vir); clear_mat(pres); /* Set the charge group center of mass of the test particle */ copy_rvec(x_init, fr->cg_cm[top->cgs.nr-1]); /* Calc energy (no forces) on new positions. * Since we only need the intermolecular energy * and the RF exclusion terms of the inserted molecule occur * within a single charge group we can pass NULL for the graph. * This also avoids shifts that would move charge groups * out of the box. * * Some checks above ensure than we can not have * twin-range interactions together with nstlist > 1, * therefore we do not need to remember the LR energies. */ /* Make do_force do a single node force calculation */ cr->nnodes = 1; do_force(fplog, cr, inputrec, step, nrnb, wcycle, top, top_global, &top_global->groups, state->box, state->x, &state->hist, f, force_vir, mdatoms, enerd, fcd, state->lambda, NULL, fr, NULL, mu_tot, t, NULL, NULL, FALSE, GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY | (bNS ? GMX_FORCE_DYNAMICBOX | GMX_FORCE_NS | GMX_FORCE_DO_LR : 0) | (bStateChanged ? GMX_FORCE_STATECHANGED : 0)); cr->nnodes = nnodes; bStateChanged = FALSE; bNS = FALSE; /* Calculate long range corrections to pressure and energy */ calc_dispcorr(fplog, inputrec, fr, step, top_global->natoms, state->box, lambda, pres, vir, &prescorr, &enercorr, &dvdlcorr); /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */ enerd->term[F_DISPCORR] = enercorr; enerd->term[F_EPOT] += enercorr; enerd->term[F_PRES] += prescorr; enerd->term[F_DVDL_VDW] += dvdlcorr; epot = enerd->term[F_EPOT]; bEnergyOutOfBounds = FALSE; #ifdef GMX_X86_SSE2 /* With SSE the energy can overflow, check for this */ if (gmx_mm_check_and_reset_overflow()) { if (debug) { fprintf(debug, "Found an SSE overflow, assuming the energy is out of bounds\n"); } bEnergyOutOfBounds = TRUE; } #endif /* If the compiler doesn't optimize this check away * we catch the NAN energies. * The epot>GMX_REAL_MAX check catches inf values, * which should nicely result in embU=0 through the exp below, * but it does not hurt to check anyhow. */ /* Non-bonded Interaction usually diverge at r=0. * With tabulated interaction functions the first few entries * should be capped in a consistent fashion between * repulsion, dispersion and Coulomb to avoid accidental * negative values in the total energy. * The table generation code in tables.c does this. * With user tbales the user should take care of this. */ if (epot != epot || epot > GMX_REAL_MAX) { bEnergyOutOfBounds = TRUE; } if (bEnergyOutOfBounds) { if (debug) { fprintf(debug, "\n time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n", t, step, epot); } embU = 0; } else { embU = exp(-beta*epot); sum_embU += embU; /* Determine the weighted energy contributions of each energy group */ e = 0; sum_UgembU[e++] += epot*embU; if (fr->bBHAM) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egBHAMSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egBHAMLR][GID(i, gid_tp, ngid)])*embU; } } else { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egLJSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egLJLR][GID(i, gid_tp, ngid)])*embU; } } if (bDispCorr) { sum_UgembU[e++] += enerd->term[F_DISPCORR]*embU; } if (bCharge) { for (i = 0; i < ngid; i++) { sum_UgembU[e++] += (enerd->grpp.ener[egCOULSR][GID(i, gid_tp, ngid)] + enerd->grpp.ener[egCOULLR][GID(i, gid_tp, ngid)])*embU; } if (bRFExcl) { sum_UgembU[e++] += enerd->term[F_RF_EXCL]*embU; } if (EEL_FULL(fr->eeltype)) { sum_UgembU[e++] += enerd->term[F_COUL_RECIP]*embU; } } } if (embU == 0 || beta*epot > bU_bin_limit) { bin[0]++; } else { i = (int)((bU_logV_bin_limit - (beta*epot - logV + refvolshift))*invbinw + 0.5); if (i < 0) { i = 0; } if (i >= nbin) { realloc_bins(&bin, &nbin, i+10); } bin[i]++; } if (debug) { fprintf(debug, "TPI %7d %12.5e %12.5f %12.5f %12.5f\n", step, epot, x_tp[XX], x_tp[YY], x_tp[ZZ]); } if (dump_pdb && epot <= dump_ener) { sprintf(str, "t%g_step%d.pdb", t, step); sprintf(str2, "t: %f step %d ener: %f", t, step, epot); write_sto_conf_mtop(str, str2, top_global, state->x, state->v, inputrec->ePBC, state->box); } } } if (PAR(cr)) { /* When running in parallel sum the energies over the processes */ gmx_sumd(1, &sum_embU, cr); gmx_sumd(nener, sum_UgembU, cr); } frame++; V_all += V; VembU_all += V*sum_embU/nsteps; if (fp_tpi) { if (bVerbose || frame%10 == 0 || frame < 10) { fprintf(stderr, "mu %10.3e <mu> %10.3e\n", -log(sum_embU/nsteps)/beta, -log(VembU_all/V_all)/beta); } fprintf(fp_tpi, "%10.3f %12.5e %12.5e %12.5e %12.5e", t, VembU_all == 0 ? 20/beta : -log(VembU_all/V_all)/beta, sum_embU == 0 ? 20/beta : -log(sum_embU/nsteps)/beta, sum_embU/nsteps, V); for (e = 0; e < nener; e++) { fprintf(fp_tpi, " %12.5e", sum_UgembU[e]/nsteps); } fprintf(fp_tpi, "\n"); fflush(fp_tpi); } bNotLastFrame = read_next_frame(oenv, status, &rerun_fr); } /* End of the loop */ runtime_end(runtime); close_trj(status); if (fp_tpi != NULL) { gmx_fio_fclose(fp_tpi); } if (fplog != NULL) { fprintf(fplog, "\n"); fprintf(fplog, " <V> = %12.5e nm^3\n", V_all/frame); fprintf(fplog, " <mu> = %12.5e kJ/mol\n", -log(VembU_all/V_all)/beta); } /* Write the Boltzmann factor histogram */ if (PAR(cr)) { /* When running in parallel sum the bins over the processes */ i = nbin; global_max(cr, &i); realloc_bins(&bin, &nbin, i); gmx_sumd(nbin, bin, cr); } if (MASTER(cr)) { fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm), "TPI energy distribution", "\\betaU - log(V/<V>)", "count", oenv); sprintf(str, "number \\betaU > %g: %9.3e", bU_bin_limit, bin[0]); xvgr_subtitle(fp_tpi, str, oenv); xvgr_legend(fp_tpi, 2, (const char **)tpid_leg, oenv); for (i = nbin-1; i > 0; i--) { bUlogV = -i/invbinw + bU_logV_bin_limit - refvolshift + log(V_all/frame); fprintf(fp_tpi, "%6.2f %10d %12.5e\n", bUlogV, (int)(bin[i]+0.5), bin[i]*exp(-bUlogV)*V_all/VembU_all); } gmx_fio_fclose(fp_tpi); } sfree(bin); sfree(sum_UgembU); runtime->nsteps_done = frame*inputrec->nsteps; return 0; }
void calc_h2order(const char *fn, atom_id index[], int ngx, rvec **slDipole, real **slOrder, real *slWidth, int *nslices, t_topology *top, int ePBC, int axis, gmx_bool bMicel, atom_id micel[], int nmic, const output_env_t oenv) { rvec *x0, /* coordinates with pbc */ dipole, /* dipole moment due to one molecules */ normal, com; /* center of mass of micel, with bMicel */ rvec *dip; /* sum of dipoles, unnormalized */ matrix box; /* box (3x3) */ t_trxstatus *status; real t, /* time from trajectory */ *sum, /* sum of all cosines of dipoles, per slice */ *frame; /* order over one frame */ int natoms, /* nr. atoms in trj */ i, j, teller = 0, slice = 0, /* current slice number */ *count; /* nr. of atoms in one slice */ gmx_rmpbc_t gpbc = NULL; if ((natoms = read_first_x(oenv, &status, fn, &t, &x0, box)) == 0) { gmx_fatal(FARGS, "Could not read coordinates from statusfile\n"); } if (!*nslices) { *nslices = (int)(box[axis][axis] * 10); /* default value */ } switch (axis) { case 0: normal[0] = 1; normal[1] = 0; normal[2] = 0; break; case 1: normal[0] = 0; normal[1] = 1; normal[2] = 0; break; case 2: normal[0] = 0; normal[1] = 0; normal[2] = 1; break; default: gmx_fatal(FARGS, "No valid value for -axis-. Exiting.\n"); /* make compiler happy */ normal[0] = 1; normal[1] = 0; normal[2] = 0; } clear_rvec(dipole); snew(count, *nslices); snew(sum, *nslices); snew(dip, *nslices); snew(frame, *nslices); *slWidth = box[axis][axis]/(*nslices); fprintf(stderr, "Box divided in %d slices. Initial width of slice: %f\n", *nslices, *slWidth); teller = 0; gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms); /*********** Start processing trajectory ***********/ do { *slWidth = box[axis][axis]/(*nslices); teller++; gmx_rmpbc(gpbc, natoms, box, x0); if (bMicel) { calc_xcm(x0, nmic, micel, top->atoms.atom, com, FALSE); } for (i = 0; i < ngx/3; i++) { /* put all waters in box */ for (j = 0; j < DIM; j++) { if (x0[index[3*i]][j] < 0) { x0[index[3*i]][j] += box[j][j]; x0[index[3*i+1]][j] += box[j][j]; x0[index[3*i+2]][j] += box[j][j]; } if (x0[index[3*i]][j] > box[j][j]) { x0[index[3*i]][j] -= box[j][j]; x0[index[3*i+1]][j] -= box[j][j]; x0[index[3*i+2]][j] -= box[j][j]; } } for (j = 0; j < DIM; j++) { dipole[j] = x0[index[3*i]][j] * top->atoms.atom[index[3*i]].q + x0[index[3*i+1]][j] * top->atoms.atom[index[3*i+1]].q + x0[index[3*i+2]][j] * top->atoms.atom[index[3*i+2]].q; } /* now we have a dipole vector. Might as well safe it. Then the rest depends on whether we're dealing with a flat or a spherical interface. */ if (bMicel) { /* this is for spherical interfaces */ rvec_sub(com, x0[index[3*i]], normal); /* vector from Oxygen to COM */ slice = norm(normal)/(*slWidth); /* spherical slice */ sum[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal)); frame[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal)); count[slice]++; } else { /* this is for flat interfaces */ /* determine which slice atom is in */ slice = (x0[index[3*i]][axis] / (*slWidth)); if (slice < 0 || slice >= *nslices) { fprintf(stderr, "Coordinate: %f ", x0[index[3*i]][axis]); fprintf(stderr, "HELP PANIC! slice = %d, OUT OF RANGE!\n", slice); } else { rvec_add(dipole, dip[slice], dip[slice]); /* Add dipole to total. mag[slice] is total dipole in axis direction */ sum[slice] += iprod(dipole, normal)/norm(dipole); frame[slice] += iprod(dipole, normal)/norm(dipole); /* increase count for that slice */ count[slice]++; } } } } while (read_next_x(oenv, status, &t, x0, box)); /*********** done with status file **********/ fprintf(stderr, "\nRead trajectory. Printing parameters to file\n"); gmx_rmpbc_done(gpbc); for (i = 0; i < *nslices; i++) /* average over frames */ { fprintf(stderr, "%d waters in slice %d\n", count[i], i); if (count[i] > 0) /* divide by number of molecules in each slice */ { sum[i] = sum[i] / count[i]; dip[i][XX] = dip[i][XX] / count[i]; dip[i][YY] = dip[i][YY] / count[i]; dip[i][ZZ] = dip[i][ZZ] / count[i]; } else { fprintf(stderr, "No water in slice %d\n", i); } } *slOrder = sum; /* copy a pointer, I hope */ *slDipole = dip; sfree(x0); /* free memory used by coordinate arrays */ }
int gmx_helixorient(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] calculates the coordinates and direction of the average", "axis inside an alpha helix, and the direction/vectors of both the", "C[GRK]alpha[grk] and (optionally) a sidechain atom relative to the axis.[PAR]", "As input, you need to specify an index group with C[GRK]alpha[grk] atoms", "corresponding to an [GRK]alpha[grk]-helix of continuous residues. Sidechain", "directions require a second index group of the same size, containing", "the heavy atom in each residue that should represent the sidechain.[PAR]", "[BB]Note[bb] that this program does not do any fitting of structures.[PAR]", "We need four C[GRK]alpha[grk] coordinates to define the local direction of the helix", "axis.[PAR]", "The tilt/rotation is calculated from Euler rotations, where we define", "the helix axis as the local [IT]x[it]-axis, the residues/C[GRK]alpha[grk] vector as [IT]y[it], and the", "[IT]z[it]-axis from their cross product. We use the Euler Y-Z-X rotation, meaning", "we first tilt the helix axis (1) around and (2) orthogonal to the residues", "vector, and finally apply the (3) rotation around it. For debugging or other", "purposes, we also write out the actual Euler rotation angles as [TT]theta[1-3].xvg[tt]" }; t_topology *top = NULL; real t; rvec *x = NULL; matrix box; t_trxstatus *status; int natoms; real theta1, theta2, theta3; int i, j, teller = 0; int iCA, iSC; atom_id *ind_CA; atom_id *ind_SC; char *gn_CA; char *gn_SC; rvec v1, v2; rvec *x_CA, *x_SC; rvec *r12; rvec *r23; rvec *r34; rvec *diff13; rvec *diff24; rvec *helixaxis; rvec *residuehelixaxis; rvec *residueorigin; rvec *residuevector; rvec *sidechainvector; rvec *residuehelixaxis_t0; rvec *residuevector_t0; rvec *axis3_t0; rvec *residuehelixaxis_tlast; rvec *residuevector_tlast; rvec *axis3_tlast; rvec refaxes[3], newaxes[3]; rvec unitaxes[3]; rvec rot_refaxes[3], rot_newaxes[3]; real tilt, rotation; rvec *axis3; real *twist, *residuetwist; real *radius, *residueradius; real *rise, *residuerise; real *residuebending; real tmp; real weight[3]; t_pbc pbc; matrix A; FILE *fpaxis, *fpcenter, *fptilt, *fprotation; FILE *fpradius, *fprise, *fptwist; FILE *fptheta1, *fptheta2, *fptheta3; FILE *fpbending; int ePBC; gmx_output_env_t *oenv; gmx_rmpbc_t gpbc = NULL; static gmx_bool bSC = FALSE; static gmx_bool bIncremental = FALSE; static t_pargs pa[] = { { "-sidechain", FALSE, etBOOL, {&bSC}, "Calculate sidechain directions relative to helix axis too." }, { "-incremental", FALSE, etBOOL, {&bIncremental}, "Calculate incremental rather than total rotation/tilt." }, }; #define NPA asize(pa) t_filenm fnm[] = { { efTPR, NULL, NULL, ffREAD }, { efTRX, "-f", NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efDAT, "-oaxis", "helixaxis", ffWRITE }, { efDAT, "-ocenter", "center", ffWRITE }, { efXVG, "-orise", "rise", ffWRITE }, { efXVG, "-oradius", "radius", ffWRITE }, { efXVG, "-otwist", "twist", ffWRITE }, { efXVG, "-obending", "bending", ffWRITE }, { efXVG, "-otilt", "tilt", ffWRITE }, { efXVG, "-orot", "rotation", ffWRITE } }; #define NFILE asize(fnm) if (!parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } top = read_top(ftp2fn(efTPR, NFILE, fnm), &ePBC); for (i = 0; i < 3; i++) { weight[i] = 1.0; } /* read index files */ printf("Select a group of Calpha atoms corresponding to a single continuous helix:\n"); get_index(&(top->atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &iCA, &ind_CA, &gn_CA); snew(x_CA, iCA); snew(x_SC, iCA); /* sic! */ snew(r12, iCA-3); snew(r23, iCA-3); snew(r34, iCA-3); snew(diff13, iCA-3); snew(diff24, iCA-3); snew(helixaxis, iCA-3); snew(twist, iCA); snew(residuetwist, iCA); snew(radius, iCA); snew(residueradius, iCA); snew(rise, iCA); snew(residuerise, iCA); snew(residueorigin, iCA); snew(residuehelixaxis, iCA); snew(residuevector, iCA); snew(sidechainvector, iCA); snew(residuebending, iCA); snew(residuehelixaxis_t0, iCA); snew(residuevector_t0, iCA); snew(axis3_t0, iCA); snew(residuehelixaxis_tlast, iCA); snew(residuevector_tlast, iCA); snew(axis3_tlast, iCA); snew(axis3, iCA); if (bSC) { printf("Select a group of atoms defining the sidechain direction (1/residue):\n"); get_index(&(top->atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &iSC, &ind_SC, &gn_SC); if (iSC != iCA) { gmx_fatal(FARGS, "Number of sidechain atoms (%d) != number of CA atoms (%d)", iSC, iCA); } } natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); fpaxis = gmx_ffopen(opt2fn("-oaxis", NFILE, fnm), "w"); fpcenter = gmx_ffopen(opt2fn("-ocenter", NFILE, fnm), "w"); fprise = gmx_ffopen(opt2fn("-orise", NFILE, fnm), "w"); fpradius = gmx_ffopen(opt2fn("-oradius", NFILE, fnm), "w"); fptwist = gmx_ffopen(opt2fn("-otwist", NFILE, fnm), "w"); fpbending = gmx_ffopen(opt2fn("-obending", NFILE, fnm), "w"); fptheta1 = gmx_ffopen("theta1.xvg", "w"); fptheta2 = gmx_ffopen("theta2.xvg", "w"); fptheta3 = gmx_ffopen("theta3.xvg", "w"); if (bIncremental) { fptilt = xvgropen(opt2fn("-otilt", NFILE, fnm), "Incremental local helix tilt", "Time(ps)", "Tilt (degrees)", oenv); fprotation = xvgropen(opt2fn("-orot", NFILE, fnm), "Incremental local helix rotation", "Time(ps)", "Rotation (degrees)", oenv); } else { fptilt = xvgropen(opt2fn("-otilt", NFILE, fnm), "Cumulative local helix tilt", "Time(ps)", "Tilt (degrees)", oenv); fprotation = xvgropen(opt2fn("-orot", NFILE, fnm), "Cumulative local helix rotation", "Time(ps)", "Rotation (degrees)", oenv); } clear_rvecs(3, unitaxes); unitaxes[0][0] = 1; unitaxes[1][1] = 1; unitaxes[2][2] = 1; gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms); do { /* initialisation for correct distance calculations */ set_pbc(&pbc, ePBC, box); /* make molecules whole again */ gmx_rmpbc(gpbc, natoms, box, x); /* copy coords to our smaller arrays */ for (i = 0; i < iCA; i++) { copy_rvec(x[ind_CA[i]], x_CA[i]); if (bSC) { copy_rvec(x[ind_SC[i]], x_SC[i]); } } for (i = 0; i < iCA-3; i++) { rvec_sub(x_CA[i+1], x_CA[i], r12[i]); rvec_sub(x_CA[i+2], x_CA[i+1], r23[i]); rvec_sub(x_CA[i+3], x_CA[i+2], r34[i]); rvec_sub(r12[i], r23[i], diff13[i]); rvec_sub(r23[i], r34[i], diff24[i]); /* calculate helix axis */ cprod(diff13[i], diff24[i], helixaxis[i]); svmul(1.0/norm(helixaxis[i]), helixaxis[i], helixaxis[i]); tmp = cos_angle(diff13[i], diff24[i]); twist[i] = 180.0/M_PI * std::acos( tmp ); radius[i] = std::sqrt( norm(diff13[i])*norm(diff24[i]) ) / (2.0* (1.0-tmp) ); rise[i] = std::abs(iprod(r23[i], helixaxis[i])); svmul(radius[i]/norm(diff13[i]), diff13[i], v1); svmul(radius[i]/norm(diff24[i]), diff24[i], v2); rvec_sub(x_CA[i+1], v1, residueorigin[i+1]); rvec_sub(x_CA[i+2], v2, residueorigin[i+2]); } residueradius[0] = residuetwist[0] = residuerise[0] = 0; residueradius[1] = radius[0]; residuetwist[1] = twist[0]; residuerise[1] = rise[0]; residuebending[0] = residuebending[1] = 0; for (i = 2; i < iCA-2; i++) { residueradius[i] = 0.5*(radius[i-2]+radius[i-1]); residuetwist[i] = 0.5*(twist[i-2]+twist[i-1]); residuerise[i] = 0.5*(rise[i-2]+rise[i-1]); residuebending[i] = 180.0/M_PI*std::acos( cos_angle(helixaxis[i-2], helixaxis[i-1]) ); } residueradius[iCA-2] = radius[iCA-4]; residuetwist[iCA-2] = twist[iCA-4]; residuerise[iCA-2] = rise[iCA-4]; residueradius[iCA-1] = residuetwist[iCA-1] = residuerise[iCA-1] = 0; residuebending[iCA-2] = residuebending[iCA-1] = 0; clear_rvec(residueorigin[0]); clear_rvec(residueorigin[iCA-1]); /* average helix axes to define them on the residues. * Just extrapolate second first/list atom. */ copy_rvec(helixaxis[0], residuehelixaxis[0]); copy_rvec(helixaxis[0], residuehelixaxis[1]); for (i = 2; i < iCA-2; i++) { rvec_add(helixaxis[i-2], helixaxis[i-1], residuehelixaxis[i]); svmul(0.5, residuehelixaxis[i], residuehelixaxis[i]); } copy_rvec(helixaxis[iCA-4], residuehelixaxis[iCA-2]); copy_rvec(helixaxis[iCA-4], residuehelixaxis[iCA-1]); /* Normalize the axis */ for (i = 0; i < iCA; i++) { svmul(1.0/norm(residuehelixaxis[i]), residuehelixaxis[i], residuehelixaxis[i]); } /* calculate vector from origin to residue CA */ fprintf(fpaxis, "%15.12g ", t); fprintf(fpcenter, "%15.12g ", t); fprintf(fprise, "%15.12g ", t); fprintf(fpradius, "%15.12g ", t); fprintf(fptwist, "%15.12g ", t); fprintf(fpbending, "%15.12g ", t); for (i = 0; i < iCA; i++) { if (i == 0 || i == iCA-1) { fprintf(fpaxis, "%15.12g %15.12g %15.12g ", 0.0, 0.0, 0.0); fprintf(fpcenter, "%15.12g %15.12g %15.12g ", 0.0, 0.0, 0.0); fprintf(fprise, "%15.12g ", 0.0); fprintf(fpradius, "%15.12g ", 0.0); fprintf(fptwist, "%15.12g ", 0.0); fprintf(fpbending, "%15.12g ", 0.0); } else { rvec_sub( bSC ? x_SC[i] : x_CA[i], residueorigin[i], residuevector[i]); svmul(1.0/norm(residuevector[i]), residuevector[i], residuevector[i]); cprod(residuehelixaxis[i], residuevector[i], axis3[i]); fprintf(fpaxis, "%15.12g %15.12g %15.12g ", residuehelixaxis[i][0], residuehelixaxis[i][1], residuehelixaxis[i][2]); fprintf(fpcenter, "%15.12g %15.12g %15.12g ", residueorigin[i][0], residueorigin[i][1], residueorigin[i][2]); fprintf(fprise, "%15.12g ", residuerise[i]); fprintf(fpradius, "%15.12g ", residueradius[i]); fprintf(fptwist, "%15.12g ", residuetwist[i]); fprintf(fpbending, "%15.12g ", residuebending[i]); } } fprintf(fprise, "\n"); fprintf(fpradius, "\n"); fprintf(fpaxis, "\n"); fprintf(fpcenter, "\n"); fprintf(fptwist, "\n"); fprintf(fpbending, "\n"); if (teller == 0) { for (i = 0; i < iCA; i++) { copy_rvec(residuehelixaxis[i], residuehelixaxis_t0[i]); copy_rvec(residuevector[i], residuevector_t0[i]); copy_rvec(axis3[i], axis3_t0[i]); } } else { fprintf(fptilt, "%15.12g ", t); fprintf(fprotation, "%15.12g ", t); fprintf(fptheta1, "%15.12g ", t); fprintf(fptheta2, "%15.12g ", t); fprintf(fptheta3, "%15.12g ", t); for (i = 0; i < iCA; i++) { if (i == 0 || i == iCA-1) { tilt = rotation = 0; } else { if (!bIncremental) { /* Total rotation & tilt */ copy_rvec(residuehelixaxis_t0[i], refaxes[0]); copy_rvec(residuevector_t0[i], refaxes[1]); copy_rvec(axis3_t0[i], refaxes[2]); } else { /* Rotation/tilt since last step */ copy_rvec(residuehelixaxis_tlast[i], refaxes[0]); copy_rvec(residuevector_tlast[i], refaxes[1]); copy_rvec(axis3_tlast[i], refaxes[2]); } copy_rvec(residuehelixaxis[i], newaxes[0]); copy_rvec(residuevector[i], newaxes[1]); copy_rvec(axis3[i], newaxes[2]); /* rotate reference frame onto unit axes */ calc_fit_R(3, 3, weight, unitaxes, refaxes, A); for (j = 0; j < 3; j++) { mvmul(A, refaxes[j], rot_refaxes[j]); mvmul(A, newaxes[j], rot_newaxes[j]); } /* Determine local rotation matrix A */ calc_fit_R(3, 3, weight, rot_newaxes, rot_refaxes, A); /* Calculate euler angles, from rotation order y-z-x, where * x is helixaxis, y residuevector, and z axis3. * * A contains rotation column vectors. */ theta1 = 180.0/M_PI*std::atan2(A[0][2], A[0][0]); theta2 = 180.0/M_PI*std::asin(-A[0][1]); theta3 = 180.0/M_PI*std::atan2(A[2][1], A[1][1]); tilt = std::sqrt(theta1*theta1+theta2*theta2); rotation = theta3; fprintf(fptheta1, "%15.12g ", theta1); fprintf(fptheta2, "%15.12g ", theta2); fprintf(fptheta3, "%15.12g ", theta3); } fprintf(fptilt, "%15.12g ", tilt); fprintf(fprotation, "%15.12g ", rotation); } fprintf(fptilt, "\n"); fprintf(fprotation, "\n"); fprintf(fptheta1, "\n"); fprintf(fptheta2, "\n"); fprintf(fptheta3, "\n"); } for (i = 0; i < iCA; i++) { copy_rvec(residuehelixaxis[i], residuehelixaxis_tlast[i]); copy_rvec(residuevector[i], residuevector_tlast[i]); copy_rvec(axis3[i], axis3_tlast[i]); } teller++; } while (read_next_x(oenv, status, &t, x, box)); gmx_rmpbc_done(gpbc); gmx_ffclose(fpaxis); gmx_ffclose(fpcenter); xvgrclose(fptilt); xvgrclose(fprotation); gmx_ffclose(fprise); gmx_ffclose(fpradius); gmx_ffclose(fptwist); gmx_ffclose(fpbending); gmx_ffclose(fptheta1); gmx_ffclose(fptheta2); gmx_ffclose(fptheta3); close_trj(status); return 0; }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j, status; int donb_flags; gmx_bool bDoEpot, bSepDVDL, bSB; int pme_flags; matrix boxs; rvec box_size; real Vsr, Vlr, Vcorr = 0; t_pbc pbc; real dvdgb; char buf[22]; double clam_i, vlam_i; real dvdl_dum[efptNR], dvdl, dvdl_nb[efptNR], lam_i[efptNR]; real dvdlsum; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s, v, dvdlambda) if (bSepDVDL) {fprintf(fplog, sepdvdlformat, s, v, dvdlambda); } GMX_MPE_LOG(ev_force_start); set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } bSepDVDL = (fr->bSepDVDL && do_per_step(step, ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr, md); } if (bSepDVDL) { fprintf(fplog, "Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step, buf), cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ dvdl = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); PRINT_SEPDVDL("Walls", 0.0, dvdl); enerd->dvdl_lin[efptVDW] += dvdl; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, atype, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &enerd->grpp, box_size, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), box_size, nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsBONDED); calc_gb_forces(cr, md, born, top, atype, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, bBornRadii, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsBONDED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } Vsr = 0; if (bSepDVDL) { for (i = 0; i < enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } dvdlsum = dvdl_nb[efptVDW] + dvdl_nb[efptCOUL]; PRINT_SEPDVDL("VdW and Coulomb SR particle-p.", Vsr, dvdlsum); } debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); wallcycle_sub_start(wcycle, ewcsBONDED); calc_bonds(fplog, cr->ms, idef, x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, flags, fr->bSepDVDL && do_per_step(step, ir->nstlog), step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } for (i = 0; i < enerd->n_lambda; i++) { reset_foreign_enerdata(enerd); for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } calc_bonds_lambda(fplog, idef, x, fr, &pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); wallcycle_sub_stop(wcycle, ewcsBONDED); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { Vcorr = 0; dvdl = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = gmx_omp_nthreads_get(emntBonded); #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { int s, e, i; rvec *fnv; tensor *vir; real *Vcorrt, *dvdlt; if (t == 0) { fnv = fr->f_novirsum; vir = &fr->vir_el_recip; Vcorrt = &Vcorr; dvdlt = &dvdl; } else { fnv = fr->f_t[t].f; vir = &fr->f_t[t].vir; Vcorrt = &fr->f_t[t].Vcorr; dvdlt = &fr->f_t[t].dvdl[efptCOUL]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir); } *dvdlt = 0; *Vcorrt = ewald_LRcorrection(fplog, fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir, lambda[efptCOUL], dvdlt); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, &Vcorr, efptCOUL, &dvdl, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (fr->n_tpi == 0) { Vcorr += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl, fr->vir_el_recip); } PRINT_SEPDVDL("Ewald excl./charge/dip. corr.", Vcorr, dvdl); enerd->dvdl_lin[efptCOUL] += dvdl; } status = 0; Vlr = 0; dvdl = 0; switch (fr->eeltype) { case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: case eelP3M_AD: if (cr->duty & DUTY_PME) { assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle, ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, bSB ? boxs : box, cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle, fr->vir_el_recip, fr->ewaldcoeff, &Vlr, lambda[efptCOUL], &dvdl, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata, fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh", Vlr, dvdl); } break; case eelEWALD: Vlr = do_ewald(fplog, FALSE, ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff, lambda[efptCOUL], &dvdl, fr->ewald_table); PRINT_SEPDVDL("Ewald long-range", Vlr, dvdl); break; default: gmx_fatal(FARGS, "No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS, "Error %d in long range electrostatics routine %s", status, EELTYPE(fr->eeltype)); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug, "Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr, Vcorr, enerd->term[F_COUL_RECIP]); pr_rvecs(debug, 0, "vir_el_recip after corr", fr->vir_el_recip, DIM); pr_rvecs(debug, 0, "fshift after LR Corrections", fr->fshift, SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET && fr->eeltype != eelRF_NEC) { dvdl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fplog, fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl); } enerd->dvdl_lin[efptCOUL] += dvdl; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL], dvdl); } } where(); debug_gmx(); if (debug) { print_nrnb(debug, nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2 = MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3 = MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr, "* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps, buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug, 0, "fshift after bondeds", fr->fshift, SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
int gmx_velacc(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the velocity autocorrelation function.", "When the [TT]-m[tt] option is used, the momentum autocorrelation", "function is calculated.[PAR]", "With option [TT]-mol[tt] the velocity autocorrelation function of", "molecules is calculated. In this case the index group should consist", "of molecule numbers instead of atom numbers.[PAR]", "Be sure that your trajectory contains frames with velocity information", "(i.e. [TT]nstvout[tt] was set in your original [REF].mdp[ref] file),", "and that the time interval between data collection points is", "much shorter than the time scale of the autocorrelation." }; static gmx_bool bMass = FALSE, bMol = FALSE, bRecip = TRUE; t_pargs pa[] = { { "-m", FALSE, etBOOL, {&bMass}, "Calculate the momentum autocorrelation function" }, { "-recip", FALSE, etBOOL, {&bRecip}, "Use cm^-1 on X-axis instead of 1/ps for spectra." }, { "-mol", FALSE, etBOOL, {&bMol}, "Calculate the velocity acf of molecules" } }; t_topology top; int ePBC = -1; t_trxframe fr; matrix box; gmx_bool bTPS = FALSE, bTop = FALSE; int gnx; atom_id *index; char *grpname; /* t0, t1 are the beginning and end time respectively. * dt is the time step, mass is temp variable for atomic mass. */ real t0, t1, dt, mass; t_trxstatus *status; int counter, n_alloc, i, j, counter_dim, k, l; rvec mv_mol; /* Array for the correlation function */ real **c1; real *normm = NULL; output_env_t oenv; #define NHISTO 360 t_filenm fnm[] = { { efTRN, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, "-o", "vac", ffWRITE }, { efXVG, "-os", "spectrum", ffOPTWR } }; #define NFILE asize(fnm) int npargs; t_pargs *ppa; npargs = asize(pa); ppa = add_acf_pargs(&npargs, pa); if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } if (bMol || bMass) { bTPS = ftp2bSet(efTPS, NFILE, fnm) || !ftp2bSet(efNDX, NFILE, fnm); } if (bTPS) { bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, NULL, NULL, box, TRUE); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); } else { rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); } if (bMol) { if (!bTop) { gmx_fatal(FARGS, "Need a topology to determine the molecules"); } snew(normm, top.atoms.nr); precalc(top, normm); index_atom2mol(&gnx, index, &top.mols); } /* Correlation stuff */ snew(c1, gnx); for (i = 0; (i < gnx); i++) { c1[i] = NULL; } read_first_frame(oenv, &status, ftp2fn(efTRN, NFILE, fnm), &fr, TRX_NEED_V); t0 = fr.time; n_alloc = 0; counter = 0; do { if (counter >= n_alloc) { n_alloc += 100; for (i = 0; i < gnx; i++) { srenew(c1[i], DIM*n_alloc); } } counter_dim = DIM*counter; if (bMol) { for (i = 0; i < gnx; i++) { clear_rvec(mv_mol); k = top.mols.index[index[i]]; l = top.mols.index[index[i]+1]; for (j = k; j < l; j++) { if (bMass) { mass = top.atoms.atom[j].m; } else { mass = normm[j]; } mv_mol[XX] += mass*fr.v[j][XX]; mv_mol[YY] += mass*fr.v[j][YY]; mv_mol[ZZ] += mass*fr.v[j][ZZ]; } c1[i][counter_dim+XX] = mv_mol[XX]; c1[i][counter_dim+YY] = mv_mol[YY]; c1[i][counter_dim+ZZ] = mv_mol[ZZ]; } } else { for (i = 0; i < gnx; i++) { if (bMass) { mass = top.atoms.atom[index[i]].m; } else { mass = 1; } c1[i][counter_dim+XX] = mass*fr.v[index[i]][XX]; c1[i][counter_dim+YY] = mass*fr.v[index[i]][YY]; c1[i][counter_dim+ZZ] = mass*fr.v[index[i]][ZZ]; } } t1 = fr.time; counter++; } while (read_next_frame(oenv, status, &fr)); close_trj(status); if (counter >= 4) { /* Compute time step between frames */ dt = (t1-t0)/(counter-1); do_autocorr(opt2fn("-o", NFILE, fnm), oenv, bMass ? "Momentum Autocorrelation Function" : "Velocity Autocorrelation Function", counter, gnx, c1, dt, eacVector, TRUE); do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); if (opt2bSet("-os", NFILE, fnm)) { calc_spectrum(counter/2, (real *) (c1[0]), (t1-t0)/2, opt2fn("-os", NFILE, fnm), oenv, bRecip); do_view(oenv, opt2fn("-os", NFILE, fnm), "-nxy"); } } else { fprintf(stderr, "Not enough frames in trajectory - no output generated.\n"); } return 0; }
static void calc_cgcm_av_stddev(t_block *cgs,int n,rvec *x,rvec av,rvec stddev, t_commrec *cr_sum) { int *cgindex; dvec s1,s2; double buf[7]; int cg,d,k0,k1,k,nrcg; real inv_ncg; rvec cg_cm; clear_dvec(s1); clear_dvec(s2); cgindex = cgs->index; for(cg=0; cg<n; cg++) { k0 = cgindex[cg]; k1 = cgindex[cg+1]; nrcg = k1 - k0; if (nrcg == 1) { copy_rvec(x[k0],cg_cm); } else { inv_ncg = 1.0/nrcg; clear_rvec(cg_cm); for(k=k0; (k<k1); k++) { rvec_inc(cg_cm,x[k]); } for(d=0; (d<DIM); d++) { cg_cm[d] *= inv_ncg; } } for(d=0; d<DIM; d++) { s1[d] += cg_cm[d]; s2[d] += cg_cm[d]*cg_cm[d]; } } if (cr_sum != NULL) { for(d=0; d<DIM; d++) { buf[d] = s1[d]; buf[DIM+d] = s2[d]; } buf[6] = n; gmx_sumd(7,buf,cr_sum); for(d=0; d<DIM; d++) { s1[d] = buf[d]; s2[d] = buf[DIM+d]; } n = (int)(buf[6] + 0.5); } dsvmul(1.0/n,s1,s1); dsvmul(1.0/n,s2,s2); for(d=0; d<DIM; d++) { av[d] = s1[d]; stddev[d] = sqrt(s2[d] - s1[d]*s1[d]); } }
static void set_tric_dir(ivec *dd_nc,gmx_ddbox_t *ddbox,matrix box) { int npbcdim,d,i,j; rvec *v,*normal; real dep,inv_skew_fac2; npbcdim = ddbox->npbcdim; normal = ddbox->normal; for(d=0; d<DIM; d++) { ddbox->tric_dir[d] = 0; for(j=d+1; j<npbcdim; j++) { if (box[j][d] != 0) { ddbox->tric_dir[d] = 1; if (dd_nc != NULL && (*dd_nc)[j] > 1 && (*dd_nc)[d] == 1) { gmx_fatal(FARGS,"Domain decomposition has not been implemented for box vectors that have non-zero components in directions that do not use domain decomposition: ncells = %d %d %d, box vector[%d] = %f %f %f", dd_nc[XX],dd_nc[YY],dd_nc[ZZ], j+1,box[j][XX],box[j][YY],box[j][ZZ]); } } } /* Convert box vectors to orthogonal vectors for this dimension, * for use in distance calculations. * Set the trilinic skewing factor that translates * the thickness of a slab perpendicular to this dimension * into the real thickness of the slab. */ if (ddbox->tric_dir[d]) { inv_skew_fac2 = 1; v = ddbox->v[d]; if (d == XX || d == YY) { /* Normalize such that the "diagonal" is 1 */ svmul(1/box[d+1][d+1],box[d+1],v[d+1]); for(i=0; i<d; i++) { v[d+1][i] = 0; } inv_skew_fac2 += sqr(v[d+1][d]); if (d == XX) { /* Normalize such that the "diagonal" is 1 */ svmul(1/box[d+2][d+2],box[d+2],v[d+2]); for(i=0; i<d; i++) { v[d+2][i] = 0; } /* Make vector [d+2] perpendicular to vector [d+1], * this does not affect the normalization. */ dep = iprod(v[d+1],v[d+2])/norm2(v[d+1]); for(i=0; i<DIM; i++) { v[d+2][i] -= dep*v[d+1][i]; } inv_skew_fac2 += sqr(v[d+2][d]); cprod(v[d+1],v[d+2],normal[d]); } else { /* cross product with (1,0,0) */ normal[d][XX] = 0; normal[d][YY] = v[d+1][ZZ]; normal[d][ZZ] = -v[d+1][YY]; } if (debug) { fprintf(debug,"box[%d] %.3f %.3f %.3f\n", d,box[d][XX],box[d][YY],box[d][ZZ]); for(i=d+1; i<DIM; i++) { fprintf(debug," v[%d] %.3f %.3f %.3f\n", i,v[i][XX],v[i][YY],v[i][ZZ]); } } } ddbox->skew_fac[d] = 1.0/sqrt(inv_skew_fac2); /* Set the normal vector length to skew_fac */ dep = ddbox->skew_fac[d]/norm(normal[d]); svmul(dep,normal[d],normal[d]); if (debug) { fprintf(debug,"skew_fac[%d] = %f\n",d,ddbox->skew_fac[d]); fprintf(debug,"normal[%d] %.3f %.3f %.3f\n", d,normal[d][XX],normal[d][YY],normal[d][ZZ]); } } else { ddbox->skew_fac[d] = 1; for(i=0; i<DIM; i++) { clear_rvec(ddbox->v[d][i]); ddbox->v[d][i][i] = 1; } clear_rvec(normal[d]); normal[d][d] = 1; } } }
void init_orires(FILE *log,int nfa,t_iatom forceatoms[],t_iparams ip[], rvec *xref,t_mdatoms *md,t_inputrec *ir, t_commrec *mcr,t_fcdata *fcd) { int i,j,d,ex,nr,*nr_ex; real mtot; rvec com; t_oriresdata *od; od = &(fcd->orires); od->fc = ir->orires_fc; od->nex = 0; od->S = NULL; if (ir->orires_tau > 0) od->edt = exp(-ir->delta_t/ir->orires_tau); else od->edt = 0; od->edt1 = 1 - od->edt; od->exp_min_t_tau = 1.0; od->nr = nfa/3; if (od->nr == 0) return; nr_ex = NULL; for(i=0; i<nfa; i+=3) { ex = ip[forceatoms[i]].orires.ex; if (ex >= od->nex) { srenew(nr_ex,ex+1); for(j=od->nex; j<ex+1; j++) nr_ex[j] = 0; od->nex = ex+1; } nr_ex[ex]++; } snew(od->S,od->nex); /* When not doing time averaging, the instaneous and time averaged data * are indentical and the pointers can point to the same memory. */ snew(od->Dinsl,od->nr); if (mcr) snew(od->Dins,od->nr); else od->Dins = od->Dinsl; if (fabs(ir->orires_tau) < GMX_REAL_MIN) od->Dtav = od->Dins; else snew(od->Dtav,od->nr); snew(od->oinsl,od->nr); if (mcr) snew(od->oins,od->nr); else od->oins = od->oinsl; if ( fabs(ir->orires_tau) < GMX_REAL_MIN) od->otav = od->oins; else snew(od->otav,od->nr); snew(od->tmp,od->nex); snew(od->TMP,od->nex); for(ex=0; ex<od->nex; ex++) { snew(od->TMP[ex],5); for(i=0; i<5; i++) snew(od->TMP[ex][i],5); } od->nref = 0; for(i=0; i<md->nr; i++) if (md->cORF[i] == 0) od->nref++; snew(od->mref,od->nref); snew(od->xref,od->nref); snew(od->xtmp,od->nref); /* Determine the reference structure on the master node. * Copy it to the other nodes after checking multi compatibility, * so we are sure the subsystems match before copying. */ clear_rvec(com); mtot = 0.0; j = 0; for(i=0; i<md->nr; i++) { if (md->cORF[i] == 0) { od->mref[j] = md->massT[i]; if (mcr==NULL || MASTER(mcr)) { copy_rvec(xref[i],od->xref[j]); for(d=0; d<DIM; d++) com[d] += od->mref[j]*xref[i][d]; } mtot += od->mref[j]; j++; } } od->invmref = 1.0/mtot; svmul(od->invmref,com,com); if (mcr==NULL || MASTER(mcr)) for(j=0; j<od->nref; j++) rvec_dec(od->xref[j],com); fprintf(log,"Found %d orientation experiments\n",od->nex); for(i=0; i<od->nex; i++) fprintf(log," experiment %d has %d restraints\n",i+1,nr_ex[i]); sfree(nr_ex); fprintf(log," the fit group consists of %d atoms and has total mass %g\n", od->nref,mtot); if (mcr) { fprintf(log," the orientation restraints are ensemble averaged over %d systems\n",mcr->nnodes); check_multi_int(log,mcr,fcd->orires.nr, "the number of orientation restraints"); check_multi_int(log,mcr,fcd->orires.nref, "the number of fit atoms for orientation restraining"); /* Copy the reference coordinates from the master to the other nodes */ gmx_sum(DIM*fcd->orires.nref,fcd->orires.xref[0],mcr); } }
int gmx_confrms(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the root mean square deviation (RMSD) of two", "structures after least-squares fitting the second structure on the first one.", "The two structures do NOT need to have the same number of atoms,", "only the two index groups used for the fit need to be identical.", "With [TT]-name[tt] only matching atom names from the selected groups", "will be used for the fit and RMSD calculation. This can be useful ", "when comparing mutants of a protein.", "[PAR]", "The superimposed structures are written to file. In a [REF].pdb[ref] file", "the two structures will be written as separate models", "(use [TT]rasmol -nmrpdb[tt]). Also in a [REF].pdb[ref] file, B-factors", "calculated from the atomic MSD values can be written with [TT]-bfac[tt].", }; static gmx_bool bOne = FALSE, bRmpbc = FALSE, bMW = TRUE, bName = FALSE, bBfac = FALSE, bFit = TRUE, bLabel = FALSE; t_pargs pa[] = { { "-one", FALSE, etBOOL, {&bOne}, "Only write the fitted structure to file" }, { "-mw", FALSE, etBOOL, {&bMW}, "Mass-weighted fitting and RMSD" }, { "-pbc", FALSE, etBOOL, {&bRmpbc}, "Try to make molecules whole again" }, { "-fit", FALSE, etBOOL, {&bFit}, "Do least squares superposition of the target structure to the reference" }, { "-name", FALSE, etBOOL, {&bName}, "Only compare matching atom names" }, { "-label", FALSE, etBOOL, {&bLabel}, "Added chain labels A for first and B for second structure"}, { "-bfac", FALSE, etBOOL, {&bBfac}, "Output B-factors from atomic MSD values" } }; t_filenm fnm[] = { { efTPS, "-f1", "conf1.gro", ffREAD }, { efSTX, "-f2", "conf2", ffREAD }, { efSTO, "-o", "fit.pdb", ffWRITE }, { efNDX, "-n1", "fit1", ffOPTRD }, { efNDX, "-n2", "fit2", ffOPTRD }, { efNDX, "-no", "match", ffOPTWR } }; #define NFILE asize(fnm) /* the two structure files */ const char *conf1file, *conf2file, *matchndxfile, *outfile; FILE *fp; char *name1, *name2; t_topology *top1, *top2; int ePBC1, ePBC2; t_atoms *atoms1, *atoms2; int warn = 0; atom_id at; real *w_rls, mass, totmass; rvec *x1, *v1, *x2, *v2, *fit_x; matrix box1, box2; output_env_t oenv; /* counters */ int i, m; /* center of mass calculation */ rvec xcm1, xcm2; /* variables for fit */ char *groupnames1, *groupnames2; int isize1, isize2; atom_id *index1, *index2; real rms, msd, minmsd, maxmsd; real *msds; if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } matchndxfile = opt2fn_null("-no", NFILE, fnm); conf1file = ftp2fn(efTPS, NFILE, fnm); conf2file = ftp2fn(efSTX, NFILE, fnm); /* reading reference structure from first structure file */ fprintf(stderr, "\nReading first structure file\n"); snew(top1, 1); read_tps_conf(conf1file, top1, &ePBC1, &x1, &v1, box1, TRUE); atoms1 = &(top1->atoms); fprintf(stderr, "%s\nContaining %d atoms in %d residues\n", *top1->name, atoms1->nr, atoms1->nres); if (bRmpbc) { rm_gropbc(atoms1, x1, box1); } fprintf(stderr, "Select group from first structure\n"); get_index(atoms1, opt2fn_null("-n1", NFILE, fnm), 1, &isize1, &index1, &groupnames1); printf("\n"); if (bFit && (isize1 < 3)) { gmx_fatal(FARGS, "Need >= 3 points to fit!\n"); } /* reading second structure file */ fprintf(stderr, "\nReading second structure file\n"); snew(top2, 1); read_tps_conf(conf2file, top2, &ePBC2, &x2, &v2, box2, TRUE); atoms2 = &(top2->atoms); fprintf(stderr, "%s\nContaining %d atoms in %d residues\n", *top2->name, atoms2->nr, atoms2->nres); if (bRmpbc) { rm_gropbc(atoms2, x2, box2); } fprintf(stderr, "Select group from second structure\n"); get_index(atoms2, opt2fn_null("-n2", NFILE, fnm), 1, &isize2, &index2, &groupnames2); if (bName) { find_matching_names(&isize1, index1, atoms1, &isize2, index2, atoms2); if (matchndxfile) { fp = gmx_ffopen(matchndxfile, "w"); fprintf(fp, "; Matching atoms between %s from %s and %s from %s\n", groupnames1, conf1file, groupnames2, conf2file); fprintf(fp, "[ Match_%s_%s ]\n", conf1file, groupnames1); for (i = 0; i < isize1; i++) { fprintf(fp, "%4d%s", index1[i]+1, (i%15 == 14 || i == isize1-1) ? "\n" : " "); } fprintf(fp, "[ Match_%s_%s ]\n", conf2file, groupnames2); for (i = 0; i < isize2; i++) { fprintf(fp, "%4d%s", index2[i]+1, (i%15 == 14 || i == isize2-1) ? "\n" : " "); } } } /* check isizes, must be equal */ if (isize2 != isize1) { gmx_fatal(FARGS, "You selected groups with differen number of atoms.\n"); } for (i = 0; i < isize1; i++) { name1 = *atoms1->atomname[index1[i]]; name2 = *atoms2->atomname[index2[i]]; if (std::strcmp(name1, name2)) { if (warn < 20) { fprintf(stderr, "Warning: atomnames at index %d don't match: %d %s, %d %s\n", i+1, index1[i]+1, name1, index2[i]+1, name2); } warn++; } if (!bMW) { atoms1->atom[index1[i]].m = 1; atoms2->atom[index2[i]].m = 1; } } if (warn) { fprintf(stderr, "%d atomname%s did not match\n", warn, (warn == 1) ? "" : "s"); } if (bFit) { /* calculate and remove center of mass of structures */ calc_rm_cm(isize1, index1, atoms1, x1, xcm1); calc_rm_cm(isize2, index2, atoms2, x2, xcm2); snew(w_rls, atoms2->nr); snew(fit_x, atoms2->nr); for (at = 0; (at < isize1); at++) { w_rls[index2[at]] = atoms1->atom[index1[at]].m; copy_rvec(x1[index1[at]], fit_x[index2[at]]); } /* do the least squares fit to the reference structure */ do_fit(atoms2->nr, w_rls, fit_x, x2); sfree(fit_x); sfree(w_rls); w_rls = NULL; } else { clear_rvec(xcm1); clear_rvec(xcm2); w_rls = NULL; } /* calculate the rms deviation */ rms = 0; totmass = 0; maxmsd = -1e18; minmsd = 1e18; snew(msds, isize1); for (at = 0; at < isize1; at++) { mass = atoms1->atom[index1[at]].m; for (m = 0; m < DIM; m++) { msd = sqr(x1[index1[at]][m] - x2[index2[at]][m]); rms += msd*mass; msds[at] += msd; } maxmsd = std::max(maxmsd, msds[at]); minmsd = std::min(minmsd, msds[at]); totmass += mass; } rms = std::sqrt(rms/totmass); printf("Root mean square deviation after lsq fit = %g nm\n", rms); if (bBfac) { printf("Atomic MSD's range from %g to %g nm^2\n", minmsd, maxmsd); } if (bFit) { /* reset coordinates of reference and fitted structure */ for (i = 0; i < atoms1->nr; i++) { for (m = 0; m < DIM; m++) { x1[i][m] += xcm1[m]; } } for (i = 0; i < atoms2->nr; i++) { for (m = 0; m < DIM; m++) { x2[i][m] += xcm1[m]; } } } outfile = ftp2fn(efSTO, NFILE, fnm); switch (fn2ftp(outfile)) { case efPDB: case efBRK: case efENT: if (bBfac || bLabel) { srenew(atoms1->pdbinfo, atoms1->nr); srenew(atoms1->atom, atoms1->nr); /* Why renew atom? */ /* Avoid segfaults when writing the pdb-file */ for (i = 0; i < atoms1->nr; i++) { atoms1->pdbinfo[i].type = eptAtom; atoms1->pdbinfo[i].occup = 1.00; atoms1->pdbinfo[i].bAnisotropic = FALSE; if (bBfac) { atoms1->pdbinfo[i].bfac = 0; } if (bLabel) { atoms1->resinfo[atoms1->atom[i].resind].chainid = 'A'; } } for (i = 0; i < isize1; i++) { /* atoms1->pdbinfo[index1[i]].type = eptAtom; */ /* atoms1->pdbinfo[index1[i]].bAnisotropic = FALSE; */ if (bBfac) { atoms1->pdbinfo[index1[i]].bfac = (800*M_PI*M_PI/3.0)*msds[i]; } /* if (bLabel) */ /* atoms1->resinfo[atoms1->atom[index1[i]].resind].chain = 'A'; */ } srenew(atoms2->pdbinfo, atoms2->nr); srenew(atoms2->atom, atoms2->nr); /* Why renew atom? */ for (i = 0; i < atoms2->nr; i++) { atoms2->pdbinfo[i].type = eptAtom; atoms2->pdbinfo[i].occup = 1.00; atoms2->pdbinfo[i].bAnisotropic = FALSE; if (bBfac) { atoms2->pdbinfo[i].bfac = 0; } if (bLabel) { atoms2->resinfo[atoms1->atom[i].resind].chainid = 'B'; } } for (i = 0; i < isize2; i++) { /* atoms2->pdbinfo[index2[i]].type = eptAtom; */ /* atoms2->pdbinfo[index2[i]].bAnisotropic = FALSE; */ if (bBfac) { atoms2->pdbinfo[index2[i]].bfac = (800*M_PI*M_PI/3.0)*msds[i]; } /* if (bLabel) */ /* atoms2->resinfo[atoms2->atom[index2[i]].resind].chain = 'B'; */ } } fp = gmx_ffopen(outfile, "w"); if (!bOne) { write_pdbfile(fp, *top1->name, atoms1, x1, ePBC1, box1, ' ', 1, NULL, TRUE); } write_pdbfile(fp, *top2->name, atoms2, x2, ePBC2, box2, ' ', bOne ? -1 : 2, NULL, TRUE); gmx_ffclose(fp); break; case efGRO: if (bBfac) { fprintf(stderr, "WARNING: cannot write B-factor values to gro file\n"); } fp = gmx_ffopen(outfile, "w"); if (!bOne) { write_hconf_p(fp, *top1->name, atoms1, 3, x1, v1, box1); } write_hconf_p(fp, *top2->name, atoms2, 3, x2, v2, box2); gmx_ffclose(fp); break; default: if (bBfac) { fprintf(stderr, "WARNING: cannot write B-factor values to %s file\n", ftp2ext(fn2ftp(outfile))); } if (!bOne) { fprintf(stderr, "WARNING: cannot write the reference structure to %s file\n", ftp2ext(fn2ftp(outfile))); } write_sto_conf(outfile, *top2->name, atoms2, x2, v2, ePBC2, box2); break; } view_all(oenv, NFILE, fnm); return 0; }
static real calc_cm(int natoms, real mass[], rvec x[], rvec v[], rvec xcm, rvec vcm, rvec acm, matrix L) { rvec dx, a0; real tm, m0; int i, m; clear_rvec(xcm); clear_rvec(vcm); clear_rvec(acm); tm = 0.0; for (i = 0; (i < natoms); i++) { m0 = mass[i]; tm += m0; cprod(x[i], v[i], a0); for (m = 0; (m < DIM); m++) { xcm[m] += m0*x[i][m]; /* c.o.m. position */ vcm[m] += m0*v[i][m]; /* c.o.m. velocity */ acm[m] += m0*a0[m]; /* rotational velocity around c.o.m. */ } } cprod(xcm, vcm, a0); for (m = 0; (m < DIM); m++) { xcm[m] /= tm; vcm[m] /= tm; acm[m] -= a0[m]/tm; } #define PVEC(str, v) fprintf(log, \ "%s[X]: %10.5e %s[Y]: %10.5e %s[Z]: %10.5e\n", \ str, v[0], str, v[1], str, v[2]) #ifdef DEBUG PVEC("xcm", xcm); PVEC("acm", acm); PVEC("vcm", vcm); #endif clear_mat(L); for (i = 0; (i < natoms); i++) { m0 = mass[i]; for (m = 0; (m < DIM); m++) { dx[m] = x[i][m]-xcm[m]; } L[XX][XX] += dx[XX]*dx[XX]*m0; L[XX][YY] += dx[XX]*dx[YY]*m0; L[XX][ZZ] += dx[XX]*dx[ZZ]*m0; L[YY][YY] += dx[YY]*dx[YY]*m0; L[YY][ZZ] += dx[YY]*dx[ZZ]*m0; L[ZZ][ZZ] += dx[ZZ]*dx[ZZ]*m0; } #ifdef DEBUG PVEC("L-x", L[XX]); PVEC("L-y", L[YY]); PVEC("L-z", L[ZZ]); #endif return tm; }