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.terms;
39  
40  import ffx.potential.bonded.Bond;
41  import ffx.potential.bonded.BondedTerm;
42  import ffx.potential.parameters.BondType;
43  
44  import java.util.ArrayList;
45  import java.util.Collection;
46  import java.util.Collections;
47  import java.util.List;
48  import java.util.logging.Logger;
49  
50  import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_NmPerAngstrom;
51  import static java.lang.String.format;
52  
53  /**
54   * Bond potential energy term using {@link ffx.potential.bonded.Bond} instances.
55   *
56   * @author Michael J. Schnieders
57   * @since 1.0
58   */
59  public class BondPotentialEnergy extends EnergyTerm {
60  
61    private static final Logger logger = Logger.getLogger(BondPotentialEnergy.class.getName());
62  
63  
64    /**
65     * Internal list of Bond instances.
66     */
67    private final List<Bond> bonds = new ArrayList<>();
68  
69    /**
70     * Create a BondPotentialEnergy with the provided name.
71     *
72     * @param name Name for this term.
73     */
74    public BondPotentialEnergy(String name) {
75      super(name);
76    }
77  
78    /**
79     * Create a BondPotentialEnergy with the provided name and force group.
80     *
81     * @param name       Name for this term.
82     * @param forceGroup Integer force group identifier.
83     */
84    public BondPotentialEnergy(String name, int forceGroup) {
85      super(name, forceGroup);
86    }
87  
88    /**
89     * Create a BondPotentialEnergy initialized with a list of bonds and force group.
90     *
91     * @param name       Name for this term.
92     * @param forceGroup Force group identifier.
93     * @param bonds      List of Bond instances to add (null-safe).
94     */
95    public BondPotentialEnergy(String name, int forceGroup, List<Bond> bonds) {
96      super(name, forceGroup);
97      if (bonds != null) {
98        Collections.sort(bonds);
99        this.bonds.addAll(bonds);
100       logger.info(format("  Bonds:                             %10d", getNumberOfBonds()));
101     }
102   }
103 
104   /**
105    * Get the number of terms in this potential energy term.
106    *
107    * @return The number of terms, which is the same as the number of bonds.
108    */
109   @Override
110   public int getNumberOfTerms() {
111     return getNumberOfBonds();
112   }
113 
114   /**
115    * Get an array of BondedTerms in this term.
116    *
117    * @return Array of BondedTerms, which are actually Bonds in this case.
118    */
119   @Override
120   public BondedTerm[] getBondedTermsArray() {
121     return getBondArray();
122   }
123 
124   /**
125    * Create a BondPotentialEnergy initialized with a collection of bonds.
126    *
127    * @param name  Name for this term (may be null).
128    * @param bonds Collection of Bond instances to add (null-safe).
129    */
130   public BondPotentialEnergy(String name, Collection<Bond> bonds) {
131     super(name);
132     if (bonds != null) {
133       this.bonds.addAll(bonds);
134     }
135   }
136 
137   /**
138    * Add a Bond to this term.
139    *
140    * @param bond Bond to add (ignored if null).
141    * @return true if the bond was added.
142    */
143   public boolean addBond(Bond bond) {
144     if (bond == null) {
145       return false;
146     }
147     return bonds.add(bond);
148   }
149 
150   /**
151    * Add an array of Bonds to this term.
152    *
153    * @param bonds Array of Bond instances to add.
154    * @return true if the bonds were added.
155    */
156   public boolean addBonds(Bond[] bonds) {
157     if (bonds == null) {
158       return false;
159     }
160     Collections.addAll(this.bonds, bonds);
161     return true;
162   }
163 
164   /**
165    * Add a list of Bonds to this term.
166    *
167    * @param bonds List of Bond instances to add.
168    * @return true if the bonds were added.
169    */
170   public boolean addBonds(List<Bond> bonds) {
171     if (bonds == null) {
172       return false;
173     }
174     this.bonds.addAll(bonds);
175     return true;
176   }
177 
178   /**
179    * Remove a Bond from this term.
180    *
181    * @param bond Bond to remove (ignored if null).
182    * @return true if the bond was present and removed.
183    */
184   public boolean removeBond(Bond bond) {
185     if (bond == null) {
186       return false;
187     }
188     return bonds.remove(bond);
189   }
190 
191   /**
192    * Get the Bond at a given index.
193    *
194    * @param index Index in the internal list.
195    * @return Bond at the specified index.
196    * @throws IndexOutOfBoundsException if index is invalid.
197    */
198   public Bond getBond(int index) {
199     return bonds.get(index);
200   }
201 
202   /**
203    * Get an unmodifiable view of the Bonds in this term.
204    *
205    * @return Unmodifiable List of Bonds.
206    */
207   public List<Bond> getBonds() {
208     return Collections.unmodifiableList(bonds);
209   }
210 
211   /**
212    * Get an array of Bonds in this term.
213    *
214    * @return Array of Bonds.
215    */
216   public Bond[] getBondArray() {
217     return bonds.toArray(new Bond[0]);
218   }
219 
220   /**
221    * Get the number of Bonds in this term.
222    *
223    * @return The number of Bonds.
224    */
225   public int getNumberOfBonds() {
226     return bonds.size();
227   }
228 
229   public String getBondEnergyString() {
230     BondType bondType = bonds.getFirst().getBondType();
231     String energy;
232     if (bondType.bondFunction == BondType.BondFunction.QUARTIC) {
233       energy = format("""
234               k*(d^2 + %.15g*d^3 + %.15g*d^4);
235               d=r-r0;
236               """,
237           bondType.cubic / OpenMM_NmPerAngstrom,
238           bondType.quartic / (OpenMM_NmPerAngstrom * OpenMM_NmPerAngstrom));
239     } else {
240       energy = """
241           k*(d^2);
242           d=r-r0;
243           """;
244     }
245     return energy;
246   }
247 
248   /**
249    * Log the details of Bond interactions.
250    */
251   @Override
252   public void log() {
253     if (getNumberOfBonds() <= 0) {
254       return;
255     }
256     logger.info("\n Bond Stretching Interactions:");
257     for (Bond bond : getBonds()) {
258       logger.info(" Bond \t" + bond.toString());
259     }
260   }
261 
262   @Override
263   public String toPDBString() {
264     if (getNumberOfBonds() <= 0) {
265       return "";
266     }
267     StringBuilder sb = new StringBuilder();
268     sb.append(format("REMARK   3   %s %g (%d)\n", "BOND STRETCHING            : ", getEnergy(), getNumberOfBonds()));
269     sb.append(format("REMARK   3   %s %g\n", "BOND RMSD                  : ", getRMSD()));
270     return sb.toString();
271   }
272 
273   @Override
274   public String toString() {
275     return format("  %s %20.8f %12d %12.3f (%8.5f)\n", "Bond Stretching   ",
276         getEnergy(), getNumberOfBonds(), getTime(), getRMSD());
277   }
278 
279 }