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-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.Force;
41  import ffx.openmm.PeriodicTorsionForce;
42  import ffx.potential.ForceFieldEnergy;
43  import ffx.potential.bonded.Torsion;
44  import ffx.potential.parameters.TorsionType;
45  import ffx.potential.terms.RestrainTorsionPotentialEnergy;
46  
47  import java.util.logging.Level;
48  import java.util.logging.Logger;
49  
50  import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_KJPerKcal;
51  import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_RadiansPerDegree;
52  import static java.lang.String.format;
53  
54  /**
55   * Restrain Torsions Force.
56   */
57  public class RestrainTorsionsForce extends PeriodicTorsionForce {
58  
59    private static final Logger logger = Logger.getLogger(RestrainTorsionsForce.class.getName());
60  
61    /**
62     * Restrain Torsion Force constructor.
63     *
64     * @param restrainTorsionPotentialEnergy The RestrainTorsionPotentialEnergy instance that contains the torsions.
65     */
66    public RestrainTorsionsForce(RestrainTorsionPotentialEnergy restrainTorsionPotentialEnergy) {
67      Torsion[] restrainTorsions = restrainTorsionPotentialEnergy.getRestrainTorsionArray();
68      for (Torsion restrainTorsion : restrainTorsions) {
69        int a1 = restrainTorsion.getAtom(0).getArrayIndex();
70        int a2 = restrainTorsion.getAtom(1).getArrayIndex();
71        int a3 = restrainTorsion.getAtom(2).getArrayIndex();
72        int a4 = restrainTorsion.getAtom(3).getArrayIndex();
73        TorsionType torsionType = restrainTorsion.torsionType;
74        int nTerms = torsionType.phase.length;
75        for (int j = 0; j < nTerms; j++) {
76          addTorsion(a1, a2, a3, a4, j + 1,
77              torsionType.phase[j] * OpenMM_RadiansPerDegree,
78              OpenMM_KJPerKcal * torsionType.torsionUnit * torsionType.amplitude[j]);
79        }
80      }
81      int forceGroup = restrainTorsionPotentialEnergy.getForceGroup();
82      setForceGroup(forceGroup);
83      logger.log(Level.INFO, format("  Restrain-Torsions \t%6d\t\t%1d", restrainTorsions.length, forceGroup));
84    }
85  
86    /**
87     * Restrain Torsion Force constructor for Dual Topology.
88     *
89     * @param topology The topology index for the OpenMM System.
90     * @param openMMDualTopologyEnergy The OpenMMDualTopologyEnergy instance.
91     */
92    public RestrainTorsionsForce(RestrainTorsionPotentialEnergy restrainTorsionPotentialEnergy, int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
93      ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
94      Torsion[] restrainTorsions = restrainTorsionPotentialEnergy.getRestrainTorsionArray();
95  
96      double scale = openMMDualTopologyEnergy.getTopologyScale(topology);
97  
98      for (Torsion restrainTorsion : restrainTorsions) {
99        int a1 = restrainTorsion.getAtom(0).getArrayIndex();
100       int a2 = restrainTorsion.getAtom(1).getArrayIndex();
101       int a3 = restrainTorsion.getAtom(2).getArrayIndex();
102       int a4 = restrainTorsion.getAtom(3).getArrayIndex();
103       a1 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a1);
104       a2 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a2);
105       a3 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a3);
106       a4 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a4);
107       TorsionType torsionType = restrainTorsion.torsionType;
108       int nTerms = torsionType.phase.length;
109       for (int j = 0; j < nTerms; j++) {
110         double k = restrainTorsion.getTorsionScale() * torsionType.torsionUnit * torsionType.amplitude[j];
111         k = k * (1 - scale); // multiply force constant by 1 minus lambda
112         addTorsion(a1, a2, a3, a4, j + 1,
113                 torsionType.phase[j] * OpenMM_RadiansPerDegree,
114                 OpenMM_KJPerKcal * k);
115       }
116     }
117 
118     int forceGroup = forceFieldEnergy.getMolecularAssembly().getForceField().getInteger("RESTRAIN_TORSION_FORCE_GROUP", 0);
119     setForceGroup(forceGroup);
120     logger.info(format("  Restrain-Torsions:                 %10d", restrainTorsions.length));
121     logger.fine(format("   Force Group:                      %10d", forceGroup));
122   }
123 
124   /**
125    * Convenience method to construct an OpenMM Torsion Force.
126    *
127    * @param openMMEnergy The OpenMM Energy instance that contains the torsions.
128    * @return A Torsion Force, or null if there are no torsions.
129    */
130   public static Force constructForce(OpenMMEnergy openMMEnergy) {
131     RestrainTorsionPotentialEnergy restrainTorsionPotentialEnergy =
132         openMMEnergy.getRestrainTorsionPotentialEnergy();
133     if (restrainTorsionPotentialEnergy == null) {
134       return null;
135     }
136     return new RestrainTorsionsForce(restrainTorsionPotentialEnergy);
137   }
138 
139   /**
140    * Convenience method to construct a Dual-Topology OpenMM Torsion Force.
141    *
142    * @param topology The topology index for the OpenMM System.
143    * @param openMMDualTopologyEnergy The OpenMMDualTopologyEnergy instance.
144    * @return A Torsion Force, or null if there are no torsions.
145    */
146   public static Force constructForce(int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
147     ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
148     RestrainTorsionPotentialEnergy restrainTorsionPotentialEnergy = forceFieldEnergy.getRestrainTorsionPotentialEnergy();
149     if (restrainTorsionPotentialEnergy == null) {
150       return null;
151     }
152     return new RestrainTorsionsForce(restrainTorsionPotentialEnergy, topology, openMMDualTopologyEnergy);
153   }
154 
155   /**
156    * Update the Restraint-Torsion force.
157    *
158    * @param openMMEnergy The OpenMM Energy that contains the restraint-torsions.
159    */
160   public void updateForce(OpenMMEnergy openMMEnergy) {
161     // Check if this system has restraintTorsions.
162     RestrainTorsionPotentialEnergy restrainTorsionPotentialEnergy =
163         openMMEnergy.getRestrainTorsionPotentialEnergy();
164     if (restrainTorsionPotentialEnergy == null) {
165       return;
166     }
167     Torsion[] restrainTorsions = restrainTorsionPotentialEnergy.getRestrainTorsionArray();
168     int index = 0;
169     for (Torsion restrainTorsion : restrainTorsions) {
170       TorsionType torsionType = restrainTorsion.torsionType;
171       int nTerms = torsionType.phase.length;
172       int a1 = restrainTorsion.getAtom(0).getArrayIndex();
173       int a2 = restrainTorsion.getAtom(1).getArrayIndex();
174       int a3 = restrainTorsion.getAtom(2).getArrayIndex();
175       int a4 = restrainTorsion.getAtom(3).getArrayIndex();
176       for (int j = 0; j < nTerms; j++) {
177         double forceConstant = OpenMM_KJPerKcal * torsionType.torsionUnit * torsionType.amplitude[j];
178         setTorsionParameters(index++, a1, a2, a3, a4, j + 1,
179             torsionType.phase[j] * OpenMM_RadiansPerDegree, forceConstant);
180       }
181     }
182     updateParametersInContext(openMMEnergy.getContext());
183   }
184 
185   /**
186    * Update the Restraint-Torsion force.
187    *
188    * @param topology The topology index for the OpenMM System.
189    * @param openMMDualTopologyEnergy The OpenMMDualTopologyEnergy instance.
190    */
191   public void updateForce(int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
192     ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
193     RestrainTorsionPotentialEnergy restrainTorsionPotentialEnergy = forceFieldEnergy.getRestrainTorsionPotentialEnergy();
194     if (restrainTorsionPotentialEnergy == null) {
195       return;
196     }
197     // Check if this system has restraintTorsions.
198     Torsion[] restrainTorsions = restrainTorsionPotentialEnergy.getRestrainTorsionArray();
199 
200     double scale = openMMDualTopologyEnergy.getTopologyScale(topology);
201 
202     int index = 0;
203     for (Torsion restrainTorsion : restrainTorsions) {
204       TorsionType torsionType = restrainTorsion.torsionType;
205       int nTerms = torsionType.phase.length;
206       int a1 = restrainTorsion.getAtom(0).getArrayIndex();
207       int a2 = restrainTorsion.getAtom(1).getArrayIndex();
208       int a3 = restrainTorsion.getAtom(2).getArrayIndex();
209       int a4 = restrainTorsion.getAtom(3).getArrayIndex();
210       a1 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a1);
211       a2 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a2);
212       a3 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a3);
213       a4 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, a4);
214       for (int j = 0; j < nTerms; j++) {
215         double forceConstant = restrainTorsion.getTorsionScale() * torsionType.torsionUnit * torsionType.amplitude[j];
216         forceConstant = forceConstant * (1 - scale); // multiply force constant by 1 minus lambda
217         setTorsionParameters(index++, a1, a2, a3, a4, j + 1,
218                 torsionType.phase[j] * OpenMM_RadiansPerDegree, OpenMM_KJPerKcal * forceConstant);
219       }
220     }
221     updateParametersInContext(openMMDualTopologyEnergy.getContext());
222   }
223 
224 }