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