1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.potential.terms;
39
40 import ffx.potential.bonded.Angle;
41 import ffx.potential.bonded.BondedTerm;
42 import ffx.potential.parameters.AngleType;
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
54
55
56
57
58 public class AnglePotentialEnergy extends EnergyTerm {
59
60 private static final Logger logger = Logger.getLogger(AnglePotentialEnergy.class.getName());
61
62
63
64
65 private final List<Angle> angles = new ArrayList<>();
66
67
68
69
70
71
72 public AnglePotentialEnergy(String name) {
73 super(name);
74 }
75
76
77
78
79
80
81
82 public AnglePotentialEnergy(String name, int forceGroup) {
83 super(name, forceGroup);
84 }
85
86
87
88
89
90
91
92
93 public AnglePotentialEnergy(String name, int forceGroup, List<Angle> angles) {
94 super(name, forceGroup);
95 if (angles != null) {
96 Collections.sort(angles);
97 this.angles.addAll(angles);
98 logger.info(format(" Angles: %10d", getNumberOfAngles()));
99 }
100 }
101
102
103
104
105
106
107 @Override
108 public int getNumberOfTerms() {
109 return getNumberOfAngles();
110 }
111
112
113
114
115
116
117 @Override
118 public BondedTerm[] getBondedTermsArray() {
119 return getAngleArray();
120 }
121
122
123
124
125
126
127
128 public AnglePotentialEnergy(String name, Collection<Angle> angles) {
129 super(name);
130 if (angles != null) {
131 this.angles.addAll(angles);
132 }
133 }
134
135
136
137
138
139
140
141 public boolean addAngle(Angle angle) {
142 if (angle == null) {
143 return false;
144 }
145 return angles.add(angle);
146 }
147
148
149
150
151
152
153
154 public boolean addAngles(Angle[] angles) {
155 if (angles == null) {
156 return false;
157 }
158 Collections.addAll(this.angles, angles);
159 return true;
160 }
161
162
163
164
165
166
167
168 public boolean addAngles(List<Angle> angles) {
169 if (angles == null) {
170 return false;
171 }
172 this.angles.addAll(angles);
173 return true;
174 }
175
176
177
178
179
180
181
182 public boolean removeAngle(Angle angle) {
183 if (angle == null) {
184 return false;
185 }
186 return angles.remove(angle);
187 }
188
189
190
191
192
193
194
195
196 public Angle getAngle(int index) {
197 return angles.get(index);
198 }
199
200
201
202
203
204
205 public List<Angle> getAngles() {
206 return Collections.unmodifiableList(angles);
207 }
208
209
210
211
212
213
214 public Angle[] getAngleArray() {
215 return angles.toArray(new Angle[0]);
216 }
217
218
219
220
221
222
223 public int getNumberOfAngles() {
224 return angles.size();
225 }
226
227
228
229
230
231 public String getAngleEnergyString() {
232 AngleType angleType = angles.getFirst().angleType;
233 String energy;
234 if (angleType.angleFunction == AngleType.AngleFunction.SEXTIC) {
235 energy = format("""
236 k*(d^2 + %.15g*d^3 + %.15g*d^4 + %.15g*d^5 + %.15g*d^6);
237 d=%.15g*theta-theta0;
238 """,
239 angleType.cubic, angleType.quartic, angleType.pentic, angleType.sextic, 180.0 / PI);
240 } else {
241 energy = format("""
242 k*(d^2);
243 d=%.15g*theta-theta0;
244 """,
245 180.0 / PI);
246 }
247 return energy;
248 }
249
250 public String getInPlaneAngleEnergyString() {
251 AngleType angleType = angles.getFirst().angleType;
252 String energy = format("""
253 k*(d^2 + %.15g*d^3 + %.15g*d^4 + %.15g*d^5 + %.15g*d^6);
254 d=theta-theta0;
255 theta = %.15g*pointangle(x1, y1, z1, projx, projy, projz, x3, y3, z3);
256 projx = x2-nx*dot;
257 projy = y2-ny*dot;
258 projz = z2-nz*dot;
259 dot = nx*(x2-x3) + ny*(y2-y3) + nz*(z2-z3);
260 nx = px/norm;
261 ny = py/norm;
262 nz = pz/norm;
263 norm = sqrt(px*px + py*py + pz*pz);
264 px = (d1y*d2z-d1z*d2y);
265 py = (d1z*d2x-d1x*d2z);
266 pz = (d1x*d2y-d1y*d2x);
267 d1x = x1-x4;
268 d1y = y1-y4;
269 d1z = z1-z4;
270 d2x = x3-x4;
271 d2y = y3-y4;
272 d2z = z3-z4;
273 """,
274 angleType.cubic, angleType.quartic, angleType.pentic, angleType.sextic, 180.0 / PI);
275 return energy;
276 }
277
278
279
280
281 @Override
282 public void log() {
283 if (getNumberOfAngles() <= 0) {
284 return;
285 }
286 logger.info("\n Angle Bending Interactions:");
287 for (Angle angle : getAngles()) {
288 logger.info(" Angle \t" + angle.toString());
289 }
290 }
291
292 @Override
293 public String toPDBString() {
294 if (getNumberOfAngles() <= 0) {
295 return "";
296 }
297 StringBuilder sb = new StringBuilder();
298 sb.append(format("REMARK 3 %s %g (%d)\n", "ANGLE BENDING : ", getEnergy(), getNumberOfAngles()));
299 sb.append(format("REMARK 3 %s %g\n", "ANGLE RMSD : ", getRMSD()));
300 return sb.toString();
301 }
302
303 @Override
304 public String toString() {
305 return format(" %s %20.8f %12d %12.3f (%8.5f)\n", "Angle Bending ",
306 getEnergy(), getNumberOfAngles(), getTime(), getRMSD());
307 }
308
309 }