void reset_x_ndim(int ndim,int ncm,atom_id ind_cm[], int nreset,atom_id *ind_reset,rvec x[],real mass[]) { int i,m,ai; rvec xcm; real tm,mm; tm=0.0; clear_rvec(xcm); for(i=0; i<ncm; i++) { ai=ind_cm[i]; mm=mass[ai]; for(m=0; m<ndim; m++) xcm[m]+=mm*x[ai][m]; tm+=mm; } for(m=0; m<ndim; m++) xcm[m]/=tm; if (ind_reset) for(i=0; i<nreset; i++) rvec_dec(x[ind_reset[i]],xcm); else for(i=0; i<nreset; i++) rvec_dec(x[i],xcm); }
void reset_x_ndim(int ndim,int ncm,const atom_id *ind_cm, int nreset,const atom_id *ind_reset, rvec x[],const real mass[]) { int i,m,ai; rvec xcm; real tm,mm; if (ndim>DIM) { gmx_incons("More than 3 dimensions not supported."); } tm = 0.0; clear_rvec(xcm); if (ind_cm != NULL) { for(i=0; i<ncm; i++) { ai = ind_cm[i]; mm = mass[ai]; for(m=0; m<ndim; m++) { xcm[m] += mm*x[ai][m]; } tm += mm; } } else { for(i=0; i<ncm; i++) { mm = mass[i]; for(m=0; m<ndim; m++) { xcm[m] += mm*x[i][m]; } tm += mm; } } for(m=0; m<ndim; m++) { xcm[m] /= tm; } if (ind_reset != NULL) { for(i=0; i<nreset; i++) { rvec_dec(x[ind_reset[i]],xcm); } } else { for(i=0; i<nreset; i++) { rvec_dec(x[i],xcm); } } }
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]); } }
/* prepare the coordinates by removing periodic boundary crossings. gnx = the number of atoms/molecules index = the indices xcur = the current coordinates xprev = the previous coordinates box = the box matrix */ static void prep_data(gmx_bool bMol,int gnx,atom_id index[], rvec xcur[],rvec xprev[],matrix box) { int i,m,ind; rvec hbox; /* Remove periodicity */ for(m=0; (m<DIM); m++) hbox[m]=0.5*box[m][m]; for(i=0; (i<gnx); i++) { if (bMol) ind = i; else ind = index[i]; for(m=DIM-1; m>=0; m--) { while(xcur[ind][m]-xprev[ind][m] <= -hbox[m]) rvec_inc(xcur[ind],box[m]); while(xcur[ind][m]-xprev[ind][m] > hbox[m]) rvec_dec(xcur[ind],box[m]); } } }
static void center_coords(t_atoms *atoms, matrix box, rvec x0[], int axis) { int i, m; real tmass, mm; rvec com, shift, box_center; tmass = 0; clear_rvec(com); for (i = 0; (i < atoms->nr); i++) { mm = atoms->atom[i].m; tmass += mm; for (m = 0; (m < DIM); m++) { com[m] += mm*x0[i][m]; } } for (m = 0; (m < DIM); m++) { com[m] /= tmass; } calc_box_center(ecenterDEF, box, box_center); rvec_sub(box_center, com, shift); shift[axis] -= box_center[axis]; for (i = 0; (i < atoms->nr); i++) { rvec_dec(x0[i], shift); } }
void do_stopcm_grp(FILE *fp,int start,int homenr,unsigned short *group_id, rvec x[],rvec v[],t_vcm *vcm) { int i,g,m; real tm,tm_1; rvec dv,dx; if (vcm->mode != ecmNO) { /* Subtract linear momentum */ g = 0; switch (vcm->ndim) { case 1: for(i=start; (i<start+homenr); i++) { if (group_id) g = group_id[i]; v[i][XX] -= vcm->group_v[g][XX]; } break; case 2: for(i=start; (i<start+homenr); i++) { if (group_id) g = group_id[i]; v[i][XX] -= vcm->group_v[g][XX]; v[i][YY] -= vcm->group_v[g][YY]; } break; case 3: for(i=start; (i<start+homenr); i++) { if (group_id) g = group_id[i]; rvec_dec(v[i],vcm->group_v[g]); } break; } if (vcm->mode == ecmANGULAR) { /* Subtract angular momentum */ for(i=start; (i<start+homenr); i++) { if (group_id) g = group_id[i]; /* Compute the correction to the velocity for each atom */ rvec_sub(x[i],vcm->group_x[g],dx); cprod(vcm->group_w[g],dx,dv); rvec_dec(v[i],dv); } } } }
static void my_sub_xcm(int nbb,atom_id bbind[],rvec x[],rvec xcm) { int i,ai; for(i=0; (i<nbb); i++) { ai=bbind[i]; rvec_dec(x[ai],xcm); } }
real sub_xcm(rvec x[], int gnx, atom_id *index, t_atom atom[], rvec xcm, gmx_bool bQ) { int i, ii; real tm; tm = calc_xcm(x, gnx, index, atom, xcm, bQ); for (i = 0; (i < gnx); i++) { ii = index ? index[i] : i; rvec_dec(x[ii], xcm); } return tm; }
static void center_molecule(int atomCount, rvec x[]) { rvec center; clear_rvec(center); for (int i = 0; i < atomCount; ++i) { rvec_inc(center, x[i]); } svmul(1.0/atomCount, center, center); for (int i = 0; i < atomCount; ++i) { rvec_dec(x[i], center); } }
static int correct_box_elem(FILE *fplog, int step, tensor box, int v, int d) { int shift, maxshift = 10; shift = 0; /* correct elem d of vector v with vector d */ while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d]) { if (fplog) { fprintf(fplog, "Step %d: correcting invalid box:\n", step); pr_rvecs(fplog, 0, "old box", box, DIM); } rvec_dec(box[v], box[d]); shift--; if (fplog) { pr_rvecs(fplog, 0, "new box", box, DIM); } if (shift <= -maxshift) { gmx_fatal(FARGS, "Box was shifted at least %d times. Please see log-file.", maxshift); } } while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d]) { if (fplog) { fprintf(fplog, "Step %d: correcting invalid box:\n", step); pr_rvecs(fplog, 0, "old box", box, DIM); } rvec_inc(box[v], box[d]); shift++; if (fplog) { pr_rvecs(fplog, 0, "new box", box, DIM); } if (shift >= maxshift) { gmx_fatal(FARGS, "Box was shifted at least %d times. Please see log-file.", maxshift); } } return shift; }
void BoxDeformation::apply(ArrayRef<RVec> x, matrix box, int64_t step) { matrix updatedBox, invbox, mu; double elapsedTime = (step + 1 - initialStep_) * timeStep_; copy_mat(box, updatedBox); for (int i = 0; i < DIM; i++) { for (int j = 0; j < DIM; j++) { if (deformationTensor_[i][j] != 0) { updatedBox[i][j] = referenceBox_[i][j] + elapsedTime * deformationTensor_[i][j]; } } } /* We correct the off-diagonal elements, * which can grow indefinitely during shearing, * so the shifts do not get messed up. */ for (int i = 1; i < DIM; i++) { for (int j = i-1; j >= 0; j--) { while (updatedBox[i][j] - box[i][j] > 0.5 * updatedBox[j][j]) { rvec_dec(updatedBox[i], updatedBox[j]); } while (updatedBox[i][j] - box[i][j] < -0.5 * updatedBox[j][j]) { rvec_inc(updatedBox[i], updatedBox[j]); } } } invertBoxMatrix(box, invbox); // Return the updated box copy_mat(updatedBox, box); mmul_ur0(box, invbox, mu); for (auto &thisX : x) { thisX[XX] = mu[XX][XX]*thisX[XX] + mu[YY][XX]*thisX[YY] + mu[ZZ][XX]*thisX[ZZ]; thisX[YY] = mu[YY][YY]*thisX[YY] + mu[ZZ][YY]*thisX[ZZ]; thisX[ZZ] = mu[ZZ][ZZ]*thisX[ZZ]; } }
void print_constraint(t_pull *pull, rvec *f, int step, matrix box, int niter) { int i,ii,m; rvec tmp,tmp2,tmp3; for (i=0;i<pull->pull.n;i++) { if (pull->bCyl) rvec_sub(pull->pull.x_con[i],pull->dyna.x_con[i],tmp); else rvec_sub(pull->pull.x_con[i],pull->ref.x_con[0],tmp); for (m=DIM-1; m>=0; m--) { if (tmp[m] < -0.5*box[m][m]) rvec_inc(tmp,box[m]); if (tmp[m] > 0.5*box[m][m]) rvec_dec(tmp,box[m]); tmp[m] *= pull->dims[m]; } if (pull->bVerbose) fprintf(pull->out,"%d:%d ds:%e f:%e n:%d\n", step,i,norm(tmp), pull->pull.f[i][ZZ],niter); else fprintf(pull->out,"%e ",pull->pull.f[i][ZZ]); } if (!pull->bVerbose) fprintf(pull->out,"\n"); /* DEBUG */ /* this code doesn't correct for pbc, needs improvement */ if (pull->bVerbose) { for (i=0;i<pull->pull.n;i++) { if (pull->bCyl) fprintf(pull->out,"eConstraint: step %d. Refgroup = dynamic (%f,%f\n" "Group %d (%s): ref. dist = %8.3f, unconstr. dist = %8.3f" " con. dist = %8.3f f_i = %8.3f\n", step, pull->r,pull->rc, i,pull->pull.grps[i], pull->dyna.x_ref[i][ZZ]-pull->pull.x_ref[i][ZZ], pull->dyna.x_unc[i][ZZ]-pull->pull.x_unc[i][ZZ], pull->dyna.x_con[i][ZZ]-pull->pull.x_con[i][ZZ], pull->pull.f[i][ZZ]); else { rvec_sub(pull->ref.x_ref[0],pull->pull.x_ref[i],tmp); rvec_sub(pull->ref.x_unc[0],pull->pull.x_unc[i],tmp2); rvec_sub(pull->ref.x_con[0],pull->pull.x_con[i],tmp3); fprintf(stderr,"grp %d:ref (%8.3f,%8.3f,%8.3f) unc(%8.3f%8.3f%8.3f\n" "con (%8.3f%8.3f%8.3f)\n",i, tmp[0],tmp[1],tmp[2], tmp2[0],tmp2[1],tmp2[2],tmp3[0],tmp3[1],tmp3[2]); } } } /* END DEBUG */ }
/* prepare the coordinates by removing periodic boundary crossings. gnx = the number of atoms/molecules index = the indices xcur = the current coordinates xprev = the previous coordinates box = the box matrix */ static void prep_data(gmx_bool bMol, int gnx, int index[], rvec xcur[], rvec xprev[], matrix box) { int i, m, ind; rvec hbox; /* Remove periodicity */ for (m = 0; (m < DIM); m++) { hbox[m] = 0.5*box[m][m]; } for (i = 0; (i < gnx); i++) { if (bMol) { ind = i; } else { ind = index[i]; } for (m = DIM-1; m >= 0; m--) { if (hbox[m] == 0) { continue; } while (xcur[ind][m]-xprev[ind][m] <= -hbox[m]) { rvec_inc(xcur[ind], box[m]); } while (xcur[ind][m]-xprev[ind][m] > hbox[m]) { rvec_dec(xcur[ind], box[m]); } } } }
void correct_t0_pbc(t_pull *pull, rvec x[], t_mdatoms *md, matrix box) { int i,ii,j,m; real tm; rvec com,dx; /* loop over all atoms in index for group i. Check if they moved more than half a box with respect to xp. If so add/subtract a box from x0. Copy x to xp. */ for (i=0;i<pull->ref.ngx[0];i++) { ii = pull->ref.idx[0][i]; /* correct for jumps across the box */ rvec_sub(x[ii],pull->ref.xp[0][i],dx); for (m=DIM-1; m>=0; m--) { if (dx[m] < -0.5*box[m][m]) { rvec_inc(dx,box[m]); if (pull->bVerbose && fabs(pull->dims[m])>GMX_REAL_MIN) fprintf(stderr,"Jumped +box: nr %d dir: %d old:%8.3f\n",ii,m, pull->ref.x0[0][i][m]); } if (dx[m] > 0.5*box[m][m]) { rvec_dec(dx,box[m]); if (pull->bVerbose && fabs(pull->dims[m])>GMX_REAL_MIN) fprintf(stderr,"Jumped -box: nr %d dir: %d old:%8.3f\n",ii,m, pull->ref.x0[0][i][m]); } pull->ref.x0[0][i][m] += dx[m]; pull->ref.xp[0][i][m] = x[ii][m]; } } tm = calc_com2(pull->ref.x0[0],pull->ref.ngx[0],pull->ref.idx[0], md,com,box); if (pull->bVerbose) fprintf(stderr,"correct_t0: Group %s: mass:%8.3f com:%8.3f%8.3f%8.3f\n", pull->ref.grps[0],tm,com[0],com[1],com[2]); }
/* calculates com of all atoms in x[], *index has their index numbers to get the masses from atom[] */ real calc_com2(rvec x[],int gnx,atom_id *index,t_mdatoms *md,rvec com, matrix box) { int i,ii,m; real m0,tm; clear_rvec(com); tm=0; for(i=0; (i<gnx); i++) { ii=index[i]; m0=md->massT[ii]; tm+=m0; for(m=0; (m<DIM); m++) com[m]+=m0*x[i][m]; } svmul(1/tm,com,com); for(m=DIM-1; m>=0; m--) { /* next two lines used to be commented out */ if (com[m] < 0 ) rvec_inc(com,box[m]); if (com[m] > box[m][m]) rvec_dec(com,box[m]); } return tm; }
void calc_rm_cm(int isize, atom_id index[], t_atoms *atoms, rvec x[], rvec xcm) { int i, d; real tm, m; /* calculate and remove center of mass of reference structure */ tm = 0; clear_rvec(xcm); for (i = 0; i < isize; i++) { m = atoms->atom[index[i]].m; for (d = 0; d < DIM; d++) { xcm[d] += m*x[index[i]][d]; } tm += m; } svmul(1/tm, xcm, xcm); for (i = 0; i < atoms->nr; i++) { rvec_dec(x[i], xcm); } }
void orient_princ(t_atoms *atoms, int isize, atom_id *index, int natoms, rvec x[], rvec *v, rvec d) { int i, m; rvec xcm, prcomp; matrix trans; calc_xcm(x, isize, index, atoms->atom, xcm, FALSE); for (i = 0; i < natoms; i++) { rvec_dec(x[i], xcm); } principal_comp(isize, index, atoms->atom, x, trans, prcomp); if (d) { copy_rvec(prcomp, d); } /* Check whether this trans matrix mirrors the molecule */ if (det(trans) < 0) { for (m = 0; (m < DIM); m++) { trans[ZZ][m] = -trans[ZZ][m]; } } rotate_atoms(natoms, NULL, x, trans); if (v) { rotate_atoms(natoms, NULL, v, trans); } for (i = 0; i < natoms; i++) { rvec_inc(x[i], xcm); } }
void center_coords(t_atoms *atoms, atom_id *index_center, int ncenter, matrix box, rvec x0[]) { int i, k, m; real tmass, mm; rvec com, shift, box_center; tmass = 0; clear_rvec(com); for (k = 0; (k < ncenter); k++) { i = index_center[k]; if (i >= atoms->nr) { gmx_fatal(FARGS, "Index %d refers to atom %d, which is larger than natoms (%d).", k+1, i+1, atoms->nr); } mm = atoms->atom[i].m; tmass += mm; for (m = 0; (m < DIM); m++) { com[m] += mm*x0[i][m]; } } for (m = 0; (m < DIM); m++) { com[m] /= tmass; } calc_box_center(ecenterDEF, box, box_center); rvec_sub(box_center, com, shift); /* Important - while the center was calculated based on a group, we should move all atoms */ for (i = 0; (i < atoms->nr); i++) { rvec_dec(x0[i], shift); } }
int gmx_editconf(int argc, char *argv[]) { const char *desc[] = { "editconf converts generic structure format to [TT].gro[tt], [TT].g96[tt]", "or [TT].pdb[tt].", "[PAR]", "The box can be modified with options [TT]-box[tt], [TT]-d[tt] and", "[TT]-angles[tt]. Both [TT]-box[tt] and [TT]-d[tt]", "will center the system in the box, unless [TT]-noc[tt] is used.", "[PAR]", "Option [TT]-bt[tt] determines the box type: [TT]triclinic[tt] is a", "triclinic box, [TT]cubic[tt] is a rectangular box with all sides equal", "[TT]dodecahedron[tt] represents a rhombic dodecahedron and", "[TT]octahedron[tt] is a truncated octahedron.", "The last two are special cases of a triclinic box.", "The length of the three box vectors of the truncated octahedron is the", "shortest distance between two opposite hexagons.", "The volume of a dodecahedron is 0.71 and that of a truncated octahedron", "is 0.77 of that of a cubic box with the same periodic image distance.", "[PAR]", "Option [TT]-box[tt] requires only", "one value for a cubic box, dodecahedron and a truncated octahedron.", "[PAR]", "With [TT]-d[tt] and a [TT]triclinic[tt] box the size of the system in the x, y", "and z directions is used. With [TT]-d[tt] and [TT]cubic[tt],", "[TT]dodecahedron[tt] or [TT]octahedron[tt] boxes, the dimensions are set", "to the diameter of the system (largest distance between atoms) plus twice", "the specified distance.", "[PAR]", "Option [TT]-angles[tt] is only meaningful with option [TT]-box[tt] and", "a triclinic box and can not be used with option [TT]-d[tt].", "[PAR]", "When [TT]-n[tt] or [TT]-ndef[tt] is set, a group", "can be selected for calculating the size and the geometric center,", "otherwise the whole system is used.", "[PAR]", "[TT]-rotate[tt] rotates the coordinates and velocities.", "[PAR]", "[TT]-princ[tt] aligns the principal axes of the system along the", "coordinate axes, this may allow you to decrease the box volume,", "but beware that molecules can rotate significantly in a nanosecond.", "[PAR]", "Scaling is applied before any of the other operations are", "performed. Boxes and coordinates can be scaled to give a certain density (option", "[TT]-density[tt]). Note that this may be inaccurate in case a gro", "file is given as input. A special feature of the scaling option, when the", "factor -1 is given in one dimension, one obtains a mirror image,", "mirrored in one of the plains, when one uses -1 in three dimensions", "a point-mirror image is obtained.[PAR]", "Groups are selected after all operations have been applied.[PAR]", "Periodicity can be removed in a crude manner.", "It is important that the box sizes at the bottom of your input file", "are correct when the periodicity is to be removed.", "[PAR]", "When writing [TT].pdb[tt] files, B-factors can be", "added with the [TT]-bf[tt] option. B-factors are read", "from a file with with following format: first line states number of", "entries in the file, next lines state an index", "followed by a B-factor. The B-factors will be attached per residue", "unless an index is larger than the number of residues or unless the", "[TT]-atom[tt] option is set. Obviously, any type of numeric data can", "be added instead of B-factors. [TT]-legend[tt] will produce", "a row of CA atoms with B-factors ranging from the minimum to the", "maximum value found, effectively making a legend for viewing.", "[PAR]", "With the option -mead a special pdb (pqr) file for the MEAD electrostatics", "program (Poisson-Boltzmann solver) can be made. A further prerequisite", "is that the input file is a run input file.", "The B-factor field is then filled with the Van der Waals radius", "of the atoms while the occupancy field will hold the charge.", "[PAR]", "The option -grasp is similar, but it puts the charges in the B-factor", "and the radius in the occupancy.", "[PAR]", "Option [TT]-align[tt] allows alignment", "of the principal axis of a specified group against the given vector, ", "with an optional center of rotation specified by [TT]-aligncenter[tt].", "[PAR]", "Finally with option [TT]-label[tt] editconf can add a chain identifier", "to a pdb file, which can be useful for analysis with e.g. rasmol.", "[PAR]", "To convert a truncated octrahedron file produced by a package which uses", "a cubic box with the corners cut off (such as Gromos) use:[BR]", "[TT]editconf -f <in> -rotate 0 45 35.264 -bt o -box <veclen> -o <out>[tt][BR]", "where [TT]veclen[tt] is the size of the cubic box times sqrt(3)/2." }; const char *bugs[] = { "For complex molecules, the periodicity removal routine may break down, ", "in that case you can use trjconv." }; static real dist = 0.0, rbox = 0.0, to_diam = 0.0; static gmx_bool bNDEF = FALSE, bRMPBC = FALSE, bCenter = FALSE, bReadVDW = FALSE, bCONECT = FALSE; static gmx_bool peratom = FALSE, bLegend = FALSE, bOrient = FALSE, bMead = FALSE, bGrasp = FALSE, bSig56 = FALSE; static rvec scale = { 1, 1, 1 }, newbox = { 0, 0, 0 }, newang = { 90, 90, 90 }; static real rho = 1000.0, rvdw = 0.12; static rvec center = { 0, 0, 0 }, translation = { 0, 0, 0 }, rotangles = { 0, 0, 0 }, aligncenter = { 0, 0, 0 }, targetvec = { 0, 0, 0 }; static const char *btype[] = { NULL, "triclinic", "cubic", "dodecahedron", "octahedron", NULL }, *label = "A"; static rvec visbox = { 0, 0, 0 }; t_pargs pa[] = { { "-ndef", FALSE, etBOOL, { &bNDEF }, "Choose output from default index groups" }, { "-visbox", FALSE, etRVEC, { visbox }, "HIDDENVisualize a grid of boxes, -1 visualizes the 14 box images" }, { "-bt", FALSE, etENUM, { btype }, "Box type for -box and -d" }, { "-box", FALSE, etRVEC, { newbox }, "Box vector lengths (a,b,c)" }, { "-angles", FALSE, etRVEC, { newang }, "Angles between the box vectors (bc,ac,ab)" }, { "-d", FALSE, etREAL, { &dist }, "Distance between the solute and the box" }, { "-c", FALSE, etBOOL, { &bCenter }, "Center molecule in box (implied by -box and -d)" }, { "-center", FALSE, etRVEC, { center }, "Coordinates of geometrical center" }, { "-aligncenter", FALSE, etRVEC, { aligncenter }, "Center of rotation for alignment" }, { "-align", FALSE, etRVEC, { targetvec }, "Align to target vector" }, { "-translate", FALSE, etRVEC, { translation }, "Translation" }, { "-rotate", FALSE, etRVEC, { rotangles }, "Rotation around the X, Y and Z axes in degrees" }, { "-princ", FALSE, etBOOL, { &bOrient }, "Orient molecule(s) along their principal axes" }, { "-scale", FALSE, etRVEC, { scale }, "Scaling factor" }, { "-density", FALSE, etREAL, { &rho }, "Density (g/l) of the output box achieved by scaling" }, { "-pbc", FALSE, etBOOL, { &bRMPBC }, "Remove the periodicity (make molecule whole again)" }, { "-grasp", FALSE, etBOOL, { &bGrasp }, "Store the charge of the atom in the B-factor field and the radius of the atom in the occupancy field" }, { "-rvdw", FALSE, etREAL, { &rvdw }, "Default Van der Waals radius (in nm) if one can not be found in the database or if no parameters are present in the topology file" }, { "-sig56", FALSE, etREAL, { &bSig56 }, "Use rmin/2 (minimum in the Van der Waals potential) rather than sigma/2 " }, { "-vdwread", FALSE, etBOOL, { &bReadVDW }, "Read the Van der Waals radii from the file vdwradii.dat rather than computing the radii based on the force field" }, { "-atom", FALSE, etBOOL, { &peratom }, "Force B-factor attachment per atom" }, { "-legend", FALSE, etBOOL, { &bLegend }, "Make B-factor legend" }, { "-label", FALSE, etSTR, { &label }, "Add chain label for all residues" }, { "-conect", FALSE, etBOOL, { &bCONECT }, "Add CONECT records to a pdb file when written. Can only be done when a topology is present" } }; #define NPA asize(pa) FILE *out; const char *infile, *outfile; char title[STRLEN]; int outftp, inftp, natom, i, j, n_bfac, itype, ntype; double *bfac = NULL, c6, c12; int *bfac_nr = NULL; t_topology *top = NULL; t_atoms atoms; char *grpname, *sgrpname, *agrpname; int isize, ssize, tsize, asize; atom_id *index, *sindex, *tindex, *aindex; rvec *x, *v, gc, min, max, size; int ePBC; matrix box,rotmatrix,trans; rvec princd,tmpvec; gmx_bool bIndex, bSetSize, bSetAng, bCubic, bDist, bSetCenter, bAlign; gmx_bool bHaveV, bScale, bRho, bTranslate, bRotate, bCalcGeom, bCalcDiam; real xs, ys, zs, xcent, ycent, zcent, diam = 0, mass = 0, d, vdw; gmx_atomprop_t aps; gmx_conect conect; output_env_t oenv; t_filenm fnm[] = { { efSTX, "-f", NULL, ffREAD }, { efNDX, "-n", NULL, ffOPTRD }, { efSTO, NULL, NULL, ffOPTWR }, { efPQR, "-mead", "mead", ffOPTWR }, { efDAT, "-bf", "bfact", ffOPTRD } }; #define NFILE asize(fnm) CopyRight(stderr, argv[0]); parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa, asize(desc), desc, asize(bugs), bugs, &oenv); bIndex = opt2bSet("-n", NFILE, fnm) || bNDEF; bMead = opt2bSet("-mead", NFILE, fnm); bSetSize = opt2parg_bSet("-box", NPA, pa); bSetAng = opt2parg_bSet("-angles", NPA, pa); bSetCenter = opt2parg_bSet("-center", NPA, pa); bDist = opt2parg_bSet("-d", NPA, pa); bAlign = opt2parg_bSet("-align", NPA, pa); /* Only automatically turn on centering without -noc */ if ((bDist || bSetSize || bSetCenter) && !opt2parg_bSet("-c", NPA, pa)) { bCenter = TRUE; } bScale = opt2parg_bSet("-scale", NPA, pa); bRho = opt2parg_bSet("-density", NPA, pa); bTranslate = opt2parg_bSet("-translate", NPA, pa); bRotate = opt2parg_bSet("-rotate", NPA, pa); if (bScale && bRho) fprintf(stderr, "WARNING: setting -density overrides -scale\n"); bScale = bScale || bRho; bCalcGeom = bCenter || bRotate || bOrient || bScale; bCalcDiam = btype[0][0] == 'c' || btype[0][0] == 'd' || btype[0][0] == 'o'; infile = ftp2fn(efSTX, NFILE, fnm); if (bMead) outfile = ftp2fn(efPQR, NFILE, fnm); else outfile = ftp2fn(efSTO, NFILE, fnm); outftp = fn2ftp(outfile); inftp = fn2ftp(infile); aps = gmx_atomprop_init(); if (bMead && bGrasp) { printf("Incompatible options -mead and -grasp. Turning off -grasp\n"); bGrasp = FALSE; } if (bGrasp && (outftp != efPDB)) gmx_fatal(FARGS, "Output file should be a .pdb file" " when using the -grasp option\n"); if ((bMead || bGrasp) && !((fn2ftp(infile) == efTPR) || (fn2ftp(infile) == efTPA) || (fn2ftp(infile) == efTPB))) gmx_fatal(FARGS,"Input file should be a .tp[abr] file" " when using the -mead option\n"); get_stx_coordnum(infile,&natom); init_t_atoms(&atoms,natom,TRUE); snew(x,natom); snew(v,natom); read_stx_conf(infile,title,&atoms,x,v,&ePBC,box); if (fn2ftp(infile) == efPDB) { get_pdb_atomnumber(&atoms,aps); } printf("Read %d atoms\n",atoms.nr); /* Get the element numbers if available in a pdb file */ if (fn2ftp(infile) == efPDB) get_pdb_atomnumber(&atoms,aps); if (ePBC != epbcNONE) { real vol = det(box); printf("Volume: %g nm^3, corresponds to roughly %d electrons\n", vol,100*((int)(vol*4.5))); } if (bMead || bGrasp || bCONECT) top = read_top(infile,NULL); if (bMead || bGrasp) { if (atoms.nr != top->atoms.nr) gmx_fatal(FARGS,"Atom numbers don't match (%d vs. %d)",atoms.nr,top->atoms.nr); snew(atoms.pdbinfo,top->atoms.nr); ntype = top->idef.atnr; for(i=0; (i<atoms.nr); i++) { /* Determine the Van der Waals radius from the force field */ if (bReadVDW) { if (!gmx_atomprop_query(aps,epropVDW, *top->atoms.resinfo[top->atoms.atom[i].resind].name, *top->atoms.atomname[i],&vdw)) vdw = rvdw; } else { itype = top->atoms.atom[i].type; c12 = top->idef.iparams[itype*ntype+itype].lj.c12; c6 = top->idef.iparams[itype*ntype+itype].lj.c6; if ((c6 != 0) && (c12 != 0)) { real sig6; if (bSig56) sig6 = 2*c12/c6; else sig6 = c12/c6; vdw = 0.5*pow(sig6,1.0/6.0); } else vdw = rvdw; } /* Factor of 10 for nm -> Angstroms */ vdw *= 10; if (bMead) { atoms.pdbinfo[i].occup = top->atoms.atom[i].q; atoms.pdbinfo[i].bfac = vdw; } else { atoms.pdbinfo[i].occup = vdw; atoms.pdbinfo[i].bfac = top->atoms.atom[i].q; } } } bHaveV=FALSE; for (i=0; (i<natom) && !bHaveV; i++) for (j=0; (j<DIM) && !bHaveV; j++) bHaveV=bHaveV || (v[i][j]!=0); printf("%selocities found\n",bHaveV?"V":"No v"); if (visbox[0] > 0) { if (bIndex) gmx_fatal(FARGS,"Sorry, can not visualize box with index groups"); if (outftp != efPDB) gmx_fatal(FARGS,"Sorry, can only visualize box with a pdb file"); } else if (visbox[0] == -1) visualize_images("images.pdb",ePBC,box); /* remove pbc */ if (bRMPBC) rm_gropbc(&atoms,x,box); if (bCalcGeom) { if (bIndex) { fprintf(stderr,"\nSelect a group for determining the system size:\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm), 1,&ssize,&sindex,&sgrpname); } else { ssize = atoms.nr; sindex = NULL; } diam=calc_geom(ssize,sindex,x,gc,min,max,bCalcDiam); rvec_sub(max, min, size); printf(" system size :%7.3f%7.3f%7.3f (nm)\n", size[XX], size[YY], size[ZZ]); if (bCalcDiam) printf(" diameter :%7.3f (nm)\n",diam); printf(" center :%7.3f%7.3f%7.3f (nm)\n", gc[XX], gc[YY], gc[ZZ]); printf(" box vectors :%7.3f%7.3f%7.3f (nm)\n", norm(box[XX]), norm(box[YY]), norm(box[ZZ])); printf(" box angles :%7.2f%7.2f%7.2f (degrees)\n", norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])), norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])), norm2(box[YY])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY]))); printf(" box volume :%7.2f (nm^3)\n",det(box)); } if (bRho || bOrient || bAlign) mass = calc_mass(&atoms,!fn2bTPX(infile),aps); if (bOrient) { atom_id *index; char *grpnames; /* Get a group for principal component analysis */ fprintf(stderr,"\nSelect group for the determining the orientation\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpnames); /* Orient the principal axes along the coordinate axes */ orient_princ(&atoms,isize,index,natom,x,bHaveV ? v : NULL, NULL); sfree(index); sfree(grpnames); } if ( bScale ) { /* scale coordinates and box */ if (bRho) { /* Compute scaling constant */ real vol,dens; vol = det(box); dens = (mass*AMU)/(vol*NANO*NANO*NANO); fprintf(stderr,"Volume of input %g (nm^3)\n",vol); fprintf(stderr,"Mass of input %g (a.m.u.)\n",mass); fprintf(stderr,"Density of input %g (g/l)\n",dens); if (vol==0 || mass==0) gmx_fatal(FARGS,"Cannot scale density with " "zero mass (%g) or volume (%g)\n",mass,vol); scale[XX] = scale[YY] = scale[ZZ] = pow(dens/rho,1.0/3.0); fprintf(stderr,"Scaling all box vectors by %g\n",scale[XX]); } scale_conf(atoms.nr,x,box,scale); } if (bAlign) { if (bIndex) { fprintf(stderr,"\nSelect a group that you want to align:\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm), 1,&asize,&aindex,&agrpname); } else { asize = atoms.nr; snew(aindex,asize); for (i=0;i<asize;i++) aindex[i]=i; } printf("Aligning %d atoms (out of %d) to %g %g %g, center of rotation %g %g %g\n",asize,natom, targetvec[XX],targetvec[YY],targetvec[ZZ], aligncenter[XX],aligncenter[YY],aligncenter[ZZ]); /*subtract out pivot point*/ for(i=0; i<asize; i++) rvec_dec(x[aindex[i]],aligncenter); /*now determine transform and rotate*/ /*will this work?*/ principal_comp(asize,aindex,atoms.atom,x, trans,princd); unitv(targetvec,targetvec); printf("Using %g %g %g as principal axis\n", trans[0][2],trans[1][2],trans[2][2]); tmpvec[XX]=trans[0][2]; tmpvec[YY]=trans[1][2]; tmpvec[ZZ]=trans[2][2]; calc_rotmatrix(tmpvec, targetvec, rotmatrix); /* rotmatrix finished */ for (i=0;i<asize;++i) { mvmul(rotmatrix,x[aindex[i]],tmpvec); copy_rvec(tmpvec,x[aindex[i]]); } /*add pivot point back*/ for(i=0; i<asize; i++) rvec_inc(x[aindex[i]],aligncenter); if (!bIndex) sfree(aindex); } if (bTranslate) { if (bIndex) { fprintf(stderr,"\nSelect a group that you want to translate:\n"); get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm), 1,&ssize,&sindex,&sgrpname); } else { ssize = atoms.nr; sindex = NULL; } printf("Translating %d atoms (out of %d) by %g %g %g nm\n",ssize,natom, translation[XX],translation[YY],translation[ZZ]); if (sindex) { for(i=0; i<ssize; i++) rvec_inc(x[sindex[i]],translation); } else { for(i=0; i<natom; i++) rvec_inc(x[i],translation); } } if (bRotate) { /* Rotate */ printf("Rotating %g, %g, %g degrees around the X, Y and Z axis respectively\n",rotangles[XX],rotangles[YY],rotangles[ZZ]); for(i=0; i<DIM; i++) rotangles[i] *= DEG2RAD; rotate_conf(natom,x,v,rotangles[XX],rotangles[YY],rotangles[ZZ]); } if (bCalcGeom) { /* recalc geometrical center and max and min coordinates and size */ calc_geom(ssize,sindex,x,gc,min,max,FALSE); rvec_sub(max, min, size); if (bScale || bOrient || bRotate) printf("new system size : %6.3f %6.3f %6.3f\n", size[XX],size[YY],size[ZZ]); } if (bSetSize || bDist || (btype[0][0]=='t' && bSetAng)) { ePBC = epbcXYZ; if (!(bSetSize || bDist)) for (i=0; i<DIM; i++) newbox[i] = norm(box[i]); clear_mat(box); /* calculate new boxsize */ switch(btype[0][0]){ case 't': if (bDist) for(i=0; i<DIM; i++) newbox[i] = size[i]+2*dist; if (!bSetAng) { box[XX][XX] = newbox[XX]; box[YY][YY] = newbox[YY]; box[ZZ][ZZ] = newbox[ZZ]; } else { matrix_convert(box,newbox,newang); } break; case 'c': case 'd': case 'o': if (bSetSize) d = newbox[0]; else d = diam+2*dist; if (btype[0][0] == 'c') for(i=0; i<DIM; i++) box[i][i] = d; else if (btype[0][0] == 'd') { box[XX][XX] = d; box[YY][YY] = d; box[ZZ][XX] = d/2; box[ZZ][YY] = d/2; box[ZZ][ZZ] = d*sqrt(2)/2; } else { box[XX][XX] = d; box[YY][XX] = d/3; box[YY][YY] = d*sqrt(2)*2/3; box[ZZ][XX] = -d/3; box[ZZ][YY] = d*sqrt(2)/3; box[ZZ][ZZ] = d*sqrt(6)/3; } break; } } /* calculate new coords for geometrical center */ if (!bSetCenter) calc_box_center(ecenterDEF,box,center); /* center molecule on 'center' */ if (bCenter) center_conf(natom,x,center,gc); /* print some */ if (bCalcGeom) { calc_geom(ssize,sindex,x, gc, min, max, FALSE); printf("new center :%7.3f%7.3f%7.3f (nm)\n",gc[XX],gc[YY],gc[ZZ]); } if (bOrient || bScale || bDist || bSetSize) { printf("new box vectors :%7.3f%7.3f%7.3f (nm)\n", norm(box[XX]), norm(box[YY]), norm(box[ZZ])); printf("new box angles :%7.2f%7.2f%7.2f (degrees)\n", norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])), norm2(box[ZZ])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])), norm2(box[YY])==0 ? 0 : RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY]))); printf("new box volume :%7.2f (nm^3)\n",det(box)); } if (check_box(epbcXYZ,box)) printf("\nWARNING: %s\n",check_box(epbcXYZ,box)); if (bDist && btype[0][0]=='t') { if(TRICLINIC(box)) { printf("\nWARNING: Your box is triclinic with non-orthogonal axes. In this case, the\n" "distance from the solute to a box surface along the corresponding normal\n" "vector might be somewhat smaller than your specified value %f.\n" "You can check the actual value with g_mindist -pi\n",dist); } else { printf("\nWARNING: No boxtype specified - distance condition applied in each dimension.\n" "If the molecule rotates the actual distance will be smaller. You might want\n" "to use a cubic box instead, or why not try a dodecahedron today?\n"); } } if (bCONECT && (outftp == efPDB) && (inftp == efTPR)) conect = gmx_conect_generate(top); else conect = NULL; if (bIndex) { fprintf(stderr,"\nSelect a group for output:\n"); get_index(&atoms,opt2fn_null("-n",NFILE,fnm), 1,&isize,&index,&grpname); if (opt2parg_bSet("-label",NPA,pa)) { for(i=0; (i<atoms.nr); i++) atoms.resinfo[atoms.atom[i].resind].chainid=label[0]; } if (opt2bSet("-bf",NFILE,fnm) || bLegend) { gmx_fatal(FARGS,"Sorry, cannot do bfactors with an index group."); } if (outftp == efPDB) { out=ffopen(outfile,"w"); write_pdbfile_indexed(out,title,&atoms,x,ePBC,box,' ',1,isize,index,conect,TRUE); ffclose(out); } else { write_sto_conf_indexed(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box,isize,index); } } else { if ((outftp == efPDB) || (outftp == efPQR)) { out=ffopen(outfile,"w"); if (bMead) { set_pdb_wide_format(TRUE); fprintf(out,"REMARK " "The B-factors in this file hold atomic radii\n"); fprintf(out,"REMARK " "The occupancy in this file hold atomic charges\n"); } else if (bGrasp) { fprintf(out,"GRASP PDB FILE\nFORMAT NUMBER=1\n"); fprintf(out,"REMARK " "The B-factors in this file hold atomic charges\n"); fprintf(out,"REMARK " "The occupancy in this file hold atomic radii\n"); } else if (opt2bSet("-bf",NFILE,fnm)) { read_bfac(opt2fn("-bf",NFILE,fnm),&n_bfac,&bfac,&bfac_nr); set_pdb_conf_bfac(atoms.nr,atoms.nres,&atoms, n_bfac,bfac,bfac_nr,peratom); } if (opt2parg_bSet("-label",NPA,pa)) { for(i=0; (i<atoms.nr); i++) atoms.resinfo[atoms.atom[i].resind].chainid=label[0]; } write_pdbfile(out,title,&atoms,x,ePBC,box,' ',-1,conect,TRUE); if (bLegend) pdb_legend(out,atoms.nr,atoms.nres,&atoms,x); if (visbox[0] > 0) visualize_box(out,bLegend ? atoms.nr+12 : atoms.nr, bLegend? atoms.nres=12 : atoms.nres,box,visbox); ffclose(out); } else write_sto_conf(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box); } gmx_atomprop_destroy(aps); do_view(oenv,outfile,NULL); thanx(stderr); return 0; }
real do_listed_vdw_q(int ftype,int nbonds, const t_iatom iatoms[],const t_iparams iparams[], const rvec x[],rvec f[],rvec fshift[], const t_pbc *pbc,const t_graph *g, real lambda,real *dvdlambda, const t_mdatoms *md, const t_forcerec *fr,gmx_grppairener_t *grppener, int *global_atom_index) { static gmx_bool bWarn=FALSE; real eps,r2,*tab,rtab2=0; rvec dx,x14[2],f14[2]; int i,ai,aj,itype; int typeA[2]={0,0},typeB[2]={0,1}; real chargeA[2]={0,0},chargeB[2]; int gid,shift_vir,shift_f; int j_index[] = { 0, 1 }; int i0=0,i1=1,i2=2; ivec dt; int outeriter,inneriter; int nthreads = 1; int count; real krf,crf,tabscale; int ntype=0; real *nbfp=NULL; real *egnb=NULL,*egcoul=NULL; t_nblist tmplist; int icoul,ivdw; gmx_bool bMolPBC,bFreeEnergy; t_pf_global *pf_global; #if GMX_THREAD_SHM_FDECOMP pthread_mutex_t mtx; #else void * mtx = NULL; #endif #if GMX_THREAD_SHM_FDECOMP pthread_mutex_initialize(&mtx); #endif bMolPBC = fr->bMolPBC; pf_global = fr->pf_global; switch (ftype) { case F_LJ14: case F_LJC14_Q: eps = fr->epsfac*fr->fudgeQQ; ntype = 1; egnb = grppener->ener[egLJ14]; egcoul = grppener->ener[egCOUL14]; break; case F_LJC_PAIRS_NB: eps = fr->epsfac; ntype = 1; egnb = grppener->ener[egLJSR]; egcoul = grppener->ener[egCOULSR]; break; default: gmx_fatal(FARGS,"Unknown function type %d in do_nonbonded14", ftype); } tab = fr->tab14.tab; rtab2 = sqr(fr->tab14.r); tabscale = fr->tab14.scale; krf = fr->k_rf; crf = fr->c_rf; /* Determine the values for icoul/ivdw. */ if (fr->bEwald) { icoul = 1; } else if(fr->bcoultab) { icoul = 3; } else if(fr->eeltype == eelRF_NEC) { icoul = 2; } else { icoul = 1; } if(fr->bvdwtab) { ivdw = 3; } else if(fr->bBHAM) { ivdw = 2; } else { ivdw = 1; } /* We don't do SSE or altivec here, due to large overhead for 4-fold * unrolling on short lists */ bFreeEnergy = FALSE; for(i=0; (i<nbonds); ) { itype = iatoms[i++]; ai = iatoms[i++]; aj = iatoms[i++]; gid = GID(md->cENER[ai],md->cENER[aj],md->nenergrp); switch (ftype) { case F_LJ14: bFreeEnergy = (fr->efep != efepNO && ((md->nPerturbed && (md->bPerturbed[ai] || md->bPerturbed[aj])) || iparams[itype].lj14.c6A != iparams[itype].lj14.c6B || iparams[itype].lj14.c12A != iparams[itype].lj14.c12B)); chargeA[0] = md->chargeA[ai]; chargeA[1] = md->chargeA[aj]; nbfp = (real *)&(iparams[itype].lj14.c6A); break; case F_LJC14_Q: eps = fr->epsfac*iparams[itype].ljc14.fqq; chargeA[0] = iparams[itype].ljc14.qi; chargeA[1] = iparams[itype].ljc14.qj; nbfp = (real *)&(iparams[itype].ljc14.c6); break; case F_LJC_PAIRS_NB: chargeA[0] = iparams[itype].ljcnb.qi; chargeA[1] = iparams[itype].ljcnb.qj; nbfp = (real *)&(iparams[itype].ljcnb.c6); break; } if (!bMolPBC) { /* This is a bonded interaction, atoms are in the same box */ shift_f = CENTRAL; r2 = distance2(x[ai],x[aj]); } else { /* Apply full periodic boundary conditions */ shift_f = pbc_dx_aiuc(pbc,x[ai],x[aj],dx); r2 = norm2(dx); } if (r2 >= rtab2) { if (!bWarn) { fprintf(stderr,"Warning: 1-4 interaction between %d and %d " "at distance %.3f which is larger than the 1-4 table size %.3f nm\n", glatnr(global_atom_index,ai), glatnr(global_atom_index,aj), sqrt(r2), sqrt(rtab2)); fprintf(stderr,"These are ignored for the rest of the simulation\n"); fprintf(stderr,"This usually means your system is exploding,\n" "if not, you should increase table-extension in your mdp file\n" "or with user tables increase the table size\n"); bWarn = TRUE; } if (debug) fprintf(debug,"%8f %8f %8f\n%8f %8f %8f\n1-4 (%d,%d) interaction not within cut-off! r=%g. Ignored\n", x[ai][XX],x[ai][YY],x[ai][ZZ], x[aj][XX],x[aj][YY],x[aj][ZZ], glatnr(global_atom_index,ai), glatnr(global_atom_index,aj), sqrt(r2)); } else { copy_rvec(x[ai],x14[0]); copy_rvec(x[aj],x14[1]); clear_rvec(f14[0]); clear_rvec(f14[1]); #ifdef DEBUG fprintf(debug,"LJ14: grp-i=%2d, grp-j=%2d, ngrp=%2d, GID=%d\n", md->cENER[ai],md->cENER[aj],md->nenergrp,gid); #endif outeriter = inneriter = count = 0; if (bFreeEnergy) { chargeB[0] = md->chargeB[ai]; chargeB[1] = md->chargeB[aj]; /* We pass &(iparams[itype].lj14.c6A) as LJ parameter matrix * to the innerloops. * Here we use that the LJ-14 parameters are stored in iparams * as c6A,c12A,c6B,c12B, which are referenced correctly * in the innerloops if we assign type combinations 0-0 and 0-1 * to atom pair ai-aj in topologies A and B respectively. */ if(ivdw==2) { gmx_fatal(FARGS,"Cannot do free energy Buckingham interactions."); } count = 0; gmx_nb_free_energy_kernel(icoul, ivdw, i1, &i0, j_index, &i1, &shift_f, fr->shift_vec[0], fshift[0], &gid, x14[0], f14[0], chargeA, chargeB, eps, krf, crf, fr->ewaldcoeff, egcoul, typeA, typeB, ntype, nbfp, egnb, tabscale, tab, lambda, dvdlambda, fr->sc_alpha, fr->sc_power, fr->sc_sigma6_def, fr->sc_sigma6_min, TRUE, &outeriter, &inneriter); } else { /* Not perturbed - call kernel 330 */ nb_kernel330 ( &i1, &i0, j_index, &i1, &shift_f, fr->shift_vec[0], fshift[0], &gid, x14[0], f14[0], chargeA, &eps, &krf, &crf, egcoul, typeA, &ntype, nbfp, egnb, &tabscale, tab, NULL, NULL, NULL, NULL, &nthreads, &count, (void *)&mtx, &outeriter, &inneriter, NULL); } /* Add the forces */ rvec_inc(f[ai],f14[0]); rvec_dec(f[aj],f14[0]); if (pf_global->bInitialized) pf_atom_add_bonded(pf_global, ai, aj, PF_INTER_NB14, f14[0]); if (g) { /* Correct the shift forces using the graph */ ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt); shift_vir = IVEC2IS(dt); rvec_inc(fshift[shift_vir],f14[0]); rvec_dec(fshift[CENTRAL],f14[0]); } /* flops: eNR_KERNEL_OUTER + eNR_KERNEL330 + 12 */ } } return 0.0; }
void add_conf(t_atoms *atoms, rvec **x, rvec **v, real **r, gmx_bool bSrenew, int ePBC, matrix box, gmx_bool bInsert, t_atoms *atoms_solvt, rvec *x_solvt, rvec *v_solvt, real *r_solvt, gmx_bool bVerbose, real rshell, int max_sol, const output_env_t oenv) { t_nblist *nlist; t_atoms *atoms_all; real max_vdw, *r_prot, *r_all, n2, r2, ib1, ib2; int natoms_prot, natoms_solvt; int i, j, jj, m, j0, j1, jjj, jnres, jnr, inr, iprot, is1, is2; int prev, resnr, nresadd, d, k, ncells, maxincell; int dx0, dx1, dy0, dy1, dz0, dz1; int ntest, nremove, nkeep; rvec dx, xi, xj, xpp, *x_all, *v_all; gmx_bool *remove, *keep; int bSolSol; natoms_prot = atoms->nr; natoms_solvt = atoms_solvt->nr; if (natoms_solvt <= 0) { fprintf(stderr, "WARNING: Nothing to add\n"); return; } if (ePBC == epbcSCREW) { gmx_fatal(FARGS, "Sorry, %s pbc is not yet supported", epbc_names[ePBC]); } if (bVerbose) { fprintf(stderr, "Calculating Overlap...\n"); } /* Set margin around box edges to largest solvent dimension. * The maximum distance between atoms in a solvent molecule should * be calculated. At the moment a fudge factor of 3 is used. */ r_prot = *r; box_margin = 3*find_max_real(natoms_solvt, r_solvt); max_vdw = max(3*find_max_real(natoms_prot, r_prot), box_margin); fprintf(stderr, "box_margin = %g\n", box_margin); snew(remove, natoms_solvt); nremove = 0; if (!bInsert) { for (i = 0; i < atoms_solvt->nr; i++) { if (outside_box_plus_margin(x_solvt[i], box) ) { i = mark_res(i, remove, atoms_solvt->nr, atoms_solvt->atom, &nremove); } } fprintf(stderr, "Removed %d atoms that were outside the box\n", nremove); } /* Define grid stuff for genbox */ /* Largest VDW radius */ snew(r_all, natoms_prot+natoms_solvt); for (i = j = 0; i < natoms_prot; i++, j++) { r_all[j] = r_prot[i]; } for (i = 0; i < natoms_solvt; i++, j++) { r_all[j] = r_solvt[i]; } /* Combine arrays */ combine_atoms(atoms, atoms_solvt, *x, v ? *v : NULL, x_solvt, v_solvt, &atoms_all, &x_all, &v_all); /* Do neighboursearching step */ do_nsgrid(stdout, bVerbose, box, x_all, atoms_all, max_vdw, oenv); /* check solvent with solute */ nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]); fprintf(stderr, "nri = %d, nrj = %d\n", nlist->nri, nlist->nrj); for (bSolSol = 0; (bSolSol <= (bInsert ? 0 : 1)); bSolSol++) { ntest = nremove = 0; fprintf(stderr, "Checking %s-Solvent overlap:", bSolSol ? "Solvent" : "Protein"); for (i = 0; (i < nlist->nri && nremove < natoms_solvt); i++) { inr = nlist->iinr[i]; j0 = nlist->jindex[i]; j1 = nlist->jindex[i+1]; rvec_add(x_all[inr], fr->shift_vec[nlist->shift[i]], xi); for (j = j0; (j < j1 && nremove < natoms_solvt); j++) { jnr = nlist->jjnr[j]; copy_rvec(x_all[jnr], xj); /* Check solvent-protein and solvent-solvent */ is1 = inr-natoms_prot; is2 = jnr-natoms_prot; /* Check if at least one of the atoms is a solvent that is not yet * listed for removal, and if both are solvent, that they are not in the * same residue. */ if ((!bSolSol && bXor((is1 >= 0), (is2 >= 0)) && /* One atom is protein */ ((is1 < 0) || ((is1 >= 0) && !remove[is1])) && ((is2 < 0) || ((is2 >= 0) && !remove[is2]))) || (bSolSol && (is1 >= 0) && (!remove[is1]) && /* is1 is solvent */ (is2 >= 0) && (!remove[is2]) && /* is2 is solvent */ (bInsert || /* when inserting also check inside the box */ (outside_box_minus_margin2(x_solvt[is1], box) && /* is1 on edge */ outside_box_minus_margin2(x_solvt[is2], box)) /* is2 on edge */ ) && (atoms_solvt->atom[is1].resind != /* Not the same residue */ atoms_solvt->atom[is2].resind))) { ntest++; rvec_sub(xi, xj, dx); n2 = norm2(dx); r2 = sqr(r_all[inr]+r_all[jnr]); if (n2 < r2) { if (bInsert) { nremove = natoms_solvt; for (k = 0; k < nremove; k++) { remove[k] = TRUE; } } /* Need only remove one of the solvents... */ if (is2 >= 0) { (void) mark_res(is2, remove, natoms_solvt, atoms_solvt->atom, &nremove); } else if (is1 >= 0) { (void) mark_res(is1, remove, natoms_solvt, atoms_solvt->atom, &nremove); } else { fprintf(stderr, "Neither atom is solvent%d %d\n", is1, is2); } } } } } if (!bInsert) { fprintf(stderr, " tested %d pairs, removed %d atoms.\n", ntest, nremove); } } if (debug) { for (i = 0; i < natoms_solvt; i++) { fprintf(debug, "remove[%5d] = %s\n", i, bool_names[remove[i]]); } } /* Search again, now with another cut-off */ if (rshell > 0) { do_nsgrid(stdout, bVerbose, box, x_all, atoms_all, rshell, oenv); nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]); fprintf(stderr, "nri = %d, nrj = %d\n", nlist->nri, nlist->nrj); nkeep = 0; snew(keep, natoms_solvt); for (i = 0; i < nlist->nri; i++) { inr = nlist->iinr[i]; j0 = nlist->jindex[i]; j1 = nlist->jindex[i+1]; for (j = j0; j < j1; j++) { jnr = nlist->jjnr[j]; /* Check solvent-protein and solvent-solvent */ is1 = inr-natoms_prot; is2 = jnr-natoms_prot; /* Check if at least one of the atoms is a solvent that is not yet * listed for removal, and if both are solvent, that they are not in the * same residue. */ if (is1 >= 0 && is2 < 0) { mark_res(is1, keep, natoms_solvt, atoms_solvt->atom, &nkeep); } else if (is1 < 0 && is2 >= 0) { mark_res(is2, keep, natoms_solvt, atoms_solvt->atom, &nkeep); } } } fprintf(stderr, "Keeping %d solvent atoms after proximity check\n", nkeep); for (i = 0; i < natoms_solvt; i++) { remove[i] = remove[i] || !keep[i]; } sfree(keep); } /* count how many atoms and residues will be added and make space */ if (bInsert) { j = atoms_solvt->nr; jnres = atoms_solvt->nres; } else { j = 0; jnres = 0; for (i = 0; ((i < atoms_solvt->nr) && ((max_sol == 0) || (jnres < max_sol))); i++) { if (!remove[i]) { j++; if ((i == 0) || (atoms_solvt->atom[i].resind != atoms_solvt->atom[i-1].resind)) { jnres++; } } } } if (debug) { fprintf(debug, "Will add %d atoms in %d residues\n", j, jnres); } if (!bInsert) { /* Flag the remaing solvent atoms to be removed */ jjj = atoms_solvt->atom[i-1].resind; for (; (i < atoms_solvt->nr); i++) { if (atoms_solvt->atom[i].resind > jjj) { remove[i] = TRUE; } else { j++; } } } if (bSrenew) { srenew(atoms->resinfo, atoms->nres+jnres); srenew(atoms->atomname, atoms->nr+j); srenew(atoms->atom, atoms->nr+j); srenew(*x, atoms->nr+j); if (v) { srenew(*v, atoms->nr+j); } srenew(*r, atoms->nr+j); } /* add the selected atoms_solvt to atoms */ if (atoms->nr > 0) { resnr = atoms->resinfo[atoms->atom[atoms->nr-1].resind].nr; } else { resnr = 0; } prev = -1; nresadd = 0; for (i = 0; i < atoms_solvt->nr; i++) { if (!remove[i]) { if (prev == -1 || atoms_solvt->atom[i].resind != atoms_solvt->atom[prev].resind) { nresadd++; atoms->nres++; resnr++; atoms->resinfo[atoms->nres-1] = atoms_solvt->resinfo[atoms_solvt->atom[i].resind]; atoms->resinfo[atoms->nres-1].nr = resnr; /* calculate shift of the solvent molecule using the first atom */ copy_rvec(x_solvt[i], dx); put_atoms_in_box(ePBC, box, 1, &dx); rvec_dec(dx, x_solvt[i]); } atoms->atom[atoms->nr] = atoms_solvt->atom[i]; atoms->atomname[atoms->nr] = atoms_solvt->atomname[i]; rvec_add(x_solvt[i], dx, (*x)[atoms->nr]); if (v) { copy_rvec(v_solvt[i], (*v)[atoms->nr]); } (*r)[atoms->nr] = r_solvt[i]; atoms->atom[atoms->nr].resind = atoms->nres-1; atoms->nr++; prev = i; } } if (bSrenew) { srenew(atoms->resinfo, atoms->nres+nresadd); } if (bVerbose) { fprintf(stderr, "Added %d molecules\n", nresadd); } sfree(remove); done_atom(atoms_all); sfree(x_all); sfree(v_all); }
real ewald_LRcorrection(FILE *fplog, int start, int end, t_commrec *cr, int thread, t_forcerec *fr, real *chargeA, real *chargeB, gmx_bool calc_excl_corr, t_blocka *excl, rvec x[], matrix box, rvec mu_tot[], int ewald_geometry, real epsilon_surface, rvec *f, tensor vir, real lambda, real *dvdlambda) { int i, i1, i2, j, k, m, iv, jv, q; atom_id *AA; double q2sumA, q2sumB, Vexcl, dvdl_excl; /* Necessary for precision */ real one_4pi_eps; real v, vc, qiA, qiB, dr, dr2, rinv, fscal, enercorr; real Vself[2], Vdipole[2], rinv2, ewc = fr->ewaldcoeff, ewcdr; rvec df, dx, mutot[2], dipcorrA, dipcorrB; tensor dxdf; real vol = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]; real L1, dipole_coeff, qqA, qqB, qqL, vr0; /*#define TABLES*/ #ifdef TABLES real tabscale = fr->tabscale; real eps, eps2, VV, FF, F, Y, Geps, Heps2, Fp, fijC, r1t; real *VFtab = fr->coulvdwtab; int n0, n1, nnn; #endif gmx_bool bFreeEnergy = (chargeB != NULL); gmx_bool bMolPBC = fr->bMolPBC; one_4pi_eps = ONE_4PI_EPS0/fr->epsilon_r; vr0 = ewc*M_2_SQRTPI; AA = excl->a; Vexcl = 0; dvdl_excl = 0; q2sumA = 0; q2sumB = 0; Vdipole[0] = 0; Vdipole[1] = 0; L1 = 1.0-lambda; /* Note that we have to transform back to gromacs units, since * mu_tot contains the dipole in debye units (for output). */ for (i = 0; (i < DIM); i++) { mutot[0][i] = mu_tot[0][i]*DEBYE2ENM; mutot[1][i] = mu_tot[1][i]*DEBYE2ENM; dipcorrA[i] = 0; dipcorrB[i] = 0; } dipole_coeff = 0; switch (ewald_geometry) { case eewg3D: if (epsilon_surface != 0) { dipole_coeff = 2*M_PI*ONE_4PI_EPS0/((2*epsilon_surface + fr->epsilon_r)*vol); for (i = 0; (i < DIM); i++) { dipcorrA[i] = 2*dipole_coeff*mutot[0][i]; dipcorrB[i] = 2*dipole_coeff*mutot[1][i]; } } break; case eewg3DC: dipole_coeff = 2*M_PI*one_4pi_eps/vol; dipcorrA[ZZ] = 2*dipole_coeff*mutot[0][ZZ]; dipcorrB[ZZ] = 2*dipole_coeff*mutot[1][ZZ]; break; default: gmx_incons("Unsupported Ewald geometry"); break; } if (debug) { fprintf(debug, "dipcorr = %8.3f %8.3f %8.3f\n", dipcorrA[XX], dipcorrA[YY], dipcorrA[ZZ]); fprintf(debug, "mutot = %8.3f %8.3f %8.3f\n", mutot[0][XX], mutot[0][YY], mutot[0][ZZ]); } clear_mat(dxdf); if ((calc_excl_corr || dipole_coeff != 0) && !bFreeEnergy) { for (i = start; (i < end); i++) { /* Initiate local variables (for this i-particle) to 0 */ qiA = chargeA[i]*one_4pi_eps; if (calc_excl_corr) { i1 = excl->index[i]; i2 = excl->index[i+1]; /* Loop over excluded neighbours */ for (j = i1; (j < i2); j++) { k = AA[j]; /* * First we must test whether k <> i, and then, because the * exclusions are all listed twice i->k and k->i we must select * just one of the two. * As a minor optimization we only compute forces when the charges * are non-zero. */ if (k > i) { qqA = qiA*chargeA[k]; if (qqA != 0.0) { rvec_sub(x[i], x[k], dx); if (bMolPBC) { /* Cheap pbc_dx, assume excluded pairs are at short distance. */ for (m = DIM-1; (m >= 0); m--) { if (dx[m] > 0.5*box[m][m]) { rvec_dec(dx, box[m]); } else if (dx[m] < -0.5*box[m][m]) { rvec_inc(dx, box[m]); } } } dr2 = norm2(dx); /* Distance between two excluded particles may be zero in the * case of shells */ if (dr2 != 0) { rinv = gmx_invsqrt(dr2); rinv2 = rinv*rinv; dr = 1.0/rinv; #ifdef TABLES r1t = tabscale*dr; n0 = r1t; assert(n0 >= 3); n1 = 12*n0; eps = r1t-n0; eps2 = eps*eps; nnn = n1; Y = VFtab[nnn]; F = VFtab[nnn+1]; Geps = eps*VFtab[nnn+2]; Heps2 = eps2*VFtab[nnn+3]; Fp = F+Geps+Heps2; VV = Y+eps*Fp; FF = Fp+Geps+2.0*Heps2; vc = qqA*(rinv-VV); fijC = qqA*FF; Vexcl += vc; fscal = vc*rinv2+fijC*tabscale*rinv; /* End of tabulated interaction part */ #else /* This is the code you would want instead if not using * tables: */ ewcdr = ewc*dr; vc = qqA*gmx_erf(ewcdr)*rinv; Vexcl += vc; #ifdef GMX_DOUBLE /* Relative accuracy at R_ERF_R_INACC of 3e-10 */ #define R_ERF_R_INACC 0.006 #else /* Relative accuracy at R_ERF_R_INACC of 2e-5 */ #define R_ERF_R_INACC 0.1 #endif if (ewcdr > R_ERF_R_INACC) { fscal = rinv2*(vc - qqA*ewc*M_2_SQRTPI*exp(-ewcdr*ewcdr)); } else { /* Use a fourth order series expansion for small ewcdr */ fscal = ewc*ewc*qqA*vr0*(2.0/3.0 - 0.4*ewcdr*ewcdr); } #endif /* The force vector is obtained by multiplication with the * distance vector */ svmul(fscal, dx, df); rvec_inc(f[k], df); rvec_dec(f[i], df); for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { dxdf[iv][jv] += dx[iv]*df[jv]; } } } else { Vexcl += qqA*vr0; } } } } } /* Dipole correction on force */ if (dipole_coeff != 0) { for (j = 0; (j < DIM); j++) { f[i][j] -= dipcorrA[j]*chargeA[i]; } } } } else if (calc_excl_corr || dipole_coeff != 0) { for (i = start; (i < end); i++) { /* Initiate local variables (for this i-particle) to 0 */ qiA = chargeA[i]*one_4pi_eps; qiB = chargeB[i]*one_4pi_eps; if (calc_excl_corr) { i1 = excl->index[i]; i2 = excl->index[i+1]; /* Loop over excluded neighbours */ for (j = i1; (j < i2); j++) { k = AA[j]; if (k > i) { qqA = qiA*chargeA[k]; qqB = qiB*chargeB[k]; if (qqA != 0.0 || qqB != 0.0) { qqL = L1*qqA + lambda*qqB; rvec_sub(x[i], x[k], dx); if (bMolPBC) { /* Cheap pbc_dx, assume excluded pairs are at short distance. */ for (m = DIM-1; (m >= 0); m--) { if (dx[m] > 0.5*box[m][m]) { rvec_dec(dx, box[m]); } else if (dx[m] < -0.5*box[m][m]) { rvec_inc(dx, box[m]); } } } dr2 = norm2(dx); if (dr2 != 0) { rinv = gmx_invsqrt(dr2); rinv2 = rinv*rinv; dr = 1.0/rinv; v = gmx_erf(ewc*dr)*rinv; vc = qqL*v; Vexcl += vc; fscal = rinv2*(vc-qqL*ewc*M_2_SQRTPI*exp(-ewc*ewc*dr2)); svmul(fscal, dx, df); rvec_inc(f[k], df); rvec_dec(f[i], df); for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { dxdf[iv][jv] += dx[iv]*df[jv]; } } dvdl_excl += (qqB - qqA)*v; } else { Vexcl += qqL*vr0; dvdl_excl += (qqB - qqA)*vr0; } } } } } /* Dipole correction on force */ if (dipole_coeff != 0) { for (j = 0; (j < DIM); j++) { f[i][j] -= L1*dipcorrA[j]*chargeA[i] + lambda*dipcorrB[j]*chargeB[i]; } } } } for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { vir[iv][jv] += 0.5*dxdf[iv][jv]; } } Vself[0] = 0; Vself[1] = 0; /* Global corrections only on master process */ if (MASTER(cr) && thread == 0) { for (q = 0; q < (bFreeEnergy ? 2 : 1); q++) { if (calc_excl_corr) { /* Self-energy correction */ Vself[q] = ewc*one_4pi_eps*fr->q2sum[q]*M_1_SQRTPI; } /* Apply surface dipole correction: * correction = dipole_coeff * (dipole)^2 */ if (dipole_coeff != 0) { if (ewald_geometry == eewg3D) { Vdipole[q] = dipole_coeff*iprod(mutot[q], mutot[q]); } else if (ewald_geometry == eewg3DC) { Vdipole[q] = dipole_coeff*mutot[q][ZZ]*mutot[q][ZZ]; } } } } if (!bFreeEnergy) { enercorr = Vdipole[0] - Vself[0] - Vexcl; } else { enercorr = L1*(Vdipole[0] - Vself[0]) + lambda*(Vdipole[1] - Vself[1]) - Vexcl; *dvdlambda += Vdipole[1] - Vself[1] - (Vdipole[0] - Vself[0]) - dvdl_excl; } if (debug) { fprintf(debug, "Long Range corrections for Ewald interactions:\n"); fprintf(debug, "start=%d,natoms=%d\n", start, end-start); fprintf(debug, "q2sum = %g, Vself=%g\n", L1*q2sumA+lambda*q2sumB, L1*Vself[0]+lambda*Vself[1]); fprintf(debug, "Long Range correction: Vexcl=%g\n", Vexcl); if (MASTER(cr) && thread == 0) { if (epsilon_surface > 0 || ewald_geometry == eewg3DC) { fprintf(debug, "Total dipole correction: Vdipole=%g\n", L1*Vdipole[0]+lambda*Vdipole[1]); } } } /* Return the correction to the energy */ return enercorr; }
real RF_excl_correction(FILE *log, const t_forcerec *fr,t_graph *g, const t_mdatoms *mdatoms,const t_blocka *excl, rvec x[],rvec f[],rvec *fshift,const t_pbc *pbc, real lambda,real *dvdlambda) { /* Calculate the reaction-field energy correction for this node: * epsfac q_i q_j (k_rf r_ij^2 - c_rf) * and force correction for all excluded pairs, including self pairs. */ int top,i,j,j1,j2,k,ki; double q2sumA,q2sumB,ener; const real *chargeA,*chargeB; real ek,ec,L1,qiA,qiB,qqA,qqB,qqL,v; rvec dx,df; atom_id *AA; ivec dt; int start = mdatoms->start; int end = mdatoms->homenr+start; int niat; gmx_bool bMolPBC = fr->bMolPBC; if (fr->n_tpi) /* For test particle insertion we only correct for the test molecule */ start = mdatoms->nr - fr->n_tpi; ek = fr->epsfac*fr->k_rf; ec = fr->epsfac*fr->c_rf; chargeA = mdatoms->chargeA; chargeB = mdatoms->chargeB; AA = excl->a; ki = CENTRAL; if (fr->bDomDec) niat = excl->nr; else niat = end; q2sumA = 0; q2sumB = 0; ener = 0; if (mdatoms->nChargePerturbed == 0) { for(i=start; i<niat; i++) { qiA = chargeA[i]; if (i < end) q2sumA += qiA*qiA; /* Do the exclusions */ j1 = excl->index[i]; j2 = excl->index[i+1]; for(j=j1; j<j2; j++) { k = AA[j]; if (k > i) { qqA = qiA*chargeA[k]; if (qqA != 0) { if (g) { rvec_sub(x[i],x[k],dx); ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt); ki=IVEC2IS(dt); } else if (bMolPBC) { ki = pbc_dx_aiuc(pbc,x[i],x[k],dx); } else rvec_sub(x[i],x[k],dx); ener += qqA*(ek*norm2(dx) - ec); svmul(-2*qqA*ek,dx,df); rvec_inc(f[i],df); rvec_dec(f[k],df); rvec_inc(fshift[ki],df); rvec_dec(fshift[CENTRAL],df); } } } } ener += -0.5*ec*q2sumA; } else { L1 = 1.0 - lambda; for(i=start; i<niat; i++) { qiA = chargeA[i]; qiB = chargeB[i]; if (i < end) { q2sumA += qiA*qiA; q2sumB += qiB*qiB; } /* Do the exclusions */ j1 = excl->index[i]; j2 = excl->index[i+1]; for(j=j1; j<j2; j++) { k = AA[j]; if (k > i) { qqA = qiA*chargeA[k]; qqB = qiB*chargeB[k]; if (qqA != 0 || qqB != 0) { qqL = L1*qqA + lambda*qqB; if (g) { rvec_sub(x[i],x[k],dx); ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt); ki=IVEC2IS(dt); } else if (bMolPBC) { ki = pbc_dx_aiuc(pbc,x[i],x[k],dx); } else rvec_sub(x[i],x[k],dx); v = ek*norm2(dx) - ec; ener += qqL*v; svmul(-2*qqL*ek,dx,df); rvec_inc(f[i],df); rvec_dec(f[k],df); rvec_inc(fshift[ki],df); rvec_dec(fshift[CENTRAL],df); *dvdlambda += (qqB - qqA)*v; } } } } ener += -0.5*ec*(L1*q2sumA + lambda*q2sumB); *dvdlambda += -0.5*ec*(q2sumB - q2sumA); } if (debug) fprintf(debug,"RF exclusion energy: %g\n",ener); return ener; }
void init_orires(FILE *fplog,const gmx_mtop_t *mtop, rvec xref[], const t_inputrec *ir, const gmx_multisim_t *ms,t_oriresdata *od, t_state *state) { int i,j,d,ex,nmol,nr,*nr_ex; double mtot; rvec com; gmx_mtop_ilistloop_t iloop; t_ilist *il; gmx_mtop_atomloop_all_t aloop; t_atom *atom; od->fc = ir->orires_fc; od->nex = 0; od->S = NULL; od->nr = gmx_mtop_ftype_count(mtop,F_ORIRES); if (od->nr == 0) { return; } nr_ex = NULL; iloop = gmx_mtop_ilistloop_init(mtop); while (gmx_mtop_ilistloop_next(iloop,&il,&nmol)) { for(i=0; i<il[F_ORIRES].nr; i+=3) { ex = mtop->ffparams.iparams[il[F_ORIRES].iatoms[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 (ms) { snew(od->Dins,od->nr); } else { od->Dins = od->Dinsl; } if (ir->orires_tau == 0) { od->Dtav = od->Dins; od->edt = 0.0; od->edt1 = 1.0; } else { snew(od->Dtav,od->nr); od->edt = exp(-ir->delta_t/ir->orires_tau); od->edt1 = 1.0 - od->edt; /* Extend the state with the orires history */ state->flags |= (1<<estORIRE_INITF); state->hist.orire_initf = 1; state->flags |= (1<<estORIRE_DTAV); state->hist.norire_Dtav = od->nr*5; snew(state->hist.orire_Dtav,state->hist.norire_Dtav); } snew(od->oinsl,od->nr); if (ms) { snew(od->oins,od->nr); } else { od->oins = od->oinsl; } if (ir->orires_tau == 0) { 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<mtop->natoms; i++) { if (ggrpnr(&mtop->groups,egcORFIT,i) == 0) { od->nref++; } } snew(od->mref,od->nref); snew(od->xref,od->nref); snew(od->xtmp,od->nref); snew(od->eig,od->nex*12); /* 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; aloop = gmx_mtop_atomloop_all_init(mtop); while(gmx_mtop_atomloop_all_next(aloop,&i,&atom)) { if (mtop->groups.grpnr[egcORFIT] == NULL || mtop->groups.grpnr[egcORFIT][i] == 0) { /* Not correct for free-energy with changing masses */ od->mref[j] = atom->m; if (ms==NULL || MASTERSIM(ms)) { 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++; } } svmul(1.0/mtot,com,com); if (ms==NULL || MASTERSIM(ms)) { for(j=0; j<od->nref; j++) { rvec_dec(od->xref[j],com); } } fprintf(fplog,"Found %d orientation experiments\n",od->nex); for(i=0; i<od->nex; i++) { fprintf(fplog," experiment %d has %d restraints\n",i+1,nr_ex[i]); } sfree(nr_ex); fprintf(fplog," the fit group consists of %d atoms and has total mass %g\n", od->nref,mtot); if (ms) { fprintf(fplog," the orientation restraints are ensemble averaged over %d systems\n",ms->nsim); check_multi_int(fplog,ms,od->nr, "the number of orientation restraints"); check_multi_int(fplog,ms,od->nref, "the number of fit atoms for orientation restraining"); check_multi_int(fplog,ms,ir->nsteps,"nsteps"); /* Copy the reference coordinates from the master to the other nodes */ gmx_sum_sim(DIM*od->nref,od->xref[0],ms); } please_cite(fplog,"Hess2003"); }
static void list_trn(char *fn) { static real mass[5] = { 15.9994, 1.008, 1.008, 0.0, 0.0 }; int i,j=0,m,fpread,fpwrite,nframe; rvec *x,*v,*f,fmol[2],xcm[2],torque[j],dx; real mmm,len; matrix box; t_trnheader trn; gmx_bool bOK; printf("Going to open %s\n",fn); fpread = open_trn(fn,"r"); fpwrite = open_tpx(NULL,"w"); gmx_fio_setdebug(fpwrite,TRUE); mmm=mass[0]+2*mass[1]; for(i=0; (i<5); i++) mass[i] /= mmm; nframe = 0; while (fread_trnheader(fpread,&trn,&bOK)) { snew(x,trn.natoms); snew(v,trn.natoms); snew(f,trn.natoms); if (fread_htrn(fpread,&trn, trn.box_size ? box : NULL, trn.x_size ? x : NULL, trn.v_size ? v : NULL, trn.f_size ? f : NULL)) { if (trn.x_size && trn.f_size) { printf("There are %d atoms\n",trn.natoms); for(j=0; (j<2); j++) { clear_rvec(xcm[j]); clear_rvec(fmol[j]); clear_rvec(torque[j]); for(i=5*j; (i<5*j+5); i++) { rvec_inc(fmol[j],f[i]); for(m=0; (m<DIM); m++) xcm[j][m] += mass[i%5]*x[i][m]; } for(i=5*j; (i<5*j+5); i++) { rvec_dec(x[i],xcm[j]); cprod(x[i],f[i],dx); rvec_inc(torque[j],dx); rvec_inc(x[i],xcm[j]); } } pr_rvecs(stdout,0,"FMOL ",fmol,2); pr_rvecs(stdout,0,"TORQUE",torque,2); printf("Distance matrix Water1-Water2\n%5s",""); for(j=0; (j<5); j++) printf(" %10s",nm[j]); printf("\n"); for(j=0; (j<5); j++) { printf("%5s",nm[j]); for(i=5; (i<10); i++) { rvec_sub(x[i],x[j],dx); len = sqrt(iprod(dx,dx)); printf(" %10.7f",len); } printf("\n"); } } } sfree(x); sfree(v); sfree(f); nframe++; } if (!bOK) fprintf(stderr,"\nWARNING: Incomplete frame header: nr %d, t=%g\n", nframe,trn.t); close_tpx(fpwrite); close_trn(fpread); }
real calc_orires_dev(const gmx_multisim_t *ms, int nfa,const t_iatom forceatoms[],const t_iparams ip[], const t_mdatoms *md,const rvec x[],const t_pbc *pbc, t_fcdata *fcd,history_t *hist) { int fa,d,i,j,type,ex,nref; real edt,edt1,invn,pfac,r2,invr,corrfac,weight,wsv2,sw,dev; tensor *S,R,TMP; rvec5 *Dinsl,*Dins,*Dtav,*rhs; real *mref,***T; double mtot; rvec *xref,*xtmp,com,r_unrot,r; t_oriresdata *od; bool bTAV; const real two_thr=2.0/3.0; od = &(fcd->orires); if (od->nr == 0) { /* This means that this is not the master node */ gmx_fatal(FARGS,"Orientation restraints are only supported on the master node, use less processors"); } bTAV = (od->edt != 0); edt = od->edt; edt1 = od->edt1; S = od->S; Dinsl= od->Dinsl; Dins = od->Dins; Dtav = od->Dtav; T = od->TMP; rhs = od->tmp; nref = od->nref; mref = od->mref; xref = od->xref; xtmp = od->xtmp; if (bTAV) { od->exp_min_t_tau = hist->orire_initf*edt; /* Correction factor to correct for the lack of history * at short times. */ corrfac = 1.0/(1.0 - od->exp_min_t_tau); } else { corrfac = 1.0; } if (ms) { invn = 1.0/ms->nsim; } else { invn = 1.0; } clear_rvec(com); mtot = 0; j=0; for(i=0; i<md->nr; i++) { if (md->cORF[i] == 0) { copy_rvec(x[i],xtmp[j]); mref[j] = md->massT[i]; for(d=0; d<DIM; d++) { com[d] += mref[j]*xref[j][d]; } mtot += mref[j]; j++; } } svmul(1.0/mtot,com,com); for(j=0; j<nref; j++) { rvec_dec(xtmp[j],com); } /* Calculate the rotation matrix to rotate x to the reference orientation */ calc_fit_R(DIM,nref,mref,xref,xtmp,R); copy_mat(R,od->R); d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; if (pbc) { pbc_dx_aiuc(pbc,x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot); } else { rvec_sub(x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot); } mvmul(R,r_unrot,r); r2 = norm2(r); invr = invsqrt(r2); /* Calculate the prefactor for the D tensor, this includes the factor 3! */ pfac = ip[type].orires.c*invr*invr*3; for(i=0; i<ip[type].orires.power; i++) { pfac *= invr; } Dinsl[d][0] = pfac*(2*r[0]*r[0] + r[1]*r[1] - r2); Dinsl[d][1] = pfac*(2*r[0]*r[1]); Dinsl[d][2] = pfac*(2*r[0]*r[2]); Dinsl[d][3] = pfac*(2*r[1]*r[1] + r[0]*r[0] - r2); Dinsl[d][4] = pfac*(2*r[1]*r[2]); if (ms) { for(i=0; i<5; i++) { Dins[d][i] = Dinsl[d][i]*invn; } } d++; } if (ms) { gmx_sum_sim(5*od->nr,Dins[0],ms); } /* Calculate the order tensor S for each experiment via optimization */ for(ex=0; ex<od->nex; ex++) { for(i=0; i<5; i++) { rhs[ex][i] = 0; for(j=0; j<=i; j++) { T[ex][i][j] = 0; } } } d = 0; for(fa=0; fa<nfa; fa+=3) { if (bTAV) { /* Here we update Dtav in t_fcdata using the data in history_t. * Thus the results stay correct when this routine * is called multiple times. */ for(i=0; i<5; i++) { Dtav[d][i] = edt*hist->orire_Dtav[d*5+i] + edt1*Dins[d][i]; } } type = forceatoms[fa]; ex = ip[type].orires.ex; weight = ip[type].orires.kfac; /* Calculate the vector rhs and half the matrix T for the 5 equations */ for(i=0; i<5; i++) { rhs[ex][i] += Dtav[d][i]*ip[type].orires.obs*weight; for(j=0; j<=i; j++) { T[ex][i][j] += Dtav[d][i]*Dtav[d][j]*weight; } } d++; } /* Now we have all the data we can calculate S */ for(ex=0; ex<od->nex; ex++) { /* Correct corrfac and copy one half of T to the other half */ for(i=0; i<5; i++) { rhs[ex][i] *= corrfac; T[ex][i][i] *= sqr(corrfac); for(j=0; j<i; j++) { T[ex][i][j] *= sqr(corrfac); T[ex][j][i] = T[ex][i][j]; } } m_inv_gen(T[ex],5,T[ex]); /* Calculate the orientation tensor S for this experiment */ S[ex][0][0] = 0; S[ex][0][1] = 0; S[ex][0][2] = 0; S[ex][1][1] = 0; S[ex][1][2] = 0; for(i=0; i<5; i++) { S[ex][0][0] += 1.5*T[ex][0][i]*rhs[ex][i]; S[ex][0][1] += 1.5*T[ex][1][i]*rhs[ex][i]; S[ex][0][2] += 1.5*T[ex][2][i]*rhs[ex][i]; S[ex][1][1] += 1.5*T[ex][3][i]*rhs[ex][i]; S[ex][1][2] += 1.5*T[ex][4][i]*rhs[ex][i]; } S[ex][1][0] = S[ex][0][1]; S[ex][2][0] = S[ex][0][2]; S[ex][2][1] = S[ex][1][2]; S[ex][2][2] = -S[ex][0][0] - S[ex][1][1]; } wsv2 = 0; sw = 0; d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; ex = ip[type].orires.ex; od->otav[d] = two_thr* corrfac*(S[ex][0][0]*Dtav[d][0] + S[ex][0][1]*Dtav[d][1] + S[ex][0][2]*Dtav[d][2] + S[ex][1][1]*Dtav[d][3] + S[ex][1][2]*Dtav[d][4]); if (bTAV) { od->oins[d] = two_thr*(S[ex][0][0]*Dins[d][0] + S[ex][0][1]*Dins[d][1] + S[ex][0][2]*Dins[d][2] + S[ex][1][1]*Dins[d][3] + S[ex][1][2]*Dins[d][4]); } if (ms) { /* When ensemble averaging is used recalculate the local orientation * for output to the energy file. */ od->oinsl[d] = two_thr* (S[ex][0][0]*Dinsl[d][0] + S[ex][0][1]*Dinsl[d][1] + S[ex][0][2]*Dinsl[d][2] + S[ex][1][1]*Dinsl[d][3] + S[ex][1][2]*Dinsl[d][4]); } dev = od->otav[d] - ip[type].orires.obs; wsv2 += ip[type].orires.kfac*sqr(dev); sw += ip[type].orires.kfac; d++; } od->rmsdev = sqrt(wsv2/sw); /* Rotate the S matrices back, so we get the correct grad(tr(S D)) */ for(ex=0; ex<od->nex; ex++) { tmmul(R,S[ex],TMP); mmul(TMP,R,S[ex]); } return od->rmsdev; /* Approx. 120*nfa/3 flops */ }
/* There's nothing special to do here if just masses are perturbed, * but if either charge or type is perturbed then the implementation * requires that B states are defined for both charge and type, and * does not optimize for the cases where only one changes. * * The parameter vectors for B states are left undefined in atoms2md() * when either FEP is inactive, or when there are no mass/charge/type * perturbations. The parameter vectors for LJ-PME are likewise * undefined when LJ-PME is not active. This works because * bHaveChargeOrTypePerturbed handles the control flow. */ void ewald_LRcorrection(int numAtomsLocal, t_commrec *cr, int numThreads, int thread, t_forcerec *fr, real *chargeA, real *chargeB, real *C6A, real *C6B, real *sigmaA, real *sigmaB, real *sigma3A, real *sigma3B, gmx_bool bHaveChargeOrTypePerturbed, gmx_bool calc_excl_corr, t_blocka *excl, rvec x[], matrix box, rvec mu_tot[], int ewald_geometry, real epsilon_surface, rvec *f, tensor vir_q, tensor vir_lj, real *Vcorr_q, real *Vcorr_lj, real lambda_q, real lambda_lj, real *dvdlambda_q, real *dvdlambda_lj) { int numAtomsToBeCorrected; if (calc_excl_corr) { /* We need to correct all exclusion pairs (cutoff-scheme = group) */ numAtomsToBeCorrected = excl->nr; GMX_RELEASE_ASSERT(numAtomsToBeCorrected >= numAtomsLocal, "We might need to do self-corrections"); } else { /* We need to correct only self interactions */ numAtomsToBeCorrected = numAtomsLocal; } int start = (numAtomsToBeCorrected* thread )/numThreads; int end = (numAtomsToBeCorrected*(thread + 1))/numThreads; int i, i1, i2, j, k, m, iv, jv, q; int *AA; double Vexcl_q, dvdl_excl_q, dvdl_excl_lj; /* Necessary for precision */ double Vexcl_lj; real one_4pi_eps; real v, vc, qiA, qiB, dr2, rinv; real Vself_q[2], Vself_lj[2], Vdipole[2], rinv2, ewc_q = fr->ewaldcoeff_q, ewcdr; real ewc_lj = fr->ewaldcoeff_lj, ewc_lj2 = ewc_lj * ewc_lj; real c6Ai = 0, c6Bi = 0, c6A = 0, c6B = 0, ewcdr2, ewcdr4, c6L = 0, rinv6; rvec df, dx, mutot[2], dipcorrA, dipcorrB; tensor dxdf_q = {{0}}, dxdf_lj = {{0}}; real vol = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]; real L1_q, L1_lj, dipole_coeff, qqA, qqB, qqL, vr0_q, vr0_lj = 0; gmx_bool bMolPBC = fr->bMolPBC; gmx_bool bDoingLBRule = (fr->ljpme_combination_rule == eljpmeLB); gmx_bool bNeedLongRangeCorrection; /* This routine can be made faster by using tables instead of analytical interactions * However, that requires a thorough verification that they are correct in all cases. */ one_4pi_eps = ONE_4PI_EPS0/fr->epsilon_r; vr0_q = ewc_q*M_2_SQRTPI; if (EVDW_PME(fr->vdwtype)) { vr0_lj = -gmx::power6(ewc_lj)/6.0; } AA = excl->a; Vexcl_q = 0; Vexcl_lj = 0; dvdl_excl_q = 0; dvdl_excl_lj = 0; Vdipole[0] = 0; Vdipole[1] = 0; L1_q = 1.0-lambda_q; L1_lj = 1.0-lambda_lj; /* Note that we have to transform back to gromacs units, since * mu_tot contains the dipole in debye units (for output). */ for (i = 0; (i < DIM); i++) { mutot[0][i] = mu_tot[0][i]*DEBYE2ENM; mutot[1][i] = mu_tot[1][i]*DEBYE2ENM; dipcorrA[i] = 0; dipcorrB[i] = 0; } dipole_coeff = 0; switch (ewald_geometry) { case eewg3D: if (epsilon_surface != 0) { dipole_coeff = 2*M_PI*ONE_4PI_EPS0/((2*epsilon_surface + fr->epsilon_r)*vol); for (i = 0; (i < DIM); i++) { dipcorrA[i] = 2*dipole_coeff*mutot[0][i]; dipcorrB[i] = 2*dipole_coeff*mutot[1][i]; } } break; case eewg3DC: dipole_coeff = 2*M_PI*one_4pi_eps/vol; dipcorrA[ZZ] = 2*dipole_coeff*mutot[0][ZZ]; dipcorrB[ZZ] = 2*dipole_coeff*mutot[1][ZZ]; break; default: gmx_incons("Unsupported Ewald geometry"); break; } if (debug) { fprintf(debug, "dipcorr = %8.3f %8.3f %8.3f\n", dipcorrA[XX], dipcorrA[YY], dipcorrA[ZZ]); fprintf(debug, "mutot = %8.3f %8.3f %8.3f\n", mutot[0][XX], mutot[0][YY], mutot[0][ZZ]); } bNeedLongRangeCorrection = (calc_excl_corr || dipole_coeff != 0); if (bNeedLongRangeCorrection && !bHaveChargeOrTypePerturbed) { for (i = start; (i < end); i++) { /* Initiate local variables (for this i-particle) to 0 */ qiA = chargeA[i]*one_4pi_eps; if (EVDW_PME(fr->vdwtype)) { c6Ai = C6A[i]; if (bDoingLBRule) { c6Ai *= sigma3A[i]; } } if (calc_excl_corr) { i1 = excl->index[i]; i2 = excl->index[i+1]; /* Loop over excluded neighbours */ for (j = i1; (j < i2); j++) { k = AA[j]; /* * First we must test whether k <> i, and then, * because the exclusions are all listed twice i->k * and k->i we must select just one of the two. As * a minor optimization we only compute forces when * the charges are non-zero. */ if (k > i) { qqA = qiA*chargeA[k]; if (EVDW_PME(fr->vdwtype)) { c6A = c6Ai * C6A[k]; if (bDoingLBRule) { c6A *= gmx::power6(0.5*(sigmaA[i]+sigmaA[k]))*sigma3A[k]; } } if (qqA != 0.0 || c6A != 0.0) { rvec_sub(x[i], x[k], dx); if (bMolPBC) { /* Cheap pbc_dx, assume excluded pairs are at short distance. */ for (m = DIM-1; (m >= 0); m--) { if (dx[m] > 0.5*box[m][m]) { rvec_dec(dx, box[m]); } else if (dx[m] < -0.5*box[m][m]) { rvec_inc(dx, box[m]); } } } dr2 = norm2(dx); /* Distance between two excluded particles * may be zero in the case of shells */ if (dr2 != 0) { rinv = gmx::invsqrt(dr2); rinv2 = rinv*rinv; if (qqA != 0.0) { real dr, fscal; dr = 1.0/rinv; ewcdr = ewc_q*dr; vc = qqA*std::erf(ewcdr)*rinv; Vexcl_q += vc; #if GMX_DOUBLE /* Relative accuracy at R_ERF_R_INACC of 3e-10 */ #define R_ERF_R_INACC 0.006 #else /* Relative accuracy at R_ERF_R_INACC of 2e-5 */ #define R_ERF_R_INACC 0.1 #endif /* fscal is the scalar force pre-multiplied by rinv, * to normalise the relative position vector dx */ if (ewcdr > R_ERF_R_INACC) { fscal = rinv2*(vc - qqA*ewc_q*M_2_SQRTPI*exp(-ewcdr*ewcdr)); } else { /* Use a fourth order series expansion for small ewcdr */ fscal = ewc_q*ewc_q*qqA*vr0_q*(2.0/3.0 - 0.4*ewcdr*ewcdr); } /* The force vector is obtained by multiplication with * the relative position vector */ svmul(fscal, dx, df); rvec_inc(f[k], df); rvec_dec(f[i], df); for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { dxdf_q[iv][jv] += dx[iv]*df[jv]; } } } if (c6A != 0.0) { real fscal; rinv6 = rinv2*rinv2*rinv2; ewcdr2 = ewc_lj2*dr2; ewcdr4 = ewcdr2*ewcdr2; /* We get the excluded long-range contribution from -C6*(1-g(r)) * g(r) is also defined in the manual under LJ-PME */ vc = -c6A*rinv6*(1.0 - exp(-ewcdr2)*(1 + ewcdr2 + 0.5*ewcdr4)); Vexcl_lj += vc; /* The force is the derivative of the potential vc. * fscal is the scalar force pre-multiplied by rinv, * to normalise the relative position vector dx */ fscal = 6.0*vc*rinv2 + c6A*rinv6*exp(-ewcdr2)*ewc_lj2*ewcdr4; /* The force vector is obtained by multiplication with * the relative position vector */ svmul(fscal, dx, df); rvec_inc(f[k], df); rvec_dec(f[i], df); for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { dxdf_lj[iv][jv] += dx[iv]*df[jv]; } } } } else { Vexcl_q += qqA*vr0_q; Vexcl_lj += c6A*vr0_lj; } } } } } /* Dipole correction on force */ if (dipole_coeff != 0 && i < numAtomsLocal) { for (j = 0; (j < DIM); j++) { f[i][j] -= dipcorrA[j]*chargeA[i]; } } } } else if (bNeedLongRangeCorrection) { for (i = start; (i < end); i++) { /* Initiate local variables (for this i-particle) to 0 */ qiA = chargeA[i]*one_4pi_eps; qiB = chargeB[i]*one_4pi_eps; if (EVDW_PME(fr->vdwtype)) { c6Ai = C6A[i]; c6Bi = C6B[i]; if (bDoingLBRule) { c6Ai *= sigma3A[i]; c6Bi *= sigma3B[i]; } } if (calc_excl_corr) { i1 = excl->index[i]; i2 = excl->index[i+1]; /* Loop over excluded neighbours */ for (j = i1; (j < i2); j++) { k = AA[j]; if (k > i) { qqA = qiA*chargeA[k]; qqB = qiB*chargeB[k]; if (EVDW_PME(fr->vdwtype)) { c6A = c6Ai*C6A[k]; c6B = c6Bi*C6B[k]; if (bDoingLBRule) { c6A *= gmx::power6(0.5*(sigmaA[i]+sigmaA[k]))*sigma3A[k]; c6B *= gmx::power6(0.5*(sigmaB[i]+sigmaB[k]))*sigma3B[k]; } } if (qqA != 0.0 || qqB != 0.0 || c6A != 0.0 || c6B != 0.0) { real fscal; qqL = L1_q*qqA + lambda_q*qqB; if (EVDW_PME(fr->vdwtype)) { c6L = L1_lj*c6A + lambda_lj*c6B; } rvec_sub(x[i], x[k], dx); if (bMolPBC) { /* Cheap pbc_dx, assume excluded pairs are at short distance. */ for (m = DIM-1; (m >= 0); m--) { if (dx[m] > 0.5*box[m][m]) { rvec_dec(dx, box[m]); } else if (dx[m] < -0.5*box[m][m]) { rvec_inc(dx, box[m]); } } } dr2 = norm2(dx); if (dr2 != 0) { rinv = gmx::invsqrt(dr2); rinv2 = rinv*rinv; if (qqA != 0.0 || qqB != 0.0) { real dr; dr = 1.0/rinv; v = std::erf(ewc_q*dr)*rinv; vc = qqL*v; Vexcl_q += vc; /* fscal is the scalar force pre-multiplied by rinv, * to normalise the relative position vector dx */ fscal = rinv2*(vc-qqL*ewc_q*M_2_SQRTPI*exp(-ewc_q*ewc_q*dr2)); dvdl_excl_q += (qqB - qqA)*v; /* The force vector is obtained by multiplication with * the relative position vector */ svmul(fscal, dx, df); rvec_inc(f[k], df); rvec_dec(f[i], df); for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { dxdf_q[iv][jv] += dx[iv]*df[jv]; } } } if ((c6A != 0.0 || c6B != 0.0) && EVDW_PME(fr->vdwtype)) { rinv6 = rinv2*rinv2*rinv2; ewcdr2 = ewc_lj2*dr2; ewcdr4 = ewcdr2*ewcdr2; v = -rinv6*(1.0 - exp(-ewcdr2)*(1 + ewcdr2 + 0.5*ewcdr4)); vc = c6L*v; Vexcl_lj += vc; /* fscal is the scalar force pre-multiplied by rinv, * to normalise the relative position vector dx */ fscal = 6.0*vc*rinv2 + c6L*rinv6*exp(-ewcdr2)*ewc_lj2*ewcdr4; dvdl_excl_lj += (c6B - c6A)*v; /* The force vector is obtained by multiplication with * the relative position vector */ svmul(fscal, dx, df); rvec_inc(f[k], df); rvec_dec(f[i], df); for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { dxdf_lj[iv][jv] += dx[iv]*df[jv]; } } } } else { Vexcl_q += qqL*vr0_q; dvdl_excl_q += (qqB - qqA)*vr0_q; Vexcl_lj += c6L*vr0_lj; dvdl_excl_lj += (c6B - c6A)*vr0_lj; } } } } } /* Dipole correction on force */ if (dipole_coeff != 0 && i < numAtomsLocal) { for (j = 0; (j < DIM); j++) { f[i][j] -= L1_q*dipcorrA[j]*chargeA[i] + lambda_q*dipcorrB[j]*chargeB[i]; } } } } for (iv = 0; (iv < DIM); iv++) { for (jv = 0; (jv < DIM); jv++) { vir_q[iv][jv] += 0.5*dxdf_q[iv][jv]; vir_lj[iv][jv] += 0.5*dxdf_lj[iv][jv]; } } Vself_q[0] = 0; Vself_q[1] = 0; Vself_lj[0] = 0; Vself_lj[1] = 0; /* Global corrections only on master process */ if (MASTER(cr) && thread == 0) { for (q = 0; q < (bHaveChargeOrTypePerturbed ? 2 : 1); q++) { if (calc_excl_corr) { /* Self-energy correction */ Vself_q[q] = ewc_q*one_4pi_eps*fr->q2sum[q]*M_1_SQRTPI; if (EVDW_PME(fr->vdwtype)) { Vself_lj[q] = fr->c6sum[q]*0.5*vr0_lj; } } /* Apply surface dipole correction: * correction = dipole_coeff * (dipole)^2 */ if (dipole_coeff != 0) { if (ewald_geometry == eewg3D) { Vdipole[q] = dipole_coeff*iprod(mutot[q], mutot[q]); } else if (ewald_geometry == eewg3DC) { Vdipole[q] = dipole_coeff*mutot[q][ZZ]*mutot[q][ZZ]; } } } } if (!bHaveChargeOrTypePerturbed) { *Vcorr_q = Vdipole[0] - Vself_q[0] - Vexcl_q; if (EVDW_PME(fr->vdwtype)) { *Vcorr_lj = -Vself_lj[0] - Vexcl_lj; } } else { *Vcorr_q = L1_q*(Vdipole[0] - Vself_q[0]) + lambda_q*(Vdipole[1] - Vself_q[1]) - Vexcl_q; *dvdlambda_q += Vdipole[1] - Vself_q[1] - (Vdipole[0] - Vself_q[0]) - dvdl_excl_q; if (EVDW_PME(fr->vdwtype)) { *Vcorr_lj = -(L1_lj*Vself_lj[0] + lambda_lj*Vself_lj[1]) - Vexcl_lj; *dvdlambda_lj += -Vself_lj[1] + Vself_lj[0] - dvdl_excl_lj; } } if (debug) { fprintf(debug, "Long Range corrections for Ewald interactions:\n"); fprintf(debug, "q2sum = %g, Vself_q=%g c6sum = %g, Vself_lj=%g\n", L1_q*fr->q2sum[0]+lambda_q*fr->q2sum[1], L1_q*Vself_q[0]+lambda_q*Vself_q[1], L1_lj*fr->c6sum[0]+lambda_lj*fr->c6sum[1], L1_lj*Vself_lj[0]+lambda_lj*Vself_lj[1]); fprintf(debug, "Electrostatic Long Range correction: Vexcl=%g\n", Vexcl_q); fprintf(debug, "Lennard-Jones Long Range correction: Vexcl=%g\n", Vexcl_lj); if (MASTER(cr) && thread == 0) { if (epsilon_surface > 0 || ewald_geometry == eewg3DC) { fprintf(debug, "Total dipole correction: Vdipole=%g\n", L1_q*Vdipole[0]+lambda_q*Vdipole[1]); } } } }
int gmx_vanhove(int argc,char *argv[]) { const char *desc[] = { "g_vanhove computes the Van Hove correlation function.", "The Van Hove G(r,t) is the probability that a particle that is at r0", "at time zero can be found at position r0+r at time t.", "g_vanhove determines G not for a vector r, but for the length of r.", "Thus it gives the probability that a particle moves a distance of r", "in time t.", "Jumps across the periodic boundaries are removed.", "Corrections are made for scaling due to isotropic", "or anisotropic pressure coupling.", "[PAR]", "With option [TT]-om[tt] the whole matrix can be written as a function", "of t and r or as a function of sqrt(t) and r (option [TT]-sqrt[tt]).", "[PAR]", "With option [TT]-or[tt] the Van Hove function is plotted for one", "or more values of t. Option [TT]-nr[tt] sets the number of times,", "option [TT]-fr[tt] the number spacing between the times.", "The binwidth is set with option [TT]-rbin[tt]. The number of bins", "is determined automatically.", "[PAR]", "With option [TT]-ot[tt] the integral up to a certain distance", "(option [TT]-rt[tt]) is plotted as a function of time.", "[PAR]", "For all frames that are read the coordinates of the selected particles", "are stored in memory. Therefore the program may use a lot of memory.", "For options [TT]-om[tt] and [TT]-ot[tt] the program may be slow.", "This is because the calculation scales as the number of frames times", "[TT]-fm[tt] or [TT]-ft[tt].", "Note that with the [TT]-dt[tt] option the memory usage and calculation", "time can be reduced." }; static int fmmax=0,ftmax=0,nlev=81,nr=1,fshift=0; static real sbin=0,rmax=2,rbin=0.01,mmax=0,rint=0; t_pargs pa[] = { { "-sqrt", FALSE, etREAL,{&sbin}, "Use sqrt(t) on the matrix axis which binspacing # in sqrt(ps)" }, { "-fm", FALSE, etINT, {&fmmax}, "Number of frames in the matrix, 0 is plot all" }, { "-rmax", FALSE, etREAL, {&rmax}, "Maximum r in the matrix (nm)" }, { "-rbin", FALSE, etREAL, {&rbin}, "Binwidth in the matrix and for -or (nm)" }, { "-mmax", FALSE, etREAL, {&mmax}, "Maximum density in the matrix, 0 is calculate (1/nm)" }, { "-nlevels" ,FALSE, etINT, {&nlev}, "Number of levels in the matrix" }, { "-nr", FALSE, etINT, {&nr}, "Number of curves for the -or output" }, { "-fr", FALSE, etINT, {&fshift}, "Frame spacing for the -or output" }, { "-rt", FALSE, etREAL, {&rint}, "Integration limit for the -ot output (nm)" }, { "-ft", FALSE, etINT, {&ftmax}, "Number of frames in the -ot output, 0 is plot all" } }; #define NPA asize(pa) t_filenm fnm[] = { { efTRX, NULL, NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXPM, "-om", "vanhove", ffOPTWR }, { efXVG, "-or", "vanhove_r", ffOPTWR }, { efXVG, "-ot", "vanhove_t", ffOPTWR } }; #define NFILE asize(fnm) output_env_t oenv; const char *matfile,*otfile,*orfile; char title[256]; t_topology top; int ePBC; matrix boxtop,box,*sbox,avbox,corr; rvec *xtop,*x,**sx; int isize,nalloc,nallocn,natom; t_trxstatus *status; atom_id *index; char *grpname; int nfr,f,ff,i,m,mat_nx=0,nbin=0,bin,mbin,fbin; real *time,t,invbin=0,rmax2=0,rint2=0,d2; real invsbin=0,matmax,normfac,dt,*tickx,*ticky; char buf[STRLEN],**legend; real **mat=NULL; int *pt=NULL,**pr=NULL,*mcount=NULL,*tcount=NULL,*rcount=NULL; FILE *fp; t_rgb rlo={1,1,1}, rhi={0,0,0}; CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); matfile = opt2fn_null("-om",NFILE,fnm); if (opt2parg_bSet("-fr",NPA,pa)) orfile = opt2fn("-or",NFILE,fnm); else orfile = opt2fn_null("-or",NFILE,fnm); if (opt2parg_bSet("-rt",NPA,pa)) otfile = opt2fn("-ot",NFILE,fnm); else otfile = opt2fn_null("-ot",NFILE,fnm); if (!matfile && !otfile && !orfile) { fprintf(stderr, "For output set one (or more) of the output file options\n"); exit(0); } read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xtop,NULL,boxtop, FALSE); get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpname); nalloc = 0; time = NULL; sbox = NULL; sx = NULL; clear_mat(avbox); natom=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); nfr = 0; do { if (nfr >= nalloc) { nalloc += 100; srenew(time,nalloc); srenew(sbox,nalloc); srenew(sx,nalloc); } time[nfr] = t; copy_mat(box,sbox[nfr]); /* This assumes that the off-diagonal box elements * are not affected by jumps across the periodic boundaries. */ m_add(avbox,box,avbox); snew(sx[nfr],isize); for(i=0; i<isize; i++) copy_rvec(x[index[i]],sx[nfr][i]); nfr++; } while (read_next_x(oenv,status,&t,natom,x,box)); /* clean up */ sfree(x); close_trj(status); fprintf(stderr,"Read %d frames\n",nfr); dt = (time[nfr-1] - time[0])/(nfr - 1); /* Some ugly rounding to get nice nice times in the output */ dt = (int)(10000.0*dt + 0.5)/10000.0; invbin = 1.0/rbin; if (matfile) { if (fmmax <= 0 || fmmax >= nfr) fmmax = nfr - 1; snew(mcount,fmmax); nbin = (int)(rmax*invbin + 0.5); if (sbin == 0) { mat_nx = fmmax + 1; } else { invsbin = 1.0/sbin; mat_nx = sqrt(fmmax*dt)*invsbin + 1; } snew(mat,mat_nx); for(f=0; f<mat_nx; f++) snew(mat[f],nbin); rmax2 = sqr(nbin*rbin); /* Initialize time zero */ mat[0][0] = nfr*isize; mcount[0] += nfr; } else { fmmax = 0; } if (orfile) { snew(pr,nr); nalloc = 0; snew(rcount,nr); } if (otfile) { if (ftmax <= 0) ftmax = nfr - 1; snew(tcount,ftmax); snew(pt,nfr); rint2 = rint*rint; /* Initialize time zero */ pt[0] = nfr*isize; tcount[0] += nfr; } else { ftmax = 0; } msmul(avbox,1.0/nfr,avbox); for(f=0; f<nfr; f++) { if (f % 100 == 0) fprintf(stderr,"\rProcessing frame %d",f); /* Scale all the configuration to the average box */ m_inv_ur0(sbox[f],corr); mmul_ur0(avbox,corr,corr); for(i=0; i<isize; i++) { mvmul_ur0(corr,sx[f][i],sx[f][i]); if (f > 0) { /* Correct for periodic jumps */ for(m=DIM-1; m>=0; m--) { while(sx[f][i][m] - sx[f-1][i][m] > 0.5*avbox[m][m]) rvec_dec(sx[f][i],avbox[m]); while(sx[f][i][m] - sx[f-1][i][m] <= -0.5*avbox[m][m]) rvec_inc(sx[f][i],avbox[m]); } } } for(ff=0; ff<f; ff++) { fbin = f - ff; if (fbin <= fmmax || fbin <= ftmax) { if (sbin == 0) mbin = fbin; else mbin = (int)(sqrt(fbin*dt)*invsbin + 0.5); for(i=0; i<isize; i++) { d2 = distance2(sx[f][i],sx[ff][i]); if (mbin < mat_nx && d2 < rmax2) { bin = (int)(sqrt(d2)*invbin + 0.5); if (bin < nbin) { mat[mbin][bin] += 1; } } if (fbin <= ftmax && d2 <= rint2) pt[fbin]++; } if (matfile) mcount[mbin]++; if (otfile) tcount[fbin]++; } } if (orfile) { for(fbin=0; fbin<nr; fbin++) { ff = f - (fbin + 1)*fshift; if (ff >= 0) { for(i=0; i<isize; i++) { d2 = distance2(sx[f][i],sx[ff][i]); bin = (int)(sqrt(d2)*invbin); if (bin >= nalloc) { nallocn = 10*(bin/10) + 11; for(m=0; m<nr; m++) { srenew(pr[m],nallocn); for(i=nalloc; i<nallocn; i++) pr[m][i] = 0; } nalloc = nallocn; } pr[fbin][bin]++; } rcount[fbin]++; } } } } fprintf(stderr,"\n"); if (matfile) { matmax = 0; for(f=0; f<mat_nx; f++) { normfac = 1.0/(mcount[f]*isize*rbin); for(i=0; i<nbin; i++) { mat[f][i] *= normfac; if (mat[f][i] > matmax && (f!=0 || i!=0)) matmax = mat[f][i]; } } fprintf(stdout,"Value at (0,0): %.3f, maximum of the rest %.3f\n", mat[0][0],matmax); if (mmax > 0) matmax = mmax; snew(tickx,mat_nx); for(f=0; f<mat_nx; f++) { if (sbin == 0) tickx[f] = f*dt; else tickx[f] = f*sbin; } snew(ticky,nbin+1); for(i=0; i<=nbin; i++) ticky[i] = i*rbin; fp = ffopen(matfile,"w"); write_xpm(fp,MAT_SPATIAL_Y,"Van Hove function","G (1/nm)", sbin==0 ? "time (ps)" : "sqrt(time) (ps^1/2)","r (nm)", mat_nx,nbin,tickx,ticky,mat,0,matmax,rlo,rhi,&nlev); ffclose(fp); } if (orfile) { fp = xvgropen(orfile,"Van Hove function","r (nm)","G (nm\\S-1\\N)",oenv); fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname); snew(legend,nr); for(fbin=0; fbin<nr; fbin++) { sprintf(buf,"%g ps",(fbin + 1)*fshift*dt); legend[fbin] = strdup(buf); } xvgr_legend(fp,nr,(const char**)legend,oenv); for(i=0; i<nalloc; i++) { fprintf(fp,"%g",i*rbin); for(fbin=0; fbin<nr; fbin++) fprintf(fp," %g", (real)pr[fbin][i]/(rcount[fbin]*isize*rbin*(i==0 ? 0.5 : 1))); fprintf(fp,"\n"); } ffclose(fp); } if (otfile) { sprintf(buf,"Probability of moving less than %g nm",rint); fp = xvgropen(otfile,buf,"t (ps)","",oenv); fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname); for(f=0; f<=ftmax; f++) fprintf(fp,"%g %g\n",f*dt,(real)pt[f]/(tcount[f]*isize)); ffclose(fp); } do_view(oenv, matfile,NULL); do_view(oenv, orfile,NULL); do_view(oenv, otfile,NULL); thanx(stderr); 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, int gmx_unused imdport, unsigned long gmx_unused Flags, gmx_walltime_accounting_t walltime_accounting) { 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; 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; gmx_int64_t frame_step_prev, frame_step; gmx_int64_t nsteps, stepblocksize = 0, step; gmx_int64_t rnd_count_stride, rnd_count; gmx_int64_t seed; double rnd[4]; int i, start, end; 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, 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 */ walltime_accounting_start(walltime_accounting); wallcycle_start(wcycle, ewcRUN); print_start(fplog, cr, walltime_accounting, "Test Particle Insertion"); /* 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", (int)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); /* Copy the random seed set by the user */ seed = inputrec->ld_seed; /* We use the frame step number as one random counter. * The second counter use the insertion (step) count. But we * need multiple random numbers per insertion. This number is * not fixed, since we generate random locations in a sphere * by putting locations in a cube and some of these fail. * A count of 20 is already extremely unlikely, so 10000 is * a safe margin for random numbers per insertion. */ rnd_count_stride = 10000; 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); /* Avoid frame step numbers <= -1 */ frame_step_prev = -1; 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)); switch (inputrec->eI) { case eiTPI: stepblocksize = inputrec->nstlist; break; case eiTPIC: stepblocksize = 1; break; default: gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]); } #ifdef GMX_SIMD /* Make sure we don't detect SIMD overflow generated before this point */ gmx_simd_check_and_reset_overflow(); #endif while (bNotLastFrame) { frame_step = rerun_fr.step; if (frame_step <= frame_step_prev) { /* We don't have step number in the trajectory file, * or we have constant or decreasing step numbers. * Ensure we have increasing step numbers, since we use * the step numbers as a counter for random numbers. */ frame_step = frame_step_prev + 1; } frame_step_prev = frame_step; 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; step = cr->nodeid*stepblocksize; while (step < nsteps) { /* Initialize the second counter for random numbers using * the insertion step index. This ensures that we get * the same random numbers independently of how many * MPI ranks we use. Also for the same seed, we get * the same initial random sequence for different nsteps. */ rnd_count = step*rnd_count_stride; if (!bCavity) { /* Random insertion in the whole volume */ bNS = (step % inputrec->nstlist == 0); if (bNS) { /* Generate a random position in the box */ gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { x_init[d] = rnd[d]*state->box[d][d]; } } if (inputrec->nstlist == 1) { copy_rvec(x_init, x_tp); } else { /* Generate coordinates within |dx|=drmax of x_init */ do { gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { dx[d] = (2*rnd[d] - 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 { gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); for (d = 0; d < DIM; d++) { dx[d] = (2*rnd[d] - 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 */ gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd); gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2); rotate_conf(a_tp1-a_tp0, state->x+a_tp0, NULL, 2*M_PI*rnd[0], 2*M_PI*rnd[1], 2*M_PI*rnd[2]); /* Shift to the insertion location */ for (i = a_tp0; i < a_tp1; i++) { rvec_inc(state->x[i], x_tp); } } /* 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->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_SIMD_X86_SSE2_OR_HIGHER /* 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, (int)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", (int)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, (int)step); sprintf(str2, "t: %f step %d ener: %f", t, (int)step, epot); write_sto_conf_mtop(str, str2, top_global, state->x, state->v, inputrec->ePBC, state->box); } step++; if ((step/stepblocksize) % cr->nnodes != cr->nodeid) { /* Skip all steps assigned to the other MPI ranks */ step += (cr->nnodes - 1)*stepblocksize; } } 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 */ walltime_accounting_end(walltime_accounting); 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); walltime_accounting_set_nsteps_done(walltime_accounting, frame*inputrec->nsteps); return 0; }
void virial(FILE *fp,gmx_bool bFull,int nmol,rvec x[],matrix box,real rcut, gmx_bool bYaw,real q[],gmx_bool bLJ) { int i,j,im,jm,natmol,ik,jk,m,ninter; rvec dx,f,ftot,dvir,vir,pres,xcmi,xcmj,*force; real dx6,dx2,dx1,fscal,c6,c12,vcoul,v12,v6,vctot,v12tot,v6tot; t_pbc pbc; set_pbc(&pbc,box); fprintf(fp,"%3s - %3s: %6s %6s %6s %6s %8s %8s %8s\n", "ai","aj","dx","dy","dz","|d|","virx","viry","virz"); clear_rvec(ftot); clear_rvec(vir); ninter = 0; vctot = 0; v12tot = 0; v6tot = 0; natmol = bYaw ? 5 : 3; snew(force,nmol*natmol); for(i=0; (i<nmol); i++) { im = natmol*i; /* Center of geometry */ clear_rvec(xcmi); for(ik=0; (ik<natmol); ik++) rvec_inc(xcmi,x[im+ik]); for(m=0; (m<DIM); m++) xcmi[m] /= natmol; for(j=i+1; (j<nmol); j++) { jm = natmol*j; /* Center of geometry */ clear_rvec(xcmj); for(jk=0; (jk<natmol); jk++) rvec_inc(xcmj,x[jm+jk]); for(m=0; (m<DIM); m++) xcmj[m] /= natmol; /* First check COM-COM distance */ pbc_dx(&pbc,xcmi,xcmj,dx); if (norm(dx) < rcut) { ninter++; /* Neirest neighbour molecules! */ clear_rvec(dvir); for(ik=0; (ik<natmol); ik++) { for(jk=0; (jk<natmol); jk++) { pbc_dx(&pbc,x[im+ik],x[jm+jk],dx); dx2 = iprod(dx,dx); dx1 = sqrt(dx2); vcoul = q[ik]*q[jk]*ONE_4PI_EPS0/dx1; vctot += vcoul; if (bLJ) { if (bYaw) { c6 = yaw_lj[ik][2*jk]; c12 = yaw_lj[ik][2*jk+1]; } else { c6 = spc_lj[ik][2*jk]; c12 = spc_lj[ik][2*jk+1]; } dx6 = dx2*dx2*dx2; v6 = c6/dx6; v12 = c12/(dx6*dx6); v6tot -= v6; v12tot+= v12; fscal = (vcoul+12*v12-6*v6)/dx2; } else fscal = vcoul/dx2; for(m=0; (m<DIM); m++) { f[m] = dx[m]*fscal; dvir[m] -= 0.5*dx[m]*f[m]; } rvec_inc(force[ik+im],f); rvec_dec(force[jk+jm],f); /*if (bFull) fprintf(fp,"%3s%4d-%3s%4d: %6.3f %6.3f %6.3f %6.3f" " %8.3f %8.3f %8.3f\n", watname[ik],im+ik,watname[jk],jm+jk, dx[XX],dx[YY],dx[ZZ],norm(dx), dvir[XX],dvir[YY],dvir[ZZ]);*/ } } if (bFull) fprintf(fp,"%3s%4d-%3s%4d: " " %8.3f %8.3f %8.3f\n", "SOL",i,"SOL",j,dvir[XX],dvir[YY],dvir[ZZ]); rvec_inc(vir,dvir); } } } fprintf(fp,"There were %d interactions between the %d molecules (%.2f %%)\n", ninter,nmol,(real)ninter/(0.5*nmol*(nmol-1))); fprintf(fp,"Vcoul: %10.4e V12: %10.4e V6: %10.4e Vtot: %10.4e (kJ/mol)\n", vctot/nmol,v12tot/nmol,v6tot/nmol,(vctot+v12tot+v6tot)/nmol); pr_rvec(fp,0,"vir ",vir,DIM,TRUE); for(m=0; (m<DIM); m++) pres[m] = -2*PRESFAC/(det(box))*vir[m]; pr_rvec(fp,0,"pres",pres,DIM,TRUE); pr_rvecs(fp,0,"force",force,natmol*nmol); sfree(force); }