real sub_xcm(rvec x[], int gnx, atom_id *index, t_atom atom[], rvec xcm, gmx_bool bQ) { int i, ii; real tm; tm = calc_xcm(x, gnx, index, atom, xcm, bQ); for (i = 0; (i < gnx); i++) { ii = index ? index[i] : i; rvec_dec(x[ii], xcm); } return tm; }
void orient_princ(t_atoms *atoms, int isize, atom_id *index, int natoms, rvec x[], rvec *v, rvec d) { int i, m; rvec xcm, prcomp; matrix trans; calc_xcm(x, isize, index, atoms->atom, xcm, FALSE); for (i = 0; i < natoms; i++) { rvec_dec(x[i], xcm); } principal_comp(isize, index, atoms->atom, x, trans, prcomp); if (d) { copy_rvec(prcomp, d); } /* Check whether this trans matrix mirrors the molecule */ if (det(trans) < 0) { for (m = 0; (m < DIM); m++) { trans[ZZ][m] = -trans[ZZ][m]; } } rotate_atoms(natoms, NULL, x, trans); if (v) { rotate_atoms(natoms, NULL, v, trans); } for (i = 0; i < natoms; i++) { rvec_inc(x[i], xcm); } }
void calc_potential(const char *fn, int **index, int gnx[], double ***slPotential, double ***slCharge, double ***slField, int *nslices, const t_topology *top, int ePBC, int axis, int nr_grps, double *slWidth, double fudge_z, gmx_bool bSpherical, gmx_bool bCorrect, const gmx_output_env_t *oenv) { rvec *x0; /* coordinates without pbc */ matrix box; /* box (3x3) */ int natoms; /* nr. atoms in trj */ t_trxstatus *status; int i, n, /* loop indices */ teller = 0, ax1 = 0, ax2 = 0, nr_frames = 0, /* number of frames */ slice; /* current slice */ double slVolume; /* volume of slice for spherical averaging */ double qsum, nn; real t; double z; rvec xcm; gmx_rmpbc_t gpbc = NULL; switch (axis) { case 0: ax1 = 1; ax2 = 2; break; case 1: ax1 = 0; ax2 = 2; break; case 2: ax1 = 0; ax2 = 1; break; default: gmx_fatal(FARGS, "Invalid axes. Terminating\n"); } if ((natoms = read_first_x(oenv, &status, fn, &t, &x0, box)) == 0) { gmx_fatal(FARGS, "Could not read coordinates from statusfile\n"); } if (!*nslices) { *nslices = static_cast<int>(box[axis][axis] * 10.0); /* default value */ } fprintf(stderr, "\nDividing the box in %d slices\n", *nslices); snew(*slField, nr_grps); snew(*slCharge, nr_grps); snew(*slPotential, nr_grps); for (i = 0; i < nr_grps; i++) { snew((*slField)[i], *nslices); snew((*slCharge)[i], *nslices); snew((*slPotential)[i], *nslices); } gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms); /*********** Start processing trajectory ***********/ do { *slWidth = box[axis][axis]/(*nslices); teller++; gmx_rmpbc(gpbc, natoms, box, x0); /* calculate position of center of mass based on group 1 */ calc_xcm(x0, gnx[0], index[0], top->atoms.atom, xcm, FALSE); svmul(-1, xcm, xcm); for (n = 0; n < nr_grps; n++) { /* Check whether we actually have all positions of the requested index * group in the trajectory file */ if (gnx[n] > natoms) { gmx_fatal(FARGS, "You selected a group with %d atoms, but only %d atoms\n" "were found in the trajectory.\n", gnx[n], natoms); } for (i = 0; i < gnx[n]; i++) /* loop over all atoms in index file */ { if (bSpherical) { rvec_add(x0[index[n][i]], xcm, x0[index[n][i]]); /* only distance from origin counts, not sign */ slice = static_cast<int>(norm(x0[index[n][i]])/(*slWidth)); /* this is a nice check for spherical groups but not for all water in a cubic box since a lot will fall outside the sphere if (slice > (*nslices)) { fprintf(stderr,"Warning: slice = %d\n",slice); } */ (*slCharge)[n][slice] += top->atoms.atom[index[n][i]].q; } else { z = x0[index[n][i]][axis]; z = z + fudge_z; if (z < 0) { z += box[axis][axis]; } if (z > box[axis][axis]) { z -= box[axis][axis]; } /* determine which slice atom is in */ slice = static_cast<int>((z / (*slWidth))); (*slCharge)[n][slice] += top->atoms.atom[index[n][i]].q; } } } nr_frames++; } while (read_next_x(oenv, status, &t, x0, box)); gmx_rmpbc_done(gpbc); /*********** done with status file **********/ close_trj(status); /* slCharge now contains the total charge per slice, summed over all frames. Now divide by nr_frames and integrate twice */ if (bSpherical) { fprintf(stderr, "\n\nRead %d frames from trajectory. Calculating potential" "in spherical coordinates\n", nr_frames); } else { fprintf(stderr, "\n\nRead %d frames from trajectory. Calculating potential\n", nr_frames); } for (n = 0; n < nr_grps; n++) { for (i = 0; i < *nslices; i++) { if (bSpherical) { /* charge per volume is now the summed charge, divided by the nr of frames and by the volume of the slice it's in, 4pi r^2 dr */ slVolume = 4*M_PI * gmx::square(i) * gmx::square(*slWidth) * *slWidth; if (slVolume == 0) { (*slCharge)[n][i] = 0; } else { (*slCharge)[n][i] = (*slCharge)[n][i] / (nr_frames * slVolume); } } else { /* get charge per volume */ (*slCharge)[n][i] = (*slCharge)[n][i] * (*nslices) / (nr_frames * box[axis][axis] * box[ax1][ax1] * box[ax2][ax2]); } } /* Now we have charge densities */ } if (bCorrect && !bSpherical) { for (n = 0; n < nr_grps; n++) { nn = 0; qsum = 0; for (i = 0; i < *nslices; i++) { if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN) { nn++; qsum += (*slCharge)[n][i]; } } qsum /= nn; for (i = 0; i < *nslices; i++) { if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN) { (*slCharge)[n][i] -= qsum; } } } } for (n = 0; n < nr_grps; n++) { /* integrate twice to get field and potential */ p_integrate((*slField)[n], (*slCharge)[n], *nslices, *slWidth); } if (bCorrect && !bSpherical) { for (n = 0; n < nr_grps; n++) { nn = 0; qsum = 0; for (i = 0; i < *nslices; i++) { if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN) { nn++; qsum += (*slField)[n][i]; } } qsum /= nn; for (i = 0; i < *nslices; i++) { if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN) { (*slField)[n][i] -= qsum; } } } } for (n = 0; n < nr_grps; n++) { p_integrate((*slPotential)[n], (*slField)[n], *nslices, *slWidth); } /* Now correct for eps0 and in spherical case for r*/ for (n = 0; n < nr_grps; n++) { for (i = 0; i < *nslices; i++) { if (bSpherical) { (*slPotential)[n][i] = ELC * (*slPotential)[n][i] * -1.0E9 / (EPS0 * i * (*slWidth)); (*slField)[n][i] = ELC * (*slField)[n][i] * 1E18 / (EPS0 * i * (*slWidth)); } else { (*slPotential)[n][i] = ELC * (*slPotential)[n][i] * -1.0E9 / EPS0; (*slField)[n][i] = ELC * (*slField)[n][i] * 1E18 / EPS0; } } } sfree(x0); /* free memory used by coordinate array */ }
void calc_h2order(const char *fn, atom_id index[], int ngx, rvec **slDipole, real **slOrder, real *slWidth, int *nslices, t_topology *top, int ePBC, int axis, gmx_bool bMicel, atom_id micel[], int nmic, const output_env_t oenv) { rvec *x0, /* coordinates with pbc */ dipole, /* dipole moment due to one molecules */ normal, com; /* center of mass of micel, with bMicel */ rvec *dip; /* sum of dipoles, unnormalized */ matrix box; /* box (3x3) */ t_trxstatus *status; real t, /* time from trajectory */ *sum, /* sum of all cosines of dipoles, per slice */ *frame; /* order over one frame */ int natoms, /* nr. atoms in trj */ i,j,teller = 0, slice=0, /* current slice number */ *count; /* nr. of atoms in one slice */ gmx_rmpbc_t gpbc=NULL; if ((natoms = read_first_x(oenv,&status,fn,&t,&x0,box)) == 0) gmx_fatal(FARGS,"Could not read coordinates from statusfile\n"); if (! *nslices) *nslices = (int)(box[axis][axis] * 10); /* default value */ switch(axis) { case 0: normal[0] = 1; normal[1] = 0; normal[2] = 0; break; case 1: normal[0] = 0; normal[1] = 1; normal[2] = 0; break; case 2: normal[0] = 0; normal[1] = 0; normal[2] = 1; break; default: gmx_fatal(FARGS,"No valid value for -axis-. Exiting.\n"); /* make compiler happy */ normal[0] = 1; normal[1] = 0; normal[2] = 0; } clear_rvec(dipole); snew(count, *nslices); snew(sum, *nslices); snew(dip, *nslices); snew(frame, *nslices); *slWidth = box[axis][axis]/(*nslices); fprintf(stderr,"Box divided in %d slices. Initial width of slice: %f\n", *nslices, *slWidth); teller = 0; gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box); /*********** Start processing trajectory ***********/ do { *slWidth = box[axis][axis]/(*nslices); teller++; gmx_rmpbc(gpbc,natoms,box,x0); if (bMicel) calc_xcm(x0, nmic, micel, top->atoms.atom, com, FALSE); for (i = 0; i < ngx/3; i++) { /* put all waters in box */ for (j = 0; j < DIM; j++) { if (x0[index[3*i]][j] < 0) { x0[index[3*i]][j] += box[j][j]; x0[index[3*i+1]][j] += box[j][j]; x0[index[3*i+2]][j] += box[j][j]; } if (x0[index[3*i]][j] > box[j][j]) { x0[index[3*i]][j] -= box[j][j]; x0[index[3*i+1]][j] -= box[j][j]; x0[index[3*i+2]][j] -= box[j][j]; } } for (j = 0; j < DIM; j++) dipole[j] = x0[index[3*i]][j] * top->atoms.atom[index[3*i]].q + x0[index[3*i+1]][j] * top->atoms.atom[index[3*i+1]].q + x0[index[3*i+2]][j] * top->atoms.atom[index[3*i+2]].q; /* now we have a dipole vector. Might as well safe it. Then the rest depends on whether we're dealing with a flat or a spherical interface. */ if (bMicel) { /* this is for spherical interfaces */ rvec_sub(com, x0[index[3*i]], normal); /* vector from Oxygen to COM */ slice = norm(normal)/(*slWidth); /* spherical slice */ sum[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal)); frame[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal)); count[slice]++; } else { /* this is for flat interfaces */ /* determine which slice atom is in */ slice = (x0[index[3*i]][axis] / (*slWidth)); if (slice < 0 || slice >= *nslices) { fprintf(stderr,"Coordinate: %f ",x0[index[3*i]][axis]); fprintf(stderr,"HELP PANIC! slice = %d, OUT OF RANGE!\n",slice); } else { rvec_add(dipole, dip[slice], dip[slice]); /* Add dipole to total. mag[slice] is total dipole in axis direction */ sum[slice] += iprod(dipole,normal)/norm(dipole); frame[slice] += iprod(dipole,normal)/norm(dipole); /* increase count for that slice */ count[slice]++; } } } } while (read_next_x(oenv,status,&t,natoms,x0,box)); /*********** done with status file **********/ fprintf(stderr,"\nRead trajectory. Printing parameters to file\n"); gmx_rmpbc_done(gpbc); for (i = 0; i < *nslices; i++) /* average over frames */ { fprintf(stderr,"%d waters in slice %d\n",count[i],i); if (count[i] > 0) /* divide by number of molecules in each slice */ { sum[i] = sum[i] / count[i]; dip[i][XX] = dip[i][XX] / count[i]; dip[i][YY] = dip[i][YY] / count[i]; dip[i][ZZ] = dip[i][ZZ] / count[i]; } else fprintf(stderr,"No water in slice %d\n",i); } *slOrder = sum; /* copy a pointer, I hope */ *slDipole = dip; sfree(x0); /* free memory used by coordinate arrays */ }
int gmx_filter(int argc,char *argv[]) { const char *desc[] = { "[TT]g_filter[tt] performs frequency filtering on a trajectory.", "The filter shape is cos([GRK]pi[grk] t/A) + 1 from -A to +A, where A is given", "by the option [TT]-nf[tt] times the time step in the input trajectory.", "This filter reduces fluctuations with period A by 85%, with period", "2*A by 50% and with period 3*A by 17% for low-pass filtering.", "Both a low-pass and high-pass filtered trajectory can be written.[PAR]", "Option [TT]-ol[tt] writes a low-pass filtered trajectory.", "A frame is written every [TT]-nf[tt] input frames.", "This ratio of filter length and output interval ensures a good", "suppression of aliasing of high-frequency motion, which is useful for", "making smooth movies. Also averages of properties which are linear", "in the coordinates are preserved, since all input frames are weighted", "equally in the output.", "When all frames are needed, use the [TT]-all[tt] option.[PAR]", "Option [TT]-oh[tt] writes a high-pass filtered trajectory.", "The high-pass filtered coordinates are added to the coordinates", "from the structure file. When using high-pass filtering use [TT]-fit[tt]", "or make sure you use a trajectory that has been fitted on", "the coordinates in the structure file." }; static int nf=10; static gmx_bool bNoJump = TRUE,bFit = FALSE,bLowAll = FALSE; t_pargs pa[] = { { "-nf", FALSE, etINT, {&nf}, "Sets the filter length as well as the output interval for low-pass filtering" }, { "-all", FALSE, etBOOL, {&bLowAll}, "Write all low-pass filtered frames" }, { "-nojump", FALSE, etBOOL, {&bNoJump}, "Remove jumps of atoms across the box" }, { "-fit", FALSE, etBOOL, {&bFit}, "Fit all frames to a reference structure" } }; const char *topfile,*lowfile,*highfile; gmx_bool bTop=FALSE; t_topology top; int ePBC=-1; rvec *xtop; matrix topbox,*box,boxf; char title[256],*grpname; int isize; atom_id *index; real *w_rls=NULL; t_trxstatus *in; t_trxstatus *outl,*outh; int nffr,i,fr,nat,j,d,m; atom_id *ind; real flen,*filt,sum,*t; rvec xcmtop,xcm,**x,*ptr,*xf,*xn,*xp,hbox; output_env_t oenv; gmx_rmpbc_t gpbc=NULL; #define NLEG asize(leg) t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efTRO, "-ol", "lowpass", ffOPTWR }, { efTRO, "-oh", "highpass", ffOPTWR } }; #define NFILE asize(fnm) parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); highfile = opt2fn_null("-oh",NFILE,fnm); if (highfile) { topfile = ftp2fn(efTPS,NFILE,fnm); lowfile = opt2fn_null("-ol",NFILE,fnm); } else { topfile = ftp2fn_null(efTPS,NFILE,fnm); lowfile = opt2fn("-ol",NFILE,fnm); } if (topfile) { bTop = read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC, &xtop,NULL,topbox,TRUE); if (bTop) { gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,topbox); gmx_rmpbc(gpbc,top.atoms.nr,topbox,xtop); } } clear_rvec(xcmtop); if (bFit) { fprintf(stderr,"Select group for least squares fit\n"); get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpname); /* Set the weight */ snew(w_rls,top.atoms.nr); for(i=0; i<isize; i++) w_rls[index[i]] = top.atoms.atom[index[i]].m; calc_xcm(xtop,isize,index,top.atoms.atom,xcmtop,FALSE); for(j=0; j<top.atoms.nr; j++) rvec_dec(xtop[j],xcmtop); } /* The actual filter length flen can actually be any real number */ flen = 2*nf; /* nffr is the number of frames that we filter over */ nffr = 2*nf - 1; snew(filt,nffr); sum = 0; for(i=0; i<nffr; i++) { filt[i] = cos(2*M_PI*(i - nf + 1)/(real)flen) + 1; sum += filt[i]; } fprintf(stdout,"filter weights:"); for(i=0; i<nffr; i++) { filt[i] /= sum; fprintf(stdout," %5.3f",filt[i]); } fprintf(stdout,"\n"); snew(t,nffr); snew(x,nffr); snew(box,nffr); nat = read_first_x(oenv,&in,opt2fn("-f",NFILE,fnm), &(t[nffr - 1]),&(x[nffr - 1]),box[nffr - 1]); snew(ind,nat); for(i=0; i<nat; i++) ind[i] = i; /* x[nffr - 1] was already allocated by read_first_x */ for(i=0; i<nffr-1; i++) snew(x[i],nat); snew(xf,nat); if (lowfile) outl = open_trx(lowfile,"w"); else outl = 0; if (highfile) outh = open_trx(highfile,"w"); else outh = 0; fr = 0; do { xn = x[nffr - 1]; if (bNoJump && fr > 0) { xp = x[nffr - 2]; for(j=0; j<nat; j++) for(d=0; d<DIM; d++) hbox[d] = 0.5*box[nffr - 1][d][d]; for(i=0; i<nat; i++) for(m=DIM-1; m>=0; m--) if (hbox[m] > 0) { while (xn[i][m] - xp[i][m] <= -hbox[m]) for(d=0; d<=m; d++) xn[i][d] += box[nffr - 1][m][d]; while (xn[i][m] - xp[i][m] > hbox[m]) for(d=0; d<=m; d++) xn[i][d] -= box[nffr - 1][m][d]; } } if (bTop) { gmx_rmpbc(gpbc,nat,box[nffr - 1],xn); } if (bFit) { calc_xcm(xn,isize,index,top.atoms.atom,xcm,FALSE); for(j=0; j<nat; j++) rvec_dec(xn[j],xcm); do_fit(nat,w_rls,xtop,xn); for(j=0; j<nat; j++) rvec_inc(xn[j],xcmtop); } if (fr >= nffr && (outh || bLowAll || fr % nf == nf - 1)) { /* Lowpass filtering */ for(j=0; j<nat; j++) clear_rvec(xf[j]); clear_mat(boxf); for(i=0; i<nffr; i++) { for(j=0; j<nat; j++) for(d=0; d<DIM; d++) xf[j][d] += filt[i]*x[i][j][d]; for(j=0; j<DIM; j++) for(d=0; d<DIM; d++) boxf[j][d] += filt[i]*box[i][j][d]; } if (outl && (bLowAll || fr % nf == nf - 1)) write_trx(outl,nat,ind,topfile ? &(top.atoms) : NULL, 0,t[nf - 1],bFit ? topbox : boxf,xf,NULL,NULL); if (outh) { /* Highpass filtering */ for(j=0; j<nat; j++) for(d=0; d<DIM; d++) xf[j][d] = xtop[j][d] + x[nf - 1][j][d] - xf[j][d]; if (bFit) for(j=0; j<nat; j++) rvec_inc(xf[j],xcmtop); for(j=0; j<DIM; j++) for(d=0; d<DIM; d++) boxf[j][d] = topbox[j][d] + box[nf - 1][j][d] - boxf[j][d]; write_trx(outh,nat,ind,topfile ? &(top.atoms) : NULL, 0,t[nf - 1],bFit ? topbox : boxf,xf,NULL,NULL); } } /* Cycle all the pointer and the box by one */ ptr = x[0]; for(i=0; i<nffr-1; i++) { t[i] = t[i+1]; x[i] = x[i+1]; copy_mat(box[i+1],box[i]); } x[nffr - 1] = ptr; fr++; } while (read_next_x(oenv,in,&(t[nffr - 1]),nat,x[nffr - 1],box[nffr - 1])); if (bTop) gmx_rmpbc_done(gpbc); if (outh) close_trx(outh); if (outl) close_trx(outl); close_trx(in); return 0; }