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.AngleTorsion;
41 import ffx.potential.bonded.BondedTerm;
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 import static java.lang.String.format;
50
51 /**
52 * Angle-Torsion potential energy term using {@link ffx.potential.bonded.AngleTorsion} instances.
53 */
54 public class AngleTorsionPotentialEnergy extends EnergyTerm {
55
56 private static final Logger logger = Logger.getLogger(AngleTorsionPotentialEnergy.class.getName());
57
58
59 /**
60 * Internal list of AngleTorsion instances.
61 */
62 private final List<AngleTorsion> angleTorsions = new ArrayList<>();
63
64 /**
65 * Create an AngleTorsionPotentialEnergy with the provided name.
66 *
67 * @param name Name for this term.
68 */
69 public AngleTorsionPotentialEnergy(String name) {
70 super(name);
71 }
72
73 /**
74 * Create an AngleTorsionPotentialEnergy with the provided name and force group.
75 *
76 * @param name Name for this term.
77 * @param forceGroup Integer force group identifier.
78 */
79 public AngleTorsionPotentialEnergy(String name, int forceGroup) {
80 super(name, forceGroup);
81 }
82
83 /**
84 * Create an AngleTorsionPotentialEnergy initialized with a list of terms and force group.
85 *
86 * @param name Name for this term.
87 * @param forceGroup Force group identifier.
88 * @param angleTorsions List of AngleTorsion instances to add (null-safe).
89 */
90 public AngleTorsionPotentialEnergy(String name, int forceGroup, List<AngleTorsion> angleTorsions) {
91 super(name, forceGroup);
92 if (angleTorsions != null) {
93 Collections.sort(angleTorsions);
94 this.angleTorsions.addAll(angleTorsions);
95 logger.info(format(" Angle-Torsions: %10d", getNumberOfAngleTorsions()));
96 }
97 }
98
99 /**
100 * {@inheritDoc}
101 */
102 @Override
103 public int getNumberOfTerms() {
104 return getNumberOfAngleTorsions();
105 }
106
107 /**
108 * {@inheritDoc}
109 */
110 @Override
111 public BondedTerm[] getBondedTermsArray() {
112 return getAngleTorsionArray();
113 }
114
115 /**
116 * Create an AngleTorsionPotentialEnergy initialized with a collection of terms.
117 *
118 * @param name Name for this term (may be null).
119 * @param angleTorsions Collection of AngleTorsion instances to add (null-safe).
120 */
121 public AngleTorsionPotentialEnergy(String name, Collection<AngleTorsion> angleTorsions) {
122 super(name);
123 if (angleTorsions != null) {
124 this.angleTorsions.addAll(angleTorsions);
125 }
126 }
127
128 /**
129 * Add an AngleTorsion to this term.
130 *
131 * @param angleTorsion AngleTorsion to add (ignored if null).
132 * @return true if it was added.
133 */
134 public boolean addAngleTorsion(AngleTorsion angleTorsion) {
135 if (angleTorsion == null) {
136 return false;
137 }
138 return angleTorsions.add(angleTorsion);
139 }
140
141 /**
142 * Add an array of AngleTorsions to this term.
143 *
144 * @param angleTorsions Array of AngleTorsion instances to add.
145 * @return true if they were added.
146 */
147 public boolean addAngleTorsions(AngleTorsion[] angleTorsions) {
148 if (angleTorsions == null) {
149 return false;
150 }
151 Collections.addAll(this.angleTorsions, angleTorsions);
152 return true;
153 }
154
155 /**
156 * Add a list of AngleTorsions to this term.
157 *
158 * @param angleTorsions List of AngleTorsion instances to add.
159 * @return true if they were added.
160 */
161 public boolean addAngleTorsions(List<AngleTorsion> angleTorsions) {
162 if (angleTorsions == null) {
163 return false;
164 }
165 this.angleTorsions.addAll(angleTorsions);
166 return true;
167 }
168
169 /**
170 * Remove an AngleTorsion from this term.
171 *
172 * @param angleTorsion AngleTorsion to remove (ignored if null).
173 * @return true if it was present and removed.
174 */
175 public boolean removeAngleTorsion(AngleTorsion angleTorsion) {
176 if (angleTorsion == null) {
177 return false;
178 }
179 return angleTorsions.remove(angleTorsion);
180 }
181
182 /**
183 * Get the AngleTorsion at a given index.
184 *
185 * @param index Index in the internal list.
186 * @return AngleTorsion at the specified index.
187 * @throws IndexOutOfBoundsException if index is invalid.
188 */
189 public AngleTorsion getAngleTorsion(int index) {
190 return angleTorsions.get(index);
191 }
192
193 /**
194 * Get an unmodifiable view of the AngleTorsions in this term.
195 *
196 * @return Unmodifiable List of AngleTorsions.
197 */
198 public List<AngleTorsion> getAngleTorsions() {
199 return Collections.unmodifiableList(angleTorsions);
200 }
201
202 /**
203 * Get an array of AngleTorsions in this term.
204 *
205 * @return Array of AngleTorsions.
206 */
207 public AngleTorsion[] getAngleTorsionArray() {
208 return angleTorsions.toArray(new AngleTorsion[0]);
209 }
210
211 /**
212 * Get the number of AngleTorsions in this term.
213 *
214 * @return The number of AngleTorsions.
215 */
216 public int getNumberOfAngleTorsions() {
217 return angleTorsions.size();
218 }
219
220 /**
221 * Log the details of Angle-Torsion interactions.
222 */
223 @Override
224 public void log() {
225 if (getNumberOfAngleTorsions() <= 0) {
226 return;
227 }
228 logger.info("\n Angle-Torsion Interactions:");
229 for (AngleTorsion angleTorsion : getAngleTorsions()) {
230 logger.info(" Angle-Torsion \t" + angleTorsion.toString());
231 }
232 }
233
234 @Override
235 public String toPDBString() {
236 if (getNumberOfAngleTorsions() <= 0) {
237 return "";
238 }
239 return format("REMARK 3 %s %g (%d)\n", "ANGLE-TORSION : ", getEnergy(), getNumberOfAngleTorsions());
240 }
241
242 @Override
243 public String toString() {
244 return format(" %s %20.8f %12d %12.3f\n", "Angle-Torsion ",
245 getEnergy(), getNumberOfAngleTorsions(), getTime());
246 }
247 }