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.DoubleArray;
41  import ffx.openmm.DoubleArray3D;
42  import ffx.openmm.Force;
43  import ffx.openmm.amoeba.TorsionTorsionForce;
44  import ffx.potential.bonded.Atom;
45  import ffx.potential.bonded.TorsionTorsion;
46  import ffx.potential.parameters.TorsionTorsionType;
47  
48  import java.util.LinkedHashMap;
49  import java.util.logging.Level;
50  import java.util.logging.Logger;
51  
52  import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_KJPerKcal;
53  import static java.lang.String.format;
54  
55  /**
56   * OpenMM TorsionTorsion Force.
57   */
58  public class AmoebaTorsionTorsionForce extends TorsionTorsionForce {
59  
60    private static final Logger logger = Logger.getLogger(AmoebaTorsionTorsionForce.class.getName());
61  
62    /**
63     * Create an OpenMM TorsionTorsion Force.
64     *
65     * @param openMMEnergy The OpenMM Energy instance that contains the torsion-torsions.
66     */
67    public AmoebaTorsionTorsionForce(OpenMMEnergy openMMEnergy) {
68      TorsionTorsion[] torsionTorsions = openMMEnergy.getTorsionTorsions();
69      if (torsionTorsions == null || torsionTorsions.length < 1) {
70        destroy();
71        return;
72      }
73  
74      // Load the torsion-torsions.
75      int nTypes = 0;
76      LinkedHashMap<String, TorsionTorsionType> torTorTypes = new LinkedHashMap<>();
77  
78      for (TorsionTorsion torsionTorsion : torsionTorsions) {
79        int ia = torsionTorsion.getAtom(0).getXyzIndex() - 1;
80        int ib = torsionTorsion.getAtom(1).getXyzIndex() - 1;
81        int ic = torsionTorsion.getAtom(2).getXyzIndex() - 1;
82        int id = torsionTorsion.getAtom(3).getXyzIndex() - 1;
83        int ie = torsionTorsion.getAtom(4).getXyzIndex() - 1;
84  
85        TorsionTorsionType torsionTorsionType = torsionTorsion.torsionTorsionType;
86        String key = torsionTorsionType.getKey();
87  
88        // Check if the TorTor parameters have already been added to the Hash.
89        int gridIndex = 0;
90        if (torTorTypes.containsKey(key)) {
91  
92          // If the TorTor has been added, get its (ordered) index in the Hash.
93          int index = 0;
94          for (String entry : torTorTypes.keySet()) {
95            if (entry.equalsIgnoreCase(key)) {
96              gridIndex = index;
97              break;
98            } else {
99              index++;
100           }
101         }
102       } else {
103         // Add the new TorTor.
104         torTorTypes.put(key, torsionTorsionType);
105         gridIndex = nTypes;
106         nTypes++;
107       }
108 
109       Atom atom = torsionTorsion.getChiralAtom();
110       int iChiral = -1;
111       if (atom != null) {
112         iChiral = atom.getXyzIndex() - 1;
113       }
114       addTorsionTorsion(ia, ib, ic, id, ie, iChiral, gridIndex);
115     }
116 
117     // Load the Torsion-Torsion parameters.
118     DoubleArray values = new DoubleArray(6);
119     int gridIndex = 0;
120     for (String key : torTorTypes.keySet()) {
121       TorsionTorsionType torTorType = torTorTypes.get(key);
122       int nx = torTorType.nx;
123       int ny = torTorType.ny;
124       double[] tx = torTorType.tx;
125       double[] ty = torTorType.ty;
126       double[] f = torTorType.energy;
127       double[] dx = torTorType.dx;
128       double[] dy = torTorType.dy;
129       double[] dxy = torTorType.dxy;
130 
131       // Create the 3D grid.
132       DoubleArray3D grid3D = new DoubleArray3D(nx, ny, 6);
133       int xIndex = 0;
134       int yIndex = 0;
135       for (int j = 0; j < nx * ny; j++) {
136         int addIndex = 0;
137         values.set(addIndex++, tx[xIndex]);
138         values.set(addIndex++, ty[yIndex]);
139         values.set(addIndex++, OpenMM_KJPerKcal * f[j]);
140         values.set(addIndex++, OpenMM_KJPerKcal * dx[j]);
141         values.set(addIndex++, OpenMM_KJPerKcal * dy[j]);
142         values.set(addIndex, OpenMM_KJPerKcal * dxy[j]);
143         grid3D.set(yIndex, xIndex, values);
144         xIndex++;
145         if (xIndex == nx) {
146           xIndex = 0;
147           yIndex++;
148         }
149       }
150       setTorsionTorsionGrid(gridIndex++, grid3D.getPointer());
151       grid3D.destroy();
152     }
153     values.destroy();
154 
155     int forceGroup = openMMEnergy.getMolecularAssembly().getForceField().getInteger("TORSION_TORSION_FORCE_GROUP", 0);
156     setForceGroup(forceGroup);
157     logger.log(Level.INFO, format("  Torsion-Torsions  \t%6d\t\t%1d", torsionTorsions.length, forceGroup));
158   }
159 
160   /**
161    * Convenience method to construct an OpenMM Torsion-Torsion Force.
162    *
163    * @param openMMEnergy The OpenMM Energy instance that contains the torsion-torsions.
164    * @return A Torsion-Torsion Force, or null if there are no torsion-torsions.
165    */
166   public static Force constructForce(OpenMMEnergy openMMEnergy) {
167     TorsionTorsion[] torsionTorsion = openMMEnergy.getTorsionTorsions();
168     if (torsionTorsion == null || torsionTorsion.length < 1) {
169       return null;
170     }
171     return new AmoebaTorsionTorsionForce(openMMEnergy);
172   }
173 }