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.BondedTerm;
41  import ffx.potential.bonded.PiOrbitalTorsion;
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  
49  /**
50   * Pi-Orbital Torsion potential energy term using {@link ffx.potential.bonded.PiOrbitalTorsion} instances.
51   */
52  public class PiOrbitalTorsionPotentialEnergy extends EnergyTerm {
53  
54    private static final Logger logger = Logger.getLogger(PiOrbitalTorsionPotentialEnergy.class.getName());
55  
56  
57    /**
58     * Internal list of PiOrbitalTorsion instances.
59     */
60    private final List<PiOrbitalTorsion> piOrbitalTorsions = new ArrayList<>();
61  
62    /**
63     * Create a PiOrbitalTorsionPotentialEnergy with the provided name.
64     *
65     * @param name Name for this term.
66     */
67    public PiOrbitalTorsionPotentialEnergy(String name) {
68      super(name);
69    }
70  
71    /**
72     * Create a PiOrbitalTorsionPotentialEnergy with the provided name and force group.
73     *
74     * @param name       Name for this term.
75     * @param forceGroup Integer force group identifier.
76     */
77    public PiOrbitalTorsionPotentialEnergy(String name, int forceGroup) {
78      super(name, forceGroup);
79    }
80  
81    /**
82     * Create a PiOrbitalTorsionPotentialEnergy initialized with a list of terms and force group.
83     *
84     * @param name              Name for this term.
85     * @param forceGroup        Force group identifier.
86     * @param piOrbitalTorsions List of PiOrbitalTorsion instances to add (null-safe).
87     */
88    public PiOrbitalTorsionPotentialEnergy(String name, int forceGroup, List<PiOrbitalTorsion> piOrbitalTorsions) {
89      super(name, forceGroup);
90      if (piOrbitalTorsions != null) {
91        Collections.sort(piOrbitalTorsions);
92        this.piOrbitalTorsions.addAll(piOrbitalTorsions);
93        logger.info(String.format("  Pi-Orbital Torsions:               %10d", getNumberOfPiOrbitalTorsions()));
94      }
95    }
96  
97    /**
98     * {@inheritDoc}
99     */
100   @Override
101   public int getNumberOfTerms() {
102     return getNumberOfPiOrbitalTorsions();
103   }
104 
105   /**
106    * {@inheritDoc}
107    */
108   @Override
109   public BondedTerm[] getBondedTermsArray() {
110     return getPiOrbitalTorsionArray();
111   }
112 
113   /**
114    * Create a PiOrbitalTorsionPotentialEnergy initialized with a collection of terms.
115    *
116    * @param name              Name for this term (may be null).
117    * @param piOrbitalTorsions Collection of PiOrbitalTorsion instances to add (null-safe).
118    */
119   public PiOrbitalTorsionPotentialEnergy(String name, Collection<PiOrbitalTorsion> piOrbitalTorsions) {
120     super(name);
121     if (piOrbitalTorsions != null) {
122       this.piOrbitalTorsions.addAll(piOrbitalTorsions);
123     }
124   }
125 
126   /**
127    * Add a PiOrbitalTorsion to this term.
128    *
129    * @param piOrbitalTorsion PiOrbitalTorsion to add (ignored if null).
130    * @return true if it was added.
131    */
132   public boolean addPiOrbitalTorsion(PiOrbitalTorsion piOrbitalTorsion) {
133     if (piOrbitalTorsion == null) {
134       return false;
135     }
136     return piOrbitalTorsions.add(piOrbitalTorsion);
137   }
138 
139   /**
140    * Add an array of PiOrbitalTorsions to this term.
141    *
142    * @param piOrbitalTorsions Array of PiOrbitalTorsion instances to add.
143    * @return true if they were added.
144    */
145   public boolean addPiOrbitalTorsions(PiOrbitalTorsion[] piOrbitalTorsions) {
146     if (piOrbitalTorsions == null) {
147       return false;
148     }
149     Collections.addAll(this.piOrbitalTorsions, piOrbitalTorsions);
150     return true;
151   }
152 
153   /**
154    * Add a list of PiOrbitalTorsions to this term.
155    *
156    * @param piOrbitalTorsions List of PiOrbitalTorsion instances to add.
157    * @return true if they were added.
158    */
159   public boolean addPiOrbitalTorsions(List<PiOrbitalTorsion> piOrbitalTorsions) {
160     if (piOrbitalTorsions == null) {
161       return false;
162     }
163     this.piOrbitalTorsions.addAll(piOrbitalTorsions);
164     return true;
165   }
166 
167   /**
168    * Remove a PiOrbitalTorsion from this term.
169    *
170    * @param piOrbitalTorsion PiOrbitalTorsion to remove (ignored if null).
171    * @return true if it was present and removed.
172    */
173   public boolean removePiOrbitalTorsion(PiOrbitalTorsion piOrbitalTorsion) {
174     if (piOrbitalTorsion == null) {
175       return false;
176     }
177     return piOrbitalTorsions.remove(piOrbitalTorsion);
178   }
179 
180   /**
181    * Get the PiOrbitalTorsion at a given index.
182    *
183    * @param index Index in the internal list.
184    * @return PiOrbitalTorsion at the specified index.
185    * @throws IndexOutOfBoundsException if index is invalid.
186    */
187   public PiOrbitalTorsion getPiOrbitalTorsion(int index) {
188     return piOrbitalTorsions.get(index);
189   }
190 
191   /**
192    * Get an unmodifiable view of the PiOrbitalTorsions in this term.
193    *
194    * @return Unmodifiable List of PiOrbitalTorsions.
195    */
196   public List<PiOrbitalTorsion> getPiOrbitalTorsions() {
197     return Collections.unmodifiableList(piOrbitalTorsions);
198   }
199 
200   /**
201    * Get an array of PiOrbitalTorsions in this term.
202    *
203    * @return Array of PiOrbitalTorsions.
204    */
205   public PiOrbitalTorsion[] getPiOrbitalTorsionArray() {
206     return piOrbitalTorsions.toArray(new PiOrbitalTorsion[0]);
207   }
208 
209   /**
210    * Get the number of PiOrbitalTorsions in this term.
211    *
212    * @return The number of PiOrbitalTorsions.
213    */
214   public int getNumberOfPiOrbitalTorsions() {
215     return piOrbitalTorsions.size();
216   }
217 
218   /**
219    * Set the lambda value for all Pi-Orbital Torsions in this term.
220    *
221    * @param lambda Lambda value to set for all  Pi-Orbital Torsions.
222    */
223   public void setLambda(double lambda) {
224     for (PiOrbitalTorsion piOrbitalTorsion : piOrbitalTorsions) {
225       piOrbitalTorsion.setLambda(lambda);
226     }
227   }
228 
229   /**
230    * Get the energy contribution from all Pi-Orbital Torsions in this term.
231    *
232    * @return Total energy from all Pi-Orbital Torsions.
233    */
234   public double getdEdL() {
235     double dEdL = 0.0;
236     for (PiOrbitalTorsion piOrbitalTorsion : piOrbitalTorsions) {
237       dEdL += piOrbitalTorsion.getdEdL();
238     }
239     return dEdL;
240   }
241 
242   /**
243    * Get the energy contribution from all Torsions in this term.
244    *
245    * @return Total energy from all Pi-Orbital Torsions.
246    */
247   public double getd2EdL2() {
248     double d2EdLambda2 = 0.0;
249     for (PiOrbitalTorsion piOrbitalTorsion : piOrbitalTorsions) {
250       d2EdLambda2 += piOrbitalTorsion.getd2EdL2();
251     }
252     return d2EdLambda2;
253   }
254 
255   public static String getPiOrbitalTorsionEnergyString() {
256     String energy = """
257         2*k*sin(phi)^2;
258         phi = pointdihedral(x3+c1x, y3+c1y, z3+c1z, x3, y3, z3, x4, y4, z4, x4+c2x, y4+c2y, z4+c2z);
259         c1x = (d14y*d24z-d14z*d24y);
260         c1y = (d14z*d24x-d14x*d24z);
261         c1z = (d14x*d24y-d14y*d24x);
262         c2x = (d53y*d63z-d53z*d63y);
263         c2y = (d53z*d63x-d53x*d63z);
264         c2z = (d53x*d63y-d53y*d63x);
265         d14x = x1-x4;
266         d14y = y1-y4;
267         d14z = z1-z4;
268         d24x = x2-x4;
269         d24y = y2-y4;
270         d24z = z2-z4;
271         d53x = x5-x3;
272         d53y = y5-y3;
273         d53z = z5-z3;
274         d63x = x6-x3;
275         d63y = y6-y3;
276         d63z = z6-z3;
277         """;
278     return energy;
279   }
280 
281   /**
282    * Log the details of Pi-Orbital Torsion interactions.
283    */
284   @Override
285   public void log() {
286     if (getNumberOfPiOrbitalTorsions() <= 0) {
287       return;
288     }
289     logger.info("\n Pi-Orbital Torsion Interactions:");
290     for (PiOrbitalTorsion piOrbitalTorsion : getPiOrbitalTorsions()) {
291       logger.info(" Pi-Torsion \t" + piOrbitalTorsion.toString());
292     }
293   }
294 
295   @Override
296   public String toPDBString() {
297     if (getNumberOfPiOrbitalTorsions() <= 0) {
298       return "";
299     }
300     return String.format("REMARK   3   %s %g (%d)\n", "PI-ORBITAL TORSION         : ", getEnergy(), getNumberOfPiOrbitalTorsions());
301   }
302 
303   @Override
304   public String toString() {
305     return String.format("  %s %20.8f %12d %12.3f\n", "Pi-Orbital Torsion",
306         getEnergy(), getNumberOfPiOrbitalTorsions(), getTime());
307   }
308 }