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.bonded;
39
40 import org.jogamp.java3d.BranchGroup;
41 import org.jogamp.java3d.Canvas3D;
42 import org.jogamp.java3d.J3DGraphics2D;
43 import org.jogamp.java3d.Material;
44 import org.jogamp.java3d.Node;
45 import org.jogamp.vecmath.Color3f;
46
47 import javax.swing.tree.DefaultMutableTreeNode;
48 import javax.swing.tree.TreeNode;
49 import java.io.Serial;
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.Enumeration;
53 import java.util.List;
54 import java.util.Objects;
55
56
57
58
59
60
61
62 @SuppressWarnings("CloneableImplementsClone")
63 public class MSNode extends DefaultMutableTreeNode implements ROLS {
64
65 @Serial
66 private static final long serialVersionUID = 1L;
67
68
69 private final int MultiScaleLevel;
70
71 protected boolean selected = false;
72
73 private String name;
74
75 private double totalMass;
76
77
78 public MSNode() {
79 name = "";
80 MultiScaleLevel = ROLS.MaxLengthScale;
81 }
82
83
84
85
86
87
88 public MSNode(String n) {
89 name = n;
90 MultiScaleLevel = ROLS.MaxLengthScale;
91 }
92
93
94
95
96
97
98
99 public MSNode(String n, int multiScaleLevel) {
100 this.name = n;
101 this.MultiScaleLevel = multiScaleLevel;
102 }
103
104
105
106
107
108
109
110
111 public MSNode contains(MSNode msNode) {
112 @SuppressWarnings("unchecked")
113 Enumeration<TreeNode> e = depthFirstEnumeration();
114 List<TreeNode> list = Collections.list(e);
115 for (TreeNode node : list) {
116 if (node.equals(msNode)) {
117 return (MSNode) node;
118 }
119 }
120 return null;
121 }
122
123
124
125
126
127
128 public boolean destroy() {
129 if (getParent() != null) {
130 removeFromParent();
131 }
132 name = null;
133 selected = false;
134 return true;
135 }
136
137
138 @Override
139 public void drawLabel(Canvas3D graphics, J3DGraphics2D g2d, Node node) {
140 if (!isSelected()) {
141 return;
142 }
143 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
144 MSNode dataNode = (MSNode) e.nextElement();
145 dataNode.drawLabel(graphics, g2d, node);
146 }
147 }
148
149
150
151
152
153
154
155 @Override
156 public boolean equals(Object o) {
157 if (this == o) {
158 return true;
159 }
160 if (o == null || getClass() != o.getClass()) {
161 return false;
162 }
163 MSNode msNode = (MSNode) o;
164 return Objects.equals(name, msNode.getName());
165 }
166
167
168
169
170
171
172 public List<Angle> getAngleList() {
173 return getList(Angle.class);
174 }
175
176
177
178
179
180
181 public List<AngleTorsion> getAngleTorsionList() {
182 return getList(AngleTorsion.class);
183 }
184
185
186
187
188
189
190 public List<Atom> getAtomList() {
191 List<Atom> atomList = getList(Atom.class);
192 Collections.sort(atomList);
193 return atomList;
194 }
195
196
197
198
199
200
201
202 public Atom getFirstActiveHeavyAtom() {
203 List<Atom> atomList = getAtomList();
204 for (Atom atom : atomList) {
205 if (atom.isHeavy() && atom.isActive()) {
206 return atom;
207 }
208 }
209 return null;
210 }
211
212
213
214
215
216
217
218 public List<Atom> getAtomList(boolean originalOrder) {
219
220
221 return getAtomList();
222 }
223
224
225
226
227
228
229 public List<Bond> getBondList() {
230 return getList(Bond.class);
231 }
232
233
234 @Override
235 public double[] getCenter(boolean w) {
236 double[] Rc = {0, 0, 0};
237 double sum = 0, mass = 1;
238 List<Atom> atomList = getAtomList();
239 for (Atom a : atomList) {
240 if (w) {
241 mass = a.getMass();
242 sum += mass;
243 }
244 Rc[0] += mass * a.getX();
245 Rc[1] += mass * a.getY();
246 Rc[2] += mass * a.getZ();
247 }
248 if (!w) {
249 sum = atomList.size();
250 }
251 for (int i = 0; i < 3; i++) {
252 Rc[i] /= sum;
253 }
254 return Rc;
255 }
256
257
258
259
260
261
262 public List<MSNode> getChildList() {
263 List<MSNode> l = new ArrayList<>();
264 Enumeration<TreeNode> e = children();
265 while (e.hasMoreElements()) {
266 l.add((MSNode) e.nextElement());
267 }
268 return l;
269 }
270
271
272
273
274
275
276 public double getExtent() {
277 double extent = 0.0;
278 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
279 MSNode node = (MSNode) e.nextElement();
280 double temp = node.getExtent();
281 if (temp > extent) {
282 extent = temp;
283 }
284 }
285 return extent;
286 }
287
288
289
290
291
292
293 public List<ImproperTorsion> getImproperTorsionList() {
294 return getList(ImproperTorsion.class);
295 }
296
297
298
299
300
301
302 public <T extends TreeNode> List<T> getList(Class<T> c) {
303 return getList(c, new ArrayList<>());
304 }
305
306
307 @Override
308 public <T extends TreeNode> List<T> getList(Class<T> c, List<T> nodes) {
309 if (c.isInstance(this)) {
310 nodes.add(c.cast(this));
311 }
312 if (isLeaf() || !canBeChild(c)) {
313 return nodes;
314 }
315 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
316 MSNode node = (MSNode) e.nextElement();
317 node.getList(c, nodes);
318 }
319 return nodes;
320 }
321
322
323 @Override
324 public <T extends TreeNode> long getMSCount(Class<T> c, long count) {
325 if (c.isInstance(this)) {
326 count++;
327 }
328 if (!canBeChild(c)) {
329 return count;
330 }
331 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
332 MSNode node = (MSNode) e.nextElement();
333 count += node.getMSCount(c, count);
334 }
335 return count;
336 }
337
338
339 @Override
340 public <T extends TreeNode> T getMSNode(Class<T> c) {
341 TreeNode[] nodes = getPath();
342 for (TreeNode n : nodes) {
343 if (c.isInstance(n)) {
344 return c.cast(n);
345 }
346 }
347 return null;
348 }
349
350
351 @Override
352 public double getMW() {
353 double weight = 0.0;
354 for (Atom atom : getAtomList()) {
355 weight += atom.getMass();
356 }
357 return weight;
358 }
359
360
361
362
363
364
365 public String getName() {
366 return name;
367 }
368
369
370
371
372
373
374 public void setName(String n) {
375 name = n;
376 }
377
378
379
380
381
382
383 public List<OutOfPlaneBend> getOutOfPlaneBendList() {
384 return getList(OutOfPlaneBend.class);
385 }
386
387
388
389
390
391
392 public List<PiOrbitalTorsion> getPiOrbitalTorsionList() {
393 return getList(PiOrbitalTorsion.class);
394 }
395
396
397
398
399
400
401 public List<StretchBend> getStretchBendList() {
402 return getList(StretchBend.class);
403 }
404
405
406
407
408
409
410 public List<StretchTorsion> getStretchTorsionList() {
411 return getList(StretchTorsion.class);
412 }
413
414
415
416
417
418
419 public List<Torsion> getTorsionList() {
420 return getList(Torsion.class);
421 }
422
423
424
425
426
427
428 public List<TorsionTorsion> getTorsionTorsionList() {
429 return getList(TorsionTorsion.class);
430 }
431
432
433
434
435
436
437
438 public double getTotalMass() {
439 if (totalMass == 0.0) {
440 return getTotalMass(true, false);
441 }
442 return totalMass;
443 }
444
445
446
447
448
449
450 public List<UreyBradley> getUreyBradleyList() {
451 return getList(UreyBradley.class);
452 }
453
454
455 @Override
456 public int hashCode() {
457 return Objects.hash(name);
458 }
459
460
461
462
463
464
465 public boolean isSelected() {
466 return selected;
467 }
468
469
470
471
472
473
474 public void setSelected(boolean b) {
475 selected = b;
476 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
477 MSNode node = (MSNode) e.nextElement();
478 node.setSelected(b);
479 }
480 }
481
482
483 public void print() {
484 System.out.println(name);
485 }
486
487
488
489
490
491
492 public void removeChild(MSNode child) {
493 if (child != null && child.getParent() == this) {
494 remove(child);
495 }
496 }
497
498
499 @Override
500 public void setColor(RendererCache.ColorModel colorModel, Color3f color, Material mat) {
501 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
502 MSNode node = (MSNode) e.nextElement();
503 node.setColor(colorModel, color, mat);
504 }
505 }
506
507
508 @Override
509 public void setView(RendererCache.ViewModel viewModel, List<BranchGroup> newShapes) {
510 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
511 MSNode node = (MSNode) e.nextElement();
512 node.setView(viewModel, newShapes);
513 }
514 }
515
516
517
518
519
520
521 @Override
522 public String toString() {
523 return name;
524 }
525
526
527 @Override
528 public void update() {
529 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
530 MSNode node = (MSNode) e.nextElement();
531 node.update();
532 }
533 }
534
535
536
537
538
539
540
541
542
543 private double getTotalMass(boolean recalculate, boolean useKahan) {
544 if (recalculate) {
545 List<Atom> atoms = getAtomList();
546 if (atoms.isEmpty()) {
547 totalMass = 0.0;
548 } else if (useKahan) {
549 totalMass = kahanSumMasses(atoms);
550 } else {
551 totalMass = sumMasses(atoms);
552 }
553 }
554 return totalMass;
555 }
556
557
558
559
560
561
562
563 private double sumMasses(List<Atom> atoms) {
564 double sumMasses = 0.0;
565 for (Atom atom : atoms) {
566 sumMasses += atom.getMass();
567 }
568 return sumMasses;
569 }
570
571
572
573
574
575
576
577
578 private double kahanSumMasses(List<Atom> atoms) {
579 double sum = 0.0;
580 double comp = 0.0;
581 for (Atom atom : atoms) {
582 double atomMass = atom.getMass() - comp;
583 double temp = sum + atomMass;
584 comp = (temp - sum) - atomMass;
585 sum = temp;
586 }
587 return sum;
588 }
589
590
591
592
593
594
595
596 private <T extends TreeNode> boolean canBeChild(Class<T> c) {
597 try {
598 int multiScaleLevel = c.getDeclaredField("MultiScaleLevel").getInt(null);
599 if (multiScaleLevel >= this.MultiScaleLevel) {
600 return false;
601 }
602 } catch (NoSuchFieldException
603 | SecurityException
604 | IllegalArgumentException
605 | IllegalAccessException e) {
606 return true;
607 }
608 return true;
609 }
610 }