Ejemplo n.º 1
0
static void pr_pull(FILE *fp,int indent,t_pull *pull)
{
  int g;

  PS("pull-geometry",EPULLGEOM(pull->eGeom));
  pr_ivec(fp,indent,"pull-dim",pull->dim,DIM,TRUE);
  PR("pull-r1",pull->cyl_r1);
  PR("pull-r0",pull->cyl_r0);
  PR("pull-constr-tol",pull->constr_tol);
  PI("pull-nstxout",pull->nstxout);
  PI("pull-nstfout",pull->nstfout);
  PI("pull-ngrp",pull->ngrp);
  for(g=0; g<pull->ngrp+1; g++)
    pr_pullgrp(fp,indent,g,&pull->grp[g]);
}
Ejemplo n.º 2
0
void make_pull_coords(pull_params_t *pull)
{
    int           c, d;
    t_pull_coord *pcrd;

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

        if (pcrd->group[0] < 0 || pcrd->group[0] >= pull->ngroup ||
            pcrd->group[1] < 0 || pcrd->group[1] >= pull->ngroup)
        {
            gmx_fatal(FARGS, "Pull group index in pull-coord%d-groups out of range, should be between %d and %d", c+1, 0, pull->ngroup+1);
        }

        if (pcrd->group[0] == pcrd->group[1])
        {
            gmx_fatal(FARGS, "Identical pull group indices in pull-coord%d-groups", c+1);
        }

        if (pcrd->eGeom == epullgCYL)
        {
            if (pull->group[pcrd->group[0]].nweight > 0)
            {
                gmx_fatal(FARGS, "Weights are not supported for the reference group with cylinder pulling");
            }
        }

        if (pcrd->eGeom != epullgDIST)
        {
            for (d = 0; d < DIM; d++)
            {
                if (pcrd->vec[d] != 0 && pcrd->dim[d] == 0)
                {
                    gmx_fatal(FARGS, "ERROR: pull-group%d-vec has non-zero %c-component while pull_dim for the %c-dimension is N\n", c+1, 'x'+d, 'x'+d);
                }
            }
        }

        if ((pcrd->eGeom == epullgDIR || pcrd->eGeom == epullgCYL) &&
            norm2(pcrd->vec) == 0)
        {
            gmx_fatal(FARGS, "pull-group%d-vec can not be zero with geometry %s",
                      c+1, EPULLGEOM(pcrd->eGeom));
        }
    }
}
Ejemplo n.º 3
0
static void process_pull_dim(char *dim_buf, ivec dim, const t_pull_coord *pcrd)
{
    int           ndim, d, nchar;
    char         *ptr, pulldim1[STRLEN];

    ptr  = dim_buf;
    ndim = 0;
    for (d = 0; d < DIM; d++)
    {
        if (sscanf(ptr, "%s%n", pulldim1, &nchar) != 1)
        {
            gmx_fatal(FARGS, "Less than 3 pull dimensions given in pull_dim: '%s'",
                      dim_buf);
        }

        if (gmx_strncasecmp(pulldim1, "N", 1) == 0)
        {
            dim[d] = 0;
        }
        else if (gmx_strncasecmp(pulldim1, "Y", 1) == 0)
        {
            dim[d] = 1;
            ndim++;
        }
        else
        {
            gmx_fatal(FARGS, "Please use Y(ES) or N(O) for pull_dim only (not %s)",
                      pulldim1);
        }
        ptr += nchar;
    }
    if (ndim == 0)
    {
        gmx_fatal(FARGS, "All entries in pull dim are N");
    }
    if ((pcrd->eGeom == epullgDIHEDRAL) && (ndim < 3))
    {
        gmx_fatal(FARGS, "Pull geometry dihedral is only useful with pull-dim = Y Y Y");
    }
    if ((pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgANGLEAXIS ) && (ndim < 2))
    {
        gmx_fatal(FARGS, "Pull geometry %s is only useful with pull-dim = Y for at least 2 dimensions",
                  EPULLGEOM(pcrd->eGeom));
    }
}
Ejemplo n.º 4
0
pull_t *set_pull_init(t_inputrec *ir, const gmx_mtop_t *mtop,
                      rvec *x, matrix box, real lambda,
                      warninp_t wi)
{
    pull_params_t *pull;
    pull_t        *pull_work;
    t_pbc          pbc;
    int            c;
    double         t_start;

    pull      = ir->pull;
    gmx::LocalAtomSetManager atomSets;
    pull_work = init_pull(nullptr, pull, ir, mtop, nullptr, &atomSets, lambda);
    auto                     mdAtoms = gmx::makeMDAtoms(nullptr, *mtop, *ir, false);
    auto                     md      = mdAtoms->mdatoms();
    atoms2md(mtop, ir, -1, nullptr, mtop->natoms, mdAtoms.get());
    if (ir->efep)
    {
        update_mdatoms(md, lambda);
    }

    set_pbc(&pbc, ir->ePBC, box);

    t_start = ir->init_t + ir->init_step*ir->delta_t;

    if (pull->bSetPbcRefToPrevStepCOM)
    {
        initPullComFromPrevStep(nullptr, pull_work, md, &pbc, x);
    }
    pull_calc_coms(nullptr, pull_work, md, &pbc, t_start, x, nullptr);

    for (int g = 0; g < pull->ngroup; g++)
    {
        bool groupObeysPbc =
            pullCheckPbcWithinGroup(*pull_work,
                                    gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec *>(x),
                                                           mtop->natoms),
                                    pbc, g, c_pullGroupSmallGroupThreshold);
        if (!groupObeysPbc)
        {
            char buf[STRLEN];
            if (pull->group[g].pbcatom_input == 0)
            {
                sprintf(buf, "When the maximum distance from a pull group reference atom to other atoms in the "
                        "group is larger than %g times half the box size a centrally placed "
                        "atom should be chosen as pbcatom. Pull group %d is larger than that and does not have "
                        "a specific atom selected as reference atom.", c_pullGroupSmallGroupThreshold, g);
                warning_error(wi, buf);
            }
            else if (!pull->bSetPbcRefToPrevStepCOM)
            {
                sprintf(buf, "The maximum distance from the chosen PBC atom (%d) of pull group %d to other "
                        "atoms in the group is larger than %g times half the box size. "
                        "Set the pull-pbc-ref-prev-step-com option to yes.", pull->group[g].pbcatom + 1,
                        g, c_pullGroupSmallGroupThreshold);
                warning_error(wi, buf);
            }
        }
        if (groupObeysPbc)
        {
            groupObeysPbc =
                pullCheckPbcWithinGroup(*pull_work,
                                        gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec *>(x),
                                                               mtop->natoms),
                                        pbc, g, c_pullGroupPbcMargin);
            if (!groupObeysPbc)
            {
                char buf[STRLEN];
                sprintf(buf,
                        "Pull group %d has atoms at a distance larger than %g times half the box size from the PBC atom (%d). "
                        "If atoms are or will more beyond half the box size from the PBC atom, the COM will be ill defined.",
                        g, c_pullGroupPbcMargin, pull->group[g].pbcatom + 1);
                set_warning_line(wi, nullptr, -1);
                warning(wi, buf);
            }
        }
    }

    fprintf(stderr, "Pull group  natoms  pbc atom  distance at start  reference at t=0\n");
    for (c = 0; c < pull->ncoord; c++)
    {
        t_pull_coord *pcrd;
        t_pull_group *pgrp0, *pgrp1;
        double        value;
        real          init = 0;

        pcrd  = &pull->coord[c];

        pgrp0 = &pull->group[pcrd->group[0]];
        pgrp1 = &pull->group[pcrd->group[1]];
        fprintf(stderr, "%8d  %8d  %8d\n",
                pcrd->group[0], pgrp0->nat, pgrp0->pbcatom+1);
        fprintf(stderr, "%8d  %8d  %8d ",
                pcrd->group[1], pgrp1->nat, pgrp1->pbcatom+1);

        if (pcrd->bStart)
        {
            init       = pcrd->init;
            pcrd->init = 0;
        }

        value  = get_pull_coord_value(pull_work, c, &pbc);

        value *= pull_conversion_factor_internal2userinput(pcrd);
        fprintf(stderr, " %10.3f %s", value, pull_coordinate_units(pcrd));

        if (pcrd->bStart)
        {
            pcrd->init = value + init;
        }

        if (pcrd->eGeom == epullgDIST)
        {
            if (pcrd->init < 0)
            {
                gmx_fatal(FARGS, "The initial pull distance (%g) needs to be non-negative with geometry %s. If you want a signed distance, use geometry %s instead.",
                          pcrd->init, EPULLGEOM(pcrd->eGeom), EPULLGEOM(epullgDIR));
            }

            /* TODO: With a positive init but a negative rate things could still
             * go wrong, but it might be fine if you don't pull too far.
             * We should give a warning or note when there is only one pull dim
             * active, since that is usually the problematic case when you should
             * be using direction. We will do this later, since an already planned
             * generalization of the pull code makes pull dim available here.
             */
        }
        else if (pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgANGLEAXIS)
        {
            if (pcrd->init < 0 || pcrd->init > 180)
            {
                gmx_fatal(FARGS,  "The initial pull reference angle (%g) is outside of the allowed range [0, 180] degrees.", pcrd->init);
            }
        }
        else if (pcrd->eGeom == epullgDIHEDRAL)
        {
            if (pcrd->init < -180 || pcrd->init > 180)
            {
                gmx_fatal(FARGS,  "The initial pull reference angle (%g) is outside of the allowed range [-180, 180] degrees.",
                          pcrd->init);
            }
        }


        fprintf(stderr, "     %10.3f %s\n", pcrd->init, pull_coordinate_units(pcrd));
    }

    return pull_work;
}
Ejemplo n.º 5
0
static void init_pull_coord(t_pull_coord *pcrd, int coord_index_for_output,
                            char *dim_buf,
                            const char *origin_buf, const char *vec_buf,
                            warninp_t wi)
{
    int    m;
    dvec   origin, vec;
    char   buf[STRLEN];

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

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

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

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

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

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

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

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

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

        /* Normalize the direction vector */
        dsvmul(1/dnorm(vec), vec, vec);
    }
    else /* This case is for are all the geometries where the pull vector is not used */
    {
        if (dnorm2(vec) > 0)
        {
            sprintf(buf, "A pull vector is given (%g  %g  %g) but will not be used with geometry %s. If you really want to use this "
                    "vector, consider using geometry %s instead.",
                    vec[0], vec[1], vec[2], EPULLGEOM(pcrd->eGeom),
                    pcrd->eGeom == epullgANGLE ? EPULLGEOM(epullgANGLEAXIS) : EPULLGEOM(epullgDIR));
            warning(wi, buf);
        }
    }
    for (m = 0; m < DIM; m++)
    {
        pcrd->origin[m] = origin[m];
        pcrd->vec[m]    = vec[m];
    }
}
Ejemplo n.º 6
0
/*! \brief
 * Read parameters of an AWH bias dimension.
 *
 * \param[in,out] ninp_p     Number of read input file entries.
 * \param[in,out] inp_p      Input file entries.
 * \param[in] prefix         Prefix for dimension parameters.
 * \param[in,out] dimParams  AWH dimensional parameters.
 * \param[in] pull_params    Pull parameters.
 * \param[in,out] wi         Struct for bookeeping warnings.
 * \param[in] bComment       True if comments should be printed.
 */
