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 }