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); } }
static void low_get_pull_coord_dr(const t_pull *pull, const t_pull_coord *pcrd, const t_pbc *pbc, double t, dvec xg, dvec xref, double max_dist2, dvec dr) { const t_pull_group *pgrp0, *pgrp1; int m; dvec xrefr, dref = {0, 0, 0}; double dr2; pgrp0 = &pull->group[pcrd->group[0]]; pgrp1 = &pull->group[pcrd->group[1]]; /* Only the first group can be an absolute reference, in that case nat=0 */ if (pgrp0->nat == 0) { for (m = 0; m < DIM; m++) { xref[m] = pcrd->origin[m]; } } copy_dvec(xref, xrefr); if (pull->eGeom == epullgDIRPBC) { for (m = 0; m < DIM; m++) { dref[m] = (pcrd->init + pcrd->rate*t)*pcrd->vec[m]; } /* Add the reference position, so we use the correct periodic image */ dvec_inc(xrefr, dref); } pbc_dx_d(pbc, xg, xrefr, dr); dr2 = 0; for (m = 0; m < DIM; m++) { dr[m] *= pull->dim[m]; dr2 += dr[m]*dr[m]; } if (max_dist2 >= 0 && dr2 > 0.98*0.98*max_dist2) { gmx_fatal(FARGS, "Distance between pull groups %d and %d (%f nm) is larger than 0.49 times the box size (%f)", pcrd->group[0], pcrd->group[1], sqrt(dr2), sqrt(max_dist2)); } if (pull->eGeom == epullgDIRPBC) { dvec_inc(dr, dref); } }
void calc_mu(int start, int homenr, rvec x[], real q[], real qB[], int nChargePerturbed, dvec mu, dvec mu_B) { int i, end, m; double mu_x, mu_y, mu_z; end = start + homenr; mu_x = mu_y = mu_z = 0.0; #pragma omp parallel for reduction(+: mu_x, mu_y, mu_z) schedule(static) \ num_threads(gmx_omp_nthreads_get(emntDefault)) for (i = start; i < end; i++) { mu_x += q[i]*x[i][XX]; mu_y += q[i]*x[i][YY]; mu_z += q[i]*x[i][ZZ]; } mu[XX] = mu_x; mu[YY] = mu_y; mu[ZZ] = mu_z; for (m = 0; (m < DIM); m++) { mu[m] *= ENM2DEBYE; } if (nChargePerturbed) { mu_x = mu_y = mu_z = 0.0; #pragma omp parallel for reduction(+: mu_x, mu_y, mu_z) schedule(static) \ num_threads(gmx_omp_nthreads_get(emntDefault)) for (i = start; i < end; i++) { mu_x += qB[i]*x[i][XX]; mu_y += qB[i]*x[i][YY]; mu_z += qB[i]*x[i][ZZ]; } mu_B[XX] = mu_x * ENM2DEBYE; mu_B[YY] = mu_y * ENM2DEBYE; mu_B[ZZ] = mu_z * ENM2DEBYE; } else { copy_dvec(mu, mu_B); } }
static void get_pullgrps_dr(const t_pull *pull,const t_pbc *pbc,int g,double t, dvec xg,dvec xref,double max_dist2, dvec dr) { t_pullgrp *pref,*pgrp; int m; dvec xrefr,dref={0,0,0}; double dr2; pgrp = &pull->grp[g]; copy_dvec(xref,xrefr); if (pull->eGeom == epullgDIRPBC) { for(m=0; m<DIM; m++) { dref[m] = (pgrp->init[0] + pgrp->rate*t)*pull->grp[g].vec[m]; } /* Add the reference position, so we use the correct periodic image */ dvec_inc(xrefr,dref); } pbc_dx_d(pbc, xg, xrefr, dr); dr2 = 0; for(m=0; m<DIM; m++) { dr[m] *= pull->dim[m]; dr2 += dr[m]*dr[m]; } if (max_dist2 >= 0 && dr2 > 0.98*0.98*max_dist2) { gmx_fatal(FARGS,"Distance of pull group %d (%f nm) is larger than 0.49 times the box size (%f)",g,sqrt(dr2),sqrt(max_dist2)); } if (pull->eGeom == epullgDIRPBC) { dvec_inc(dr,dref); } }
/* 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); } }
void gamlr(int *famid, // 1 gaus, 2 bin, 3 pois int *n_in, // nobs int *p_in, // nvar int *N_in, // length of nonzero x entries int *xi_in, // length-l row ids for nonzero x int *xp_in, // length-p+1 pointers to each column start double *xv_in, // nonzero x entry values double *y_in, // length-n y int *prexx, // indicator for pre-calc xx double *xxv_in, // dense columns of upper tri for xx double *eta, // length-n fixed shifts (assumed zero for gaussian) double *varweight, // length-p weights double *obsweight, // length-n weights int *standardize, // whether to scale penalty by sd(x_j) int *nlam, // length of the path double *delta, // path stepsize double *penscale, // gamma in the GL paper double *thresh, // cd convergence int *maxit, // cd max iterations double *lambda, // output lambda double *deviance, // output deviance double *df, // output df double *alpha, // output intercepts double *beta, // output coefficients int *exits, // exit status. 0 is normal int *verb) // talk? { dirty = 1; // flag to say the function has been called // time stamp for periodic R interaction time_t itime = time(NULL); /** Build global variables **/ fam = *famid; n = *n_in; p = *p_in; nd = (double) n; pd = (double) p; N = *N_in; W = varweight; V = obsweight; E = eta; Y = y_in; xi = xi_in; xp = xp_in; xv = xv_in; doxx = *prexx; xxv = xxv_in; H = new_dvec(p); checkdata(*standardize); A=0.0; B = new_dzero(p); G = new_dzero(p); ag0 = new_dzero(p); gam = *penscale; npass = itertotal = 0; // some local variables double Lold, NLLHD, Lsat; int s; // family dependent settings switch( fam ) { case 2: nllhd = &bin_nllhd; reweight = &bin_reweight; A = log(ybar/(1-ybar)); Lsat = 0.0; break; case 3: nllhd = &po_nllhd; reweight = &po_reweight; A = log(ybar); // nonzero saturated deviance Lsat = ysum; for(int i=0; i<n; i++) if(Y[i]!=0) Lsat += -Y[i]*log(Y[i]); break; default: fam = 1; // if it wasn't already nllhd = &lin_nllhd; A = (ysum - sum_dvec(eta,n))/nd; Lsat=0.0; } if(fam!=1){ Z = new_dvec(n); vxbar = new_dvec(p); vxz = new_dvec(p); } else{ Z = Y; vxz = new_dzero(p); if(V[0]!=0){ vxbar = new_dvec(p); vstats(); } else{ vxbar = xbar; vsum = nd; for(int j=0; j<p; j++) for(int i=xp[j]; i<xp[j+1]; i++) vxz[j] += xv[i]*Z[xi[i]]; } } l1pen = INFINITY; Lold = INFINITY; NLLHD = nllhd(n, A, E, Y); if(*verb) speak("*** n=%d observations and p=%d covariates ***\n", n,p); // move along the path for(s=0; s<*nlam; s++){ // deflate the penalty if(s>0) lambda[s] = lambda[s-1]*(*delta); l1pen = lambda[s]*nd; // run descent exits[s] = cdsolve(*thresh,*maxit); // update parameters and objective itertotal += npass; Lold = NLLHD; NLLHD = nllhd(n, A, E, Y); deviance[s] = 2.0*(NLLHD - Lsat); df[s] = dof(s, lambda, NLLHD); alpha[s] = A; copy_dvec(&beta[s*p],B,p); if(s==0) *thresh *= deviance[0]; // relativism // gamma lasso updating for(int j=0; j<p; j++) if(isfinite(gam)){ if( (W[j]>0.0) & isfinite(W[j]) ) W[j] = 1.0/(1.0+gam*fabs(B[j])); } else if(B[j]!=0.0){ W[j] = 0.0; } // verbalize if(*verb) speak("segment %d: lambda = %.4g, dev = %.4g, npass = %d\n", s+1, lambda[s], deviance[s], npass); // exit checks if(deviance[s]<0.0){ exits[s] = 1; shout("Warning: negative deviance. "); } if(df[s] >= nd){ exits[s] = 1; shout("Warning: saturated model. "); } if(exits[s]){ shout("Finishing path early.\n"); *nlam = s; break; } itime = interact(itime); } *maxit = itertotal; gamlr_cleanup(); }
/* 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); } }
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]); } } } }
/* Apply constraint using SHAKE */ static void do_constraint(t_pull *pull, t_pbc *pbc, rvec *x, rvec *v, gmx_bool bMaster, tensor vir, double dt, double t) { dvec *r_ij; /* x[i] com of i in prev. step. Obeys constr. -> r_ij[i] */ dvec unc_ij; /* xp[i] com of i this step, before constr. -> unc_ij */ dvec *rnew; /* current 'new' positions of the groups */ double *dr_tot; /* the total update of the coords */ double ref; dvec vec; double d0, inpr; double lambda, rm, mass, invdt = 0; gmx_bool bConverged_all, bConverged = FALSE; int niter = 0, g, c, ii, j, m, max_iter = 100; double a; dvec f; /* the pull force */ dvec tmp, tmp3; t_pull_group *pdyna, *pgrp0, *pgrp1; t_pull_coord *pcrd; snew(r_ij, pull->ncoord); snew(dr_tot, pull->ncoord); snew(rnew, pull->ngroup); /* copy the current unconstrained positions for use in iterations. We iterate until rinew[i] and rjnew[j] obey the constraints. Then rinew - pull.x_unc[i] is the correction dr to group i */ for (g = 0; g < pull->ngroup; g++) { copy_dvec(pull->group[g].xp, rnew[g]); } if (PULL_CYL(pull)) { /* There is only one pull coordinate and reference group */ copy_dvec(pull->dyna[0].xp, rnew[pull->coord[0].group[0]]); } /* Determine the constraint directions from the old positions */ for (c = 0; c < pull->ncoord; c++) { get_pull_coord_dr(pull, c, pbc, t, r_ij[c]); /* Store the difference vector at time t for printing */ copy_dvec(r_ij[c], pull->coord[c].dr); if (debug) { fprintf(debug, "Pull coord %d dr %f %f %f\n", c, r_ij[c][XX], r_ij[c][YY], r_ij[c][ZZ]); } if (pull->eGeom == epullgDIR || pull->eGeom == epullgDIRPBC) { /* Select the component along vec */ a = 0; for (m = 0; m < DIM; m++) { a += pull->coord[c].vec[m]*r_ij[c][m]; } for (m = 0; m < DIM; m++) { r_ij[c][m] = a*pull->coord[c].vec[m]; } } } bConverged_all = FALSE; while (!bConverged_all && niter < max_iter) { bConverged_all = TRUE; /* loop over all constraints */ for (c = 0; c < pull->ncoord; c++) { dvec dr0, dr1; pcrd = &pull->coord[c]; pgrp0 = &pull->group[pcrd->group[0]]; pgrp1 = &pull->group[pcrd->group[1]]; /* Get the current difference vector */ low_get_pull_coord_dr(pull, pcrd, pbc, t, rnew[pcrd->group[1]], rnew[pcrd->group[0]], -1, unc_ij); ref = pcrd->init + pcrd->rate*t; if (debug) { fprintf(debug, "Pull coord %d, iteration %d\n", c, niter); } rm = 1.0/(pgrp0->invtm + pgrp1->invtm); switch (pull->eGeom) { case epullgDIST: if (ref <= 0) { gmx_fatal(FARGS, "The pull constraint reference distance for group %d is <= 0 (%f)", c, ref); } { double q, c_a, c_b, c_c; c_a = diprod(r_ij[c], r_ij[c]); c_b = diprod(unc_ij, r_ij[c])*2; c_c = diprod(unc_ij, unc_ij) - dsqr(ref); if (c_b < 0) { q = -0.5*(c_b - sqrt(c_b*c_b - 4*c_a*c_c)); lambda = -q/c_a; } else { q = -0.5*(c_b + sqrt(c_b*c_b - 4*c_a*c_c)); lambda = -c_c/q; } if (debug) { fprintf(debug, "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n", c_a, c_b, c_c, lambda); } } /* The position corrections dr due to the constraints */ dsvmul(-lambda*rm*pgrp1->invtm, r_ij[c], dr1); dsvmul( lambda*rm*pgrp0->invtm, r_ij[c], dr0); dr_tot[c] += -lambda*dnorm(r_ij[c]); break; case epullgDIR: case epullgDIRPBC: case epullgCYL: /* A 1-dimensional constraint along a vector */ a = 0; for (m = 0; m < DIM; m++) { vec[m] = pcrd->vec[m]; a += unc_ij[m]*vec[m]; } /* Select only the component along the vector */ dsvmul(a, vec, unc_ij); lambda = a - ref; if (debug) { fprintf(debug, "Pull inpr %e lambda: %e\n", a, lambda); } /* The position corrections dr due to the constraints */ dsvmul(-lambda*rm*pgrp1->invtm, vec, dr1); dsvmul( lambda*rm*pgrp0->invtm, vec, dr0); dr_tot[c] += -lambda; break; } /* DEBUG */ if (debug) { int g0, g1; g0 = pcrd->group[0]; g1 = pcrd->group[1]; low_get_pull_coord_dr(pull, pcrd, pbc, t, rnew[g1], rnew[g0], -1, tmp); low_get_pull_coord_dr(pull, pcrd, pbc, t, dr1, dr0, -1, tmp3); fprintf(debug, "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n", rnew[g0][0], rnew[g0][1], rnew[g0][2], rnew[g1][0], rnew[g1][1], rnew[g1][2], dnorm(tmp)); fprintf(debug, "Pull ref %8s %8s %8s %8s %8s %8s d: %8.5f\n", "", "", "", "", "", "", ref); fprintf(debug, "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n", dr0[0], dr0[1], dr0[2], dr1[0], dr1[1], dr1[2], dnorm(tmp3)); } /* END DEBUG */ /* Update the COMs with dr */ dvec_inc(rnew[pcrd->group[1]], dr1); dvec_inc(rnew[pcrd->group[0]], dr0); } /* Check if all constraints are fullfilled now */ for (c = 0; c < pull->ncoord; c++) { pcrd = &pull->coord[c]; low_get_pull_coord_dr(pull, pcrd, pbc, t, rnew[pcrd->group[1]], rnew[pcrd->group[0]], -1, unc_ij); switch (pull->eGeom) { case epullgDIST: bConverged = fabs(dnorm(unc_ij) - ref) < pull->constr_tol; break; case epullgDIR: case epullgDIRPBC: case epullgCYL: for (m = 0; m < DIM; m++) { vec[m] = pcrd->vec[m]; } inpr = diprod(unc_ij, vec); dsvmul(inpr, vec, unc_ij); bConverged = fabs(diprod(unc_ij, vec) - ref) < pull->constr_tol; break; } if (!bConverged) { if (debug) { fprintf(debug, "NOT CONVERGED YET: Group %d:" "d_ref = %f, current d = %f\n", g, ref, dnorm(unc_ij)); } bConverged_all = FALSE; } } niter++; /* if after all constraints are dealt with and bConverged is still TRUE we're finished, if not we do another iteration */ } if (niter > max_iter) { gmx_fatal(FARGS, "Too many iterations for constraint run: %d", niter); } /* DONE ITERATING, NOW UPDATE COORDINATES AND CALC. CONSTRAINT FORCES */ if (v) { invdt = 1/dt; } /* update atoms in the groups */ for (g = 0; g < pull->ngroup; g++) { const t_pull_group *pgrp; dvec dr; if (PULL_CYL(pull) && g == pull->coord[0].group[0]) { pgrp = &pull->dyna[0]; } else { pgrp = &pull->group[g]; } /* get the final constraint displacement dr for group g */ dvec_sub(rnew[g], pgrp->xp, dr); /* select components of dr */ for (m = 0; m < DIM; m++) { dr[m] *= pull->dim[m]; } /* update the atom positions */ copy_dvec(dr, tmp); for (j = 0; j < pgrp->nat_loc; j++) { ii = pgrp->ind_loc[j]; if (pgrp->weight_loc) { dsvmul(pgrp->wscale*pgrp->weight_loc[j], dr, tmp); } for (m = 0; m < DIM; m++) { x[ii][m] += tmp[m]; } if (v) { for (m = 0; m < DIM; m++) { v[ii][m] += invdt*tmp[m]; } } } } /* calculate the constraint forces, used for output and virial only */ for (c = 0; c < pull->ncoord; c++) { pcrd = &pull->coord[c]; pcrd->f_scal = dr_tot[c]/((pull->group[pcrd->group[0]].invtm + pull->group[pcrd->group[1]].invtm)*dt*dt); if (vir && bMaster) { double f_invr; /* Add the pull contribution to the virial */ f_invr = pcrd->f_scal/dnorm(r_ij[c]); for (j = 0; j < DIM; j++) { for (m = 0; m < DIM; m++) { vir[j][m] -= 0.5*f_invr*r_ij[c][j]*r_ij[c][m]; } } } } /* finished! I hope. Give back some memory */ sfree(r_ij); sfree(dr_tot); sfree(rnew); }
/* Apply constraint using SHAKE */ static void do_constraint(t_pull *pull, t_mdatoms *md, t_pbc *pbc, rvec *x, rvec *v, gmx_bool bMaster, tensor vir, double dt, double t) { dvec *r_ij; /* x[i] com of i in prev. step. Obeys constr. -> r_ij[i] */ dvec unc_ij; /* xp[i] com of i this step, before constr. -> unc_ij */ dvec *rinew; /* current 'new' position of group i */ dvec *rjnew; /* current 'new' position of group j */ dvec ref,vec; double d0,inpr; double lambda, rm, mass, invdt=0; gmx_bool bConverged_all,bConverged=FALSE; int niter=0,g,ii,j,m,max_iter=100; double q,a,b,c; /* for solving the quadratic equation, see Num. Recipes in C ed 2 p. 184 */ dvec *dr; /* correction for group i */ dvec ref_dr; /* correction for group j */ dvec f; /* the pull force */ dvec tmp,tmp3; t_pullgrp *pdyna,*pgrp,*pref; snew(r_ij,pull->ngrp+1); if (PULL_CYL(pull)) { snew(rjnew,pull->ngrp+1); } else { snew(rjnew,1); } snew(dr,pull->ngrp+1); snew(rinew,pull->ngrp+1); /* copy the current unconstrained positions for use in iterations. We iterate until rinew[i] and rjnew[j] obey the constraints. Then rinew - pull.x_unc[i] is the correction dr to group i */ for(g=1; g<1+pull->ngrp; g++) { copy_dvec(pull->grp[g].xp,rinew[g]); } if (PULL_CYL(pull)) { for(g=1; g<1+pull->ngrp; g++) { copy_dvec(pull->dyna[g].xp,rjnew[g]); } } else { copy_dvec(pull->grp[0].xp,rjnew[0]); } /* Determine the constraint directions from the old positions */ for(g=1; g<1+pull->ngrp; g++) { get_pullgrp_dr(pull,pbc,g,t,r_ij[g]); /* Store the difference vector at time t for printing */ copy_dvec(r_ij[g],pull->grp[g].dr); if (debug) { fprintf(debug,"Pull group %d dr %f %f %f\n", g,r_ij[g][XX],r_ij[g][YY],r_ij[g][ZZ]); } if (pull->eGeom == epullgDIR || pull->eGeom == epullgDIRPBC) { /* Select the component along vec */ a = 0; for(m=0; m<DIM; m++) { a += pull->grp[g].vec[m]*r_ij[g][m]; } for(m=0; m<DIM; m++) { r_ij[g][m] = a*pull->grp[g].vec[m]; } } } bConverged_all = FALSE; while (!bConverged_all && niter < max_iter) { bConverged_all = TRUE; /* loop over all constraints */ for(g=1; g<1+pull->ngrp; g++) { pgrp = &pull->grp[g]; if (PULL_CYL(pull)) pref = &pull->dyna[g]; else pref = &pull->grp[0]; /* Get the current difference vector */ get_pullgrps_dr(pull,pbc,g,t,rinew[g],rjnew[PULL_CYL(pull) ? g : 0], -1,unc_ij); if (pull->eGeom == epullgPOS) { for(m=0; m<DIM; m++) { ref[m] = pgrp->init[m] + pgrp->rate*t*pgrp->vec[m]; } } else { ref[0] = pgrp->init[0] + pgrp->rate*t; /* Keep the compiler happy */ ref[1] = 0; ref[2] = 0; } if (debug) { fprintf(debug,"Pull group %d, iteration %d\n",g,niter); } rm = 1.0/(pull->grp[g].invtm + pref->invtm); switch (pull->eGeom) { case epullgDIST: if (ref[0] <= 0) { gmx_fatal(FARGS,"The pull constraint reference distance for group %d is <= 0 (%f)",g,ref[0]); } a = diprod(r_ij[g],r_ij[g]); b = diprod(unc_ij,r_ij[g])*2; c = diprod(unc_ij,unc_ij) - dsqr(ref[0]); if (b < 0) { q = -0.5*(b - sqrt(b*b - 4*a*c)); lambda = -q/a; } else { q = -0.5*(b + sqrt(b*b - 4*a*c)); lambda = -c/q; } if (debug) { fprintf(debug, "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n", a,b,c,lambda); } /* The position corrections dr due to the constraints */ dsvmul(-lambda*rm*pgrp->invtm, r_ij[g], dr[g]); dsvmul( lambda*rm*pref->invtm, r_ij[g], ref_dr); break; case epullgDIR: case epullgDIRPBC: case epullgCYL: /* A 1-dimensional constraint along a vector */ a = 0; for(m=0; m<DIM; m++) { vec[m] = pgrp->vec[m]; a += unc_ij[m]*vec[m]; } /* Select only the component along the vector */ dsvmul(a,vec,unc_ij); lambda = a - ref[0]; if (debug) { fprintf(debug,"Pull inpr %e lambda: %e\n",a,lambda); } /* The position corrections dr due to the constraints */ dsvmul(-lambda*rm*pull->grp[g].invtm, vec, dr[g]); dsvmul( lambda*rm* pref->invtm, vec,ref_dr); break; case epullgPOS: for(m=0; m<DIM; m++) { if (pull->dim[m]) { lambda = r_ij[g][m] - ref[m]; /* The position corrections dr due to the constraints */ dr[g][m] = -lambda*rm*pull->grp[g].invtm; ref_dr[m] = lambda*rm*pref->invtm; } else { dr[g][m] = 0; ref_dr[m] = 0; } } break; } /* DEBUG */ if (debug) { j = (PULL_CYL(pull) ? g : 0); get_pullgrps_dr(pull,pbc,g,t,rinew[g],rjnew[j],-1,tmp); get_pullgrps_dr(pull,pbc,g,t,dr[g] ,ref_dr ,-1,tmp3); fprintf(debug, "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n", rinew[g][0],rinew[g][1],rinew[g][2], rjnew[j][0],rjnew[j][1],rjnew[j][2], dnorm(tmp)); if (pull->eGeom == epullgPOS) { fprintf(debug, "Pull ref %8.5f %8.5f %8.5f\n", pgrp->vec[0],pgrp->vec[1],pgrp->vec[2]); } else { fprintf(debug, "Pull ref %8s %8s %8s %8s %8s %8s d: %8.5f %8.5f %8.5f\n", "","","","","","",ref[0],ref[1],ref[2]); } fprintf(debug, "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n", dr[g][0],dr[g][1],dr[g][2], ref_dr[0],ref_dr[1],ref_dr[2], dnorm(tmp3)); fprintf(debug, "Pull cor %10.7f %10.7f %10.7f\n", dr[g][0],dr[g][1],dr[g][2]); } /* END DEBUG */ /* Update the COMs with dr */ dvec_inc(rinew[g], dr[g]); dvec_inc(rjnew[PULL_CYL(pull) ? g : 0],ref_dr); } /* Check if all constraints are fullfilled now */ for(g=1; g<1+pull->ngrp; g++) { pgrp = &pull->grp[g]; get_pullgrps_dr(pull,pbc,g,t,rinew[g],rjnew[PULL_CYL(pull) ? g : 0], -1,unc_ij); switch (pull->eGeom) { case epullgDIST: bConverged = fabs(dnorm(unc_ij) - ref[0]) < pull->constr_tol; break; case epullgDIR: case epullgDIRPBC: case epullgCYL: for(m=0; m<DIM; m++) { vec[m] = pgrp->vec[m]; } inpr = diprod(unc_ij,vec); dsvmul(inpr,vec,unc_ij); bConverged = fabs(diprod(unc_ij,vec) - ref[0]) < pull->constr_tol; break; case epullgPOS: bConverged = TRUE; for(m=0; m<DIM; m++) { if (pull->dim[m] && fabs(unc_ij[m] - ref[m]) >= pull->constr_tol) { bConverged = FALSE; } } break; } if (!bConverged) { if (debug) { fprintf(debug,"NOT CONVERGED YET: Group %d:" "d_ref = %f %f %f, current d = %f\n", g,ref[0],ref[1],ref[2],dnorm(unc_ij)); } bConverged_all = FALSE; } } niter++; /* if after all constraints are dealt with and bConverged is still TRUE we're finished, if not we do another iteration */ } if (niter > max_iter) { gmx_fatal(FARGS,"Too many iterations for constraint run: %d",niter); } /* DONE ITERATING, NOW UPDATE COORDINATES AND CALC. CONSTRAINT FORCES */ if (v) { invdt = 1/dt; } /* update the normal groups */ for(g=1; g<1+pull->ngrp; g++) { pgrp = &pull->grp[g]; /* get the final dr and constraint force for group i */ dvec_sub(rinew[g],pgrp->xp,dr[g]); /* select components of dr */ for(m=0; m<DIM; m++) { dr[g][m] *= pull->dim[m]; } dsvmul(1.0/(pgrp->invtm*dt*dt),dr[g],f); dvec_inc(pgrp->f,f); switch (pull->eGeom) { case epullgDIST: for(m=0; m<DIM; m++) { pgrp->f_scal += r_ij[g][m]*f[m]/dnorm(r_ij[g]); } break; case epullgDIR: case epullgDIRPBC: case epullgCYL: for(m=0; m<DIM; m++) { pgrp->f_scal += pgrp->vec[m]*f[m]; } break; case epullgPOS: break; } if (vir && bMaster) { /* Add the pull contribution to the virial */ for(j=0; j<DIM; j++) { for(m=0; m<DIM; m++) { vir[j][m] -= 0.5*f[j]*r_ij[g][m]; } } } /* update the atom positions */ copy_dvec(dr[g],tmp); for(j=0;j<pgrp->nat_loc;j++) { ii = pgrp->ind_loc[j]; if (pgrp->weight_loc) { dsvmul(pgrp->wscale*pgrp->weight_loc[j],dr[g],tmp); } for(m=0; m<DIM; m++) { x[ii][m] += tmp[m]; } if (v) { for(m=0; m<DIM; m++) { v[ii][m] += invdt*tmp[m]; } } } } /* update the reference groups */ if (PULL_CYL(pull)) { /* update the dynamic reference groups */ for(g=1; g<1+pull->ngrp; g++) { pdyna = &pull->dyna[g]; dvec_sub(rjnew[g],pdyna->xp,ref_dr); /* select components of ref_dr */ for(m=0; m<DIM; m++) { ref_dr[m] *= pull->dim[m]; } for(j=0;j<pdyna->nat_loc;j++) { /* reset the atoms with dr, weighted by w_i */ dsvmul(pdyna->wscale*pdyna->weight_loc[j],ref_dr,tmp); ii = pdyna->ind_loc[j]; for(m=0; m<DIM; m++) { x[ii][m] += tmp[m]; } if (v) { for(m=0; m<DIM; m++) { v[ii][m] += invdt*tmp[m]; } } } } } else { pgrp = &pull->grp[0]; /* update the reference group */ dvec_sub(rjnew[0],pgrp->xp, ref_dr); /* select components of ref_dr */ for(m=0;m<DIM;m++) { ref_dr[m] *= pull->dim[m]; } copy_dvec(ref_dr,tmp); for(j=0; j<pgrp->nat_loc;j++) { ii = pgrp->ind_loc[j]; if (pgrp->weight_loc) { dsvmul(pgrp->wscale*pgrp->weight_loc[j],ref_dr,tmp); } for(m=0; m<DIM; m++) { x[ii][m] += tmp[m]; } if (v) { for(m=0; m<DIM; m++) { v[ii][m] += invdt*tmp[m]; } } } } /* finished! I hope. Give back some memory */ sfree(r_ij); sfree(rinew); sfree(rjnew); sfree(dr); }
void pbc_dx_d(const t_pbc *pbc, const dvec x1, const dvec x2, dvec dx) { int i, j; dvec dx_start, trial; double d2min, d2trial; gmx_bool bRot; dvec_sub(x1, x2, dx); switch (pbc->ePBCDX) { case epbcdxRECTANGULAR: case epbcdx2D_RECT: for (i = 0; i < DIM; i++) { if (i != pbc->dim) { while (dx[i] > pbc->hbox_diag[i]) { dx[i] -= pbc->fbox_diag[i]; } while (dx[i] <= pbc->mhbox_diag[i]) { dx[i] += pbc->fbox_diag[i]; } } } break; case epbcdxTRICLINIC: case epbcdx2D_TRIC: d2min = 0; for (i = DIM-1; i >= 0; i--) { if (i != pbc->dim) { while (dx[i] > pbc->hbox_diag[i]) { for (j = i; j >= 0; j--) { dx[j] -= pbc->box[i][j]; } } while (dx[i] <= pbc->mhbox_diag[i]) { for (j = i; j >= 0; j--) { dx[j] += pbc->box[i][j]; } } d2min += dx[i]*dx[i]; } } if (d2min > pbc->max_cutoff2) { copy_dvec(dx, dx_start); /* Now try all possible shifts, when the distance is within max_cutoff * it must be the shortest possible distance. */ i = 0; while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) { for (j = 0; j < DIM; j++) { trial[j] = dx_start[j] + pbc->tric_vec[i][j]; } d2trial = 0; for (j = 0; j < DIM; j++) { if (j != pbc->dim) { d2trial += trial[j]*trial[j]; } } if (d2trial < d2min) { copy_dvec(trial, dx); d2min = d2trial; } i++; } } break; case epbcdxSCREW_RECT: /* The shift definition requires x first */ bRot = FALSE; while (dx[XX] > pbc->hbox_diag[XX]) { dx[XX] -= pbc->fbox_diag[XX]; bRot = !bRot; } while (dx[XX] <= pbc->mhbox_diag[XX]) { dx[XX] += pbc->fbox_diag[YY]; bRot = !bRot; } if (bRot) { /* Rotate around the x-axis in the middle of the box */ dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY]; dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ]; } /* Normal pbc for y and z */ for (i = YY; i <= ZZ; i++) { while (dx[i] > pbc->hbox_diag[i]) { dx[i] -= pbc->fbox_diag[i]; } while (dx[i] <= pbc->mhbox_diag[i]) { dx[i] += pbc->fbox_diag[i]; } } break; case epbcdxNOPBC: case epbcdxUNSUPPORTED: break; default: gmx_fatal(FARGS, "Internal error in pbc_dx, set_pbc has not been called"); break; } }
double* new_dup_dvec(double *v, int n) { double* dv_new = new_dvec(n); copy_dvec(dv_new, v, n); return dv_new; }