Пример #1
0
void calc_mu(int start,int homenr,rvec x[],real q[],real qB[],
	     int nChargePerturbed,
	     dvec mu,dvec mu_B)
{
  int i,end,m;
  
  end   = start + homenr;  
  
  clear_dvec(mu);
  for(i=start; (i<end); i++)
    for(m=0; (m<DIM); m++)
      mu[m] += q[i]*x[i][m];
  
  for(m=0; (m<DIM); m++)
    mu[m] *= ENM2DEBYE;
  
  if (nChargePerturbed) {
    clear_dvec(mu_B);
    for(i=start; (i<end); i++)
      for(m=0; (m<DIM); m++)
	mu_B[m] += qB[i]*x[i][m];
    
    for(m=0; (m<DIM); m++)
      mu_B[m] *= ENM2DEBYE;
  } else {
    copy_dvec(mu,mu_B);
  }
}
Пример #2
0
static void calc_x_av_stddev(int n, rvec *x, rvec av, rvec stddev)
{
    dvec s1, s2;
    int  i, d;

    clear_dvec(s1);
    clear_dvec(s2);

    for (i = 0; i < n; i++)
    {
        for (d = 0; d < DIM; d++)
        {
            s1[d] += x[i][d];
            s2[d] += x[i][d]*x[i][d];
        }
    }

    dsvmul(1.0/n, s1, s1);
    dsvmul(1.0/n, s2, s2);

    for (d = 0; d < DIM; d++)
    {
        av[d]     = s1[d];
        stddev[d] = std::sqrt(s2[d] - s1[d]*s1[d]);
    }
}
Пример #3
0
static void init_pullgrp(t_pullgrp *pg,char *wbuf,
			 bool bRef,int eGeom,char *s_vec)
{
  double d;
  int    n,m;
  dvec   vec;

  pg->nweight = 0;
  while (sscanf(wbuf,"%lf %n",&d,&n) == 1) {
    if (pg->nweight % 100 == 0) {
      srenew(pg->weight,pg->nweight+100);
    }
    pg->weight[pg->nweight++] = d;
    wbuf += n;
  }
  if (!bRef) {
    if (eGeom == epullgDIST) {
      clear_dvec(vec);
    } else {
      string2dvec(s_vec,vec);
      if (eGeom == epullgDIR || eGeom == epullgCYL || 
	  (eGeom == epullgPOS && dnorm(vec) != 0))
	/* Normalize the direction vector */
	dsvmul(1/dnorm(vec),vec,vec);
    }
    for(m=0; m<DIM; m++)
      pg->vec[m] = vec[m];
  }
}
Пример #4
0
/* Determine the (weighted) sum vector from positions x */
extern double get_sum_of_positions(rvec x[], real weight[], const int nat, dvec dsumvec)
{
    int i;
    rvec x_weighted;
    double weight_sum = 0.0;


    /* Zero out the center */
    clear_dvec(dsumvec);

    /* Loop over all atoms and add their weighted position vectors */
    if (weight != NULL)
    {
        for (i=0; i<nat; i++)
        {
            weight_sum += weight[i];
            svmul(weight[i], x[i], x_weighted);
            dsumvec[XX] += x_weighted[XX];
            dsumvec[YY] += x_weighted[YY];
            dsumvec[ZZ] += x_weighted[ZZ];
        }
    }
    else
    {
        for (i=0; i<nat; i++)
        {
            dsumvec[XX] += x[i][XX];
            dsumvec[YY] += x[i][YY];
            dsumvec[ZZ] += x[i][ZZ];
        }
    }
    return weight_sum;
}
Пример #5
0
/* calculate the center of mass for a group 
   gnx = the number of atoms/molecules
   index = the indices
   xcur = the current coordinates
   xprev = the previous coordinates
   box = the box matrix
   atoms = atom data (for mass)
   com(output) = center of mass  */
