void BoxDeformation::apply(ArrayRef<RVec> x, matrix box, int64_t step) { matrix updatedBox, invbox, mu; double elapsedTime = (step + 1 - initialStep_) * timeStep_; copy_mat(box, updatedBox); for (int i = 0; i < DIM; i++) { for (int j = 0; j < DIM; j++) { if (deformationTensor_[i][j] != 0) { updatedBox[i][j] = referenceBox_[i][j] + elapsedTime * deformationTensor_[i][j]; } } } /* We correct the off-diagonal elements, * which can grow indefinitely during shearing, * so the shifts do not get messed up. */ for (int i = 1; i < DIM; i++) { for (int j = i-1; j >= 0; j--) { while (updatedBox[i][j] - box[i][j] > 0.5 * updatedBox[j][j]) { rvec_dec(updatedBox[i], updatedBox[j]); } while (updatedBox[i][j] - box[i][j] < -0.5 * updatedBox[j][j]) { rvec_inc(updatedBox[i], updatedBox[j]); } } } invertBoxMatrix(box, invbox); // Return the updated box copy_mat(updatedBox, box); mmul_ur0(box, invbox, mu); for (auto &thisX : x) { thisX[XX] = mu[XX][XX]*thisX[XX] + mu[YY][XX]*thisX[YY] + mu[ZZ][XX]*thisX[ZZ]; thisX[YY] = mu[YY][YY]*thisX[YY] + mu[ZZ][YY]*thisX[ZZ]; thisX[ZZ] = mu[ZZ][ZZ]*thisX[ZZ]; } }
int gmx_vanhove(int argc,char *argv[]) { const char *desc[] = { "g_vanhove computes the Van Hove correlation function.", "The Van Hove G(r,t) is the probability that a particle that is at r0", "at time zero can be found at position r0+r at time t.", "g_vanhove determines G not for a vector r, but for the length of r.", "Thus it gives the probability that a particle moves a distance of r", "in time t.", "Jumps across the periodic boundaries are removed.", "Corrections are made for scaling due to isotropic", "or anisotropic pressure coupling.", "[PAR]", "With option [TT]-om[tt] the whole matrix can be written as a function", "of t and r or as a function of sqrt(t) and r (option [TT]-sqrt[tt]).", "[PAR]", "With option [TT]-or[tt] the Van Hove function is plotted for one", "or more values of t. Option [TT]-nr[tt] sets the number of times,", "option [TT]-fr[tt] the number spacing between the times.", "The binwidth is set with option [TT]-rbin[tt]. The number of bins", "is determined automatically.", "[PAR]", "With option [TT]-ot[tt] the integral up to a certain distance", "(option [TT]-rt[tt]) is plotted as a function of time.", "[PAR]", "For all frames that are read the coordinates of the selected particles", "are stored in memory. Therefore the program may use a lot of memory.", "For options [TT]-om[tt] and [TT]-ot[tt] the program may be slow.", "This is because the calculation scales as the number of frames times", "[TT]-fm[tt] or [TT]-ft[tt].", "Note that with the [TT]-dt[tt] option the memory usage and calculation", "time can be reduced." }; static int fmmax=0,ftmax=0,nlev=81,nr=1,fshift=0; static real sbin=0,rmax=2,rbin=0.01,mmax=0,rint=0; t_pargs pa[] = { { "-sqrt", FALSE, etREAL,{&sbin}, "Use sqrt(t) on the matrix axis which binspacing # in sqrt(ps)" }, { "-fm", FALSE, etINT, {&fmmax}, "Number of frames in the matrix, 0 is plot all" }, { "-rmax", FALSE, etREAL, {&rmax}, "Maximum r in the matrix (nm)" }, { "-rbin", FALSE, etREAL, {&rbin}, "Binwidth in the matrix and for -or (nm)" }, { "-mmax", FALSE, etREAL, {&mmax}, "Maximum density in the matrix, 0 is calculate (1/nm)" }, { "-nlevels" ,FALSE, etINT, {&nlev}, "Number of levels in the matrix" }, { "-nr", FALSE, etINT, {&nr}, "Number of curves for the -or output" }, { "-fr", FALSE, etINT, {&fshift}, "Frame spacing for the -or output" }, { "-rt", FALSE, etREAL, {&rint}, "Integration limit for the -ot output (nm)" }, { "-ft", FALSE, etINT, {&ftmax}, "Number of frames in the -ot output, 0 is plot all" } }; #define NPA asize(pa) t_filenm fnm[] = { { efTRX, NULL, NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXPM, "-om", "vanhove", ffOPTWR }, { efXVG, "-or", "vanhove_r", ffOPTWR }, { efXVG, "-ot", "vanhove_t", ffOPTWR } }; #define NFILE asize(fnm) output_env_t oenv; const char *matfile,*otfile,*orfile; char title[256]; t_topology top; int ePBC; matrix boxtop,box,*sbox,avbox,corr; rvec *xtop,*x,**sx; int isize,nalloc,nallocn,natom; t_trxstatus *status; atom_id *index; char *grpname; int nfr,f,ff,i,m,mat_nx=0,nbin=0,bin,mbin,fbin; real *time,t,invbin=0,rmax2=0,rint2=0,d2; real invsbin=0,matmax,normfac,dt,*tickx,*ticky; char buf[STRLEN],**legend; real **mat=NULL; int *pt=NULL,**pr=NULL,*mcount=NULL,*tcount=NULL,*rcount=NULL; FILE *fp; t_rgb rlo={1,1,1}, rhi={0,0,0}; CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); matfile = opt2fn_null("-om",NFILE,fnm); if (opt2parg_bSet("-fr",NPA,pa)) orfile = opt2fn("-or",NFILE,fnm); else orfile = opt2fn_null("-or",NFILE,fnm); if (opt2parg_bSet("-rt",NPA,pa)) otfile = opt2fn("-ot",NFILE,fnm); else otfile = opt2fn_null("-ot",NFILE,fnm); if (!matfile && !otfile && !orfile) { fprintf(stderr, "For output set one (or more) of the output file options\n"); exit(0); } read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xtop,NULL,boxtop, FALSE); get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpname); nalloc = 0; time = NULL; sbox = NULL; sx = NULL; clear_mat(avbox); natom=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); nfr = 0; do { if (nfr >= nalloc) { nalloc += 100; srenew(time,nalloc); srenew(sbox,nalloc); srenew(sx,nalloc); } time[nfr] = t; copy_mat(box,sbox[nfr]); /* This assumes that the off-diagonal box elements * are not affected by jumps across the periodic boundaries. */ m_add(avbox,box,avbox); snew(sx[nfr],isize); for(i=0; i<isize; i++) copy_rvec(x[index[i]],sx[nfr][i]); nfr++; } while (read_next_x(oenv,status,&t,natom,x,box)); /* clean up */ sfree(x); close_trj(status); fprintf(stderr,"Read %d frames\n",nfr); dt = (time[nfr-1] - time[0])/(nfr - 1); /* Some ugly rounding to get nice nice times in the output */ dt = (int)(10000.0*dt + 0.5)/10000.0; invbin = 1.0/rbin; if (matfile) { if (fmmax <= 0 || fmmax >= nfr) fmmax = nfr - 1; snew(mcount,fmmax); nbin = (int)(rmax*invbin + 0.5); if (sbin == 0) { mat_nx = fmmax + 1; } else { invsbin = 1.0/sbin; mat_nx = sqrt(fmmax*dt)*invsbin + 1; } snew(mat,mat_nx); for(f=0; f<mat_nx; f++) snew(mat[f],nbin); rmax2 = sqr(nbin*rbin); /* Initialize time zero */ mat[0][0] = nfr*isize; mcount[0] += nfr; } else { fmmax = 0; } if (orfile) { snew(pr,nr); nalloc = 0; snew(rcount,nr); } if (otfile) { if (ftmax <= 0) ftmax = nfr - 1; snew(tcount,ftmax); snew(pt,nfr); rint2 = rint*rint; /* Initialize time zero */ pt[0] = nfr*isize; tcount[0] += nfr; } else { ftmax = 0; } msmul(avbox,1.0/nfr,avbox); for(f=0; f<nfr; f++) { if (f % 100 == 0) fprintf(stderr,"\rProcessing frame %d",f); /* Scale all the configuration to the average box */ m_inv_ur0(sbox[f],corr); mmul_ur0(avbox,corr,corr); for(i=0; i<isize; i++) { mvmul_ur0(corr,sx[f][i],sx[f][i]); if (f > 0) { /* Correct for periodic jumps */ for(m=DIM-1; m>=0; m--) { while(sx[f][i][m] - sx[f-1][i][m] > 0.5*avbox[m][m]) rvec_dec(sx[f][i],avbox[m]); while(sx[f][i][m] - sx[f-1][i][m] <= -0.5*avbox[m][m]) rvec_inc(sx[f][i],avbox[m]); } } } for(ff=0; ff<f; ff++) { fbin = f - ff; if (fbin <= fmmax || fbin <= ftmax) { if (sbin == 0) mbin = fbin; else mbin = (int)(sqrt(fbin*dt)*invsbin + 0.5); for(i=0; i<isize; i++) { d2 = distance2(sx[f][i],sx[ff][i]); if (mbin < mat_nx && d2 < rmax2) { bin = (int)(sqrt(d2)*invbin + 0.5); if (bin < nbin) { mat[mbin][bin] += 1; } } if (fbin <= ftmax && d2 <= rint2) pt[fbin]++; } if (matfile) mcount[mbin]++; if (otfile) tcount[fbin]++; } } if (orfile) { for(fbin=0; fbin<nr; fbin++) { ff = f - (fbin + 1)*fshift; if (ff >= 0) { for(i=0; i<isize; i++) { d2 = distance2(sx[f][i],sx[ff][i]); bin = (int)(sqrt(d2)*invbin); if (bin >= nalloc) { nallocn = 10*(bin/10) + 11; for(m=0; m<nr; m++) { srenew(pr[m],nallocn); for(i=nalloc; i<nallocn; i++) pr[m][i] = 0; } nalloc = nallocn; } pr[fbin][bin]++; } rcount[fbin]++; } } } } fprintf(stderr,"\n"); if (matfile) { matmax = 0; for(f=0; f<mat_nx; f++) { normfac = 1.0/(mcount[f]*isize*rbin); for(i=0; i<nbin; i++) { mat[f][i] *= normfac; if (mat[f][i] > matmax && (f!=0 || i!=0)) matmax = mat[f][i]; } } fprintf(stdout,"Value at (0,0): %.3f, maximum of the rest %.3f\n", mat[0][0],matmax); if (mmax > 0) matmax = mmax; snew(tickx,mat_nx); for(f=0; f<mat_nx; f++) { if (sbin == 0) tickx[f] = f*dt; else tickx[f] = f*sbin; } snew(ticky,nbin+1); for(i=0; i<=nbin; i++) ticky[i] = i*rbin; fp = ffopen(matfile,"w"); write_xpm(fp,MAT_SPATIAL_Y,"Van Hove function","G (1/nm)", sbin==0 ? "time (ps)" : "sqrt(time) (ps^1/2)","r (nm)", mat_nx,nbin,tickx,ticky,mat,0,matmax,rlo,rhi,&nlev); ffclose(fp); } if (orfile) { fp = xvgropen(orfile,"Van Hove function","r (nm)","G (nm\\S-1\\N)",oenv); fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname); snew(legend,nr); for(fbin=0; fbin<nr; fbin++) { sprintf(buf,"%g ps",(fbin + 1)*fshift*dt); legend[fbin] = strdup(buf); } xvgr_legend(fp,nr,(const char**)legend,oenv); for(i=0; i<nalloc; i++) { fprintf(fp,"%g",i*rbin); for(fbin=0; fbin<nr; fbin++) fprintf(fp," %g", (real)pr[fbin][i]/(rcount[fbin]*isize*rbin*(i==0 ? 0.5 : 1))); fprintf(fp,"\n"); } ffclose(fp); } if (otfile) { sprintf(buf,"Probability of moving less than %g nm",rint); fp = xvgropen(otfile,buf,"t (ps)","",oenv); fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname); for(f=0; f<=ftmax; f++) fprintf(fp,"%g %g\n",f*dt,(real)pt[f]/(tcount[f]*isize)); ffclose(fp); } do_view(oenv, matfile,NULL); do_view(oenv, orfile,NULL); do_view(oenv, otfile,NULL); thanx(stderr); return 0; }
void parrinellorahman_pcoupl(FILE *fplog,gmx_step_t step, t_inputrec *ir,real dt,tensor pres, tensor box,tensor box_rel,tensor boxv, tensor M,matrix mu,bool bFirstStep) { /* This doesn't do any coordinate updating. It just * integrates the box vector equations from the calculated * acceleration due to pressure difference. We also compute * the tensor M which is used in update to couple the particle * coordinates to the box vectors. * * In Nose and Klein (Mol.Phys 50 (1983) no 5., p 1055) this is * given as * -1 . . -1 * M_nk = (h') * (h' * h + h' h) * h * * with the dots denoting time derivatives and h is the transformation from * the scaled frame to the real frame, i.e. the TRANSPOSE of the box. * This also goes for the pressure and M tensors - they are transposed relative * to ours. Our equation thus becomes: * * -1 . . -1 * M_gmx = M_nk' = b * (b * b' + b * b') * b' * * where b is the gromacs box matrix. * Our box accelerations are given by * .. .. * b = vol/W inv(box') * (P-ref_P) (=h') */ int d,n; tensor winv; real vol=box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]; real atot,arel,change,maxchange,xy_pressure; tensor invbox,pdiff,t1,t2; real maxl; m_inv_ur0(box,invbox); if (!bFirstStep) { /* Note that PRESFAC does not occur here. * The pressure and compressibility always occur as a product, * therefore the pressure unit drops out. */ maxl=max(box[XX][XX],box[YY][YY]); maxl=max(maxl,box[ZZ][ZZ]); for(d=0;d<DIM;d++) for(n=0;n<DIM;n++) winv[d][n]= (4*M_PI*M_PI*ir->compress[d][n])/(3*ir->tau_p*ir->tau_p*maxl); m_sub(pres,ir->ref_p,pdiff); if(ir->epct==epctSURFACETENSION) { /* Unlike Berendsen coupling it might not be trivial to include a z * pressure correction here? On the other hand we don't scale the * box momentarily, but change accelerations, so it might not be crucial. */ xy_pressure=0.5*(pres[XX][XX]+pres[YY][YY]); for(d=0;d<ZZ;d++) pdiff[d][d]=(xy_pressure-(pres[ZZ][ZZ]-ir->ref_p[d][d]/box[d][d])); } tmmul(invbox,pdiff,t1); /* Move the off-diagonal elements of the 'force' to one side to ensure * that we obey the box constraints. */ for(d=0;d<DIM;d++) { for(n=0;n<d;n++) { t1[d][n] += t1[n][d]; t1[n][d] = 0; } } switch (ir->epct) { case epctANISOTROPIC: for(d=0;d<DIM;d++) for(n=0;n<=d;n++) t1[d][n] *= winv[d][n]*vol; break; case epctISOTROPIC: /* calculate total volume acceleration */ atot=box[XX][XX]*box[YY][YY]*t1[ZZ][ZZ]+ box[XX][XX]*t1[YY][YY]*box[ZZ][ZZ]+ t1[XX][XX]*box[YY][YY]*box[ZZ][ZZ]; arel=atot/(3*vol); /* set all RELATIVE box accelerations equal, and maintain total V * change speed */ for(d=0;d<DIM;d++) for(n=0;n<=d;n++) t1[d][n] = winv[0][0]*vol*arel*box[d][n]; break; case epctSEMIISOTROPIC: case epctSURFACETENSION: /* Note the correction to pdiff above for surftens. coupling */ /* calculate total XY volume acceleration */ atot=box[XX][XX]*t1[YY][YY]+t1[XX][XX]*box[YY][YY]; arel=atot/(2*box[XX][XX]*box[YY][YY]); /* set RELATIVE XY box accelerations equal, and maintain total V * change speed. Dont change the third box vector accelerations */ for(d=0;d<ZZ;d++) for(n=0;n<=d;n++) t1[d][n] = winv[d][n]*vol*arel*box[d][n]; for(n=0;n<DIM;n++) t1[ZZ][n] *= winv[d][n]*vol; break; default: gmx_fatal(FARGS,"Parrinello-Rahman pressure coupling type %s " "not supported yet\n",EPCOUPLTYPETYPE(ir->epct)); break; } maxchange=0; for(d=0;d<DIM;d++) for(n=0;n<=d;n++) { boxv[d][n] += dt*t1[d][n]; /* We do NOT update the box vectors themselves here, since * we need them for shifting later. It is instead done last * in the update() routine. */ /* Calculate the change relative to diagonal elements - * since it's perfectly ok for the off-diagonal ones to * be zero it doesn't make sense to check the change relative * to its current size. */ change=fabs(dt*boxv[d][n]/box[d][d]); if(change>maxchange) maxchange=change; } if (maxchange > 0.01 && fplog) { char buf[22]; fprintf(fplog,"\nStep %s Warning: Pressure scaling more than 1%%.\n", gmx_step_str(step,buf)); } } preserve_box_shape(ir,box_rel,boxv); mtmul(boxv,box,t1); /* t1=boxv * b' */ mmul(invbox,t1,t2); mtmul(t2,invbox,M); /* Determine the scaling matrix mu for the coordinates */ for(d=0;d<DIM;d++) for(n=0;n<=d;n++) t1[d][n] = box[d][n] + dt*boxv[d][n]; preserve_box_shape(ir,box_rel,t1); /* t1 is the box at t+dt, determine mu as the relative change */ mmul_ur0(invbox,t1,mu); }