2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
39 * \brief Defines the high-level constraint code.
41 * \author Berk Hess <hess@kth.se>
42 * \author Mark Abraham <mark.j.abraham@gmail.com>
43 * \ingroup module_mdlib
55 #include "gromacs/domdec/domdec.h"
56 #include "gromacs/domdec/domdec_struct.h"
57 #include "gromacs/essentialdynamics/edsam.h"
58 #include "gromacs/fileio/confio.h"
59 #include "gromacs/fileio/gmxfio.h"
60 #include "gromacs/fileio/pdbio.h"
61 #include "gromacs/gmxlib/nrnb.h"
62 #include "gromacs/math/arrayrefwithpadding.h"
63 #include "gromacs/math/utilities.h"
64 #include "gromacs/math/vec.h"
65 #include "gromacs/mdlib/gmx_omp_nthreads.h"
66 #include "gromacs/mdlib/lincs.h"
67 #include "gromacs/mdlib/settle.h"
68 #include "gromacs/mdlib/shake.h"
69 #include "gromacs/mdtypes/commrec.h"
70 #include "gromacs/mdtypes/inputrec.h"
71 #include "gromacs/mdtypes/md_enums.h"
72 #include "gromacs/mdtypes/state.h"
73 #include "gromacs/pbcutil/pbc.h"
74 #include "gromacs/pulling/pull.h"
75 #include "gromacs/timing/wallcycle.h"
76 #include "gromacs/topology/ifunc.h"
77 #include "gromacs/topology/mtop_lookup.h"
78 #include "gromacs/topology/mtop_util.h"
79 #include "gromacs/utility/arrayref.h"
80 #include "gromacs/utility/exceptions.h"
81 #include "gromacs/utility/fatalerror.h"
82 #include "gromacs/utility/gmxassert.h"
83 #include "gromacs/utility/listoflists.h"
84 #include "gromacs/utility/pleasecite.h"
85 #include "gromacs/utility/txtdump.h"
90 /* \brief Impl class for Constraints
92 * \todo Members like md, idef are valid only for the lifetime of a
93 * domain, which would be good to make clearer in the structure of the
94 * code. It should not be possible to call apply() if setConstraints()
95 * has not been called. For example, this could be achieved if
96 * setConstraints returned a valid object with such a method. That
97 * still requires that we manage the lifetime of that object
98 * correctly, however. */
99 class Constraints::Impl
102 Impl(const gmx_mtop_t& mtop_p,
103 const t_inputrec& ir_p,
106 const t_commrec* cr_p,
107 bool useUpdateGroups,
108 const gmx_multisim_t* ms,
110 gmx_wallcycle* wcycle_p,
111 bool pbcHandlingRequired,
112 ObservablesReducerBuilder* observablesReducerBuilder,
116 void setConstraints(gmx_localtop_t* top,
119 gmx::ArrayRef<const real> masses,
120 gmx::ArrayRef<const real> inverseMasses,
121 bool hasMassPerturbedAtoms,
123 gmx::ArrayRef<const unsigned short> cFREEZE);
124 bool apply(bool bLog,
129 ArrayRefWithPadding<RVec> x,
130 ArrayRefWithPadding<RVec> xprime,
131 ArrayRef<RVec> min_proj,
135 ArrayRefWithPadding<RVec> v,
137 tensor constraintsVirial,
138 ConstraintVariable econq);
139 //! The total number of constraints.
141 //! The number of flexible constraints.
143 //! A list of atoms to constraints for each moleculetype.
144 std::vector<ListOfLists<int>> at2con_mt;
145 //! A list of atoms to settles for each moleculetype
146 std::vector<std::vector<int>> at2settle_mt;
148 Lincs* lincsd = nullptr; // TODO this should become a unique_ptr
150 std::unique_ptr<shakedata> shaked;
152 std::unique_ptr<SettleData> settled;
153 //! The maximum number of warnings.
155 //! The number of warnings for LINCS.
156 int warncount_lincs = 0;
157 //! The number of warnings for SETTLE.
158 int warncount_settle = 0;
159 //! The essential dynamics data.
160 gmx_edsam* ed = nullptr;
162 //! Thread-local virial contribution.
163 tensor* threadConstraintsVirial = { nullptr };
164 //! Did a settle error occur?
165 bool* bSettleErrorHasOccurred = nullptr;
167 //! Pointer to the global topology - only used for printing warnings.
168 const gmx_mtop_t& mtop;
169 //! Parameters for the interactions in this domain.
170 const InteractionDefinitions* idef = nullptr;
171 //! Total number of atoms.
173 //! Number of local atoms.
174 int numHomeAtoms_ = 0;
176 gmx::ArrayRef<const real> masses_;
178 gmx::ArrayRef<const real> inverseMasses_;
179 //! If there are atoms with perturbed mass (for FEP).
180 bool hasMassPerturbedAtoms_;
181 //! FEP lambda value.
183 //! Freeze groups data
184 gmx::ArrayRef<const unsigned short> cFREEZE_;
185 //! Whether we need to do pbc for handling bonds.
186 bool pbcHandlingRequired_ = false;
190 //! Communication support.
191 const t_commrec* cr = nullptr;
192 //! Multi-sim support.
193 const gmx_multisim_t* ms = nullptr;
194 //! Pulling code object, if any.
195 pull_t* pull_work = nullptr;
196 /*!\brief Input options.
198 * \todo Replace with IMdpOptions */
199 const t_inputrec& ir;
200 //! Flop counting support.
201 t_nrnb* nrnb = nullptr;
202 //! Tracks wallcycle usage.
203 gmx_wallcycle* wcycle;
206 Constraints::~Constraints() = default;
208 int Constraints::numFlexibleConstraints() const
210 return impl_->nflexcon;
213 bool Constraints::havePerturbedConstraints() const
215 const gmx_ffparams_t& ffparams = impl_->mtop.ffparams;
217 for (size_t i = 0; i < ffparams.functype.size(); i++)
219 if ((ffparams.functype[i] == F_CONSTR || ffparams.functype[i] == F_CONSTRNC)
220 && ffparams.iparams[i].constr.dA != ffparams.iparams[i].constr.dB)
229 //! Clears constraint quantities for atoms in nonlocal region.
230 static void clear_constraint_quantity_nonlocal(const gmx_domdec_t& dd, ArrayRef<RVec> q)
232 int nonlocal_at_start, nonlocal_at_end;
234 dd_get_constraint_range(dd, &nonlocal_at_start, &nonlocal_at_end);
236 for (int at = nonlocal_at_start; at < nonlocal_at_end; at++)
242 void too_many_constraint_warnings(ConstraintAlgorithm eConstrAlg, int warncount)
245 "Too many %s warnings (%d)\n"
246 "If you know what you are doing you can %s"
247 "set the environment variable GMX_MAXCONSTRWARN to -1,\n"
248 "but normally it is better to fix the problem",
249 (eConstrAlg == ConstraintAlgorithm::Lincs) ? "LINCS" : "SETTLE",
251 (eConstrAlg == ConstraintAlgorithm::Lincs)
252 ? "adjust the lincs warning threshold in your mdp file\nor "
256 //! Writes out coordinates.
257 static void write_constr_pdb(const char* fn,
259 const gmx_mtop_t& mtop,
263 ArrayRef<const RVec> x,
268 int dd_ac0 = 0, dd_ac1 = 0, i, ii, resnr;
270 const char * anm, *resnm;
273 if (haveDDAtomOrdering(*cr))
276 dd_get_constraint_range(*dd, &dd_ac0, &dd_ac1);
283 sprintf(fname, "%s_n%d.pdb", fn, cr->sim_nodeid);
287 sprintf(fname, "%s.pdb", fn);
290 out = gmx_fio_fopen(fname, "w");
292 fprintf(out, "TITLE %s\n", title);
293 gmx_write_pdb_box(out, PbcType::Unset, box);
295 for (i = start; i < start + homenr; i++)
299 if (i >= dd_numHomeAtoms(*dd) && i < dd_ac0)
303 ii = dd->globalAtomIndices[i];
309 mtopGetAtomAndResidueName(mtop, ii, &molb, &anm, &resnr, &resnm, nullptr);
310 gmx_fprintf_pdb_atomline(out,
326 fprintf(out, "TER\n");
331 //! Writes out domain contents to help diagnose crashes.
332 static void dump_confs(FILE* log,
334 const gmx_mtop_t& mtop,
338 ArrayRef<const RVec> x,
339 ArrayRef<const RVec> xprime,
342 char buf[STRLEN], buf2[22];
344 char* env = getenv("GMX_SUPPRESS_DUMP");
350 sprintf(buf, "step%sb", gmx_step_str(step, buf2));
351 write_constr_pdb(buf, "initial coordinates", mtop, start, homenr, cr, x, box);
352 sprintf(buf, "step%sc", gmx_step_str(step, buf2));
353 write_constr_pdb(buf, "coordinates after constraining", mtop, start, homenr, cr, xprime, box);
356 fprintf(log, "Wrote pdb files with previous and current coordinates\n");
358 fprintf(stderr, "Wrote pdb files with previous and current coordinates\n");
361 bool Constraints::apply(bool bLog,
366 ArrayRefWithPadding<RVec> x,
367 ArrayRefWithPadding<RVec> xprime,
368 ArrayRef<RVec> min_proj,
372 ArrayRefWithPadding<RVec> v,
374 tensor constraintsVirial,
375 ConstraintVariable econq)
377 return impl_->apply(bLog,
394 bool Constraints::Impl::apply(bool bLog,
399 ArrayRefWithPadding<RVec> x,
400 ArrayRefWithPadding<RVec> xprime,
401 ArrayRef<RVec> min_proj,
405 ArrayRefWithPadding<RVec> v,
407 tensor constraintsVirial,
408 ConstraintVariable econq)
413 real invdt, vir_fac = 0, t;
415 t_pbc pbc, *pbc_null;
419 wallcycle_start(wcycle, WallCycleCounter::Constr);
421 if (econq == ConstraintVariable::ForceDispl && !EI_ENERGY_MINIMIZATION(ir.eI))
424 "constrain called for forces displacements while not doing energy minimization, "
425 "can not do this while the LINCS and SETTLE constraint connection matrices are "
434 scaled_delta_t = step_scaling * ir.delta_t;
436 /* Prepare time step for use in constraint implementations, and
437 avoid generating inf when ir.delta_t = 0. */
444 invdt = 1.0 / scaled_delta_t;
447 if (ir.efep != FreeEnergyPerturbationType::No && EI_DYNAMICS(ir.eI))
449 /* Set the constraint lengths for the step at which this configuration
450 * is meant to be. The invmasses should not be changed.
452 lambda += delta_step * ir.fepvals->delta_lambda;
457 clear_mat(constraintsVirial);
459 const InteractionList& settle = idef->il[F_SETTLE];
460 nsettle = settle.size() / (1 + NRAL(F_SETTLE));
464 nth = gmx_omp_nthreads_get(ModuleMultiThread::Settle);
471 /* We do not need full pbc when constraints do not cross update groups
472 * i.e. when dd->constraint_comm==NULL.
473 * Note that PBC for constraints is different from PBC for bondeds.
474 * For constraints there is both forward and backward communication.
476 if (ir.pbcType != PbcType::No && (cr->dd || pbcHandlingRequired_)
477 && !(cr->dd && cr->dd->constraint_comm == nullptr))
479 /* With pbc=screw the screw has been changed to a shift
480 * by the constraint coordinate communication routine,
481 * so that here we can use normal pbc.
483 pbc_null = set_pbc_dd(
484 &pbc, ir.pbcType, haveDDAtomOrdering(*cr) ? cr->dd->numCells : nullptr, FALSE, box);
491 /* Communicate the coordinates required for the non-local constraints
492 * for LINCS and/or SETTLE.
494 if (havePPDomainDecomposition(cr))
496 dd_move_x_constraints(cr->dd,
498 x.unpaddedArrayRef(),
499 xprime.unpaddedArrayRef(),
500 econq == ConstraintVariable::Positions);
504 /* We need to initialize the non-local components of v.
505 * We never actually use these values, but we do increment them,
506 * so we should avoid uninitialized variables and overflows.
508 clear_constraint_quantity_nonlocal(*cr->dd, v.unpaddedArrayRef());
512 if (lincsd != nullptr)
514 bOK = constrain_lincs(bLog || bEner,
526 hasMassPerturbedAtoms_,
530 v.unpaddedArrayRef(),
537 if (!bOK && maxwarn < INT_MAX)
542 "Constraint error in algorithm %s at step %s\n",
543 enumValueToString(ConstraintAlgorithm::Lincs),
544 gmx_step_str(step, buf));
550 if (shaked != nullptr)
552 bOK = constrain_shake(log,
557 x.unpaddedArrayRef(),
558 xprime.unpaddedArrayRef(),
565 v.unpaddedArrayRef(),
571 if (!bOK && maxwarn < INT_MAX)
576 "Constraint error in algorithm %s at step %s\n",
577 enumValueToString(ConstraintAlgorithm::Shake),
578 gmx_step_str(step, buf));
586 bool bSettleErrorHasOccurred0 = false;
590 case ConstraintVariable::Positions:
591 #pragma omp parallel for num_threads(nth) schedule(static)
592 for (int th = 0; th < nth; th++)
598 clear_mat(threadConstraintsVirial[th]);
610 th == 0 ? constraintsVirial : threadConstraintsVirial[th],
611 th == 0 ? &bSettleErrorHasOccurred0 : &bSettleErrorHasOccurred[th]);
613 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
615 inc_nrnb(nrnb, eNR_SETTLE, nsettle);
618 inc_nrnb(nrnb, eNR_CONSTR_V, nsettle * 3);
622 inc_nrnb(nrnb, eNR_CONSTR_VIR, nsettle * 3);
625 case ConstraintVariable::Velocities:
626 case ConstraintVariable::Derivative:
627 case ConstraintVariable::Force:
628 case ConstraintVariable::ForceDispl:
629 #pragma omp parallel for num_threads(nth) schedule(static)
630 for (int th = 0; th < nth; th++)
634 int calcvir_atom_end;
638 calcvir_atom_end = 0;
642 calcvir_atom_end = numHomeAtoms_;
647 clear_mat(threadConstraintsVirial[th]);
650 int start_th = (nsettle * th) / nth;
651 int end_th = (nsettle * (th + 1)) / nth;
653 if (start_th >= 0 && end_th - start_th > 0)
655 settle_proj(*settled,
658 settle.iatoms.data() + start_th * (1 + NRAL(F_SETTLE)),
660 x.unpaddedArrayRef(),
661 xprime.unpaddedArrayRef(),
664 th == 0 ? constraintsVirial : threadConstraintsVirial[th]);
667 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
669 /* This is an overestimate */
670 inc_nrnb(nrnb, eNR_SETTLE, nsettle);
672 case ConstraintVariable::Deriv_FlexCon:
673 /* Nothing to do, since the are no flexible constraints in settles */
675 default: gmx_incons("Unknown constraint quantity for settle");
680 /* Reduce the virial contributions over the threads */
681 for (int th = 1; th < nth; th++)
683 m_add(constraintsVirial, threadConstraintsVirial[th], constraintsVirial);
687 if (econq == ConstraintVariable::Positions)
689 for (int th = 1; th < nth; th++)
691 bSettleErrorHasOccurred0 = bSettleErrorHasOccurred0 || bSettleErrorHasOccurred[th];
694 if (bSettleErrorHasOccurred0)
700 ": One or more water molecules can not be settled.\n"
701 "Check for bad contacts and/or reduce the timestep if appropriate.\n",
705 fprintf(log, "%s", buf);
707 fprintf(stderr, "%s", buf);
709 if (warncount_settle > maxwarn)
711 too_many_constraint_warnings(ConstraintAlgorithm::Count, warncount_settle);
722 /* The normal uses of constrain() pass step_scaling = 1.0.
723 * The call to constrain() for SD1 that passes step_scaling =
724 * 0.5 also passes vir = NULL, so cannot reach this
725 * assertion. This assertion should remain until someone knows
726 * that this path works for their intended purpose, and then
727 * they can use scaled_delta_t instead of ir.delta_t
729 assert(gmx_within_tol(step_scaling, 1.0, GMX_REAL_EPS));
732 case ConstraintVariable::Positions: vir_fac = 0.5 / (ir.delta_t * ir.delta_t); break;
733 case ConstraintVariable::Velocities: vir_fac = 0.5 / ir.delta_t; break;
734 case ConstraintVariable::Force:
735 case ConstraintVariable::ForceDispl: vir_fac = 0.5; break;
736 default: gmx_incons("Unsupported constraint quantity for virial");
741 vir_fac *= 2; /* only constraining over half the distance here */
743 for (int i = 0; i < DIM; i++)
745 for (int j = 0; j < DIM; j++)
747 constraintsVirial[i][j] *= vir_fac;
754 dump_confs(log, step, mtop, start, numHomeAtoms_, cr, x.unpaddedArrayRef(), xprime.unpaddedArrayRef(), box);
757 if (econq == ConstraintVariable::Positions)
759 if (ir.bPull && pull_have_constraint(*pull_work))
761 if (EI_DYNAMICS(ir.eI))
763 t = ir.init_t + (step + delta_step) * ir.delta_t;
769 set_pbc(&pbc, ir.pbcType, box);
770 pull_constraint(pull_work,
776 x.unpaddedArrayRef(),
777 xprime.unpaddedArrayRef(),
778 v.unpaddedArrayRef(),
781 if (ed && delta_step > 0)
783 /* apply the essential dynamics constraints here */
784 do_edsam(&ir, step, cr, xprime.unpaddedArrayRef(), v.unpaddedArrayRef(), box, ed);
787 wallcycle_stop(wcycle, WallCycleCounter::Constr);
789 const bool haveVelocities = (!v.empty() || econq == ConstraintVariable::Velocities);
790 if (haveVelocities && !cFREEZE_.empty())
792 /* Set the velocities of frozen dimensions to zero */
794 if (econq == ConstraintVariable::Velocities)
796 vRef = xprime.unpaddedArrayRef();
800 vRef = v.unpaddedArrayRef();
803 int gmx_unused numThreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
805 #pragma omp parallel for num_threads(numThreads) schedule(static)
806 for (int i = 0; i < numHomeAtoms_; i++)
808 int freezeGroup = cFREEZE_[i];
810 for (int d = 0; d < DIM; d++)
812 if (ir.opts.nFreeze[freezeGroup][d])
823 real Constraints::rmsd() const
827 return lincs_rmsd(impl_->lincsd);
835 int Constraints::numConstraintsTotal()
837 return impl_->ncon_tot;
840 FlexibleConstraintTreatment flexibleConstraintTreatment(bool haveDynamicsIntegrator)
842 if (haveDynamicsIntegrator)
844 return FlexibleConstraintTreatment::Include;
848 return FlexibleConstraintTreatment::Exclude;
852 /*! \brief Returns a block struct to go from atoms to constraints
854 * The block struct will contain constraint indices with lower indices
855 * directly matching the order in F_CONSTR and higher indices matching
856 * the order in F_CONSTRNC offset by the number of constraints in F_CONSTR.
858 * \param[in] numAtoms The number of atoms to construct the list for
859 * \param[in] ilists The interaction lists, size F_NRE
860 * \param[in] iparams Interaction parameters, can be null when
861 * \p flexibleConstraintTreatment==Include
862 * \param[in] flexibleConstraintTreatment The flexible constraint treatment,
865 * \returns a block struct with all constraints for each atom
867 static ListOfLists<int> makeAtomsToConstraintsList(int numAtoms,
868 ArrayRef<const InteractionList> ilists,
869 ArrayRef<const t_iparams> iparams,
870 FlexibleConstraintTreatment flexibleConstraintTreatment)
872 GMX_ASSERT(flexibleConstraintTreatment == FlexibleConstraintTreatment::Include || !iparams.empty(),
873 "With flexible constraint detection we need valid iparams");
875 std::vector<int> count(numAtoms);
877 for (int ftype = F_CONSTR; ftype <= F_CONSTRNC; ftype++)
879 const InteractionList& ilist = ilists[ftype];
880 const int stride = 1 + NRAL(ftype);
881 for (int i = 0; i < ilist.size(); i += stride)
883 if (flexibleConstraintTreatment == FlexibleConstraintTreatment::Include
884 || !isConstraintFlexible(iparams, ilist.iatoms[i]))
886 for (int j = 1; j < 3; j++)
888 int a = ilist.iatoms[i + j];
895 std::vector<int> listRanges(numAtoms + 1);
896 for (int a = 0; a < numAtoms; a++)
898 listRanges[a + 1] = listRanges[a] + count[a];
901 std::vector<int> elements(listRanges[numAtoms]);
903 /* The F_CONSTRNC constraints have constraint numbers
904 * that continue after the last F_CONSTR constraint.
906 int numConstraints = 0;
907 for (int ftype = F_CONSTR; ftype <= F_CONSTRNC; ftype++)
909 const InteractionList& ilist = ilists[ftype];
910 const int stride = 1 + NRAL(ftype);
911 for (int i = 0; i < ilist.size(); i += stride)
913 if (flexibleConstraintTreatment == FlexibleConstraintTreatment::Include
914 || !isConstraintFlexible(iparams, ilist.iatoms[i]))
916 for (int j = 1; j < 3; j++)
918 const int a = ilist.iatoms[i + j];
919 elements[listRanges[a] + count[a]++] = numConstraints;
926 return ListOfLists<int>(std::move(listRanges), std::move(elements));
929 ListOfLists<int> make_at2con(int numAtoms,
930 ArrayRef<const InteractionList> ilist,
931 ArrayRef<const t_iparams> iparams,
932 FlexibleConstraintTreatment flexibleConstraintTreatment)
934 return makeAtomsToConstraintsList(numAtoms, ilist, iparams, flexibleConstraintTreatment);
937 ListOfLists<int> make_at2con(const gmx_moltype_t& moltype,
938 gmx::ArrayRef<const t_iparams> iparams,
939 FlexibleConstraintTreatment flexibleConstraintTreatment)
941 return makeAtomsToConstraintsList(
942 moltype.atoms.nr, makeConstArrayRef(moltype.ilist), iparams, flexibleConstraintTreatment);
945 //! Return the number of flexible constraints in the \c ilist and \c iparams.
946 int countFlexibleConstraints(ArrayRef<const InteractionList> ilist, ArrayRef<const t_iparams> iparams)
949 for (int ftype = F_CONSTR; ftype <= F_CONSTRNC; ftype++)
951 const int numIatomsPerConstraint = 3;
952 for (int i = 0; i < ilist[ftype].size(); i += numIatomsPerConstraint)
954 const int type = ilist[ftype].iatoms[i];
955 if (iparams[type].constr.dA == 0 && iparams[type].constr.dB == 0)
965 //! Returns the index of the settle to which each atom belongs.
966 static std::vector<int> make_at2settle(int natoms, const InteractionList& ilist)
968 /* Set all to no settle */
969 std::vector<int> at2s(natoms, -1);
971 const int stride = 1 + NRAL(F_SETTLE);
973 for (int s = 0; s < ilist.size(); s += stride)
975 at2s[ilist.iatoms[s + 1]] = s / stride;
976 at2s[ilist.iatoms[s + 2]] = s / stride;
977 at2s[ilist.iatoms[s + 3]] = s / stride;
983 void Constraints::Impl::setConstraints(gmx_localtop_t* top,
986 gmx::ArrayRef<const real> masses,
987 gmx::ArrayRef<const real> inverseMasses,
988 const bool hasMassPerturbedAtoms,
990 gmx::ArrayRef<const unsigned short> cFREEZE)
992 numAtoms_ = numAtoms;
993 numHomeAtoms_ = numHomeAtoms;
995 inverseMasses_ = inverseMasses;
996 hasMassPerturbedAtoms_ = hasMassPerturbedAtoms;
1004 /* With DD we might also need to call LINCS on a domain no constraints for
1005 * communicating coordinates to other nodes that do have constraints.
1007 if (ir.eConstrAlg == ConstraintAlgorithm::Lincs)
1009 set_lincs(*idef, numAtoms_, inverseMasses_, lambda_, EI_DYNAMICS(ir.eI), cr, lincsd);
1011 if (ir.eConstrAlg == ConstraintAlgorithm::Shake)
1015 // We are using the local topology, so there are only
1016 // F_CONSTR constraints.
1017 GMX_RELEASE_ASSERT(idef->il[F_CONSTRNC].empty(),
1018 "Here we should not have no-connect constraints");
1019 make_shake_sblock_dd(shaked.get(), idef->il[F_CONSTR]);
1023 make_shake_sblock_serial(shaked.get(), &top->idef, numAtoms_);
1030 settled->setConstraints(idef->il[F_SETTLE], numHomeAtoms_, masses_, inverseMasses_);
1033 /* Make a selection of the local atoms for essential dynamics */
1036 dd_make_local_ed_indices(cr->dd, ed);
1040 void Constraints::setConstraints(gmx_localtop_t* top,
1042 const int numHomeAtoms,
1043 gmx::ArrayRef<const real> masses,
1044 gmx::ArrayRef<const real> inverseMasses,
1045 const bool hasMassPerturbedAtoms,
1047 gmx::ArrayRef<const unsigned short> cFREEZE)
1049 impl_->setConstraints(
1050 top, numAtoms, numHomeAtoms, masses, inverseMasses, hasMassPerturbedAtoms, lambda, cFREEZE);
1053 /*! \brief Makes a per-moleculetype container of mappings from atom
1054 * indices to constraint indices.
1056 * Note that flexible constraints are only enabled with a dynamical integrator. */
1057 static std::vector<ListOfLists<int>> makeAtomToConstraintMappings(const gmx_mtop_t& mtop,
1058 FlexibleConstraintTreatment flexibleConstraintTreatment)
1060 std::vector<ListOfLists<int>> mapping;
1061 mapping.reserve(mtop.moltype.size());
1062 for (const gmx_moltype_t& moltype : mtop.moltype)
1064 mapping.push_back(make_at2con(moltype, mtop.ffparams.iparams, flexibleConstraintTreatment));
1069 Constraints::Constraints(const gmx_mtop_t& mtop,
1070 const t_inputrec& ir,
1073 const t_commrec* cr,
1074 const bool useUpdateGroups,
1075 const gmx_multisim_t* ms,
1077 gmx_wallcycle* wcycle,
1078 bool pbcHandlingRequired,
1079 ObservablesReducerBuilder* observablesReducerBuilder,
1082 impl_(new Impl(mtop, ir, pull_work, log, cr, useUpdateGroups, ms, nrnb, wcycle, pbcHandlingRequired, observablesReducerBuilder, numConstraints, numSettles))
1086 Constraints::Impl::Impl(const gmx_mtop_t& mtop_p,
1087 const t_inputrec& ir_p,
1090 const t_commrec* cr_p,
1091 const bool useUpdateGroups,
1092 const gmx_multisim_t* ms_p,
1094 gmx_wallcycle* wcycle_p,
1095 bool pbcHandlingRequired,
1096 ObservablesReducerBuilder* observablesReducerBuilder,
1099 ncon_tot(numConstraints),
1101 pbcHandlingRequired_(pbcHandlingRequired),
1105 pull_work(pull_work),
1110 if (numConstraints + numSettles > 0 && ir.epc == PressureCoupling::Mttk)
1112 gmx_fatal(FARGS, "Constraints are not implemented with MTTK pressure control.");
1116 if (numConstraints > 0)
1118 at2con_mt = makeAtomToConstraintMappings(mtop, flexibleConstraintTreatment(EI_DYNAMICS(ir.eI)));
1120 for (const gmx_molblock_t& molblock : mtop.molblock)
1122 int count = countFlexibleConstraints(mtop.moltype[molblock.type].ilist, mtop.ffparams.iparams);
1123 nflexcon += molblock.nmol * count;
1130 fprintf(log, "There are %d flexible constraints\n", nflexcon);
1131 if (ir.fc_stepsize == 0)
1135 "WARNING: step size for flexible constraining = 0\n"
1136 " All flexible constraints will be rigid.\n"
1137 " Will try to keep all flexible constraints at their original "
1139 " but the lengths may exhibit some drift.\n\n");
1145 please_cite(log, "Hess2002");
1149 // When there are multiple PP domains and update groups are
1150 // not in use, the constraints might be split across the
1151 // domains, needing particular handling.
1152 const bool mayHaveSplitConstraints = haveDDAtomOrdering(*cr) && !useUpdateGroups;
1154 if (ir.eConstrAlg == ConstraintAlgorithm::Lincs)
1156 lincsd = init_lincs(
1157 log, mtop, nflexcon, at2con_mt, mayHaveSplitConstraints, ir.nLincsIter, ir.nProjOrder, observablesReducerBuilder);
1160 if (ir.eConstrAlg == ConstraintAlgorithm::Shake)
1162 if (mayHaveSplitConstraints)
1165 "SHAKE is not supported with domain decomposition and constraints that "
1166 "cross domain boundaries, use LINCS");
1171 "For this system also velocities and/or forces need to be constrained, "
1172 "this can not be done with SHAKE, you should select LINCS");
1174 please_cite(log, "Ryckaert77a");
1177 please_cite(log, "Barth95a");
1180 shaked = std::make_unique<shakedata>();
1186 please_cite(log, "Miyamoto92a");
1188 settled = std::make_unique<SettleData>(mtop);
1190 // SETTLE with perturbed masses is not implemented. grompp now checks
1191 // for this, but old .tpr files that did this might still exist.
1192 if (haveFepPerturbedMassesInSettles(mtop))
1195 "SETTLE is not implemented for atoms whose mass is perturbed. "
1196 "You might\ninstead use normal constraints.");
1199 /* Make an atom to settle index for use in domain decomposition */
1200 for (size_t mt = 0; mt < mtop.moltype.size(); mt++)
1202 at2settle_mt.emplace_back(
1203 make_at2settle(mtop.moltype[mt].atoms.nr, mtop.moltype[mt].ilist[F_SETTLE]));
1206 /* Allocate thread-local work arrays */
1207 int nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Settle);
1208 if (nthreads > 1 && threadConstraintsVirial == nullptr)
1210 snew(threadConstraintsVirial, nthreads);
1211 snew(bSettleErrorHasOccurred, nthreads);
1216 char* env = getenv("GMX_MAXCONSTRWARN");
1220 sscanf(env, "%8d", &maxwarn);
1227 fprintf(log, "Setting the maximum number of constraint warnings to %d\n", maxwarn);
1231 fprintf(stderr, "Setting the maximum number of constraint warnings to %d\n", maxwarn);
1234 warncount_lincs = 0;
1235 warncount_settle = 0;
1238 Constraints::Impl::~Impl()
1240 if (bSettleErrorHasOccurred != nullptr)
1242 sfree(bSettleErrorHasOccurred);
1244 if (threadConstraintsVirial != nullptr)
1246 sfree(threadConstraintsVirial);
1251 void Constraints::saveEdsamPointer(gmx_edsam* ed)
1256 ArrayRef<const ListOfLists<int>> Constraints::atom2constraints_moltype() const
1258 return impl_->at2con_mt;
1261 ArrayRef<const std::vector<int>> Constraints::atom2settle_moltype() const
1263 return impl_->at2settle_mt;
1266 void do_constrain_first(FILE* fplog,
1267 gmx::Constraints* constr,
1268 const t_inputrec* ir,
1271 ArrayRefWithPadding<RVec> x,
1272 ArrayRefWithPadding<RVec> v,
1276 int i, m, start, end;
1278 real dt = ir->delta_t;
1281 PaddedVector<RVec> savex(numAtoms);
1288 fprintf(debug, "vcm: start=%d, homenr=%d, end=%d\n", start, numHomeAtoms, end);
1290 /* Do a first constrain to reset particles... */
1291 step = ir->init_step;
1294 char buf[STEPSTRSIZE];
1295 fprintf(fplog, "\nConstraining the starting coordinates (step %s)\n", gmx_step_str(step, buf));
1299 bool needsLogging = true;
1300 bool computeEnergy = false;
1301 bool computeVirial = false;
1302 /* constrain the current position */
1303 constr->apply(needsLogging,
1317 gmx::ConstraintVariable::Positions);
1320 /* constrain the inital velocity, and save it */
1321 /* also may be useful if we need the ekin from the halfstep for velocity verlet */
1322 constr->apply(needsLogging,
1329 v.unpaddedArrayRef(),
1336 gmx::ConstraintVariable::Velocities);
1338 /* constrain the inital velocities at t-dt/2 */
1339 if (EI_STATE_VELOCITY(ir->eI) && ir->eI != IntegrationAlgorithm::VV)
1341 auto subX = x.paddedArrayRef().subArray(start, end);
1342 auto subV = v.paddedArrayRef().subArray(start, end);
1343 for (i = start; (i < end); i++)
1345 for (m = 0; (m < DIM); m++)
1347 /* Reverse the velocity */
1348 subV[i][m] = -subV[i][m];
1349 /* Store the position at t-dt in buf */
1350 savex[i][m] = subX[i][m] + dt * subV[i][m];
1353 /* Shake the positions at t=-dt with the positions at t=0
1354 * as reference coordinates.
1358 char buf[STEPSTRSIZE];
1359 fprintf(fplog, "\nConstraining the coordinates at t0-dt (step %s)\n", gmx_step_str(step, buf));
1362 constr->apply(needsLogging,
1368 savex.arrayRefWithPadding(),
1376 gmx::ConstraintVariable::Positions);
1378 for (i = start; i < end; i++)
1380 for (m = 0; m < DIM; m++)
1382 /* Re-reverse the velocities */
1383 subV[i][m] = -subV[i][m];
1389 void constrain_velocities(gmx::Constraints* constr,
1395 gmx_bool computeVirial,
1396 tensor constraintsVirial)
1398 if (constr != nullptr)
1400 constr->apply(do_log,
1405 state->x.arrayRefWithPadding(),
1406 state->v.arrayRefWithPadding(),
1407 state->v.arrayRefWithPadding().unpaddedArrayRef(),
1409 state->lambda[FreeEnergyPerturbationCouplingType::Bonded],
1411 ArrayRefWithPadding<RVec>(),
1414 ConstraintVariable::Velocities);
1418 void constrain_coordinates(gmx::Constraints* constr,
1423 ArrayRefWithPadding<RVec> xp,
1425 gmx_bool computeVirial,
1426 tensor constraintsVirial)
1428 if (constr != nullptr)
1430 constr->apply(do_log,
1435 state->x.arrayRefWithPadding(),
1439 state->lambda[FreeEnergyPerturbationCouplingType::Bonded],
1441 state->v.arrayRefWithPadding(),
1444 ConstraintVariable::Positions);