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 List<Atom> getAtomList(boolean originalOrder) {
203
204
205 return getAtomList();
206 }
207
208
209
210
211
212
213 public List<Bond> getBondList() {
214 return getList(Bond.class);
215 }
216
217
218 @Override
219 public double[] getCenter(boolean w) {
220 double[] Rc = {0, 0, 0};
221 double sum = 0, mass = 1;
222 List<Atom> atomList = getAtomList();
223 for (Atom a : atomList) {
224 if (w) {
225 mass = a.getMass();
226 sum += mass;
227 }
228 Rc[0] += mass * a.getX();
229 Rc[1] += mass * a.getY();
230 Rc[2] += mass * a.getZ();
231 }
232 if (!w) {
233 sum = atomList.size();
234 }
235 for (int i = 0; i < 3; i++) {
236 Rc[i] /= sum;
237 }
238 return Rc;
239 }
240
241
242
243
244
245
246 public List<MSNode> getChildList() {
247 List<MSNode> l = new ArrayList<>();
248 Enumeration<TreeNode> e = children();
249 while (e.hasMoreElements()) {
250 l.add((MSNode) e.nextElement());
251 }
252 return l;
253 }
254
255
256
257
258
259
260 public double getExtent() {
261 double extent = 0.0;
262 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
263 MSNode node = (MSNode) e.nextElement();
264 double temp = node.getExtent();
265 if (temp > extent) {
266 extent = temp;
267 }
268 }
269 return extent;
270 }
271
272
273
274
275
276
277 public List<ImproperTorsion> getImproperTorsionList() {
278 return getList(ImproperTorsion.class);
279 }
280
281
282
283
284
285
286 public <T extends TreeNode> List<T> getList(Class<T> c) {
287 return getList(c, new ArrayList<>());
288 }
289
290
291 @Override
292 public <T extends TreeNode> List<T> getList(Class<T> c, List<T> nodes) {
293 if (c.isInstance(this)) {
294 nodes.add(c.cast(this));
295 }
296 if (isLeaf() || !canBeChild(c)) {
297 return nodes;
298 }
299 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
300 MSNode node = (MSNode) e.nextElement();
301 node.getList(c, nodes);
302 }
303 return nodes;
304 }
305
306
307 @Override
308 public <T extends TreeNode> long getMSCount(Class<T> c, long count) {
309 if (c.isInstance(this)) {
310 count++;
311 }
312 if (!canBeChild(c)) {
313 return count;
314 }
315 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
316 MSNode node = (MSNode) e.nextElement();
317 count += node.getMSCount(c, count);
318 }
319 return count;
320 }
321
322
323 @Override
324 public <T extends TreeNode> T getMSNode(Class<T> c) {
325 TreeNode[] nodes = getPath();
326 for (TreeNode n : nodes) {
327 if (c.isInstance(n)) {
328 return c.cast(n);
329 }
330 }
331 return null;
332 }
333
334
335 @Override
336 public double getMW() {
337 double weight = 0.0;
338 for (Atom atom : getAtomList()) {
339 weight += atom.getMass();
340 }
341 return weight;
342 }
343
344
345
346
347
348
349 public String getName() {
350 return name;
351 }
352
353
354
355
356
357
358 public void setName(String n) {
359 name = n;
360 }
361
362
363
364
365
366
367 public List<OutOfPlaneBend> getOutOfPlaneBendList() {
368 return getList(OutOfPlaneBend.class);
369 }
370
371
372
373
374
375
376 public List<PiOrbitalTorsion> getPiOrbitalTorsionList() {
377 return getList(PiOrbitalTorsion.class);
378 }
379
380
381
382
383
384
385 public List<StretchBend> getStretchBendList() {
386 return getList(StretchBend.class);
387 }
388
389
390
391
392
393
394 public List<StretchTorsion> getStretchTorsionList() {
395 return getList(StretchTorsion.class);
396 }
397
398
399
400
401
402
403 public List<Torsion> getTorsionList() {
404 return getList(Torsion.class);
405 }
406
407
408
409
410
411
412 public List<TorsionTorsion> getTorsionTorsionList() {
413 return getList(TorsionTorsion.class);
414 }
415
416
417
418
419
420
421
422 public double getTotalMass() {
423 if (totalMass == 0.0) {
424 return getTotalMass(true, false);
425 }
426 return totalMass;
427 }
428
429
430
431
432
433
434 public List<UreyBradley> getUreyBradleyList() {
435 return getList(UreyBradley.class);
436 }
437
438
439 @Override
440 public int hashCode() {
441 return Objects.hash(name);
442 }
443
444
445
446
447
448
449 public boolean isSelected() {
450 return selected;
451 }
452
453
454
455
456
457
458 public void setSelected(boolean b) {
459 selected = b;
460 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
461 MSNode node = (MSNode) e.nextElement();
462 node.setSelected(b);
463 }
464 }
465
466
467 public void print() {
468 System.out.println(name);
469 }
470
471
472
473
474
475
476 public void removeChild(MSNode child) {
477 if (child != null && child.getParent() == this) {
478 remove(child);
479 }
480 }
481
482
483 @Override
484 public void setColor(RendererCache.ColorModel colorModel, Color3f color, Material mat) {
485 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
486 MSNode node = (MSNode) e.nextElement();
487 node.setColor(colorModel, color, mat);
488 }
489 }
490
491
492 @Override
493 public void setView(RendererCache.ViewModel viewModel, List<BranchGroup> newShapes) {
494 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
495 MSNode node = (MSNode) e.nextElement();
496 node.setView(viewModel, newShapes);
497 }
498 }
499
500
501
502
503
504
505 @Override
506 public String toString() {
507 return name;
508 }
509
510
511 @Override
512 public void update() {
513 for (Enumeration<TreeNode> e = children(); e.hasMoreElements(); ) {
514 MSNode node = (MSNode) e.nextElement();
515 node.update();
516 }
517 }
518
519
520
521
522
523
524
525
526
527 private double getTotalMass(boolean recalculate, boolean useKahan) {
528 if (recalculate) {
529 List<Atom> atoms = getAtomList();
530 if (atoms.isEmpty()) {
531 totalMass = 0.0;
532 } else if (useKahan) {
533 totalMass = kahanSumMasses(atoms);
534 } else {
535 totalMass = sumMasses(atoms);
536 }
537 }
538 return totalMass;
539 }
540
541
542
543
544
545
546
547 private double sumMasses(List<Atom> atoms) {
548 double sumMasses = 0.0;
549 for (Atom atom : atoms) {
550 sumMasses += atom.getMass();
551 }
552 return sumMasses;
553 }
554
555
556
557
558
559
560
561
562 private double kahanSumMasses(List<Atom> atoms) {
563 double sum = 0.0;
564 double comp = 0.0;
565 for (Atom atom : atoms) {
566 double atomMass = atom.getMass() - comp;
567 double temp = sum + atomMass;
568 comp = (temp - sum) - atomMass;
569 sum = temp;
570 }
571 return sum;
572 }
573
574
575
576
577
578
579
580 private <T extends TreeNode> boolean canBeChild(Class<T> c) {
581 try {
582 int multiScaleLevel = c.getDeclaredField("MultiScaleLevel").getInt(null);
583 if (multiScaleLevel >= this.MultiScaleLevel) {
584 return false;
585 }
586 } catch (NoSuchFieldException
587 | SecurityException
588 | IllegalArgumentException
589 | IllegalAccessException e) {
590 return true;
591 }
592 return true;
593 }
594 }