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]); } }
void calc_triclinic_images(matrix box,rvec img[]) { int i; /* Calculate 3 adjacent images in the xy-plane */ copy_rvec(box[0],img[0]); copy_rvec(box[1],img[1]); if (img[1][XX] < 0) svmul(-1,img[1],img[1]); rvec_sub(img[1],img[0],img[2]); /* Get the next 3 in the xy-plane as mirror images */ for(i=0; i<3; i++) svmul(-1,img[i],img[3+i]); /* Calculate the first 4 out of xy-plane images */ copy_rvec(box[2],img[6]); if (img[6][XX] < 0) svmul(-1,img[6],img[6]); for(i=0; i<3; i++) rvec_add(img[6],img[i+1],img[7+i]); /* Mirror the last 4 from the previous in opposite rotation */ for(i=0; i<4; i++) svmul(-1,img[6 + (2+i) % 4],img[10+i]); }
PyObject *wrap_fit(PyObject *self,PyObject *args) { PyObject *cs1, *cs2, *mass; if(!PyArg_ParseTuple(args,"OOO",&cs1, &cs2, &mass)) return NULL; int natoms1 = PySequence_Length(cs1); int natoms2 = PySequence_Length(cs2); if( natoms1 != natoms2 ) { Error("Cannot fit coordinate sets with different lengths"); } rvec x1[natoms1]; rvec x2[natoms1]; real m[natoms1]; PyObject2rvec( cs1, x1, natoms1); PyObject2rvec( cs2, x2, natoms2); PyObject2real_array(mass, m, natoms1); rvec cent; center_and_get_vec(x1, natoms1, cent); // center x1 and get vector for back translation center(x2, natoms1); // center x2 do_fit(natoms1, m, x1, x2); int i; for(i=0;i<natoms1;i++) // translate back rvec_add( x2[i], cent, x2[i]); PyObject *ret = rvec2PyObject(x2, natoms1); return ret; }
static void periodic_dist(matrix box, rvec x[], int n, atom_id index[], real *rmin, real *rmax, int *min_ind) { #define NSHIFT 26 int sx, sy, sz, i, j, s; real sqr_box, r2min, r2max, r2; rvec shift[NSHIFT], d0, d; sqr_box = sqr(min(norm(box[XX]), min(norm(box[YY]), norm(box[ZZ])))); s = 0; for (sz = -1; sz <= 1; sz++) { for (sy = -1; sy <= 1; sy++) { for (sx = -1; sx <= 1; sx++) { if (sx != 0 || sy != 0 || sz != 0) { for (i = 0; i < DIM; i++) { shift[s][i] = sx*box[XX][i]+sy*box[YY][i]+sz*box[ZZ][i]; } s++; } } } } r2min = sqr_box; r2max = 0; for (i = 0; i < n; i++) { for (j = i+1; j < n; j++) { rvec_sub(x[index[i]], x[index[j]], d0); r2 = norm2(d0); if (r2 > r2max) { r2max = r2; } for (s = 0; s < NSHIFT; s++) { rvec_add(d0, shift[s], d); r2 = norm2(d); if (r2 < r2min) { r2min = r2; min_ind[0] = i; min_ind[1] = j; } } } } *rmin = sqrt(r2min); *rmax = sqrt(r2max); }
void visualize_box(FILE *out,int a0,int r0,matrix box,rvec gridsize) { int *edge; rvec *vert,shift; int nx,ny,nz,nbox,nat; int i,j,x,y,z; int rectedge[24] = { 0,1, 1,3, 3,2, 0,2, 0,4, 1,5, 3,7, 2,6, 4,5, 5,7, 7,6, 6,4 }; a0++; r0++; nx = (int)(gridsize[XX]+0.5); ny = (int)(gridsize[YY]+0.5); nz = (int)(gridsize[ZZ]+0.5); nbox = nx*ny*nz; if (TRICLINIC(box)) { nat = nbox*NCUCVERT; snew(vert,nat); calc_compact_unitcell_vertices(ecenterDEF,box,vert); j = 0; for(z=0; z<nz; z++) for(y=0; y<ny; y++) for(x=0; x<nx; x++) { for(i=0; i<DIM; i++) shift[i] = x*box[0][i]+y*box[1][i]+z*box[2][i]; for(i=0; i<NCUCVERT; i++) { rvec_add(vert[i],shift,vert[j]); j++; } } for(i=0; i<nat; i++) { fprintf(out,pdbformat,"ATOM",a0+i,"C","BOX",'K'+i/NCUCVERT,r0+i, 10*vert[i][XX],10*vert[i][YY],10*vert[i][ZZ]); fprintf(out,"\n"); } edge = compact_unitcell_edges(); for(j=0; j<nbox; j++) for(i=0; i<NCUCEDGE; i++) fprintf(out,"CONECT%5d%5d\n", a0 + j*NCUCVERT + edge[2*i], a0 + j*NCUCVERT + edge[2*i+1]); sfree(vert); } else { i=0; for(z=0; z<=1; z++) for(y=0; y<=1; y++) for(x=0; x<=1; x++) { fprintf(out,pdbformat,"ATOM",a0+i,"C","BOX",'K'+i/8,r0+i, x*10*box[XX][XX],y*10*box[YY][YY],z*10*box[ZZ][ZZ]); fprintf(out,"\n"); i++; } for(i=0; i<24; i+=2) fprintf(out,"CONECT%5d%5d\n",a0+rectedge[i],a0+rectedge[i+1]); } }
static void calc_com_pbc(int nrefat, t_topology *top, rvec x[], t_pbc *pbc, atom_id index[], rvec xref, int ePBC) { const real tol = 1e-4; gmx_bool bChanged; int m, j, ai, iter; real mass, mtot; rvec dx, xtest; /* First simple calculation */ clear_rvec(xref); mtot = 0; for (m = 0; (m < nrefat); m++) { ai = index[m]; mass = top->atoms.atom[ai].m; for (j = 0; (j < DIM); j++) { xref[j] += mass*x[ai][j]; } mtot += mass; } svmul(1/mtot, xref, xref); /* Now check if any atom is more than half the box from the COM */ if (ePBC != epbcNONE) { iter = 0; do { bChanged = FALSE; for (m = 0; (m < nrefat); m++) { ai = index[m]; mass = top->atoms.atom[ai].m/mtot; pbc_dx(pbc, x[ai], xref, dx); rvec_add(xref, dx, xtest); for (j = 0; (j < DIM); j++) { if (std::abs(xtest[j]-x[ai][j]) > tol) { /* Here we have used the wrong image for contributing to the COM */ xref[j] += mass*(xtest[j]-x[ai][j]); x[ai][j] = xtest[j]; bChanged = TRUE; } } } if (bChanged) { printf("COM: %8.3f %8.3f %8.3f iter = %d\n", xref[XX], xref[YY], xref[ZZ], iter); } iter++; } while (bChanged); } }
PyObject *apply_rotation( PyObject *self, PyObject *args) { PyObject *Rotation; PyObject *py_v; real phi; if(!PyArg_ParseTuple(args,"OOd",&Rotation,&py_v, &phi)) return NULL; PyObject *rm1 = PyObject_GetAttrString(Rotation,"m1"); PyObject *rm2 = PyObject_GetAttrString(Rotation,"m2"); matrix m1, m2; PyObject2matrix(rm1, m1); PyObject2matrix(rm2, m2); rvec v, v2; PyObject *py_v2 = PyObject_GetAttrString(Rotation,"v2"); Pyvec2rvec(py_v, v); Pyvec2rvec(py_v2, v2); rvec vec; rvec_sub(v, v2, vec ); rvec b, d, a, c, e; mvmul(m1, vec, b); mvmul(m2, vec, d); real cc = cos(phi); svmul( cc, vec, a); svmul( -cc, b, c); svmul( sin(phi), d, e); clear_rvec( vec ); rvec_add( a, b, vec); rvec_add( vec, c, vec ); rvec_add( vec, e, vec ); clear_rvec(v); rvec_add( v2, vec, v); return Py_BuildValue("[ddd]", v[XX], v[YY], v[ZZ] ); }
void write_conf_to_grofile(const System& system, const std::string& path, const real sigma, const OutputMode mode) { constexpr char ATOM_NAME[2] = "C"; constexpr char RESIDUE_NAME[4] = "SOL"; auto open_mode = std::ios::out; if (mode == OutputMode::Append) { open_mode = open_mode | std::ios::app; } std::ofstream out { path, open_mode }; out << system.title << '\n' << system.num_atoms() << '\n'; out.setf(std::ios::fixed); out.precision(3); uint64_t n = 1; for (const auto &list : system.cell_lists) { for (unsigned i = 0; i < list.num_atoms(); ++i) { const auto x0 = RVec { list.xs.at(i * NDIM + XX), list.xs.at(i * NDIM + YY), list.xs.at(i * NDIM + ZZ) }; const auto xabs = rvec_add(x0, list.origin); out << std::setw(5) << std::right << n << std::setw(5) << std::left << RESIDUE_NAME << std::setw(5) << std::right << ATOM_NAME << std::setw(5) << n << std::setw(8) << xabs[XX] * sigma << std::setw(8) << xabs[YY] * sigma << std::setw(8) << xabs[ZZ] * sigma << '\n'; ++n; } } out << std::setw(9) << std::right << system.box_size[0] * sigma << ' ' << std::setw(9) << system.box_size[1] * sigma << ' ' << std::setw(9) << system.box_size[2] * sigma << '\n'; }
//! Helper method to calculate a vector from two or three positions. static void calc_vec(int natoms, rvec x[], t_pbc *pbc, rvec xout, rvec cout) { switch (natoms) { case 2: if (pbc) { pbc_dx(pbc, x[1], x[0], xout); } else { rvec_sub(x[1], x[0], xout); } svmul(0.5, xout, cout); rvec_add(x[0], cout, cout); break; case 3: { rvec v1, v2; if (pbc) { pbc_dx(pbc, x[1], x[0], v1); pbc_dx(pbc, x[2], x[0], v2); } else { rvec_sub(x[1], x[0], v1); rvec_sub(x[2], x[0], v2); } cprod(v1, v2, xout); rvec_add(x[0], x[1], cout); rvec_add(cout, x[2], cout); svmul(1.0/3.0, cout, cout); break; } default: GMX_RELEASE_ASSERT(false, "Incorrectly initialized number of atoms"); } }
static PetscErrorCode gs_gop_vec_local_plus( gs_id *gs, PetscScalar *vals, PetscInt step) { PetscInt *num, *map, **reduce; PetscScalar *base; PetscFunctionBegin; num = gs->num_local_reduce; reduce = gs->local_reduce; while ((map = *reduce)) { base = vals + map[0] * step; /* wall */ if (*num == 2) { num++; reduce++; rvec_add (base,vals+map[1]*step,step); rvec_copy(vals+map[1]*step,base,step); } /* corner shared by three elements */ else if (*num == 3) { num++; reduce++; rvec_add (base,vals+map[1]*step,step); rvec_add (base,vals+map[2]*step,step); rvec_copy(vals+map[2]*step,base,step); rvec_copy(vals+map[1]*step,base,step); } /* corner shared by four elements */ else if (*num == 4) { num++; reduce++; rvec_add (base,vals+map[1]*step,step); rvec_add (base,vals+map[2]*step,step); rvec_add (base,vals+map[3]*step,step); rvec_copy(vals+map[3]*step,base,step); rvec_copy(vals+map[2]*step,base,step); rvec_copy(vals+map[1]*step,base,step); } /* general case ... odd geoms ... 3D */ else { num++; while (*++map >= 0) {rvec_add (base,vals+*map*step,step);} map = *reduce; while (*++map >= 0) {rvec_copy(vals+*map*step,base,step);} reduce++; } } PetscFunctionReturn(0); }
/*! * \param[in] top Topology structure with masses. * \param[in] x Position vectors of all atoms. * \param[in] pbc Periodic boundary conditions structure. * \param[in] nrefat Number of atoms in the index. * \param[in] index Indices of atoms. * \param[out] xout COM position for the indexed atoms. * * Works as gmx_calc_com(), but takes into account periodic boundary * conditions: If any atom is more than half the box from the COM, * it is wrapped around and a new COM is calculated. This is repeated * until no atoms violate the condition. * * Modified from src/tools/gmx_sorient.c in Gromacs distribution. */ void gmx_calc_com_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc, int nrefat, const int index[], rvec xout) { GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top), "No masses available while mass weighting was requested"); /* First simple calculation */ clear_rvec(xout); real mtot = 0; int molb = 0; for (int m = 0; m < nrefat; ++m) { const int ai = index[m]; const real mass = mtopGetAtomMass(top, ai, &molb); for (int j = 0; j < DIM; ++j) { xout[j] += mass * x[ai][j]; } mtot += mass; } svmul(1.0/mtot, xout, xout); /* Now check if any atom is more than half the box from the COM */ if (pbc) { const real tol = 1e-4; bool bChanged; do { bChanged = false; molb = 0; for (int m = 0; m < nrefat; ++m) { rvec dx, xtest; const int ai = index[m]; const real mass = mtopGetAtomMass(top, ai, &molb) / mtot; pbc_dx(pbc, x[ai], xout, dx); rvec_add(xout, dx, xtest); for (int j = 0; j < DIM; ++j) { if (fabs(xtest[j] - x[ai][j]) > tol) { /* Here we have used the wrong image for contributing to the COM */ xout[j] += mass * (xtest[j] - x[ai][j]); x[ai][j] = xtest[j]; bChanged = true; } } } } while (bChanged); } }
static void calc_ringh(rvec xattach, rvec xb, rvec xc, rvec xh) { rvec tab, tac; real n; /* Add a proton on a ring to atom attach at distance 0.1 nm */ rvec_sub(xattach, xb, tab); rvec_sub(xattach, xc, tac); rvec_add(tab, tac, xh); n = 0.1/norm(xh); svmul(n, xh, xh); rvec_inc(xh, xattach); }
static void calc_vec(int natoms, rvec x[], t_pbc *pbc, rvec xout, rvec cout) { switch (natoms) { case 2: if (pbc) { pbc_dx(pbc, x[1], x[0], xout); } else { rvec_sub(x[1], x[0], xout); } svmul(0.5, xout, cout); rvec_add(x[0], cout, cout); break; case 3: { rvec v1, v2; if (pbc) { pbc_dx(pbc, x[1], x[0], v1); pbc_dx(pbc, x[2], x[0], v2); } else { rvec_sub(x[1], x[0], v1); rvec_sub(x[2], x[0], v2); } cprod(v1, v2, xout); rvec_add(x[0], x[1], cout); rvec_add(cout, x[2], cout); svmul(1.0/3.0, cout, cout); break; } } }
void dump_pbc(FILE *fp, t_pbc *pbc) { rvec sum_box; fprintf(fp, "ePBCDX = %d\n", pbc->ePBCDX); pr_rvecs(fp, 0, "box", pbc->box, DIM); pr_rvecs(fp, 0, "fbox_diag", &pbc->fbox_diag, 1); pr_rvecs(fp, 0, "hbox_diag", &pbc->hbox_diag, 1); pr_rvecs(fp, 0, "mhbox_diag", &pbc->mhbox_diag, 1); rvec_add(pbc->hbox_diag, pbc->mhbox_diag, sum_box); pr_rvecs(fp, 0, "sum of the above two", &sum_box, 1); fprintf(fp, "max_cutoff2 = %g\n", pbc->max_cutoff2); fprintf(fp, "ntric_vec = %d\n", pbc->ntric_vec); if (pbc->ntric_vec > 0) { pr_ivecs(fp, 0, "tric_shift", pbc->tric_shift, pbc->ntric_vec, FALSE); pr_rvecs(fp, 0, "tric_vec", pbc->tric_vec, pbc->ntric_vec); } }
const char * put_atoms_in_compact_unitcell(int ePBC,int ecenter,matrix box, int natoms,rvec x[]) { t_pbc pbc; rvec box_center,dx; int i; set_pbc(&pbc,ePBC,box); calc_box_center(ecenter,box,box_center); for(i=0; i<natoms; i++) { pbc_dx(&pbc,x[i],box_center,dx); rvec_add(box_center,dx,x[i]); } return pbc.bLimitDistance ? "WARNING: Could not put all atoms in the compact unitcell\n" : NULL; }
void put_atoms_in_compact_unitcell(int ePBC, int ecenter, const matrix box, int natoms, rvec x[]) { t_pbc pbc; rvec box_center, dx; int i; set_pbc(&pbc, ePBC, box); if (pbc.ePBCDX == epbcdxUNSUPPORTED) { gmx_fatal(FARGS, "Can not put atoms in compact unitcell with unsupported PBC"); } calc_box_center(ecenter, box, box_center); for (i = 0; i < natoms; i++) { pbc_dx(&pbc, x[i], box_center, dx); rvec_add(box_center, dx, x[i]); } }
/*! * \param[in] top Topology structure (unused, can be NULL). * \param[in] x Position vectors of all atoms. * \param[in] pbc Periodic boundary conditions structure. * \param[in] nrefat Number of atoms in the index. * \param[in] index Indices of atoms. * \param[out] xout COG position for the indexed atoms. * * Works exactly as gmx_calc_com_pbc(), but calculates the center of geometry. */ void gmx_calc_cog_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc, int nrefat, const int index[], rvec xout) { const real tol = 1e-4; bool bChanged; int m, j, ai, iter; rvec dx, xtest; /* First simple calculation */ gmx_calc_cog(top, x, nrefat, index, xout); /* Now check if any atom is more than half the box from the COM */ if (pbc) { iter = 0; do { bChanged = false; for (m = 0; m < nrefat; ++m) { ai = index[m]; pbc_dx(pbc, x[ai], xout, dx); rvec_add(xout, dx, xtest); for (j = 0; j < DIM; ++j) { if (fabs(xtest[j] - x[ai][j]) > tol) { /* Here we have used the wrong image for contributing to the COM */ xout[j] += (xtest[j] - x[ai][j]) / nrefat; x[ai][j] = xtest[j]; bChanged = true; } } } iter++; } while (bChanged); } }
void random_h_coords(int natmol,int nmol,rvec x[],rvec box, gmx_bool bYaw,real odist,real hdist) { #define cx 0.81649658 #define cy 0.47140452 #define cy2 0.94280904 #define cz 0.33333333 rvec xx[24] = { { 0, 0, 0 }, /* O1 */ { 0, 0, 1 }, /* H relative to Oxygen */ { cx, cy, -cz }, { cx, cy, -cz }, /* O2 */ { 0, 0, -1 }, /* H relative to Oxygen */ { cx,-cy, +cz }, { cx, cy+cy2, 0 }, /* O3 */ { -cx, cy, -cz }, /* H relative to Oxygen */ { 0, -cy2, -cz }, { 0, 2*cy+cy2, -cz }, /* O4 */ {-cx,-cy, +cz }, /* H relative to Oxygen */ { 0 , cy2, +cz }, { 0, 0, 1 }, /* O5 */ {-cx, cy, +cz }, /* H relative to Oxygen */ { 0 , -cy2, +cz }, { cx, cy, 1+cz }, /* O6 */ { -cx, -cy, -cz }, /* H relative to Oxygen */ { 0, cy2, -cz }, { cx, cy+cy2, 1 }, /* O7 */ { 0, 0, -1 }, /* H relative to Oxygen */ { cx, cy, +cz }, { 0, 2*cy+cy2,1+cz }, /* O8 */ { 0, 0, 1 }, /* H relative to Oxygen */ { cx, -cy, -cz } }; int i,iin,iout,j,m; rvec tmp,t2,dip; clear_rvec(dip); for(i=0; (i<nmol); i++) { iin = natmol*i; iout = iin; svmul(odist,x[iin],x[iout]); svmul(-0.82,x[iout],t2); rvec_inc(dip,t2); for(j=1; (j<=2); j++) { svmul(hdist,xx[3*(i % 8)+j],tmp); rvec_add(x[iout],tmp,x[iout+j]); svmul(0.41,x[iout+j],t2); rvec_inc(dip,t2); } } box[XX] = 2*cx; box[YY] = 2*(cy2+cy); box[ZZ] = 2*(1+cz); for(i=0; (i<DIM); i++) box[i] *= odist; printf("Unitcell: %10.5f %10.5f %10.5f\n",box[XX],box[YY],box[ZZ]); printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip[XX],dip[YY],dip[ZZ]); }
gmx_radial_distribution_histogram_t *calc_radial_distribution_histogram ( gmx_sans_t *gsans, rvec *x, matrix box, atom_id *index, int isize, double binwidth, gmx_bool bMC, gmx_bool bNORM, real mcover, unsigned int seed) { gmx_radial_distribution_histogram_t *pr = NULL; rvec dist; double rmax; int i, j; #ifdef GMX_OPENMP double **tgr; int tid; int nthreads; gmx_rng_t *trng = NULL; #endif gmx_large_int_t mc = 0, max; gmx_rng_t rng = NULL; /* allocate memory for pr */ snew(pr, 1); /* set some fields */ pr->binwidth = binwidth; /* * create max dist rvec * dist = box[xx] + box[yy] + box[zz] */ rvec_add(box[XX], box[YY], dist); rvec_add(box[ZZ], dist, dist); rmax = norm(dist); pr->grn = (int)floor(rmax/pr->binwidth)+1; rmax = pr->grn*pr->binwidth; snew(pr->gr, pr->grn); if (bMC) { /* Special case for setting automaticaly number of mc iterations to 1% of total number of direct iterations */ if (mcover == -1) { max = (gmx_large_int_t)floor(0.5*0.01*isize*(isize-1)); } else { max = (gmx_large_int_t)floor(0.5*mcover*isize*(isize-1)); } rng = gmx_rng_init(seed); #ifdef GMX_OPENMP nthreads = gmx_omp_get_max_threads(); snew(tgr, nthreads); snew(trng, nthreads); for (i = 0; i < nthreads; i++) { snew(tgr[i], pr->grn); trng[i] = gmx_rng_init(gmx_rng_uniform_uint32(rng)); } #pragma omp parallel shared(tgr,trng,mc) private(tid,i,j) { tid = gmx_omp_get_thread_num(); /* now starting parallel threads */ #pragma omp for for (mc = 0; mc < max; mc++) { i = (int)floor(gmx_rng_uniform_real(trng[tid])*isize); j = (int)floor(gmx_rng_uniform_real(trng[tid])*isize); if (i != j) { tgr[tid][(int)floor(sqrt(distance2(x[index[i]], x[index[j]]))/binwidth)] += gsans->slength[index[i]]*gsans->slength[index[j]]; } } } /* collecting data from threads */ for (i = 0; i < pr->grn; i++) { for (j = 0; j < nthreads; j++) { pr->gr[i] += tgr[j][i]; } } /* freeing memory for tgr and destroying trng */ for (i = 0; i < nthreads; i++) { sfree(tgr[i]); gmx_rng_destroy(trng[i]); } sfree(tgr); sfree(trng); #else for (mc = 0; mc < max; mc++) { i = (int)floor(gmx_rng_uniform_real(rng)*isize); j = (int)floor(gmx_rng_uniform_real(rng)*isize); if (i != j) { pr->gr[(int)floor(sqrt(distance2(x[index[i]], x[index[j]]))/binwidth)] += gsans->slength[index[i]]*gsans->slength[index[j]]; } } #endif gmx_rng_destroy(rng); } else { #ifdef GMX_OPENMP nthreads = gmx_omp_get_max_threads(); /* Allocating memory for tgr arrays */ snew(tgr, nthreads); for (i = 0; i < nthreads; i++) { snew(tgr[i], pr->grn); } #pragma omp parallel shared(tgr) private(tid,i,j) { tid = gmx_omp_get_thread_num(); /* starting parallel threads */ #pragma omp for for (i = 0; i < isize; i++) { for (j = 0; j < i; j++) { tgr[tid][(int)floor(sqrt(distance2(x[index[i]], x[index[j]]))/binwidth)] += gsans->slength[index[i]]*gsans->slength[index[j]]; } } } /* collecating data for pr->gr */ for (i = 0; i < pr->grn; i++) { for (j = 0; j < nthreads; j++) { pr->gr[i] += tgr[j][i]; } } /* freeing memory for tgr */ for (i = 0; i < nthreads; i++) { sfree(tgr[i]); } sfree(tgr); #else for (i = 0; i < isize; i++) { for (j = 0; j < i; j++) { pr->gr[(int)floor(sqrt(distance2(x[index[i]], x[index[j]]))/binwidth)] += gsans->slength[index[i]]*gsans->slength[index[j]]; } } #endif } /* normalize if needed */ if (bNORM) { normalize_probability(pr->grn, pr->gr); } snew(pr->r, pr->grn); for (i = 0; i < pr->grn; i++) { pr->r[i] = (pr->binwidth*i+pr->binwidth*0.5); } return (gmx_radial_distribution_histogram_t *) pr; }
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); }
void dd_move_x_specat(gmx_domdec_t *dd, gmx_domdec_specat_comm_t *spac, matrix box, rvec *x0, rvec *x1, gmx_bool bX1IsCoord) { gmx_specatsend_t *spas; rvec *x, *vbuf, *rbuf; int nvec, v, n, nn, ns0, ns1, nr0, nr1, nr, d, dim, dir, i; gmx_bool bPBC, bScrew = FALSE; rvec shift = {0, 0, 0}; nvec = 1; if (x1 != NULL) { nvec++; } n = spac->at_start; for (d = 0; d < dd->ndim; d++) { dim = dd->dim[d]; if (dd->nc[dim] > 2) { /* Pulse the grid forward and backward */ vbuf = spac->vbuf; for (dir = 0; dir < 2; dir++) { if (dir == 0 && dd->ci[dim] == 0) { bPBC = TRUE; bScrew = (dd->bScrewPBC && dim == XX); copy_rvec(box[dim], shift); } else if (dir == 1 && dd->ci[dim] == dd->nc[dim]-1) { bPBC = TRUE; bScrew = (dd->bScrewPBC && dim == XX); for (i = 0; i < DIM; i++) { shift[i] = -box[dim][i]; } } else { bPBC = FALSE; bScrew = FALSE; } spas = &spac->spas[d][dir]; for (v = 0; v < nvec; v++) { x = (v == 0 ? x0 : x1); /* Copy the required coordinates to the send buffer */ if (!bPBC || (v == 1 && !bX1IsCoord)) { /* Only copy */ for (i = 0; i < spas->nsend; i++) { copy_rvec(x[spas->a[i]], *vbuf); vbuf++; } } else if (!bScrew) { /* Shift coordinates */ for (i = 0; i < spas->nsend; i++) { rvec_add(x[spas->a[i]], shift, *vbuf); vbuf++; } } else { /* Shift and rotate coordinates */ for (i = 0; i < spas->nsend; i++) { (*vbuf)[XX] = x[spas->a[i]][XX] + shift[XX]; (*vbuf)[YY] = box[YY][YY] - x[spas->a[i]][YY] + shift[YY]; (*vbuf)[ZZ] = box[ZZ][ZZ] - x[spas->a[i]][ZZ] + shift[ZZ]; vbuf++; } } } } /* Send and receive the coordinates */ spas = spac->spas[d]; ns0 = spas[0].nsend; nr0 = spas[0].nrecv; ns1 = spas[1].nsend; nr1 = spas[1].nrecv; if (nvec == 1) { dd_sendrecv2_rvec(dd, d, spac->vbuf+ns0, ns1, x0+n, nr1, spac->vbuf, ns0, x0+n+nr1, nr0); } else { /* Communicate both vectors in one buffer */ rbuf = spac->vbuf2; dd_sendrecv2_rvec(dd, d, spac->vbuf+2*ns0, 2*ns1, rbuf, 2*nr1, spac->vbuf, 2*ns0, rbuf+2*nr1, 2*nr0); /* Split the buffer into the two vectors */ nn = n; for (dir = 1; dir >= 0; dir--) { nr = spas[dir].nrecv; for (v = 0; v < 2; v++) { x = (v == 0 ? x0 : x1); for (i = 0; i < nr; i++) { copy_rvec(*rbuf, x[nn+i]); rbuf++; } } nn += nr; } } n += nr0 + nr1; } else { spas = &spac->spas[d][0]; /* Copy the required coordinates to the send buffer */ vbuf = spac->vbuf; for (v = 0; v < nvec; v++) { x = (v == 0 ? x0 : x1); if (dd->bScrewPBC && dim == XX && (dd->ci[XX] == 0 || dd->ci[XX] == dd->nc[XX]-1)) { /* Here we only perform the rotation, the rest of the pbc * is handled in the constraint or viste routines. */ for (i = 0; i < spas->nsend; i++) { (*vbuf)[XX] = x[spas->a[i]][XX]; (*vbuf)[YY] = box[YY][YY] - x[spas->a[i]][YY]; (*vbuf)[ZZ] = box[ZZ][ZZ] - x[spas->a[i]][ZZ]; vbuf++; } } else { for (i = 0; i < spas->nsend; i++) { copy_rvec(x[spas->a[i]], *vbuf); vbuf++; } } } /* Send and receive the coordinates */ if (nvec == 1) { dd_sendrecv_rvec(dd, d, dddirBackward, spac->vbuf, spas->nsend, x0+n, spas->nrecv); } else { /* Communicate both vectors in one buffer */ rbuf = spac->vbuf2; dd_sendrecv_rvec(dd, d, dddirBackward, spac->vbuf, 2*spas->nsend, rbuf, 2*spas->nrecv); /* Split the buffer into the two vectors */ nr = spas[0].nrecv; for (v = 0; v < 2; v++) { x = (v == 0 ? x0 : x1); for (i = 0; i < nr; i++) { copy_rvec(*rbuf, x[n+i]); rbuf++; } } } n += spas->nrecv; } } }
void update_cell_lists(System& system) { std::vector<CellList> new_lists; new_lists.reserve(system.cell_lists.size()); for (const auto& list : system.cell_lists) { new_lists.push_back( CellList(list.num_atoms(), list.origin, system.cell_size) ); new_lists.back().to_neighbours = list.to_neighbours; } for (unsigned from_index = 0; from_index < system.cell_lists.size(); ++from_index) { auto& list = system.cell_lists.at(from_index); for (unsigned i = 0; i < list.num_atoms(); ++i) { const auto current = i * NDIM; const auto x = RVec { list.xs.at(current + XX), list.xs.at(current + YY), list.xs.at(current + ZZ) }; const auto x0 = rvec_add(list.origin, x); const auto to_index = get_atom_bin_index( x0, system.cell_size, system.shape); auto& to_list = new_lists.at(to_index); // If the indices are the same we have the exact coordinates // and can transfer them without adjusting between the (identical) // origins. Minor save of computational time, more importantly // it avoids another floating point rounding error. if (from_index == to_index) { std::copy_n(list.xs.cbegin() + current, NDIM, std::back_inserter(to_list.xs)); } else { const auto x1 = rvec_sub(x0, to_list.origin); std::copy_n(x1.cbegin(), NDIM, std::back_inserter(to_list.xs)); } std::copy_n(list.vs.cbegin() + current, NDIM, std::back_inserter(to_list.vs)); std::copy_n(list.fs.cbegin() + current, NDIM, std::back_inserter(to_list.fs_prev)); } } for (auto& list : new_lists) { list.xs.shrink_to_fit(); list.vs.shrink_to_fit(); list.fs_prev.shrink_to_fit(); list.fs.resize(list.xs.size(), 0.0); list.fs.shrink_to_fit(); list.update_num_atoms(); } system.cell_lists = std::move(new_lists); }
void unitcell(rvec x[],rvec box,gmx_bool bYaw,real odist,real hdist) { #define cx 0.81649658 #define cy 0.47140452 #define cy2 0.94280904 #define cz 0.33333333 rvec xx[24] = { { 0, 0, 0 }, /* O1 */ { 0, 0, 1 }, /* H relative to Oxygen */ { cx, cy, -cz }, { cx, cy, -cz }, /* O2 */ { 0, 0, -1 }, /* H relative to Oxygen */ { cx,-cy, +cz }, { cx, cy+cy2, 0 }, /* O3 */ { -cx, cy, -cz }, /* H relative to Oxygen */ { 0, -cy2, -cz }, { 0, 2*cy+cy2, -cz }, /* O4 */ {-cx,-cy, +cz }, /* H relative to Oxygen */ { 0 , cy2, +cz }, { 0, 0, 1 }, /* O5 */ {-cx, cy, +cz }, /* H relative to Oxygen */ { 0 , -cy2, +cz }, { cx, cy, 1+cz }, /* O6 */ { -cx, -cy, -cz }, /* H relative to Oxygen */ { 0, cy2, -cz }, { cx, cy+cy2, 1 }, /* O7 */ { 0, 0, -1 }, /* H relative to Oxygen */ { cx, cy, +cz }, { 0, 2*cy+cy2,1+cz }, /* O8 */ { 0, 0, 1 }, /* H relative to Oxygen */ { cx, -cy, -cz } }; int i,iin,iout,j,m; rvec tmp,t2,dip; clear_rvec(dip); for(i=0; (i<8); i++) { iin = 3*i; if (bYaw) iout = 5*i; else iout = iin; svmul(odist,xx[iin],x[iout]); svmul(-0.82,x[iout],t2); rvec_inc(dip,t2); for(j=1; (j<=2); j++) { svmul(hdist,xx[iin+j],tmp); rvec_add(x[iout],tmp,x[iout+j]); svmul(0.41,x[iout+j],t2); rvec_inc(dip,t2); } if (bYaw) for(m=0; (m<DIM); m++) x[iout+3][m] = x[iout+4][m] = (1-2*DCONS)*x[iout][m]+DCONS*(x[iout+1][m]+x[iout+2][m]); } box[XX] = 2*cx; box[YY] = 2*(cy2+cy); box[ZZ] = 2*(1+cz); for(i=0; (i<DIM); i++) box[i] *= odist; printf("Unitcell: %10.5f %10.5f %10.5f\n",box[XX],box[YY],box[ZZ]); printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip[XX],dip[YY],dip[ZZ]); }
void calc_running_com(t_pull *pull) { int i,j,n; rvec ave; real tm; /* for group i, we have nhist[i] points of history. The maximum nr of points is pull->reflag. The array comhist[i][0..nhist[i]-1] has the positions of the center of mass over the last nhist[i] steps. x_unc[i] has the new ones. Remove the oldest one from the list, add the new one, calculate the average, put that in x_unc instead and return. We just move all coms 1 down in the list and add the latest one to the top. */ if (pull->bCyl) { /* act on dyna groups */ for (i=0;i<pull->pull.n;i++) { clear_rvec(ave); for (j=0;j<(pull->reflag-1);j++) { copy_rvec(pull->dyna.comhist[i][j+1],pull->dyna.comhist[i][j]); rvec_add(ave,pull->dyna.comhist[i][j],ave); } copy_rvec(pull->dyna.x_unc[i],pull->dyna.comhist[i][j]); rvec_add(ave,pull->dyna.x_unc[i],ave); svmul(1.0/pull->reflag,ave,ave); /* now ave has the running com for group i, copy it to x_unc[i] */ copy_rvec(ave,pull->dyna.x_unc[i]); #ifdef DEBUG if (pull->bVerbose) for (n=0;n<pull->reflag;n++) fprintf(stderr,"Comhist %d, grp %d: %8.3f%8.3f%8.3f\n",n,i, pull->dyna.comhist[i][n][XX], pull->dyna.comhist[i][n][YY], pull->dyna.comhist[i][n][ZZ]); #endif } } else { /* act on ref group */ clear_rvec(ave); for (j=0;j<(pull->reflag-1);j++) { copy_rvec(pull->ref.comhist[0][j+1],pull->ref.comhist[0][j]); rvec_add(ave,pull->ref.comhist[0][j],ave); } copy_rvec(pull->ref.x_unc[0],pull->ref.comhist[0][j]); rvec_add(ave,pull->ref.x_unc[0],ave); svmul(1.0/pull->reflag,ave,ave); /* now ave has the running com for group i, copy it to x_unc[0] */ copy_rvec(ave,pull->ref.x_unc[0]); #ifdef DEBUG if (pull->bVerbose) for (i=0;i<pull->reflag;i++) fprintf(stderr,"Comhist %d: %8.3f%8.3f%8.3f\n",i, pull->ref.comhist[0][i][XX], pull->ref.comhist[0][i][YY], pull->ref.comhist[0][i][ZZ]); #endif } }
/* calculate the angle and distance between the two groups */ static void calc_angle(int ePBC,matrix box,rvec x[], atom_id index1[], atom_id index2[], int gnx1, int gnx2, real *angle, real *distance, real *distance1, real *distance2) /* distance is distance between centers, distance 1 between center of plane and atom one of vector, distance 2 same for atom two */ { rvec normal1,normal2, /* normals on planes of interest */ center1,center2, /* center of triangle of points given to define plane,*/ /* or center of vector if a vector is given */ h1,h2,h3,h4,h5; /* temp. vectors */ t_pbc pbc; set_pbc(&pbc,ePBC,box); switch(gnx1) { case 3: /* group 1 defines plane */ calculate_normal(index1,x,normal1,center1); break; case 2: /* group 1 defines vector */ rvec_sub(x[index1[0]],x[index1[1]],normal1); rvec_add(x[index1[0]],x[index1[1]],h1); svmul(0.5,h1,center1); /* center is geometric mean */ break; default: /* group 1 does none of the above */ gmx_fatal(FARGS,"Something wrong with contents of index file.\n"); } switch(gnx2) { case 3: /* group 2 defines plane */ calculate_normal(index2,x,normal2,center2); break; case 2: /* group 2 defines vector */ rvec_sub(x[index2[0]],x[index2[1]],normal2); rvec_add(x[index2[0]],x[index2[1]],h2); svmul(0.5,h2,center2); /* center is geometric mean */ break; case 0: normal2[XX] = 0; normal2[YY] = 0; normal2[ZZ] = 1; center2[XX] = 0; center2[YY] = 0; center2[ZZ] = 0; break; default: /* group 2 does none of the above */ gmx_fatal(FARGS,"Something wrong with contents of index file.\n"); } *angle = cos_angle(normal1,normal2); if (box) pbc_dx(&pbc,center1,center2,h3); else rvec_sub(center1,center2,h3); *distance = norm(h3); if (gnx1 == 3 && gnx2 == 2) { if (box) { pbc_dx(&pbc,center1,x[index2[0]],h4); pbc_dx(&pbc,center1,x[index2[1]],h5); } else { rvec_sub(center1,x[index2[0]],h4); rvec_sub(center1,x[index2[1]],h5); } *distance1 = norm(h4); *distance2 = norm(h5); } else if (gnx1 == 2 && gnx2 ==3) { rvec_sub(center1,x[index1[0]],h4); rvec_sub(center1,x[index1[1]],h5); *distance1 = norm(h4); *distance2 = norm(h5); } else { *distance1 = 0; *distance2 = 0; } }
static void rot_conf(t_atoms *atoms, rvec x[], rvec v[], real trans, real angle, rvec head, rvec tail, matrix box, int isize, atom_id index[], rvec xout[], rvec vout[]) { rvec arrow, center, xcm; real theta, phi, arrow_len; mat4 Rx, Ry, Rz, Rinvy, Rinvz, Mtot, Tcm, Tinvcm, Tx; mat4 temp1, temp2, temp3, temp4, temp21, temp43; vec4 xv; int i, j, ai; rvec_sub(tail, head, arrow); arrow_len = norm(arrow); if (debug) { fprintf(debug, "Arrow vector: %10.4f %10.4f %10.4f\n", arrow[XX], arrow[YY], arrow[ZZ]); fprintf(debug, "Effective translation %g nm\n", trans); } if (arrow_len == 0.0) { gmx_fatal(FARGS, "Arrow vector not given"); } /* Copy all aoms to output */ for (i = 0; (i < atoms->nr); i++) { copy_rvec(x[i], xout[i]); copy_rvec(v[i], vout[i]); } /* Compute center of mass and move atoms there */ clear_rvec(xcm); for (i = 0; (i < isize); i++) { rvec_inc(xcm, x[index[i]]); } for (i = 0; (i < DIM); i++) { xcm[i] /= isize; } if (debug) { fprintf(debug, "Center of mass: %10.4f %10.4f %10.4f\n", xcm[XX], xcm[YY], xcm[ZZ]); } for (i = 0; (i < isize); i++) { rvec_sub(x[index[i]], xcm, xout[index[i]]); } /* Compute theta and phi that describe the arrow */ theta = acos(arrow[ZZ]/arrow_len); phi = atan2(arrow[YY]/arrow_len, arrow[XX]/arrow_len); if (debug) { fprintf(debug, "Phi = %.1f, Theta = %.1f\n", RAD2DEG*phi, RAD2DEG*theta); } /* Now the total rotation matrix: */ /* Rotate a couple of times */ rotate(ZZ, -phi, Rz); rotate(YY, M_PI/2-theta, Ry); rotate(XX, angle*DEG2RAD, Rx); Rx[WW][XX] = trans; rotate(YY, theta-M_PI/2, Rinvy); rotate(ZZ, phi, Rinvz); mult_matrix(temp1, Ry, Rz); mult_matrix(temp2, Rinvy, Rx); mult_matrix(temp3, temp2, temp1); mult_matrix(Mtot, Rinvz, temp3); print_m4(debug, "Rz", Rz); print_m4(debug, "Ry", Ry); print_m4(debug, "Rx", Rx); print_m4(debug, "Rinvy", Rinvy); print_m4(debug, "Rinvz", Rinvz); print_m4(debug, "Mtot", Mtot); for (i = 0; (i < isize); i++) { ai = index[i]; m4_op(Mtot, xout[ai], xv); rvec_add(xv, xcm, xout[ai]); m4_op(Mtot, v[ai], xv); copy_rvec(xv, vout[ai]); } }
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; }
int gmx_dyecoupl(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] extracts dye dynamics from trajectory files.", "Currently, R and kappa^2 between dyes is extracted for (F)RET", "simulations with assumed dipolar coupling as in the Foerster equation.", "It further allows the calculation of R(t) and kappa^2(t), R and", "kappa^2 histograms and averages, as well as the instantaneous FRET", "efficiency E(t) for a specified Foerster radius R_0 (switch [TT]-R0[tt]).", "The input dyes have to be whole (see res and mol pbc options", "in [TT]trjconv[tt]).", "The dye transition dipole moment has to be defined by at least", "a single atom pair, however multiple atom pairs can be provided ", "in the index file. The distance R is calculated on the basis of", "the COMs of the given atom pairs.", "The [TT]-pbcdist[tt] option calculates distances to the nearest periodic", "image instead to the distance in the box. This works however only," "for periodic boundaries in all 3 dimensions.", "The [TT]-norm[tt] option (area-) normalizes the histograms." }; static gmx_bool bPBCdist = FALSE, bNormHist = FALSE; int histbins = 50; gmx_output_env_t *oenv; real R0 = -1; t_pargs pa[] = { { "-pbcdist", FALSE, etBOOL, { &bPBCdist }, "Distance R based on PBC" }, { "-norm", FALSE, etBOOL, { &bNormHist }, "Normalize histograms" }, { "-bins", FALSE, etINT, {&histbins}, "# of histogram bins" }, { "-R0", FALSE, etREAL, {&R0}, "Foerster radius including kappa^2=2/3 in nm" } }; #define NPA asize(pa) t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efNDX, NULL, NULL, ffREAD }, { efXVG, "-ot", "rkappa", ffOPTWR }, { efXVG, "-oe", "insteff", ffOPTWR }, { efDAT, "-o", "rkappa", ffOPTWR }, { efXVG, "-rhist", "rhist", ffOPTWR }, { efXVG, "-khist", "khist", ffOPTWR } }; #define NFILE asize(fnm) const char *in_trajfile, *out_xvgrkfile = NULL, *out_xvginstefffile = NULL, *out_xvgrhistfile = NULL, *out_xvgkhistfile = NULL, *out_datfile = NULL; gmx_bool bHaveFirstFrame, bHaveNextFrame, indexOK = TRUE; int ndon, nacc; atom_id *donindex, *accindex; char *grpnm; t_trxstatus *status; t_trxframe fr; int flags; int allocblock = 1000; real histexpand = 1e-6; rvec donvec, accvec, donpos, accpos, dist, distnorm; int natoms; /*we rely on PBC autodetection (...currently)*/ int ePBC = -1; real *rvalues = NULL, *kappa2values = NULL, *rhist = NULL, *khist = NULL; t_pbc *pbc = NULL; int i, bin; FILE *rkfp = NULL, *rhfp = NULL, *khfp = NULL, *datfp = NULL, *iefp = NULL; gmx_bool bRKout, bRhistout, bKhistout, bDatout, bInstEffout, grident; const char *rkleg[2] = { "R", "\\f{Symbol}k\\f{}\\S2\\N" }; const char *rhleg[1] = { "p(R)" }; const char *khleg[1] = { "p(\\f{Symbol}k\\f{}\\S2\\N)" }; const char *ieleg[1] = { "E\\sRET\\N(t)" }; real R, kappa2, insteff, Rs = 0., kappa2s = 0., insteffs = 0., rmax, rmin, kmin = 0., kmax = 4., rrange, krange, rincr, kincr, Rfrac; int rkcount = 0, rblocksallocated = 0, kblocksallocated = 0; if (!parse_common_args(&argc, argv, PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW | PCA_TIME_UNIT, NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } /* Check command line options for filenames and set bool flags when switch used*/ in_trajfile = opt2fn("-f", NFILE, fnm); out_xvgrkfile = opt2fn("-ot", NFILE, fnm); out_xvgrhistfile = opt2fn("-rhist", NFILE, fnm); out_xvgkhistfile = opt2fn("-khist", NFILE, fnm); out_xvginstefffile = opt2fn("-oe", NFILE, fnm); out_datfile = opt2fn("-o", NFILE, fnm); bRKout = opt2bSet("-ot", NFILE, fnm); bRhistout = opt2bSet("-rhist", NFILE, fnm); bKhistout = opt2bSet("-khist", NFILE, fnm); bDatout = opt2bSet("-o", NFILE, fnm); bInstEffout = opt2bSet("-oe", NFILE, fnm); /* PBC warning. */ if (bPBCdist) { printf("Calculating distances to periodic image.\n"); printf("Be careful! This produces only valid results for PBC in all three dimensions\n"); } if (bInstEffout && R0 <= 0.) { gmx_fatal(FARGS, "You have to specify R0 and R0 has to be larger than 0 nm.\n\n"); } printf("Select group with donor atom pairs defining the transition moment\n"); get_index(NULL, ftp2fn_null(efNDX, NFILE, fnm), 1, &ndon, &donindex, &grpnm); printf("Select group with acceptor atom pairs defining the transition moment\n"); get_index(NULL, ftp2fn_null(efNDX, NFILE, fnm), 1, &nacc, &accindex, &grpnm); /*check if groups are identical*/ grident = TRUE; if (ndon == nacc) { for (i = 0; i < nacc; i++) { if (accindex[i] != donindex[i]) { grident = FALSE; break; } } } if (grident) { gmx_fatal(FARGS, "Donor and acceptor group are identical. This makes no sense."); } printf("Reading first frame\n"); /* open trx file for reading */ flags = 0; flags = flags | TRX_READ_X; bHaveFirstFrame = read_first_frame(oenv, &status, in_trajfile, &fr, flags); if (bHaveFirstFrame) { printf("First frame is OK\n"); natoms = fr.natoms; if ((ndon % 2 != 0) || (nacc % 2 != 0)) { indexOK = FALSE; } else { for (i = 0; i < ndon; i++) { if (donindex[i] >= natoms) { indexOK = FALSE; } } for (i = 0; i < nacc; i++) { if (accindex[i] >= natoms) { indexOK = FALSE; } } } if (indexOK) { if (bDatout) { datfp = gmx_ffopen(out_datfile, "w"); } if (bRKout) { rkfp = xvgropen(out_xvgrkfile, "Distance and \\f{Symbol}k\\f{}\\S2\\N trajectory", "Time (ps)", "Distance (nm) / \\f{Symbol}k\\f{}\\S2\\N", oenv); xvgr_legend(rkfp, 2, rkleg, oenv); } if (bInstEffout) { iefp = xvgropen(out_xvginstefffile, "Instantaneous RET Efficiency", "Time (ps)", "RET Efficiency", oenv); xvgr_legend(iefp, 1, ieleg, oenv); } if (bRhistout) { snew(rvalues, allocblock); rblocksallocated += 1; snew(rhist, histbins); } if (bKhistout) { snew(kappa2values, allocblock); kblocksallocated += 1; snew(khist, histbins); } do { clear_rvec(donvec); clear_rvec(accvec); clear_rvec(donpos); clear_rvec(accpos); for (i = 0; i < ndon / 2; i++) { rvec_sub(donvec, fr.x[donindex[2 * i]], donvec); rvec_add(donvec, fr.x[donindex[2 * i + 1]], donvec); rvec_add(donpos, fr.x[donindex[2 * i]], donpos); rvec_add(donpos, fr.x[donindex[2 * i + 1]], donpos); } for (i = 0; i < nacc / 2; i++) { rvec_sub(accvec, fr.x[accindex[2 * i]], accvec); rvec_add(accvec, fr.x[accindex[2 * i + 1]], accvec); rvec_add(accpos, fr.x[accindex[2 * i]], accpos); rvec_add(accpos, fr.x[accindex[2 * i + 1]], accpos); } unitv(donvec, donvec); unitv(accvec, accvec); svmul(1.0 / ndon, donpos, donpos); svmul(1.0 / nacc, accpos, accpos); if (bPBCdist) { set_pbc(pbc, ePBC, fr.box); pbc_dx(pbc, donpos, accpos, dist); } else { rvec_sub(donpos, accpos, dist); } unitv(dist, distnorm); R = norm(dist); kappa2 = iprod(donvec, accvec)- 3.* (iprod(donvec, distnorm) * iprod(distnorm, accvec)); kappa2 *= kappa2; if (R0 > 0) { Rfrac = R/R0; insteff = 1/(1+(Rfrac*Rfrac*Rfrac*Rfrac*Rfrac*Rfrac)*2/3/kappa2); insteffs += insteff; if (bInstEffout) { fprintf(iefp, "%12.7f %12.7f\n", fr.time, insteff); } } Rs += R; kappa2s += kappa2; rkcount++; if (bRKout) { fprintf(rkfp, "%12.7f %12.7f %12.7f\n", fr.time, R, kappa2); } if (bDatout) { fprintf(datfp, "%12.7f %12.7f %12.7f\n", fr.time, R, kappa2); } if (bRhistout) { rvalues[rkcount-1] = R; if (rkcount % allocblock == 0) { srenew(rvalues, allocblock*(rblocksallocated+1)); rblocksallocated += 1; } } if (bKhistout) { kappa2values[rkcount-1] = kappa2; if (rkcount % allocblock == 0) { srenew(kappa2values, allocblock*(kblocksallocated+1)); kblocksallocated += 1; } } bHaveNextFrame = read_next_frame(oenv, status, &fr); } while (bHaveNextFrame); if (bRKout) { xvgrclose(rkfp); } if (bDatout) { gmx_ffclose(datfp); } if (bInstEffout) { xvgrclose(iefp); } if (bRhistout) { printf("Writing R-Histogram\n"); rmin = rvalues[0]; rmax = rvalues[0]; for (i = 1; i < rkcount; i++) { if (rvalues[i] < rmin) { rmin = rvalues[i]; } else if (rvalues[i] > rmax) { rmax = rvalues[i]; } } rmin -= histexpand; rmax += histexpand; rrange = rmax - rmin; rincr = rrange / histbins; for (i = 1; i < rkcount; i++) { bin = static_cast<int>((rvalues[i] - rmin) / rincr); rhist[bin] += 1; } if (bNormHist) { for (i = 0; i < histbins; i++) { rhist[i] /= rkcount * rrange/histbins; } rhfp = xvgropen(out_xvgrhistfile, "Distance Distribution", "R (nm)", "Normalized Probability", oenv); } else { rhfp = xvgropen(out_xvgrhistfile, "Distance Distribution", "R (nm)", "Probability", oenv); } xvgr_legend(rhfp, 1, rhleg, oenv); for (i = 0; i < histbins; i++) { fprintf(rhfp, "%12.7f %12.7f\n", (i + 0.5) * rincr + rmin, rhist[i]); } xvgrclose(rhfp); } if (bKhistout) { printf("Writing kappa^2-Histogram\n"); krange = kmax - kmin; kincr = krange / histbins; for (i = 1; i < rkcount; i++) { bin = static_cast<int>((kappa2values[i] - kmin) / kincr); khist[bin] += 1; } if (bNormHist) { for (i = 0; i < histbins; i++) { khist[i] /= rkcount * krange/histbins; } khfp = xvgropen(out_xvgkhistfile, "\\f{Symbol}k\\f{}\\S2\\N Distribution", "\\f{Symbol}k\\f{}\\S2\\N", "Normalized Probability", oenv); } else { khfp = xvgropen(out_xvgkhistfile, "\\f{Symbol}k\\f{}\\S2\\N Distribution", "\\f{Symbol}k\\f{}\\S2\\N", "Probability", oenv); } xvgr_legend(khfp, 1, khleg, oenv); for (i = 0; i < histbins; i++) { fprintf(khfp, "%12.7f %12.7f\n", (i + 0.5) * kincr + kmin, khist[i]); } xvgrclose(khfp); } printf("\nAverages:\n"); printf("R_avg = %8.4f nm\nKappa^2 = %8.4f\n", Rs / rkcount, kappa2s / rkcount); if (R0 > 0) { printf("E_RETavg = %8.4f\n", insteffs / rkcount); } please_cite(stdout, "Hoefling2011"); } else { gmx_fatal(FARGS, "Index file invalid, check your index file for correct pairs.\n"); } } else { gmx_fatal(FARGS, "Could not read first frame of the trajectory.\n"); } return 0; }
/* Estimate the reciprocal space part error of the SPME Ewald sum. */ static real estimate_reciprocal( t_inputinfo *info, rvec x[], /* array of particles */ real q[], /* array of charges */ int nr, /* number of charges = size of the charge array */ FILE *fp_out, gmx_bool bVerbose, unsigned int seed, /* The seed for the random number generator */ int *nsamples, /* Return the number of samples used if Monte Carlo * algorithm is used for self energy error estimate */ t_commrec *cr) { real e_rec=0; /* reciprocal error estimate */ real e_rec1=0; /* Error estimate term 1*/ real e_rec2=0; /* Error estimate term 2*/ real e_rec3=0; /* Error estimate term 3 */ real e_rec3x=0; /* part of Error estimate term 3 in x */ real e_rec3y=0; /* part of Error estimate term 3 in y */ real e_rec3z=0; /* part of Error estimate term 3 in z */ int i,ci; int nx,ny,nz; /* grid coordinates */ real q2_all=0; /* sum of squared charges */ rvec gridpx; /* reciprocal grid point in x direction*/ rvec gridpxy; /* reciprocal grid point in x and y direction*/ rvec gridp; /* complete reciprocal grid point in 3 directions*/ rvec tmpvec; /* template to create points from basis vectors */ rvec tmpvec2; /* template to create points from basis vectors */ real coeff=0; /* variable to compute coefficients of the error estimate */ real coeff2=0; /* variable to compute coefficients of the error estimate */ real tmp=0; /* variables to compute different factors from vectors */ real tmp1=0; real tmp2=0; gmx_bool bFraction; /* Random number generator */ gmx_rng_t rng=NULL; int *numbers=NULL; /* Index variables for parallel work distribution */ int startglobal,stopglobal; int startlocal, stoplocal; int x_per_core; int xtot; #ifdef TAKETIME double t0=0.0; double t1=0.0; #endif rng=gmx_rng_init(seed); clear_rvec(gridpx); clear_rvec(gridpxy); clear_rvec(gridp); clear_rvec(tmpvec); clear_rvec(tmpvec2); for(i=0;i<nr;i++) { q2_all += q[i]*q[i]; } /* Calculate indices for work distribution */ startglobal=-info->nkx[0]/2; stopglobal = info->nkx[0]/2; xtot = stopglobal*2+1; if (PAR(cr)) { x_per_core = ceil((real)xtot / (real)cr->nnodes); startlocal = startglobal + x_per_core*cr->nodeid; stoplocal = startlocal + x_per_core -1; if (stoplocal > stopglobal) stoplocal = stopglobal; } else { startlocal = startglobal; stoplocal = stopglobal; x_per_core = xtot; } /* #ifdef GMX_LIB_MPI MPI_Barrier(MPI_COMM_WORLD); #endif */ #ifdef GMX_LIB_MPI #ifdef TAKETIME if (MASTER(cr)) t0 = MPI_Wtime(); #endif #endif if (MASTER(cr)){ fprintf(stderr, "Calculating reciprocal error part 1 ..."); } for(nx=startlocal; nx<=stoplocal; nx++) { svmul(nx,info->recipbox[XX],gridpx); for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++) { svmul(ny,info->recipbox[YY],tmpvec); rvec_add(gridpx,tmpvec,gridpxy); for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++) { if ( 0 == nx && 0 == ny && 0 == nz ) continue; svmul(nz,info->recipbox[ZZ],tmpvec); rvec_add(gridpxy,tmpvec,gridp); tmp=norm2(gridp); coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] ) ; coeff/= 2.0 * M_PI * info->volume * tmp; coeff2=tmp ; tmp=eps_poly2(nx,info->nkx[0],info->pme_order[0]); tmp+=eps_poly2(ny,info->nkx[0],info->pme_order[0]); tmp+=eps_poly2(nz,info->nkx[0],info->pme_order[0]); tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]); tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]); tmp+=2.0 * tmp1 * tmp2; tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]); tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]); tmp+=2.0 * tmp1 * tmp2; tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]); tmp2=eps_poly1(nx,info->nkx[0],info->pme_order[0]); tmp+=2.0 * tmp1 * tmp2; tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]); tmp1+=eps_poly1(ny,info->nky[0],info->pme_order[0]); tmp1+=eps_poly1(nz,info->nkz[0],info->pme_order[0]); tmp+= tmp1 * tmp1; e_rec1+= 32.0 * M_PI * M_PI * coeff * coeff * coeff2 * tmp * q2_all * q2_all / nr ; tmp1=eps_poly3(nx,info->nkx[0],info->pme_order[0]); tmp1*=info->nkx[0]; tmp2=iprod(gridp,info->recipbox[XX]); tmp=tmp1*tmp2; tmp1=eps_poly3(ny,info->nky[0],info->pme_order[0]); tmp1*=info->nky[0]; tmp2=iprod(gridp,info->recipbox[YY]); tmp+=tmp1*tmp2; tmp1=eps_poly3(nz,info->nkz[0],info->pme_order[0]); tmp1*=info->nkz[0]; tmp2=iprod(gridp,info->recipbox[ZZ]); tmp+=tmp1*tmp2; tmp*=4.0 * M_PI; tmp1=eps_poly4(nx,info->nkx[0],info->pme_order[0]); tmp1*=norm2(info->recipbox[XX]); tmp1*=info->nkx[0] * info->nkx[0]; tmp+=tmp1; tmp1=eps_poly4(ny,info->nky[0],info->pme_order[0]); tmp1*=norm2(info->recipbox[YY]); tmp1*=info->nky[0] * info->nky[0]; tmp+=tmp1; tmp1=eps_poly4(nz,info->nkz[0],info->pme_order[0]); tmp1*=norm2(info->recipbox[ZZ]); tmp1*=info->nkz[0] * info->nkz[0]; tmp+=tmp1; e_rec2+= 4.0 * coeff * coeff * tmp * q2_all * q2_all / nr ; } } if (MASTER(cr)) fprintf(stderr, "\rCalculating reciprocal error part 1 ... %3.0f%%", 100.0*(nx-startlocal+1)/(x_per_core)); } if (MASTER(cr)) fprintf(stderr, "\n"); /* Use just a fraction of all charges to estimate the self energy error term? */ bFraction = (info->fracself > 0.0) && (info->fracself < 1.0); if (bFraction) { /* Here xtot is the number of samples taken for the Monte Carlo calculation * of the average of term IV of equation 35 in Wang2010. Round up to a * number of samples that is divisible by the number of nodes */ x_per_core = ceil(info->fracself * nr / (real)cr->nnodes); xtot = x_per_core * cr->nnodes; } else { /* In this case we use all nr particle positions */ xtot = nr; x_per_core = ceil( (real)xtot / (real)cr->nnodes ); } startlocal = x_per_core * cr->nodeid; stoplocal = min(startlocal + x_per_core, xtot); /* min needed if xtot == nr */ if (bFraction) { /* Make shure we get identical results in serial and parallel. Therefore, * take the sample indices from a single, global random number array that * is constructed on the master node and that only depends on the seed */ snew(numbers, xtot); if (MASTER(cr)) { for (i=0; i<xtot; i++) { numbers[i] = floor(gmx_rng_uniform_real(rng) * nr ); } } /* Broadcast the random number array to the other nodes */ if (PAR(cr)) { nblock_bc(cr,xtot,numbers); } if (bVerbose && MASTER(cr)) { fprintf(stdout, "Using %d sample%s to approximate the self interaction error term", xtot, xtot==1?"":"s"); if (PAR(cr)) fprintf(stdout, " (%d sample%s per node)", x_per_core, x_per_core==1?"":"s"); fprintf(stdout, ".\n"); } } /* Return the number of positions used for the Monte Carlo algorithm */ *nsamples = xtot; for(i=startlocal;i<stoplocal;i++) { e_rec3x=0; e_rec3y=0; e_rec3z=0; if (bFraction) { /* Randomly pick a charge */ ci = numbers[i]; } else { /* Use all charges */ ci = i; } /* for(nx=startlocal; nx<=stoplocal; nx++)*/ for(nx=-info->nkx[0]/2; nx<info->nkx[0]/2+1; nx++) { svmul(nx,info->recipbox[XX],gridpx); for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++) { svmul(ny,info->recipbox[YY],tmpvec); rvec_add(gridpx,tmpvec,gridpxy); for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++) { if ( 0 == nx && 0 == ny && 0 == nz) continue; svmul(nz,info->recipbox[ZZ],tmpvec); rvec_add(gridpxy,tmpvec,gridp); tmp=norm2(gridp); coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] ); coeff/= tmp ; e_rec3x+=coeff*eps_self(nx,info->nkx[0],info->recipbox[XX],info->pme_order[0],x[ci]); e_rec3y+=coeff*eps_self(ny,info->nky[0],info->recipbox[YY],info->pme_order[0],x[ci]); e_rec3z+=coeff*eps_self(nz,info->nkz[0],info->recipbox[ZZ],info->pme_order[0],x[ci]); } } } clear_rvec(tmpvec2); svmul(e_rec3x,info->recipbox[XX],tmpvec); rvec_inc(tmpvec2,tmpvec); svmul(e_rec3y,info->recipbox[YY],tmpvec); rvec_inc(tmpvec2,tmpvec); svmul(e_rec3z,info->recipbox[ZZ],tmpvec); rvec_inc(tmpvec2,tmpvec); e_rec3 += q[ci]*q[ci]*q[ci]*q[ci]*norm2(tmpvec2) / ( xtot * M_PI * info->volume * M_PI * info->volume); if (MASTER(cr)){ fprintf(stderr, "\rCalculating reciprocal error part 2 ... %3.0f%%", 100.0*(i+1)/stoplocal); } } if (MASTER(cr)) fprintf(stderr, "\n"); #ifdef GMX_LIB_MPI #ifdef TAKETIME if (MASTER(cr)) { t1= MPI_Wtime() - t0; fprintf(fp_out, "Recip. err. est. took : %lf s\n", t1); } #endif #endif #ifdef DEBUG if (PAR(cr)) { fprintf(stderr, "Node %3d: nx=[%3d...%3d] e_rec3=%e\n", cr->nodeid, startlocal, stoplocal, e_rec3); } #endif if (PAR(cr)) { gmx_sum(1,&e_rec1,cr); gmx_sum(1,&e_rec2,cr); gmx_sum(1,&e_rec3,cr); } /* e_rec1*=8.0 * q2_all / info->volume / info->volume / nr ; e_rec2*= q2_all / M_PI / M_PI / info->volume / info->volume / nr ; e_rec3/= M_PI * M_PI * info->volume * info->volume * nr ; */ e_rec=sqrt(e_rec1+e_rec2+e_rec3); return ONE_4PI_EPS0 * e_rec; }
int main(int argc,char *argv[]) { static char *desc[] = { "[TT]mkice[tt] generates an ice crystal in the Ih crystal form which is the", "most stable form. The rectangular unitcell contains eight molecules", "and all oxygens are tetrahedrally coordinated.[PAR]", "If an input file is given it is interpreted as a series of oxygen", "coordinates the distance between which can be scaled by the odist flag.", "The program then adds hydrogens to the oxygens in random orientation", "but with proper OH distances and HOH angle. This feature allows to", "build water clusters based on oxygen coordinates only." }; static int nx=1,ny=1,nz=1; static gmx_bool bYaw=FALSE,bLJ=TRUE,bFull=TRUE,bSeries=FALSE; static gmx_bool bOrdered=TRUE,bDiamond=FALSE,bPBC=TRUE; static real rcut=0.3,odist=0.274,hdist=0.09572; t_pargs pa[] = { { "-nx", FALSE, etINT, {&nx}, "nx" }, { "-ny", FALSE, etINT, {&ny}, "ny" }, { "-nz", FALSE, etINT, {&nz}, "nz" }, { "-yaw", FALSE, etBOOL, {&bYaw}, "Generate virtual sites and shell positions" }, { "-lj", FALSE, etBOOL, {&bLJ}, "Use LJ as well as coulomb for virial calculation" }, { "-rcut", FALSE,etREAL, {&rcut},"Cut-off for virial calculations" }, { "-full", FALSE,etBOOL, {&bFull},"Full virial output" }, { "-odist", FALSE, etREAL, {&odist}, "Distance (nm) between oxygens" }, { "-hdist", FALSE, etREAL, {&hdist}, "Bondlength (nm) for OH bond" }, { "-diamond",FALSE,etBOOL, {&bDiamond}, "Make a diamond instead" }, { "-pbc", FALSE, etBOOL, {&bPBC}, "Make a periodic diamond" }, { "-order", FALSE,etBOOL, {&bOrdered}, "Make a proton-ordered ice lattice" }, { "-series",FALSE, etBOOL, {&bSeries}, "Do a series of virial calculations with different cut-off (from 0.3 up till the specified one)" } }; t_filenm fnm[] = { { efSTO, "-p", "ice", ffWRITE }, { efSTO, "-c", NULL, ffOPTRD }, { efDAT, "-f", NULL, ffOPTRD }, { efTRN, "-o", "ice", ffOPTWR } }; #define NFILE asize(fnm) FILE *fp; char *fn,quote[256]; int i,j,k,n,nmax,m,natom,natmol; t_atoms *pdba; t_atoms atoms; t_symtab symtab; rvec box,tmp,*xx; matrix boxje; CopyRight(stdout,argv[0]); parse_common_args(&argc,argv,0,NFILE,fnm,asize(pa),pa,asize(desc), desc,0,NULL); if (debug) { fprintf(debug,"nx = %3d, ny = %3d, nz = %3d\n",nx,ny,nz); fprintf(debug,"YAW = %3s, LJ = %3s, rcut = %g\n",yesno_names[bYaw], yesno_names[bLJ],rcut); } if (bYaw) natmol = 5; else if (bDiamond) natmol = 1; else natmol = 3; if (opt2bSet("-f",NFILE,fnm)) { natom = read_rel_coords(opt2fn("-f",NFILE,fnm),&xx,natmol); nmax = natom; } else { natom = natmol*8; nmax = natom*nx*ny*nz; snew(xx,nmax); } snew(pdba,1); init_t_atoms(pdba,nmax,TRUE); pdba->nr = nmax; open_symtab(&symtab); for(n=0; (n<nmax); n++) { pdba->pdbinfo[n].type = epdbATOM; pdba->pdbinfo[n].atomnr = 1+n; pdba->atom[n].resnr = 1+(n/natmol); pdba->atomname[n] = put_symtab(&symtab, bDiamond ? diamname[(n % natmol)] : watname[(n % natmol)]); if (bDiamond) pdba->resname[n] = put_symtab(&symtab,"DIA"); else pdba->resname[n] = put_symtab(&symtab,"SOL"); sprintf(pdba->pdbinfo[n].pdbresnr,"%d",n); pdba->atom[n].chain = ' '; } /* Generate the unit cell */ if (bDiamond) unitcell_d(xx,box,odist); else if (opt2bSet("-f",NFILE,fnm)) { random_h_coords(natmol,natom/natmol,xx,box,bYaw,odist,hdist); } else unitcell(xx,box,bYaw,odist,hdist); if (debug) { clear_mat(boxje); boxje[XX][XX] = box[XX]; boxje[YY][YY] = box[YY]; boxje[ZZ][ZZ] = box[ZZ]; } n=0; for(i=0; (i<nx); i++) { tmp[XX] = i*box[XX]; for(j=0; (j<ny); j++) { tmp[YY] = j*box[YY]; for(k=0; (k<nz); k++) { tmp[ZZ] = k*box[ZZ]; for(m=0; (m<natom); m++,n++) { if ((!bOrdered && ((m % natmol) == 0)) || bOrdered) rvec_add(xx[n % natom],tmp,xx[n]); else ; } } } } clear_mat(boxje); boxje[XX][XX] = box[XX]*nx; boxje[YY][YY] = box[YY]*ny; boxje[ZZ][ZZ] = box[ZZ]*nz; printf("Crystal: %10.5f %10.5f %10.5f\n", nx*box[XX],ny*box[YY],nz*box[ZZ]); if (debug && !bDiamond) { if (bSeries) for(i=3; (i<=10*rcut); i++) { fprintf(debug,"This is with rcut = %g\n",i*0.1); virial(debug,bFull,nmax/natmol,xx,boxje, 0.1*i,bYaw,bYaw ? qyaw : qspc,bLJ); } else virial(debug,bFull,nmax/natmol,xx,boxje, rcut,bYaw,bYaw ? qyaw : qspc,bLJ); } if (bDiamond) mk_diamond(pdba,xx,odist,&symtab,bPBC,boxje); fn = ftp2fn(efSTO,NFILE,fnm); if (fn2ftp(fn) == efPDB) { fp = gmx_ffopen(fn,"w"); if (bDiamond) fprintf(fp,"HEADER This is a *diamond*\n"); else fprintf(fp,"HEADER A beautiful Ice Ih crystal\n"); fprintf(fp,"REMARK Generated by mkice with the following options:\n" "REMARK nx = %d, ny = %d, nz = %d, odist = %g, hdist = %g\n", nx,ny,nz,odist,hdist); bromacs(quote,255); write_pdbfile(fp,quote,pdba,xx,boxje,' ',-1); gmx_ffclose(fp); } else { bromacs(quote,255); write_sto_conf(fn,quote,pdba,xx,NULL,boxje); } if (ftp2bSet(efTRN,NFILE,fnm)) write_trn(ftp2fn(efTRN,NFILE,fnm),0,0,0,boxje,nmax,xx,NULL,NULL); return 0; }