예제 #1
0
static void pull_set_pbcatoms(t_commrec *cr, t_pull *pull,
                              t_mdatoms *md, rvec *x,
                              rvec *x_pbc)
{
    int g, n, m;

    n = 0;
    for (g = 0; g < pull->ngroup; g++)
    {
        if ((g == 0 && PULL_CYL(pull)) || pull->group[g].pbcatom == -1)
        {
            clear_rvec(x_pbc[g]);
        }
        else
        {
            pull_set_pbcatom(cr, &pull->group[g], md, x, x_pbc[g]);
            for (m = 0; m < DIM; m++)
            {
                if (pull->dim[m] == 0)
                {
                    x_pbc[g][m] = 0.0;
                }
            }
            n++;
        }
    }

    if (cr && PAR(cr) && n > 0)
    {
        /* Sum over the nodes to get x_pbc from the home node of pbcatom */
        gmx_sum(pull->ngroup*DIM, x_pbc[0], cr);
    }
}
예제 #2
0
파일: pull.c 프로젝트: exianshine/gromacs
static void pull_print_x(FILE *out, t_pull *pull, double t)
{
    int                 c;
    const t_pull_coord *pcrd;

    fprintf(out, "%.4f", t);

    for (c = 0; c < pull->ncoord; c++)
    {
        pcrd = &pull->coord[c];

        if (pull->bPrintRef)
        {
            if (PULL_CYL(pull))
            {
                pull_print_group_x(out, pull->dim, &pull->dyna[c]);
            }
            else
            {
                pull_print_group_x(out, pull->dim, &pull->group[pcrd->group[0]]);  
            }
        }
        pull_print_coord_dr(out, pull->dim, pcrd);
    }
    fprintf(out, "\n");
}
예제 #3
0
파일: pull.c 프로젝트: exianshine/gromacs
static void get_pull_coord_dr(const t_pull *pull,
                              int coord_ind,
                              const t_pbc *pbc, double t,
                              dvec dr)
{
    double              md2;
    const t_pull_coord *pcrd;

    if (pull->eGeom == epullgDIRPBC)
    {
        md2 = -1;
    }
    else
    {
        md2 = max_pull_distance2(pull, pbc);
    }

    pcrd = &pull->coord[coord_ind];

    low_get_pull_coord_dr(pull, pcrd, pbc, t,
                          pull->group[pcrd->group[1]].x,
                          PULL_CYL(pull) ? pull->dyna[coord_ind].x : pull->group[pcrd->group[0]].x,
                          md2,
                          dr);
}
예제 #4
0
static void pull_print_x(FILE *out,t_pull *pull,double t) 
{
    int g;
  
    fprintf(out, "%.4f", t);
    
    if (PULL_CYL(pull))
    {
        for (g=1; g<1+pull->ngrp; g++)
        {
            pull_print_x_grp(out,TRUE ,pull->dim,&pull->dyna[g]);
            pull_print_x_grp(out,FALSE,pull->dim,&pull->grp[g]);
        }
    }
    else
    {
        for (g=0; g<1+pull->ngrp; g++)
        {
            if (pull->grp[g].nat > 0)
            {
                pull_print_x_grp(out,g==0,pull->dim,&pull->grp[g]);
            }
        }
    }
    fprintf(out,"\n");
}
예제 #5
0
static void get_pullgrp_dr(const t_pull *pull,const t_pbc *pbc,int g,double t,
                           dvec dr)
{
    double md2;

    if (pull->eGeom == epullgDIRPBC)
    {
        md2 = -1;
    }
    else
    {
        md2 = max_pull_distance2(pull,pbc);
    }

    get_pullgrps_dr(pull,pbc,g,t,
                    pull->grp[g].x,
                    PULL_CYL(pull) ? pull->dyna[g].x : pull->grp[0].x,
                    md2,
                    dr);
}
예제 #6
0
파일: pull.c 프로젝트: exianshine/gromacs
/* Apply forces in a mass weighted fashion */
static void apply_forces(t_pull * pull, t_mdatoms * md, rvec *f)
{
    int                 c;
    const t_pull_coord *pcrd;

    for (c = 0; c < pull->ncoord; c++)
    {
        pcrd = &pull->coord[c];

        if (PULL_CYL(pull))
        {
            apply_forces_grp(&pull->dyna[c], md, pcrd->f, -1, f);
        }
        else
        {
            if (pull->group[pcrd->group[0]].nat > 0)
            {
                apply_forces_grp(&pull->group[pcrd->group[0]], md, pcrd->f, -1, f);
            }
        }
        apply_forces_grp(&pull->group[pcrd->group[1]], md, pcrd->f, 1, f);
    }
}
예제 #7
0
/* Apply forces in a mass weighted fashion */
static void apply_forces(t_pull * pull, t_mdatoms * md, gmx_ga2la_t ga2la,
                         rvec *f)
{
    int i;
    t_pullgrp *pgrp;
    
    for(i=1; i<pull->ngrp+1; i++)
    {
        pgrp = &(pull->grp[i]);
        apply_forces_grp(pgrp,md,ga2la,pgrp->f,1,f);
        if (pull->grp[0].nat)
        {
            if (PULL_CYL(pull))
            {
                apply_forces_grp(&(pull->dyna[i]),md,ga2la,pgrp->f,-1,f);
            }
            else
            {
                apply_forces_grp(&(pull->grp[0]),md,ga2la,pgrp->f,-1,f);
            }
        }
    }
}
예제 #8
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);
    }
}
예제 #9
0
파일: pull.c 프로젝트: exianshine/gromacs
/* 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);
}
예제 #10
0
파일: pull.c 프로젝트: exianshine/gromacs
void init_pull(FILE *fplog, t_inputrec *ir, int nfile, const t_filenm fnm[],
               gmx_mtop_t *mtop, t_commrec *cr, const output_env_t oenv, real lambda,
               gmx_bool bOutFile, unsigned long Flags)
{
    t_pull       *pull;
    t_pull_group *pgrp;
    int           c, g, start = 0, end = 0, m;

    pull = ir->pull;

    pull->ePBC = ir->ePBC;
    switch (pull->ePBC)
    {
        case epbcNONE: pull->npbcdim = 0; break;
        case epbcXY:   pull->npbcdim = 2; break;
        default:       pull->npbcdim = 3; break;
    }

    if (fplog)
    {
        gmx_bool bAbs, bCos;

        bAbs = FALSE;
        for (c = 0; c < pull->ncoord; c++)
        {
            if (pull->group[pull->coord[c].group[0]].nat == 0 ||
                pull->group[pull->coord[c].group[1]].nat == 0)
            {
                bAbs = TRUE;
            }
        }
        
        fprintf(fplog, "\nWill apply %s COM pulling in geometry '%s'\n",
                EPULLTYPE(ir->ePull), EPULLGEOM(pull->eGeom));
        fprintf(fplog, "with %d pull coordinate%s and %d group%s\n",
                pull->ncoord, pull->ncoord == 1 ? "" : "s",
                pull->ngroup, pull->ngroup == 1 ? "" : "s");
        if (bAbs)
        {
            fprintf(fplog, "with an absolute reference\n");
        }
        bCos = FALSE;
        for (g = 0; g < pull->ngroup; g++)
        {
            if (pull->group[g].nat > 1 &&
                pull->group[g].pbcatom < 0)
            {
                /* We are using cosine weighting */
                fprintf(fplog, "Cosine weighting is used for group %d\n", g);
                bCos = TRUE;
            }
        }
        if (bCos)
        {
            please_cite(fplog, "Engin2010");
        }
    }

    /* We always add the virial contribution,
     * except for geometry = direction_periodic where this is impossible.
     */
    pull->bVirial = (pull->eGeom != epullgDIRPBC);
    if (getenv("GMX_NO_PULLVIR") != NULL)
    {
        if (fplog)
        {
            fprintf(fplog, "Found env. var., will not add the virial contribution of the COM pull forces\n");
        }
        pull->bVirial = FALSE;
    }

    if (cr && PARTDECOMP(cr))
    {
        pd_at_range(cr, &start, &end);
    }
    pull->rbuf     = NULL;
    pull->dbuf     = NULL;
    pull->dbuf_cyl = NULL;
    pull->bRefAt   = FALSE;
    pull->cosdim   = -1;
    for (g = 0; g < pull->ngroup; g++)
    {
        pgrp           = &pull->group[g];
        pgrp->epgrppbc = epgrppbcNONE;
        if (pgrp->nat > 0)
        {
            /* Determine if we need to take PBC into account for calculating
             * the COM's of the pull groups.
             */
            for (m = 0; m < pull->npbcdim; m++)
            {
                if (pull->dim[m] && pgrp->nat > 1)
                {
                    if (pgrp->pbcatom >= 0)
                    {
                        pgrp->epgrppbc = epgrppbcREFAT;
                        pull->bRefAt   = TRUE;
                    }
                    else
                    {
                        if (pgrp->weight)
                        {
                            gmx_fatal(FARGS, "Pull groups can not have relative weights and cosine weighting at same time");
                        }
                        pgrp->epgrppbc = epgrppbcCOS;
                        if (pull->cosdim >= 0 && pull->cosdim != m)
                        {
                            gmx_fatal(FARGS, "Can only use cosine weighting with pulling in one dimension (use mdp option pull_dim)");
                        }
                        pull->cosdim = m;
                    }
                }
            }
            /* Set the indices */
            init_pull_group_index(fplog, cr, start, end, g, pgrp, pull->dim, mtop, ir, lambda);
            if (PULL_CYL(pull) && pgrp->invtm == 0)
            {
                gmx_fatal(FARGS, "Can not have frozen atoms in a cylinder pull group");
            }
        }
        else
        {
            /* Absolute reference, set the inverse mass to zero */
            pgrp->invtm  = 0;
            pgrp->wscale = 1;
        }
    }

    /* if we use dynamic reference groups, do some initialising for them */
    if (PULL_CYL(pull))
    {
        if (ir->ePull == epullCONSTRAINT && pull->ncoord > 1)
        {
            /* We can't easily update the single reference group with multiple
             * constraints. This would require recalculating COMs.
             */
            gmx_fatal(FARGS, "Constraint COM pulling supports only one coordinate with geometry=cylinder, you can use umbrella pulling with multiple coordinates");
        }

        for (c = 0; c < pull->ncoord; c++)
        {
            if (pull->group[pull->coord[c].group[0]].nat == 0)
            {
                gmx_fatal(FARGS, "Dynamic reference groups are not supported when using absolute reference!\n");
            }
        }

        snew(pull->dyna, pull->ncoord);
    }

    /* Only do I/O when we are doing dynamics and if we are the MASTER */
    pull->out_x = NULL;
    pull->out_f = NULL;
    if (bOutFile)
    {
        if (pull->nstxout > 0)
        {
            pull->out_x = open_pull_out(opt2fn("-px", nfile, fnm), pull, oenv, TRUE, Flags);
        }
        if (pull->nstfout > 0)
        {
            pull->out_f = open_pull_out(opt2fn("-pf", nfile, fnm), pull, oenv,
                                        FALSE, Flags);
        }
    }
}
예제 #11
0
/* 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);
}
예제 #12
0
static FILE *open_pull_out(const char *fn,t_pull *pull,const output_env_t oenv, 
                           gmx_bool bCoord, unsigned long Flags)
{
    FILE *fp;
    int  nsets,g,m;
    char **setname,buf[10];
    
    if(Flags & MD_APPENDFILES)
    {
        fp = gmx_fio_fopen(fn,"a+");
    }
    else
    {
        fp = gmx_fio_fopen(fn,"w+");
        if (bCoord)
        {
            xvgr_header(fp,"Pull COM",  "Time (ps)","Position (nm)",
                        exvggtXNY,oenv);
        }
        else
        {
            xvgr_header(fp,"Pull force","Time (ps)","Force (kJ/mol/nm)",
                        exvggtXNY,oenv);
        }
        
        snew(setname,(1+pull->ngrp)*DIM);
        nsets = 0;
        for(g=0; g<1+pull->ngrp; g++)
        {
            if (pull->grp[g].nat > 0 &&
                (g > 0 || (bCoord && !PULL_CYL(pull))))
            {
                if (bCoord || pull->eGeom == epullgPOS)
                {
                    if (PULL_CYL(pull))
                    {
                        for(m=0; m<DIM; m++)
                        {
                            if (pull->dim[m])
                            {
                                sprintf(buf,"%d %s%c",g,"c",'X'+m);
                                setname[nsets] = strdup(buf);
                                nsets++;
                            }
                        }
                    }
                    for(m=0; m<DIM; m++)
                    {
                        if (pull->dim[m])
                        {
                            sprintf(buf,"%d %s%c",
                                    g,(bCoord && g > 0)?"d":"",'X'+m);
                            setname[nsets] = strdup(buf);
                            nsets++;
                        }
                    }
                }
                else
                {
                    sprintf(buf,"%d",g);
                    setname[nsets] = strdup(buf);
                    nsets++;
                }
            }
        }
        if (bCoord || nsets > 1)
        {
            xvgr_legend(fp,nsets,(const char**)setname,oenv);
        }
        for(g=0; g<nsets; g++)
        {
            sfree(setname[g]);
        }
        sfree(setname);
    }
    
    return fp;
}