Пример #1
0
void reset_x_ndim(int ndim,int ncm,atom_id ind_cm[],
		  int nreset,atom_id *ind_reset,rvec x[],real mass[])
{
  int  i,m,ai;
  rvec xcm;
  real tm,mm;
  
  tm=0.0;
  clear_rvec(xcm);
  for(i=0; i<ncm; i++) {
    ai=ind_cm[i];
    mm=mass[ai];
    for(m=0; m<ndim; m++)
      xcm[m]+=mm*x[ai][m];
    tm+=mm;
  }
  for(m=0; m<ndim; m++)
    xcm[m]/=tm;
    
  if (ind_reset)
    for(i=0; i<nreset; i++)
      rvec_dec(x[ind_reset[i]],xcm);
  else
    for(i=0; i<nreset; i++)
      rvec_dec(x[i],xcm);
}
Пример #2
0
void reset_x_ndim(int ndim,int ncm,const atom_id *ind_cm,
                  int nreset,const atom_id *ind_reset,
                  rvec x[],const real mass[])
{
    int  i,m,ai;
    rvec xcm;
    real tm,mm;

    if (ndim>DIM)
    {
        gmx_incons("More than 3 dimensions not supported.");
    }
    tm = 0.0;
    clear_rvec(xcm);
    if (ind_cm != NULL)
    {
        for(i=0; i<ncm; i++)
        {
            ai = ind_cm[i];
            mm = mass[ai];
            for(m=0; m<ndim; m++)
            {
                xcm[m] += mm*x[ai][m];
            }
            tm += mm;
        }
    }
    else
    {
        for(i=0; i<ncm; i++)
        {
            mm = mass[i];
            for(m=0; m<ndim; m++)
            {
                xcm[m] += mm*x[i][m];
            }
            tm += mm;
        }
    }
    for(m=0; m<ndim; m++)
    {
        xcm[m] /= tm;
    }

    if (ind_reset != NULL)
    {
        for(i=0; i<nreset; i++)
        {
            rvec_dec(x[ind_reset[i]],xcm);
        }
    }
    else
    {
        for(i=0; i<nreset; i++)
        {
            rvec_dec(x[i],xcm);
        }
    }
}
Пример #3
0
static void calc_axes(rvec x[],t_atom atom[],int gnx[],atom_id *index[],
		      gmx_bool bRot,t_bundle *bun)
{
  int  end,i,div,d;
  real *mtot,m;
  rvec axis[MAX_ENDS],cent;
  
  snew(mtot,bun->n);

  for(end=0; end<bun->nend; end++) {
    for(i=0; i<bun->n; i++) {
      clear_rvec(bun->end[end][i]);
      mtot[i] = 0;
    }
    div = gnx[end]/bun->n;
    for(i=0; i<gnx[end]; i++) {
      m = atom[index[end][i]].m;
      for(d=0; d<DIM; d++)
	bun->end[end][i/div][d] += m*x[index[end][i]][d];
      mtot[i/div] += m;
    }
    clear_rvec(axis[end]);
    for(i=0; i<bun->n; i++) {
      svmul(1.0/mtot[i],bun->end[end][i],bun->end[end][i]);
      rvec_inc(axis[end],bun->end[end][i]);
    }
    svmul(1.0/bun->n,axis[end],axis[end]);
  }
  sfree(mtot);

  rvec_add(axis[0],axis[1],cent);
  svmul(0.5,cent,cent);
  /* center the bundle on the origin */
  for(end=0; end<bun->nend; end++) {
    rvec_dec(axis[end],cent);
    for(i=0; i<bun->n; i++)
      rvec_dec(bun->end[end][i],cent);
  }
  if (bRot) {
    /* rotate the axis parallel to the z-axis */
    rotate_ends(bun,axis[0],YY,ZZ);
    rotate_ends(bun,axis[0],XX,ZZ);
  }
  for(i=0; i<bun->n; i++) {
    rvec_add(bun->end[0][i],bun->end[1][i],bun->mid[i]);
    svmul(0.5,bun->mid[i],bun->mid[i]);
    rvec_sub(bun->end[0][i],bun->end[1][i],bun->dir[i]);
    bun->len[i] = norm(bun->dir[i]);
    unitv(bun->dir[i],bun->dir[i]);
  }
}
Пример #4
0
/* prepare the coordinates by removing periodic boundary crossings.
   gnx = the number of atoms/molecules
   index = the indices
   xcur = the current coordinates
   xprev = the previous coordinates
   box = the box matrix */
static void prep_data(gmx_bool bMol,int gnx,atom_id index[],
		      rvec xcur[],rvec xprev[],matrix box)
{
    int  i,m,ind;
    rvec hbox;

    /* Remove periodicity */
    for(m=0; (m<DIM); m++)
        hbox[m]=0.5*box[m][m];
    
    for(i=0; (i<gnx); i++) {
        if (bMol)
            ind = i;
        else
            ind = index[i];

        for(m=DIM-1; m>=0; m--) 
        {
            while(xcur[ind][m]-xprev[ind][m] <= -hbox[m])
                rvec_inc(xcur[ind],box[m]);
            while(xcur[ind][m]-xprev[ind][m] >  hbox[m])
                rvec_dec(xcur[ind],box[m]);
        }      
    }
}
Пример #5
0
static void center_coords(t_atoms *atoms, matrix box, rvec x0[], int axis)
{
    int  i, m;
    real tmass, mm;
    rvec com, shift, box_center;

    tmass = 0;
    clear_rvec(com);
    for (i = 0; (i < atoms->nr); i++)
    {
        mm     = atoms->atom[i].m;
        tmass += mm;
        for (m = 0; (m < DIM); m++)
        {
            com[m] += mm*x0[i][m];
        }
    }
    for (m = 0; (m < DIM); m++)
    {
        com[m] /= tmass;
    }
    calc_box_center(ecenterDEF, box, box_center);
    rvec_sub(box_center, com, shift);
    shift[axis] -= box_center[axis];

    for (i = 0; (i < atoms->nr); i++)
    {
        rvec_dec(x0[i], shift);
    }
}
Пример #6
0
void do_stopcm_grp(FILE *fp,int start,int homenr,unsigned short *group_id,
		   rvec x[],rvec v[],t_vcm *vcm)
{
  int  i,g,m;
  real tm,tm_1;
  rvec dv,dx;
  
  if (vcm->mode != ecmNO) {
    /* Subtract linear momentum */
    g = 0;
    switch (vcm->ndim) {
    case 1:
      for(i=start; (i<start+homenr); i++) {
	if (group_id)
	  g = group_id[i];
	v[i][XX] -= vcm->group_v[g][XX];
      }
      break;
    case 2:
      for(i=start; (i<start+homenr); i++) {
	if (group_id)
	  g = group_id[i];
	v[i][XX] -= vcm->group_v[g][XX];
	v[i][YY] -= vcm->group_v[g][YY];
      }
      break;
    case 3:
      for(i=start; (i<start+homenr); i++) {
	if (group_id)
	  g = group_id[i];
	rvec_dec(v[i],vcm->group_v[g]);
      }
      break;
    }
    if (vcm->mode == ecmANGULAR) {
      /* Subtract angular momentum */
      for(i=start; (i<start+homenr); i++) {
	if (group_id)
	  g = group_id[i];
	/* Compute the correction to the velocity for each atom */
	rvec_sub(x[i],vcm->group_x[g],dx);
	cprod(vcm->group_w[g],dx,dv);
	rvec_dec(v[i],dv);
      }
    }
  }
}
Пример #7
0
static void my_sub_xcm(int nbb,atom_id bbind[],rvec x[],rvec xcm)
{
  int i,ai;
  
  for(i=0; (i<nbb); i++) {
    ai=bbind[i];
    rvec_dec(x[ai],xcm);
  }
}
Пример #8
0
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;
}
Пример #9
0
static void center_molecule(int atomCount, rvec x[])
{
    rvec center;
    clear_rvec(center);
    for (int i = 0; i < atomCount; ++i)
    {
        rvec_inc(center, x[i]);
    }
    svmul(1.0/atomCount, center, center);
    for (int i = 0; i < atomCount; ++i)
    {
        rvec_dec(x[i], center);
    }
}
Пример #10
0
static int correct_box_elem(FILE *fplog, int step, tensor box, int v, int d)
{
    int shift, maxshift = 10;

    shift = 0;

    /* correct elem d of vector v with vector d */
    while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d])
    {
        if (fplog)
        {
            fprintf(fplog, "Step %d: correcting invalid box:\n", step);
            pr_rvecs(fplog, 0, "old box", box, DIM);
        }
        rvec_dec(box[v], box[d]);
        shift--;
        if (fplog)
        {
            pr_rvecs(fplog, 0, "new box", box, DIM);
        }
        if (shift <= -maxshift)
        {
            gmx_fatal(FARGS,
                      "Box was shifted at least %d times. Please see log-file.",
                      maxshift);
        }
    }
    while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d])
    {
        if (fplog)
        {
            fprintf(fplog, "Step %d: correcting invalid box:\n", step);
            pr_rvecs(fplog, 0, "old box", box, DIM);
        }
        rvec_inc(box[v], box[d]);
        shift++;
        if (fplog)
        {
            pr_rvecs(fplog, 0, "new box", box, DIM);
        }
        if (shift >= maxshift)
        {
            gmx_fatal(FARGS,
                      "Box was shifted at least %d times. Please see log-file.",
                      maxshift);
        }
    }

    return shift;
}
Пример #11
0
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];
    }
}
Пример #12
0
void print_constraint(t_pull *pull, rvec *f, int step, matrix box, int niter) 
{
  int i,ii,m; 
  rvec tmp,tmp2,tmp3;

  for (i=0;i<pull->pull.n;i++) {
    if (pull->bCyl) 
      rvec_sub(pull->pull.x_con[i],pull->dyna.x_con[i],tmp);
    else 
      rvec_sub(pull->pull.x_con[i],pull->ref.x_con[0],tmp);
    for (m=DIM-1; m>=0; m--) {
      if (tmp[m] < -0.5*box[m][m]) rvec_inc(tmp,box[m]);
      if (tmp[m] >  0.5*box[m][m]) rvec_dec(tmp,box[m]);
      tmp[m] *= pull->dims[m];
    }
    if (pull->bVerbose) 
      fprintf(pull->out,"%d:%d ds:%e f:%e n:%d\n", step,i,norm(tmp),
	      pull->pull.f[i][ZZ],niter);
    else
      fprintf(pull->out,"%e ",pull->pull.f[i][ZZ]);
  }

  if (!pull->bVerbose)
    fprintf(pull->out,"\n");

  /* DEBUG */ /* this code doesn't correct for pbc, needs improvement */
  if (pull->bVerbose) {
    for (i=0;i<pull->pull.n;i++) {
      if (pull->bCyl) 
	fprintf(pull->out,"eConstraint: step %d. Refgroup = dynamic (%f,%f\n"
		"Group %d (%s): ref. dist = %8.3f, unconstr. dist = %8.3f"
		" con. dist = %8.3f f_i = %8.3f\n", step, pull->r,pull->rc,
		i,pull->pull.grps[i],
		pull->dyna.x_ref[i][ZZ]-pull->pull.x_ref[i][ZZ],
		pull->dyna.x_unc[i][ZZ]-pull->pull.x_unc[i][ZZ],
		pull->dyna.x_con[i][ZZ]-pull->pull.x_con[i][ZZ],
		pull->pull.f[i][ZZ]);
      else {
	rvec_sub(pull->ref.x_ref[0],pull->pull.x_ref[i],tmp);
	rvec_sub(pull->ref.x_unc[0],pull->pull.x_unc[i],tmp2);
	rvec_sub(pull->ref.x_con[0],pull->pull.x_con[i],tmp3);
	fprintf(stderr,"grp %d:ref (%8.3f,%8.3f,%8.3f) unc(%8.3f%8.3f%8.3f\n"
		"con (%8.3f%8.3f%8.3f)\n",i, tmp[0],tmp[1],tmp[2],
		tmp2[0],tmp2[1],tmp2[2],tmp3[0],tmp3[1],tmp3[2]);
      }
    }
  } /* END DEBUG */

}
Пример #13
0
/* prepare the coordinates by removing periodic boundary crossings.
   gnx = the number of atoms/molecules
   index = the indices
   xcur = the current coordinates
   xprev = the previous coordinates
   box = the box matrix */
static void prep_data(gmx_bool bMol, int gnx, int index[],
                      rvec xcur[], rvec xprev[], matrix box)
{
    int  i, m, ind;
    rvec hbox;

    /* Remove periodicity */
    for (m = 0; (m < DIM); m++)
    {
        hbox[m] = 0.5*box[m][m];
    }

    for (i = 0; (i < gnx); i++)
    {
        if (bMol)
        {
            ind = i;
        }
        else
        {
            ind = index[i];
        }

        for (m = DIM-1; m >= 0; m--)
        {
            if (hbox[m] == 0)
            {
                continue;
            }
            while (xcur[ind][m]-xprev[ind][m] <= -hbox[m])
            {
                rvec_inc(xcur[ind], box[m]);
            }
            while (xcur[ind][m]-xprev[ind][m] >  hbox[m])
            {
                rvec_dec(xcur[ind], box[m]);
            }
        }
    }
}
Пример #14
0
void correct_t0_pbc(t_pull *pull, rvec x[], t_mdatoms *md, matrix box) {
  int i,ii,j,m;
  real tm;
  rvec com,dx;

  /* loop over all atoms in index for group i. Check if they moved
     more than half a box with respect to xp. If so add/subtract a box 
     from x0. Copy x to xp.
   */
  for (i=0;i<pull->ref.ngx[0];i++) {
    ii = pull->ref.idx[0][i];
    
    /* correct for jumps across the box */
    rvec_sub(x[ii],pull->ref.xp[0][i],dx);
    for (m=DIM-1; m>=0; m--) {
      if (dx[m] < -0.5*box[m][m]) {
	rvec_inc(dx,box[m]);
	if (pull->bVerbose && fabs(pull->dims[m])>GMX_REAL_MIN)
	  fprintf(stderr,"Jumped +box: nr %d dir: %d old:%8.3f\n",ii,m,
		  pull->ref.x0[0][i][m]); 
      }
      
      if (dx[m] >  0.5*box[m][m]) {
	rvec_dec(dx,box[m]);
	if (pull->bVerbose && fabs(pull->dims[m])>GMX_REAL_MIN)
	  fprintf(stderr,"Jumped -box: nr %d dir: %d old:%8.3f\n",ii,m,
		  pull->ref.x0[0][i][m]); 
      }

      pull->ref.x0[0][i][m] += dx[m];
      pull->ref.xp[0][i][m]  = x[ii][m];
    }
  }
  tm = calc_com2(pull->ref.x0[0],pull->ref.ngx[0],pull->ref.idx[0],
		 md,com,box);
  if (pull->bVerbose) 
    fprintf(stderr,"correct_t0: Group %s: mass:%8.3f com:%8.3f%8.3f%8.3f\n",
	    pull->ref.grps[0],tm,com[0],com[1],com[2]);
}
Пример #15
0
/* calculates com of all atoms in x[], *index has their index numbers
   to get the masses from atom[] */
