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