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.OutOfPlaneBend;
42  import ffx.potential.parameters.OutOfPlaneBendType;
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  import static java.lang.String.format;
50  import static org.apache.commons.math3.util.FastMath.PI;
51  
52  /**
53   * Out-of-Plane Bend potential energy term using {@link ffx.potential.bonded.OutOfPlaneBend} instances.
54   */
55  public class OutOfPlaneBendPotentialEnergy extends EnergyTerm {
56  
57    private static final Logger logger = Logger.getLogger(OutOfPlaneBendPotentialEnergy.class.getName());
58  
59  
60    /**
61     * Internal list of OutOfPlaneBend instances.
62     */
63    private final List<OutOfPlaneBend> outOfPlaneBends = new ArrayList<>();
64  
65    /**
66     * Create an OutOfPlaneBendPotentialEnergy with the provided name.
67     *
68     * @param name Name for this term.
69     */
70    public OutOfPlaneBendPotentialEnergy(String name) {
71      super(name);
72    }
73  
74    /**
75     * Create an OutOfPlaneBendPotentialEnergy with the provided name and force group.
76     *
77     * @param name       Name for this term.
78     * @param forceGroup Integer force group identifier.
79     */
80    public OutOfPlaneBendPotentialEnergy(String name, int forceGroup) {
81      super(name, forceGroup);
82    }
83  
84    /**
85     * Create an OutOfPlaneBendPotentialEnergy initialized with a list of terms and force group.
86     *
87     * @param name            Name for this term.
88     * @param forceGroup      Force group identifier.
89     * @param outOfPlaneBends List of OutOfPlaneBend instances to add (null-safe).
90     */
91    public OutOfPlaneBendPotentialEnergy(String name, int forceGroup, List<OutOfPlaneBend> outOfPlaneBends) {
92      super(name, forceGroup);
93      if (outOfPlaneBends != null) {
94        Collections.sort(outOfPlaneBends);
95        this.outOfPlaneBends.addAll(outOfPlaneBends);
96        logger.info(format("  Out-of-Plane Bends:                %10d", getNumberOfOutOfPlaneBends()));
97      }
98    }
99  
100   /**
101    * {@inheritDoc}
102    */
103   @Override
104   public int getNumberOfTerms() {
105     return getNumberOfOutOfPlaneBends();
106   }
107 
108   /**
109    * {@inheritDoc}
110    */
111   @Override
112   public BondedTerm[] getBondedTermsArray() {
113     return getOutOfPlaneBendArray();
114   }
115 
116   /**
117    * Create an OutOfPlaneBendPotentialEnergy initialized with a collection of terms.
118    *
119    * @param name            Name for this term (may be null).
120    * @param outOfPlaneBends Collection of OutOfPlaneBend instances to add (null-safe).
121    */
122   public OutOfPlaneBendPotentialEnergy(String name, Collection<OutOfPlaneBend> outOfPlaneBends) {
123     super(name);
124     if (outOfPlaneBends != null) {
125       this.outOfPlaneBends.addAll(outOfPlaneBends);
126     }
127   }
128 
129   /**
130    * Add an OutOfPlaneBend to this term.
131    *
132    * @param outOfPlaneBend OutOfPlaneBend to add (ignored if null).
133    * @return true if it was added.
134    */
135   public boolean addOutOfPlaneBend(OutOfPlaneBend outOfPlaneBend) {
136     if (outOfPlaneBend == null) {
137       return false;
138     }
139     return outOfPlaneBends.add(outOfPlaneBend);
140   }
141 
142   /**
143    * Add an array of OutOfPlaneBends to this term.
144    *
145    * @param outOfPlaneBends Array of OutOfPlaneBend instances to add.
146    * @return true if they were added.
147    */
148   public boolean addOutOfPlaneBends(OutOfPlaneBend[] outOfPlaneBends) {
149     if (outOfPlaneBends == null) {
150       return false;
151     }
152     Collections.addAll(this.outOfPlaneBends, outOfPlaneBends);
153     return true;
154   }
155 
156   /**
157    * Add a list of OutOfPlaneBends to this term.
158    *
159    * @param outOfPlaneBends List of OutOfPlaneBend instances to add.
160    * @return true if they were added.
161    */
162   public boolean addOutOfPlaneBends(List<OutOfPlaneBend> outOfPlaneBends) {
163     if (outOfPlaneBends == null) {
164       return false;
165     }
166     this.outOfPlaneBends.addAll(outOfPlaneBends);
167     return true;
168   }
169 
170   /**
171    * Remove an OutOfPlaneBend from this term.
172    *
173    * @param outOfPlaneBend OutOfPlaneBend to remove (ignored if null).
174    * @return true if it was present and removed.
175    */
176   public boolean removeOutOfPlaneBend(OutOfPlaneBend outOfPlaneBend) {
177     if (outOfPlaneBend == null) {
178       return false;
179     }
180     return outOfPlaneBends.remove(outOfPlaneBend);
181   }
182 
183   /**
184    * Get the OutOfPlaneBend at a given index.
185    *
186    * @param index Index in the internal list.
187    * @return OutOfPlaneBend at the specified index.
188    * @throws IndexOutOfBoundsException if index is invalid.
189    */
190   public OutOfPlaneBend getOutOfPlaneBend(int index) {
191     return outOfPlaneBends.get(index);
192   }
193 
194   /**
195    * Get an unmodifiable view of the OutOfPlaneBends in this term.
196    *
197    * @return Unmodifiable List of OutOfPlaneBends.
198    */
199   public List<OutOfPlaneBend> getOutOfPlaneBends() {
200     return Collections.unmodifiableList(outOfPlaneBends);
201   }
202 
203   /**
204    * Get an array of OutOfPlaneBends in this term.
205    *
206    * @return Array of OutOfPlaneBends.
207    */
208   public OutOfPlaneBend[] getOutOfPlaneBendArray() {
209     return outOfPlaneBends.toArray(new OutOfPlaneBend[0]);
210   }
211 
212   /**
213    * Get the number of OutOfPlaneBends in this term.
214    *
215    * @return The number of OutOfPlaneBends.
216    */
217   public int getNumberOfOutOfPlaneBends() {
218     return outOfPlaneBends.size();
219   }
220 
221 
222   /**
223    * Get a string representation of the Out-of-Plane Bend energy expression.
224    * @return A formatted string representing the energy expression for Out-of-Plane Bends.
225    */
226   public String getOutOfPlaneEnergyString() {
227     OutOfPlaneBendType outOfPlaneBendType = outOfPlaneBends.getFirst().outOfPlaneBendType;
228     String energy = format(""" 
229             k*(theta^2 + %.15g*theta^3 + %.15g*theta^4 + %.15g*theta^5 + %.15g*theta^6);
230             theta = %.15g*pointangle(x2, y2, z2, x4, y4, z4, projx, projy, projz);
231             projx = x2-nx*dot;
232             projy = y2-ny*dot;
233             projz = z2-nz*dot;
234             dot = nx*(x2-x3) + ny*(y2-y3) + nz*(z2-z3);
235             nx = px/norm;
236             ny = py/norm;
237             nz = pz/norm;
238             norm = sqrt(px*px + py*py + pz*pz);
239             px = (d1y*d2z-d1z*d2y);
240             py = (d1z*d2x-d1x*d2z);
241             pz = (d1x*d2y-d1y*d2x);
242             d1x = x1-x4;
243             d1y = y1-y4;
244             d1z = z1-z4;
245             d2x = x3-x4;
246             d2y = y3-y4;
247             d2z = z3-z4
248             """,
249         outOfPlaneBendType.cubic, outOfPlaneBendType.quartic,
250         outOfPlaneBendType.pentic, outOfPlaneBendType.sextic, 180.0 / PI);
251     return energy;
252   }
253 
254   /**
255    * Log the details of Out-of-Plane Bend interactions.
256    */
257   @Override
258   public void log() {
259     if (getNumberOfOutOfPlaneBends() <= 0) {
260       return;
261     }
262     logger.info("\n Out-of-Plane Bend Interactions:");
263     for (OutOfPlaneBend outOfPlaneBend : getOutOfPlaneBends()) {
264       logger.info(" Out-of-Plane Bend \t" + outOfPlaneBend.toString());
265     }
266   }
267 
268   @Override
269   public String toPDBString() {
270     if (getNumberOfOutOfPlaneBends() <= 0) {
271       return "";
272     }
273     return format("REMARK   3   %s %g (%d)\n", "OUT-OF-PLANE BEND          : ", getEnergy(), getNumberOfOutOfPlaneBends());
274   }
275 
276   @Override
277   public String toString() {
278     return format("  %s %20.8f %12d %12.3f\n", "Out-of-Plane Bend ",
279         getEnergy(), getNumberOfOutOfPlaneBends(), getTime());
280   }
281 }