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];
    }
}
Exemple #2
0
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;
}
Exemple #3
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);
}