View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
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 }