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