static void readDimParams(int *ninp_p, t_inpfile **inp_p, const char *prefix,
                          AwhDimParams *dimParams, const pull_params_t *pull_params,
                          warninp_t wi, bool bComment)
{
    char       warningmsg[STRLEN];

    int        ninp = *ninp_p;
    t_inpfile *inp  = *inp_p;

    if (bComment)
    {
        CTYPE("The provider of the reaction coordinate, currently only pull is supported");
    }
    char opt[STRLEN];
    sprintf(opt, "%s-coord-provider", prefix);
    EETYPE(opt, dimParams->eCoordProvider, eawhcoordprovider_names);

    if (bComment)
    {
        CTYPE("The coordinate index for this dimension");
    }
    sprintf(opt, "%s-coord-index", prefix);
    int coordIndexInput;
    ITYPE(opt, coordIndexInput, 1);
    if (coordIndexInput <  1)
    {
        gmx_fatal(FARGS, "Failed to read a valid coordinate index for %s. "
                  "Note that the pull coordinate indexing starts at 1.", opt);
    }

    /* The pull coordinate indices start at 1 in the input file, at 0 internally */
    dimParams->coordIndex = coordIndexInput - 1;

    /* The pull settings need to be consistent with the AWH settings */
    if (!(pull_params->coord[dimParams->coordIndex].eType == epullEXTERNAL) )
    {
        gmx_fatal(FARGS, "AWH biasing can only be  applied to pull type %s",
                  EPULLTYPE(epullEXTERNAL));
    }

    if (dimParams->coordIndex >= pull_params->ncoord)
    {
        gmx_fatal(FARGS, "The given AWH coordinate index (%d) is larger than the number of pull coordinates (%d)",
                  coordIndexInput, pull_params->ncoord);
    }
    if (pull_params->coord[dimParams->coordIndex].rate != 0)
    {
        sprintf(warningmsg, "Setting pull-coord%d-rate (%g) is incompatible with AWH biasing this coordinate", coordIndexInput, pull_params->coord[dimParams->coordIndex].rate);
        warning_error(wi, warningmsg);
    }

    /* Grid params for each axis */
    int eGeom = pull_params->coord[dimParams->coordIndex].eGeom;

    if (bComment)
    {
        CTYPE("Start and end values for each coordinate dimension");
    }

    sprintf(opt, "%s-start", prefix);
    RTYPE(opt, dimParams->origin, 0.);

    sprintf(opt, "%s-end", prefix);
    RTYPE(opt, dimParams->end, 0.);

    if (gmx_within_tol(dimParams->end - dimParams->origin, 0, GMX_REAL_EPS))
    {
        sprintf(warningmsg, "The given interval length given by %s-start (%g) and %s-end (%g) is zero. "
                "This will result in only one point along this axis in the coordinate value grid.",
                prefix, dimParams->origin, prefix, dimParams->end);
        warning(wi, warningmsg);
    }
    /* Check that the requested interval is in allowed range */
    if (eGeom == epullgDIST)
    {
        if (dimParams->origin < 0 || dimParams->end < 0)
        {
            gmx_fatal(FARGS, "%s-start (%g) or %s-end (%g) set to a negative value. With pull geometry distance coordinate values are non-negative. "
                      "Perhaps you want to use geometry %s instead?",
                      prefix, dimParams->origin, prefix, dimParams->end, EPULLGEOM(epullgDIR));
        }
    }
    else if (eGeom == epullgANGLE || eGeom == epullgANGLEAXIS)
    {
        if (dimParams->origin < 0 || dimParams->end > 180)
        {
            gmx_fatal(FARGS, "%s-start (%g) and %s-end (%g) are outside of the allowed range 0 to 180 deg for pull geometries %s and %s ",
                      prefix, dimParams->origin, prefix, dimParams->end, EPULLGEOM(epullgANGLE), EPULLGEOM(epullgANGLEAXIS));
        }
    }
    else if (eGeom == epullgDIHEDRAL)
    {
        if (dimParams->origin < -180 || dimParams->end > 180)
        {
            gmx_fatal(FARGS, "%s-start (%g) and %s-end (%g) are outside of the allowed range -180 to 180 deg for pull geometry %s. ",
                      prefix, dimParams->origin, prefix, dimParams->end, EPULLGEOM(epullgDIHEDRAL));
        }
    }

    if (bComment)
    {
        CTYPE("The force constant for this coordinate (kJ/mol/nm^2 or kJ/mol/rad^2)");
    }
    sprintf(opt, "%s-force-constant", prefix);
    RTYPE(opt, dimParams->forceConstant, 0);
    if (dimParams->forceConstant <= 0)
    {
        warning_error(wi, "The force AWH bias force constant should be > 0");
    }

    if (bComment)
    {
        CTYPE("Estimated diffusion constant (nm^2/ps or rad^2/ps)");
    }
    sprintf(opt, "%s-diffusion", prefix);
    RTYPE(opt, dimParams->diffusion, 0);

    if (dimParams->diffusion <= 0)
    {
        const double diffusion_default = 1e-5;
        sprintf(warningmsg, "%s not explicitly set by user."
                " You can choose to use a default value (%g nm^2/ps or rad^2/ps) but this may very well be non-optimal for your system!",
                opt, diffusion_default);
        warning(wi, warningmsg);
        dimParams->diffusion = diffusion_default;
    }

    if (bComment)
    {
        CTYPE("Diameter that needs to be sampled around a point before it is considered covered.");
    }
    sprintf(opt, "%s-cover-diameter", prefix);
    RTYPE(opt, dimParams->coverDiameter, 0);

    if (dimParams->coverDiameter < 0)
    {
        gmx_fatal(FARGS, "%s (%g) cannot be negative.",
                  opt, dimParams->coverDiameter);
    }

    *ninp_p   = ninp;
    *inp_p    = inp;
}
Ejemplo n.º 7
0
/*! \brief
 * Gets the period of a pull coordinate.
 *
 * \param[in] pull_params      Pull parameters.
 * \param[in] coord_ind        Pull coordinate index.
 * \param[in] box              Box vectors.
 * \returns the period (or 0 if not periodic).
 */
