static t_bbb *mk_bonds(int natoms,rvec x[],real odist, gmx_bool bPBC,matrix box) { real od2 = odist*odist+1e-5; t_pbc pbc; t_bbb *bbb; int i,j; rvec dx; if (bPBC) set_pbc(&pbc,box); snew(bbb,natoms); for(i=0; (i<natoms); i++) { for(j=i+1; (j<natoms); j++) { if (bPBC) pbc_dx(&pbc,x[i],x[j],dx); else rvec_sub(x[i],x[j],dx); if (iprod(dx,dx) <= od2) { bbb[i].aa[bbb[i].n++] = j; bbb[j].aa[bbb[j].n++] = i; } } } if (debug) #define PRB(nn) (bbb[(i)].n >= (nn)) ? bbb[i].aa[nn-1] : -1 for(i=0; (i<natoms); i++) fprintf(debug,"bonds from %3d: %d %d %d %d\n", i,PRB(1),PRB(2),PRB(3),PRB(4)); #undef PRB return bbb; }
/* This is a (maybe) slow workaround to avoid the neighbor searching in addconf.c, which * leaks memory (May 2012). The function could be deleted as soon as the momory leaks * in addconf.c are fixed. * However, when inserting a small molecule in a system containing not too many atoms, * allPairsDistOk is probably even faster than addconf.c */ static gmx_bool allPairsDistOk(t_atoms *atoms, rvec *x, real *r, int ePBC, matrix box, t_atoms *atoms_insrt, rvec *x_n, real *r_insrt) { int i, j; rvec dx; real n2, r2; t_pbc pbc; set_pbc(&pbc, ePBC, box); for (i = 0; i < atoms->nr; i++) { for (j = 0; j < atoms_insrt->nr; j++) { pbc_dx(&pbc, x[i], x_n[j], dx); n2 = norm2(dx); r2 = sqr(r[i]+r_insrt[j]); if (n2 < r2) { return FALSE; } } } return TRUE; }
void set_pull_init(t_inputrec *ir, gmx_mtop_t *mtop, rvec *x, matrix box, real lambda, const output_env_t oenv) { pull_params_t *pull; struct pull_t *pull_work; t_mdatoms *md; t_pbc pbc; int c; double t_start; pull = ir->pull; pull_work = init_pull(NULL, pull, ir, 0, NULL, mtop, NULL, oenv, lambda, FALSE, 0); md = init_mdatoms(NULL, mtop, ir->efep); atoms2md(mtop, ir, 0, NULL, mtop->natoms, md); if (ir->efep) { update_mdatoms(md, lambda); } set_pbc(&pbc, ir->ePBC, box); t_start = ir->init_t + ir->init_step*ir->delta_t; pull_calc_coms(NULL, pull_work, md, &pbc, t_start, x, NULL); fprintf(stderr, "Pull group natoms pbc atom distance at start reference at t=0\n"); for (c = 0; c < pull->ncoord; c++) { t_pull_coord *pcrd; t_pull_group *pgrp0, *pgrp1; double value; real init = 0; pcrd = &pull->coord[c]; pgrp0 = &pull->group[pcrd->group[0]]; pgrp1 = &pull->group[pcrd->group[1]]; fprintf(stderr, "%8d %8d %8d\n", pcrd->group[0], pgrp0->nat, pgrp0->pbcatom+1); fprintf(stderr, "%8d %8d %8d ", pcrd->group[1], pgrp1->nat, pgrp1->pbcatom+1); if (pcrd->bStart) { init = pcrd->init; pcrd->init = 0; } get_pull_coord_value(pull_work, c, &pbc, &value); fprintf(stderr, " %10.3f nm", value); if (pcrd->bStart) { pcrd->init = value + init; } fprintf(stderr, " %10.3f nm\n", pcrd->init); } finish_pull(pull_work); }
static void calc_dist_tot(int nind, atom_id index[], rvec x[], int ePBC, matrix box, real **d, real **dtot, real **dtot2, gmx_bool bNMR, real **dtot1_3, real **dtot1_6) { int i, j; real *xi; real temp, temp2, temp1_3; rvec dx; t_pbc pbc; set_pbc(&pbc, ePBC, box); for (i = 0; (i < nind-1); i++) { xi = x[index[i]]; for (j = i+1; (j < nind); j++) { pbc_dx(&pbc, xi, x[index[j]], dx); temp2 = norm2(dx); temp = std::sqrt(temp2); d[i][j] = temp; dtot[i][j] += temp; dtot2[i][j] += temp2; if (bNMR) { temp1_3 = 1.0/(temp*temp2); dtot1_3[i][j] += temp1_3; dtot1_6[i][j] += temp1_3*temp1_3; } } } }
void mk_bonds(int nnm, t_nm2type nmt[], t_atoms *atoms, rvec x[], t_params *bond, int nbond[], gmx_bool bPBC, matrix box) { t_param b; int i, j; t_pbc pbc; rvec dx; real dx2; for (i = 0; (i < MAXATOMLIST); i++) { b.a[i] = -1; } for (i = 0; (i < MAXFORCEPARAM); i++) { b.c[i] = 0.0; } if (bPBC) { set_pbc(&pbc, -1, box); } for (i = 0; (i < atoms->nr); i++) { if ((i % 10) == 0) { fprintf(stderr, "\ratom %d", i); } for (j = i+1; (j < atoms->nr); j++) { if (bPBC) { pbc_dx(&pbc, x[i], x[j], dx); } else { rvec_sub(x[i], x[j], dx); } dx2 = iprod(dx, dx); if (is_bond(nnm, nmt, *atoms->atomname[i], *atoms->atomname[j], sqrt(dx2))) { b.AI = i; b.AJ = j; b.C0 = sqrt(dx2); add_param_to_list (bond, &b); nbond[i]++; nbond[j]++; if (debug) { fprintf(debug, "Bonding atoms %s-%d and %s-%d\n", *atoms->atomname[i], i+1, *atoms->atomname[j], j+1); } } } } fprintf(stderr, "\ratom %d\n", i); }
static void chk_bonds(t_idef *idef, int ePBC, rvec *x, matrix box, real tol) { int ftype, i, k, ai, aj, type; real b0, blen, deviation, devtot; t_pbc pbc; rvec dx; devtot = 0; set_pbc(&pbc, ePBC, box); for (ftype = 0; (ftype < F_NRE); ftype++) { if ((interaction_function[ftype].flags & IF_CHEMBOND) == IF_CHEMBOND) { for (k = 0; (k < idef->il[ftype].nr); ) { type = idef->il[ftype].iatoms[k++]; ai = idef->il[ftype].iatoms[k++]; aj = idef->il[ftype].iatoms[k++]; b0 = 0; switch (ftype) { case F_BONDS: b0 = idef->iparams[type].harmonic.rA; break; case F_G96BONDS: b0 = sqrt(idef->iparams[type].harmonic.rA); break; case F_MORSE: b0 = idef->iparams[type].morse.b0A; break; case F_CUBICBONDS: b0 = idef->iparams[type].cubic.b0; break; case F_CONSTR: b0 = idef->iparams[type].constr.dA; break; default: break; } if (b0 != 0) { pbc_dx(&pbc, x[ai], x[aj], dx); blen = norm(dx); deviation = sqr(blen-b0); if (sqrt(deviation/sqr(b0) > tol)) { fprintf(stderr, "Distance between atoms %d and %d is %.3f, should be %.3f\n", ai+1, aj+1, blen, b0); } } } } } }
static void calc_mj(t_topology top, int ePBC, matrix box, gmx_bool bNoJump, int isize, int index0[], \ rvec fr[], rvec mj, real mass2[], real qmol[]) { int i, j, k, l; rvec tmp; rvec center; rvec mt1, mt2; t_pbc pbc; calc_box_center(ecenterRECT, box, center); if (!bNoJump) { set_pbc(&pbc, ePBC, box); } clear_rvec(tmp); for (i = 0; i < isize; i++) { clear_rvec(mt1); clear_rvec(mt2); k = top.mols.index[index0[i]]; l = top.mols.index[index0[i+1]]; for (j = k; j < l; j++) { svmul(mass2[j], fr[j], tmp); rvec_inc(mt1, tmp); } if (bNoJump) { svmul(qmol[k], mt1, mt1); } else { pbc_dx(&pbc, mt1, center, mt2); svmul(qmol[k], mt2, mt1); } rvec_inc(mj, mt1); } }
void setStateDependentAwhParams(AwhParams *awhParams, const pull_params_t *pull_params, pull_t *pull_work, const matrix box, int ePBC, const t_grpopts *inputrecGroupOptions, warninp_t wi) { /* The temperature is not really state depenendent but is not known * when read_awhParams is called (in get ir). * It is known first after do_index has been called in grompp.cpp. */ if (inputrecGroupOptions->ref_t == NULL || inputrecGroupOptions->ref_t[0] <= 0) { gmx_fatal(FARGS, "AWH biasing is only supported for temperatures > 0"); } for (int i = 1; i < inputrecGroupOptions->ngtc; i++) { if (inputrecGroupOptions->ref_t[i] != inputrecGroupOptions->ref_t[0]) { gmx_fatal(FARGS, "AWH biasing is currently only supported for identical temperatures for all temperature coupling groups"); } } t_pbc pbc; set_pbc(&pbc, ePBC, box); for (int k = 0; k < awhParams->numBias; k++) { AwhBiasParams *awhBiasParams = &awhParams->awhBiasParams[k]; for (int d = 0; d < awhBiasParams->ndim; d++) { AwhDimParams *dimParams = &awhBiasParams->dimParams[d]; /* The periodiciy of the AWH grid in certain cases depends on the simulation box */ dimParams->period = get_pull_coord_period(pull_params, dimParams->coordIndex, box); /* The initial coordinate value, converted to external user units. */ dimParams->coordValueInit = get_pull_coord_value(pull_work, dimParams->coordIndex, &pbc); t_pull_coord *pullCoord = &pull_params->coord[dimParams->coordIndex]; dimParams->coordValueInit *= pull_conversion_factor_internal2userinput(pullCoord); } } checkInputConsistencyInterval(awhParams, wi); /* Register AWH as external potential with pull to check consistency. */ Awh::registerAwhWithPull(*awhParams, pull_work); }
void calc_angles_dihs(t_params *ang, t_params *dih, rvec x[], gmx_bool bPBC, matrix box) { int i, ai, aj, ak, al, t1, t2, t3; rvec r_ij, r_kj, r_kl, m, n; real sign, th, costh, ph; t_pbc pbc; if (bPBC) { set_pbc(&pbc, epbcXYZ, box); } if (debug) { pr_rvecs(debug, 0, "X2TOP", box, DIM); } for (i = 0; (i < ang->nr); i++) { ai = ang->param[i].AI; aj = ang->param[i].AJ; ak = ang->param[i].AK; th = RAD2DEG*bond_angle(x[ai], x[aj], x[ak], bPBC ? &pbc : NULL, r_ij, r_kj, &costh, &t1, &t2); if (debug) { fprintf(debug, "X2TOP: ai=%3d aj=%3d ak=%3d r_ij=%8.3f r_kj=%8.3f th=%8.3f\n", ai, aj, ak, norm(r_ij), norm(r_kj), th); } ang->param[i].C0 = th; } for (i = 0; (i < dih->nr); i++) { ai = dih->param[i].AI; aj = dih->param[i].AJ; ak = dih->param[i].AK; al = dih->param[i].AL; ph = RAD2DEG*dih_angle(x[ai], x[aj], x[ak], x[al], bPBC ? &pbc : NULL, r_ij, r_kj, r_kl, m, n, &sign, &t1, &t2, &t3); if (debug) { fprintf(debug, "X2TOP: ai=%3d aj=%3d ak=%3d al=%3d r_ij=%8.3f r_kj=%8.3f r_kl=%8.3f ph=%8.3f\n", ai, aj, ak, al, norm(r_ij), norm(r_kj), norm(r_kl), ph); } dih->param[i].C0 = ph; } }
static void calc_mat(int nres, int natoms, int rndx[], rvec x[], atom_id *index, real trunc, real **mdmat, int **nmat, int ePBC, matrix box) { int i, j, resi, resj; real trunc2, r, r2; t_pbc pbc; rvec ddx; set_pbc(&pbc, ePBC, box); trunc2 = sqr(trunc); for (resi = 0; (resi < nres); resi++) { for (resj = 0; (resj < nres); resj++) { mdmat[resi][resj] = FARAWAY; } } for (i = 0; (i < natoms); i++) { resi = rndx[i]; for (j = i+1; (j < natoms); j++) { resj = rndx[j]; pbc_dx(&pbc, x[index[i]], x[index[j]], ddx); r2 = norm2(ddx); if (r2 < trunc2) { nmat[resi][j]++; nmat[resj][i]++; } mdmat[resi][resj] = min(r2, mdmat[resi][resj]); } } for (resi = 0; (resi < nres); resi++) { mdmat[resi][resi] = 0; for (resj = resi+1; (resj < nres); resj++) { r = sqrt(mdmat[resi][resj]); mdmat[resi][resj] = r; mdmat[resj][resi] = r; } } }
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; }
static void calc_dist(int nind, int index[], const rvec x[], int ePBC, matrix box, real **d) { int i, j; rvec dx; real temp2; t_pbc pbc; set_pbc(&pbc, ePBC, box); for (i = 0; (i < nind-1); i++) { const real *xi = x[index[i]]; for (j = i+1; (j < nind); j++) { pbc_dx(&pbc, xi, x[index[j]], dx); temp2 = norm2(dx); d[i][j] = std::sqrt(temp2); } } }
void partition_absorbing_box( grid_t * g, double gx0, double gy0, double gz0, double gx1, double gy1, double gz1, int gnx, int gny, int gnz, int gpx, int gpy, int gpz, int pbc ) { int px, py, pz; partition_periodic_box( g, gx0, gy0, gz0, gx1, gy1, gz1, gnx, gny, gnz, gpx, gpy, gpz ); // Override periodic boundary conditions RANK_TO_INDEX( world_rank, px,py,pz ); if( px==0 && gnx>1 ) { set_fbc(g,BOUNDARY(-1,0,0),absorb_fields); set_pbc(g,BOUNDARY(-1,0,0),pbc); } if( px==gpx-1 && gnx>1 ) { set_fbc(g,BOUNDARY( 1,0,0),absorb_fields); set_pbc(g,BOUNDARY( 1,0,0),pbc); } if( py==0 && gny>1 ) { set_fbc(g,BOUNDARY(0,-1,0),absorb_fields); set_pbc(g,BOUNDARY(0,-1,0),pbc); } if( py==gpy-1 && gny>1 ) { set_fbc(g,BOUNDARY(0, 1,0),absorb_fields); set_pbc(g,BOUNDARY(0, 1,0),pbc); } if( pz==0 && gnz>1 ) { set_fbc(g,BOUNDARY(0,0,-1),absorb_fields); set_pbc(g,BOUNDARY(0,0,-1),pbc); } if( pz==gpz-1 && gnz>1 ) { set_fbc(g,BOUNDARY(0,0, 1),absorb_fields); set_pbc(g,BOUNDARY(0,0, 1),pbc); } }
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]); } }
int gmx_dist(int argc,char *argv[]) { const char *desc[] = { "[TT]g_dist[tt] can calculate the distance between the centers of mass of two", "groups of atoms as a function of time. The total distance and its", "[IT]x[it]-, [IT]y[it]-, and [IT]z[it]-components are plotted.[PAR]", "Or when [TT]-dist[tt] is set, print all the atoms in group 2 that are", "closer than a certain distance to the center of mass of group 1.[PAR]", "With options [TT]-lt[tt] and [TT]-dist[tt] the number of contacts", "of all atoms in group 2 that are closer than a certain distance", "to the center of mass of group 1 are plotted as a function of the time", "that the contact was continuously present.[PAR]", "Other programs that calculate distances are [TT]g_mindist[tt]", "and [TT]g_bond[tt]." }; t_topology *top=NULL; int ePBC; real t,t0,cut2,dist2; rvec *x=NULL,*v=NULL,dx; matrix box; t_trxstatus *status; int natoms; int g,d,i,j,res,teller=0; atom_id aid; int ngrps; /* the number of index groups */ atom_id **index,max; /* the index for the atom numbers */ int *isize; /* the size of each group */ char **grpname; /* the name of each group */ rvec *com; real *mass; FILE *fp=NULL,*fplt=NULL; gmx_bool bCutoff,bPrintDist,bLifeTime; t_pbc *pbc; int *contact_time=NULL,*ccount=NULL,ccount_nalloc=0,sum; char buf[STRLEN]; output_env_t oenv; gmx_rmpbc_t gpbc=NULL; const char *leg[4] = { "|d|","d\\sx\\N","d\\sy\\N","d\\sz\\N" }; static real cut=0; static t_pargs pa[] = { { "-dist", FALSE, etREAL, {&cut}, "Print all atoms in group 2 closer than dist to the center of mass of group 1" } }; #define NPA asize(pa) t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPX, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, NULL, "dist", ffOPTWR }, { efXVG, "-lt", "lifetime", ffOPTWR }, }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_BE_NICE, NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL,&oenv); bCutoff = opt2parg_bSet("-dist",NPA,pa); cut2 = cut*cut; bLifeTime = opt2bSet("-lt",NFILE,fnm); bPrintDist = (bCutoff && !bLifeTime); top=read_top(ftp2fn(efTPX,NFILE,fnm),&ePBC); /* read index files */ ngrps = 2; snew(com,ngrps); snew(grpname,ngrps); snew(index,ngrps); snew(isize,ngrps); get_index(&top->atoms,ftp2fn(efNDX,NFILE,fnm),ngrps,isize,index,grpname); /* calculate mass */ max=0; snew(mass,ngrps); for(g=0;(g<ngrps);g++) { mass[g]=0; for(i=0;(i<isize[g]);i++) { if (index[g][i]>max) max=index[g][i]; if (index[g][i] >= top->atoms.nr) gmx_fatal(FARGS,"Atom number %d, item %d of group %d, is larger than number of atoms in the topolgy (%d)\n",index[g][i]+1,i+1,g+1,top->atoms.nr+1); mass[g]+=top->atoms.atom[index[g][i]].m; } } natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); t0 = t; if (max>=natoms) gmx_fatal(FARGS,"Atom number %d in an index group is larger than number of atoms in the trajectory (%d)\n",(int)max+1,natoms); if (!bCutoff) { /* open output file */ fp = xvgropen(ftp2fn(efXVG,NFILE,fnm), "Distance","Time (ps)","Distance (nm)",oenv); xvgr_legend(fp,4,leg,oenv); } else { ngrps = 1; if (bLifeTime) snew(contact_time,isize[1]); } if (ePBC != epbcNONE) snew(pbc,1); else pbc = NULL; gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box); do { /* initialisation for correct distance calculations */ if (pbc) { set_pbc(pbc,ePBC,box); /* make molecules whole again */ gmx_rmpbc(gpbc,natoms,box,x); } /* calculate center of masses */ for(g=0;(g<ngrps);g++) { if (isize[g] == 1) { copy_rvec(x[index[g][0]],com[g]); } else { for(d=0;(d<DIM);d++) { com[g][d]=0; for(i=0;(i<isize[g]);i++) { com[g][d] += x[index[g][i]][d] * top->atoms.atom[index[g][i]].m; } com[g][d] /= mass[g]; } } } if (!bCutoff) { /* write to output */ fprintf(fp,"%12.7f ",t); for(g=0;(g<ngrps/2);g++) { if (pbc) pbc_dx(pbc,com[2*g],com[2*g+1],dx); else rvec_sub(com[2*g],com[2*g+1],dx); fprintf(fp,"%12.7f %12.7f %12.7f %12.7f", norm(dx),dx[XX],dx[YY],dx[ZZ]); } fprintf(fp,"\n"); } else { for(i=0;(i<isize[1]);i++) { j=index[1][i]; if (pbc) pbc_dx(pbc,x[j],com[0],dx); else rvec_sub(x[j],com[0],dx); dist2 = norm2(dx); if (dist2<cut2) { if (bPrintDist) { res=top->atoms.atom[j].resind; fprintf(stdout,"\rt: %g %d %s %d %s %g (nm)\n", t,top->atoms.resinfo[res].nr,*top->atoms.resinfo[res].name, j+1,*top->atoms.atomname[j],sqrt(dist2)); } if (bLifeTime) contact_time[i]++; } else { if (bLifeTime) { if (contact_time[i]) { add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1); contact_time[i] = 0; } } } } } teller++; } while (read_next_x(oenv,status,&t,natoms,x,box)); gmx_rmpbc_done(gpbc); if (!bCutoff) ffclose(fp); close_trj(status); if (bCutoff && bLifeTime) { /* Add the contacts still present in the last frame */ for(i=0; i<isize[1]; i++) if (contact_time[i]) add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1); sprintf(buf,"%s - %s within %g nm", grpname[0],grpname[1],cut); fp = xvgropen(opt2fn("-lt",NFILE,fnm), buf,"Time (ps)","Number of contacts",oenv); for(i=0; i<min(ccount_nalloc,teller-1); i++) { /* Account for all subintervals of longer intervals */ sum = 0; for(j=i; j<ccount_nalloc; j++) sum += (j-i+1)*ccount[j]; fprintf(fp,"%10.3f %10.3f\n",i*(t-t0)/(teller-1),sum/(double)(teller-i)); } ffclose(fp); } thanx(stderr); return 0; }
int gmx_densmap(int argc,char *argv[]) { const char *desc[] = { "[TT]g_densmap[tt] computes 2D number-density maps.", "It can make planar and axial-radial density maps.", "The output [TT].xpm[tt] file can be visualized with for instance xv", "and can be converted to postscript with [TT]xpm2ps[tt].", "Optionally, output can be in text form to a [TT].dat[tt] file with [TT]-od[tt], instead of the usual [TT].xpm[tt] file with [TT]-o[tt].", "[PAR]", "The default analysis is a 2-D number-density map for a selected", "group of atoms in the x-y plane.", "The averaging direction can be changed with the option [TT]-aver[tt].", "When [TT]-xmin[tt] and/or [TT]-xmax[tt] are set only atoms that are", "within the limit(s) in the averaging direction are taken into account.", "The grid spacing is set with the option [TT]-bin[tt].", "When [TT]-n1[tt] or [TT]-n2[tt] is non-zero, the grid", "size is set by this option.", "Box size fluctuations are properly taken into account.", "[PAR]", "When options [TT]-amax[tt] and [TT]-rmax[tt] are set, an axial-radial", "number-density map is made. Three groups should be supplied, the centers", "of mass of the first two groups define the axis, the third defines the", "analysis group. The axial direction goes from -amax to +amax, where", "the center is defined as the midpoint between the centers of mass and", "the positive direction goes from the first to the second center of mass.", "The radial direction goes from 0 to rmax or from -rmax to +rmax", "when the [TT]-mirror[tt] option has been set.", "[PAR]", "The normalization of the output is set with the [TT]-unit[tt] option.", "The default produces a true number density. Unit [TT]nm-2[tt] leaves out", "the normalization for the averaging or the angular direction.", "Option [TT]count[tt] produces the count for each grid cell.", "When you do not want the scale in the output to go", "from zero to the maximum density, you can set the maximum", "with the option [TT]-dmax[tt]." }; static int n1=0,n2=0; static real xmin=-1,xmax=-1,bin=0.02,dmin=0,dmax=0,amax=0,rmax=0; static gmx_bool bMirror=FALSE, bSums=FALSE; static const char *eaver[]= { NULL, "z", "y", "x", NULL }; static const char *eunit[]= { NULL, "nm-3", "nm-2", "count", NULL }; t_pargs pa[] = { { "-bin", FALSE, etREAL, {&bin}, "Grid size (nm)" }, { "-aver", FALSE, etENUM, {eaver}, "The direction to average over" }, { "-xmin", FALSE, etREAL, {&xmin}, "Minimum coordinate for averaging" }, { "-xmax", FALSE, etREAL, {&xmax}, "Maximum coordinate for averaging" }, { "-n1", FALSE, etINT, {&n1}, "Number of grid cells in the first direction" }, { "-n2", FALSE, etINT, {&n2}, "Number of grid cells in the second direction" }, { "-amax", FALSE, etREAL, {&amax}, "Maximum axial distance from the center" }, { "-rmax", FALSE, etREAL, {&rmax}, "Maximum radial distance" }, { "-mirror", FALSE, etBOOL, {&bMirror}, "Add the mirror image below the axial axis" }, { "-sums", FALSE, etBOOL, {&bSums}, "Print density sums (1D map) to stdout" }, { "-unit", FALSE, etENUM, {eunit}, "Unit for the output" }, { "-dmin", FALSE, etREAL, {&dmin}, "Minimum density in output" }, { "-dmax", FALSE, etREAL, {&dmax}, "Maximum density in output (0 means calculate it)" }, }; gmx_bool bXmin,bXmax,bRadial; FILE *fp; t_trxstatus *status; t_topology top; int ePBC=-1; rvec *x,xcom[2],direction,center,dx; matrix box; real t,m,mtot; t_pbc pbc; int cav=0,c1=0,c2=0,natoms; char **grpname,title[256],buf[STRLEN]; const char *unit; int i,j,k,l,ngrps,anagrp,*gnx=NULL,nindex,nradial=0,nfr,nmpower; atom_id **ind=NULL,*index; real **grid,maxgrid,m1,m2,box1,box2,*tickx,*tickz,invcellvol; real invspa=0,invspz=0,axial,r,vol_old,vol,rowsum; int nlev=51; t_rgb rlo= {1,1,1}, rhi= {0,0,0}; output_env_t oenv; const char *label[]= { "x (nm)", "y (nm)", "z (nm)" }; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efDAT, "-od", "densmap", ffOPTWR }, { efXPM, "-o", "densmap", ffWRITE } }; #define NFILE asize(fnm) int npargs; CopyRight(stderr,argv[0]); npargs = asize(pa); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE, NFILE,fnm,npargs,pa,asize(desc),desc,0,NULL,&oenv); bXmin = opt2parg_bSet("-xmin",npargs,pa); bXmax = opt2parg_bSet("-xmax",npargs,pa); bRadial = (amax>0 || rmax>0); if (bRadial) { if (amax<=0 || rmax<=0) gmx_fatal(FARGS,"Both amax and rmax should be larger than zero"); } if (strcmp(eunit[0],"nm-3") == 0) { nmpower = -3; unit = "(nm^-3)"; } else if (strcmp(eunit[0],"nm-2") == 0) { nmpower = -2; unit = "(nm^-2)"; } else { nmpower = 0; unit = "count"; } if (ftp2bSet(efTPS,NFILE,fnm) || !ftp2bSet(efNDX,NFILE,fnm)) read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&x,NULL,box, bRadial); if (!bRadial) { ngrps = 1; fprintf(stderr,"\nSelect an analysis group\n"); } else { ngrps = 3; fprintf(stderr, "\nSelect two groups to define the axis and an analysis group\n"); } snew(gnx,ngrps); snew(grpname,ngrps); snew(ind,ngrps); get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),ngrps,gnx,ind,grpname); anagrp = ngrps - 1; nindex = gnx[anagrp]; index = ind[anagrp]; if (bRadial) { if ((gnx[0]>1 || gnx[1]>1) && !ftp2bSet(efTPS,NFILE,fnm)) gmx_fatal(FARGS,"No run input file was supplied (option -s), this is required for the center of mass calculation"); } switch (eaver[0][0]) { case 'x': cav = XX; c1 = YY; c2 = ZZ; break; case 'y': cav = YY; c1 = XX; c2 = ZZ; break; case 'z': cav = ZZ; c1 = XX; c2 = YY; break; } natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); if (!bRadial) { if (n1 == 0) n1 = (int)(box[c1][c1]/bin + 0.5); if (n2 == 0) n2 = (int)(box[c2][c2]/bin + 0.5); } else { n1 = (int)(2*amax/bin + 0.5); nradial = (int)(rmax/bin + 0.5); invspa = n1/(2*amax); invspz = nradial/rmax; if (bMirror) n2 = 2*nradial; else n2 = nradial; } snew(grid,n1); for(i=0; i<n1; i++) snew(grid[i],n2); box1 = 0; box2 = 0; nfr = 0; do { if (!bRadial) { box1 += box[c1][c1]; box2 += box[c2][c2]; invcellvol = n1*n2; if (nmpower == -3) invcellvol /= det(box); else if (nmpower == -2) invcellvol /= box[c1][c1]*box[c2][c2]; for(i=0; i<nindex; i++) { j = index[i]; if ((!bXmin || x[j][cav] >= xmin) && (!bXmax || x[j][cav] <= xmax)) { m1 = x[j][c1]/box[c1][c1]; if (m1 >= 1) m1 -= 1; if (m1 < 0) m1 += 1; m2 = x[j][c2]/box[c2][c2]; if (m2 >= 1) m2 -= 1; if (m2 < 0) m2 += 1; grid[(int)(m1*n1)][(int)(m2*n2)] += invcellvol; } } } else { set_pbc(&pbc,ePBC,box); for(i=0; i<2; i++) { if (gnx[i] == 1) { /* One atom, just copy the coordinates */ copy_rvec(x[ind[i][0]],xcom[i]); } else { /* Calculate the center of mass */ clear_rvec(xcom[i]); mtot = 0; for(j=0; j<gnx[i]; j++) { k = ind[i][j]; m = top.atoms.atom[k].m; for(l=0; l<DIM; l++) xcom[i][l] += m*x[k][l]; mtot += m; } svmul(1/mtot,xcom[i],xcom[i]); } } pbc_dx(&pbc,xcom[1],xcom[0],direction); for(i=0; i<DIM; i++) center[i] = xcom[0][i] + 0.5*direction[i]; unitv(direction,direction); for(i=0; i<nindex; i++) { j = index[i]; pbc_dx(&pbc,x[j],center,dx); axial = iprod(dx,direction); r = sqrt(norm2(dx) - axial*axial); if (axial>=-amax && axial<amax && r<rmax) { if (bMirror) r += rmax; grid[(int)((axial + amax)*invspa)][(int)(r*invspz)] += 1; } } } nfr++; } while(read_next_x(oenv,status,&t,natoms,x,box)); close_trj(status); /* normalize gridpoints */ maxgrid = 0; if (!bRadial) { for (i=0; i<n1; i++) { for (j=0; j<n2; j++) { grid[i][j] /= nfr; if (grid[i][j] > maxgrid) maxgrid = grid[i][j]; } } } else { for (i=0; i<n1; i++) { vol_old = 0; for (j=0; j<nradial; j++) { switch (nmpower) { case -3: vol = M_PI*(j+1)*(j+1)/(invspz*invspz*invspa); break; case -2: vol = (j+1)/(invspz*invspa); break; default: vol = j+1; break; } if (bMirror) k = j + nradial; else k = j; grid[i][k] /= nfr*(vol - vol_old); if (bMirror) grid[i][nradial-1-j] = grid[i][k]; vol_old = vol; if (grid[i][k] > maxgrid) maxgrid = grid[i][k]; } } } fprintf(stdout,"\n The maximum density is %f %s\n",maxgrid,unit); if (dmax > 0) maxgrid = dmax; snew(tickx,n1+1); snew(tickz,n2+1); if (!bRadial) { /* normalize box-axes */ box1 /= nfr; box2 /= nfr; for (i=0; i<=n1; i++) tickx[i] = i*box1/n1; for (i=0; i<=n2; i++) tickz[i] = i*box2/n2; } else { for (i=0; i<=n1; i++) tickx[i] = i/invspa - amax; if (bMirror) { for (i=0; i<=n2; i++) tickz[i] = i/invspz - rmax; } else { for (i=0; i<=n2; i++) tickz[i] = i/invspz; } } if (bSums) { for (i=0; i<n1; ++i) { fprintf(stdout,"Density sums:\n"); rowsum=0; for (j=0; j<n2; ++j) rowsum+=grid[i][j]; fprintf(stdout,"%g\t",rowsum); } fprintf(stdout,"\n"); } sprintf(buf,"%s number density",grpname[anagrp]); if (!bRadial && (bXmin || bXmax)) { if (!bXmax) sprintf(buf+strlen(buf),", %c > %g nm",eaver[0][0],xmin); else if (!bXmin) sprintf(buf+strlen(buf),", %c < %g nm",eaver[0][0],xmax); else sprintf(buf+strlen(buf),", %c: %g - %g nm",eaver[0][0],xmin,xmax); } if (ftp2bSet(efDAT,NFILE,fnm)) { fp = ffopen(ftp2fn(efDAT,NFILE,fnm),"w"); /*optional text form output: first row is tickz; first col is tickx */ fprintf(fp,"0\t"); for(j=0; j<n2; ++j) fprintf(fp,"%g\t",tickz[j]); fprintf(fp,"\n"); for (i=0; i<n1; ++i) { fprintf(fp,"%g\t",tickx[i]); for (j=0; j<n2; ++j) fprintf(fp,"%g\t",grid[i][j]); fprintf(fp,"\n"); } ffclose(fp); } else { fp = ffopen(ftp2fn(efXPM,NFILE,fnm),"w"); write_xpm(fp,MAT_SPATIAL_X | MAT_SPATIAL_Y,buf,unit, bRadial ? "axial (nm)" : label[c1],bRadial ? "r (nm)" : label[c2], n1,n2,tickx,tickz,grid,dmin,maxgrid,rlo,rhi,&nlev); ffclose(fp); } thanx(stderr); do_view(oenv,opt2fn("-o",NFILE,fnm),NULL); return 0; }
void read_ang_dih(const char *trj_fn, gmx_bool bAngles, gmx_bool bSaveAll, gmx_bool bRb, gmx_bool bPBC, int maxangstat, int angstat[], int *nframes, real **time, int isize, atom_id index[], real **trans_frac, real **aver_angle, real *dih[], const output_env_t oenv) { t_pbc *pbc; t_trxstatus *status; int i, angind, natoms, total, teller; int nangles, n_alloc; real t, fraction, pifac, aa, angle; real *angles[2]; matrix box; rvec *x; int cur = 0; #define prev (1-cur) snew(pbc, 1); natoms = read_first_x(oenv, &status, trj_fn, &t, &x, box); if (bAngles) { nangles = isize/3; pifac = M_PI; } else { nangles = isize/4; pifac = 2.0*M_PI; } snew(angles[cur], nangles); snew(angles[prev], nangles); /* Start the loop over frames */ total = 0; teller = 0; n_alloc = 0; *time = NULL; *trans_frac = NULL; *aver_angle = NULL; do { if (teller >= n_alloc) { n_alloc += 100; if (bSaveAll) { for (i = 0; (i < nangles); i++) { srenew(dih[i], n_alloc); } } srenew(*time, n_alloc); srenew(*trans_frac, n_alloc); srenew(*aver_angle, n_alloc); } (*time)[teller] = t; if (pbc) { set_pbc(pbc, -1, box); } if (bAngles) { calc_angles(pbc, isize, index, angles[cur], x); } else { calc_dihs(pbc, isize, index, angles[cur], x); /* Trans fraction */ fraction = calc_fraction(angles[cur], nangles); (*trans_frac)[teller] = fraction; /* Change Ryckaert-Bellemans dihedrals to polymer convention * Modified 990913 by Erik: * We actually shouldn't change the convention, since it's * calculated from polymer above, but we change the intervall * from [-180,180] to [0,360]. */ if (bRb) { for (i = 0; (i < nangles); i++) { if (angles[cur][i] <= 0.0) { angles[cur][i] += 2*M_PI; } } } /* Periodicity in dihedral space... */ if (bPBC) { for (i = 0; (i < nangles); i++) { real dd = angles[cur][i]; angles[cur][i] = atan2(sin(dd), cos(dd)); } } else { if (teller > 1) { for (i = 0; (i < nangles); i++) { while (angles[cur][i] <= angles[prev][i] - M_PI) { angles[cur][i] += 2*M_PI; } while (angles[cur][i] > angles[prev][i] + M_PI) { angles[cur][i] -= 2*M_PI; } } } } } /* Average angles */ aa = 0; for (i = 0; (i < nangles); i++) { aa = aa+angles[cur][i]; /* angle in rad / 2Pi * max determines bin. bins go from 0 to maxangstat, even though scale goes from -pi to pi (dihedral) or -pi/2 to pi/2 (angle) Basically: translate the x-axis by Pi. Translate it back by -Pi when plotting. */ angle = angles[cur][i]; if (!bAngles) { while (angle < -M_PI) { angle += 2*M_PI; } while (angle >= M_PI) { angle -= 2*M_PI; } angle += M_PI; } /* Update the distribution histogram */ angind = (int) ((angle*maxangstat)/pifac + 0.5); if (angind == maxangstat) { angind = 0; } if ( (angind < 0) || (angind >= maxangstat) ) { /* this will never happen */ gmx_fatal(FARGS, "angle (%f) index out of range (0..%d) : %d\n", angle, maxangstat, angind); } angstat[angind]++; if (angind == maxangstat) { fprintf(stderr, "angle %d fr %d = %g\n", i, cur, angle); } total++; } /* average over all angles */ (*aver_angle)[teller] = (aa/nangles); /* this copies all current dih. angles to dih[i], teller is frame */ if (bSaveAll) { for (i = 0; i < nangles; i++) { dih[i][teller] = angles[cur][i]; } } /* Swap buffers */ cur = prev; /* Increment loop counter */ teller++; } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); sfree(x); sfree(angles[cur]); sfree(angles[prev]); *nframes = teller; }
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; }
gmx_bool constrain(FILE *fplog, gmx_bool bLog, gmx_bool bEner, struct gmx_constr *constr, t_idef *idef, t_inputrec *ir, gmx_ekindata_t *ekind, t_commrec *cr, gmx_int64_t step, int delta_step, t_mdatoms *md, rvec *x, rvec *xprime, rvec *min_proj, gmx_bool bMolPBC, matrix box, real lambda, real *dvdlambda, rvec *v, tensor *vir, t_nrnb *nrnb, int econq, gmx_bool bPscal, real veta, real vetanew) { gmx_bool bOK, bDump; int start, homenr, nrend; int i, j, d; int ncons, settle_error; tensor vir_r_m_dr; rvec *vstor; real invdt, vir_fac, t; t_ilist *settle; int nsettle; t_pbc pbc, *pbc_null; char buf[22]; t_vetavars vetavar; int nth, th; if (econq == econqForceDispl && !EI_ENERGY_MINIMIZATION(ir->eI)) { gmx_incons("constrain called for forces displacements while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted"); } bOK = TRUE; bDump = FALSE; start = 0; homenr = md->homenr; nrend = start+homenr; /* set constants for pressure control integration */ init_vetavars(&vetavar, econq != econqCoord, veta, vetanew, ir, ekind, bPscal); if (ir->delta_t == 0) { invdt = 0; } else { invdt = 1/ir->delta_t; } if (ir->efep != efepNO && EI_DYNAMICS(ir->eI)) { /* Set the constraint lengths for the step at which this configuration * is meant to be. The invmasses should not be changed. */ lambda += delta_step*ir->fepvals->delta_lambda; } if (vir != NULL) { clear_mat(vir_r_m_dr); } where(); settle = &idef->il[F_SETTLE]; nsettle = settle->nr/(1+NRAL(F_SETTLE)); if (nsettle > 0) { nth = gmx_omp_nthreads_get(emntSETTLE); } else { nth = 1; } if (nth > 1 && constr->vir_r_m_dr_th == NULL) { snew(constr->vir_r_m_dr_th, nth); snew(constr->settle_error, nth); } settle_error = -1; /* We do not need full pbc when constraints do not cross charge groups, * i.e. when dd->constraint_comm==NULL. * Note that PBC for constraints is different from PBC for bondeds. * For constraints there is both forward and backward communication. */ if (ir->ePBC != epbcNONE && (cr->dd || bMolPBC) && !(cr->dd && cr->dd->constraint_comm == NULL)) { /* With pbc=screw the screw has been changed to a shift * by the constraint coordinate communication routine, * so that here we can use normal pbc. */ pbc_null = set_pbc_dd(&pbc, ir->ePBC, cr->dd, FALSE, box); } else { pbc_null = NULL; } /* Communicate the coordinates required for the non-local constraints * for LINCS and/or SETTLE. */ if (cr->dd) { dd_move_x_constraints(cr->dd, box, x, xprime, econq == econqCoord); } if (constr->lincsd != NULL) { bOK = constrain_lincs(fplog, bLog, bEner, ir, step, constr->lincsd, md, cr, x, xprime, min_proj, box, pbc_null, lambda, dvdlambda, invdt, v, vir != NULL, vir_r_m_dr, econq, nrnb, constr->maxwarn, &constr->warncount_lincs); if (!bOK && constr->maxwarn >= 0) { if (fplog != NULL) { fprintf(fplog, "Constraint error in algorithm %s at step %s\n", econstr_names[econtLINCS], gmx_step_str(step, buf)); } bDump = TRUE; } } if (constr->nblocks > 0) { switch (econq) { case (econqCoord): bOK = bshakef(fplog, constr->shaked, md->invmass, constr->nblocks, constr->sblock, idef, ir, x, xprime, nrnb, constr->lagr, lambda, dvdlambda, invdt, v, vir != NULL, vir_r_m_dr, constr->maxwarn >= 0, econq, &vetavar); break; case (econqVeloc): bOK = bshakef(fplog, constr->shaked, md->invmass, constr->nblocks, constr->sblock, idef, ir, x, min_proj, nrnb, constr->lagr, lambda, dvdlambda, invdt, NULL, vir != NULL, vir_r_m_dr, constr->maxwarn >= 0, econq, &vetavar); break; default: gmx_fatal(FARGS, "Internal error, SHAKE called for constraining something else than coordinates"); break; } if (!bOK && constr->maxwarn >= 0) { if (fplog != NULL) { fprintf(fplog, "Constraint error in algorithm %s at step %s\n", econstr_names[econtSHAKE], gmx_step_str(step, buf)); } bDump = TRUE; } } if (nsettle > 0) { int calcvir_atom_end; if (vir == NULL) { calcvir_atom_end = 0; } else { calcvir_atom_end = md->homenr; } switch (econq) { case econqCoord: #pragma omp parallel for num_threads(nth) schedule(static) for (th = 0; th < nth; th++) { int start_th, end_th; if (th > 0) { clear_mat(constr->vir_r_m_dr_th[th]); } start_th = (nsettle* th )/nth; end_th = (nsettle*(th+1))/nth; if (start_th >= 0 && end_th - start_th > 0) { csettle(constr->settled, end_th-start_th, settle->iatoms+start_th*(1+NRAL(F_SETTLE)), pbc_null, x[0], xprime[0], invdt, v ? v[0] : NULL, calcvir_atom_end, th == 0 ? vir_r_m_dr : constr->vir_r_m_dr_th[th], th == 0 ? &settle_error : &constr->settle_error[th], &vetavar); } } inc_nrnb(nrnb, eNR_SETTLE, nsettle); if (v != NULL) { inc_nrnb(nrnb, eNR_CONSTR_V, nsettle*3); } if (vir != NULL) { inc_nrnb(nrnb, eNR_CONSTR_VIR, nsettle*3); } break; case econqVeloc: case econqDeriv: case econqForce: case econqForceDispl: #pragma omp parallel for num_threads(nth) schedule(static) for (th = 0; th < nth; th++) { int start_th, end_th; if (th > 0) { clear_mat(constr->vir_r_m_dr_th[th]); } start_th = (nsettle* th )/nth; end_th = (nsettle*(th+1))/nth; if (start_th >= 0 && end_th - start_th > 0) { settle_proj(constr->settled, econq, end_th-start_th, settle->iatoms+start_th*(1+NRAL(F_SETTLE)), pbc_null, x, xprime, min_proj, calcvir_atom_end, th == 0 ? vir_r_m_dr : constr->vir_r_m_dr_th[th], &vetavar); } } /* This is an overestimate */ inc_nrnb(nrnb, eNR_SETTLE, nsettle); break; case econqDeriv_FlexCon: /* Nothing to do, since the are no flexible constraints in settles */ break; default: gmx_incons("Unknown constraint quantity for settle"); } } if (settle->nr > 0) { /* Combine virial and error info of the other threads */ for (i = 1; i < nth; i++) { m_add(vir_r_m_dr, constr->vir_r_m_dr_th[i], vir_r_m_dr); settle_error = constr->settle_error[i]; } if (econq == econqCoord && settle_error >= 0) { bOK = FALSE; if (constr->maxwarn >= 0) { char buf[256]; sprintf(buf, "\nstep " "%"GMX_PRId64 ": Water molecule starting at atom %d can not be " "settled.\nCheck for bad contacts and/or reduce the timestep if appropriate.\n", step, ddglatnr(cr->dd, settle->iatoms[settle_error*(1+NRAL(F_SETTLE))+1])); if (fplog) { fprintf(fplog, "%s", buf); } fprintf(stderr, "%s", buf); constr->warncount_settle++; if (constr->warncount_settle > constr->maxwarn) { too_many_constraint_warnings(-1, constr->warncount_settle); } bDump = TRUE; } } } free_vetavars(&vetavar); if (vir != NULL) { switch (econq) { case econqCoord: vir_fac = 0.5/(ir->delta_t*ir->delta_t); break; case econqVeloc: vir_fac = 0.5/ir->delta_t; break; case econqForce: case econqForceDispl: vir_fac = 0.5; break; default: vir_fac = 0; gmx_incons("Unsupported constraint quantity for virial"); } if (EI_VV(ir->eI)) { vir_fac *= 2; /* only constraining over half the distance here */ } for (i = 0; i < DIM; i++) { for (j = 0; j < DIM; j++) { (*vir)[i][j] = vir_fac*vir_r_m_dr[i][j]; } } } if (bDump) { dump_confs(fplog, step, constr->warn_mtop, start, homenr, cr, x, xprime, box); } if (econq == econqCoord) { if (ir->ePull == epullCONSTRAINT) { if (EI_DYNAMICS(ir->eI)) { t = ir->init_t + (step + delta_step)*ir->delta_t; } else { t = ir->init_t; } set_pbc(&pbc, ir->ePBC, box); pull_constraint(ir->pull, md, &pbc, cr, ir->delta_t, t, x, xprime, v, *vir); } if (constr->ed && delta_step > 0) { /* apply the essential dynamcs constraints here */ do_edsam(ir, step, cr, xprime, v, box, constr->ed); } } return bOK; }
void orient(int natom,rvec *x,rvec *v, rvec angle,matrix box) { real longest,rij,rzi; int i,j,m,max_i=0,max_j=0; rvec origin; int temp; real alfa=0,beta=0,gamma=0; t_pbc pbc; set_pbc(&pbc,-1,box); /*first i am going to look for the longest atom-atom distance*/ longest=dist2(&pbc,x[0],x[1]); i=0; j=1; for (i=0;(i<natom);i++) { for (j=0;(j<natom);j++) { rij=dist2(&pbc,x[i],x[j]); if (rij>longest) { max_i=i; max_j=j; longest=rij; } } } /* first check if x[max_i]<x[max_j] else swap*/ if (x[max_i][2]>x[max_j][2]) { temp=max_i; max_i=max_j; max_j=temp; } /*set the origin to x[i]*/ for(m=0;(m<DIM);m++) origin[m]=x[max_i][m]; for(i=0;(i<natom);i++) for(m=0;(m<DIM);m++) x[i][m]-=origin[m]; /* calculate the rotation angles alfa(x_axis) and beta(y_axis) * the rotation angles must be calculated clockwise looking * along the rotation axis to the origin* * alfa (x-axis) */ alfa=atan(x[max_j][ZZ]/x[max_j][YY])-M_PI_2; beta=M_PI_2-atan(x[max_j][ZZ]/x[max_j][XX]); rotate_conf(natom,x,v,alfa,beta,gamma); /* now search the longest distance for rotation along the z_axis */ longest=distance_to_z(x[0]); max_i=0; for (i=1;(i<natom);i++) { rzi=distance_to_z(x[i]); if (rzi>longest) { longest = rzi; max_i=i; } } gamma=atan(x[max_i][YY]/x[max_i][XX])-M_PI_2; rotate_conf(natom,x,v,0,0,gamma); angle[0]=alfa; angle[1]=beta; angle[2]=gamma; } /*orient()*/
void do_force_lowlevel(t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_localtop_t *top, gmx_genborn_t *born, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j; int donb_flags; gmx_bool bSB; int pme_flags; matrix boxs; rvec box_size; t_pbc pbc; real dvdl_dum[efptNR], dvdl_nb[efptNR]; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr); } /* Call the short range functions all in one go. */ #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ real dvdl_walls = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); enerd->dvdl_lin[efptVDW] += dvdl_walls; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; /* Currently all group scheme kernels always calculate (shift-)forces */ if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_VIRIAL) { donb_flags |= GMX_NONBONDED_DO_SHIFTFORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(fr, x, f, f_longrange, md, excl, &enerd->grpp, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { real lam_i[efptNR]; for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsLISTED); calc_gb_forces(cr, md, born, top, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsLISTED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } debug_gmx(); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before listed forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no listed forces have to be evaluated. * * The shifting and PBC code is deliberately not timed, since with * the Verlet scheme it only takes non-zero time with triclinic * boxes, and even then the time is around a factor of 100 less * than the next smallest counter. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do listed interactions or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_LISTED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype))) { /* TODO There are no electrostatics methods that require this transformation, when using the Verlet scheme, so update the above conditional. */ /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); do_force_listed(wcycle, box, ir->fepvals, cr->ms, idef, (const rvec *) x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, flags); where(); *cycles_pme = 0; clear_mat(fr->vir_el_recip); clear_mat(fr->vir_lj_recip); /* Do long-range electrostatics and/or LJ-PME, including related short-range * corrections. */ if (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype)) { int status = 0; real Vlr_q = 0, Vlr_lj = 0, Vcorr_q = 0, Vcorr_lj = 0; real dvdl_long_range_q = 0, dvdl_long_range_lj = 0; bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } if (EEL_PME_EWALD(fr->eeltype) || EVDW_PME(fr->vdwtype)) { real dvdl_long_range_correction_q = 0; real dvdl_long_range_correction_lj = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid * contributions will be calculated in * gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = fr->nthread_ewc; #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { try { tensor *vir_q, *vir_lj; real *Vcorrt_q, *Vcorrt_lj, *dvdlt_q, *dvdlt_lj; if (t == 0) { vir_q = &fr->vir_el_recip; vir_lj = &fr->vir_lj_recip; Vcorrt_q = &Vcorr_q; Vcorrt_lj = &Vcorr_lj; dvdlt_q = &dvdl_long_range_correction_q; dvdlt_lj = &dvdl_long_range_correction_lj; } else { vir_q = &fr->ewc_t[t].vir_q; vir_lj = &fr->ewc_t[t].vir_lj; Vcorrt_q = &fr->ewc_t[t].Vcorr_q; Vcorrt_lj = &fr->ewc_t[t].Vcorr_lj; dvdlt_q = &fr->ewc_t[t].dvdl[efptCOUL]; dvdlt_lj = &fr->ewc_t[t].dvdl[efptVDW]; clear_mat(*vir_q); clear_mat(*vir_lj); } *dvdlt_q = 0; *dvdlt_lj = 0; /* Threading is only supported with the Verlet cut-off * scheme and then only single particle forces (no * exclusion forces) are calculated, so we can store * the forces in the normal, single fr->f_novirsum array. */ ewald_LRcorrection(fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->chargeB, md->sqrt_c6A, md->sqrt_c6B, md->sigmaA, md->sigmaB, md->sigma3A, md->sigma3B, md->nChargePerturbed || md->nTypePerturbed, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fr->f_novirsum, *vir_q, *vir_lj, Vcorrt_q, Vcorrt_lj, lambda[efptCOUL], lambda[efptVDW], dvdlt_q, dvdlt_lj); } GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR; } if (nthreads > 1) { reduce_thread_energies(fr->vir_el_recip, fr->vir_lj_recip, &Vcorr_q, &Vcorr_lj, &dvdl_long_range_correction_q, &dvdl_long_range_correction_lj, nthreads, fr->ewc_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); }
int gmx_spatial(int argc,char *argv[]) { const char *desc[] = { "g_spatial calculates the spatial distribution function and ", "outputs it in a form that can be read by VMD as Gaussian98 cube format. ", "This was developed from template.c (gromacs-3.3). ", "For a system of 32K atoms and a 50ns trajectory, the SDF can be generated ", "in about 30 minutes, with most of the time dedicated to the two runs through ", "trjconv that are required to center everything properly. ", "This also takes a whole bunch of space (3 copies of the xtc file). ", "Still, the pictures are pretty and very informative when the fitted selection is properly made. ", "3-4 atoms in a widely mobile group like a free amino acid in solution works ", "well, or select the protein backbone in a stable folded structure to get the SDF ", "of solvent and look at the time-averaged solvation shell. ", "It is also possible using this program to generate the SDF based on some arbitrarty ", "Cartesian coordinate. To do that, simply omit the preliminary trjconv steps. \n", "USAGE: \n", "1. Use make_ndx to create a group containing the atoms around which you want the SDF \n", "2. trjconv -s a.tpr -f a.xtc -o b.xtc -center tric -ur compact -pbc none \n", "3. trjconv -s a.tpr -f b.xtc -o c.xtc -fit rot+trans \n", "4. run g_spatial on the xtc output of step #3. \n", "5. Load grid.cube into VMD and view as an isosurface. \n", "*** Systems such as micelles will require trjconv -pbc cluster between steps 1 and 2\n", "WARNINGS: \n", "The SDF will be generated for a cube that contains all bins that have some non-zero occupancy. ", "However, the preparatory -fit rot+trans option to trjconv implies that your system will be rotating ", "and translating in space (in order that the selected group does not). Therefore the values that are ", "returned will only be valid for some region around your central group/coordinate that has full overlap ", "with system volume throughout the entire translated/rotated system over the course of the trajectory. ", "It is up to the user to ensure that this is the case. \n", "BUGS: \n", "When the allocated memory is not large enough, a segmentation fault may occur. This is usually detected ", "and the program is halted prior to the fault while displaying a warning message suggesting the use of the -nab ", "option. However, the program does not detect all such events. If you encounter a segmentation fault, run it again ", "with an increased -nab value. \n", "RISKY OPTIONS: \n", "To reduce the amount of space and time required, you can output only the coords ", "that are going to be used in the first and subsequent run through trjconv. ", "However, be sure to set the -nab option to a sufficiently high value since ", "memory is allocated for cube bins based on the initial coords and the -nab ", "(Number of Additional Bins) option value. \n" }; static gmx_bool bPBC=FALSE; static gmx_bool bSHIFT=FALSE; static int iIGNOREOUTER=-1; /*Positive values may help if the surface is spikey */ static gmx_bool bCUTDOWN=TRUE; static real rBINWIDTH=0.05; /* nm */ static gmx_bool bCALCDIV=TRUE; static int iNAB=4; t_pargs pa[] = { { "-pbc", FALSE, etBOOL, {&bPBC}, "Use periodic boundary conditions for computing distances" }, { "-div", FALSE, etBOOL, {&bCALCDIV}, "Calculate and apply the divisor for bin occupancies based on atoms/minimal cube size. Set as TRUE for visualization and as FALSE (-nodiv) to get accurate counts per frame" }, { "-ign", FALSE, etINT, {&iIGNOREOUTER}, "Do not display this number of outer cubes (positive values may reduce boundary speckles; -1 ensures outer surface is visible)" }, /* { "-cut", bCUTDOWN, etBOOL, {&bCUTDOWN},*/ /* "Display a total cube that is of minimal size" }, */ { "-bin", FALSE, etREAL, {&rBINWIDTH}, "Width of the bins in nm" }, { "-nab", FALSE, etINT, {&iNAB}, "Number of additional bins to ensure proper memory allocation" } }; double MINBIN[3]; double MAXBIN[3]; t_topology top; int ePBC; char title[STRLEN]; t_trxframe fr; rvec *xtop,*shx[26]; matrix box,box_pbc; t_trxstatus *status; int flags = TRX_READ_X; t_pbc pbc; t_atoms *atoms; int natoms; char *grpnm,*grpnmp; atom_id *index,*indexp; int i,nidx,nidxp; int v; int j,k; long ***bin=(long ***)NULL; long nbin[3]; FILE *flp; long x,y,z,minx,miny,minz,maxx,maxy,maxz; long numfr, numcu; long tot,max,min; double norm; output_env_t oenv; gmx_rmpbc_t gpbc=NULL; t_filenm fnm[] = { { efTPS, NULL, NULL, ffREAD }, /* this is for the topology */ { efTRX, "-f", NULL, ffREAD }, /* and this for the trajectory */ { efNDX, NULL, NULL, ffOPTRD } }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); /* This is the routine responsible for adding default options, * calling the X/motif interface, etc. */ parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xtop,NULL,box,TRUE); sfree(xtop); atoms=&(top.atoms); printf("Select group to generate SDF:\n"); get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&nidx,&index,&grpnm); printf("Select group to output coords (e.g. solute):\n"); get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&nidxp,&indexp,&grpnmp); /* The first time we read data is a little special */ natoms=read_first_frame(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&fr,flags); /* Memory Allocation */ MINBIN[XX]=MAXBIN[XX]=fr.x[0][XX]; MINBIN[YY]=MAXBIN[YY]=fr.x[0][YY]; MINBIN[ZZ]=MAXBIN[ZZ]=fr.x[0][ZZ]; for(i=1; i<top.atoms.nr; ++i) { if(fr.x[i][XX]<MINBIN[XX])MINBIN[XX]=fr.x[i][XX]; if(fr.x[i][XX]>MAXBIN[XX])MAXBIN[XX]=fr.x[i][XX]; if(fr.x[i][YY]<MINBIN[YY])MINBIN[YY]=fr.x[i][YY]; if(fr.x[i][YY]>MAXBIN[YY])MAXBIN[YY]=fr.x[i][YY]; if(fr.x[i][ZZ]<MINBIN[ZZ])MINBIN[ZZ]=fr.x[i][ZZ]; if(fr.x[i][ZZ]>MAXBIN[ZZ])MAXBIN[ZZ]=fr.x[i][ZZ]; } for (i=ZZ; i>=XX; --i){ MAXBIN[i]=(ceil((MAXBIN[i]-MINBIN[i])/rBINWIDTH)+(double)iNAB)*rBINWIDTH+MINBIN[i]; MINBIN[i]-=(double)iNAB*rBINWIDTH; nbin[i]=(long)ceil((MAXBIN[i]-MINBIN[i])/rBINWIDTH); } bin=(long ***)malloc(nbin[XX]*sizeof(long **)); if(!bin)mequit(); for(i=0; i<nbin[XX]; ++i){ bin[i]=(long **)malloc(nbin[YY]*sizeof(long *)); if(!bin[i])mequit(); for(j=0; j<nbin[YY]; ++j){ bin[i][j]=(long *)calloc(nbin[ZZ],sizeof(long)); if(!bin[i][j])mequit(); } } copy_mat(box,box_pbc); numfr=0; minx=miny=minz=999; maxx=maxy=maxz=0; if (bPBC) gpbc = gmx_rmpbc_init(&top.idef,ePBC,natoms,box); /* This is the main loop over frames */ do { /* Must init pbc every step because of pressure coupling */ copy_mat(box,box_pbc); if (bPBC) { gmx_rmpbc_trxfr(gpbc,&fr); set_pbc(&pbc,ePBC,box_pbc); } for(i=0; i<nidx; i++) { if(fr.x[index[i]][XX]<MINBIN[XX]||fr.x[index[i]][XX]>MAXBIN[XX]|| fr.x[index[i]][YY]<MINBIN[YY]||fr.x[index[i]][YY]>MAXBIN[YY]|| fr.x[index[i]][ZZ]<MINBIN[ZZ]||fr.x[index[i]][ZZ]>MAXBIN[ZZ]) { printf("There was an item outside of the allocated memory. Increase the value given with the -nab option.\n"); printf("Memory was allocated for [%f,%f,%f]\tto\t[%f,%f,%f]\n",MINBIN[XX],MINBIN[YY],MINBIN[ZZ],MAXBIN[XX],MAXBIN[YY],MAXBIN[ZZ]); printf("Memory was required for [%f,%f,%f]\n",fr.x[index[i]][XX],fr.x[index[i]][YY],fr.x[index[i]][ZZ]); exit(1); } x=(long)ceil((fr.x[index[i]][XX]-MINBIN[XX])/rBINWIDTH); y=(long)ceil((fr.x[index[i]][YY]-MINBIN[YY])/rBINWIDTH); z=(long)ceil((fr.x[index[i]][ZZ]-MINBIN[ZZ])/rBINWIDTH); ++bin[x][y][z]; if(x<minx)minx=x; if(x>maxx)maxx=x; if(y<miny)miny=y; if(y>maxy)maxy=y; if(z<minz)minz=z; if(z>maxz)maxz=z; } numfr++; /* printf("%f\t%f\t%f\n",box[XX][XX],box[YY][YY],box[ZZ][ZZ]); */ } while(read_next_frame(oenv,status,&fr)); if (bPBC) gmx_rmpbc_done(gpbc); if(!bCUTDOWN){ minx=miny=minz=0; maxx=nbin[XX]; maxy=nbin[YY]; maxz=nbin[ZZ]; } /* OUTPUT */ flp=ffopen("grid.cube","w"); fprintf(flp,"Spatial Distribution Function\n"); fprintf(flp,"test\n"); fprintf(flp,"%5d%12.6f%12.6f%12.6f\n",nidxp,(MINBIN[XX]+(minx+iIGNOREOUTER)*rBINWIDTH)*10./bohr,(MINBIN[YY]+(miny+iIGNOREOUTER)*rBINWIDTH)*10./bohr,(MINBIN[ZZ]+(minz+iIGNOREOUTER)*rBINWIDTH)*10./bohr); fprintf(flp,"%5ld%12.6f%12.6f%12.6f\n",maxx-minx+1-(2*iIGNOREOUTER),rBINWIDTH*10./bohr,0.,0.); fprintf(flp,"%5ld%12.6f%12.6f%12.6f\n",maxy-miny+1-(2*iIGNOREOUTER),0.,rBINWIDTH*10./bohr,0.); fprintf(flp,"%5ld%12.6f%12.6f%12.6f\n",maxz-minz+1-(2*iIGNOREOUTER),0.,0.,rBINWIDTH*10./bohr); for(i=0; i<nidxp; i++){ v=2; if(*(top.atoms.atomname[indexp[i]][0])=='C')v=6; if(*(top.atoms.atomname[indexp[i]][0])=='N')v=7; if(*(top.atoms.atomname[indexp[i]][0])=='O')v=8; if(*(top.atoms.atomname[indexp[i]][0])=='H')v=1; if(*(top.atoms.atomname[indexp[i]][0])=='S')v=16; fprintf(flp,"%5d%12.6f%12.6f%12.6f%12.6f\n",v,0.,(double)fr.x[indexp[i]][XX]*10./bohr,(double)fr.x[indexp[i]][YY]*10./bohr,(double)fr.x[indexp[i]][ZZ]*10./bohr); } tot=0; for(k=0;k<nbin[XX];k++) { if(!(k<minx||k>maxx))continue; for(j=0;j<nbin[YY];j++) { if(!(j<miny||j>maxy))continue; for(i=0;i<nbin[ZZ];i++) { if(!(i<minz||i>maxz))continue; if(bin[k][j][i]!=0){ printf("A bin was not empty when it should have been empty. Programming error.\n"); printf("bin[%d][%d][%d] was = %ld\n",k,j,i,bin[k][j][i]); exit(1); } } } } min=999; max=0; for(k=0;k<nbin[XX];k++) { if(k<minx+iIGNOREOUTER||k>maxx-iIGNOREOUTER)continue; for(j=0;j<nbin[YY];j++) { if(j<miny+iIGNOREOUTER||j>maxy-iIGNOREOUTER)continue; for(i=0;i<nbin[ZZ];i++) { if(i<minz+iIGNOREOUTER||i>maxz-iIGNOREOUTER)continue; tot+=bin[k][j][i]; if(bin[k][j][i]>max)max=bin[k][j][i]; if(bin[k][j][i]<min)min=bin[k][j][i]; } } } numcu=(maxx-minx+1-(2*iIGNOREOUTER))*(maxy-miny+1-(2*iIGNOREOUTER))*(maxz-minz+1-(2*iIGNOREOUTER)); if(bCALCDIV){ norm=((double)numcu*(double)numfr) / (double)tot; }else{ norm=1.0; } for(k=0;k<nbin[XX];k++) { if(k<minx+iIGNOREOUTER||k>maxx-iIGNOREOUTER)continue; for(j=0;j<nbin[YY];j++) { if(j<miny+iIGNOREOUTER||j>maxy-iIGNOREOUTER)continue; for(i=0;i<nbin[ZZ];i++) { if(i<minz+iIGNOREOUTER||i>maxz-iIGNOREOUTER)continue; fprintf(flp,"%12.6f ",norm*(double)bin[k][j][i]/(double)numfr); } fprintf(flp,"\n"); } fprintf(flp,"\n"); } ffclose(flp); /* printf("x=%d to %d\n",minx,maxx); */ /* printf("y=%d to %d\n",miny,maxy); */ /* printf("z=%d to %d\n",minz,maxz); */ if(bCALCDIV){ printf("Counts per frame in all %ld cubes divided by %le\n",numcu,1.0/norm); printf("Normalized data: average %le, min %le, max %le\n",1.0,norm*(double)min/(double)numfr,norm*(double)max/(double)numfr); }else{ printf("grid.cube contains counts per frame in all %ld cubes\n",numcu); printf("Raw data: average %le, min %le, max %le\n",1.0/norm,(double)min/(double)numfr,(double)max/(double)numfr); } thanx(stderr); return 0; }
static char *insert_mols(char *mol_insrt,int nmol_insrt,int ntry,int seed, t_atoms *atoms,rvec **x,real **r,int ePBC,matrix box, gmx_atomprop_t aps,real r_distance,real rshell) { t_pbc pbc; static char *title_insrt; t_atoms atoms_insrt; rvec *x_insrt,*x_n; real *r_insrt; int ePBC_insrt; matrix box_insrt; int i,mol,onr; real alfa,beta,gamma; rvec offset_x; int try; set_pbc(&pbc,ePBC,box); /* read number of atoms of insert molecules */ get_stx_coordnum(mol_insrt,&atoms_insrt.nr); if (atoms_insrt.nr == 0) gmx_fatal(FARGS,"No molecule in %s, please check your input\n",mol_insrt); /* allocate memory for atom coordinates of insert molecules */ snew(x_insrt,atoms_insrt.nr); snew(r_insrt,atoms_insrt.nr); snew(atoms_insrt.resname,atoms_insrt.nr); snew(atoms_insrt.atomname,atoms_insrt.nr); snew(atoms_insrt.atom,atoms_insrt.nr); atoms_insrt.pdbinfo = NULL; snew(x_n,atoms_insrt.nr); snew(title_insrt,STRLEN); /* read residue number, residue names, atomnames, coordinates etc. */ fprintf(stderr,"Reading molecule configuration \n"); read_stx_conf(mol_insrt,title_insrt,&atoms_insrt,x_insrt,NULL, &ePBC_insrt,box_insrt); fprintf(stderr,"%s\nContaining %d atoms in %d residue\n", title_insrt,atoms_insrt.nr,atoms_insrt.nres); srenew(atoms_insrt.resname,atoms_insrt.nres); /* initialise van der waals arrays of insert molecules */ mk_vdw(&atoms_insrt,r_insrt,aps,r_distance); srenew(atoms->resname,(atoms->nres+nmol_insrt)); srenew(atoms->atomname,(atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(atoms->atom,(atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*x,(atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*r,(atoms->nr+atoms_insrt.nr*nmol_insrt)); try=mol=0; while ((mol < nmol_insrt) && (try < ntry*nmol_insrt)) { fprintf(stderr,"\rTry %d",try++); for (i=0;(i<atoms_insrt.nr);i++) { if (atoms_insrt.atom[i].resnr!=0) gmx_fatal(FARGS,"more then one residue in insert molecules\n" "program terminated\n"); copy_rvec(x_insrt[i],x_n[i]); } alfa=2*M_PI*rando(&seed); beta=2*M_PI*rando(&seed); gamma=2*M_PI*rando(&seed); rotate_conf(atoms_insrt.nr,x_n,NULL,alfa,beta,gamma); offset_x[XX]=box[XX][XX]*rando(&seed); offset_x[YY]=box[YY][YY]*rando(&seed); offset_x[ZZ]=box[ZZ][ZZ]*rando(&seed); gen_box(0,atoms_insrt.nr,x_n,box_insrt,offset_x,TRUE); if (!in_box(&pbc,x_n[0]) || !in_box(&pbc,x_n[atoms_insrt.nr-1])) continue; onr=atoms->nr; add_conf(atoms,x,NULL,r,FALSE,ePBC,box,TRUE, &atoms_insrt,x_n,NULL,r_insrt,FALSE,rshell,0); if (atoms->nr==(atoms_insrt.nr+onr)) { mol++; fprintf(stderr," success (now %d atoms)!",atoms->nr); } } srenew(atoms->resname, atoms->nres); srenew(atoms->atomname, atoms->nr); srenew(atoms->atom, atoms->nr); srenew(*x, atoms->nr); srenew(*r, atoms->nr); fprintf(stderr,"\n"); /* print number of molecules added */ fprintf(stderr,"Added %d molecules (out of %d requested) of %s\n", mol,nmol_insrt,*atoms_insrt.resname[0]); return title_insrt; } static void add_solv(char *fn,t_atoms *atoms,rvec **x,rvec **v,real **r, int ePBC,matrix box, gmx_atomprop_t aps,real r_distance,int *atoms_added, int *residues_added,real rshell,int max_sol) { int i,nmol; ivec n_box; char filename[STRLEN]; char title_solvt[STRLEN]; t_atoms *atoms_solvt; rvec *x_solvt,*v_solvt=NULL; real *r_solvt; int ePBC_solvt; matrix box_solvt; int onr,onres; strncpy(filename,libfn(fn),STRLEN); snew(atoms_solvt,1); get_stx_coordnum(filename,&(atoms_solvt->nr)); if (atoms_solvt->nr == 0) gmx_fatal(FARGS,"No solvent in %s, please check your input\n",filename); snew(x_solvt,atoms_solvt->nr); if (v) snew(v_solvt,atoms_solvt->nr); snew(r_solvt,atoms_solvt->nr); snew(atoms_solvt->resname,atoms_solvt->nr); snew(atoms_solvt->atomname,atoms_solvt->nr); snew(atoms_solvt->atom,atoms_solvt->nr); atoms_solvt->pdbinfo = NULL; fprintf(stderr,"Reading solvent configuration%s\n", v_solvt?" and velocities":""); read_stx_conf(filename,title_solvt,atoms_solvt,x_solvt,v_solvt, &ePBC_solvt,box_solvt); fprintf(stderr,"\"%s\"\n",title_solvt); fprintf(stderr,"solvent configuration contains %d atoms in %d residues\n", atoms_solvt->nr,atoms_solvt->nres); fprintf(stderr,"\n"); /* apply pbc for solvent configuration for whole molecules */ rm_res_pbc(atoms_solvt,x_solvt,box_solvt); /* initialise van der waals arrays of solvent configuration */ mk_vdw(atoms_solvt,r_solvt,aps,r_distance); /* calculate the box multiplication factors n_box[0...DIM] */ nmol=1; for (i=0; (i < DIM);i++) { n_box[i] = 1; while (n_box[i]*box_solvt[i][i] < box[i][i]) n_box[i]++; nmol*=n_box[i]; } fprintf(stderr,"Will generate new solvent configuration of %dx%dx%d boxes\n", n_box[XX],n_box[YY],n_box[ZZ]); /* realloc atoms_solvt for the new solvent configuration */ srenew(atoms_solvt->resname,atoms_solvt->nres*nmol); srenew(atoms_solvt->atomname,atoms_solvt->nr*nmol); srenew(atoms_solvt->atom,atoms_solvt->nr*nmol); srenew(x_solvt,atoms_solvt->nr*nmol); if (v_solvt) srenew(v_solvt,atoms_solvt->nr*nmol); srenew(r_solvt,atoms_solvt->nr*nmol); /* generate a new solvent configuration */ genconf(atoms_solvt,x_solvt,v_solvt,r_solvt,box_solvt,n_box); #ifdef DEBUG print_stat(x_solvt,atoms_solvt->nr,box_solvt); #endif #ifdef DEBUG print_stat(x_solvt,atoms_solvt->nr,box_solvt); #endif /* Sort the solvent mixture, not the protein... */ sort_molecule(&atoms_solvt,x_solvt,v_solvt,r_solvt); /* add the two configurations */ onr=atoms->nr; onres=atoms->nres; add_conf(atoms,x,v,r,TRUE,ePBC,box,FALSE, atoms_solvt,x_solvt,v_solvt,r_solvt,TRUE,rshell,max_sol); *atoms_added=atoms->nr-onr; *residues_added=atoms->nres-onres; sfree(x_solvt); sfree(r_solvt); fprintf(stderr,"Generated solvent containing %d atoms in %d residues\n", *atoms_added,*residues_added); }
void chk_tps(const char *fn, real vdw_fac, real bon_lo, real bon_hi) { int natom, i, j, k; char title[STRLEN]; t_topology top; int ePBC; t_atoms *atoms; rvec *x, *v; rvec dx; matrix box; t_pbc pbc; gmx_bool bV, bX, bB, bFirst, bOut; real r2, ekin, temp1, temp2, dist2, vdwfac2, bonlo2, bonhi2; real *atom_vdw; gmx_atomprop_t aps; fprintf(stderr, "Checking coordinate file %s\n", fn); read_tps_conf(fn, title, &top, &ePBC, &x, &v, box, TRUE); atoms = &top.atoms; natom = atoms->nr; fprintf(stderr, "%d atoms in file\n", atoms->nr); /* check coordinates and box */ bV = FALSE; bX = FALSE; for (i = 0; (i < natom) && !(bV && bX); i++) { for (j = 0; (j < DIM) && !(bV && bX); j++) { bV = bV || (v[i][j] != 0); bX = bX || (x[i][j] != 0); } } bB = FALSE; for (i = 0; (i < DIM) && !bB; i++) { for (j = 0; (j < DIM) && !bB; j++) { bB = bB || (box[i][j] != 0); } } fprintf(stderr, "coordinates %s\n", bX ? "found" : "absent"); fprintf(stderr, "box %s\n", bB ? "found" : "absent"); fprintf(stderr, "velocities %s\n", bV ? "found" : "absent"); fprintf(stderr, "\n"); /* check velocities */ if (bV) { ekin = 0.0; for (i = 0; (i < natom); i++) { for (j = 0; (j < DIM); j++) { ekin += 0.5*atoms->atom[i].m*v[i][j]*v[i][j]; } } temp1 = (2.0*ekin)/(natom*DIM*BOLTZ); temp2 = (2.0*ekin)/(natom*(DIM-1)*BOLTZ); fprintf(stderr, "Kinetic energy: %g (kJ/mol)\n", ekin); fprintf(stderr, "Assuming the number of degrees of freedom to be " "Natoms * %d or Natoms * %d,\n" "the velocities correspond to a temperature of the system\n" "of %g K or %g K respectively.\n\n", DIM, DIM-1, temp1, temp2); } /* check coordinates */ if (bX) { vdwfac2 = sqr(vdw_fac); bonlo2 = sqr(bon_lo); bonhi2 = sqr(bon_hi); fprintf(stderr, "Checking for atoms closer than %g and not between %g and %g,\n" "relative to sum of Van der Waals distance:\n", vdw_fac, bon_lo, bon_hi); snew(atom_vdw, natom); aps = gmx_atomprop_init(); for (i = 0; (i < natom); i++) { gmx_atomprop_query(aps, epropVDW, *(atoms->resinfo[atoms->atom[i].resind].name), *(atoms->atomname[i]), &(atom_vdw[i])); if (debug) { fprintf(debug, "%5d %4s %4s %7g\n", i+1, *(atoms->resinfo[atoms->atom[i].resind].name), *(atoms->atomname[i]), atom_vdw[i]); } } gmx_atomprop_destroy(aps); if (bB) { set_pbc(&pbc, ePBC, box); } bFirst = TRUE; for (i = 0; (i < natom); i++) { if (((i+1)%10) == 0) { fprintf(stderr, "\r%5d", i+1); } for (j = i+1; (j < natom); j++) { if (bB) { pbc_dx(&pbc, x[i], x[j], dx); } else { rvec_sub(x[i], x[j], dx); } r2 = iprod(dx, dx); dist2 = sqr(atom_vdw[i]+atom_vdw[j]); if ( (r2 <= dist2*bonlo2) || ( (r2 >= dist2*bonhi2) && (r2 <= dist2*vdwfac2) ) ) { if (bFirst) { fprintf(stderr, "\r%5s %4s %8s %5s %5s %4s %8s %5s %6s\n", "atom#", "name", "residue", "r_vdw", "atom#", "name", "residue", "r_vdw", "distance"); bFirst = FALSE; } fprintf(stderr, "\r%5d %4s %4s%4d %-5.3g %5d %4s %4s%4d %-5.3g %-6.4g\n", i+1, *(atoms->atomname[i]), *(atoms->resinfo[atoms->atom[i].resind].name), atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i], j+1, *(atoms->atomname[j]), *(atoms->resinfo[atoms->atom[j].resind].name), atoms->resinfo[atoms->atom[j].resind].nr, atom_vdw[j], sqrt(r2) ); } } } if (bFirst) { fprintf(stderr, "\rno close atoms found\n"); } fprintf(stderr, "\r \n"); if (bB) { /* check box */ bFirst = TRUE; k = 0; for (i = 0; (i < natom) && (k < 10); i++) { bOut = FALSE; for (j = 0; (j < DIM) && !bOut; j++) { bOut = bOut || (x[i][j] < 0) || (x[i][j] > box[j][j]); } if (bOut) { k++; if (bFirst) { fprintf(stderr, "Atoms outside box ( "); for (j = 0; (j < DIM); j++) { fprintf(stderr, "%g ", box[j][j]); } fprintf(stderr, "):\n" "(These may occur often and are normally not a problem)\n" "%5s %4s %8s %5s %s\n", "atom#", "name", "residue", "r_vdw", "coordinate"); bFirst = FALSE; } fprintf(stderr, "%5d %4s %4s%4d %-5.3g", i, *(atoms->atomname[i]), *(atoms->resinfo[atoms->atom[i].resind].name), atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i]); for (j = 0; (j < DIM); j++) { fprintf(stderr, " %6.3g", x[i][j]); } fprintf(stderr, "\n"); } } if (k == 10) { fprintf(stderr, "(maybe more)\n"); } if (bFirst) { fprintf(stderr, "no atoms found outside box\n"); } fprintf(stderr, "\n"); } } }
int gmx_saltbr(int argc, char *argv[]) { const char *desc[] = { "[TT]g_saltbr[tt] plots the distance between all combination of charged groups", "as a function of time. The groups are combined in different ways.", "A minimum distance can be given (i.e. a cut-off), such that groups", "that are never closer than that distance will not be plotted.[PAR]", "Output will be in a number of fixed filenames, [TT]min-min.xvg[tt], [TT]plus-min.xvg[tt]", "and [TT]plus-plus.xvg[tt], or files for every individual ion pair if the [TT]-sep[tt]", "option is selected. In this case, files are named as [TT]sb-(Resname)(Resnr)-(Atomnr)[tt].", "There may be [BB]many[bb] such files." }; static gmx_bool bSep = FALSE; static real truncate = 1000.0; t_pargs pa[] = { { "-t", FALSE, etREAL, {&truncate}, "Groups that are never closer than this distance are not plotted" }, { "-sep", FALSE, etBOOL, {&bSep}, "Use separate files for each interaction (may be MANY)" } }; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPX, NULL, NULL, ffREAD }, }; #define NFILE asize(fnm) FILE *out[3], *fp; static const char *title[3] = { "Distance between positively charged groups", "Distance between negatively charged groups", "Distance between oppositely charged groups" }; static const char *fn[3] = { "plus-plus.xvg", "min-min.xvg", "plus-min.xvg" }; int nset[3] = {0, 0, 0}; t_topology *top; int ePBC; char *buf; t_trxstatus *status; int i, j, k, m, nnn, teller, ncg, n1, n2, n3, natoms; real t, *time, qi, qj; t_charge *cg; real ***cgdist; int **nWithin; double t0, dt; char label[234]; t_pbc pbc; rvec *x; matrix box; output_env_t oenv; parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv); top = read_top(ftp2fn(efTPX, NFILE, fnm), &ePBC); cg = mk_charge(&top->atoms, &(top->cgs), &ncg); snew(cgdist, ncg); snew(nWithin, ncg); for (i = 0; (i < ncg); i++) { snew(cgdist[i], ncg); snew(nWithin[i], ncg); } natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); teller = 0; time = NULL; do { srenew(time, teller+1); time[teller] = t; set_pbc(&pbc, ePBC, box); for (i = 0; (i < ncg); i++) { for (j = i+1; (j < ncg); j++) { srenew(cgdist[i][j], teller+1); cgdist[i][j][teller] = calc_dist(&pbc, x, &(top->cgs), cg[i].cg, cg[j].cg); if (cgdist[i][j][teller] < truncate) { nWithin[i][j] = 1; } } } teller++; } while (read_next_x(oenv, status, &t, natoms, x, box)); fprintf(stderr, "\n"); close_trj(status); if (bSep) { snew(buf, 256); for (i = 0; (i < ncg); i++) { for (j = i+1; (j < ncg); j++) { if (nWithin[i][j]) { sprintf(buf, "sb-%s:%s.xvg", cg[i].label, cg[j].label); fp = xvgropen(buf, buf, "Time (ps)", "Distance (nm)", oenv); for (k = 0; (k < teller); k++) { fprintf(fp, "%10g %10g\n", time[k], cgdist[i][j][k]); } ffclose(fp); } } } sfree(buf); } else { for (m = 0; (m < 3); m++) { out[m] = xvgropen(fn[m], title[m], "Time (ps)", "Distance (nm)", oenv); } snew(buf, 256); for (i = 0; (i < ncg); i++) { qi = cg[i].q; for (j = i+1; (j < ncg); j++) { qj = cg[j].q; if (nWithin[i][j]) { sprintf(buf, "%s:%s", cg[i].label, cg[j].label); if (qi*qj < 0) { nnn = 2; } else if (qi+qj > 0) { nnn = 0; } else { nnn = 1; } if (nset[nnn] == 0) { xvgr_legend(out[nnn], 1, (const char**)&buf, oenv); } else { if (output_env_get_xvg_format(oenv) == exvgXMGR) { fprintf(out[nnn], "@ legend string %d \"%s\"\n", nset[nnn], buf); } else if (output_env_get_xvg_format(oenv) == exvgXMGRACE) { fprintf(out[nnn], "@ s%d legend \"%s\"\n", nset[nnn], buf); } } nset[nnn]++; nWithin[i][j] = nnn+1; } } } for (k = 0; (k < teller); k++) { for (m = 0; (m < 3); m++) { fprintf(out[m], "%10g", time[k]); } for (i = 0; (i < ncg); i++) { for (j = i+1; (j < ncg); j++) { nnn = nWithin[i][j]; if (nnn > 0) { fprintf(out[nnn-1], " %10g", cgdist[i][j][k]); } } } for (m = 0; (m < 3); m++) { fprintf(out[m], "\n"); } } for (m = 0; (m < 3); m++) { ffclose(out[m]); if (nset[m] == 0) { remove(fn[m]); } } } thanx(stderr); return 0; }
/* 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; } }
int gmx_genion(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] randomly replaces solvent molecules with monoatomic ions.", "The group of solvent molecules should be continuous and all molecules", "should have the same number of atoms.", "The user should add the ion molecules to the topology file or use", "the [TT]-p[tt] option to automatically modify the topology.[PAR]", "The ion molecule type, residue and atom names in all force fields", "are the capitalized element names without sign. This molecule name", "should be given with [TT]-pname[tt] or [TT]-nname[tt], and the", "[TT][molecules][tt] section of your topology updated accordingly,", "either by hand or with [TT]-p[tt]. Do not use an atom name instead!", "[PAR]Ions which can have multiple charge states get the multiplicity", "added, without sign, for the uncommon states only.[PAR]", "For larger ions, e.g. sulfate we recommended using [gmx-insert-molecules]." }; const char *bugs[] = { "If you specify a salt concentration existing ions are not taken into " "account. In effect you therefore specify the amount of salt to be added.", }; static int p_num = 0, n_num = 0, p_q = 1, n_q = -1; static const char *p_name = "NA", *n_name = "CL"; static real rmin = 0.6, conc = 0; static int seed = 1993; static gmx_bool bNeutral = FALSE; static t_pargs pa[] = { { "-np", FALSE, etINT, {&p_num}, "Number of positive ions" }, { "-pname", FALSE, etSTR, {&p_name}, "Name of the positive ion" }, { "-pq", FALSE, etINT, {&p_q}, "Charge of the positive ion" }, { "-nn", FALSE, etINT, {&n_num}, "Number of negative ions" }, { "-nname", FALSE, etSTR, {&n_name}, "Name of the negative ion" }, { "-nq", FALSE, etINT, {&n_q}, "Charge of the negative ion" }, { "-rmin", FALSE, etREAL, {&rmin}, "Minimum distance between ions" }, { "-seed", FALSE, etINT, {&seed}, "Seed for random number generator" }, { "-conc", FALSE, etREAL, {&conc}, "Specify salt concentration (mol/liter). This will add sufficient ions to reach up to the specified concentration as computed from the volume of the cell in the input [REF].tpr[ref] file. Overrides the [TT]-np[tt] and [TT]-nn[tt] options." }, { "-neutral", FALSE, etBOOL, {&bNeutral}, "This option will add enough ions to neutralize the system. These ions are added on top of those specified with [TT]-np[tt]/[TT]-nn[tt] or [TT]-conc[tt]. "} }; t_topology top; rvec *x, *v; real vol, qtot; matrix box; t_atoms atoms; t_pbc pbc; int *repl, ePBC; atom_id *index; char *grpname; gmx_bool *bSet; int i, nw, nwa, nsa, nsalt, iqtot; gmx_output_env_t *oenv; gmx_rng_t rng; t_filenm fnm[] = { { efTPR, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efSTO, "-o", NULL, ffWRITE }, { efTOP, "-p", "topol", ffOPTRW } }; #define NFILE asize(fnm) if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv)) { return 0; } /* Check input for something sensible */ if ((p_num < 0) || (n_num < 0)) { gmx_fatal(FARGS, "Negative number of ions to add?"); } if (conc > 0 && (p_num > 0 || n_num > 0)) { fprintf(stderr, "WARNING: -conc specified, overriding -nn and -np.\n"); } /* Read atom positions and charges */ read_tps_conf(ftp2fn(efTPR, NFILE, fnm), &top, &ePBC, &x, &v, box, FALSE); atoms = top.atoms; /* Compute total charge */ qtot = 0; for (i = 0; (i < atoms.nr); i++) { qtot += atoms.atom[i].q; } iqtot = std::round(qtot); if (conc > 0) { /* Compute number of ions to be added */ vol = det(box); nsalt = std::round(conc*vol*AVOGADRO/1e24); p_num = abs(nsalt*n_q); n_num = abs(nsalt*p_q); } if (bNeutral) { int qdelta = p_num*p_q + n_num*n_q + iqtot; /* Check if the system is neutralizable * is (qdelta == p_q*p_num + n_q*n_num) solvable for p_num and n_num? */ int gcd = gmx_greatest_common_divisor(n_q, p_q); if ((qdelta % gcd) != 0) { gmx_fatal(FARGS, "Can't neutralize this system using -nq %d and" " -pq %d.\n", n_q, p_q); } while (qdelta != 0) { while (qdelta < 0) { p_num++; qdelta += p_q; } while (qdelta > 0) { n_num++; qdelta += n_q; } } } if ((p_num == 0) && (n_num == 0)) { fprintf(stderr, "No ions to add, will just copy input configuration.\n"); } else { printf("Will try to add %d %s ions and %d %s ions.\n", p_num, p_name, n_num, n_name); printf("Select a continuous group of solvent molecules\n"); get_index(&atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &nwa, &index, &grpname); for (i = 1; i < nwa; i++) { if (index[i] != index[i-1]+1) { gmx_fatal(FARGS, "The solvent group %s is not continuous: " "index[%d]=%d, index[%d]=%d", grpname, i, index[i-1]+1, i+1, index[i]+1); } } nsa = 1; while ((nsa < nwa) && (atoms.atom[index[nsa]].resind == atoms.atom[index[nsa-1]].resind)) { nsa++; } if (nwa % nsa) { gmx_fatal(FARGS, "Your solvent group size (%d) is not a multiple of %d", nwa, nsa); } nw = nwa/nsa; fprintf(stderr, "Number of (%d-atomic) solvent molecules: %d\n", nsa, nw); if (p_num+n_num > nw) { gmx_fatal(FARGS, "Not enough solvent for adding ions"); } if (opt2bSet("-p", NFILE, fnm)) { update_topol(opt2fn("-p", NFILE, fnm), p_num, n_num, p_name, n_name, grpname); } snew(bSet, nw); snew(repl, nw); snew(v, atoms.nr); snew(atoms.pdbinfo, atoms.nr); set_pbc(&pbc, ePBC, box); if (seed == 0) { rng = gmx_rng_init(gmx_rng_make_seed()); } else { rng = gmx_rng_init(seed); } /* Now loop over the ions that have to be placed */ while (p_num-- > 0) { insert_ion(nsa, &nw, bSet, repl, index, x, &pbc, 1, p_q, p_name, &atoms, rmin, rng); } while (n_num-- > 0) { insert_ion(nsa, &nw, bSet, repl, index, x, &pbc, -1, n_q, n_name, &atoms, rmin, rng); } gmx_rng_destroy(rng); fprintf(stderr, "\n"); if (nw) { sort_ions(nsa, nw, repl, index, &atoms, x, p_name, n_name); } sfree(atoms.pdbinfo); atoms.pdbinfo = NULL; } write_sto_conf(ftp2fn(efSTO, NFILE, fnm), *top.name, &atoms, x, NULL, ePBC, box); return 0; }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j, status; int donb_flags; gmx_bool bDoEpot, bSepDVDL, bSB; int pme_flags; matrix boxs; rvec box_size; real Vsr, Vlr, Vcorr = 0; t_pbc pbc; real dvdgb; char buf[22]; double clam_i, vlam_i; real dvdl_dum[efptNR], dvdl, dvdl_nb[efptNR], lam_i[efptNR]; real dvdlsum; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s, v, dvdlambda) if (bSepDVDL) {fprintf(fplog, sepdvdlformat, s, v, dvdlambda); } GMX_MPE_LOG(ev_force_start); set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } bSepDVDL = (fr->bSepDVDL && do_per_step(step, ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr, md); } if (bSepDVDL) { fprintf(fplog, "Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step, buf), cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ dvdl = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); PRINT_SEPDVDL("Walls", 0.0, dvdl); enerd->dvdl_lin[efptVDW] += dvdl; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, atype, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &enerd->grpp, box_size, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), box_size, nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsBONDED); calc_gb_forces(cr, md, born, top, atype, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, bBornRadii, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsBONDED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } Vsr = 0; if (bSepDVDL) { for (i = 0; i < enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } dvdlsum = dvdl_nb[efptVDW] + dvdl_nb[efptCOUL]; PRINT_SEPDVDL("VdW and Coulomb SR particle-p.", Vsr, dvdlsum); } debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); wallcycle_sub_start(wcycle, ewcsBONDED); calc_bonds(fplog, cr->ms, idef, x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, flags, fr->bSepDVDL && do_per_step(step, ir->nstlog), step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } for (i = 0; i < enerd->n_lambda; i++) { reset_foreign_enerdata(enerd); for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } calc_bonds_lambda(fplog, idef, x, fr, &pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); wallcycle_sub_stop(wcycle, ewcsBONDED); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { Vcorr = 0; dvdl = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = gmx_omp_nthreads_get(emntBonded); #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { int s, e, i; rvec *fnv; tensor *vir; real *Vcorrt, *dvdlt; if (t == 0) { fnv = fr->f_novirsum; vir = &fr->vir_el_recip; Vcorrt = &Vcorr; dvdlt = &dvdl; } else { fnv = fr->f_t[t].f; vir = &fr->f_t[t].vir; Vcorrt = &fr->f_t[t].Vcorr; dvdlt = &fr->f_t[t].dvdl[efptCOUL]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir); } *dvdlt = 0; *Vcorrt = ewald_LRcorrection(fplog, fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir, lambda[efptCOUL], dvdlt); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, &Vcorr, efptCOUL, &dvdl, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (fr->n_tpi == 0) { Vcorr += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl, fr->vir_el_recip); } PRINT_SEPDVDL("Ewald excl./charge/dip. corr.", Vcorr, dvdl); enerd->dvdl_lin[efptCOUL] += dvdl; } status = 0; Vlr = 0; dvdl = 0; switch (fr->eeltype) { case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: case eelP3M_AD: if (cr->duty & DUTY_PME) { assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle, ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, bSB ? boxs : box, cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle, fr->vir_el_recip, fr->ewaldcoeff, &Vlr, lambda[efptCOUL], &dvdl, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata, fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh", Vlr, dvdl); } break; case eelEWALD: Vlr = do_ewald(fplog, FALSE, ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff, lambda[efptCOUL], &dvdl, fr->ewald_table); PRINT_SEPDVDL("Ewald long-range", Vlr, dvdl); break; default: gmx_fatal(FARGS, "No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS, "Error %d in long range electrostatics routine %s", status, EELTYPE(fr->eeltype)); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug, "Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr, Vcorr, enerd->term[F_COUL_RECIP]); pr_rvecs(debug, 0, "vir_el_recip after corr", fr->vir_el_recip, DIM); pr_rvecs(debug, 0, "fshift after LR Corrections", fr->fshift, SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET && fr->eeltype != eelRF_NEC) { dvdl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fplog, fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl); } enerd->dvdl_lin[efptCOUL] += dvdl; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL], dvdl); } } where(); debug_gmx(); if (debug) { print_nrnb(debug, nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2 = MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3 = MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr, "* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps, buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug, 0, "fshift after bondeds", fr->fshift, SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
static char *insert_mols(const char *mol_insrt, int nmol_insrt, int ntry, int seed, t_atoms *atoms, rvec **x, real **r, int ePBC, matrix box, gmx_atomprop_t aps, real r_distance, real rshell, const output_env_t oenv) { t_pbc pbc; static char *title_insrt; t_atoms atoms_insrt; rvec *x_insrt, *x_n; real *r_insrt; int ePBC_insrt; matrix box_insrt; int i, mol, onr; real alfa, beta, gamma; rvec offset_x; int trial; set_pbc(&pbc, ePBC, box); /* read number of atoms of insert molecules */ get_stx_coordnum(mol_insrt, &atoms_insrt.nr); if (atoms_insrt.nr == 0) { gmx_fatal(FARGS, "No molecule in %s, please check your input\n", mol_insrt); } /* allocate memory for atom coordinates of insert molecules */ snew(x_insrt, atoms_insrt.nr); snew(r_insrt, atoms_insrt.nr); snew(atoms_insrt.resinfo, atoms_insrt.nr); snew(atoms_insrt.atomname, atoms_insrt.nr); snew(atoms_insrt.atom, atoms_insrt.nr); atoms_insrt.pdbinfo = NULL; snew(x_n, atoms_insrt.nr); snew(title_insrt, STRLEN); /* read residue number, residue names, atomnames, coordinates etc. */ fprintf(stderr, "Reading molecule configuration \n"); read_stx_conf(mol_insrt, title_insrt, &atoms_insrt, x_insrt, NULL, &ePBC_insrt, box_insrt); fprintf(stderr, "%s\nContaining %d atoms in %d residue\n", title_insrt, atoms_insrt.nr, atoms_insrt.nres); srenew(atoms_insrt.resinfo, atoms_insrt.nres); /* initialise van der waals arrays of insert molecules */ mk_vdw(&atoms_insrt, r_insrt, aps, r_distance); srenew(atoms->resinfo, (atoms->nres+nmol_insrt*atoms_insrt.nres)); srenew(atoms->atomname, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(atoms->atom, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*x, (atoms->nr+atoms_insrt.nr*nmol_insrt)); srenew(*r, (atoms->nr+atoms_insrt.nr*nmol_insrt)); trial = mol = 0; while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt)) { fprintf(stderr, "\rTry %d", trial++); for (i = 0; (i < atoms_insrt.nr); i++) { copy_rvec(x_insrt[i], x_n[i]); } alfa = 2*M_PI*rando( &seed); beta = 2*M_PI*rando( &seed); gamma = 2*M_PI*rando( &seed); rotate_conf(atoms_insrt.nr, x_n, NULL, alfa, beta, gamma); offset_x[XX] = box[XX][XX]*rando(&seed); offset_x[YY] = box[YY][YY]*rando(&seed); offset_x[ZZ] = box[ZZ][ZZ]*rando(&seed); gen_box(0, atoms_insrt.nr, x_n, box_insrt, offset_x, TRUE); if (!in_box(&pbc, x_n[0]) || !in_box(&pbc, x_n[atoms_insrt.nr-1])) { continue; } onr = atoms->nr; add_conf(atoms, x, NULL, r, FALSE, ePBC, box, TRUE, &atoms_insrt, x_n, NULL, r_insrt, FALSE, rshell, 0, oenv); if (atoms->nr == (atoms_insrt.nr+onr)) { mol++; fprintf(stderr, " success (now %d atoms)!", atoms->nr); } } srenew(atoms->resinfo, atoms->nres); srenew(atoms->atomname, atoms->nr); srenew(atoms->atom, atoms->nr); srenew(*x, atoms->nr); srenew(*r, atoms->nr); fprintf(stderr, "\n"); /* print number of molecules added */ fprintf(stderr, "Added %d molecules (out of %d requested) of %s\n", mol, nmol_insrt, *atoms_insrt.resinfo[0].name); return title_insrt; }
bool constrain(FILE *fplog,bool bLog,bool bEner, struct gmx_constr *constr, t_idef *idef,t_inputrec *ir, t_commrec *cr, gmx_step_t step,int delta_step, t_mdatoms *md, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda, rvec *v,tensor *vir, t_nrnb *nrnb,int econq) { bool bOK; int start,homenr; int i,j; int ncons,error; tensor rmdr; real invdt,vir_fac,t; t_ilist *settle; int nsettle; t_pbc pbc; char buf[22]; if (econq == econqForceDispl && !EI_ENERGY_MINIMIZATION(ir->eI)) { gmx_incons("constrain called for forces displacements while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted"); } bOK = TRUE; start = md->start; homenr = md->homenr; if (ir->delta_t == 0) { invdt = 0; } else { invdt = 1/ir->delta_t; } if (ir->efep != efepNO && EI_DYNAMICS(ir->eI)) { /* Set the constraint lengths for the step at which this configuration * is meant to be. The invmasses should not be changed. */ lambda += delta_step*ir->delta_lambda; } if (vir != NULL) { clear_mat(rmdr); } where(); if (constr->lincsd) { bOK = constrain_lincs(fplog,bLog,bEner,ir,step,constr->lincsd,md,cr, x,xprime,min_proj,box,lambda,dvdlambda, invdt,v,vir!=NULL,rmdr, econq,nrnb, constr->maxwarn,&constr->warncount_lincs); if (!bOK && constr->maxwarn >= 0 && fplog) { fprintf(fplog,"Constraint error in algorithm %s at step %s\n", econstr_names[econtLINCS],gmx_step_str(step,buf)); } } if (constr->nblocks > 0) { if (econq != econqCoord) { gmx_fatal(FARGS,"Internal error, SHAKE called for constraining something else than coordinates"); } bOK = bshakef(fplog,constr->shaked, homenr,md->invmass,constr->nblocks,constr->sblock, idef,ir,box,x,xprime,nrnb, constr->lagr,lambda,dvdlambda, invdt,v,vir!=NULL,rmdr,constr->maxwarn>=0); if (!bOK && constr->maxwarn >= 0 && fplog) { fprintf(fplog,"Constraint error in algorithm %s at step %s\n", econstr_names[econtSHAKE],gmx_step_str(step,buf)); } } settle = &idef->il[F_SETTLE]; if (settle->nr > 0) { nsettle = settle->nr/2; switch (econq) { case econqCoord: csettle(constr->settled, nsettle,settle->iatoms,x[0],xprime[0], invdt,v[0],vir!=NULL,rmdr,&error); inc_nrnb(nrnb,eNR_SETTLE,nsettle); if (v != NULL) { inc_nrnb(nrnb,eNR_CONSTR_V,nsettle*3); } if (vir != NULL) { inc_nrnb(nrnb,eNR_CONSTR_VIR,nsettle*3); } bOK = (error < 0); if (!bOK && constr->maxwarn >= 0) { char buf[256]; sprintf(buf, "\nt = %.3f ps: Water molecule starting at atom %d can not be " "settled.\nCheck for bad contacts and/or reduce the timestep.\n", ir->init_t+step*ir->delta_t, ddglatnr(cr->dd,settle->iatoms[error*2+1])); if (fplog) { fprintf(fplog,"%s",buf); } fprintf(stderr,"%s",buf); constr->warncount_settle++; if (constr->warncount_settle > constr->maxwarn) { too_many_constraint_warnings(-1,constr->warncount_settle); } break; case econqVeloc: case econqDeriv: case econqForce: case econqForceDispl: settle_proj(fplog,constr->settled,econq, nsettle,settle->iatoms,x, xprime,min_proj,vir!=NULL,rmdr); /* This is an overestimate */ inc_nrnb(nrnb,eNR_SETTLE,nsettle); break; case econqDeriv_FlexCon: /* Nothing to do, since the are no flexible constraints in settles */ break; default: gmx_incons("Unknown constraint quantity for settle"); } } } if (vir != NULL) { switch (econq) { case econqCoord: vir_fac = 0.5/(ir->delta_t*ir->delta_t); break; case econqVeloc: /* Assume that these are velocities */ vir_fac = 0.5/ir->delta_t; break; case econqForce: case econqForceDispl: vir_fac = 0.5; break; default: vir_fac = 0; gmx_incons("Unsupported constraint quantity for virial"); } for(i=0; i<DIM; i++) { for(j=0; j<DIM; j++) { (*vir)[i][j] = vir_fac*rmdr[i][j]; } } } if (!bOK && constr->maxwarn >= 0) { dump_confs(fplog,step,constr->warn_mtop,start,homenr,cr,x,xprime,box); } if (econq == econqCoord) { if (ir->ePull == epullCONSTRAINT) { if (EI_DYNAMICS(ir->eI)) { t = ir->init_t + (step + delta_step)*ir->delta_t; } else { t = ir->init_t; } set_pbc(&pbc,ir->ePBC,box); pull_constraint(ir->pull,md,&pbc,cr,ir->delta_t,t,x,xprime,v,*vir); } if (constr->ed && delta_step > 0) { /* apply the essential dynamcs constraints here */ do_edsam(ir,step,md,cr,xprime,v,box,constr->ed); } } return bOK; }