1 // ******************************************************************************
2 //
3 // Title: Force Field X.
4 // Description: Force Field X - Software for Molecular Biophysics.
5 // Copyright: Copyright (c) Michael J. Schnieders 2001-2025.
6 //
7 // This file is part of Force Field X.
8 //
9 // Force Field X is free software; you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License version 3 as published by
11 // the Free Software Foundation.
12 //
13 // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 // details.
17 //
18 // You should have received a copy of the GNU General Public License along with
19 // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20 // Place, Suite 330, Boston, MA 02111-1307 USA
21 //
22 // Linking this library statically or dynamically with other modules is making a
23 // combined work based on this library. Thus, the terms and conditions of the
24 // GNU General Public License cover the whole combination.
25 //
26 // As a special exception, the copyright holders of this library give you
27 // permission to link this library with independent modules to produce an
28 // executable, regardless of the license terms of these independent modules, and
29 // to copy and distribute the resulting executable under terms of your choice,
30 // provided that you also meet, for each linked independent module, the terms
31 // and conditions of the license of that module. An independent module is a
32 // module which is not derived from or based on this library. If you modify this
33 // library, you may extend this exception to your version of the library, but
34 // you are not obligated to do so. If you do not wish to do so, delete this
35 // exception statement from your version.
36 //
37 // ******************************************************************************
38 package ffx.potential.openmm;
39
40 import ffx.openmm.CustomIntegrator;
41
42 import java.util.logging.Logger;
43
44 import static java.lang.String.format;
45 import static java.util.Arrays.copyOfRange;
46
47 /**
48 * OpenMM Custom MTS Integrator.
49 */
50 public class CustomMTSIntegrator extends CustomIntegrator {
51
52 private static final Logger logger = Logger.getLogger(CustomMTSIntegrator.class.getName());
53
54 public CustomMTSIntegrator(double dt, double constraintTolerance, boolean hasAmoebaCavitationForce) {
55 super(dt);
56 setConstraintTolerance(constraintTolerance);
57
58 int n = 4;
59 // Force group 1 contains slowly varying forces.
60 // Force group 0 contains the fast varying forces.
61 int[] forceGroups = {1, 0};
62 // There will be 1 force evaluation per outer step, and 4 per inner step.
63 int[] subSteps = {1, 4};
64 if (hasAmoebaCavitationForce) {
65 n = 8;
66 // Force group 2 contains the cavitation force.
67 // Force group 1 contains slowly varying forces.
68 // Force group 0 contains the fast varying forces.
69 forceGroups = new int[]{2, 1, 0};
70 // There will be 1 force evaluation per outer step.
71 // There will be 2 force evaluations per middle step.
72 // There will be 8 force evaluations per inner step.
73 subSteps = new int[]{1, 2, 8};
74 }
75
76 addPerDofVariable("x1", 0.0);
77 addUpdateContextState();
78 createMTSSubStep(1, forceGroups, subSteps);
79 addConstrainVelocities();
80 logger.info(" Custom MTS Integrator");
81 logger.info(format(" Time step: %6.2f (fsec)", dt * 1000));
82 logger.info(format(" Inner Time step: %6.2f (fsec)", dt / n * 1000));
83 }
84
85 /**
86 * Create substeps for the MTS CustomIntegrator.
87 *
88 * @param parentSubsteps The number of substeps for the previous force group.
89 * @param forceGroups The force groups to be evaluated.
90 * @param subSteps The number of substeps for each force group.
91 */
92 public void createMTSSubStep(int parentSubsteps, int[] forceGroups, int[] subSteps) {
93 int forceGroup = forceGroups[0];
94 int steps = subSteps[0];
95 int stepsPerParentStep = steps / parentSubsteps;
96 if (stepsPerParentStep < 1 || steps % parentSubsteps != 0) {
97 throw new IllegalArgumentException(
98 "The number for substeps for each group must be a multiple of the number for the previous group");
99 }
100 if (forceGroup < 0 || forceGroup > 31) {
101 throw new IllegalArgumentException("Force group must be between 0 and 31");
102 }
103 for (int i = 0; i < stepsPerParentStep; i++) {
104 addComputePerDof("v", "v+0.5*(dt/" + steps + ")*f" + forceGroup + "/m");
105 if (forceGroups.length == 1) {
106 addComputePerDof("x", "x+(dt/" + steps + ")*v");
107 addComputePerDof("x1", "x");
108 addConstrainPositions();
109 addComputePerDof("v", "v+(x-x1)/(dt/" + steps + ")");
110 addConstrainVelocities();
111 } else {
112 createMTSSubStep(steps, copyOfRange(forceGroups, 1, forceGroups.length),
113 copyOfRange(subSteps, 1, subSteps.length));
114 }
115 addComputePerDof("v", "v+0.5*(dt/" + steps + ")*f" + forceGroup + "/m");
116 }
117 }
118 }