static double get_pull_coord_period(const pull_params_t *pull_params,
                                    int                  coord_ind,
                                    const matrix         box)
{
    double        period;
    t_pull_coord *pcrd_params = &pull_params->coord[coord_ind];

    if (pcrd_params->eGeom == epullgDIRPBC)
    {
        /* For direction periodic, we need the pull vector to be one of the box vectors
           (or more generally I guess it could be an integer combination of boxvectors).
           This boxvector should to be orthogonal to the (periodic) plane spanned by the other two box vectors.
           Here we assume that the pull vector is either x, y or z.
         * E.g. for pull vec = (1, 0, 0) the box vector tensor should look like:
         * | x 0 0 |
         * | 0 a c |
         * | 0 b d |
         *
           The period is then given by the box length x.

           Note: we make these checks here for AWH and not in pull because we allow pull to be more general.
         */
        int m_pullvec = -1, count_nonzeros = 0;

        /* Check that pull vec has only one component and which component it is. This component gives the relevant box vector */
        for (int m = 0; m < DIM; m++)
        {
            if (pcrd_params->vec[m] != 0)
            {
                m_pullvec = m;
                count_nonzeros++;
            }
        }
        if (count_nonzeros != 1)
        {
            gmx_fatal(FARGS, "For AWH biasing pull coordinate %d with pull geometry %s, the pull vector needs to be parallel to "
                      "a box vector that is parallel to either the x, y or z axis and is orthogonal to the other box vectors.",
                      coord_ind + 1, EPULLGEOM(epullgDIRPBC));
        }

        /* Check that there is a box vec parallel to pull vec and that this boxvec is orthogonal to the other box vectors */
        for (int m = 0; m < DIM; m++)
        {
            for (int n = 0; n < DIM; n++)
            {
                if ((n != m) && (n == m_pullvec || m == m_pullvec) && box[m][n] > 0)
                {
                    gmx_fatal(FARGS, "For AWH biasing pull coordinate %d with pull geometry %s, there needs to be a box vector parallel to the pull vector that is "
                              "orthogonal to the other box vectors.",
                              coord_ind + 1, EPULLGEOM(epullgDIRPBC));
                }
            }
        }

        /* If this box vector only has one component as we assumed the norm should be equal to the absolute value of that component */
        period = static_cast<double>(norm(box[m_pullvec]));
    }
    else if (pcrd_params->eGeom == epullgDIHEDRAL)
    {
        /* The dihedral angle is periodic in -180 to 180 deg */
        period = 360;
    }
    else
    {
        period = 0;
    }

    return period;
}
Ejemplo n.º 8
0
static void init_pull_coord(t_pull_coord *pcrd,
                            char *dim_buf,
                            const char *origin_buf, const char *vec_buf,
                            warninp_t wi)
{
    int    m;
    dvec   origin, vec;
    char   buf[STRLEN];

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

    process_pull_dim(dim_buf, pcrd->dim);

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

    /* Check and set the pull vector */
    clear_dvec(vec);
    if (pcrd->eGeom == epullgDIST)
    {
        if (pcrd->init < 0)
        {
            sprintf(buf, "The initial pull distance is negative with geometry %s, while a distance can not be negative. Use geometry %s instead.",
                    EPULLGEOM(pcrd->eGeom), EPULLGEOM(epullgDIR));
            warning_error(wi, buf);
        }
        /* TODO: With a positive init but a negative rate things could still
         * go wrong, but it might be fine if you don't pull too far.
         * We should give a warning or note when there is only one pull dim
         * active, since that is usually the problematic case when you should
         * be using direction. We will do this later, since an already planned
         * generalization of the pull code makes pull dim available here.
         */
    }
    else if (pcrd->eGeom != epullgDIRRELATIVE)
    {
        string2dvec(vec_buf, vec);
        if (dnorm2(vec) == 0)
        {
            gmx_fatal(FARGS, "With pull geometry %s the pull vector can not be 0,0,0",
                      epullg_names[pcrd->eGeom]);
        }
        if (pcrd->eGeom == epullgDIR || pcrd->eGeom == epullgCYL)
        {
            /* Normalize the direction vector */
            dsvmul(1/dnorm(vec), vec, vec);
        }
    }
    for (m = 0; m < DIM; m++)
    {
        pcrd->origin[m] = origin[m];
        pcrd->vec[m]    = vec[m];
    }
}
Ejemplo n.º 9
0
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);
        }
    }
}
Ejemplo n.º 10
0
void make_pull_groups(t_pull *pull, char **pgnames, t_blocka *grps, char **gnames)
{
    int        d, nchar, g, ig = -1, i;
    char      *ptr, pulldim1[STRLEN];
    t_pullgrp *pgrp;

    ptr = pulldim;
    i   = 0;
    for (d = 0; d < DIM; d++)
    {
        if (sscanf(ptr, "%s%n", pulldim1, &nchar) != 1)
        {
            gmx_fatal(FARGS, "Less than 3 pull dimensions given in pull_dim: '%s'",
                      pulldim);
        }

        if (gmx_strncasecmp(pulldim1, "N", 1) == 0)
        {
            pull->dim[d] = 0;
        }
        else if (gmx_strncasecmp(pulldim1, "Y", 1) == 0)
        {
            pull->dim[d] = 1;
            i++;
        }
        else
        {
            gmx_fatal(FARGS, "Please use Y(ES) or N(O) for pull_dim only (not %s)",
                      pulldim1);
        }
        ptr += nchar;
    }
    if (i == 0)
    {
        gmx_fatal(FARGS, "All entries in pull_dim are N");
    }

    for (g = 0; g < pull->ngrp+1; g++)
    {
        pgrp = &pull->grp[g];
        if (g == 0 && strcmp(pgnames[g], "") == 0)
        {
            pgrp->nat = 0;
        }
        else
        {
            ig        = search_string(pgnames[g], grps->nr, gnames);
            pgrp->nat = grps->index[ig+1] - grps->index[ig];
        }
        if (pgrp->nat > 0)
        {
            fprintf(stderr, "Pull group %d '%s' has %d atoms\n",
                    g, pgnames[g], pgrp->nat);
            snew(pgrp->ind, pgrp->nat);
            for (i = 0; i < pgrp->nat; i++)
            {
                pgrp->ind[i] = grps->a[grps->index[ig]+i];
            }

            if (pull->eGeom == epullgCYL && g == 0 && pgrp->nweight > 0)
            {
                gmx_fatal(FARGS, "Weights are not supported for the reference group with cylinder pulling");
            }
            if (pgrp->nweight > 0 && pgrp->nweight != pgrp->nat)
            {
                gmx_fatal(FARGS, "Number of weights (%d) for pull group %d '%s' does not match the number of atoms (%d)",
                          pgrp->nweight, g, pgnames[g], pgrp->nat);
            }

            if (pgrp->nat == 1)
            {
                /* No pbc is required for this group */
                pgrp->pbcatom = -1;
            }
            else
            {
                if (pgrp->pbcatom > 0)
                {
                    pgrp->pbcatom -= 1;
                }
                else if (pgrp->pbcatom == 0)
                {
                    pgrp->pbcatom = pgrp->ind[(pgrp->nat-1)/2];
                }
                else
                {
                    /* Use cosine weighting */
                    pgrp->pbcatom = -1;
                }
            }

            if (g > 0 && pull->eGeom != epullgDIST)
            {
                for (d = 0; d < DIM; d++)
                {
                    if (pgrp->vec[d] != 0 && pull->dim[d] == 0)
                    {
                        gmx_fatal(FARGS, "ERROR: pull_vec%d has non-zero %c-component while pull_dim in N\n", g, 'x'+d);
                    }
                }
            }

            if ((pull->eGeom == epullgDIR || pull->eGeom == epullgCYL) &&
                g > 0 && norm2(pgrp->vec) == 0)
            {
                gmx_fatal(FARGS, "pull_vec%d can not be zero with geometry %s",
                          g, EPULLGEOM(pull->eGeom));
            }
            if ((pull->eGeom == epullgPOS) && pgrp->rate != 0 &&
                g > 0 && norm2(pgrp->vec) == 0)
            {
                gmx_fatal(FARGS, "pull_vec%d can not be zero with geometry %s and non-zero rate",
                          g, EPULLGEOM(pull->eGeom));
            }
        }
        else
        {
            if (g == 0)
            {
                if (pull->eGeom == epullgCYL)
                {
                    gmx_fatal(FARGS, "Absolute reference groups are not supported with geometry %s", EPULLGEOM(pull->eGeom));
                }
            }
            else
            {
                gmx_fatal(FARGS, "Pull group %d '%s' is empty", g, pgnames[g]);
            }
            pgrp->pbcatom = -1;
        }
    }
}
Ejemplo n.º 11
0
void make_pull_coords(t_pull *pull)
{
    int           ndim, d, nchar, c;
    char         *ptr, pulldim1[STRLEN];
    t_pull_coord *pcrd;

    ptr  = pulldim;
    ndim = 0;
    for (d = 0; d < DIM; d++)
    {
        if (sscanf(ptr, "%s%n", pulldim1, &nchar) != 1)
        {
            gmx_fatal(FARGS, "Less than 3 pull dimensions given in pull_dim: '%s'",
                      pulldim);
        }

        if (gmx_strncasecmp(pulldim1, "N", 1) == 0)
        {
            pull->dim[d] = 0;
        }
        else if (gmx_strncasecmp(pulldim1, "Y", 1) == 0)
        {
            pull->dim[d] = 1;
            ndim++;
        }
        else
        {
            gmx_fatal(FARGS, "Please use Y(ES) or N(O) for pull_dim only (not %s)",
                      pulldim1);
        }
        ptr += nchar;
    }
    if (ndim == 0)
    {
        gmx_fatal(FARGS, "All entries in pull_dim are N");
    }

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

        if (pcrd->group[0] < 0 || pcrd->group[0] >= pull->ngroup ||
            pcrd->group[1] < 0 || pcrd->group[1] >= pull->ngroup)
        {
            gmx_fatal(FARGS, "Pull group index in pull-coord%d-groups out of range, should be between %d and %d", c+1, 0, pull->ngroup+1);
        }

        if (pcrd->group[0] == pcrd->group[1])
        {
            gmx_fatal(FARGS, "Identical pull group indices in pull-coord%d-groups", c+1);
        }

        if (pull->eGeom == epullgCYL && pcrd->group[0] != 1)
        {
            gmx_fatal(FARGS, "With pull geometry %s, the first pull group should always be 1", EPULLGEOM(pull->eGeom));
        }

        if (pull->eGeom != epullgDIST)
        {
            for (d = 0; d < DIM; d++)
            {
                if (pcrd->vec[d] != 0 && pull->dim[d] == 0)
                {
                    gmx_fatal(FARGS, "ERROR: pull-group%d-vec has non-zero %c-component while pull_dim for the %c-dimension is N\n", c+1, 'x'+d, 'x'+d);
                }
            }
        }

        if ((pull->eGeom == epullgDIR || pull->eGeom == epullgCYL) &&
            norm2(pcrd->vec) == 0)
        {
            gmx_fatal(FARGS, "pull-group%d-vec can not be zero with geometry %s",
                      c+1, EPULLGEOM(pull->eGeom));
        }
    }
}
Ejemplo n.º 12
0
pull_t *set_pull_init(t_inputrec *ir, const gmx_mtop_t *mtop,
                      rvec *x, matrix box, real lambda,
                      const gmx_output_env_t *oenv)
{
    pull_params_t *pull;
    pull_t        *pull_work;
    t_mdatoms     *md;
    t_pbc          pbc;
    int            c;
    double         t_start;

    pull      = ir->pull;
    pull_work = init_pull(NULL, pull, ir, 0, NULL, mtop, NULL, oenv, lambda, FALSE, 0);
    md        = init_mdatoms(NULL, mtop, ir->efep);
    atoms2md(mtop, ir, -1, NULL, mtop->natoms, md);
    if (ir->efep)
    {
        update_mdatoms(md, lambda);
    }

    set_pbc(&pbc, ir->ePBC, box);

    t_start = ir->init_t + ir->init_step*ir->delta_t;

    pull_calc_coms(NULL, pull_work, md, &pbc, t_start, x, NULL);

    fprintf(stderr, "Pull group  natoms  pbc atom  distance at start  reference at t=0\n");
    for (c = 0; c < pull->ncoord; c++)
    {
        t_pull_coord *pcrd;
        t_pull_group *pgrp0, *pgrp1;
        double        value;
        real          init = 0;

        pcrd  = &pull->coord[c];

        pgrp0 = &pull->group[pcrd->group[0]];
        pgrp1 = &pull->group[pcrd->group[1]];
        fprintf(stderr, "%8d  %8d  %8d\n",
                pcrd->group[0], pgrp0->nat, pgrp0->pbcatom+1);
        fprintf(stderr, "%8d  %8d  %8d ",
                pcrd->group[1], pgrp1->nat, pgrp1->pbcatom+1);

        if (pcrd->bStart)
        {
            init       = pcrd->init;
            pcrd->init = 0;
        }

        get_pull_coord_value(pull_work, c, &pbc, &value);

        value *= pull_conversion_factor_internal2userinput(pcrd);
        fprintf(stderr, " %10.3f %s", value, pull_coordinate_units(pcrd));

        if (pcrd->bStart)
        {
            pcrd->init = value + init;
        }

        if (pcrd->eGeom == epullgDIST)
        {
            if (pcrd->init < 0)
            {
                gmx_fatal(FARGS, "The initial pull distance (%g) needs to be non-negative with geometry %s. If you want a signed distance, use geometry %s instead.",
                          pcrd->init, EPULLGEOM(pcrd->eGeom), EPULLGEOM(epullgDIR));
            }

            /* TODO: With a positive init but a negative rate things could still
             * go wrong, but it might be fine if you don't pull too far.
             * We should give a warning or note when there is only one pull dim
             * active, since that is usually the problematic case when you should
             * be using direction. We will do this later, since an already planned
             * generalization of the pull code makes pull dim available here.
             */
        }
        else if (pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgANGLEAXIS)
        {
            if (pcrd->init < 0 || pcrd->init > 180)
            {
                gmx_fatal(FARGS,  "The initial pull reference angle (%g) is outside of the allowed range [0, 180] degrees.", pcrd->init);
            }
        }
        else if (pcrd->eGeom == epullgDIHEDRAL)
        {
            if (pcrd->init < -180 || pcrd->init > 180)
            {
                gmx_fatal(FARGS,  "The initial pull reference angle (%g) is outside of the allowed range [-180, 180] degrees.",
                          pcrd->init);
            }
        }


        fprintf(stderr, "     %10.3f %s\n", pcrd->init, pull_coordinate_units(pcrd));
    }

    return pull_work;
}