static void calc_com(gmx_bool bMol, int gnx, atom_id index[], 
                     rvec xcur[],rvec xprev[],matrix box, t_atoms *atoms,
                     rvec com)
{
    int  i,m,ind;
    real mass;
    double tmass;
    dvec sx;

    clear_dvec(sx);
    tmass = 0;
    mass = 1;

    prep_data(bMol, gnx, index, xcur, xprev, box);
    for(i=0; (i<gnx); i++) 
    {
        if (bMol)
            ind = i;
        else
            ind = index[i];


        mass = atoms->atom[ind].m;
        for(m=0; m<DIM; m++)
            sx[m] += mass*xcur[ind][m];
        tmass += mass;
    }
    for(m=0; m<DIM; m++)
        com[m] = sx[m]/tmass;
}
Пример #6
0
static void init_pull_coord(t_pull_coord *pcrd, int eGeom,
                            const char *origin_buf, const char *vec_buf)
{
    int    m;
    dvec   origin, vec;

    string2dvec(origin_buf, origin);
    if (pcrd->group[0] != 0 && dnorm(origin) > 0)
    {
        gmx_fatal(FARGS, "The pull origin can only be set with an absolute reference");
    }

    if (eGeom == epullgDIST)
    {
        clear_dvec(vec);
    }
    else
    {
        string2dvec(vec_buf, vec);
        if (eGeom == epullgDIR || eGeom == epullgCYL)
        {
            /* Normalize the direction vector */
            dsvmul(1/dnorm(vec), vec, vec);
        }
    }
    for (m = 0; m < DIM; m++)
    {
        pcrd->origin[m] = origin[m];
        pcrd->vec[m]    = vec[m];
    }
}
Пример #7
0
static void average_data(rvec x[], rvec xav[], real *mass,
                         int ngrps, int isize[], int **index)
{
    int    g, i, ind, d;
    real   m;
    rvec   tmp;
    double sum[DIM], mtot;

    for (g = 0; g < ngrps; g++)
    {
        clear_dvec(sum);
        clear_rvec(xav[g]);
        mtot = 0;
        for (i = 0; i < isize[g]; i++)
        {
            ind = index[g][i];
            if (mass != NULL)
            {
                m = mass[ind];
                svmul(m, x[ind], tmp);
                for (d = 0; d < DIM; d++)
                {
                    sum[d] += tmp[d];
                }
                mtot += m;
            }
            else
            {
                for (d = 0; d < DIM; d++)
                {
                    sum[d] += x[ind][d];
                }
            }
        }
        if (mass != NULL)
        {
            for (d = 0; d < DIM; d++)
            {
                xav[g][d] = sum[d]/mtot;
            }
        }
        else
        {
            /* mass=NULL, so these are forces: sum only (do not average) */
            for (d = 0; d < DIM; d++)
            {
                xav[g][d] = sum[d];
            }
        }
    }
}
Пример #8
0
void clear_pull_forces(t_pull *pull)
{
    int i;

    /* Zeroing the forces is only required for constraint pulling.
     * It can happen that multiple constraint steps need to be applied
     * and therefore the constraint forces need to be accumulated.
     */
    for (i = 0; i < pull->ncoord; i++)
    {
        clear_dvec(pull->coord[i].f);
        pull->coord[i].f_scal = 0;
    }
}
Пример #9
0
void calc_gyro_z(rvec x[],matrix box,
		 int gnx,atom_id index[],t_atom atom[],
		 int nz,real time,FILE *out)
{
  static dvec *inertia=NULL;
  static double *tm=NULL;
  int    i,ii,j,zi;
  real   zf,w,sdet,e1,e2;

  if (inertia == NULL) {
    snew(inertia,nz);
    snew(tm,nz);
  }

  for(i=0; i<nz; i++) {
    clear_dvec(inertia[i]);
    tm[i] = 0;
  }

  for(i=0; (i<gnx); i++) {
    ii = index[i];
    zf = nz*x[ii][ZZ]/box[ZZ][ZZ];
    if (zf >= nz)
      zf -= nz;
    if (zf < 0)
      zf += nz;
    for(j=0; j<2; j++) {
      zi = zf + j;
      if (zi == nz)
	zi = 0;
      w = atom[ii].m*(1 + cos(M_PI*(zf - zi)));
      inertia[zi][0] += w*sqr(x[ii][YY]);
      inertia[zi][1] += w*sqr(x[ii][XX]);
      inertia[zi][2] -= w*x[ii][XX]*x[ii][YY];
      tm[zi] += w;
    }
  }
  fprintf(out,"%10g",time);
  for(j=0; j<nz; j++) {
    for(i=0; i<3; i++)
      inertia[j][i] /= tm[j];
    sdet = sqrt(sqr(inertia[j][0] - inertia[j][1]) + 4*sqr(inertia[j][2]));
    e1 = sqrt(0.5*(inertia[j][0] + inertia[j][1] + sdet));
    e2 = sqrt(0.5*(inertia[j][0] + inertia[j][1] - sdet));
    fprintf(out," %5.3f %5.3f",e1,e2);
  }
  fprintf(out,"\n");
}
Пример #10
0
static real ektrans(rvec v[], real mass[], int isize, int index[])
{
    dvec   mvcom;
    double mtot;
    int    i, j, d;

    clear_dvec(mvcom);
    mtot = 0;
    for (i = 0; i < isize; i++)
    {
        j = index[i];
        for (d = 0; d < DIM; d++)
        {
            mvcom[d] += mass[j]*v[j][d];
        }
        mtot += mass[j];
    }

    return dnorm2(mvcom)/(mtot*2);
}
Пример #11
0
static real ekrot(rvec x[], rvec v[], real mass[], int isize, int index[])
{
    static real **TCM = NULL, **L;
    double        tm, m0, lxx, lxy, lxz, lyy, lyz, lzz, ekrot;
    rvec          a0, ocm;
    dvec          dx, b0;
    dvec          xcm, vcm, acm;
    int           i, j, m, n;

    if (TCM == NULL)
    {
        snew(TCM, DIM);
        for (i = 0; i < DIM; i++)
        {
            snew(TCM[i], DIM);
        }
        snew(L, DIM);
        for (i = 0; i < DIM; i++)
        {
            snew(L[i], DIM);
        }
    }

    clear_dvec(xcm);
    clear_dvec(vcm);
    clear_dvec(acm);
    tm = 0.0;
    for (i = 0; i < isize; i++)
    {
        j   = index[i];
        m0  = mass[j];
        tm += m0;
        cprod(x[j], v[j], a0);
        for (m = 0; (m < DIM); m++)
        {
            xcm[m] += m0*x[j][m]; /* c.o.m. position */
            vcm[m] += m0*v[j][m]; /* c.o.m. velocity */
            acm[m] += m0*a0[m];   /* rotational velocity around c.o.m. */
        }
    }
    dcprod(xcm, vcm, b0);
    for (m = 0; (m < DIM); m++)
    {
        xcm[m] /= tm;
        vcm[m] /= tm;
        acm[m] -= b0[m]/tm;
    }

    lxx = lxy = lxz = lyy = lyz = lzz = 0.0;
    for (i = 0; i < isize; i++)
    {
        j  = index[i];
        m0 = mass[j];
        for (m = 0; m < DIM; m++)
        {
            dx[m] = x[j][m] - xcm[m];
        }
        lxx += dx[XX]*dx[XX]*m0;
        lxy += dx[XX]*dx[YY]*m0;
        lxz += dx[XX]*dx[ZZ]*m0;
        lyy += dx[YY]*dx[YY]*m0;
        lyz += dx[YY]*dx[ZZ]*m0;
        lzz += dx[ZZ]*dx[ZZ]*m0;
    }

    L[XX][XX] =  lyy + lzz;
    L[YY][XX] = -lxy;
    L[ZZ][XX] = -lxz;
    L[XX][YY] = -lxy;
    L[YY][YY] =  lxx + lzz;
    L[ZZ][YY] = -lyz;
    L[XX][ZZ] = -lxz;
    L[YY][ZZ] = -lyz;
    L[ZZ][ZZ] =  lxx + lyy;

    m_inv_gen(L, DIM, TCM);

    /* Compute omega (hoeksnelheid) */
    clear_rvec(ocm);
    ekrot = 0;
    for (m = 0; m < DIM; m++)
    {
        for (n = 0; n < DIM; n++)
        {
            ocm[m] += TCM[m][n]*acm[n];
        }
        ekrot += 0.5*ocm[m]*acm[m];
    }

    return ekrot;
}
Пример #12
0
static void init_pull_coord(t_pull_coord *pcrd, int coord_index_for_output,
                            char *dim_buf,
                            const char *origin_buf, const char *vec_buf,
                            warninp_t wi)
{
    int    m;
    dvec   origin, vec;
    char   buf[STRLEN];

    if (pcrd->eType == epullCONSTRAINT && (pcrd->eGeom == epullgCYL ||
                                           pcrd->eGeom == epullgDIRRELATIVE ||
                                           pcrd->eGeom == epullgANGLE ||
                                           pcrd->eGeom == epullgANGLEAXIS ||
                                           pcrd->eGeom == epullgDIHEDRAL))
    {
        gmx_fatal(FARGS, "Pulling of type %s can not be combined with geometry %s. Consider using pull type %s.",
                  epull_names[pcrd->eType],
                  epullg_names[pcrd->eGeom],
                  epull_names[epullUMBRELLA]);
    }

    if (pcrd->eType == epullEXTERNAL)
    {
        if (pcrd->externalPotentialProvider[0] == '\0')
        {
            sprintf(buf, "The use of pull type '%s' for pull coordinate %d requires that the name of the module providing the potential external is set with the option %s%d%s",
                    epull_names[pcrd->eType], coord_index_for_output,
                    "pull-coord", coord_index_for_output, "-potential-provider");
            warning_error(wi, buf);
        }

        if (pcrd->rate != 0)
        {
            sprintf(buf, "The use of pull type '%s' for pull coordinate %d requires that the pull rate is zero",
                    epull_names[pcrd->eType], coord_index_for_output);
            warning_error(wi, buf);
        }

        if (pcrd->eGeom == epullgCYL)
        {
            /* Warn the user of a PBC restriction, caused by the fact that
             * there is no reference value with an external pull potential.
             */
            sprintf(buf, "With pull type '%s' and geometry '%s', the distance component along the cylinder axis between atoms in the cylinder group and the COM of the pull group should be smaller than half the box length",
                    epull_names[pcrd->eType], epullg_names[pcrd->eGeom]);
            warning_note(wi, buf);
        }
    }

    process_pull_dim(dim_buf, pcrd->dim, pcrd);

    string2dvec(origin_buf, origin);
    if (pcrd->group[0] != 0 && dnorm(origin) > 0)
    {
        gmx_fatal(FARGS, "The pull origin can only be set with an absolute reference");
    }

    /* Check the given initial reference value and warn for dangerous values */
    if (pcrd->eGeom == epullgDIST)
    {
        if (pcrd->bStart && pcrd->init < 0)
        {
            sprintf(buf, "The initial reference distance set by pull-coord-init is set to a negative value (%g) with geometry %s while distances need to be non-negative. "
                    "This may work, since you have set pull-coord-start to 'yes' which modifies this value, but only for certain starting distances. "
                    "If this is a mistake you may want to use geometry %s instead.",
                    pcrd->init, EPULLGEOM(pcrd->eGeom), EPULLGEOM(epullgDIR));
            warning(wi, buf);
        }
    }
    else if (pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgANGLEAXIS)
    {
        if (pcrd->bStart && (pcrd->init < 0 || pcrd->init > 180))
        {
            /* This value of pcrd->init may be ok depending on pcrd->bStart which modifies pcrd->init later on */
            sprintf(buf, "The initial reference angle set by pull-coord-init (%g) is outside of the allowed range [0, 180] degrees for geometry (%s). "
                    "This may work, since you have set pull-coord-start to 'yes' which modifies this value, but only for certain starting angles.",
                    pcrd->init, EPULLGEOM(pcrd->eGeom));
            warning(wi, buf);
        }
    }
    else if (pcrd->eGeom == epullgDIHEDRAL)
    {
        if (pcrd->bStart && (pcrd->init < -180 || pcrd->init > 180))
        {
            sprintf(buf, "The initial reference angle set by pull-coord-init (%g) is outside of the allowed range [-180, 180] degrees for geometry (%s). "
                    "This may work, since you have set pull-coord-start to 'yes' which modifies this value, but only for certain starting angles.",
                    pcrd->init, EPULLGEOM(pcrd->eGeom));
            warning(wi, buf);
        }
    }

    /* Check and set the pull vector */
    clear_dvec(vec);
    string2dvec(vec_buf, vec);

    if (pcrd->eGeom == epullgDIR || pcrd->eGeom == epullgCYL || pcrd->eGeom == epullgDIRPBC || pcrd->eGeom == epullgANGLEAXIS)
    {
        if (dnorm2(vec) == 0)
        {
            gmx_fatal(FARGS, "With pull geometry %s the pull vector can not be 0,0,0",
                      epullg_names[pcrd->eGeom]);
        }
        for (int d = 0; d < DIM; d++)
        {
            if (vec[d] != 0 && pcrd->dim[d] == 0)
            {
                gmx_fatal(FARGS, "pull-coord-vec has non-zero %c-component while pull_dim for the %c-dimension is set to N", 'x'+d, 'x'+d);
            }
        }

        /* Normalize the direction vector */
        dsvmul(1/dnorm(vec), vec, vec);
    }
    else /* This case is for are all the geometries where the pull vector is not used */
    {
        if (dnorm2(vec) > 0)
        {
            sprintf(buf, "A pull vector is given (%g  %g  %g) but will not be used with geometry %s. If you really want to use this "
                    "vector, consider using geometry %s instead.",
                    vec[0], vec[1], vec[2], EPULLGEOM(pcrd->eGeom),
                    pcrd->eGeom == epullgANGLE ? EPULLGEOM(epullgANGLEAXIS) : EPULLGEOM(epullgDIR));
            warning(wi, buf);
        }
    }
    for (m = 0; m < DIM; m++)
    {
        pcrd->origin[m] = origin[m];
        pcrd->vec[m]    = vec[m];
    }
}
Пример #13
0
/* calculates center of mass of selection index from all coordinates x */
void pull_calc_coms(t_commrec *cr,
                    t_pull *pull, t_mdatoms *md, t_pbc *pbc, double t,
                    rvec x[], rvec *xp)
{
    int           g, i, ii, m;
    real          mass, w, wm, twopi_box = 0;
    double        wmass, wwmass, invwmass;
    dvec          com, comp;
    double        cm, sm, cmp, smp, ccm, csm, ssm, csw, snw;
    rvec         *xx[2], x_pbc = {0, 0, 0}, dx;
    t_pull_group *pgrp;

    if (pull->rbuf == NULL)
    {
        snew(pull->rbuf, pull->ngroup);
    }
    if (pull->dbuf == NULL)
    {
        snew(pull->dbuf, 3*pull->ngroup);
    }

    if (pull->bRefAt)
    {
        pull_set_pbcatoms(cr, pull, md, x, pull->rbuf);
    }

    if (pull->cosdim >= 0)
    {
        for (m = pull->cosdim+1; m < pull->npbcdim; m++)
        {
            if (pbc->box[m][pull->cosdim] != 0)
            {
                gmx_fatal(FARGS, "Can not do cosine weighting for trilinic dimensions");
            }
        }
        twopi_box = 2.0*M_PI/pbc->box[pull->cosdim][pull->cosdim];
    }

    for (g = 0; g < pull->ngroup; g++)
    {
        pgrp = &pull->group[g];
        clear_dvec(com);
        clear_dvec(comp);
        wmass  = 0;
        wwmass = 0;
        cm     = 0;
        sm     = 0;
        cmp    = 0;
        smp    = 0;
        ccm    = 0;
        csm    = 0;
        ssm    = 0;
        if (!(g == 0 && PULL_CYL(pull)))
        {
            if (pgrp->epgrppbc == epgrppbcREFAT)
            {
                /* Set the pbc atom */
                copy_rvec(pull->rbuf[g], x_pbc);
            }
            w = 1;
            for (i = 0; i < pgrp->nat_loc; i++)
            {
                ii   = pgrp->ind_loc[i];
                mass = md->massT[ii];
                if (pgrp->epgrppbc != epgrppbcCOS)
                {
                    if (pgrp->weight_loc)
                    {
                        w = pgrp->weight_loc[i];
                    }
                    wm      = w*mass;
                    wmass  += wm;
                    wwmass += wm*w;
                    if (pgrp->epgrppbc == epgrppbcNONE)
                    {
                        /* Plain COM: sum the coordinates */
                        for (m = 0; m < DIM; m++)
                        {
                            com[m]    += wm*x[ii][m];
                        }
                        if (xp)
                        {
                            for (m = 0; m < DIM; m++)
                            {
                                comp[m] += wm*xp[ii][m];
                            }
                        }
                    }
                    else
                    {
                        /* Sum the difference with the reference atom */
                        pbc_dx(pbc, x[ii], x_pbc, dx);
                        for (m = 0; m < DIM; m++)
                        {
                            com[m]    += wm*dx[m];
                        }
                        if (xp)
                        {
                            /* For xp add the difference between xp and x to dx,
                             * such that we use the same periodic image,
                             * also when xp has a large displacement.
                             */
                            for (m = 0; m < DIM; m++)
                            {
                                comp[m] += wm*(dx[m] + xp[ii][m] - x[ii][m]);
                            }
                        }
                    }
                }
                else
                {
                    /* Determine cos and sin sums */
                    csw  = cos(x[ii][pull->cosdim]*twopi_box);
                    snw  = sin(x[ii][pull->cosdim]*twopi_box);
                    cm  += csw*mass;
                    sm  += snw*mass;
                    ccm += csw*csw*mass;
                    csm += csw*snw*mass;
                    ssm += snw*snw*mass;

                    if (xp)
                    {
                        csw  = cos(xp[ii][pull->cosdim]*twopi_box);
                        snw  = sin(xp[ii][pull->cosdim]*twopi_box);
                        cmp += csw*mass;
                        smp += snw*mass;
                    }
                }
            }
        }

        /* Copy local sums to a buffer for global summing */
        switch (pgrp->epgrppbc)
        {
            case epgrppbcNONE:
            case epgrppbcREFAT:
                copy_dvec(com, pull->dbuf[g*3]);
                copy_dvec(comp, pull->dbuf[g*3+1]);
                pull->dbuf[g*3+2][0] = wmass;
                pull->dbuf[g*3+2][1] = wwmass;
                pull->dbuf[g*3+2][2] = 0;
                break;
            case epgrppbcCOS:
                pull->dbuf[g*3  ][0] = cm;
                pull->dbuf[g*3  ][1] = sm;
                pull->dbuf[g*3  ][2] = 0;
                pull->dbuf[g*3+1][0] = ccm;
                pull->dbuf[g*3+1][1] = csm;
                pull->dbuf[g*3+1][2] = ssm;
                pull->dbuf[g*3+2][0] = cmp;
                pull->dbuf[g*3+2][1] = smp;
                pull->dbuf[g*3+2][2] = 0;
                break;
        }
    }

    if (cr && PAR(cr))
    {
        /* Sum the contributions over the nodes */
        gmx_sumd(pull->ngroup*3*DIM, pull->dbuf[0], cr);
    }

    for (g = 0; g < pull->ngroup; g++)
    {
        pgrp = &pull->group[g];
        if (pgrp->nat > 0 && !(g == 0 && PULL_CYL(pull)))
        {
            if (pgrp->epgrppbc != epgrppbcCOS)
            {
                /* Determine the inverse mass */
                wmass    = pull->dbuf[g*3+2][0];
                wwmass   = pull->dbuf[g*3+2][1];
                invwmass = 1/wmass;
                /* invtm==0 signals a frozen group, so then we should keep it zero */
                if (pgrp->invtm > 0)
                {
                    pgrp->wscale = wmass/wwmass;
                    pgrp->invtm  = 1.0/(pgrp->wscale*wmass);
                }
                /* Divide by the total mass */
                for (m = 0; m < DIM; m++)
                {
                    pgrp->x[m]    = pull->dbuf[g*3  ][m]*invwmass;
                    if (xp)
                    {
                        pgrp->xp[m] = pull->dbuf[g*3+1][m]*invwmass;
                    }
                    if (pgrp->epgrppbc == epgrppbcREFAT)
                    {
                        pgrp->x[m]    += pull->rbuf[g][m];
                        if (xp)
                        {
                            pgrp->xp[m] += pull->rbuf[g][m];
                        }
                    }
                }
            }
            else
            {
                /* Determine the optimal location of the cosine weight */
                csw                   = pull->dbuf[g*3][0];
                snw                   = pull->dbuf[g*3][1];
                pgrp->x[pull->cosdim] = atan2_0_2pi(snw, csw)/twopi_box;
                /* Set the weights for the local atoms */
                wmass  = sqrt(csw*csw + snw*snw);
                wwmass = (pull->dbuf[g*3+1][0]*csw*csw +
                          pull->dbuf[g*3+1][1]*csw*snw +
                          pull->dbuf[g*3+1][2]*snw*snw)/(wmass*wmass);
                pgrp->wscale = wmass/wwmass;
                pgrp->invtm  = 1.0/(pgrp->wscale*wmass);
                /* Set the weights for the local atoms */
                csw *= pgrp->invtm;
                snw *= pgrp->invtm;
                for (i = 0; i < pgrp->nat_loc; i++)
                {
                    ii                  = pgrp->ind_loc[i];
                    pgrp->weight_loc[i] = csw*cos(twopi_box*x[ii][pull->cosdim]) +
                        snw*sin(twopi_box*x[ii][pull->cosdim]);
                }
                if (xp)
                {
                    csw                    = pull->dbuf[g*3+2][0];
                    snw                    = pull->dbuf[g*3+2][1];
                    pgrp->xp[pull->cosdim] = atan2_0_2pi(snw, csw)/twopi_box;
                }
            }
            if (debug)
            {
                fprintf(debug, "Pull group %d wmass %f wwmass %f invtm %f\n",
                        g, wmass, wwmass, pgrp->invtm);
            }
        }
    }

    if (PULL_CYL(pull))
    {
        /* Calculate the COMs for the cyclinder reference groups */
        make_cyl_refgrps(cr, pull, md, pbc, t, x, xp);
    }
}
Пример #14
0
real do_walls(t_inputrec *ir,t_forcerec *fr,matrix box,t_mdatoms *md,
	      rvec x[],rvec f[],real lambda,real Vlj[],t_nrnb *nrnb)
{
    int  nwall,w,lam,i;
    int  ntw[2],at,ntype,ngid,ggid,*egp_flags,*type;
    real *nbfp,lamfac,fac_d[2],fac_r[2],Cd,Cr,Vtot,Fwall[2];
    real wall_z[2],r,mr,r1,r2,r4,Vd,Vr,V=0,Fd,Fr,F=0,dvdlambda;
    dvec xf_z;
    int  n0,nnn;
    real tabscale,*VFtab,rt,eps,eps2,Yt,Ft,Geps,Heps,Heps2,Fp,VV,FF;
    unsigned short *gid=md->cENER;
    t_forcetable *tab;

    nwall     = ir->nwall;
    ngid      = ir->opts.ngener;
    ntype     = fr->ntype;
    nbfp      = fr->nbfp;
    egp_flags = fr->egp_flags;

    for(w=0; w<nwall; w++)
    {
        ntw[w] = 2*ntype*ir->wall_atomtype[w];
        switch (ir->wall_type)
        {
        case ewt93:
            fac_d[w] = ir->wall_density[w]*M_PI/6;
            fac_r[w] = ir->wall_density[w]*M_PI/45;
            break;
        case ewt104:
            fac_d[w] = ir->wall_density[w]*M_PI/2;
            fac_r[w] = ir->wall_density[w]*M_PI/5;
            break;
        default:
            break;
        }
        Fwall[w] = 0;
    }
    wall_z[0] = 0;
    wall_z[1] = box[ZZ][ZZ];

    Vtot = 0;
    dvdlambda = 0;
    clear_dvec(xf_z);
    for(lam=0; lam<(md->nPerturbed ? 2 : 1); lam++)
    {
        if (md->nPerturbed)
        {
            if (lam == 0)
            {
                lamfac = 1 - lambda;
                type = md->typeA;
            }
            else
            {
                lamfac = 0;
                type = md->typeB;
            }
        }
        else
        {
            lamfac = 1;
            type = md->typeA;
        }
        for(i=md->start; i<md->start+md->homenr; i++)
        {
            for(w=0; w<nwall; w++)
            {
                /* The wall energy groups are always at the end of the list */
                ggid = gid[i]*ngid + ngid - nwall + w;
                at = type[i];
                Cd = nbfp[ntw[w]+2*at];
                Cr = nbfp[ntw[w]+2*at+1];
                if (!((Cd==0 && Cr==0) || (egp_flags[ggid] & EGP_EXCL)))
                {
                    if (w == 0)
                    {
                        r = x[i][ZZ];
                    }
                    else
                    {
                        r = wall_z[1] - x[i][ZZ];
                    }
                    if (r < ir->wall_r_linpot)
                    {
                        mr = ir->wall_r_linpot - r;
                        r  = ir->wall_r_linpot;
                    }
                    else
                    {
                        mr = 0;
                    }
                    switch (ir->wall_type)
                    {
                    case ewtTABLE:
                        if (r < 0)
                        {
                            wall_error(i,x,r);
                        }
                        tab = &(fr->wall_tab[w][gid[i]]);
                        tabscale = tab->scale;
                        VFtab    = tab->tab;
                        
                        rt    = r*tabscale;
                        n0    = rt;
                        if (n0 >= tab->n)
                        {
                            /* Beyond the table range, set V and F to zero */
                            V     = 0;
                            F     = 0;
                        }
                        else
                        {
                            eps   = rt - n0;
                            eps2  = eps*eps;
                            /* Dispersion */
                            nnn   = 8*n0;
                            Yt    = VFtab[nnn];
                            Ft    = VFtab[nnn+1];
                            Geps  = VFtab[nnn+2]*eps;
                            Heps2 = VFtab[nnn+3]*eps2;
                            Fp    = Ft + Geps + Heps2;
                            VV    = Yt + Fp*eps;
                            FF    = Fp + Geps + 2.0*Heps2;
                            Vd    = Cd*VV;
                            Fd    = Cd*FF;
                            /* Repulsion */
                            nnn   = nnn + 4;
                            Yt    = VFtab[nnn];
                            Ft    = VFtab[nnn+1];
                            Geps  = VFtab[nnn+2]*eps;
                            Heps2 = VFtab[nnn+3]*eps2;
                            Fp    = Ft + Geps + Heps2;
                            VV    = Yt + Fp*eps;
                            FF    = Fp + Geps + 2.0*Heps2;
                            Vr    = Cr*VV;
                            Fr    = Cr*FF;
                            V     = Vd + Vr;
                            F     = -lamfac*(Fd + Fr)*tabscale;
                        }
                        break;
                    case ewt93:
                        if (r <= 0)
                        {
                            wall_error(i,x,r);
                        }
                        r1 = 1/r;
                        r2 = r1*r1;
                        r4 = r2*r2;
                        Vd = fac_d[w]*Cd*r2*r1;
                        Vr = fac_r[w]*Cr*r4*r4*r1;
                        V  = Vr - Vd;
                        F  = lamfac*(9*Vr - 3*Vd)*r1;
                        break;
                    case ewt104:
                        if (r <= 0)
                        {
                            wall_error(i,x,r);
                        }
                        r1 = 1/r;
                        r2 = r1*r1;
                        r4 = r2*r2;
                        Vd = fac_d[w]*Cd*r4;
                        Vr = fac_r[w]*Cr*r4*r4*r2;
                        V  = Vr - Vd;
                        F  = lamfac*(10*Vr - 4*Vd)*r1;
                        break;
                    case ewt126:
                        if (r <= 0)
                        {
                            wall_error(i,x,r);
                        }
                        r1 = 1/r;
                        r2 = r1*r1;
                        r4 = r2*r2;
                        Vd = Cd*r4*r2;
                        Vr = Cr*r4*r4*r4;
                        V  = Vr - Vd;
                        F  = lamfac*(12*Vr - 6*Vd)*r1;
                        break;
                    default:
                        break;
                    }
                    if (mr > 0)
                    {
                        V += mr*F;
                    }
                    if (w == 1)
                    {
                        F = -F;
                    }
                    Vlj[ggid] += lamfac*V;
                    Vtot      += V;
                    f[i][ZZ]  += F;
                    /* Because of the single sum virial calculation we need
                     * to add  the full virial contribution of the walls.
                     * Since the force only has a z-component, there is only
                     * a contribution to the z component of the virial tensor.
                     * We could also determine the virial contribution directly,
                     * which would be cheaper here, but that would require extra
                     * communication for f_novirsum for with virtual sites
                     * in parallel.
                     */
                    xf_z[XX]  -= x[i][XX]*F;
                    xf_z[YY]  -= x[i][YY]*F;
                    xf_z[ZZ]  -= wall_z[w]*F;
                }
            }
        }
        if (md->nPerturbed)
        {
            dvdlambda += (lam==0 ? -1 : 1)*Vtot;
        }
        
        inc_nrnb(nrnb,eNR_WALLS,md->homenr);
    }

    for(i=0; i<DIM; i++)
    {
        fr->vir_wall_z[i] = -0.5*xf_z[i];
    }
    
    return dvdlambda;
}
Пример #15
0
static void read_posres(gmx_mtop_t *mtop,t_molinfo *molinfo,bool bTopB,
			char *fn,
			int rc_scaling, int ePBC, 
			rvec com)
{
  bool   bFirst = TRUE;
  rvec   *x,*v,*xp;
  dvec   sum;
  double totmass;
  t_atoms dumat;
  matrix box,invbox;
  int    natoms,npbcdim=0;
  char   title[STRLEN];
  int    a,i,ai,j,k,mb,nat_molb;
  gmx_molblock_t *molb;
  t_params *pr;
  t_atom *atom;

  get_stx_coordnum(fn,&natoms);
  if (natoms != mtop->natoms) {
    sprintf(warn_buf,"The number of atoms in %s (%d) does not match the number of atoms in the topology (%d). Will assume that the first %d atoms in the topology and %s match.",fn,natoms,mtop->natoms,min(mtop->natoms,natoms),fn);
    warning(NULL);
  }
  snew(x,natoms);
  snew(v,natoms);
  init_t_atoms(&dumat,natoms,FALSE);
  read_stx_conf(fn,title,&dumat,x,v,NULL,box);
  
  npbcdim = ePBC2npbcdim(ePBC);
  clear_rvec(com);
  if (rc_scaling != erscNO) {
    copy_mat(box,invbox);
    for(j=npbcdim; j<DIM; j++) {
      clear_rvec(invbox[j]);
      invbox[j][j] = 1;
    }
    m_inv_ur0(invbox,invbox);
  }

  /* Copy the reference coordinates to mtop */
  clear_dvec(sum);
  totmass = 0;
  a = 0;
  for(mb=0; mb<mtop->nmolblock; mb++) {
    molb = &mtop->molblock[mb];
    nat_molb = molb->nmol*mtop->moltype[molb->type].atoms.nr;
    pr = &(molinfo[molb->type].plist[F_POSRES]);
    if (pr->nr > 0) {
      atom = mtop->moltype[molb->type].atoms.atom;
      for(i=0; (i<pr->nr); i++) {
	ai=pr->param[i].AI;
	if (ai >= natoms) {
	  gmx_fatal(FARGS,"Position restraint atom index (%d) in moltype '%s' is larger than number of atoms in %s (%d).\n",
		    ai+1,*molinfo[molb->type].name,fn,natoms);
	}
	if (rc_scaling == erscCOM) {
	  /* Determine the center of mass of the posres reference coordinates */
	  for(j=0; j<npbcdim; j++) {
	    sum[j] += atom[ai].m*x[a+ai][j];
	  }
	  totmass  += atom[ai].m;
	}
      }
      if (!bTopB) {
	molb->nposres_xA = nat_molb;
	snew(molb->posres_xA,molb->nposres_xA);
	for(i=0; i<nat_molb; i++) {
	  copy_rvec(x[a+i],molb->posres_xA[i]);
	}
      } else {
	molb->nposres_xB = nat_molb;
	snew(molb->posres_xB,molb->nposres_xB);
	for(i=0; i<nat_molb; i++) {
	  copy_rvec(x[a+i],molb->posres_xB[i]);
	}
      }
    }
    a += nat_molb;
  }
  if (rc_scaling == erscCOM) {
    if (totmass == 0)
      gmx_fatal(FARGS,"The total mass of the position restraint atoms is 0");
    for(j=0; j<npbcdim; j++)
      com[j] = sum[j]/totmass;
    fprintf(stderr,"The center of mass of the position restraint coord's is %6.3f %6.3f %6.3f\n",com[XX],com[YY],com[ZZ]);
  }

  if (rc_scaling != erscNO) {
    for(mb=0; mb<mtop->nmolblock; mb++) {
      molb = &mtop->molblock[mb];
      nat_molb = molb->nmol*mtop->moltype[molb->type].atoms.nr;
      if (molb->nposres_xA > 0 || molb->nposres_xB > 0) {
	xp = (!bTopB ? molb->posres_xA : molb->posres_xB);
	for(i=0; i<nat_molb; i++) {
	  for(j=0; j<npbcdim; j++) {
	    if (rc_scaling == erscALL) {
	      /* Convert from Cartesian to crystal coordinates */
	      xp[i][j] *= invbox[j][j];
	      for(k=j+1; k<npbcdim; k++) {
		xp[i][j] += invbox[k][j]*xp[i][k];
	      }
	    } else if (rc_scaling == erscCOM) {
	      /* Subtract the center of mass */
	      xp[i][j] -= com[j];
	    }
	  }
	}
      }
    }

    if (rc_scaling == erscCOM) {
      /* Convert the COM from Cartesian to crystal coordinates */
      for(j=0; j<npbcdim; j++) {
	com[j] *= invbox[j][j];
	for(k=j+1; k<npbcdim; k++) {
	  com[j] += invbox[k][j]*com[k];
	}
      }
    }
  }
  
  free_t_atoms(&dumat,TRUE);
  sfree(x);
  sfree(v);
}
Пример #16
0
static void calc_gyro_z(rvec x[], matrix box,
                        int gnx, int index[], t_atom atom[],
                        int nz, real time, FILE *out)
{
    static dvec   *inertia = nullptr;
    static double *tm      = nullptr;
    int            i, ii, j, zi;
    real           zf, w, sdet, e1, e2;

    if (inertia == nullptr)
    {
        snew(inertia, nz);
        snew(tm, nz);
    }

    for (i = 0; i < nz; i++)
    {
        clear_dvec(inertia[i]);
        tm[i] = 0;
    }

    for (i = 0; (i < gnx); i++)
    {
        ii = index[i];
        zf = nz*x[ii][ZZ]/box[ZZ][ZZ];
        if (zf >= nz)
        {
            zf -= nz;
        }
        if (zf < 0)
        {
            zf += nz;
        }
        for (j = 0; j < 2; j++)
        {
            zi = static_cast<int>(zf + j);
            if (zi == nz)
            {
                zi = 0;
            }
            w               = atom[ii].m*(1 + std::cos(M_PI*(zf - zi)));
            inertia[zi][0] += w*gmx::square(x[ii][YY]);
            inertia[zi][1] += w*gmx::square(x[ii][XX]);
            inertia[zi][2] -= w*x[ii][XX]*x[ii][YY];
            tm[zi]         += w;
        }
    }
    fprintf(out, "%10g", time);
    for (j = 0; j < nz; j++)
    {
        for (i = 0; i < 3; i++)
        {
            inertia[j][i] /= tm[j];
        }
        sdet = std::sqrt(gmx::square(inertia[j][0] - inertia[j][1]) + 4*gmx::square(inertia[j][2]));
        e1   = std::sqrt(0.5*(inertia[j][0] + inertia[j][1] + sdet));
        e2   = std::sqrt(0.5*(inertia[j][0] + inertia[j][1] - sdet));
        fprintf(out, " %5.3f %5.3f", e1, e2);
    }
    fprintf(out, "\n");
}
Пример #17
0
static void init_pull_coord(t_pull_coord *pcrd,
                            char *dim_buf,
                            const char *origin_buf, const char *vec_buf,
                            warninp_t wi)
{
    int    m;
    dvec   origin, vec;
    char   buf[STRLEN];

    if (pcrd->eType == epullCONSTRAINT && (pcrd->eGeom == epullgCYL ||
                                           pcrd->eGeom == epullgDIRRELATIVE))
    {
        gmx_fatal(FARGS, "Pulling of type %s can not be combined with geometry %s. Consider using pull type %s.",
                  epull_names[pcrd->eType],
                  epullg_names[pcrd->eGeom],
                  epull_names[epullUMBRELLA]);
    }

    process_pull_dim(dim_buf, pcrd->dim);

    string2dvec(origin_buf, origin);
    if (pcrd->group[0] != 0 && dnorm(origin) > 0)
    {
        gmx_fatal(FARGS, "The pull origin can only be set with an absolute reference");
    }

    /* Check and set the pull vector */
    clear_dvec(vec);
    if (pcrd->eGeom == epullgDIST)
    {
        if (pcrd->init < 0)
        {
            sprintf(buf, "The initial pull distance is negative with geometry %s, while a distance can not be negative. Use geometry %s instead.",
                    EPULLGEOM(pcrd->eGeom), EPULLGEOM(epullgDIR));
            warning_error(wi, buf);
        }
        /* TODO: With a positive init but a negative rate things could still
         * go wrong, but it might be fine if you don't pull too far.
         * We should give a warning or note when there is only one pull dim
         * active, since that is usually the problematic case when you should
         * be using direction. We will do this later, since an already planned
         * generalization of the pull code makes pull dim available here.
         */
    }
    else if (pcrd->eGeom != epullgDIRRELATIVE)
    {
        string2dvec(vec_buf, vec);
        if (dnorm2(vec) == 0)
        {
            gmx_fatal(FARGS, "With pull geometry %s the pull vector can not be 0,0,0",
                      epullg_names[pcrd->eGeom]);
        }
        if (pcrd->eGeom == epullgDIR || pcrd->eGeom == epullgCYL)
        {
            /* Normalize the direction vector */
            dsvmul(1/dnorm(vec), vec, vec);
        }
    }
    for (m = 0; m < DIM; m++)
    {
        pcrd->origin[m] = origin[m];
        pcrd->vec[m]    = vec[m];
    }
}
Пример #18
0
static void calc_cgcm_av_stddev(t_block *cgs, int n, rvec *x, rvec av, rvec stddev,
                                t_commrec *cr_sum)
{
    int   *cgindex;
    dvec   s1, s2;
    double buf[7];
    int    cg, d, k0, k1, k, nrcg;
    real   inv_ncg;
    rvec   cg_cm;

    clear_dvec(s1);
    clear_dvec(s2);

    cgindex = cgs->index;
    for (cg = 0; cg < n; cg++)
    {
        k0      = cgindex[cg];
        k1      = cgindex[cg+1];
        nrcg    = k1 - k0;
        if (nrcg == 1)
        {
            copy_rvec(x[k0], cg_cm);
        }
        else
        {
            inv_ncg = 1.0/nrcg;

            clear_rvec(cg_cm);
            for (k = k0; (k < k1); k++)
            {
                rvec_inc(cg_cm, x[k]);
            }
            for (d = 0; (d < DIM); d++)
            {
                cg_cm[d] *= inv_ncg;
            }
        }
        for (d = 0; d < DIM; d++)
        {
            s1[d] += cg_cm[d];
            s2[d] += cg_cm[d]*cg_cm[d];
        }
    }

    if (cr_sum != NULL)
    {
        for (d = 0; d < DIM; d++)
        {
            buf[d]     = s1[d];
            buf[DIM+d] = s2[d];
        }
        buf[6] = n;
        gmx_sumd(7, buf, cr_sum);
        for (d = 0; d < DIM; d++)
        {
            s1[d] = buf[d];
            s2[d] = buf[DIM+d];
        }
        n = (int)(buf[6] + 0.5);
    }

    dsvmul(1.0/n, s1, s1);
    dsvmul(1.0/n, s2, s2);

    for (d = 0; d < DIM; d++)
    {
        av[d]     = s1[d];
        stddev[d] = sqrt(s2[d] - s1[d]*s1[d]);
    }
}
Пример #19
0
static void make_cyl_refgrps(t_commrec *cr, struct pull_t *pull, t_mdatoms *md,
                             t_pbc *pbc, double t, rvec *x)
{
    /* The size and stride per coord for the reduction buffer */
    const int       stride = 9;
    int             c, i, ii, m, start, end;
    rvec            g_x, dx, dir;
    double          inv_cyl_r2;
    pull_comm_t    *comm;
    gmx_ga2la_t    *ga2la = NULL;

    comm = &pull->comm;

    if (comm->dbuf_cyl == NULL)
    {
        snew(comm->dbuf_cyl, pull->ncoord*stride);
    }

    if (cr && DOMAINDECOMP(cr))
    {
        ga2la = cr->dd->ga2la;
    }

    start = 0;
    end   = md->homenr;

    inv_cyl_r2 = 1.0/gmx::square(pull->params.cylinder_r);

    /* loop over all groups to make a reference group for each*/
    for (c = 0; c < pull->ncoord; c++)
    {
        pull_coord_work_t *pcrd;
        double             sum_a, wmass, wwmass;
        dvec               radf_fac0, radf_fac1;

        pcrd   = &pull->coord[c];

        sum_a  = 0;
        wmass  = 0;
        wwmass = 0;
        clear_dvec(radf_fac0);
        clear_dvec(radf_fac1);

        if (pcrd->params.eGeom == epullgCYL)
        {
            pull_group_work_t *pref, *pgrp, *pdyna;

            /* pref will be the same group for all pull coordinates */
            pref  = &pull->group[pcrd->params.group[0]];
            pgrp  = &pull->group[pcrd->params.group[1]];
            pdyna = &pull->dyna[c];
            copy_rvec(pcrd->vec, dir);
            pdyna->nat_loc = 0;

            /* We calculate distances with respect to the reference location
             * of this cylinder group (g_x), which we already have now since
             * we reduced the other group COM over the ranks. This resolves
             * any PBC issues and we don't need to use a PBC-atom here.
             */
            if (pcrd->params.rate != 0)
            {
                /* With rate=0, value_ref is set initially */
                pcrd->value_ref = pcrd->params.init + pcrd->params.rate*t;
            }
            for (m = 0; m < DIM; m++)
            {
                g_x[m] = pgrp->x[m] - pcrd->vec[m]*pcrd->value_ref;
            }

            /* loop over all atoms in the main ref group */
            for (i = 0; i < pref->params.nat; i++)
            {
                ii = pref->params.ind[i];
                if (ga2la)
                {
                    if (!ga2la_get_home(ga2la, pref->params.ind[i], &ii))
                    {
                        ii = -1;
                    }
                }
                if (ii >= start && ii < end)
                {
                    double dr2, dr2_rel, inp;
                    dvec   dr;

                    pbc_dx_aiuc(pbc, x[ii], g_x, dx);
                    inp = iprod(dir, dx);
                    dr2 = 0;
                    for (m = 0; m < DIM; m++)
                    {
                        /* Determine the radial components */
                        dr[m] = dx[m] - inp*dir[m];
                        dr2  += dr[m]*dr[m];
                    }
                    dr2_rel = dr2*inv_cyl_r2;

                    if (dr2_rel < 1)
                    {
                        double mass, weight, dweight_r;
                        dvec   mdw;

                        /* add to index, to sum of COM, to weight array */
                        if (pdyna->nat_loc >= pdyna->nalloc_loc)
                        {
                            pdyna->nalloc_loc = over_alloc_large(pdyna->nat_loc+1);
                            srenew(pdyna->ind_loc,    pdyna->nalloc_loc);
                            srenew(pdyna->weight_loc, pdyna->nalloc_loc);
                            srenew(pdyna->mdw,        pdyna->nalloc_loc);
                            srenew(pdyna->dv,         pdyna->nalloc_loc);
                        }
                        pdyna->ind_loc[pdyna->nat_loc] = ii;

                        mass      = md->massT[ii];
                        /* The radial weight function is 1-2x^2+x^4,
                         * where x=r/cylinder_r. Since this function depends
                         * on the radial component, we also get radial forces
                         * on both groups.
                         */
                        weight    = 1 + (-2 + dr2_rel)*dr2_rel;
                        dweight_r = (-4 + 4*dr2_rel)*inv_cyl_r2;
                        pdyna->weight_loc[pdyna->nat_loc] = weight;
                        sum_a    += mass*weight*inp;
                        wmass    += mass*weight;
                        wwmass   += mass*weight*weight;
                        dsvmul(mass*dweight_r, dr, mdw);
                        copy_dvec(mdw, pdyna->mdw[pdyna->nat_loc]);
                        /* Currently we only have the axial component of the
                         * distance (inp) up to an unkown offset. We add this
                         * offset after the reduction needs to determine the
                         * COM of the cylinder group.
                         */
                        pdyna->dv[pdyna->nat_loc] = inp;
                        for (m = 0; m < DIM; m++)
                        {
                            radf_fac0[m] += mdw[m];
                            radf_fac1[m] += mdw[m]*inp;
                        }
                        pdyna->nat_loc++;
                    }
                }
            }
        }
        comm->dbuf_cyl[c*stride+0] = wmass;
        comm->dbuf_cyl[c*stride+1] = wwmass;
        comm->dbuf_cyl[c*stride+2] = sum_a;
        comm->dbuf_cyl[c*stride+3] = radf_fac0[XX];
        comm->dbuf_cyl[c*stride+4] = radf_fac0[YY];
        comm->dbuf_cyl[c*stride+5] = radf_fac0[ZZ];
        comm->dbuf_cyl[c*stride+6] = radf_fac1[XX];
        comm->dbuf_cyl[c*stride+7] = radf_fac1[YY];
        comm->dbuf_cyl[c*stride+8] = radf_fac1[ZZ];
    }

    if (cr != NULL && PAR(cr))
    {
        /* Sum the contributions over the ranks */
        pull_reduce_double(cr, comm, pull->ncoord*stride, comm->dbuf_cyl);
    }

    for (c = 0; c < pull->ncoord; c++)
    {
        pull_coord_work_t *pcrd;

        pcrd  = &pull->coord[c];

        if (pcrd->params.eGeom == epullgCYL)
        {
            pull_group_work_t *pdyna, *pgrp;
            double             wmass, wwmass, dist;

            pdyna = &pull->dyna[c];
            pgrp  = &pull->group[pcrd->params.group[1]];

            wmass          = comm->dbuf_cyl[c*stride+0];
            wwmass         = comm->dbuf_cyl[c*stride+1];
            pdyna->mwscale = 1.0/wmass;
            /* Cylinder pulling can't be used with constraints, but we set
             * wscale and invtm anyhow, in case someone would like to use them.
             */
            pdyna->wscale  = wmass/wwmass;
            pdyna->invtm   = wwmass/(wmass*wmass);

            /* We store the deviation of the COM from the reference location
             * used above, since we need it when we apply the radial forces
             * to the atoms in the cylinder group.
             */
            pcrd->cyl_dev  = 0;
            for (m = 0; m < DIM; m++)
            {
                g_x[m]         = pgrp->x[m] - pcrd->vec[m]*pcrd->value_ref;
                dist           = -pcrd->vec[m]*comm->dbuf_cyl[c*stride+2]*pdyna->mwscale;
                pdyna->x[m]    = g_x[m] - dist;
                pcrd->cyl_dev += dist;
            }
            /* Now we know the exact COM of the cylinder reference group,
             * we can determine the radial force factor (ffrad) that when
             * multiplied with the axial pull force will give the radial
             * force on the pulled (non-cylinder) group.
             */
            for (m = 0; m < DIM; m++)
            {
                pcrd->ffrad[m] = (comm->dbuf_cyl[c*stride+6+m] +
                                  comm->dbuf_cyl[c*stride+3+m]*pcrd->cyl_dev)/wmass;
            }

            if (debug)
            {
                fprintf(debug, "Pull cylinder group %d:%8.3f%8.3f%8.3f m:%8.3f\n",
                        c, pdyna->x[0], pdyna->x[1],
                        pdyna->x[2], 1.0/pdyna->invtm);
                fprintf(debug, "ffrad %8.3f %8.3f %8.3f\n",
                        pcrd->ffrad[XX], pcrd->ffrad[YY], pcrd->ffrad[ZZ]);
            }
        }
    }
}
Пример #20
0
int gmx_polystat(int argc, char *argv[])
{
    const char     *desc[] = {
        "[THISMODULE] plots static properties of polymers as a function of time",
        "and prints the average.[PAR]",
        "By default it determines the average end-to-end distance and radii",
        "of gyration of polymers. It asks for an index group and split this",
        "into molecules. The end-to-end distance is then determined using",
        "the first and the last atom in the index group for each molecules.",
        "For the radius of gyration the total and the three principal components",
        "for the average gyration tensor are written.",
        "With option [TT]-v[tt] the eigenvectors are written.",
        "With option [TT]-pc[tt] also the average eigenvalues of the individual",
        "gyration tensors are written.",
        "With option [TT]-i[tt] the mean square internal distances are",
        "written.[PAR]",
        "With option [TT]-p[tt] the persistence length is determined.",
        "The chosen index group should consist of atoms that are",
        "consecutively bonded in the polymer mainchains.",
        "The persistence length is then determined from the cosine of",
        "the angles between bonds with an index difference that is even,",
        "the odd pairs are not used, because straight polymer backbones",
        "are usually all trans and therefore only every second bond aligns.",
        "The persistence length is defined as number of bonds where",
        "the average cos reaches a value of 1/e. This point is determined",
        "by a linear interpolation of [LOG]<cos>[log]."
    };
    static gmx_bool bMW  = TRUE, bPC = FALSE;
    t_pargs         pa[] = {
        { "-mw", FALSE, etBOOL, {&bMW},
          "Use the mass weighting for radii of gyration" },
        { "-pc", FALSE, etBOOL, {&bPC},
          "Plot average eigenvalues" }
    };

    t_filenm        fnm[] = {
        { efTPR, nullptr, nullptr,  ffREAD  },
        { efTRX, "-f", nullptr,  ffREAD  },
        { efNDX, nullptr, nullptr,  ffOPTRD },
        { efXVG, "-o", "polystat",  ffWRITE },
        { efXVG, "-v", "polyvec", ffOPTWR },
        { efXVG, "-p", "persist",  ffOPTWR },
        { efXVG, "-i", "intdist", ffOPTWR }
    };
#define NFILE asize(fnm)

    t_topology       *top;
    gmx_output_env_t *oenv;
    int               ePBC;
    int               isize, *index, nmol, *molind, mol, nat_min = 0, nat_max = 0;
    char             *grpname;
    t_trxstatus      *status;
    real              t;
    rvec             *x, *bond = nullptr;
    matrix            box;
    int               natoms, i, j, frame, ind0, ind1, a, d, d2, ord[DIM] = {0};
    dvec              cm, sum_eig = {0, 0, 0};
    double          **gyr, **gyr_all, eig[DIM], **eigv;
    double            sum_eed2, sum_eed2_tot, sum_gyro, sum_gyro_tot, sum_pers_tot;
    int              *ninp    = nullptr;
    double           *sum_inp = nullptr, pers;
    double           *intd, ymax, ymin;
    double            mmol, m;
    char              title[STRLEN];
    FILE             *out, *outv, *outp, *outi;
    const char       *leg[8] = {
        "end to end", "<R\\sg\\N>",
        "<R\\sg\\N> eig1", "<R\\sg\\N> eig2", "<R\\sg\\N> eig3",
        "<R\\sg\\N eig1>", "<R\\sg\\N eig2>", "<R\\sg\\N eig3>"
    };
    char            **legp, buf[STRLEN];
    gmx_rmpbc_t       gpbc = nullptr;

    if (!parse_common_args(&argc, argv,
                           PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT,
                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
    {
        return 0;
    }

    snew(top, 1);
    ePBC = read_tpx_top(ftp2fn(efTPR, NFILE, fnm),
                        nullptr, box, &natoms, nullptr, nullptr, top);

    fprintf(stderr, "Select a group of polymer mainchain atoms:\n");
    get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm),
              1, &isize, &index, &grpname);

    snew(molind, top->mols.nr+1);
    nmol = 0;
    mol  = -1;
    for (i = 0; i < isize; i++)
    {
        if (i == 0 || index[i] >= top->mols.index[mol+1])
        {
            molind[nmol++] = i;
            do
            {
                mol++;
            }
            while (index[i] >= top->mols.index[mol+1]);
        }
    }
    molind[nmol] = i;
    nat_min      = top->atoms.nr;
    nat_max      = 0;
    for (mol = 0; mol < nmol; mol++)
    {
        nat_min = std::min(nat_min, molind[mol+1]-molind[mol]);
        nat_max = std::max(nat_max, molind[mol+1]-molind[mol]);
    }
    fprintf(stderr, "Group %s consists of %d molecules\n", grpname, nmol);
    fprintf(stderr, "Group size per molecule, min: %d atoms, max %d atoms\n",
            nat_min, nat_max);

    sprintf(title, "Size of %d polymers", nmol);
    out = xvgropen(opt2fn("-o", NFILE, fnm), title, output_env_get_xvgr_tlabel(oenv), "(nm)",
                   oenv);
    xvgr_legend(out, bPC ? 8 : 5, leg, oenv);

    if (opt2bSet("-v", NFILE, fnm))
    {
        outv = xvgropen(opt2fn("-v", NFILE, fnm), "Principal components",
                        output_env_get_xvgr_tlabel(oenv), "(nm)", oenv);
        snew(legp, DIM*DIM);
        for (d = 0; d < DIM; d++)
        {
            for (d2 = 0; d2 < DIM; d2++)
            {
                sprintf(buf, "eig%d %c", d+1, 'x'+d2);
                legp[d*DIM+d2] = gmx_strdup(buf);
            }
        }
        xvgr_legend(outv, DIM*DIM, (const char**)legp, oenv);
    }
    else
    {
        outv = nullptr;
    }

    if (opt2bSet("-p", NFILE, fnm))
    {
        outp = xvgropen(opt2fn("-p", NFILE, fnm), "Persistence length",
                        output_env_get_xvgr_tlabel(oenv), "bonds", oenv);
        snew(bond, nat_max-1);
        snew(sum_inp, nat_min/2);
        snew(ninp, nat_min/2);
    }
    else
    {
        outp = nullptr;
    }

    if (opt2bSet("-i", NFILE, fnm))
    {
        outi = xvgropen(opt2fn("-i", NFILE, fnm), "Internal distances",
                        "n", "<R\\S2\\N(n)>/n (nm\\S2\\N)", oenv);
        i = index[molind[1]-1] - index[molind[0]]; /* Length of polymer -1 */
        snew(intd, i);
    }
    else
    {
        intd = nullptr;
        outi = nullptr;
    }

    natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);

    snew(gyr, DIM);
    snew(gyr_all, DIM);
    snew(eigv, DIM);
    for (d = 0; d < DIM; d++)
    {
        snew(gyr[d], DIM);
        snew(gyr_all[d], DIM);
        snew(eigv[d], DIM);
    }

    frame        = 0;
    sum_eed2_tot = 0;
    sum_gyro_tot = 0;
    sum_pers_tot = 0;

    gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms);

    do
    {
        gmx_rmpbc(gpbc, natoms, box, x);

        sum_eed2 = 0;
        for (d = 0; d < DIM; d++)
        {
            clear_dvec(gyr_all[d]);
        }

        if (bPC)
        {
            clear_dvec(sum_eig);
        }

        if (outp)
        {
            for (i = 0; i < nat_min/2; i++)
            {
                sum_inp[i] = 0;
                ninp[i]    = 0;
            }
        }

        for (mol = 0; mol < nmol; mol++)
        {
            ind0 = molind[mol];
            ind1 = molind[mol+1];

            /* Determine end to end distance */
            sum_eed2 += distance2(x[index[ind0]], x[index[ind1-1]]);

            /* Determine internal distances */
            if (outi)
            {
                calc_int_dist(intd, x, index[ind0], index[ind1-1]);
            }

            /* Determine the radius of gyration */
            clear_dvec(cm);
            for (d = 0; d < DIM; d++)
            {
                clear_dvec(gyr[d]);
            }
            mmol = 0;

            for (i = ind0; i < ind1; i++)
            {
                a = index[i];
                if (bMW)
                {
                    m = top->atoms.atom[a].m;
                }
                else
                {
                    m = 1;
                }
                mmol += m;
                for (d = 0; d < DIM; d++)
                {
                    cm[d] += m*x[a][d];
                    for (d2 = 0; d2 < DIM; d2++)
                    {
                        gyr[d][d2] += m*x[a][d]*x[a][d2];
                    }
                }
            }
            dsvmul(1/mmol, cm, cm);
            for (d = 0; d < DIM; d++)
            {
                for (d2 = 0; d2 < DIM; d2++)
                {
                    gyr[d][d2]      = gyr[d][d2]/mmol - cm[d]*cm[d2];
                    gyr_all[d][d2] += gyr[d][d2];
                }
            }
            if (bPC)
            {
                gyro_eigen(gyr, eig, eigv, ord);
                for (d = 0; d < DIM; d++)
                {
                    sum_eig[d] += eig[ord[d]];
                }
            }
            if (outp)
            {
                for (i = ind0; i < ind1-1; i++)
                {
                    rvec_sub(x[index[i+1]], x[index[i]], bond[i-ind0]);
                    unitv(bond[i-ind0], bond[i-ind0]);
                }
                for (i = ind0; i < ind1-1; i++)
                {
                    for (j = 0; (i+j < ind1-1 && j < nat_min/2); j += 2)
                    {
                        sum_inp[j] += iprod(bond[i-ind0], bond[i-ind0+j]);
                        ninp[j]++;
                    }
                }
            }
        }
        sum_eed2 /= nmol;

        sum_gyro = 0;
        for (d = 0; d < DIM; d++)
        {
            for (d2 = 0; d2 < DIM; d2++)
            {
                gyr_all[d][d2] /= nmol;
            }
            sum_gyro += gyr_all[d][d];
        }

        gyro_eigen(gyr_all, eig, eigv, ord);

        fprintf(out, "%10.3f %8.4f %8.4f %8.4f %8.4f %8.4f",
                t*output_env_get_time_factor(oenv),
                std::sqrt(sum_eed2), sqrt(sum_gyro),
                std::sqrt(eig[ord[0]]), std::sqrt(eig[ord[1]]), std::sqrt(eig[ord[2]]));
        if (bPC)
        {
            for (d = 0; d < DIM; d++)
            {
                fprintf(out, " %8.4f", std::sqrt(sum_eig[d]/nmol));
            }
        }
        fprintf(out, "\n");

        if (outv)
        {
            fprintf(outv, "%10.3f", t*output_env_get_time_factor(oenv));
            for (d = 0; d < DIM; d++)
            {
                for (d2 = 0; d2 < DIM; d2++)
                {
                    fprintf(outv, " %6.3f", eigv[ord[d]][d2]);
                }
            }
            fprintf(outv, "\n");
        }

        sum_eed2_tot += sum_eed2;
        sum_gyro_tot += sum_gyro;

        if (outp)
        {
            i = -1;
            for (j = 0; j < nat_min/2; j += 2)
            {
                sum_inp[j] /= ninp[j];
                if (i == -1 && sum_inp[j] <= std::exp(-1.0))
                {
                    i = j;
                }
            }
            if (i == -1)
            {
                pers = j;
            }
            else
            {
                /* Do linear interpolation on a log scale */
                pers = i - 2.0
                    + 2.0*(std::log(sum_inp[i-2]) + 1.0)/(std::log(sum_inp[i-2]) - std::log(sum_inp[i]));
            }
            fprintf(outp, "%10.3f %8.4f\n", t*output_env_get_time_factor(oenv), pers);
            sum_pers_tot += pers;
        }

        frame++;
    }
    while (read_next_x(oenv, status, &t, x, box));

    gmx_rmpbc_done(gpbc);

    close_trx(status);

    xvgrclose(out);
    if (outv)
    {
        xvgrclose(outv);
    }
    if (outp)
    {
        xvgrclose(outp);
    }

    sum_eed2_tot /= frame;
    sum_gyro_tot /= frame;
    sum_pers_tot /= frame;
    fprintf(stdout, "\nAverage end to end distance: %.3f (nm)\n",
            std::sqrt(sum_eed2_tot));
    fprintf(stdout, "\nAverage radius of gyration:  %.3f (nm)\n",
            std::sqrt(sum_gyro_tot));
    if (opt2bSet("-p", NFILE, fnm))
    {
        fprintf(stdout, "\nAverage persistence length:  %.2f bonds\n",
                sum_pers_tot);
    }

    /* Handle printing of internal distances. */
    if (outi)
    {
        if (output_env_get_print_xvgr_codes(oenv))
        {
            fprintf(outi, "@    xaxes scale Logarithmic\n");
        }
        ymax = -1;
        ymin = 1e300;
        j    = index[molind[1]-1] - index[molind[0]]; /* Polymer length -1. */
        for (i = 0; i < j; i++)
        {
            intd[i] /= (i + 1) * frame * nmol;
            if (intd[i] > ymax)
            {
                ymax = intd[i];
            }
            if (intd[i] < ymin)
            {
                ymin = intd[i];
            }
        }
        xvgr_world(outi, 1, ymin, j, ymax, oenv);
        for (i = 0; i < j; i++)
        {
            fprintf(outi, "%d  %8.4f\n", i+1, intd[i]);
        }
        xvgrclose(outi);
    }

    do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
    if (opt2bSet("-v", NFILE, fnm))
    {
        do_view(oenv, opt2fn("-v", NFILE, fnm), "-nxy");
    }
    if (opt2bSet("-p", NFILE, fnm))
    {
        do_view(oenv, opt2fn("-p", NFILE, fnm), "-nxy");
    }

    return 0;
}
Пример #21
0
/* calculates center of mass of selection index from all coordinates x */
void pull_calc_coms(t_commrec *cr,
                    struct pull_t *pull, t_mdatoms *md, t_pbc *pbc, double t,
                    rvec x[], rvec *xp)
{
    int          g;
    real         twopi_box = 0;
    pull_comm_t *comm;

    comm = &pull->comm;

    if (comm->rbuf == NULL)
    {
        snew(comm->rbuf, pull->ngroup);
    }
    if (comm->dbuf == NULL)
    {
        snew(comm->dbuf, 3*pull->ngroup);
    }

    if (pull->bRefAt && pull->bSetPBCatoms)
    {
        pull_set_pbcatoms(cr, pull, x, comm->rbuf);

        if (cr != NULL && DOMAINDECOMP(cr))
        {
            /* We can keep these PBC reference coordinates fixed for nstlist
             * steps, since atoms won't jump over PBC.
             * This avoids a global reduction at the next nstlist-1 steps.
             * Note that the exact values of the pbc reference coordinates
             * are irrelevant, as long all atoms in the group are within
             * half a box distance of the reference coordinate.
             */
            pull->bSetPBCatoms = FALSE;
        }
    }

    if (pull->cosdim >= 0)
    {
        int m;

        assert(pull->npbcdim <= DIM);

        for (m = pull->cosdim+1; m < pull->npbcdim; m++)
        {
            if (pbc->box[m][pull->cosdim] != 0)
            {
                gmx_fatal(FARGS, "Can not do cosine weighting for trilinic dimensions");
            }
        }
        twopi_box = 2.0*M_PI/pbc->box[pull->cosdim][pull->cosdim];
    }

    for (g = 0; g < pull->ngroup; g++)
    {
        pull_group_work_t *pgrp;

        pgrp = &pull->group[g];

        if (pgrp->bCalcCOM)
        {
            if (pgrp->epgrppbc != epgrppbcCOS)
            {
                dvec   com, comp;
                double wmass, wwmass;
                rvec   x_pbc = { 0, 0, 0 };
                int    i;

                clear_dvec(com);
                clear_dvec(comp);
                wmass  = 0;
                wwmass = 0;

                if (pgrp->epgrppbc == epgrppbcREFAT)
                {
                    /* Set the pbc atom */
                    copy_rvec(comm->rbuf[g], x_pbc);
                }

                for (i = 0; i < pgrp->nat_loc; i++)
                {
                    int  ii, m;
                    real mass, wm;

                    ii   = pgrp->ind_loc[i];
                    mass = md->massT[ii];
                    if (pgrp->weight_loc == NULL)
                    {
                        wm     = mass;
                        wmass += wm;
                    }
                    else
                    {
                        real w;

                        w       = pgrp->weight_loc[i];
                        wm      = w*mass;
                        wmass  += wm;
                        wwmass += wm*w;
                    }
                    if (pgrp->epgrppbc == epgrppbcNONE)
                    {
                        /* Plain COM: sum the coordinates */
                        for (m = 0; m < DIM; m++)
                        {
                            com[m]    += wm*x[ii][m];
                        }
                        if (xp)
                        {
                            for (m = 0; m < DIM; m++)
                            {
                                comp[m] += wm*xp[ii][m];
                            }
                        }
                    }
                    else
                    {
                        rvec dx;

                        /* Sum the difference with the reference atom */
                        pbc_dx(pbc, x[ii], x_pbc, dx);
                        for (m = 0; m < DIM; m++)
                        {
                            com[m]    += wm*dx[m];
                        }
                        if (xp)
                        {
                            /* For xp add the difference between xp and x to dx,
                             * such that we use the same periodic image,
                             * also when xp has a large displacement.
                             */
                            for (m = 0; m < DIM; m++)
                            {
                                comp[m] += wm*(dx[m] + xp[ii][m] - x[ii][m]);
                            }
                        }
                    }
                }

                /* We do this check after the loop above to avoid more nesting.
                 * If we have a single-atom group the mass is irrelevant, so
                 * we can remove the mass factor to avoid division by zero.
                 * Note that with constraint pulling the mass does matter, but
                 * in that case a check group mass != 0 has been done before.
                 */
                if (pgrp->params.nat == 1 && pgrp->nat_loc == 1 && wmass == 0)
                {
                    int m;

                    /* Copy the single atom coordinate */
                    for (m = 0; m < DIM; m++)
                    {
                        com[m] = x[pgrp->ind_loc[0]][m];
                    }
                    /* Set all mass factors to 1 to get the correct COM */
                    wmass  = 1;
                    wwmass = 1;
                }

                if (pgrp->weight_loc == NULL)
                {
                    wwmass = wmass;
                }

                /* Copy local sums to a buffer for global summing */
                copy_dvec(com,  comm->dbuf[g*3]);
                copy_dvec(comp, comm->dbuf[g*3 + 1]);
                comm->dbuf[g*3 + 2][0] = wmass;
                comm->dbuf[g*3 + 2][1] = wwmass;
                comm->dbuf[g*3 + 2][2] = 0;
            }
            else
            {
                /* Cosine weighting geometry */
                double cm, sm, cmp, smp, ccm, csm, ssm, csw, snw;
                int    i;

                cm  = 0;
                sm  = 0;
                cmp = 0;
                smp = 0;
                ccm = 0;
                csm = 0;
                ssm = 0;

                for (i = 0; i < pgrp->nat_loc; i++)
                {
                    int  ii;
                    real mass;

                    ii   = pgrp->ind_loc[i];
                    mass = md->massT[ii];
                    /* Determine cos and sin sums */
                    csw  = cos(x[ii][pull->cosdim]*twopi_box);
                    snw  = sin(x[ii][pull->cosdim]*twopi_box);
                    cm  += csw*mass;
                    sm  += snw*mass;
                    ccm += csw*csw*mass;
                    csm += csw*snw*mass;
                    ssm += snw*snw*mass;

                    if (xp)
                    {
                        csw  = cos(xp[ii][pull->cosdim]*twopi_box);
                        snw  = sin(xp[ii][pull->cosdim]*twopi_box);
                        cmp += csw*mass;
                        smp += snw*mass;
                    }
                }

                /* Copy local sums to a buffer for global summing */
                comm->dbuf[g*3  ][0] = cm;
                comm->dbuf[g*3  ][1] = sm;
                comm->dbuf[g*3  ][2] = 0;
                comm->dbuf[g*3+1][0] = ccm;
                comm->dbuf[g*3+1][1] = csm;
                comm->dbuf[g*3+1][2] = ssm;
                comm->dbuf[g*3+2][0] = cmp;
                comm->dbuf[g*3+2][1] = smp;
                comm->dbuf[g*3+2][2] = 0;
            }
        }
    }

    pull_reduce_double(cr, comm, pull->ngroup*3*DIM, comm->dbuf[0]);

    for (g = 0; g < pull->ngroup; g++)
    {
        pull_group_work_t *pgrp;

        pgrp = &pull->group[g];
        if (pgrp->params.nat > 0 && pgrp->bCalcCOM)
        {
            if (pgrp->epgrppbc != epgrppbcCOS)
            {
                double wmass, wwmass;
                int    m;

                /* Determine the inverse mass */
                wmass             = comm->dbuf[g*3+2][0];
                wwmass            = comm->dbuf[g*3+2][1];
                pgrp->mwscale     = 1.0/wmass;
                /* invtm==0 signals a frozen group, so then we should keep it zero */
                if (pgrp->invtm != 0)
                {
                    pgrp->wscale  = wmass/wwmass;
                    pgrp->invtm   = wwmass/(wmass*wmass);
                }
                /* Divide by the total mass */
                for (m = 0; m < DIM; m++)
                {
                    pgrp->x[m]      = comm->dbuf[g*3  ][m]*pgrp->mwscale;
                    if (xp)
                    {
                        pgrp->xp[m] = comm->dbuf[g*3+1][m]*pgrp->mwscale;
                    }
                    if (pgrp->epgrppbc == epgrppbcREFAT)
                    {
                        pgrp->x[m]      += comm->rbuf[g][m];
                        if (xp)
                        {
                            pgrp->xp[m] += comm->rbuf[g][m];
                        }
                    }
                }
            }
            else
            {
                /* Cosine weighting geometry */
                double csw, snw, wmass, wwmass;
                int    i, ii;

                /* Determine the optimal location of the cosine weight */
                csw                   = comm->dbuf[g*3][0];
                snw                   = comm->dbuf[g*3][1];
                pgrp->x[pull->cosdim] = atan2_0_2pi(snw, csw)/twopi_box;
                /* Set the weights for the local atoms */
                wmass  = sqrt(csw*csw + snw*snw);
                wwmass = (comm->dbuf[g*3+1][0]*csw*csw +
                          comm->dbuf[g*3+1][1]*csw*snw +
                          comm->dbuf[g*3+1][2]*snw*snw)/(wmass*wmass);

                pgrp->mwscale = 1.0/wmass;
                pgrp->wscale  = wmass/wwmass;
                pgrp->invtm   = wwmass/(wmass*wmass);
                /* Set the weights for the local atoms */
                csw *= pgrp->invtm;
                snw *= pgrp->invtm;
                for (i = 0; i < pgrp->nat_loc; i++)
                {
                    ii                  = pgrp->ind_loc[i];
                    pgrp->weight_loc[i] = csw*cos(twopi_box*x[ii][pull->cosdim]) +
                        snw*sin(twopi_box*x[ii][pull->cosdim]);
                }
                if (xp)
                {
                    csw                    = comm->dbuf[g*3+2][0];
                    snw                    = comm->dbuf[g*3+2][1];
                    pgrp->xp[pull->cosdim] = atan2_0_2pi(snw, csw)/twopi_box;
                }
            }
            if (debug)
            {
                fprintf(debug, "Pull group %d wmass %f invtm %f\n",
                        g, 1.0/pgrp->mwscale, pgrp->invtm);
            }
        }
    }

    if (pull->bCylinder)
    {
        /* Calculate the COMs for the cyclinder reference groups */
        make_cyl_refgrps(cr, pull, md, pbc, t, x);
    }
}