real calc_com2(rvec x[],int gnx,atom_id *index,t_mdatoms *md,rvec com,
	       matrix box)
{
  int  i,ii,m;
  real m0,tm;

  clear_rvec(com);
  tm=0;
  for(i=0; (i<gnx); i++) {
    ii=index[i];
    m0=md->massT[ii];
    tm+=m0;
    for(m=0; (m<DIM); m++)
      com[m]+=m0*x[i][m];
  }
  svmul(1/tm,com,com);
  for(m=DIM-1; m>=0; m--) {
    /* next two lines used to be commented out */
    if (com[m] < 0        ) rvec_inc(com,box[m]);
    if (com[m] > box[m][m]) rvec_dec(com,box[m]); 
  }
  return tm;
}
Пример #16
0
void calc_rm_cm(int isize, atom_id index[], t_atoms *atoms, rvec x[], rvec xcm)
{
    int  i, d;
    real tm, m;

    /* calculate and remove center of mass of reference structure */
    tm = 0;
    clear_rvec(xcm);
    for (i = 0; i < isize; i++)
    {
        m = atoms->atom[index[i]].m;
        for (d = 0; d < DIM; d++)
        {
            xcm[d] += m*x[index[i]][d];
        }
        tm += m;
    }
    svmul(1/tm, xcm, xcm);
    for (i = 0; i < atoms->nr; i++)
    {
        rvec_dec(x[i], xcm);
    }
}
Пример #17
0
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);
    }
}
Пример #18
0
void center_coords(t_atoms *atoms, atom_id *index_center, int ncenter,
                   matrix box, rvec x0[])
{
    int  i, k, m;
    real tmass, mm;
    rvec com, shift, box_center;

    tmass = 0;
    clear_rvec(com);
    for (k = 0; (k < ncenter); k++)
    {
        i = index_center[k];
        if (i >= atoms->nr)
        {
            gmx_fatal(FARGS, "Index %d refers to atom %d, which is larger than natoms (%d).",
                      k+1, i+1, atoms->nr);
        }
        mm     = atoms->atom[i].m;
        tmass += mm;
        for (m = 0; (m < DIM); m++)
        {
            com[m] += mm*x0[i][m];
        }
    }
    for (m = 0; (m < DIM); m++)
    {
        com[m] /= tmass;
    }
    calc_box_center(ecenterDEF, box, box_center);
    rvec_sub(box_center, com, shift);

    /* Important - while the center was calculated based on a group, we should move all atoms */
    for (i = 0; (i < atoms->nr); i++)
    {
        rvec_dec(x0[i], shift);
    }
}
Пример #19
0
int gmx_editconf(int argc, char *argv[])
{
    const char
        *desc[] =
            {
                "editconf converts generic structure format to [TT].gro[tt], [TT].g96[tt]",
                "or [TT].pdb[tt].",
                "[PAR]",
                "The box can be modified with options [TT]-box[tt], [TT]-d[tt] and",
                "[TT]-angles[tt]. Both [TT]-box[tt] and [TT]-d[tt]",
                "will center the system in the box, unless [TT]-noc[tt] is used.",
                "[PAR]",
                "Option [TT]-bt[tt] determines the box type: [TT]triclinic[tt] is a",
                "triclinic box, [TT]cubic[tt] is a rectangular box with all sides equal",
                "[TT]dodecahedron[tt] represents a rhombic dodecahedron and",
                "[TT]octahedron[tt] is a truncated octahedron.",
                "The last two are special cases of a triclinic box.",
                "The length of the three box vectors of the truncated octahedron is the",
                "shortest distance between two opposite hexagons.",
                "The volume of a dodecahedron is 0.71 and that of a truncated octahedron",
                "is 0.77 of that of a cubic box with the same periodic image distance.",
                "[PAR]",
                "Option [TT]-box[tt] requires only",
                "one value for a cubic box, dodecahedron and a truncated octahedron.",
                "[PAR]",
                "With [TT]-d[tt] and a [TT]triclinic[tt] box the size of the system in the x, y",
                "and z directions is used. With [TT]-d[tt] and [TT]cubic[tt],",
                "[TT]dodecahedron[tt] or [TT]octahedron[tt] boxes, the dimensions are set",
                "to the diameter of the system (largest distance between atoms) plus twice",
                "the specified distance.",
                "[PAR]",
                "Option [TT]-angles[tt] is only meaningful with option [TT]-box[tt] and",
                "a triclinic box and can not be used with option [TT]-d[tt].",
                "[PAR]",
                "When [TT]-n[tt] or [TT]-ndef[tt] is set, a group",
                "can be selected for calculating the size and the geometric center,",
                "otherwise the whole system is used.",
                "[PAR]",
                "[TT]-rotate[tt] rotates the coordinates and velocities.",
                "[PAR]",
                "[TT]-princ[tt] aligns the principal axes of the system along the",
                "coordinate axes, this may allow you to decrease the box volume,",
                "but beware that molecules can rotate significantly in a nanosecond.",
                "[PAR]",
                "Scaling is applied before any of the other operations are",
                "performed. Boxes and coordinates can be scaled to give a certain density (option",
                "[TT]-density[tt]). Note that this may be inaccurate in case a gro",
                "file is given as input. A special feature of the scaling option, when the",
                "factor -1 is given in one dimension, one obtains a mirror image,",
                "mirrored in one of the plains, when one uses -1 in three dimensions",
                "a point-mirror image is obtained.[PAR]",
                "Groups are selected after all operations have been applied.[PAR]",
                "Periodicity can be removed in a crude manner.",
                "It is important that the box sizes at the bottom of your input file",
                "are correct when the periodicity is to be removed.",
                "[PAR]",
                "When writing [TT].pdb[tt] files, B-factors can be",
                "added with the [TT]-bf[tt] option. B-factors are read",
                "from a file with with following format: first line states number of",
                "entries in the file, next lines state an index",
                "followed by a B-factor. The B-factors will be attached per residue",
                "unless an index is larger than the number of residues or unless the",
                "[TT]-atom[tt] option is set. Obviously, any type of numeric data can",
                "be added instead of B-factors. [TT]-legend[tt] will produce",
                "a row of CA atoms with B-factors ranging from the minimum to the",
                "maximum value found, effectively making a legend for viewing.",
                "[PAR]",
                "With the option -mead a special pdb (pqr) file for the MEAD electrostatics",
                "program (Poisson-Boltzmann solver) can be made. A further prerequisite",
                "is that the input file is a run input file.",
                "The B-factor field is then filled with the Van der Waals radius",
                "of the atoms while the occupancy field will hold the charge.",
                "[PAR]",
                "The option -grasp is similar, but it puts the charges in the B-factor",
                "and the radius in the occupancy.",
                "[PAR]",
                "Option [TT]-align[tt] allows alignment",
                "of the principal axis of a specified group against the given vector, ",
				"with an optional center of rotation specified by [TT]-aligncenter[tt].",
                "[PAR]",
                "Finally with option [TT]-label[tt] editconf can add a chain identifier",
                "to a pdb file, which can be useful for analysis with e.g. rasmol.",
                    "[PAR]",
                "To convert a truncated octrahedron file produced by a package which uses",
                "a cubic box with the corners cut off (such as Gromos) use:[BR]",
                "[TT]editconf -f <in> -rotate 0 45 35.264 -bt o -box <veclen> -o <out>[tt][BR]",
                "where [TT]veclen[tt] is the size of the cubic box times sqrt(3)/2." };
    const char *bugs[] =
        {
            "For complex molecules, the periodicity removal routine may break down, ",
                "in that case you can use trjconv." };
    static real dist = 0.0, rbox = 0.0, to_diam = 0.0;
    static gmx_bool bNDEF = FALSE, bRMPBC = FALSE, bCenter = FALSE, bReadVDW =
        FALSE, bCONECT = FALSE;
    static gmx_bool peratom = FALSE, bLegend = FALSE, bOrient = FALSE, bMead =
        FALSE, bGrasp = FALSE, bSig56 = FALSE;
    static rvec scale =
        { 1, 1, 1 }, newbox =
        { 0, 0, 0 }, newang =
        { 90, 90, 90 };
    static real rho = 1000.0, rvdw = 0.12;
    static rvec center =
        { 0, 0, 0 }, translation =
        { 0, 0, 0 }, rotangles =
        { 0, 0, 0 }, aligncenter =
		{ 0, 0, 0 }, targetvec =
        { 0, 0, 0 };
    static const char *btype[] =
        { NULL, "triclinic", "cubic", "dodecahedron", "octahedron", NULL },
        *label = "A";
    static rvec visbox =
        { 0, 0, 0 };
    t_pargs
        pa[] =
            {
                    { "-ndef", FALSE, etBOOL,
                        { &bNDEF }, "Choose output from default index groups" },
                    { "-visbox", FALSE, etRVEC,
                        { visbox },
                        "HIDDENVisualize a grid of boxes, -1 visualizes the 14 box images" },
                    { "-bt", FALSE, etENUM,
                        { btype }, "Box type for -box and -d" },
                    { "-box", FALSE, etRVEC,
                        { newbox }, "Box vector lengths (a,b,c)" },
                    { "-angles", FALSE, etRVEC,
                        { newang }, "Angles between the box vectors (bc,ac,ab)" },
                    { "-d", FALSE, etREAL,
                        { &dist }, "Distance between the solute and the box" },
                    { "-c", FALSE, etBOOL,
                        { &bCenter },
                        "Center molecule in box (implied by -box and -d)" },
                    { "-center", FALSE, etRVEC,
                        { center }, "Coordinates of geometrical center" },
                    { "-aligncenter", FALSE, etRVEC,
                        { aligncenter }, "Center of rotation for alignment" },
                    { "-align", FALSE, etRVEC,
                        { targetvec },
                        "Align to target vector" },
                    { "-translate", FALSE, etRVEC,
                        { translation }, "Translation" },
                    { "-rotate", FALSE, etRVEC,
                        { rotangles },
                        "Rotation around the X, Y and Z axes in degrees" },
                    { "-princ", FALSE, etBOOL,
                        { &bOrient },
                        "Orient molecule(s) along their principal axes" },
                    { "-scale", FALSE, etRVEC,
                        { scale }, "Scaling factor" },
                    { "-density", FALSE, etREAL,
                        { &rho },
                        "Density (g/l) of the output box achieved by scaling" },
                    { "-pbc", FALSE, etBOOL,
                        { &bRMPBC },
                        "Remove the periodicity (make molecule whole again)" },
                    { "-grasp", FALSE, etBOOL,
                        { &bGrasp },
                        "Store the charge of the atom in the B-factor field and the radius of the atom in the occupancy field" },
                    {
                        "-rvdw", FALSE, etREAL,
                         { &rvdw },
                        "Default Van der Waals radius (in nm) if one can not be found in the database or if no parameters are present in the topology file" },
                    { "-sig56", FALSE, etREAL,
                        { &bSig56 },
                        "Use rmin/2 (minimum in the Van der Waals potential) rather than sigma/2 " },
                    {
                        "-vdwread", FALSE, etBOOL,
                        { &bReadVDW },
                        "Read the Van der Waals radii from the file vdwradii.dat rather than computing the radii based on the force field" },
                    { "-atom", FALSE, etBOOL,
                        { &peratom }, "Force B-factor attachment per atom" },
                    { "-legend", FALSE, etBOOL,
                        { &bLegend }, "Make B-factor legend" },
                    { "-label", FALSE, etSTR,
                        { &label }, "Add chain label for all residues" },
                    {
                        "-conect", FALSE, etBOOL,
                        { &bCONECT },
                        "Add CONECT records to a pdb file when written. Can only be done when a topology is present" } };
#define NPA asize(pa)

    FILE *out;
    const char *infile, *outfile;
    char title[STRLEN];
    int outftp, inftp, natom, i, j, n_bfac, itype, ntype;
    double *bfac = NULL, c6, c12;
    int *bfac_nr = NULL;
    t_topology *top = NULL;
    t_atoms atoms;
    char *grpname, *sgrpname, *agrpname;
    int isize, ssize, tsize, asize;
    atom_id *index, *sindex, *tindex, *aindex;
    rvec *x, *v, gc, min, max, size;
    int ePBC;
    matrix box,rotmatrix,trans;
	rvec princd,tmpvec;
    gmx_bool bIndex, bSetSize, bSetAng, bCubic, bDist, bSetCenter, bAlign;
    gmx_bool bHaveV, bScale, bRho, bTranslate, bRotate, bCalcGeom, bCalcDiam;
    real xs, ys, zs, xcent, ycent, zcent, diam = 0, mass = 0, d, vdw;
    gmx_atomprop_t aps;
    gmx_conect conect;
    output_env_t oenv;
    t_filenm fnm[] =
        {
            { efSTX, "-f", NULL, ffREAD },
            { efNDX, "-n", NULL, ffOPTRD },
            { efSTO, NULL, NULL, ffOPTWR },
            { efPQR, "-mead", "mead", ffOPTWR },
            { efDAT, "-bf", "bfact", ffOPTRD } };
#define NFILE asize(fnm)

    CopyRight(stderr, argv[0]);
    parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa,
                      asize(desc), desc, asize(bugs), bugs, &oenv);

    bIndex = opt2bSet("-n", NFILE, fnm) || bNDEF;
    bMead = opt2bSet("-mead", NFILE, fnm);
    bSetSize = opt2parg_bSet("-box", NPA, pa);
    bSetAng = opt2parg_bSet("-angles", NPA, pa);
    bSetCenter = opt2parg_bSet("-center", NPA, pa);
    bDist = opt2parg_bSet("-d", NPA, pa);
	bAlign = opt2parg_bSet("-align", NPA, pa);
    /* Only automatically turn on centering without -noc */
    if ((bDist || bSetSize || bSetCenter) && !opt2parg_bSet("-c", NPA, pa))
    {
        bCenter = TRUE;
    }
    bScale = opt2parg_bSet("-scale", NPA, pa);
    bRho = opt2parg_bSet("-density", NPA, pa);
    bTranslate = opt2parg_bSet("-translate", NPA, pa);
    bRotate = opt2parg_bSet("-rotate", NPA, pa);
    if (bScale && bRho)
        fprintf(stderr, "WARNING: setting -density overrides -scale\n");
    bScale = bScale || bRho;
    bCalcGeom = bCenter || bRotate || bOrient || bScale;
    bCalcDiam = btype[0][0] == 'c' || btype[0][0] == 'd' || btype[0][0] == 'o';

    infile = ftp2fn(efSTX, NFILE, fnm);
    if (bMead)
        outfile = ftp2fn(efPQR, NFILE, fnm);
    else
        outfile = ftp2fn(efSTO, NFILE, fnm);
    outftp = fn2ftp(outfile);
    inftp = fn2ftp(infile);

    aps = gmx_atomprop_init();

    if (bMead && bGrasp)
    {
        printf("Incompatible options -mead and -grasp. Turning off -grasp\n");
        bGrasp = FALSE;
    }
    if (bGrasp && (outftp != efPDB))
        gmx_fatal(FARGS, "Output file should be a .pdb file"
        " when using the -grasp option\n");
        if ((bMead || bGrasp) && !((fn2ftp(infile) == efTPR) ||
                (fn2ftp(infile) == efTPA) ||
                (fn2ftp(infile) == efTPB)))
        gmx_fatal(FARGS,"Input file should be a .tp[abr] file"
            " when using the -mead option\n");

        get_stx_coordnum(infile,&natom);
        init_t_atoms(&atoms,natom,TRUE);
        snew(x,natom);
        snew(v,natom);
        read_stx_conf(infile,title,&atoms,x,v,&ePBC,box);
        if (fn2ftp(infile) == efPDB)
        {
            get_pdb_atomnumber(&atoms,aps);
        }
        printf("Read %d atoms\n",atoms.nr);

        /* Get the element numbers if available in a pdb file */
        if (fn2ftp(infile) == efPDB)
        get_pdb_atomnumber(&atoms,aps);

        if (ePBC != epbcNONE)
        {
            real vol = det(box);
            printf("Volume: %g nm^3, corresponds to roughly %d electrons\n",
                vol,100*((int)(vol*4.5)));
        }

        if (bMead || bGrasp || bCONECT)
        top = read_top(infile,NULL);

        if (bMead || bGrasp)
        {
            if (atoms.nr != top->atoms.nr)
            gmx_fatal(FARGS,"Atom numbers don't match (%d vs. %d)",atoms.nr,top->atoms.nr);
        snew(atoms.pdbinfo,top->atoms.nr); 
        ntype = top->idef.atnr;
        for(i=0; (i<atoms.nr); i++) {
            /* Determine the Van der Waals radius from the force field */
            if (bReadVDW) {
                if (!gmx_atomprop_query(aps,epropVDW,
                                        *top->atoms.resinfo[top->atoms.atom[i].resind].name,
                                        *top->atoms.atomname[i],&vdw))
                    vdw = rvdw;
            }
            else {
                itype = top->atoms.atom[i].type;
                c12   = top->idef.iparams[itype*ntype+itype].lj.c12;
                c6    = top->idef.iparams[itype*ntype+itype].lj.c6;
                if ((c6 != 0) && (c12 != 0)) {
                    real sig6; 
                    if (bSig56)
                        sig6 = 2*c12/c6;
                    else
                        sig6 = c12/c6;
                    vdw   = 0.5*pow(sig6,1.0/6.0);
                }
                else
                    vdw = rvdw;
            }
            /* Factor of 10 for nm -> Angstroms */
            vdw *= 10;

            if (bMead) {
                atoms.pdbinfo[i].occup = top->atoms.atom[i].q;
                atoms.pdbinfo[i].bfac  = vdw;
            }
            else {
                atoms.pdbinfo[i].occup = vdw;
                atoms.pdbinfo[i].bfac  = top->atoms.atom[i].q;
            }
        }
    }
    bHaveV=FALSE;
    for (i=0; (i<natom) && !bHaveV; i++)
        for (j=0; (j<DIM) && !bHaveV; j++)
            bHaveV=bHaveV || (v[i][j]!=0);
    printf("%selocities found\n",bHaveV?"V":"No v");

    if (visbox[0] > 0) {
        if (bIndex)
            gmx_fatal(FARGS,"Sorry, can not visualize box with index groups");
        if (outftp != efPDB)
            gmx_fatal(FARGS,"Sorry, can only visualize box with a pdb file");
    } else if (visbox[0] == -1)
        visualize_images("images.pdb",ePBC,box);

    /* remove pbc */
    if (bRMPBC) 
        rm_gropbc(&atoms,x,box);

    if (bCalcGeom) {
        if (bIndex) {
            fprintf(stderr,"\nSelect a group for determining the system size:\n");
            get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),
                      1,&ssize,&sindex,&sgrpname);
        } else {
            ssize = atoms.nr;
            sindex = NULL;
        }
        diam=calc_geom(ssize,sindex,x,gc,min,max,bCalcDiam);
        rvec_sub(max, min, size);
        printf("    system size :%7.3f%7.3f%7.3f (nm)\n",
               size[XX], size[YY], size[ZZ]);
        if (bCalcDiam)
            printf("    diameter    :%7.3f               (nm)\n",diam);
        printf("    center      :%7.3f%7.3f%7.3f (nm)\n", gc[XX], gc[YY], gc[ZZ]);
        printf("    box vectors :%7.3f%7.3f%7.3f (nm)\n", 
               norm(box[XX]), norm(box[YY]), norm(box[ZZ]));
        printf("    box angles  :%7.2f%7.2f%7.2f (degrees)\n",
               norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])),
        norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])),
        norm2(box[YY])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY])));
        printf("    box volume  :%7.2f               (nm^3)\n",det(box));
    }

    if (bRho || bOrient || bAlign)
        mass = calc_mass(&atoms,!fn2bTPX(infile),aps);

    if (bOrient) {
        atom_id *index;
        char    *grpnames;

        /* Get a group for principal component analysis */
        fprintf(stderr,"\nSelect group for the determining the orientation\n");
        get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpnames);

        /* Orient the principal axes along the coordinate axes */
        orient_princ(&atoms,isize,index,natom,x,bHaveV ? v : NULL, NULL);
        sfree(index);
        sfree(grpnames);
    }

    if ( bScale ) {
        /* scale coordinates and box */
        if (bRho) {
            /* Compute scaling constant */
            real vol,dens;

            vol = det(box);
            dens = (mass*AMU)/(vol*NANO*NANO*NANO);
            fprintf(stderr,"Volume  of input %g (nm^3)\n",vol);
            fprintf(stderr,"Mass    of input %g (a.m.u.)\n",mass);
            fprintf(stderr,"Density of input %g (g/l)\n",dens);
            if (vol==0 || mass==0)
                gmx_fatal(FARGS,"Cannot scale density with "
                          "zero mass (%g) or volume (%g)\n",mass,vol);

            scale[XX] = scale[YY] = scale[ZZ] = pow(dens/rho,1.0/3.0);
            fprintf(stderr,"Scaling all box vectors by %g\n",scale[XX]);
        }
        scale_conf(atoms.nr,x,box,scale);
    }

	if (bAlign) {
		if (bIndex) {
            fprintf(stderr,"\nSelect a group that you want to align:\n");
            get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),
                      1,&asize,&aindex,&agrpname);
        } else {
            asize = atoms.nr;
            snew(aindex,asize);
			for (i=0;i<asize;i++)
				aindex[i]=i;
        }
		printf("Aligning %d atoms (out of %d) to %g %g %g, center of rotation %g %g %g\n",asize,natom,
			targetvec[XX],targetvec[YY],targetvec[ZZ],
			aligncenter[XX],aligncenter[YY],aligncenter[ZZ]);
		/*subtract out pivot point*/
		for(i=0; i<asize; i++)
			rvec_dec(x[aindex[i]],aligncenter);
		/*now determine transform and rotate*/
		/*will this work?*/
		principal_comp(asize,aindex,atoms.atom,x, trans,princd);

		unitv(targetvec,targetvec);
		printf("Using %g %g %g as principal axis\n", trans[0][2],trans[1][2],trans[2][2]);
		tmpvec[XX]=trans[0][2]; tmpvec[YY]=trans[1][2]; tmpvec[ZZ]=trans[2][2];
		calc_rotmatrix(tmpvec, targetvec, rotmatrix);
		/* rotmatrix finished */

		for (i=0;i<asize;++i)
		{
			mvmul(rotmatrix,x[aindex[i]],tmpvec);
			copy_rvec(tmpvec,x[aindex[i]]);
		}

		/*add pivot point back*/
		for(i=0; i<asize; i++)
			rvec_inc(x[aindex[i]],aligncenter);
		if (!bIndex)
			sfree(aindex);
	}

    if (bTranslate) {
        if (bIndex) {
            fprintf(stderr,"\nSelect a group that you want to translate:\n");
            get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),
                      1,&ssize,&sindex,&sgrpname);
        } else {
            ssize = atoms.nr;
            sindex = NULL;
        }
        printf("Translating %d atoms (out of %d) by %g %g %g nm\n",ssize,natom,
               translation[XX],translation[YY],translation[ZZ]);
        if (sindex) {
            for(i=0; i<ssize; i++)
                rvec_inc(x[sindex[i]],translation);
        }
        else {
            for(i=0; i<natom; i++)
                rvec_inc(x[i],translation);
        }
    }
    if (bRotate) {
        /* Rotate */
        printf("Rotating %g, %g, %g degrees around the X, Y and Z axis respectively\n",rotangles[XX],rotangles[YY],rotangles[ZZ]);
        for(i=0; i<DIM; i++)
            rotangles[i] *= DEG2RAD;
        rotate_conf(natom,x,v,rotangles[XX],rotangles[YY],rotangles[ZZ]);
    }

    if (bCalcGeom) {
        /* recalc geometrical center and max and min coordinates and size */
        calc_geom(ssize,sindex,x,gc,min,max,FALSE);
        rvec_sub(max, min, size);
        if (bScale || bOrient || bRotate)
            printf("new system size : %6.3f %6.3f %6.3f\n",
                   size[XX],size[YY],size[ZZ]);
    }

    if (bSetSize || bDist || (btype[0][0]=='t' && bSetAng)) {
        ePBC = epbcXYZ;
        if (!(bSetSize || bDist))
            for (i=0; i<DIM; i++)
                newbox[i] = norm(box[i]);
        clear_mat(box);
        /* calculate new boxsize */
        switch(btype[0][0]){
        case 't':
            if (bDist)
                for(i=0; i<DIM; i++)
                    newbox[i] = size[i]+2*dist;
            if (!bSetAng) {
                box[XX][XX] = newbox[XX];
                box[YY][YY] = newbox[YY];
                box[ZZ][ZZ] = newbox[ZZ];
            } else {
                matrix_convert(box,newbox,newang);
            }
            break;
        case 'c':
        case 'd':
        case 'o':
            if (bSetSize)
                d = newbox[0];
            else
                d = diam+2*dist;
            if (btype[0][0] == 'c')
                for(i=0; i<DIM; i++)
                    box[i][i] = d;
            else if (btype[0][0] == 'd') {
                box[XX][XX] = d;
                box[YY][YY] = d;
                box[ZZ][XX] = d/2;
                box[ZZ][YY] = d/2;
                box[ZZ][ZZ] = d*sqrt(2)/2;
            } else {
                box[XX][XX] = d;
                box[YY][XX] = d/3;
                box[YY][YY] = d*sqrt(2)*2/3;
                box[ZZ][XX] = -d/3;
                box[ZZ][YY] = d*sqrt(2)/3;
                box[ZZ][ZZ] = d*sqrt(6)/3;
            }
            break;
        } 
    }

    /* calculate new coords for geometrical center */
    if (!bSetCenter)
        calc_box_center(ecenterDEF,box,center);

    /* center molecule on 'center' */
    if (bCenter)
        center_conf(natom,x,center,gc);

    /* print some */
    if (bCalcGeom) {
        calc_geom(ssize,sindex,x, gc, min, max, FALSE);
        printf("new center      :%7.3f%7.3f%7.3f (nm)\n",gc[XX],gc[YY],gc[ZZ]);
    }
    if (bOrient || bScale || bDist || bSetSize) {
        printf("new box vectors :%7.3f%7.3f%7.3f (nm)\n", 
               norm(box[XX]), norm(box[YY]), norm(box[ZZ]));
        printf("new box angles  :%7.2f%7.2f%7.2f (degrees)\n",
               norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])),
        norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])),
        norm2(box[YY])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY])));
        printf("new box volume  :%7.2f               (nm^3)\n",det(box));
    }  

    if (check_box(epbcXYZ,box))
        printf("\nWARNING: %s\n",check_box(epbcXYZ,box));

    if (bDist && btype[0][0]=='t')
    {
        if(TRICLINIC(box))
        {
            printf("\nWARNING: Your box is triclinic with non-orthogonal axes. In this case, the\n"
                "distance from the solute to a box surface along the corresponding normal\n"
                "vector might be somewhat smaller than your specified value %f.\n"
                "You can check the actual value with g_mindist -pi\n",dist);
        }
        else
        {
            printf("\nWARNING: No boxtype specified - distance condition applied in each dimension.\n"
                "If the molecule rotates the actual distance will be smaller. You might want\n"
                "to use a cubic box instead, or why not try a dodecahedron today?\n");
        }
    }
    if (bCONECT && (outftp == efPDB) && (inftp == efTPR)) 
        conect = gmx_conect_generate(top);
    else
        conect = NULL;

    if (bIndex) {
        fprintf(stderr,"\nSelect a group for output:\n");
        get_index(&atoms,opt2fn_null("-n",NFILE,fnm),
                  1,&isize,&index,&grpname);
        if (opt2parg_bSet("-label",NPA,pa)) {
            for(i=0; (i<atoms.nr); i++) 
                atoms.resinfo[atoms.atom[i].resind].chainid=label[0];
        }
                
        if (opt2bSet("-bf",NFILE,fnm) || bLegend)
        {
            gmx_fatal(FARGS,"Sorry, cannot do bfactors with an index group.");
        }

        if (outftp == efPDB) 
        {
            out=ffopen(outfile,"w");
            write_pdbfile_indexed(out,title,&atoms,x,ePBC,box,' ',1,isize,index,conect,TRUE);
            ffclose(out);
        }
        else
        {
            write_sto_conf_indexed(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box,isize,index); 
        }
    }
    else {
        if ((outftp == efPDB) || (outftp == efPQR)) {
            out=ffopen(outfile,"w");
            if (bMead) {
                set_pdb_wide_format(TRUE);
                fprintf(out,"REMARK    "
                        "The B-factors in this file hold atomic radii\n");
                fprintf(out,"REMARK    "
                        "The occupancy in this file hold atomic charges\n");
            }
            else if (bGrasp) {
                fprintf(out,"GRASP PDB FILE\nFORMAT NUMBER=1\n");
                fprintf(out,"REMARK    "
                        "The B-factors in this file hold atomic charges\n");
                fprintf(out,"REMARK    "
                        "The occupancy in this file hold atomic radii\n");
            }
            else if (opt2bSet("-bf",NFILE,fnm)) {
                read_bfac(opt2fn("-bf",NFILE,fnm),&n_bfac,&bfac,&bfac_nr);
                set_pdb_conf_bfac(atoms.nr,atoms.nres,&atoms,
                                  n_bfac,bfac,bfac_nr,peratom);
            }
            if (opt2parg_bSet("-label",NPA,pa)) {
                for(i=0; (i<atoms.nr); i++) 
                    atoms.resinfo[atoms.atom[i].resind].chainid=label[0];
            }
            write_pdbfile(out,title,&atoms,x,ePBC,box,' ',-1,conect,TRUE);
            if (bLegend)
                pdb_legend(out,atoms.nr,atoms.nres,&atoms,x);
            if (visbox[0] > 0)
                visualize_box(out,bLegend ? atoms.nr+12 : atoms.nr,
                    bLegend? atoms.nres=12 : atoms.nres,box,visbox);
            ffclose(out);
        }
        else
            write_sto_conf(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box); 
    }
    gmx_atomprop_destroy(aps);

    do_view(oenv,outfile,NULL);

    thanx(stderr);

    return 0;
}
Пример #20
0
real 
do_listed_vdw_q(int ftype,int nbonds,
                const t_iatom iatoms[],const t_iparams iparams[],
                const rvec x[],rvec f[],rvec fshift[],
                const t_pbc *pbc,const t_graph *g,
                real lambda,real *dvdlambda,
                const t_mdatoms *md,
                const t_forcerec *fr,gmx_grppairener_t *grppener,
                int *global_atom_index)
{
    static    gmx_bool bWarn=FALSE;
    real      eps,r2,*tab,rtab2=0;
    rvec      dx,x14[2],f14[2];
    int       i,ai,aj,itype;
    int       typeA[2]={0,0},typeB[2]={0,1};
    real      chargeA[2]={0,0},chargeB[2];
    int       gid,shift_vir,shift_f;
    int       j_index[] = { 0, 1 };
    int       i0=0,i1=1,i2=2;
    ivec      dt;
    int       outeriter,inneriter;
    int       nthreads = 1;
    int       count;
    real      krf,crf,tabscale;
    int       ntype=0;
    real      *nbfp=NULL;
    real      *egnb=NULL,*egcoul=NULL;
    t_nblist  tmplist;
    int       icoul,ivdw;
    gmx_bool      bMolPBC,bFreeEnergy;
    t_pf_global *pf_global;
    
    
#if GMX_THREAD_SHM_FDECOMP
    pthread_mutex_t mtx;
#else
    void *    mtx = NULL;
#endif

    
#if GMX_THREAD_SHM_FDECOMP
    pthread_mutex_initialize(&mtx);
#endif

    bMolPBC = fr->bMolPBC;

    pf_global = fr->pf_global;
    
    switch (ftype) {
    case F_LJ14:
    case F_LJC14_Q:
        eps = fr->epsfac*fr->fudgeQQ;
        ntype  = 1;
        egnb   = grppener->ener[egLJ14];
        egcoul = grppener->ener[egCOUL14];
        break;
    case F_LJC_PAIRS_NB:
        eps = fr->epsfac;
        ntype  = 1;
        egnb   = grppener->ener[egLJSR];
        egcoul = grppener->ener[egCOULSR];
        break;
    default:
        gmx_fatal(FARGS,"Unknown function type %d in do_nonbonded14",
                  ftype);
    }
    tab = fr->tab14.tab;
    rtab2 = sqr(fr->tab14.r);
    tabscale = fr->tab14.scale;

    krf = fr->k_rf;
    crf = fr->c_rf;

    /* Determine the values for icoul/ivdw. */
    if (fr->bEwald) {
        icoul = 1;
    } 
    else if(fr->bcoultab)
    {
        icoul = 3;
    }
    else if(fr->eeltype == eelRF_NEC)
    {
        icoul = 2;
    }
    else 
    {
        icoul = 1;
    }
    
    if(fr->bvdwtab)
    {
        ivdw = 3;
    }
    else if(fr->bBHAM)
    {
        ivdw = 2;
    }
    else 
    {
        ivdw = 1;
    }
    
    
    /* We don't do SSE or altivec here, due to large overhead for 4-fold 
     * unrolling on short lists 
     */
    
    bFreeEnergy = FALSE;
    for(i=0; (i<nbonds); ) 
    {
        itype = iatoms[i++];
        ai    = iatoms[i++];
        aj    = iatoms[i++];
        gid   = GID(md->cENER[ai],md->cENER[aj],md->nenergrp);
        
        switch (ftype) {
        case F_LJ14:
            bFreeEnergy =
                (fr->efep != efepNO &&
                 ((md->nPerturbed && (md->bPerturbed[ai] || md->bPerturbed[aj])) ||
                  iparams[itype].lj14.c6A != iparams[itype].lj14.c6B ||
                  iparams[itype].lj14.c12A != iparams[itype].lj14.c12B));
            chargeA[0] = md->chargeA[ai];
            chargeA[1] = md->chargeA[aj];
            nbfp = (real *)&(iparams[itype].lj14.c6A);
            break;
        case F_LJC14_Q:
            eps = fr->epsfac*iparams[itype].ljc14.fqq;
            chargeA[0] = iparams[itype].ljc14.qi;
            chargeA[1] = iparams[itype].ljc14.qj;
            nbfp = (real *)&(iparams[itype].ljc14.c6);
            break;
        case F_LJC_PAIRS_NB:
            chargeA[0] = iparams[itype].ljcnb.qi;
            chargeA[1] = iparams[itype].ljcnb.qj;
            nbfp = (real *)&(iparams[itype].ljcnb.c6);
            break;
        }
        
        if (!bMolPBC) 
        {
            /* This is a bonded interaction, atoms are in the same box */
            shift_f = CENTRAL;
            r2 = distance2(x[ai],x[aj]);
        }
        else 
        {
            /* Apply full periodic boundary conditions */
            shift_f = pbc_dx_aiuc(pbc,x[ai],x[aj],dx);
            r2 = norm2(dx);
        }

        if (r2 >= rtab2) 
        {
            if (!bWarn) 
            {
                fprintf(stderr,"Warning: 1-4 interaction between %d and %d "
                        "at distance %.3f which is larger than the 1-4 table size %.3f nm\n", 
			glatnr(global_atom_index,ai),
			glatnr(global_atom_index,aj),
			sqrt(r2), sqrt(rtab2));
                fprintf(stderr,"These are ignored for the rest of the simulation\n");
                fprintf(stderr,"This usually means your system is exploding,\n"
                        "if not, you should increase table-extension in your mdp file\n"
                        "or with user tables increase the table size\n");
                bWarn = TRUE;
            }
            if (debug) 
	      fprintf(debug,"%8f %8f %8f\n%8f %8f %8f\n1-4 (%d,%d) interaction not within cut-off! r=%g. Ignored\n",
		      x[ai][XX],x[ai][YY],x[ai][ZZ],
		      x[aj][XX],x[aj][YY],x[aj][ZZ],
		      glatnr(global_atom_index,ai),
		      glatnr(global_atom_index,aj),
		      sqrt(r2));
        }
        else 
        {
            copy_rvec(x[ai],x14[0]);
            copy_rvec(x[aj],x14[1]);
            clear_rvec(f14[0]);
            clear_rvec(f14[1]);
#ifdef DEBUG
            fprintf(debug,"LJ14: grp-i=%2d, grp-j=%2d, ngrp=%2d, GID=%d\n",
                    md->cENER[ai],md->cENER[aj],md->nenergrp,gid);
#endif
            
	    outeriter = inneriter = count = 0;
	    if (bFreeEnergy)
        {
            chargeB[0] = md->chargeB[ai];
            chargeB[1] = md->chargeB[aj];
            /* We pass &(iparams[itype].lj14.c6A) as LJ parameter matrix
             * to the innerloops.
             * Here we use that the LJ-14 parameters are stored in iparams
             * as c6A,c12A,c6B,c12B, which are referenced correctly
             * in the innerloops if we assign type combinations 0-0 and 0-1
             * to atom pair ai-aj in topologies A and B respectively.
             */
            if(ivdw==2)
            {
                gmx_fatal(FARGS,"Cannot do free energy Buckingham interactions.");
            }
            count = 0;
            gmx_nb_free_energy_kernel(icoul,
                                      ivdw,
                                      i1,
                                      &i0,
                                      j_index,
                                      &i1,
                                      &shift_f,
                                      fr->shift_vec[0],
                                      fshift[0],
                                      &gid,
                                      x14[0],
                                      f14[0],
                                      chargeA,
                                      chargeB,
                                      eps,
                                      krf,
                                      crf,
                                      fr->ewaldcoeff,
                                      egcoul,
                                      typeA,
                                      typeB,
                                      ntype,
                                      nbfp,
                                      egnb,
                                      tabscale,
                                      tab,
                                      lambda,
                                      dvdlambda,
                                      fr->sc_alpha,
                                      fr->sc_power,
                                      fr->sc_sigma6_def,
                                      fr->sc_sigma6_min,
                                      TRUE,
                                      &outeriter,
                                      &inneriter);
        }
        else 
        { 
            /* Not perturbed - call kernel 330 */
            nb_kernel330
                ( &i1,
                  &i0,
                  j_index,
                  &i1,
                  &shift_f,
                  fr->shift_vec[0],
                  fshift[0],
                  &gid,
                  x14[0],
                  f14[0],
                  chargeA,
                  &eps,
                  &krf,
                  &crf,
                  egcoul,
                  typeA,
                  &ntype,
                  nbfp,
                  egnb,
                  &tabscale,
                  tab,
                  NULL,
                  NULL,
                  NULL,
                  NULL,
                  &nthreads,
                  &count,
                  (void *)&mtx,
                  &outeriter,
                  &inneriter,
                  NULL);                
        }
        
        /* Add the forces */
        rvec_inc(f[ai],f14[0]);
        rvec_dec(f[aj],f14[0]);

	if (pf_global->bInitialized)
	    pf_atom_add_bonded(pf_global, ai, aj, PF_INTER_NB14, f14[0]);

        if (g) 
        {
            /* Correct the shift forces using the graph */
            ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt);    
            shift_vir = IVEC2IS(dt);
            rvec_inc(fshift[shift_vir],f14[0]);
            rvec_dec(fshift[CENTRAL],f14[0]);
        }
        
	    /* flops: eNR_KERNEL_OUTER + eNR_KERNEL330 + 12 */
        }
    }
    return 0.0;
}
Пример #21
0
void add_conf(t_atoms *atoms, rvec **x, rvec **v, real **r, gmx_bool bSrenew,
              int ePBC, matrix box, gmx_bool bInsert,
              t_atoms *atoms_solvt, rvec *x_solvt, rvec *v_solvt, real *r_solvt,
              gmx_bool bVerbose, real rshell, int max_sol, const output_env_t oenv)
{
    t_nblist       *nlist;
    t_atoms        *atoms_all;
    real            max_vdw, *r_prot, *r_all, n2, r2, ib1, ib2;
    int             natoms_prot, natoms_solvt;
    int             i, j, jj, m, j0, j1, jjj, jnres, jnr, inr, iprot, is1, is2;
    int             prev, resnr, nresadd, d, k, ncells, maxincell;
    int             dx0, dx1, dy0, dy1, dz0, dz1;
    int             ntest, nremove, nkeep;
    rvec            dx, xi, xj, xpp, *x_all, *v_all;
    gmx_bool       *remove, *keep;
    int             bSolSol;

    natoms_prot  = atoms->nr;
    natoms_solvt = atoms_solvt->nr;
    if (natoms_solvt <= 0)
    {
        fprintf(stderr, "WARNING: Nothing to add\n");
        return;
    }

    if (ePBC == epbcSCREW)
    {
        gmx_fatal(FARGS, "Sorry, %s pbc is not yet supported", epbc_names[ePBC]);
    }

    if (bVerbose)
    {
        fprintf(stderr, "Calculating Overlap...\n");
    }

    /* Set margin around box edges to largest solvent dimension.
     * The maximum distance between atoms in a solvent molecule should
     * be calculated. At the moment a fudge factor of 3 is used.
     */
    r_prot     = *r;
    box_margin = 3*find_max_real(natoms_solvt, r_solvt);
    max_vdw    = max(3*find_max_real(natoms_prot, r_prot), box_margin);
    fprintf(stderr, "box_margin = %g\n", box_margin);

    snew(remove, natoms_solvt);

    nremove = 0;
    if (!bInsert)
    {
        for (i = 0; i < atoms_solvt->nr; i++)
        {
            if (outside_box_plus_margin(x_solvt[i], box) )
            {
                i = mark_res(i, remove, atoms_solvt->nr, atoms_solvt->atom, &nremove);
            }
        }
        fprintf(stderr, "Removed %d atoms that were outside the box\n", nremove);
    }

    /* Define grid stuff for genbox */
    /* Largest VDW radius */
    snew(r_all, natoms_prot+natoms_solvt);
    for (i = j = 0; i < natoms_prot; i++, j++)
    {
        r_all[j] = r_prot[i];
    }
    for (i = 0; i < natoms_solvt; i++, j++)
    {
        r_all[j] = r_solvt[i];
    }

    /* Combine arrays */
    combine_atoms(atoms, atoms_solvt, *x, v ? *v : NULL, x_solvt, v_solvt,
                  &atoms_all, &x_all, &v_all);

    /* Do neighboursearching step */
    do_nsgrid(stdout, bVerbose, box, x_all, atoms_all, max_vdw, oenv);

    /* check solvent with solute */
    nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]);
    fprintf(stderr, "nri = %d, nrj = %d\n", nlist->nri, nlist->nrj);
    for (bSolSol = 0; (bSolSol <= (bInsert ? 0 : 1)); bSolSol++)
    {
        ntest = nremove = 0;
        fprintf(stderr, "Checking %s-Solvent overlap:",
                bSolSol ? "Solvent" : "Protein");
        for (i = 0; (i < nlist->nri && nremove < natoms_solvt); i++)
        {
            inr = nlist->iinr[i];
            j0  = nlist->jindex[i];
            j1  = nlist->jindex[i+1];
            rvec_add(x_all[inr], fr->shift_vec[nlist->shift[i]], xi);

            for (j = j0; (j < j1 && nremove < natoms_solvt); j++)
            {
                jnr = nlist->jjnr[j];
                copy_rvec(x_all[jnr], xj);

                /* Check solvent-protein and solvent-solvent */
                is1 = inr-natoms_prot;
                is2 = jnr-natoms_prot;

                /* Check if at least one of the atoms is a solvent that is not yet
                 * listed for removal, and if both are solvent, that they are not in the
                 * same residue.
                 */
                if ((!bSolSol &&
                     bXor((is1 >= 0), (is2 >= 0)) && /* One atom is protein */
                     ((is1 < 0) || ((is1 >= 0) && !remove[is1])) &&
                     ((is2 < 0) || ((is2 >= 0) && !remove[is2]))) ||

                    (bSolSol  &&
                     (is1 >= 0) && (!remove[is1]) &&                   /* is1 is solvent */
                     (is2 >= 0) && (!remove[is2]) &&                   /* is2 is solvent */
                     (bInsert ||                                       /* when inserting also check inside the box */
                      (outside_box_minus_margin2(x_solvt[is1], box) && /* is1 on edge */
                       outside_box_minus_margin2(x_solvt[is2], box))   /* is2 on edge */
                     ) &&
                     (atoms_solvt->atom[is1].resind !=                 /* Not the same residue */
                      atoms_solvt->atom[is2].resind)))
                {

                    ntest++;
                    rvec_sub(xi, xj, dx);
                    n2 = norm2(dx);
                    r2 = sqr(r_all[inr]+r_all[jnr]);
                    if (n2 < r2)
                    {
                        if (bInsert)
                        {
                            nremove = natoms_solvt;
                            for (k = 0; k < nremove; k++)
                            {
                                remove[k] = TRUE;
                            }
                        }
                        /* Need only remove one of the solvents... */
                        if (is2 >= 0)
                        {
                            (void) mark_res(is2, remove, natoms_solvt, atoms_solvt->atom,
                                            &nremove);
                        }
                        else if (is1 >= 0)
                        {
                            (void) mark_res(is1, remove, natoms_solvt, atoms_solvt->atom,
                                            &nremove);
                        }
                        else
                        {
                            fprintf(stderr, "Neither atom is solvent%d %d\n", is1, is2);
                        }
                    }
                }
            }
        }
        if (!bInsert)
        {
            fprintf(stderr, " tested %d pairs, removed %d atoms.\n", ntest, nremove);
        }
    }
    if (debug)
    {
        for (i = 0; i < natoms_solvt; i++)
        {
            fprintf(debug, "remove[%5d] = %s\n", i, bool_names[remove[i]]);
        }
    }

    /* Search again, now with another cut-off */
    if (rshell > 0)
    {
        do_nsgrid(stdout, bVerbose, box, x_all, atoms_all, rshell, oenv);
        nlist = &(fr->nblists[0].nlist_sr[eNL_VDW]);
        fprintf(stderr, "nri = %d, nrj = %d\n", nlist->nri, nlist->nrj);
        nkeep = 0;
        snew(keep, natoms_solvt);
        for (i = 0; i < nlist->nri; i++)
        {
            inr = nlist->iinr[i];
            j0  = nlist->jindex[i];
            j1  = nlist->jindex[i+1];

            for (j = j0; j < j1; j++)
            {
                jnr = nlist->jjnr[j];

                /* Check solvent-protein and solvent-solvent */
                is1 = inr-natoms_prot;
                is2 = jnr-natoms_prot;

                /* Check if at least one of the atoms is a solvent that is not yet
                 * listed for removal, and if both are solvent, that they are not in the
                 * same residue.
                 */
                if (is1 >= 0 && is2 < 0)
                {
                    mark_res(is1, keep, natoms_solvt, atoms_solvt->atom, &nkeep);
                }
                else if (is1 < 0 && is2 >= 0)
                {
                    mark_res(is2, keep, natoms_solvt, atoms_solvt->atom, &nkeep);
                }
            }
        }
        fprintf(stderr, "Keeping %d solvent atoms after proximity check\n",
                nkeep);
        for (i = 0; i < natoms_solvt; i++)
        {
            remove[i] = remove[i] || !keep[i];
        }
        sfree(keep);
    }
    /* count how many atoms and residues will be added and make space */
    if (bInsert)
    {
        j     = atoms_solvt->nr;
        jnres = atoms_solvt->nres;
    }
    else
    {
        j     = 0;
        jnres = 0;
        for (i = 0; ((i < atoms_solvt->nr) &&
                     ((max_sol == 0) || (jnres < max_sol))); i++)
        {
            if (!remove[i])
            {
                j++;
                if ((i == 0) ||
                    (atoms_solvt->atom[i].resind != atoms_solvt->atom[i-1].resind))
                {
                    jnres++;
                }
            }
        }
    }
    if (debug)
    {
        fprintf(debug, "Will add %d atoms in %d residues\n", j, jnres);
    }
    if (!bInsert)
    {
        /* Flag the remaing solvent atoms to be removed */
        jjj = atoms_solvt->atom[i-1].resind;
        for (; (i < atoms_solvt->nr); i++)
        {
            if (atoms_solvt->atom[i].resind > jjj)
            {
                remove[i] = TRUE;
            }
            else
            {
                j++;
            }
        }
    }

    if (bSrenew)
    {
        srenew(atoms->resinfo,  atoms->nres+jnres);
        srenew(atoms->atomname, atoms->nr+j);
        srenew(atoms->atom,     atoms->nr+j);
        srenew(*x,              atoms->nr+j);
        if (v)
        {
            srenew(*v,       atoms->nr+j);
        }
        srenew(*r,              atoms->nr+j);
    }

    /* add the selected atoms_solvt to atoms */
    if (atoms->nr > 0)
    {
        resnr = atoms->resinfo[atoms->atom[atoms->nr-1].resind].nr;
    }
    else
    {
        resnr = 0;
    }
    prev    = -1;
    nresadd = 0;
    for (i = 0; i < atoms_solvt->nr; i++)
    {
        if (!remove[i])
        {
            if (prev == -1 ||
                atoms_solvt->atom[i].resind != atoms_solvt->atom[prev].resind)
            {
                nresadd++;
                atoms->nres++;
                resnr++;
                atoms->resinfo[atoms->nres-1] =
                    atoms_solvt->resinfo[atoms_solvt->atom[i].resind];
                atoms->resinfo[atoms->nres-1].nr = resnr;
                /* calculate shift of the solvent molecule using the first atom */
                copy_rvec(x_solvt[i], dx);
                put_atoms_in_box(ePBC, box, 1, &dx);
                rvec_dec(dx, x_solvt[i]);
            }
            atoms->atom[atoms->nr]     = atoms_solvt->atom[i];
            atoms->atomname[atoms->nr] = atoms_solvt->atomname[i];
            rvec_add(x_solvt[i], dx, (*x)[atoms->nr]);
            if (v)
            {
                copy_rvec(v_solvt[i], (*v)[atoms->nr]);
            }
            (*r)[atoms->nr]               = r_solvt[i];
            atoms->atom[atoms->nr].resind = atoms->nres-1;
            atoms->nr++;
            prev = i;
        }
    }
    if (bSrenew)
    {
        srenew(atoms->resinfo,  atoms->nres+nresadd);
    }

    if (bVerbose)
    {
        fprintf(stderr, "Added %d molecules\n", nresadd);
    }

    sfree(remove);
    done_atom(atoms_all);
    sfree(x_all);
    sfree(v_all);
}
Пример #22
0
real ewald_LRcorrection(FILE *fplog,
                        int start, int end,
                        t_commrec *cr, int thread, t_forcerec *fr,
                        real *chargeA, real *chargeB,
                        gmx_bool calc_excl_corr,
                        t_blocka *excl, rvec x[],
                        matrix box, rvec mu_tot[],
                        int ewald_geometry, real epsilon_surface,
                        rvec *f, tensor vir,
                        real lambda, real *dvdlambda)
{
    int      i, i1, i2, j, k, m, iv, jv, q;
    atom_id *AA;
    double   q2sumA, q2sumB, Vexcl, dvdl_excl; /* Necessary for precision */
    real     one_4pi_eps;
    real     v, vc, qiA, qiB, dr, dr2, rinv, fscal, enercorr;
    real     Vself[2], Vdipole[2], rinv2, ewc = fr->ewaldcoeff, ewcdr;
    rvec     df, dx, mutot[2], dipcorrA, dipcorrB;
    tensor   dxdf;
    real     vol = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
    real     L1, dipole_coeff, qqA, qqB, qqL, vr0;
    /*#define TABLES*/
#ifdef TABLES
    real        tabscale = fr->tabscale;
    real        eps, eps2, VV, FF, F, Y, Geps, Heps2, Fp, fijC, r1t;
    real       *VFtab = fr->coulvdwtab;
    int         n0, n1, nnn;
#endif
    gmx_bool    bFreeEnergy = (chargeB != NULL);
    gmx_bool    bMolPBC     = fr->bMolPBC;

    one_4pi_eps = ONE_4PI_EPS0/fr->epsilon_r;
    vr0         = ewc*M_2_SQRTPI;

    AA         = excl->a;
    Vexcl      = 0;
    dvdl_excl  = 0;
    q2sumA     = 0;
    q2sumB     = 0;
    Vdipole[0] = 0;
    Vdipole[1] = 0;
    L1         = 1.0-lambda;

    /* Note that we have to transform back to gromacs units, since
     * mu_tot contains the dipole in debye units (for output).
     */
    for (i = 0; (i < DIM); i++)
    {
        mutot[0][i] = mu_tot[0][i]*DEBYE2ENM;
        mutot[1][i] = mu_tot[1][i]*DEBYE2ENM;
        dipcorrA[i] = 0;
        dipcorrB[i] = 0;
    }
    dipole_coeff = 0;
    switch (ewald_geometry)
    {
        case eewg3D:
            if (epsilon_surface != 0)
            {
                dipole_coeff =
                    2*M_PI*ONE_4PI_EPS0/((2*epsilon_surface + fr->epsilon_r)*vol);
                for (i = 0; (i < DIM); i++)
                {
                    dipcorrA[i] = 2*dipole_coeff*mutot[0][i];
                    dipcorrB[i] = 2*dipole_coeff*mutot[1][i];
                }
            }
            break;
        case eewg3DC:
            dipole_coeff = 2*M_PI*one_4pi_eps/vol;
            dipcorrA[ZZ] = 2*dipole_coeff*mutot[0][ZZ];
            dipcorrB[ZZ] = 2*dipole_coeff*mutot[1][ZZ];
            break;
        default:
            gmx_incons("Unsupported Ewald geometry");
            break;
    }
    if (debug)
    {
        fprintf(debug, "dipcorr = %8.3f  %8.3f  %8.3f\n",
                dipcorrA[XX], dipcorrA[YY], dipcorrA[ZZ]);
        fprintf(debug, "mutot   = %8.3f  %8.3f  %8.3f\n",
                mutot[0][XX], mutot[0][YY], mutot[0][ZZ]);
    }

    clear_mat(dxdf);
    if ((calc_excl_corr || dipole_coeff != 0) && !bFreeEnergy)
    {
        for (i = start; (i < end); i++)
        {
            /* Initiate local variables (for this i-particle) to 0 */
            qiA = chargeA[i]*one_4pi_eps;

            if (calc_excl_corr)
            {
                i1  = excl->index[i];
                i2  = excl->index[i+1];

                /* Loop over excluded neighbours */
                for (j = i1; (j < i2); j++)
                {
                    k = AA[j];
                    /*
                     * First we must test whether k <> i, and then, because the
                     * exclusions are all listed twice i->k and k->i we must select
                     * just one of the two.
                     * As a minor optimization we only compute forces when the charges
                     * are non-zero.
                     */
                    if (k > i)
                    {
                        qqA = qiA*chargeA[k];
                        if (qqA != 0.0)
                        {
                            rvec_sub(x[i], x[k], dx);
                            if (bMolPBC)
                            {
                                /* Cheap pbc_dx, assume excluded pairs are at short distance. */
                                for (m = DIM-1; (m >= 0); m--)
                                {
                                    if (dx[m] > 0.5*box[m][m])
                                    {
                                        rvec_dec(dx, box[m]);
                                    }
                                    else if (dx[m] < -0.5*box[m][m])
                                    {
                                        rvec_inc(dx, box[m]);
                                    }
                                }
                            }
                            dr2 = norm2(dx);
                            /* Distance between two excluded particles may be zero in the
                             * case of shells
                             */
                            if (dr2 != 0)
                            {
                                rinv              = gmx_invsqrt(dr2);
                                rinv2             = rinv*rinv;
                                dr                = 1.0/rinv;
#ifdef TABLES
                                r1t               = tabscale*dr;
                                n0                = r1t;
                                assert(n0 >= 3);
                                n1                = 12*n0;
                                eps               = r1t-n0;
                                eps2              = eps*eps;
                                nnn               = n1;
                                Y                 = VFtab[nnn];
                                F                 = VFtab[nnn+1];
                                Geps              = eps*VFtab[nnn+2];
                                Heps2             = eps2*VFtab[nnn+3];
                                Fp                = F+Geps+Heps2;
                                VV                = Y+eps*Fp;
                                FF                = Fp+Geps+2.0*Heps2;
                                vc                = qqA*(rinv-VV);
                                fijC              = qqA*FF;
                                Vexcl            += vc;

                                fscal             = vc*rinv2+fijC*tabscale*rinv;
                                /* End of tabulated interaction part */
#else

                                /* This is the code you would want instead if not using
                                 * tables:
                                 */
                                ewcdr   = ewc*dr;
                                vc      = qqA*gmx_erf(ewcdr)*rinv;
                                Vexcl  += vc;
#ifdef GMX_DOUBLE
                                /* Relative accuracy at R_ERF_R_INACC of 3e-10 */
#define       R_ERF_R_INACC 0.006
#else
                                /* Relative accuracy at R_ERF_R_INACC of 2e-5 */
#define       R_ERF_R_INACC 0.1
#endif
                                if (ewcdr > R_ERF_R_INACC)
                                {
                                    fscal = rinv2*(vc - qqA*ewc*M_2_SQRTPI*exp(-ewcdr*ewcdr));
                                }
                                else
                                {
                                    /* Use a fourth order series expansion for small ewcdr */
                                    fscal = ewc*ewc*qqA*vr0*(2.0/3.0 - 0.4*ewcdr*ewcdr);
                                }
#endif
                                /* The force vector is obtained by multiplication with the
                                 * distance vector
                                 */
                                svmul(fscal, dx, df);
                                rvec_inc(f[k], df);
                                rvec_dec(f[i], df);
                                for (iv = 0; (iv < DIM); iv++)
                                {
                                    for (jv = 0; (jv < DIM); jv++)
                                    {
                                        dxdf[iv][jv] += dx[iv]*df[jv];
                                    }
                                }
                            }
                            else
                            {
                                Vexcl += qqA*vr0;
                            }
                        }
                    }
                }
            }
            /* Dipole correction on force */
            if (dipole_coeff != 0)
            {
                for (j = 0; (j < DIM); j++)
                {
                    f[i][j] -= dipcorrA[j]*chargeA[i];
                }
            }
        }
    }
    else if (calc_excl_corr || dipole_coeff != 0)
    {
        for (i = start; (i < end); i++)
        {
            /* Initiate local variables (for this i-particle) to 0 */
            qiA = chargeA[i]*one_4pi_eps;
            qiB = chargeB[i]*one_4pi_eps;

            if (calc_excl_corr)
            {
                i1  = excl->index[i];
                i2  = excl->index[i+1];

                /* Loop over excluded neighbours */
                for (j = i1; (j < i2); j++)
                {
                    k = AA[j];
                    if (k > i)
                    {
                        qqA = qiA*chargeA[k];
                        qqB = qiB*chargeB[k];
                        if (qqA != 0.0 || qqB != 0.0)
                        {
                            qqL = L1*qqA + lambda*qqB;
                            rvec_sub(x[i], x[k], dx);
                            if (bMolPBC)
                            {
                                /* Cheap pbc_dx, assume excluded pairs are at short distance. */
                                for (m = DIM-1; (m >= 0); m--)
                                {
                                    if (dx[m] > 0.5*box[m][m])
                                    {
                                        rvec_dec(dx, box[m]);
                                    }
                                    else if (dx[m] < -0.5*box[m][m])
                                    {
                                        rvec_inc(dx, box[m]);
                                    }
                                }
                            }
                            dr2 = norm2(dx);
                            if (dr2 != 0)
                            {
                                rinv   = gmx_invsqrt(dr2);
                                rinv2  = rinv*rinv;
                                dr     = 1.0/rinv;
                                v      = gmx_erf(ewc*dr)*rinv;
                                vc     = qqL*v;
                                Vexcl += vc;
                                fscal  = rinv2*(vc-qqL*ewc*M_2_SQRTPI*exp(-ewc*ewc*dr2));
                                svmul(fscal, dx, df);
                                rvec_inc(f[k], df);
                                rvec_dec(f[i], df);
                                for (iv = 0; (iv < DIM); iv++)
                                {
                                    for (jv = 0; (jv < DIM); jv++)
                                    {
                                        dxdf[iv][jv] += dx[iv]*df[jv];
                                    }
                                }
                                dvdl_excl += (qqB - qqA)*v;
                            }
                            else
                            {
                                Vexcl     +=         qqL*vr0;
                                dvdl_excl += (qqB - qqA)*vr0;
                            }
                        }
                    }
                }
            }
            /* Dipole correction on force */
            if (dipole_coeff != 0)
            {
                for (j = 0; (j < DIM); j++)
                {
                    f[i][j] -= L1*dipcorrA[j]*chargeA[i]
                        + lambda*dipcorrB[j]*chargeB[i];
                }
            }
        }
    }
    for (iv = 0; (iv < DIM); iv++)
    {
        for (jv = 0; (jv < DIM); jv++)
        {
            vir[iv][jv] += 0.5*dxdf[iv][jv];
        }
    }


    Vself[0] = 0;
    Vself[1] = 0;
    /* Global corrections only on master process */
    if (MASTER(cr) && thread == 0)
    {
        for (q = 0; q < (bFreeEnergy ? 2 : 1); q++)
        {
            if (calc_excl_corr)
            {
                /* Self-energy correction */
                Vself[q] = ewc*one_4pi_eps*fr->q2sum[q]*M_1_SQRTPI;
            }

            /* Apply surface dipole correction:
             * correction = dipole_coeff * (dipole)^2
             */
            if (dipole_coeff != 0)
            {
                if (ewald_geometry == eewg3D)
                {
                    Vdipole[q] = dipole_coeff*iprod(mutot[q], mutot[q]);
                }
                else if (ewald_geometry == eewg3DC)
                {
                    Vdipole[q] = dipole_coeff*mutot[q][ZZ]*mutot[q][ZZ];
                }
            }
        }
    }

    if (!bFreeEnergy)
    {
        enercorr = Vdipole[0] - Vself[0] - Vexcl;
    }
    else
    {
        enercorr = L1*(Vdipole[0] - Vself[0])
            + lambda*(Vdipole[1] - Vself[1])
            - Vexcl;
        *dvdlambda += Vdipole[1] - Vself[1]
            - (Vdipole[0] - Vself[0]) - dvdl_excl;
    }

    if (debug)
    {
        fprintf(debug, "Long Range corrections for Ewald interactions:\n");
        fprintf(debug, "start=%d,natoms=%d\n", start, end-start);
        fprintf(debug, "q2sum = %g, Vself=%g\n",
                L1*q2sumA+lambda*q2sumB, L1*Vself[0]+lambda*Vself[1]);
        fprintf(debug, "Long Range correction: Vexcl=%g\n", Vexcl);
        if (MASTER(cr) && thread == 0)
        {
            if (epsilon_surface > 0 || ewald_geometry == eewg3DC)
            {
                fprintf(debug, "Total dipole correction: Vdipole=%g\n",
                        L1*Vdipole[0]+lambda*Vdipole[1]);
            }
        }
    }

    /* Return the correction to the energy */
    return enercorr;
}
Пример #23
0
real RF_excl_correction(FILE *log,
			const t_forcerec *fr,t_graph *g,
			const t_mdatoms *mdatoms,const t_blocka *excl,
			rvec x[],rvec f[],rvec *fshift,const t_pbc *pbc,
			real lambda,real *dvdlambda)
{
  /* Calculate the reaction-field energy correction for this node:
   * epsfac q_i q_j (k_rf r_ij^2 - c_rf)
   * and force correction for all excluded pairs, including self pairs.
   */
  int    top,i,j,j1,j2,k,ki;
  double q2sumA,q2sumB,ener;
  const real *chargeA,*chargeB;
  real   ek,ec,L1,qiA,qiB,qqA,qqB,qqL,v;
  rvec   dx,df;
  atom_id *AA;
  ivec   dt;
  int    start = mdatoms->start;
  int    end   = mdatoms->homenr+start;
  int    niat;
  gmx_bool   bMolPBC = fr->bMolPBC;

  if (fr->n_tpi)
    /* For test particle insertion we only correct for the test molecule */
    start = mdatoms->nr - fr->n_tpi;

  ek = fr->epsfac*fr->k_rf;
  ec = fr->epsfac*fr->c_rf;
  chargeA = mdatoms->chargeA;
  chargeB = mdatoms->chargeB;
  AA = excl->a;
  ki = CENTRAL;

  if (fr->bDomDec)
    niat = excl->nr;
  else
    niat = end;

  q2sumA = 0;
  q2sumB = 0;
  ener = 0;
  if (mdatoms->nChargePerturbed == 0) {
    for(i=start; i<niat; i++) {
      qiA = chargeA[i];
      if (i < end)
	q2sumA += qiA*qiA;
      /* Do the exclusions */
      j1  = excl->index[i];
      j2  = excl->index[i+1];
      for(j=j1; j<j2; j++) {
	k = AA[j];
	if (k > i) {
	  qqA = qiA*chargeA[k];
	  if (qqA != 0) {
	    if (g) {
	      rvec_sub(x[i],x[k],dx);
	      ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt);
	      ki=IVEC2IS(dt);
	    } else if (bMolPBC) {
	      ki = pbc_dx_aiuc(pbc,x[i],x[k],dx);
	    } else
	      rvec_sub(x[i],x[k],dx);
	    ener += qqA*(ek*norm2(dx) - ec);
	    svmul(-2*qqA*ek,dx,df);
	    rvec_inc(f[i],df);
	    rvec_dec(f[k],df);
	    rvec_inc(fshift[ki],df);
	    rvec_dec(fshift[CENTRAL],df);
	  }
	}
      }
    }
    ener += -0.5*ec*q2sumA;
  } else {
    L1 = 1.0 - lambda;
    for(i=start; i<niat; i++) {
      qiA = chargeA[i];
      qiB = chargeB[i];
      if (i < end) {
	q2sumA += qiA*qiA;
	q2sumB += qiB*qiB;
      }
      /* Do the exclusions */
      j1  = excl->index[i];
      j2  = excl->index[i+1];
      for(j=j1; j<j2; j++) {
	k = AA[j];
	if (k > i) {
	  qqA = qiA*chargeA[k];
	  qqB = qiB*chargeB[k];
	  if (qqA != 0 || qqB != 0) {
	    qqL = L1*qqA + lambda*qqB;
	    if (g) {
	      rvec_sub(x[i],x[k],dx);
	      ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt);
	      ki=IVEC2IS(dt);
	    } else if (bMolPBC) {
	      ki = pbc_dx_aiuc(pbc,x[i],x[k],dx);
	    } else
	      rvec_sub(x[i],x[k],dx);
	    v = ek*norm2(dx) - ec;
	    ener += qqL*v;
	    svmul(-2*qqL*ek,dx,df);
	    rvec_inc(f[i],df);
	    rvec_dec(f[k],df);
	    rvec_inc(fshift[ki],df);
	    rvec_dec(fshift[CENTRAL],df);
	    *dvdlambda += (qqB - qqA)*v;
	  }
	}
      }
    }
    ener += -0.5*ec*(L1*q2sumA + lambda*q2sumB);
    *dvdlambda += -0.5*ec*(q2sumB - q2sumA);
  }
  
  if (debug)
    fprintf(debug,"RF exclusion energy: %g\n",ener);
  
  return ener;
}
Пример #24
0
void init_orires(FILE *fplog,const gmx_mtop_t *mtop,
                 rvec xref[],
                 const t_inputrec *ir,
                 const gmx_multisim_t *ms,t_oriresdata *od,
                 t_state *state)
{
    int    i,j,d,ex,nmol,nr,*nr_ex;
    double mtot;
    rvec   com;
    gmx_mtop_ilistloop_t iloop;
    t_ilist *il;
    gmx_mtop_atomloop_all_t aloop;
    t_atom *atom;

    od->fc  = ir->orires_fc;
    od->nex = 0;
    od->S   = NULL;

    od->nr = gmx_mtop_ftype_count(mtop,F_ORIRES);
    if (od->nr == 0)
    {
        return;
    }
    
    nr_ex = NULL;
    
    iloop = gmx_mtop_ilistloop_init(mtop);
    while (gmx_mtop_ilistloop_next(iloop,&il,&nmol))
    {
        for(i=0; i<il[F_ORIRES].nr; i+=3)
        {
            ex = mtop->ffparams.iparams[il[F_ORIRES].iatoms[i]].orires.ex;
            if (ex >= od->nex)
            {
                srenew(nr_ex,ex+1);
                for(j=od->nex; j<ex+1; j++)
                {
                    nr_ex[j] = 0;
            }
                od->nex = ex+1;
            }
            nr_ex[ex]++;
        }
    }
    snew(od->S,od->nex);
    /* When not doing time averaging, the instaneous and time averaged data
     * are indentical and the pointers can point to the same memory.
     */
    snew(od->Dinsl,od->nr);
    if (ms)
    {
        snew(od->Dins,od->nr);
    }
    else
    {
        od->Dins = od->Dinsl;
    }

    if (ir->orires_tau == 0)
    {
        od->Dtav = od->Dins;
        od->edt  = 0.0;
        od->edt1 = 1.0;
    }
    else
    {
        snew(od->Dtav,od->nr);
        od->edt  = exp(-ir->delta_t/ir->orires_tau);
        od->edt1 = 1.0 - od->edt;

        /* Extend the state with the orires history */
        state->flags |= (1<<estORIRE_INITF);
        state->hist.orire_initf = 1;
        state->flags |= (1<<estORIRE_DTAV);
        state->hist.norire_Dtav = od->nr*5;
        snew(state->hist.orire_Dtav,state->hist.norire_Dtav);
    }

    snew(od->oinsl,od->nr);
    if (ms)
    {
        snew(od->oins,od->nr);
    }
    else
    {
        od->oins = od->oinsl;
    }
    if (ir->orires_tau == 0) {
        od->otav = od->oins;
    }
    else
    {
        snew(od->otav,od->nr);
    }
    snew(od->tmp,od->nex);
    snew(od->TMP,od->nex);
    for(ex=0; ex<od->nex; ex++)
    {
        snew(od->TMP[ex],5);
        for(i=0; i<5; i++)
        {
            snew(od->TMP[ex][i],5);
        }
    }
    
    od->nref = 0;
    for(i=0; i<mtop->natoms; i++)
    {
        if (ggrpnr(&mtop->groups,egcORFIT,i) == 0)
        {
            od->nref++;
        }
    }
    snew(od->mref,od->nref);
    snew(od->xref,od->nref);
    snew(od->xtmp,od->nref);
    
    snew(od->eig,od->nex*12);
    
    /* Determine the reference structure on the master node.
     * Copy it to the other nodes after checking multi compatibility,
     * so we are sure the subsystems match before copying.
     */
    clear_rvec(com);
    mtot = 0.0;
    j = 0;
    aloop = gmx_mtop_atomloop_all_init(mtop);
    while(gmx_mtop_atomloop_all_next(aloop,&i,&atom))
    {
        if (mtop->groups.grpnr[egcORFIT] == NULL ||
            mtop->groups.grpnr[egcORFIT][i] == 0)
        {
            /* Not correct for free-energy with changing masses */
            od->mref[j] = atom->m;
            if (ms==NULL || MASTERSIM(ms))
            {
                copy_rvec(xref[i],od->xref[j]);
                for(d=0; d<DIM; d++)
                {
                    com[d] += od->mref[j]*xref[i][d];
                }
            }
            mtot += od->mref[j];
            j++;
        }
    }
    svmul(1.0/mtot,com,com);
    if (ms==NULL || MASTERSIM(ms))
    {
        for(j=0; j<od->nref; j++)
        {
            rvec_dec(od->xref[j],com);
        }
    }
    
    fprintf(fplog,"Found %d orientation experiments\n",od->nex);
    for(i=0; i<od->nex; i++)
    {
        fprintf(fplog,"  experiment %d has %d restraints\n",i+1,nr_ex[i]);
    }
    
    sfree(nr_ex);
    
    fprintf(fplog,"  the fit group consists of %d atoms and has total mass %g\n",
            od->nref,mtot);
    
    if (ms)
    {
        fprintf(fplog,"  the orientation restraints are ensemble averaged over %d systems\n",ms->nsim);
        
        check_multi_int(fplog,ms,od->nr,
                        "the number of orientation restraints");
        check_multi_int(fplog,ms,od->nref,
                        "the number of fit atoms for orientation restraining");
        check_multi_int(fplog,ms,ir->nsteps,"nsteps");
        /* Copy the reference coordinates from the master to the other nodes */
        gmx_sum_sim(DIM*od->nref,od->xref[0],ms);
    }
    
    please_cite(fplog,"Hess2003");
}
Пример #25
0
static void list_trn(char *fn)
{
  static real mass[5] = { 15.9994, 1.008, 1.008, 0.0, 0.0 };
  int         i,j=0,m,fpread,fpwrite,nframe;
  rvec        *x,*v,*f,fmol[2],xcm[2],torque[j],dx;
  real        mmm,len;
  matrix      box;
  t_trnheader trn;
  gmx_bool        bOK;

  printf("Going to open %s\n",fn);
  fpread  = open_trn(fn,"r"); 
  fpwrite = open_tpx(NULL,"w");
  gmx_fio_setdebug(fpwrite,TRUE);
  
  mmm=mass[0]+2*mass[1];
  for(i=0; (i<5); i++) 
    mass[i] /= mmm;
  
  nframe = 0;
  while (fread_trnheader(fpread,&trn,&bOK)) {
    snew(x,trn.natoms);
    snew(v,trn.natoms);
    snew(f,trn.natoms);
    if (fread_htrn(fpread,&trn,
		   trn.box_size ? box : NULL,
		   trn.x_size   ? x : NULL,
		   trn.v_size   ? v : NULL,
		   trn.f_size   ? f : NULL)) {
		   
      if (trn.x_size && trn.f_size) {
	printf("There are %d atoms\n",trn.natoms);
	for(j=0; (j<2); j++) {
	  clear_rvec(xcm[j]);
	  clear_rvec(fmol[j]);
	  clear_rvec(torque[j]);
	  for(i=5*j; (i<5*j+5); i++) {
	    rvec_inc(fmol[j],f[i]);
	    for(m=0; (m<DIM); m++)
	      xcm[j][m] += mass[i%5]*x[i][m];
	  }
	  for(i=5*j; (i<5*j+5); i++) {
	    rvec_dec(x[i],xcm[j]);
	    cprod(x[i],f[i],dx);
	    rvec_inc(torque[j],dx);
	    rvec_inc(x[i],xcm[j]);
	  }
	}
	pr_rvecs(stdout,0,"FMOL  ",fmol,2);
	pr_rvecs(stdout,0,"TORQUE",torque,2);
	printf("Distance matrix Water1-Water2\n%5s","");
	for(j=0; (j<5); j++) 
	  printf("  %10s",nm[j]);
	printf("\n");
	for(j=0; (j<5); j++) {
	  printf("%5s",nm[j]);
	  for(i=5; (i<10); i++) {
	    rvec_sub(x[i],x[j],dx);
	    len = sqrt(iprod(dx,dx));
	    printf("  %10.7f",len);
	  }
	  printf("\n");
	}
      }
    }
    sfree(x);
    sfree(v);
    sfree(f);
    nframe++;
  }
  if (!bOK)
    fprintf(stderr,"\nWARNING: Incomplete frame header: nr %d, t=%g\n",
	    nframe,trn.t);
  close_tpx(fpwrite);
  close_trn(fpread);
}
Пример #26
0
real calc_orires_dev(const gmx_multisim_t *ms,
                     int nfa,const t_iatom forceatoms[],const t_iparams ip[],
                     const t_mdatoms *md,const rvec x[],const t_pbc *pbc,
                     t_fcdata *fcd,history_t *hist)
{
    int          fa,d,i,j,type,ex,nref;
    real         edt,edt1,invn,pfac,r2,invr,corrfac,weight,wsv2,sw,dev;
    tensor       *S,R,TMP;
    rvec5        *Dinsl,*Dins,*Dtav,*rhs;
    real         *mref,***T;
    double       mtot;
    rvec         *xref,*xtmp,com,r_unrot,r;
    t_oriresdata *od;
    bool         bTAV;
    const real   two_thr=2.0/3.0;
    
    od = &(fcd->orires);

    if (od->nr == 0)
    {
        /* This means that this is not the master node */
        gmx_fatal(FARGS,"Orientation restraints are only supported on the master node, use less processors");
    }
    
    bTAV = (od->edt != 0);
    edt  = od->edt;
    edt1 = od->edt1;
    S    = od->S;
    Dinsl= od->Dinsl;
    Dins = od->Dins;
    Dtav = od->Dtav;
    T    = od->TMP;
    rhs  = od->tmp;
    nref = od->nref;
    mref = od->mref;
    xref = od->xref;
    xtmp = od->xtmp;
    
    if (bTAV)
    {
        od->exp_min_t_tau = hist->orire_initf*edt;
        
        /* Correction factor to correct for the lack of history
         * at short times.
         */
        corrfac = 1.0/(1.0 - od->exp_min_t_tau);
    }
    else
    {
        corrfac = 1.0;
    }

    if (ms)
    {
        invn = 1.0/ms->nsim;
    }
    else
    {
        invn = 1.0;
    }
    
    clear_rvec(com);
    mtot = 0;
    j=0;
    for(i=0; i<md->nr; i++)
    {
        if (md->cORF[i] == 0)
        {
            copy_rvec(x[i],xtmp[j]);
            mref[j] = md->massT[i];
            for(d=0; d<DIM; d++)
            {
                com[d] += mref[j]*xref[j][d];
            }
            mtot += mref[j];
            j++;
        }
    }
    svmul(1.0/mtot,com,com);
    for(j=0; j<nref; j++)
    {
        rvec_dec(xtmp[j],com);
    }
    /* Calculate the rotation matrix to rotate x to the reference orientation */
    calc_fit_R(DIM,nref,mref,xref,xtmp,R);
    copy_mat(R,od->R);
    
    d = 0;
    for(fa=0; fa<nfa; fa+=3)
    {
        type = forceatoms[fa];
        if (pbc)
        {
            pbc_dx_aiuc(pbc,x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot);
        }
        else
        {
            rvec_sub(x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot);
        }
        mvmul(R,r_unrot,r);
        r2   = norm2(r);
        invr = invsqrt(r2);
        /* Calculate the prefactor for the D tensor, this includes the factor 3! */
        pfac = ip[type].orires.c*invr*invr*3;
        for(i=0; i<ip[type].orires.power; i++)
        {
            pfac *= invr;
        }
        Dinsl[d][0] = pfac*(2*r[0]*r[0] + r[1]*r[1] - r2);
        Dinsl[d][1] = pfac*(2*r[0]*r[1]);
        Dinsl[d][2] = pfac*(2*r[0]*r[2]);
        Dinsl[d][3] = pfac*(2*r[1]*r[1] + r[0]*r[0] - r2);
        Dinsl[d][4] = pfac*(2*r[1]*r[2]);
        
        if (ms)
        {
            for(i=0; i<5; i++)
            {
                Dins[d][i] = Dinsl[d][i]*invn;
            }
        }

        d++;
    }
  
    if (ms)
    {
        gmx_sum_sim(5*od->nr,Dins[0],ms);
    }
   
    /* Calculate the order tensor S for each experiment via optimization */
    for(ex=0; ex<od->nex; ex++)
    {
        for(i=0; i<5; i++)
        {
            rhs[ex][i] = 0;
            for(j=0; j<=i; j++)
            {
                T[ex][i][j] = 0;
            }
        }
    }
    d = 0;
    for(fa=0; fa<nfa; fa+=3)
    {
        if (bTAV)
        {
            /* Here we update Dtav in t_fcdata using the data in history_t.
             * Thus the results stay correct when this routine
             * is called multiple times.
             */
            for(i=0; i<5; i++)
            {
                Dtav[d][i] = edt*hist->orire_Dtav[d*5+i] + edt1*Dins[d][i];
            }
        }
        
        type   = forceatoms[fa];
        ex     = ip[type].orires.ex;
        weight = ip[type].orires.kfac;
        /* Calculate the vector rhs and half the matrix T for the 5 equations */
        for(i=0; i<5; i++) {
            rhs[ex][i] += Dtav[d][i]*ip[type].orires.obs*weight;
            for(j=0; j<=i; j++)
            {
                T[ex][i][j] += Dtav[d][i]*Dtav[d][j]*weight;
            }
        }
        d++;
    }
    /* Now we have all the data we can calculate S */
    for(ex=0; ex<od->nex; ex++)
    {
        /* Correct corrfac and copy one half of T to the other half */
        for(i=0; i<5; i++)
        {
            rhs[ex][i]  *= corrfac;
            T[ex][i][i] *= sqr(corrfac);
            for(j=0; j<i; j++)
            {
                T[ex][i][j] *= sqr(corrfac);
                T[ex][j][i]  = T[ex][i][j];
            }
        }
        m_inv_gen(T[ex],5,T[ex]);
        /* Calculate the orientation tensor S for this experiment */
        S[ex][0][0] = 0;
        S[ex][0][1] = 0;
        S[ex][0][2] = 0;
        S[ex][1][1] = 0;
        S[ex][1][2] = 0;
        for(i=0; i<5; i++)
        {
            S[ex][0][0] += 1.5*T[ex][0][i]*rhs[ex][i];
            S[ex][0][1] += 1.5*T[ex][1][i]*rhs[ex][i];
            S[ex][0][2] += 1.5*T[ex][2][i]*rhs[ex][i];
            S[ex][1][1] += 1.5*T[ex][3][i]*rhs[ex][i];
            S[ex][1][2] += 1.5*T[ex][4][i]*rhs[ex][i];
        }
        S[ex][1][0] = S[ex][0][1];
        S[ex][2][0] = S[ex][0][2];
        S[ex][2][1] = S[ex][1][2];
        S[ex][2][2] = -S[ex][0][0] - S[ex][1][1];
    }
    
    wsv2 = 0;
    sw   = 0;
    
    d = 0;
    for(fa=0; fa<nfa; fa+=3)
    {
        type = forceatoms[fa];
        ex = ip[type].orires.ex;
        
        od->otav[d] = two_thr*
            corrfac*(S[ex][0][0]*Dtav[d][0] + S[ex][0][1]*Dtav[d][1] +
                     S[ex][0][2]*Dtav[d][2] + S[ex][1][1]*Dtav[d][3] +
                     S[ex][1][2]*Dtav[d][4]);
        if (bTAV)
        {
            od->oins[d] = two_thr*(S[ex][0][0]*Dins[d][0] + S[ex][0][1]*Dins[d][1] +
                                   S[ex][0][2]*Dins[d][2] + S[ex][1][1]*Dins[d][3] +
                                   S[ex][1][2]*Dins[d][4]);
        }
        if (ms)
        {
            /* When ensemble averaging is used recalculate the local orientation
             * for output to the energy file.
             */
            od->oinsl[d] = two_thr*
                (S[ex][0][0]*Dinsl[d][0] + S[ex][0][1]*Dinsl[d][1] +
                 S[ex][0][2]*Dinsl[d][2] + S[ex][1][1]*Dinsl[d][3] +
                 S[ex][1][2]*Dinsl[d][4]);
        }
        
        dev = od->otav[d] - ip[type].orires.obs;
        
        wsv2 += ip[type].orires.kfac*sqr(dev);
        sw   += ip[type].orires.kfac;
        
        d++;
    }
    od->rmsdev = sqrt(wsv2/sw);
    
    /* Rotate the S matrices back, so we get the correct grad(tr(S D)) */
    for(ex=0; ex<od->nex; ex++)
    {
        tmmul(R,S[ex],TMP);
        mmul(TMP,R,S[ex]);
    }
    
    return od->rmsdev;
    
    /* Approx. 120*nfa/3 flops */
}
Пример #27
0
/* There's nothing special to do here if just masses are perturbed,
 * but if either charge or type is perturbed then the implementation
 * requires that B states are defined for both charge and type, and
 * does not optimize for the cases where only one changes.
 *
 * The parameter vectors for B states are left undefined in atoms2md()
 * when either FEP is inactive, or when there are no mass/charge/type
 * perturbations. The parameter vectors for LJ-PME are likewise
 * undefined when LJ-PME is not active. This works because
 * bHaveChargeOrTypePerturbed handles the control flow. */
