main() { double ans, a, b, c; a = 2.0; b = -5.0; c = 7.0; printf( "\n\n Test of utility routines." ); printf( "\n\n" ); ans = dsqr( a ); printf( "\n a = %lf ans = dsqr( a ) = %lf", a, ans ); ans = dcub( a ); printf( "\n a = %lf ans = dcub( a ) = %lf", a, ans ); ans = dpow4( a ); printf( "\n a = %lf ans = dpow4( a ) = %lf", a, ans ); ans = dpow5( a ); printf( "\n a = %lf ans = dpow5( a ) = %lf", a, ans ); ans = dsgn( a ); printf( "\n a = %lf ans = dsgn( a ) = %lf", a, ans ); ans = dsgn( b ); printf( "\n b = %lf ans = dsgn( b ) = %lf", b, ans ); ans = dsign( a, b ); printf( "\n a = %lf, b = %lf, ans = sign( a, b ) = %lf", a, b, ans ); ans = dpythag( a, b ); printf( "\n a = %lf, b = %lf, ans = pythag( a, b ) = %lf", a, b, ans ); ans = dmin( a, b ); printf( "\n a = %lf, b = %lf, ans = dmin( a, b ) = %lf", a, b, ans ); ans = dmax( a, b ); printf( "\n a = %lf, b = %lf, ans = dmax( a, b ) = %lf", a, b, ans ); ans = dmin3( a, b, c ); printf( "\n a = %lf, b = %lf, c = %lf, ans = dmin3( a, b, c ) = %lf", a, b, c, ans ); ans = dmax3( a, b, c ); printf( "\n a = %lf, b = %lf, c = %lf, ans = dmax3( a, b, c ) = %lf", a, b, c, ans ); printf( "\n\n" ); }
double dawson( double x ) { int i, n0; double d1, d2, e1, e2, sum, x2, xp, xx, ans; static double c[NMAX+1]; static int init = 0; if ( init == 0 ) { init = 1; for ( i = 1; i <= NMAX; ++i ) { c[i] = exp( -dsqr( ( 2.0*i - 1.0 )*H ) ); } } if ( fabs(x) < XMIN ) { /* * Use series expansion. */ x2 = x*x; ans = x*( 1.0 - (2.0/3.0)*x2*( 1.0 - (2.0/5.0)*x2*( 1.0 - (2.0/7.0)*x2 ) ) ); } else { /* * Use sampling theorem representation. */ xx = fabs(x); n0 = 2*( (int)(0.5 + 0.5*xx/H) ); xp = xx - n0*H; e1 = exp(2.0*xp*H); e2 = e1*e1; d1 = (double) n0 + 1.0; d2 = d1 - 2.0; sum = 0.0; for ( i = 1; i <= NMAX; ++i ) { sum += c[i]*( e1/d1 + 1.0/(d2*e1) ); d1 += 2.0; d2 -= 2.0; e1 *= e2; } ans = dsign( exp( -xp*xp ), x )*sum/SQRTPI; } return ans; }
static void make_cyl_refgrps(t_commrec *cr, t_pull *pull, t_mdatoms *md, t_pbc *pbc, double t, rvec *x, rvec *xp) { int c, i, ii, m, start, end; rvec g_x, dx, dir; double r0_2, sum_a, sum_ap, dr2, mass, weight, wmass, wwmass, inp; t_pull_coord *pcrd; t_pull_group *pref, *pgrp, *pdyna; gmx_ga2la_t ga2la = NULL; if (pull->dbuf_cyl == NULL) { snew(pull->dbuf_cyl, pull->ncoord*4); } if (cr && DOMAINDECOMP(cr)) { ga2la = cr->dd->ga2la; } start = 0; end = md->homenr; r0_2 = dsqr(pull->cyl_r0); /* loop over all groups to make a reference group for each*/ for (c = 0; c < pull->ncoord; c++) { pcrd = &pull->coord[c]; /* pref will be the same group for all pull coordinates */ pref = &pull->group[pcrd->group[0]]; pgrp = &pull->group[pcrd->group[1]]; pdyna = &pull->dyna[c]; copy_rvec(pcrd->vec, dir); sum_a = 0; sum_ap = 0; wmass = 0; wwmass = 0; pdyna->nat_loc = 0; for (m = 0; m < DIM; m++) { g_x[m] = pgrp->x[m] - pcrd->vec[m]*(pcrd->init + pcrd->rate*t); } /* loop over all atoms in the main ref group */ for (i = 0; i < pref->nat; i++) { ii = pref->ind[i]; if (ga2la) { if (!ga2la_get_home(ga2la, pref->ind[i], &ii)) { ii = -1; } } if (ii >= start && ii < end) { pbc_dx_aiuc(pbc, x[ii], g_x, dx); inp = iprod(dir, dx); dr2 = 0; for (m = 0; m < DIM; m++) { dr2 += dsqr(dx[m] - inp*dir[m]); } if (dr2 < r0_2) { /* 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); } pdyna->ind_loc[pdyna->nat_loc] = ii; mass = md->massT[ii]; weight = get_weight(sqrt(dr2), pull->cyl_r1, pull->cyl_r0); pdyna->weight_loc[pdyna->nat_loc] = weight; sum_a += mass*weight*inp; if (xp) { pbc_dx_aiuc(pbc, xp[ii], g_x, dx); inp = iprod(dir, dx); sum_ap += mass*weight*inp; } wmass += mass*weight; wwmass += mass*sqr(weight); pdyna->nat_loc++; } } } pull->dbuf_cyl[c*4+0] = wmass; pull->dbuf_cyl[c*4+1] = wwmass; pull->dbuf_cyl[c*4+2] = sum_a; pull->dbuf_cyl[c*4+3] = sum_ap; } if (cr && PAR(cr)) { /* Sum the contributions over the nodes */ gmx_sumd(pull->ncoord*4, pull->dbuf_cyl, cr); } for (c = 0; c < pull->ncoord; c++) { pcrd = &pull->coord[c]; pdyna = &pull->dyna[c]; pgrp = &pull->group[pcrd->group[1]]; wmass = pull->dbuf_cyl[c*4+0]; wwmass = pull->dbuf_cyl[c*4+1]; pdyna->wscale = wmass/wwmass; pdyna->invtm = 1.0/(pdyna->wscale*wmass); for (m = 0; m < DIM; m++) { g_x[m] = pgrp->x[m] - pcrd->vec[m]*(pcrd->init + pcrd->rate*t); pdyna->x[m] = g_x[m] + pcrd->vec[m]*pull->dbuf_cyl[c*4+2]/wmass; if (xp) { pdyna->xp[m] = g_x[m] + pcrd->vec[m]*pull->dbuf_cyl[c*4+3]/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); } } }
double Neuroseg_Ry_P(const Neuroseg *seg, const double *res, Neuropos_Reference_e ref) { return Neuroseg_Ry(seg, ref) * sqrt(dsqr(res[0]) * cos(seg->theta) + dsqr(res[1]) * sin(seg->theta)); }
static void convert_full_sums(ener_old_t *ener_old,t_enxframe *fr) { int nstep_all; int ne,ns,i; double esum_all,eav_all; if (fr->nsum > 0) { ne = 0; ns = 0; for(i=0; i<fr->nre; i++) { if (fr->ener[i].e != 0) ne++; if (fr->ener[i].esum != 0) ns++; } if (ne > 0 && ns == 0) { /* We do not have all energy sums */ fr->nsum = 0; } } /* Convert old full simulation sums to sums between energy frames */ nstep_all = fr->step - ener_old->first_step + 1; if (fr->nsum > 1 && fr->nsum == nstep_all && ener_old->nsum_prev > 0) { /* Set the new sum length: the frame step difference */ fr->nsum = fr->step - ener_old->step_prev; for(i=0; i<fr->nre; i++) { esum_all = fr->ener[i].esum; eav_all = fr->ener[i].eav; fr->ener[i].esum = esum_all - ener_old->ener_prev[i].esum; fr->ener[i].eav = eav_all - ener_old->ener_prev[i].eav - dsqr(ener_old->ener_prev[i].esum/(nstep_all - fr->nsum) - esum_all/nstep_all)* (nstep_all - fr->nsum)*nstep_all/(double)fr->nsum; ener_old->ener_prev[i].esum = esum_all; ener_old->ener_prev[i].eav = eav_all; } ener_old->nsum_prev = nstep_all; } else if (fr->nsum > 0) { if (fr->nsum != nstep_all) { fprintf(stderr,"\nWARNING: something is wrong with the energy sums, will not use exact averages\n"); ener_old->nsum_prev = 0; } else { ener_old->nsum_prev = nstep_all; } /* Copy all sums to ener_prev */ for(i=0; i<fr->nre; i++) { ener_old->ener_prev[i].esum = fr->ener[i].esum; ener_old->ener_prev[i].eav = fr->ener[i].eav; } } ener_old->step_prev = fr->step; }
static void update_ee_sum(int nre, gmx_int64_t *ee_sum_step, gmx_int64_t *ee_sum_nsteps, gmx_int64_t *ee_sum_nsum, t_energy *ee_sum, t_enxframe *fr, int out_step) { gmx_int64_t nsteps, nsum, fr_nsum; int i; nsteps = *ee_sum_nsteps; nsum = *ee_sum_nsum; fr_nsum = fr->nsum; if (fr_nsum == 0) { fr_nsum = 1; } if (nsteps == 0) { if (fr_nsum == 1) { for (i = 0; i < nre; i++) { ee_sum[i].esum = fr->ener[i].e; ee_sum[i].eav = 0; } } else { for (i = 0; i < nre; i++) { ee_sum[i].esum = fr->ener[i].esum; ee_sum[i].eav = fr->ener[i].eav; } } nsteps = fr->nsteps; nsum = fr_nsum; } else if (out_step + *ee_sum_nsum - *ee_sum_step == nsteps + fr->nsteps) { if (fr_nsum == 1) { for (i = 0; i < nre; i++) { ee_sum[i].eav += dsqr(ee_sum[i].esum/nsum - (ee_sum[i].esum + fr->ener[i].e)/(nsum + 1))*nsum*(nsum + 1); ee_sum[i].esum += fr->ener[i].e; } } else { for (i = 0; i < fr->nre; i++) { ee_sum[i].eav += fr->ener[i].eav + dsqr(ee_sum[i].esum/nsum - (ee_sum[i].esum + fr->ener[i].esum)/(nsum + fr->nsum))* nsum*(nsum + fr->nsum)/(double)fr->nsum; ee_sum[i].esum += fr->ener[i].esum; } } nsteps += fr->nsteps; nsum += fr_nsum; } else { if (fr->nsum != 0) { fprintf(stderr, "\nWARNING: missing energy sums at time %f\n", fr->t); } nsteps = 0; nsum = 0; } *ee_sum_step = out_step; *ee_sum_nsteps = nsteps; *ee_sum_nsum = nsum; }
/* Pulling with a harmonic umbrella potential or constant force */ static void do_pull_pot(int ePull, t_pull *pull, t_pbc *pbc, double t, real lambda, real *V, tensor vir, real *dVdl) { int c, j, m; double dev, ndr, invdr; real k, dkdl; t_pull_coord *pcrd; /* loop over the pull coordinates */ *V = 0; *dVdl = 0; for (c = 0; c < pull->ncoord; c++) { pcrd = &pull->coord[c]; get_pull_coord_distance(pull, c, pbc, t, pcrd->dr, &dev); k = (1.0 - lambda)*pcrd->k + lambda*pcrd->kB; dkdl = pcrd->kB - pcrd->k; switch (pull->eGeom) { case epullgDIST: ndr = dnorm(pcrd->dr); invdr = 1/ndr; if (ePull == epullUMBRELLA) { pcrd->f_scal = -k*dev; *V += 0.5* k*dsqr(dev); *dVdl += 0.5*dkdl*dsqr(dev); } else { pcrd->f_scal = -k; *V += k*ndr; *dVdl += dkdl*ndr; } for (m = 0; m < DIM; m++) { pcrd->f[m] = pcrd->f_scal*pcrd->dr[m]*invdr; } break; case epullgDIR: case epullgDIRPBC: case epullgCYL: if (ePull == epullUMBRELLA) { pcrd->f_scal = -k*dev; *V += 0.5* k*dsqr(dev); *dVdl += 0.5*dkdl*dsqr(dev); } else { ndr = 0; for (m = 0; m < DIM; m++) { ndr += pcrd->vec[m]*pcrd->dr[m]; } pcrd->f_scal = -k; *V += k*ndr; *dVdl += dkdl*ndr; } for (m = 0; m < DIM; m++) { pcrd->f[m] = pcrd->f_scal*pcrd->vec[m]; } break; } if (vir) { /* Add the pull contribution to the virial */ for (j = 0; j < DIM; j++) { for (m = 0; m < DIM; m++) { vir[j][m] -= 0.5*pcrd->f[j]*pcrd->dr[m]; } } } } }
static int gmx_stats_compute(gmx_stats *stats, int weight) { double yy, yx, xx, sx, sy, dy, chi2, chi2aa, d2; double ssxx, ssyy, ssxy; double w, wtot, yx_nw, sy_nw, sx_nw, yy_nw, xx_nw, dx2, dy2; int i, N; N = stats->np; if (stats->computed == 0) { if (N < 1) { return estatsNO_POINTS; } xx = xx_nw = 0; yy = yy_nw = 0; yx = yx_nw = 0; sx = sx_nw = 0; sy = sy_nw = 0; wtot = 0; d2 = 0; for (i = 0; (i < N); i++) { d2 += dsqr(stats->x[i]-stats->y[i]); if ((stats->dy[i]) && (weight == elsqWEIGHT_Y)) { w = 1/dsqr(stats->dy[i]); } else { w = 1; } wtot += w; xx += w*dsqr(stats->x[i]); xx_nw += dsqr(stats->x[i]); yy += w*dsqr(stats->y[i]); yy_nw += dsqr(stats->y[i]); yx += w*stats->y[i]*stats->x[i]; yx_nw += stats->y[i]*stats->x[i]; sx += w*stats->x[i]; sx_nw += stats->x[i]; sy += w*stats->y[i]; sy_nw += stats->y[i]; } /* Compute average, sigma and error */ stats->aver = sy_nw/N; stats->sigma_aver = sqrt(yy_nw/N - dsqr(sy_nw/N)); stats->error = stats->sigma_aver/sqrt(N); /* Compute RMSD between x and y */ stats->rmsd = sqrt(d2/N); /* Correlation coefficient for data */ yx_nw /= N; xx_nw /= N; yy_nw /= N; sx_nw /= N; sy_nw /= N; ssxx = N*(xx_nw - dsqr(sx_nw)); ssyy = N*(yy_nw - dsqr(sy_nw)); ssxy = N*(yx_nw - (sx_nw*sy_nw)); stats->Rdata = sqrt(dsqr(ssxy)/(ssxx*ssyy)); /* Compute straight line through datapoints, either with intercept zero (result in aa) or with intercept variable (results in a and b) */ yx = yx/wtot; xx = xx/wtot; sx = sx/wtot; sy = sy/wtot; stats->aa = (yx/xx); stats->a = (yx-sx*sy)/(xx-sx*sx); stats->b = (sy)-(stats->a)*(sx); /* Compute chi2, deviation from a line y = ax+b. Also compute chi2aa which returns the deviation from a line y = ax. */ chi2 = 0; chi2aa = 0; for (i = 0; (i < N); i++) { if (stats->dy[i] > 0) { dy = stats->dy[i]; } else { dy = 1; } chi2aa += dsqr((stats->y[i]-(stats->aa*stats->x[i]))/dy); chi2 += dsqr((stats->y[i]-(stats->a*stats->x[i]+stats->b))/dy); } if (N > 2) { stats->chi2 = sqrt(chi2/(N-2)); stats->chi2aa = sqrt(chi2aa/(N-2)); /* Look up equations! */ dx2 = (xx-sx*sx); dy2 = (yy-sy*sy); stats->sigma_a = sqrt(stats->chi2/((N-2)*dx2)); stats->sigma_b = stats->sigma_a*sqrt(xx); stats->Rfit = fabs(ssxy)/sqrt(ssxx*ssyy); /*stats->a*sqrt(dx2/dy2);*/ stats->Rfitaa = stats->aa*sqrt(dx2/dy2); } else { stats->chi2 = 0; stats->chi2aa = 0; stats->sigma_a = 0; stats->sigma_b = 0; stats->Rfit = 0; stats->Rfitaa = 0; } stats->computed = 1; } return estatsOK; }
/* 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); }
/* Pulling with a harmonic umbrella potential or constant force */ static void do_pull_pot(int ePull, t_pull *pull, t_pbc *pbc, double t, real lambda, real *V, tensor vir, real *dVdl) { int g,j,m; dvec dev; double ndr,invdr; real k,dkdl; t_pullgrp *pgrp; /* loop over the groups that are being pulled */ *V = 0; *dVdl = 0; for(g=1; g<1+pull->ngrp; g++) { pgrp = &pull->grp[g]; get_pullgrp_distance(pull,pbc,g,t,pgrp->dr,dev); k = (1.0 - lambda)*pgrp->k + lambda*pgrp->kB; dkdl = pgrp->kB - pgrp->k; switch (pull->eGeom) { case epullgDIST: ndr = dnorm(pgrp->dr); invdr = 1/ndr; if (ePull == epullUMBRELLA) { pgrp->f_scal = -k*dev[0]; *V += 0.5* k*dsqr(dev[0]); *dVdl += 0.5*dkdl*dsqr(dev[0]); } else { pgrp->f_scal = -k; *V += k*ndr; *dVdl += dkdl*ndr; } for(m=0; m<DIM; m++) { pgrp->f[m] = pgrp->f_scal*pgrp->dr[m]*invdr; } break; case epullgDIR: case epullgDIRPBC: case epullgCYL: if (ePull == epullUMBRELLA) { pgrp->f_scal = -k*dev[0]; *V += 0.5* k*dsqr(dev[0]); *dVdl += 0.5*dkdl*dsqr(dev[0]); } else { ndr = 0; for(m=0; m<DIM; m++) { ndr += pgrp->vec[m]*pgrp->dr[m]; } pgrp->f_scal = -k; *V += k*ndr; *dVdl += dkdl*ndr; } for(m=0; m<DIM; m++) { pgrp->f[m] = pgrp->f_scal*pgrp->vec[m]; } break; case epullgPOS: for(m=0; m<DIM; m++) { if (ePull == epullUMBRELLA) { pgrp->f[m] = -k*dev[m]; *V += 0.5* k*dsqr(dev[m]); *dVdl += 0.5*dkdl*dsqr(dev[m]); } else { pgrp->f[m] = -k*pull->dim[m]; *V += k*pgrp->dr[m]*pull->dim[m]; *dVdl += dkdl*pgrp->dr[m]*pull->dim[m]; } } break; } if (vir) { /* Add the pull contribution to the virial */ for(j=0; j<DIM; j++) { for(m=0;m<DIM;m++) { vir[j][m] -= 0.5*pgrp->f[j]*pgrp->dr[m]; } } } } }
/* 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); }
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/dsqr(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]); } } } }
/** * Calculate approximate squared (flat projected) distance between this point * and another * * @param tp Point to calculate distance to * * @return Approximate squared distance */ gcc_pure unsigned approx_sq_dist(const TracePoint& tp) const { return dsqr(get_flatLocation().Longitude-tp.get_flatLocation().Longitude)+ dsqr(get_flatLocation().Latitude-tp.get_flatLocation().Latitude); }