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 edu.rit.pj.IntegerForLoop;
41 import edu.rit.pj.IntegerSchedule;
42 import edu.rit.pj.ParallelRegion;
43 import edu.rit.pj.ParallelTeam;
44 import ffx.numerics.Potential;
45 import ffx.numerics.atomic.AtomicDoubleArray;
46 import ffx.numerics.atomic.AtomicDoubleArray3D;
47 import ffx.potential.MolecularAssembly;
48 import ffx.potential.bonded.Atom;
49 import ffx.potential.bonded.BondedTerm;
50 import ffx.potential.parameters.ForceField;
51
52 import java.util.ArrayList;
53 import java.util.Collections;
54 import java.util.List;
55 import java.util.logging.Logger;
56
57 import static ffx.potential.parameters.ForceField.toEnumForm;
58 import static java.lang.String.format;
59
60 public class EnergyTermRegion extends ParallelRegion {
61
62 private static final Logger logger = Logger.getLogger(EnergyTermRegion.class.getName());
63
64
65
66
67 private final Atom[] atoms;
68
69
70
71 private final int nAtoms;
72
73
74
75 private boolean gradient = false;
76
77
78
79 private boolean initAtomGradients = true;
80
81
82
83
84
85 private Potential.STATE state = Potential.STATE.BOTH;
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 protected boolean checkAlchemicalAtoms = true;
108
109
110
111 protected boolean lambdaBondedTerms = false;
112
113
114
115 protected boolean lambdaAllBondedTerms = false;
116
117
118
119 private final List<EnergyTerm> energyTerms = new ArrayList<>();
120
121
122
123 private final BondedTermLoop[] bondedTermLoops;
124
125
126
127 private final GradInitLoop[] gradInitLoops;
128
129
130
131 private final GradReduceLoop[] gradReduceLoops;
132
133
134
135 private final AtomicDoubleArray3D grad;
136
137
138
139
140 private final AtomicDoubleArray3D lambdaGrad;
141
142
143
144
145
146
147
148
149 public EnergyTermRegion(ParallelTeam parallelTeam,
150 MolecularAssembly molecularAssembly,
151 boolean lambdaTerm) {
152 this.atoms = molecularAssembly.getAtomArray();
153 this.nAtoms = atoms.length;
154
155
156 AtomicDoubleArray.AtomicDoubleArrayImpl atomicDoubleArrayImpl = AtomicDoubleArray.AtomicDoubleArrayImpl.MULTI;
157 ForceField forceField = molecularAssembly.getForceField();
158
159 int nThreads = parallelTeam.getThreadCount();
160 bondedTermLoops = new BondedTermLoop[nThreads];
161 gradInitLoops = new GradInitLoop[nThreads];
162 gradReduceLoops = new GradReduceLoop[nThreads];
163 for (int i = 0; i < nThreads; i++) {
164 bondedTermLoops[i] = new BondedTermLoop();
165 gradInitLoops[i] = new GradInitLoop();
166 gradReduceLoops[i] = new GradReduceLoop();
167 }
168
169 String value = forceField.getString("ARRAY_REDUCTION", "MULTI");
170 try {
171 atomicDoubleArrayImpl = AtomicDoubleArray.AtomicDoubleArrayImpl.valueOf(toEnumForm(value));
172 } catch (Exception e) {
173 logger.info(format(" Unrecognized ARRAY-REDUCTION %s; defaulting to %s", value,
174 atomicDoubleArrayImpl));
175 }
176 logger.fine(format(" Bonded using %s arrays.", atomicDoubleArrayImpl));
177
178 int nAtoms = molecularAssembly.getAtomArray().length;
179 grad = new AtomicDoubleArray3D(atomicDoubleArrayImpl, nAtoms, nThreads);
180 if (lambdaTerm) {
181 lambdaGrad = new AtomicDoubleArray3D(atomicDoubleArrayImpl, nAtoms, nThreads);
182 } else {
183 lambdaGrad = null;
184 }
185 }
186
187 public void setCheckAlchemicalAtoms(boolean checkAlchemicalAtoms) {
188 this.checkAlchemicalAtoms = checkAlchemicalAtoms;
189 }
190
191 public boolean getCheckAlchemicalAtoms() {
192 return checkAlchemicalAtoms;
193 }
194
195 public void setLambdaBondedTerms(boolean lambdaBondedTerms) {
196 this.lambdaBondedTerms = lambdaBondedTerms;
197 }
198
199 public boolean getLambdaBondedTerms() {
200 return lambdaBondedTerms;
201 }
202
203 public void setLambdaAllBondedTerms(boolean lambdaAllBondedTerms) {
204 this.lambdaAllBondedTerms = lambdaAllBondedTerms;
205 }
206
207 public boolean getLambdaAllBondedTerms() {
208 return lambdaAllBondedTerms;
209 }
210
211 public void setInitAtomGradients(boolean initAtomGradients) {
212 this.initAtomGradients = initAtomGradients;
213 }
214
215 public boolean getInitAtomGradients() {
216 return initAtomGradients;
217 }
218
219
220
221
222
223
224 public double getEnergy() {
225 double energy = 0.0;
226 for (EnergyTerm term : energyTerms) {
227 energy += term.getEnergy();
228 }
229 return energy;
230 }
231
232
233
234
235 public void log() {
236 for (EnergyTerm term : energyTerms) {
237 term.log();
238 }
239 }
240
241
242
243
244
245
246 public String toString() {
247 StringBuilder sb = new StringBuilder();
248 for (EnergyTerm term : energyTerms) {
249 sb.append(term.toString());
250 }
251 return sb.toString();
252 }
253
254
255
256
257
258
259 public String toPDBString() {
260 StringBuilder sb = new StringBuilder();
261 for (EnergyTerm term : energyTerms) {
262 sb.append(term.toPDBString());
263 }
264 return sb.toString();
265 }
266
267
268
269
270
271
272 public void setState(Potential.STATE state) {
273 if (state == null) {
274 throw new IllegalArgumentException("Potential state cannot be null.");
275 }
276 this.state = state;
277 }
278
279
280
281
282
283
284 public void setGradient(boolean gradient) {
285 this.gradient = gradient;
286 }
287
288
289
290
291
292
293 public boolean getGradient() {
294 return gradient;
295 }
296
297
298
299
300
301
302
303 public boolean addEnergyTerm(EnergyTerm term) {
304 if (term == null) {
305 return false;
306 }
307 return energyTerms.add(term);
308 }
309
310
311
312
313
314
315
316 public boolean removeEnergyTerm(EnergyTerm term) {
317 if (term == null) {
318 return false;
319 }
320 return energyTerms.remove(term);
321 }
322
323
324
325
326
327
328
329
330 public EnergyTerm getEnergyTerm(int index) {
331 return energyTerms.get(index);
332 }
333
334
335
336
337
338
339 public List<EnergyTerm> getEnergyTerms() {
340 return Collections.unmodifiableList(energyTerms);
341 }
342
343 @Override
344 public void start() {
345
346 for (EnergyTerm term : energyTerms) {
347 term.setEnergy(0.0);
348 term.setRMSD(0.0);
349 }
350 }
351
352 @Override
353 public void run() throws Exception {
354 int threadIndex = getThreadIndex();
355
356
357 if (gradient) {
358 execute(0, nAtoms - 1, gradInitLoops[threadIndex]);
359 }
360
361
362 if (state == Potential.STATE.BOTH || state == Potential.STATE.FAST) {
363
364 BondedTermLoop bondedTermLoop = bondedTermLoops[threadIndex];
365 for (EnergyTerm term : energyTerms) {
366 if (threadIndex == 0) {
367 term.startTime();
368 }
369 bondedTermLoop.setEnergyTerm(term);
370 execute(0, term.getNumberOfTerms() - 1, bondedTermLoop);
371 if (threadIndex == 0) {
372 term.stopTime();
373 }
374 }
375 }
376
377
378 if (gradient) {
379 execute(0, nAtoms - 1, gradReduceLoops[threadIndex]);
380 }
381
382 }
383
384 private class BondedTermLoop extends IntegerForLoop {
385
386 private EnergyTerm energyTerm;
387
388 public void setEnergyTerm(EnergyTerm terms) {
389 this.energyTerm = terms;
390 }
391
392 @Override
393 public void run(int first, int last) {
394 int threadIndex = getThreadIndex();
395 double localEnergy = 0.0;
396 double localRMSD = 0.0;
397
398 BondedTerm[] bondedTerms = energyTerm.getBondedTermsArray();
399 for (int i = first; i <= last; i++) {
400 BondedTerm term = bondedTerms[i];
401 boolean used = true;
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418 if (checkAlchemicalAtoms) {
419 used = !lambdaBondedTerms || lambdaAllBondedTerms || (term.applyLambda() && !term.isLambdaScaled());
420 }
421 if (used) {
422 localEnergy += term.energy(gradient, threadIndex, grad, lambdaGrad);
423 double value = term.getValue();
424 localRMSD += value * value;
425 }
426 }
427
428 energyTerm.addAndGetEnergy(localEnergy);
429 energyTerm.addAndGetRMSD(localRMSD);
430 }
431
432 }
433
434 private class GradInitLoop extends IntegerForLoop {
435
436 @Override
437 public void run(int first, int last) {
438 int threadID = getThreadIndex();
439 if (gradient) {
440 grad.reset(threadID, first, last);
441 if (initAtomGradients) {
442 for (int i = first; i <= last; i++) {
443 atoms[i].setXYZGradient(0.0, 0.0, 0.0);
444 }
445 }
446 }
447 if (lambdaGrad != null) {
448 lambdaGrad.reset(threadID, first, last);
449 if (initAtomGradients) {
450 for (int i = first; i <= last; i++) {
451 atoms[i].setLambdaXYZGradient(0.0, 0.0, 0.0);
452 }
453 }
454 }
455 }
456
457 @Override
458 public IntegerSchedule schedule() {
459 return IntegerSchedule.fixed();
460 }
461 }
462
463 private class GradReduceLoop extends IntegerForLoop {
464
465 @Override
466 public void run(int first, int last) {
467 if (gradient) {
468 grad.reduce(first, last);
469 for (int i = first; i <= last; i++) {
470 Atom a = atoms[i];
471 a.addToXYZGradient(grad.getX(i), grad.getY(i), grad.getZ(i));
472 }
473 }
474 if (lambdaGrad != null) {
475 lambdaGrad.reduce(first, last);
476 for (int i = first; i <= last; i++) {
477 Atom a = atoms[i];
478 a.addToLambdaXYZGradient(lambdaGrad.getX(i), lambdaGrad.getY(i), lambdaGrad.getZ(i));
479 }
480 }
481 }
482
483 @Override
484 public IntegerSchedule schedule() {
485 return IntegerSchedule.fixed();
486 }
487 }
488 }