void ewald_LRcorrection(int numAtomsLocal,
                        t_commrec *cr,
                        int numThreads, int thread,
                        t_forcerec *fr,
                        real *chargeA, real *chargeB,
                        real *C6A, real *C6B,
                        real *sigmaA, real *sigmaB,
                        real *sigma3A, real *sigma3B,
                        gmx_bool bHaveChargeOrTypePerturbed,
                        gmx_bool calc_excl_corr,
                        t_blocka *excl, rvec x[],
                        matrix box, rvec mu_tot[],
                        int ewald_geometry, real epsilon_surface,
                        rvec *f, tensor vir_q, tensor vir_lj,
                        real *Vcorr_q, real *Vcorr_lj,
                        real lambda_q, real lambda_lj,
                        real *dvdlambda_q, real *dvdlambda_lj)
{
    int numAtomsToBeCorrected;
    if (calc_excl_corr)
    {
        /* We need to correct all exclusion pairs (cutoff-scheme = group) */
        numAtomsToBeCorrected = excl->nr;

        GMX_RELEASE_ASSERT(numAtomsToBeCorrected >= numAtomsLocal, "We might need to do self-corrections");
    }
    else
    {
        /* We need to correct only self interactions */
        numAtomsToBeCorrected = numAtomsLocal;
    }
    int         start =  (numAtomsToBeCorrected* thread     )/numThreads;
    int         end   =  (numAtomsToBeCorrected*(thread + 1))/numThreads;

    int         i, i1, i2, j, k, m, iv, jv, q;
    int        *AA;
    double      Vexcl_q, dvdl_excl_q, dvdl_excl_lj; /* Necessary for precision */
    double      Vexcl_lj;
    real        one_4pi_eps;
    real        v, vc, qiA, qiB, dr2, rinv;
    real        Vself_q[2], Vself_lj[2], Vdipole[2], rinv2, ewc_q = fr->ewaldcoeff_q, ewcdr;
    real        ewc_lj = fr->ewaldcoeff_lj, ewc_lj2 = ewc_lj * ewc_lj;
    real        c6Ai   = 0, c6Bi = 0, c6A = 0, c6B = 0, ewcdr2, ewcdr4, c6L = 0, rinv6;
    rvec        df, dx, mutot[2], dipcorrA, dipcorrB;
    tensor      dxdf_q = {{0}}, dxdf_lj = {{0}};
    real        vol    = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
    real        L1_q, L1_lj, dipole_coeff, qqA, qqB, qqL, vr0_q, vr0_lj = 0;
    gmx_bool    bMolPBC      = fr->bMolPBC;
    gmx_bool    bDoingLBRule = (fr->ljpme_combination_rule == eljpmeLB);
    gmx_bool    bNeedLongRangeCorrection;

    /* This routine can be made faster by using tables instead of analytical interactions
     * However, that requires a thorough verification that they are correct in all cases.
     */

    one_4pi_eps   = ONE_4PI_EPS0/fr->epsilon_r;
    vr0_q         = ewc_q*M_2_SQRTPI;
    if (EVDW_PME(fr->vdwtype))
    {
        vr0_lj    = -gmx::power6(ewc_lj)/6.0;
    }

    AA           = excl->a;
    Vexcl_q      = 0;
    Vexcl_lj     = 0;
    dvdl_excl_q  = 0;
    dvdl_excl_lj = 0;
    Vdipole[0]   = 0;
    Vdipole[1]   = 0;
    L1_q         = 1.0-lambda_q;
    L1_lj        = 1.0-lambda_lj;
    /* Note that we have to transform back to gromacs units, since
     * mu_tot contains the dipole in debye units (for output).
     */
    for (i = 0; (i < DIM); i++)
    {
        mutot[0][i] = mu_tot[0][i]*DEBYE2ENM;
        mutot[1][i] = mu_tot[1][i]*DEBYE2ENM;
        dipcorrA[i] = 0;
        dipcorrB[i] = 0;
    }
    dipole_coeff = 0;
    switch (ewald_geometry)
    {
        case eewg3D:
            if (epsilon_surface != 0)
            {
                dipole_coeff =
                    2*M_PI*ONE_4PI_EPS0/((2*epsilon_surface + fr->epsilon_r)*vol);
                for (i = 0; (i < DIM); i++)
                {
                    dipcorrA[i] = 2*dipole_coeff*mutot[0][i];
                    dipcorrB[i] = 2*dipole_coeff*mutot[1][i];
                }
            }
            break;
        case eewg3DC:
            dipole_coeff = 2*M_PI*one_4pi_eps/vol;
            dipcorrA[ZZ] = 2*dipole_coeff*mutot[0][ZZ];
            dipcorrB[ZZ] = 2*dipole_coeff*mutot[1][ZZ];
            break;
        default:
            gmx_incons("Unsupported Ewald geometry");
            break;
    }
    if (debug)
    {
        fprintf(debug, "dipcorr = %8.3f  %8.3f  %8.3f\n",
                dipcorrA[XX], dipcorrA[YY], dipcorrA[ZZ]);
        fprintf(debug, "mutot   = %8.3f  %8.3f  %8.3f\n",
                mutot[0][XX], mutot[0][YY], mutot[0][ZZ]);
    }
    bNeedLongRangeCorrection = (calc_excl_corr || dipole_coeff != 0);
    if (bNeedLongRangeCorrection && !bHaveChargeOrTypePerturbed)
    {
        for (i = start; (i < end); i++)
        {
            /* Initiate local variables (for this i-particle) to 0 */
            qiA = chargeA[i]*one_4pi_eps;
            if (EVDW_PME(fr->vdwtype))
            {
                c6Ai = C6A[i];
                if (bDoingLBRule)
                {
                    c6Ai *= sigma3A[i];
                }
            }
            if (calc_excl_corr)
            {
                i1  = excl->index[i];
                i2  = excl->index[i+1];

                /* Loop over excluded neighbours */
                for (j = i1; (j < i2); j++)
                {
                    k = AA[j];
                    /*
                     * First we must test whether k <> i, and then,
                     * because the exclusions are all listed twice i->k
                     * and k->i we must select just one of the two.  As
                     * a minor optimization we only compute forces when
                     * the charges are non-zero.
                     */
                    if (k > i)
                    {
                        qqA = qiA*chargeA[k];
                        if (EVDW_PME(fr->vdwtype))
                        {
                            c6A  = c6Ai * C6A[k];
                            if (bDoingLBRule)
                            {
                                c6A *= gmx::power6(0.5*(sigmaA[i]+sigmaA[k]))*sigma3A[k];
                            }
                        }
                        if (qqA != 0.0 || c6A != 0.0)
                        {
                            rvec_sub(x[i], x[k], dx);
                            if (bMolPBC)
                            {
                                /* Cheap pbc_dx, assume excluded pairs are at short distance. */
                                for (m = DIM-1; (m >= 0); m--)
                                {
                                    if (dx[m] > 0.5*box[m][m])
                                    {
                                        rvec_dec(dx, box[m]);
                                    }
                                    else if (dx[m] < -0.5*box[m][m])
                                    {
                                        rvec_inc(dx, box[m]);
                                    }
                                }
                            }
                            dr2 = norm2(dx);
                            /* Distance between two excluded particles
                             * may be zero in the case of shells
                             */
                            if (dr2 != 0)
                            {
                                rinv              = gmx::invsqrt(dr2);
                                rinv2             = rinv*rinv;
                                if (qqA != 0.0)
                                {
                                    real dr, fscal;

                                    dr       = 1.0/rinv;
                                    ewcdr    = ewc_q*dr;
                                    vc       = qqA*std::erf(ewcdr)*rinv;
                                    Vexcl_q += vc;
#if GMX_DOUBLE
                                    /* Relative accuracy at R_ERF_R_INACC of 3e-10 */
#define       R_ERF_R_INACC 0.006
#else
                                    /* Relative accuracy at R_ERF_R_INACC of 2e-5 */
#define       R_ERF_R_INACC 0.1
#endif
                                    /* fscal is the scalar force pre-multiplied by rinv,
                                     * to normalise the relative position vector dx */
                                    if (ewcdr > R_ERF_R_INACC)
                                    {
                                        fscal = rinv2*(vc - qqA*ewc_q*M_2_SQRTPI*exp(-ewcdr*ewcdr));
                                    }
                                    else
                                    {
                                        /* Use a fourth order series expansion for small ewcdr */
                                        fscal = ewc_q*ewc_q*qqA*vr0_q*(2.0/3.0 - 0.4*ewcdr*ewcdr);
                                    }

                                    /* The force vector is obtained by multiplication with
                                     * the relative position vector
                                     */
                                    svmul(fscal, dx, df);
                                    rvec_inc(f[k], df);
                                    rvec_dec(f[i], df);
                                    for (iv = 0; (iv < DIM); iv++)
                                    {
                                        for (jv = 0; (jv < DIM); jv++)
                                        {
                                            dxdf_q[iv][jv] += dx[iv]*df[jv];
                                        }
                                    }
                                }

                                if (c6A != 0.0)
                                {
                                    real fscal;

                                    rinv6     = rinv2*rinv2*rinv2;
                                    ewcdr2    = ewc_lj2*dr2;
                                    ewcdr4    = ewcdr2*ewcdr2;
                                    /* We get the excluded long-range contribution from -C6*(1-g(r))
                                     * g(r) is also defined in the manual under LJ-PME
                                     */
                                    vc        = -c6A*rinv6*(1.0 - exp(-ewcdr2)*(1 + ewcdr2 + 0.5*ewcdr4));
                                    Vexcl_lj += vc;
                                    /* The force is the derivative of the potential vc.
                                     * fscal is the scalar force pre-multiplied by rinv,
                                     * to normalise the relative position vector dx */
                                    fscal     = 6.0*vc*rinv2 + c6A*rinv6*exp(-ewcdr2)*ewc_lj2*ewcdr4;

                                    /* The force vector is obtained by multiplication with
                                     * the relative position vector
                                     */
                                    svmul(fscal, dx, df);
                                    rvec_inc(f[k], df);
                                    rvec_dec(f[i], df);
                                    for (iv = 0; (iv < DIM); iv++)
                                    {
                                        for (jv = 0; (jv < DIM); jv++)
                                        {
                                            dxdf_lj[iv][jv] += dx[iv]*df[jv];
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Vexcl_q  += qqA*vr0_q;
                                Vexcl_lj += c6A*vr0_lj;
                            }
                        }
                    }
                }
            }
            /* Dipole correction on force */
            if (dipole_coeff != 0 && i < numAtomsLocal)
            {
                for (j = 0; (j < DIM); j++)
                {
                    f[i][j] -= dipcorrA[j]*chargeA[i];
                }
            }
        }
    }
    else if (bNeedLongRangeCorrection)
    {
        for (i = start; (i < end); i++)
        {
            /* Initiate local variables (for this i-particle) to 0 */
            qiA = chargeA[i]*one_4pi_eps;
            qiB = chargeB[i]*one_4pi_eps;
            if (EVDW_PME(fr->vdwtype))
            {
                c6Ai = C6A[i];
                c6Bi = C6B[i];
                if (bDoingLBRule)
                {
                    c6Ai *= sigma3A[i];
                    c6Bi *= sigma3B[i];
                }
            }
            if (calc_excl_corr)
            {
                i1  = excl->index[i];
                i2  = excl->index[i+1];

                /* Loop over excluded neighbours */
                for (j = i1; (j < i2); j++)
                {
                    k = AA[j];
                    if (k > i)
                    {
                        qqA = qiA*chargeA[k];
                        qqB = qiB*chargeB[k];
                        if (EVDW_PME(fr->vdwtype))
                        {
                            c6A = c6Ai*C6A[k];
                            c6B = c6Bi*C6B[k];
                            if (bDoingLBRule)
                            {
                                c6A *= gmx::power6(0.5*(sigmaA[i]+sigmaA[k]))*sigma3A[k];
                                c6B *= gmx::power6(0.5*(sigmaB[i]+sigmaB[k]))*sigma3B[k];
                            }
                        }
                        if (qqA != 0.0 || qqB != 0.0 || c6A != 0.0 || c6B != 0.0)
                        {
                            real fscal;

                            qqL   = L1_q*qqA + lambda_q*qqB;
                            if (EVDW_PME(fr->vdwtype))
                            {
                                c6L = L1_lj*c6A + lambda_lj*c6B;
                            }
                            rvec_sub(x[i], x[k], dx);
                            if (bMolPBC)
                            {
                                /* Cheap pbc_dx, assume excluded pairs are at short distance. */
                                for (m = DIM-1; (m >= 0); m--)
                                {
                                    if (dx[m] > 0.5*box[m][m])
                                    {
                                        rvec_dec(dx, box[m]);
                                    }
                                    else if (dx[m] < -0.5*box[m][m])
                                    {
                                        rvec_inc(dx, box[m]);
                                    }
                                }
                            }
                            dr2 = norm2(dx);
                            if (dr2 != 0)
                            {
                                rinv    = gmx::invsqrt(dr2);
                                rinv2   = rinv*rinv;
                                if (qqA != 0.0 || qqB != 0.0)
                                {
                                    real dr;

                                    dr           = 1.0/rinv;
                                    v            = std::erf(ewc_q*dr)*rinv;
                                    vc           = qqL*v;
                                    Vexcl_q     += vc;
                                    /* fscal is the scalar force pre-multiplied by rinv,
                                     * to normalise the relative position vector dx */
                                    fscal        = rinv2*(vc-qqL*ewc_q*M_2_SQRTPI*exp(-ewc_q*ewc_q*dr2));
                                    dvdl_excl_q += (qqB - qqA)*v;

                                    /* The force vector is obtained by multiplication with
                                     * the relative position vector
                                     */
                                    svmul(fscal, dx, df);
                                    rvec_inc(f[k], df);
                                    rvec_dec(f[i], df);
                                    for (iv = 0; (iv < DIM); iv++)
                                    {
                                        for (jv = 0; (jv < DIM); jv++)
                                        {
                                            dxdf_q[iv][jv] += dx[iv]*df[jv];
                                        }
                                    }
                                }

                                if ((c6A != 0.0 || c6B != 0.0) && EVDW_PME(fr->vdwtype))
                                {
                                    rinv6         = rinv2*rinv2*rinv2;
                                    ewcdr2        = ewc_lj2*dr2;
                                    ewcdr4        = ewcdr2*ewcdr2;
                                    v             = -rinv6*(1.0 - exp(-ewcdr2)*(1 + ewcdr2 + 0.5*ewcdr4));
                                    vc            = c6L*v;
                                    Vexcl_lj     += vc;
                                    /* fscal is the scalar force pre-multiplied by rinv,
                                     * to normalise the relative position vector dx */
                                    fscal         = 6.0*vc*rinv2 + c6L*rinv6*exp(-ewcdr2)*ewc_lj2*ewcdr4;
                                    dvdl_excl_lj += (c6B - c6A)*v;

                                    /* The force vector is obtained by multiplication with
                                     * the relative position vector
                                     */
                                    svmul(fscal, dx, df);
                                    rvec_inc(f[k], df);
                                    rvec_dec(f[i], df);
                                    for (iv = 0; (iv < DIM); iv++)
                                    {
                                        for (jv = 0; (jv < DIM); jv++)
                                        {
                                            dxdf_lj[iv][jv] += dx[iv]*df[jv];
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Vexcl_q      += qqL*vr0_q;
                                dvdl_excl_q  += (qqB - qqA)*vr0_q;
                                Vexcl_lj     += c6L*vr0_lj;
                                dvdl_excl_lj += (c6B - c6A)*vr0_lj;
                            }
                        }
                    }
                }
            }
            /* Dipole correction on force */
            if (dipole_coeff != 0 && i < numAtomsLocal)
            {
                for (j = 0; (j < DIM); j++)
                {
                    f[i][j] -= L1_q*dipcorrA[j]*chargeA[i]
                        + lambda_q*dipcorrB[j]*chargeB[i];
                }
            }
        }
    }
    for (iv = 0; (iv < DIM); iv++)
    {
        for (jv = 0; (jv < DIM); jv++)
        {
            vir_q[iv][jv]  += 0.5*dxdf_q[iv][jv];
            vir_lj[iv][jv] += 0.5*dxdf_lj[iv][jv];
        }
    }

    Vself_q[0]  = 0;
    Vself_q[1]  = 0;
    Vself_lj[0] = 0;
    Vself_lj[1] = 0;

    /* Global corrections only on master process */
    if (MASTER(cr) && thread == 0)
    {
        for (q = 0; q < (bHaveChargeOrTypePerturbed ? 2 : 1); q++)
        {
            if (calc_excl_corr)
            {
                /* Self-energy correction */
                Vself_q[q] = ewc_q*one_4pi_eps*fr->q2sum[q]*M_1_SQRTPI;
                if (EVDW_PME(fr->vdwtype))
                {
                    Vself_lj[q] =  fr->c6sum[q]*0.5*vr0_lj;
                }
            }

            /* Apply surface dipole correction:
             * correction = dipole_coeff * (dipole)^2
             */
            if (dipole_coeff != 0)
            {
                if (ewald_geometry == eewg3D)
                {
                    Vdipole[q] = dipole_coeff*iprod(mutot[q], mutot[q]);
                }
                else if (ewald_geometry == eewg3DC)
                {
                    Vdipole[q] = dipole_coeff*mutot[q][ZZ]*mutot[q][ZZ];
                }
            }
        }
    }
    if (!bHaveChargeOrTypePerturbed)
    {
        *Vcorr_q = Vdipole[0] - Vself_q[0] - Vexcl_q;
        if (EVDW_PME(fr->vdwtype))
        {
            *Vcorr_lj = -Vself_lj[0] - Vexcl_lj;
        }
    }
    else
    {
        *Vcorr_q = L1_q*(Vdipole[0] - Vself_q[0])
            + lambda_q*(Vdipole[1] - Vself_q[1])
            - Vexcl_q;
        *dvdlambda_q += Vdipole[1] - Vself_q[1]
            - (Vdipole[0] - Vself_q[0]) - dvdl_excl_q;
        if (EVDW_PME(fr->vdwtype))
        {
            *Vcorr_lj      = -(L1_lj*Vself_lj[0] + lambda_lj*Vself_lj[1]) - Vexcl_lj;
            *dvdlambda_lj += -Vself_lj[1] + Vself_lj[0] - dvdl_excl_lj;
        }
    }

    if (debug)
    {
        fprintf(debug, "Long Range corrections for Ewald interactions:\n");
        fprintf(debug, "q2sum = %g, Vself_q=%g c6sum = %g, Vself_lj=%g\n",
                L1_q*fr->q2sum[0]+lambda_q*fr->q2sum[1], L1_q*Vself_q[0]+lambda_q*Vself_q[1], L1_lj*fr->c6sum[0]+lambda_lj*fr->c6sum[1], L1_lj*Vself_lj[0]+lambda_lj*Vself_lj[1]);
        fprintf(debug, "Electrostatic Long Range correction: Vexcl=%g\n", Vexcl_q);
        fprintf(debug, "Lennard-Jones Long Range correction: Vexcl=%g\n", Vexcl_lj);
        if (MASTER(cr) && thread == 0)
        {
            if (epsilon_surface > 0 || ewald_geometry == eewg3DC)
            {
                fprintf(debug, "Total dipole correction: Vdipole=%g\n",
                        L1_q*Vdipole[0]+lambda_q*Vdipole[1]);
            }
        }
    }
}
Пример #28
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;
}
Пример #29
0
double do_tpi(FILE *fplog, t_commrec *cr,
              int nfile, const t_filenm fnm[],
              const output_env_t oenv, gmx_bool bVerbose, gmx_bool gmx_unused bCompact,
              int gmx_unused nstglobalcomm,
              gmx_vsite_t gmx_unused *vsite, gmx_constr_t gmx_unused constr,
              int gmx_unused stepout,
              t_inputrec *inputrec,
              gmx_mtop_t *top_global, t_fcdata *fcd,
              t_state *state,
              t_mdatoms *mdatoms,
              t_nrnb *nrnb, gmx_wallcycle_t wcycle,
              gmx_edsam_t gmx_unused ed,
              t_forcerec *fr,
              int gmx_unused repl_ex_nst, int gmx_unused repl_ex_nex, int gmx_unused repl_ex_seed,
              gmx_membed_t gmx_unused membed,
              real gmx_unused cpt_period, real gmx_unused max_hours,
              const char gmx_unused *deviceOptions,
              int gmx_unused imdport,
              unsigned long gmx_unused Flags,
              gmx_walltime_accounting_t walltime_accounting)
{
    const char     *TPI = "Test Particle Insertion";
    gmx_localtop_t *top;
    gmx_groups_t   *groups;
    gmx_enerdata_t *enerd;
    rvec           *f;
    real            lambda, t, temp, beta, drmax, epot;
    double          embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
    t_trxstatus    *status;
    t_trxframe      rerun_fr;
    gmx_bool        bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
    tensor          force_vir, shake_vir, vir, pres;
    int             cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e;
    rvec           *x_mol;
    rvec            mu_tot, x_init, dx, x_tp;
    int             nnodes, frame;
    gmx_int64_t     frame_step_prev, frame_step;
    gmx_int64_t     nsteps, stepblocksize = 0, step;
    gmx_int64_t     rnd_count_stride, rnd_count;
    gmx_int64_t     seed;
    double          rnd[4];
    int             i, start, end;
    FILE           *fp_tpi = NULL;
    char           *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
    double          dbl, dump_ener;
    gmx_bool        bCavity;
    int             nat_cavity  = 0, d;
    real           *mass_cavity = NULL, mass_tot;
    int             nbin;
    double          invbinw, *bin, refvolshift, logV, bUlogV;
    real            dvdl, prescorr, enercorr, dvdlcorr;
    gmx_bool        bEnergyOutOfBounds;
    const char     *tpid_leg[2] = {"direct", "reweighted"};

    /* Since there is no upper limit to the insertion energies,
     * we need to set an upper limit for the distribution output.
     */
    real bU_bin_limit      = 50;
    real bU_logV_bin_limit = bU_bin_limit + 10;

    nnodes = cr->nnodes;

    top = gmx_mtop_generate_local_top(top_global, inputrec);

    groups = &top_global->groups;

    bCavity = (inputrec->eI == eiTPIC);
    if (bCavity)
    {
        ptr = getenv("GMX_TPIC_MASSES");
        if (ptr == NULL)
        {
            nat_cavity = 1;
        }
        else
        {
            /* Read (multiple) masses from env var GMX_TPIC_MASSES,
             * The center of mass of the last atoms is then used for TPIC.
             */
            nat_cavity = 0;
            while (sscanf(ptr, "%lf%n", &dbl, &i) > 0)
            {
                srenew(mass_cavity, nat_cavity+1);
                mass_cavity[nat_cavity] = dbl;
                fprintf(fplog, "mass[%d] = %f\n",
                        nat_cavity+1, mass_cavity[nat_cavity]);
                nat_cavity++;
                ptr += i;
            }
            if (nat_cavity == 0)
            {
                gmx_fatal(FARGS, "Found %d masses in GMX_TPIC_MASSES", nat_cavity);
            }
        }
    }

    /*
       init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot,
       state->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/
    /* We never need full pbc for TPI */
    fr->ePBC = epbcXYZ;
    /* Determine the temperature for the Boltzmann weighting */
    temp = inputrec->opts.ref_t[0];
    if (fplog)
    {
        for (i = 1; (i < inputrec->opts.ngtc); i++)
        {
            if (inputrec->opts.ref_t[i] != temp)
            {
                fprintf(fplog, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n");
                fprintf(stderr, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n");
            }
        }
        fprintf(fplog,
                "\n  The temperature for test particle insertion is %.3f K\n\n",
                temp);
    }
    beta = 1.0/(BOLTZ*temp);

    /* Number of insertions per frame */
    nsteps = inputrec->nsteps;

    /* Use the same neighborlist with more insertions points
     * in a sphere of radius drmax around the initial point
     */
    /* This should be a proper mdp parameter */
    drmax = inputrec->rtpi;

    /* An environment variable can be set to dump all configurations
     * to pdb with an insertion energy <= this value.
     */
    dump_pdb  = getenv("GMX_TPI_DUMP");
    dump_ener = 0;
    if (dump_pdb)
    {
        sscanf(dump_pdb, "%lf", &dump_ener);
    }

    atoms2md(top_global, inputrec, 0, NULL, top_global->natoms, mdatoms);
    update_mdatoms(mdatoms, inputrec->fepvals->init_lambda);

    snew(enerd, 1);
    init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd);
    snew(f, top_global->natoms);

    /* Print to log file  */
    walltime_accounting_start(walltime_accounting);
    wallcycle_start(wcycle, ewcRUN);
    print_start(fplog, cr, walltime_accounting, "Test Particle Insertion");

    /* The last charge group is the group to be inserted */
    cg_tp = top->cgs.nr - 1;
    a_tp0 = top->cgs.index[cg_tp];
    a_tp1 = top->cgs.index[cg_tp+1];
    if (debug)
    {
        fprintf(debug, "TPI cg %d, atoms %d-%d\n", cg_tp, a_tp0, a_tp1);
    }
    if (a_tp1 - a_tp0 > 1 &&
        (inputrec->rlist < inputrec->rcoulomb ||
         inputrec->rlist < inputrec->rvdw))
    {
        gmx_fatal(FARGS, "Can not do TPI for multi-atom molecule with a twin-range cut-off");
    }
    snew(x_mol, a_tp1-a_tp0);

    bDispCorr = (inputrec->eDispCorr != edispcNO);
    bCharge   = FALSE;
    for (i = a_tp0; i < a_tp1; i++)
    {
        /* Copy the coordinates of the molecule to be insterted */
        copy_rvec(state->x[i], x_mol[i-a_tp0]);
        /* Check if we need to print electrostatic energies */
        bCharge |= (mdatoms->chargeA[i] != 0 ||
                    (mdatoms->chargeB && mdatoms->chargeB[i] != 0));
    }
    bRFExcl = (bCharge && EEL_RF(fr->eeltype) && fr->eeltype != eelRF_NEC);

    calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state->x, fr->cg_cm);
    if (bCavity)
    {
        if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog)
        {
            fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n");
            fprintf(stderr, "WARNING: Your TPI molecule is not centered at 0,0,0\n");
        }
    }
    else
    {
        /* Center the molecule to be inserted at zero */
        for (i = 0; i < a_tp1-a_tp0; i++)
        {
            rvec_dec(x_mol[i], fr->cg_cm[cg_tp]);
        }
    }

    if (fplog)
    {
        fprintf(fplog, "\nWill insert %d atoms %s partial charges\n",
                a_tp1-a_tp0, bCharge ? "with" : "without");

        fprintf(fplog, "\nWill insert %d times in each frame of %s\n",
                (int)nsteps, opt2fn("-rerun", nfile, fnm));
    }

    if (!bCavity)
    {
        if (inputrec->nstlist > 1)
        {
            if (drmax == 0 && a_tp1-a_tp0 == 1)
            {
                gmx_fatal(FARGS, "Re-using the neighborlist %d times for insertions of a single atom in a sphere of radius %f does not make sense", inputrec->nstlist, drmax);
            }
            if (fplog)
            {
                fprintf(fplog, "Will use the same neighborlist for %d insertions in a sphere of radius %f\n", inputrec->nstlist, drmax);
            }
        }
    }
    else
    {
        if (fplog)
        {
            fprintf(fplog, "Will insert randomly in a sphere of radius %f around the center of the cavity\n", drmax);
        }
    }

    ngid   = groups->grps[egcENER].nr;
    gid_tp = GET_CGINFO_GID(fr->cginfo[cg_tp]);
    nener  = 1 + ngid;
    if (bDispCorr)
    {
        nener += 1;
    }
    if (bCharge)
    {
        nener += ngid;
        if (bRFExcl)
        {
            nener += 1;
        }
        if (EEL_FULL(fr->eeltype))
        {
            nener += 1;
        }
    }
    snew(sum_UgembU, nener);

    /* Copy the random seed set by the user */
    seed = inputrec->ld_seed;
    /* We use the frame step number as one random counter.
     * The second counter use the insertion (step) count. But we
     * need multiple random numbers per insertion. This number is
     * not fixed, since we generate random locations in a sphere
     * by putting locations in a cube and some of these fail.
     * A count of 20 is already extremely unlikely, so 10000 is
     * a safe margin for random numbers per insertion.
     */
    rnd_count_stride = 10000;

    if (MASTER(cr))
    {
        fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm),
                          "TPI energies", "Time (ps)",
                          "(kJ mol\\S-1\\N) / (nm\\S3\\N)", oenv);
        xvgr_subtitle(fp_tpi, "f. are averages over one frame", oenv);
        snew(leg, 4+nener);
        e = 0;
        sprintf(str, "-kT log(<Ve\\S-\\betaU\\N>/<V>)");
        leg[e++] = strdup(str);
        sprintf(str, "f. -kT log<e\\S-\\betaU\\N>");
        leg[e++] = strdup(str);
        sprintf(str, "f. <e\\S-\\betaU\\N>");
        leg[e++] = strdup(str);
        sprintf(str, "f. V");
        leg[e++] = strdup(str);
        sprintf(str, "f. <Ue\\S-\\betaU\\N>");
        leg[e++] = strdup(str);
        for (i = 0; i < ngid; i++)
        {
            sprintf(str, "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>",
                    *(groups->grpname[groups->grps[egcENER].nm_ind[i]]));
            leg[e++] = strdup(str);
        }
        if (bDispCorr)
        {
            sprintf(str, "f. <U\\sdisp c\\Ne\\S-\\betaU\\N>");
            leg[e++] = strdup(str);
        }
        if (bCharge)
        {
            for (i = 0; i < ngid; i++)
            {
                sprintf(str, "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>",
                        *(groups->grpname[groups->grps[egcENER].nm_ind[i]]));
                leg[e++] = strdup(str);
            }
            if (bRFExcl)
            {
                sprintf(str, "f. <U\\sRF excl\\Ne\\S-\\betaU\\N>");
                leg[e++] = strdup(str);
            }
            if (EEL_FULL(fr->eeltype))
            {
                sprintf(str, "f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>");
                leg[e++] = strdup(str);
            }
        }
        xvgr_legend(fp_tpi, 4+nener, (const char**)leg, oenv);
        for (i = 0; i < 4+nener; i++)
        {
            sfree(leg[i]);
        }
        sfree(leg);
    }
    clear_rvec(x_init);
    V_all     = 0;
    VembU_all = 0;

    invbinw = 10;
    nbin    = 10;
    snew(bin, nbin);

    /* Avoid frame step numbers <= -1 */
    frame_step_prev = -1;

    bNotLastFrame = read_first_frame(oenv, &status, opt2fn("-rerun", nfile, fnm),
                                     &rerun_fr, TRX_NEED_X);
    frame = 0;

    if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) !=
        mdatoms->nr - (a_tp1 - a_tp0))
    {
        gmx_fatal(FARGS, "Number of atoms in trajectory (%d)%s "
                  "is not equal the number in the run input file (%d) "
                  "minus the number of atoms to insert (%d)\n",
                  rerun_fr.natoms, bCavity ? " minus one" : "",
                  mdatoms->nr, a_tp1-a_tp0);
    }

    refvolshift = log(det(rerun_fr.box));

    switch (inputrec->eI)
    {
        case eiTPI:
            stepblocksize = inputrec->nstlist;
            break;
        case eiTPIC:
            stepblocksize = 1;
            break;
        default:
            gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]);
    }

