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 }