#ifdef GMX_SIMD
    /* Make sure we don't detect SIMD overflow generated before this point */
    gmx_simd_check_and_reset_overflow();
#endif

    while (bNotLastFrame)
    {
        frame_step      = rerun_fr.step;
        if (frame_step <= frame_step_prev)
        {
            /* We don't have step number in the trajectory file,
             * or we have constant or decreasing step numbers.
             * Ensure we have increasing step numbers, since we use
             * the step numbers as a counter for random numbers.
             */
            frame_step  = frame_step_prev + 1;
        }
        frame_step_prev = frame_step;

        lambda = rerun_fr.lambda;
        t      = rerun_fr.time;

        sum_embU = 0;
        for (e = 0; e < nener; e++)
        {
            sum_UgembU[e] = 0;
        }

        /* Copy the coordinates from the input trajectory */
        for (i = 0; i < rerun_fr.natoms; i++)
        {
            copy_rvec(rerun_fr.x[i], state->x[i]);
        }
        copy_mat(rerun_fr.box, state->box);

        V    = det(state->box);
        logV = log(V);

        bStateChanged = TRUE;
        bNS           = TRUE;

        step = cr->nodeid*stepblocksize;
        while (step < nsteps)
        {
            /* Initialize the second counter for random numbers using
             * the insertion step index. This ensures that we get
             * the same random numbers independently of how many
             * MPI ranks we use. Also for the same seed, we get
             * the same initial random sequence for different nsteps.
             */
            rnd_count = step*rnd_count_stride;

            if (!bCavity)
            {
                /* Random insertion in the whole volume */
                bNS = (step % inputrec->nstlist == 0);
                if (bNS)
                {
                    /* Generate a random position in the box */
                    gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd);
                    gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2);
                    for (d = 0; d < DIM; d++)
                    {
                        x_init[d] = rnd[d]*state->box[d][d];
                    }
                }
                if (inputrec->nstlist == 1)
                {
                    copy_rvec(x_init, x_tp);
                }
                else
                {
                    /* Generate coordinates within |dx|=drmax of x_init */
                    do
                    {
                        gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd);
                        gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2);
                        for (d = 0; d < DIM; d++)
                        {
                            dx[d] = (2*rnd[d] - 1)*drmax;
                        }
                    }
                    while (norm2(dx) > drmax*drmax);
                    rvec_add(x_init, dx, x_tp);
                }
            }
            else
            {
                /* Random insertion around a cavity location
                 * given by the last coordinate of the trajectory.
                 */
                if (step == 0)
                {
                    if (nat_cavity == 1)
                    {
                        /* Copy the location of the cavity */
                        copy_rvec(rerun_fr.x[rerun_fr.natoms-1], x_init);
                    }
                    else
                    {
                        /* Determine the center of mass of the last molecule */
                        clear_rvec(x_init);
                        mass_tot = 0;
                        for (i = 0; i < nat_cavity; i++)
                        {
                            for (d = 0; d < DIM; d++)
                            {
                                x_init[d] +=
                                    mass_cavity[i]*rerun_fr.x[rerun_fr.natoms-nat_cavity+i][d];
                            }
                            mass_tot += mass_cavity[i];
                        }
                        for (d = 0; d < DIM; d++)
                        {
                            x_init[d] /= mass_tot;
                        }
                    }
                }
                /* Generate coordinates within |dx|=drmax of x_init */
                do
                {
                    gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd);
                    gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2);
                    for (d = 0; d < DIM; d++)
                    {
                        dx[d] = (2*rnd[d] - 1)*drmax;
                    }
                }
                while (norm2(dx) > drmax*drmax);
                rvec_add(x_init, dx, x_tp);
            }

            if (a_tp1 - a_tp0 == 1)
            {
                /* Insert a single atom, just copy the insertion location */
                copy_rvec(x_tp, state->x[a_tp0]);
            }
            else
            {
                /* Copy the coordinates from the top file */
                for (i = a_tp0; i < a_tp1; i++)
                {
                    copy_rvec(x_mol[i-a_tp0], state->x[i]);
                }
                /* Rotate the molecule randomly */
                gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd);
                gmx_rng_cycle_2uniform(frame_step, rnd_count++, seed, RND_SEED_TPI, rnd+2);
                rotate_conf(a_tp1-a_tp0, state->x+a_tp0, NULL,
                            2*M_PI*rnd[0],
                            2*M_PI*rnd[1],
                            2*M_PI*rnd[2]);
                /* Shift to the insertion location */
                for (i = a_tp0; i < a_tp1; i++)
                {
                    rvec_inc(state->x[i], x_tp);
                }
            }

            /* Clear some matrix variables  */
            clear_mat(force_vir);
            clear_mat(shake_vir);
            clear_mat(vir);
            clear_mat(pres);

            /* Set the charge group center of mass of the test particle */
            copy_rvec(x_init, fr->cg_cm[top->cgs.nr-1]);

            /* Calc energy (no forces) on new positions.
             * Since we only need the intermolecular energy
             * and the RF exclusion terms of the inserted molecule occur
             * within a single charge group we can pass NULL for the graph.
             * This also avoids shifts that would move charge groups
             * out of the box.
             *
             * Some checks above ensure than we can not have
             * twin-range interactions together with nstlist > 1,
             * therefore we do not need to remember the LR energies.
             */
            /* Make do_force do a single node force calculation */
            cr->nnodes = 1;
            do_force(fplog, cr, inputrec,
                     step, nrnb, wcycle, top, &top_global->groups,
                     state->box, state->x, &state->hist,
                     f, force_vir, mdatoms, enerd, fcd,
                     state->lambda,
                     NULL, fr, NULL, mu_tot, t, NULL, NULL, FALSE,
                     GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY |
                     (bNS ? GMX_FORCE_DYNAMICBOX | GMX_FORCE_NS | GMX_FORCE_DO_LR : 0) |
                     (bStateChanged ? GMX_FORCE_STATECHANGED : 0));
            cr->nnodes    = nnodes;
            bStateChanged = FALSE;
            bNS           = FALSE;

            /* Calculate long range corrections to pressure and energy */
            calc_dispcorr(fplog, inputrec, fr, step, top_global->natoms, state->box,
                          lambda, pres, vir, &prescorr, &enercorr, &dvdlcorr);
            /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */
            enerd->term[F_DISPCORR]  = enercorr;
            enerd->term[F_EPOT]     += enercorr;
            enerd->term[F_PRES]     += prescorr;
            enerd->term[F_DVDL_VDW] += dvdlcorr;

            epot               = enerd->term[F_EPOT];
            bEnergyOutOfBounds = FALSE;
#ifdef GMX_SIMD_X86_SSE2_OR_HIGHER
            /* With SSE the energy can overflow, check for this */
            if (gmx_mm_check_and_reset_overflow())
            {
                if (debug)
                {
                    fprintf(debug, "Found an SSE overflow, assuming the energy is out of bounds\n");
                }
                bEnergyOutOfBounds = TRUE;
            }
#endif
            /* If the compiler doesn't optimize this check away
             * we catch the NAN energies.
             * The epot>GMX_REAL_MAX check catches inf values,
             * which should nicely result in embU=0 through the exp below,
             * but it does not hurt to check anyhow.
             */
            /* Non-bonded Interaction usually diverge at r=0.
             * With tabulated interaction functions the first few entries
             * should be capped in a consistent fashion between
             * repulsion, dispersion and Coulomb to avoid accidental
             * negative values in the total energy.
             * The table generation code in tables.c does this.
             * With user tbales the user should take care of this.
             */
            if (epot != epot || epot > GMX_REAL_MAX)
            {
                bEnergyOutOfBounds = TRUE;
            }
            if (bEnergyOutOfBounds)
            {
                if (debug)
                {
                    fprintf(debug, "\n  time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n", t, (int)step, epot);
                }
                embU = 0;
            }
            else
            {
                embU      = exp(-beta*epot);
                sum_embU += embU;
                /* Determine the weighted energy contributions of each energy group */
                e                = 0;
                sum_UgembU[e++] += epot*embU;
                if (fr->bBHAM)
                {
                    for (i = 0; i < ngid; i++)
                    {
                        sum_UgembU[e++] +=
                            (enerd->grpp.ener[egBHAMSR][GID(i, gid_tp, ngid)] +
                             enerd->grpp.ener[egBHAMLR][GID(i, gid_tp, ngid)])*embU;
                    }
                }
                else
                {
                    for (i = 0; i < ngid; i++)
                    {
                        sum_UgembU[e++] +=
                            (enerd->grpp.ener[egLJSR][GID(i, gid_tp, ngid)] +
                             enerd->grpp.ener[egLJLR][GID(i, gid_tp, ngid)])*embU;
                    }
                }
                if (bDispCorr)
                {
                    sum_UgembU[e++] += enerd->term[F_DISPCORR]*embU;
                }
                if (bCharge)
                {
                    for (i = 0; i < ngid; i++)
                    {
                        sum_UgembU[e++] +=
                            (enerd->grpp.ener[egCOULSR][GID(i, gid_tp, ngid)] +
                             enerd->grpp.ener[egCOULLR][GID(i, gid_tp, ngid)])*embU;
                    }
                    if (bRFExcl)
                    {
                        sum_UgembU[e++] += enerd->term[F_RF_EXCL]*embU;
                    }
                    if (EEL_FULL(fr->eeltype))
                    {
                        sum_UgembU[e++] += enerd->term[F_COUL_RECIP]*embU;
                    }
                }
            }

            if (embU == 0 || beta*epot > bU_bin_limit)
            {
                bin[0]++;
            }
            else
            {
                i = (int)((bU_logV_bin_limit
                           - (beta*epot - logV + refvolshift))*invbinw
                          + 0.5);
                if (i < 0)
                {
                    i = 0;
                }
                if (i >= nbin)
                {
                    realloc_bins(&bin, &nbin, i+10);
                }
                bin[i]++;
            }

            if (debug)
            {
                fprintf(debug, "TPI %7d %12.5e %12.5f %12.5f %12.5f\n",
                        (int)step, epot, x_tp[XX], x_tp[YY], x_tp[ZZ]);
            }

            if (dump_pdb && epot <= dump_ener)
            {
                sprintf(str, "t%g_step%d.pdb", t, (int)step);
                sprintf(str2, "t: %f step %d ener: %f", t, (int)step, epot);
                write_sto_conf_mtop(str, str2, top_global, state->x, state->v,
                                    inputrec->ePBC, state->box);
            }

            step++;
            if ((step/stepblocksize) % cr->nnodes != cr->nodeid)
            {
                /* Skip all steps assigned to the other MPI ranks */
                step += (cr->nnodes - 1)*stepblocksize;
            }
        }

        if (PAR(cr))
        {
            /* When running in parallel sum the energies over the processes */
            gmx_sumd(1,    &sum_embU, cr);
            gmx_sumd(nener, sum_UgembU, cr);
        }

        frame++;
        V_all     += V;
        VembU_all += V*sum_embU/nsteps;

        if (fp_tpi)
        {
            if (bVerbose || frame%10 == 0 || frame < 10)
            {
                fprintf(stderr, "mu %10.3e <mu> %10.3e\n",
                        -log(sum_embU/nsteps)/beta, -log(VembU_all/V_all)/beta);
            }

            fprintf(fp_tpi, "%10.3f %12.5e %12.5e %12.5e %12.5e",
                    t,
                    VembU_all == 0 ? 20/beta : -log(VembU_all/V_all)/beta,
                    sum_embU == 0  ? 20/beta : -log(sum_embU/nsteps)/beta,
                    sum_embU/nsteps, V);
            for (e = 0; e < nener; e++)
            {
                fprintf(fp_tpi, " %12.5e", sum_UgembU[e]/nsteps);
            }
            fprintf(fp_tpi, "\n");
            fflush(fp_tpi);
        }

        bNotLastFrame = read_next_frame(oenv, status, &rerun_fr);
    } /* End of the loop  */
    walltime_accounting_end(walltime_accounting);

    close_trj(status);

    if (fp_tpi != NULL)
    {
        gmx_fio_fclose(fp_tpi);
    }

    if (fplog != NULL)
    {
        fprintf(fplog, "\n");
        fprintf(fplog, "  <V>  = %12.5e nm^3\n", V_all/frame);
        fprintf(fplog, "  <mu> = %12.5e kJ/mol\n", -log(VembU_all/V_all)/beta);
    }

    /* Write the Boltzmann factor histogram */
    if (PAR(cr))
    {
        /* When running in parallel sum the bins over the processes */
        i = nbin;
        global_max(cr, &i);
        realloc_bins(&bin, &nbin, i);
        gmx_sumd(nbin, bin, cr);
    }
    if (MASTER(cr))
    {
        fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm),
                          "TPI energy distribution",
                          "\\betaU - log(V/<V>)", "count", oenv);
        sprintf(str, "number \\betaU > %g: %9.3e", bU_bin_limit, bin[0]);
        xvgr_subtitle(fp_tpi, str, oenv);
        xvgr_legend(fp_tpi, 2, (const char **)tpid_leg, oenv);
        for (i = nbin-1; i > 0; i--)
        {
            bUlogV = -i/invbinw + bU_logV_bin_limit - refvolshift + log(V_all/frame);
            fprintf(fp_tpi, "%6.2f %10d %12.5e\n",
                    bUlogV,
                    (int)(bin[i]+0.5),
                    bin[i]*exp(-bUlogV)*V_all/VembU_all);
        }
        gmx_fio_fclose(fp_tpi);
    }
    sfree(bin);

    sfree(sum_UgembU);

    walltime_accounting_set_nsteps_done(walltime_accounting, frame*inputrec->nsteps);

    return 0;
}
Пример #30
0
void virial(FILE *fp,gmx_bool bFull,int nmol,rvec x[],matrix box,real rcut,
	    gmx_bool bYaw,real q[],gmx_bool bLJ)
{
  int  i,j,im,jm,natmol,ik,jk,m,ninter;
  rvec dx,f,ftot,dvir,vir,pres,xcmi,xcmj,*force;
  real dx6,dx2,dx1,fscal,c6,c12,vcoul,v12,v6,vctot,v12tot,v6tot;
  t_pbc pbc;
  
  set_pbc(&pbc,box);
  fprintf(fp,"%3s   -  %3s: %6s %6s %6s  %6s %8s %8s %8s\n",
	  "ai","aj","dx","dy","dz","|d|","virx","viry","virz");
  clear_rvec(ftot);
  clear_rvec(vir);
  ninter = 0;
  vctot  = 0;
  v12tot = 0;
  v6tot  = 0;
  natmol = bYaw ? 5 : 3;
  snew(force,nmol*natmol);
  
  for(i=0; (i<nmol); i++) {
    im = natmol*i;
    /* Center of geometry */
    clear_rvec(xcmi);
    for(ik=0; (ik<natmol); ik++)
      rvec_inc(xcmi,x[im+ik]);
    for(m=0; (m<DIM); m++)
      xcmi[m] /= natmol;

    for(j=i+1; (j<nmol); j++) {
      jm = natmol*j;
      /* Center of geometry */
      clear_rvec(xcmj);
      for(jk=0; (jk<natmol); jk++)
	rvec_inc(xcmj,x[jm+jk]);
      for(m=0; (m<DIM); m++)
	xcmj[m] /= natmol;

      /* First check COM-COM distance */
      pbc_dx(&pbc,xcmi,xcmj,dx);
      if (norm(dx) < rcut) {
	ninter++;
	/* Neirest neighbour molecules! */
	clear_rvec(dvir);
	for(ik=0; (ik<natmol); ik++) {
	  for(jk=0; (jk<natmol); jk++) {
	    pbc_dx(&pbc,x[im+ik],x[jm+jk],dx);
	    dx2    = iprod(dx,dx);
	    dx1    = sqrt(dx2);
	    vcoul  = q[ik]*q[jk]*ONE_4PI_EPS0/dx1;
	    vctot += vcoul;
	    
	    if (bLJ) {
	      if (bYaw) {
		c6  = yaw_lj[ik][2*jk];
		c12 = yaw_lj[ik][2*jk+1];
	      }
	      else {
		c6  = spc_lj[ik][2*jk];
		c12 = spc_lj[ik][2*jk+1];
	      }
	      dx6    = dx2*dx2*dx2;
	      v6     = c6/dx6;
	      v12    = c12/(dx6*dx6);
	      v6tot -= v6;
	      v12tot+= v12;
	      fscal  = (vcoul+12*v12-6*v6)/dx2;
	    }
	    else
	      fscal  = vcoul/dx2;
	    for(m=0; (m<DIM); m++) {
	      f[m]     = dx[m]*fscal;
	      dvir[m] -= 0.5*dx[m]*f[m];
	    }
	    rvec_inc(force[ik+im],f);
	    rvec_dec(force[jk+jm],f);
	    /*if (bFull)
	      fprintf(fp,"%3s%4d-%3s%4d: %6.3f %6.3f %6.3f %6.3f"
		      " %8.3f %8.3f %8.3f\n",
		      watname[ik],im+ik,watname[jk],jm+jk,
		      dx[XX],dx[YY],dx[ZZ],norm(dx),
		      dvir[XX],dvir[YY],dvir[ZZ]);*/
	  }
	}
	if (bFull)
	  fprintf(fp,"%3s%4d-%3s%4d: "
		  " %8.3f %8.3f %8.3f\n",
		  "SOL",i,"SOL",j,dvir[XX],dvir[YY],dvir[ZZ]);
	rvec_inc(vir,dvir);
      }
    }
  }
  fprintf(fp,"There were %d interactions between the %d molecules (%.2f %%)\n",
	  ninter,nmol,(real)ninter/(0.5*nmol*(nmol-1)));
  fprintf(fp,"Vcoul: %10.4e  V12: %10.4e  V6: %10.4e  Vtot: %10.4e (kJ/mol)\n",
	  vctot/nmol,v12tot/nmol,v6tot/nmol,(vctot+v12tot+v6tot)/nmol);
  pr_rvec(fp,0,"vir ",vir,DIM,TRUE);
  
  for(m=0; (m<DIM); m++) 
    pres[m] = -2*PRESFAC/(det(box))*vir[m];
  pr_rvec(fp,0,"pres",pres,DIM,TRUE);
  pr_rvecs(fp,0,"force",force,natmol*nmol);
  sfree(force);
}