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;
39
40 import edu.rit.pj.ParallelTeam;
41 import ffx.crystal.Crystal;
42 import ffx.crystal.SymOp;
43 import ffx.potential.bonded.Atom;
44 import ffx.potential.bonded.Bond;
45 import ffx.potential.bonded.MSGroup;
46 import ffx.potential.bonded.MSNode;
47 import ffx.potential.bonded.Molecule;
48 import ffx.potential.bonded.Polymer;
49 import ffx.potential.bonded.RendererCache;
50 import ffx.potential.bonded.Residue;
51 import ffx.potential.bonded.Residue.ResidueType;
52 import ffx.potential.parameters.ForceField;
53 import ffx.utilities.StringUtils;
54 import org.apache.commons.configuration2.CompositeConfiguration;
55 import org.jogamp.java3d.Appearance;
56 import org.jogamp.java3d.BoundingSphere;
57 import org.jogamp.java3d.BranchGroup;
58 import org.jogamp.java3d.ColoringAttributes;
59 import org.jogamp.java3d.GeometryArray;
60 import org.jogamp.java3d.Group;
61 import org.jogamp.java3d.LineArray;
62 import org.jogamp.java3d.LineAttributes;
63 import org.jogamp.java3d.Link;
64 import org.jogamp.java3d.Material;
65 import org.jogamp.java3d.Node;
66 import org.jogamp.java3d.RenderingAttributes;
67 import org.jogamp.java3d.Shape3D;
68 import org.jogamp.java3d.SharedGroup;
69 import org.jogamp.java3d.Switch;
70 import org.jogamp.java3d.Transform3D;
71 import org.jogamp.java3d.TransformGroup;
72 import org.jogamp.java3d.utils.picking.PickTool;
73 import org.jogamp.vecmath.Color3f;
74 import org.jogamp.vecmath.Matrix3d;
75 import org.jogamp.vecmath.Point3d;
76 import org.jogamp.vecmath.Vector3d;
77
78 import java.awt.GraphicsEnvironment;
79 import java.io.File;
80 import java.io.Serial;
81 import java.util.ArrayList;
82 import java.util.Arrays;
83 import java.util.HashMap;
84 import java.util.HashSet;
85 import java.util.Iterator;
86 import java.util.List;
87 import java.util.ListIterator;
88 import java.util.Set;
89 import java.util.logging.Level;
90 import java.util.logging.Logger;
91 import java.util.stream.Collectors;
92 import java.util.stream.Stream;
93
94 import static ffx.crystal.SymOp.applyCartesianSymOp;
95 import static ffx.numerics.math.DoubleMath.length;
96 import static ffx.numerics.math.DoubleMath.sub;
97 import static java.lang.String.format;
98
99
100
101
102
103
104
105 public class MolecularAssembly extends MSGroup {
106
107 @Serial
108 private static final long serialVersionUID = 1L;
109
110 private static final Logger logger = Logger.getLogger(MolecularAssembly.class.getName());
111 private static final double[] a = new double[3];
112 private Character alternateLocation = ' ';
113 private final List<String> headerLines = new ArrayList<>();
114
115 private final MSNode ions = new MSNode("Ions");
116 private final HashMap<String, Molecule> ionHashMap = new HashMap<>();
117 private final MSNode water = new MSNode("Water");
118 private final HashMap<String, Molecule> waterHashMap = new HashMap<>();
119 private final MSNode molecules = new MSNode("Hetero Molecules");
120 private final HashMap<String, Molecule> moleculeHashMap = new HashMap<>();
121 private final List<BranchGroup> myNewShapes = new ArrayList<>();
122
123 protected ForceField forceField;
124
125 private File file;
126
127 private File archiveFile;
128 private ForceFieldEnergy potentialEnergy;
129 private CompositeConfiguration properties;
130 private Vector3d offset;
131 private int cycles = 1;
132 private int currentCycle = 1;
133
134
135 private BranchGroup branchGroup;
136 private TransformGroup originToRot;
137 private Transform3D originToRotT3D;
138 private Vector3d originToRotV3D;
139 private TransformGroup rotToCOM;
140 private Transform3D rotToCOMT3D;
141 private Vector3d rotToCOMV3D;
142 private BranchGroup base;
143 private Switch switchGroup;
144 private Shape3D wire;
145 private BranchGroup vrml;
146 private TransformGroup vrmlTG;
147 private Transform3D vrmlTd;
148 private BranchGroup childNodes;
149 private Atom[] atomLookUp;
150 private LineAttributes lineAttributes;
151 private boolean visible = false;
152 private FractionalMode fractionalMode = FractionalMode.MOLECULE;
153 private double[][] fractionalCoordinates;
154 private boolean titrateConformer = false;
155 private Atom atomInitial;
156
157
158
159
160
161
162 public MolecularAssembly(String name) {
163 super(name);
164 getAtomNode().setName("MacroMolecules");
165 add(molecules);
166 add(ions);
167 add(water);
168 }
169
170
171
172
173
174
175
176 public MolecularAssembly(String name, MSNode Polymers) {
177 super(name, Polymers);
178 }
179
180
181
182
183
184
185
186
187
188 public MolecularAssembly(String name, MSNode Polymers, CompositeConfiguration properties) {
189 this(name, Polymers);
190 this.properties = properties;
191 }
192
193
194
195
196
197
198
199 public void setAlternateLocation(Character alternateLocation) {
200 this.alternateLocation = alternateLocation;
201 }
202
203
204
205
206
207
208 public Character getAlternateLocation() {
209 return alternateLocation;
210 }
211
212
213
214
215
216
217 public void setOccupancy(double occupancy) {
218 List<Atom> atoms = getAtomList();
219 for (Atom atom : atoms) {
220 atom.setOccupancy(occupancy);
221 }
222 }
223
224
225
226
227
228
229
230 public void setOccupancy(double occupancy, Character alternateLocation) {
231 List<Atom> atoms = getAtomList();
232 for (Atom atom : atoms) {
233 if (atom.getAltLoc().equals(alternateLocation)) {
234 atom.setOccupancy(occupancy);
235 }
236 }
237 }
238
239
240
241
242
243
244 public void addHeaderLine(String line) {
245 headerLines.add(line);
246 }
247
248
249
250
251 @Override
252 public MSNode addMSNode(MSNode o) {
253 List<MSNode> Polymers = getAtomNodeList();
254 if (o instanceof Atom) {
255 Atom atom = (Atom) o;
256 if (atom.isModRes()) {
257 return getResidue(atom, true, Residue.ResidueType.AA);
258 } else if (!atom.isHetero()) {
259 String resName = atom.getResidueName();
260 switch (resName) {
261 case "HIS":
262 case "HIE":
263 case "HID":
264 case "ASP":
265 case "ASH":
266 case "GLU":
267 case "GLH":
268 case "LYS":
269 case "LYD":
270 for (Residue residue : getResidueList()) {
271 if (residue.getResidueNumber() == atom.getResidueNumber()) {
272 for (Atom currentAtom : residue.getAtomList()) {
273 if (atom.getResidueNumber() == currentAtom.getResidueNumber() && atom.getChainID() == currentAtom.getChainID()
274 && atom.getAltLoc() != currentAtom.getAltLoc() && !atom.getResidueName().equals(currentAtom.getResidueName()) &&
275 atom.getName().equals(currentAtom.getName())) {
276 titrateConformer = true;
277 atomInitial = currentAtom;
278 return getResidue(atom, true);
279 } else {
280 titrateConformer = false;
281 atomInitial = null;
282 }
283 }
284 }
285 }
286 break;
287 default:
288 break;
289 }
290 return getResidue(atom, true);
291 } else {
292 return getMolecule(atom, true);
293 }
294 } else if (o instanceof Residue) {
295 Residue residue = (Residue) o;
296 Character chainID = residue.getChainID();
297 String segID = residue.getSegID();
298 int index = Polymers.indexOf(new Polymer(chainID, segID));
299
300 if (index != -1) {
301 Polymer c = (Polymer) Polymers.get(index);
302 setFinalized(false);
303 return c.addMSNode(residue);
304 } else {
305 Polymer newc = new Polymer(chainID, segID);
306 getAtomNode().add(newc);
307 setFinalized(false);
308 return newc.addMSNode(residue);
309 }
310 } else if (o instanceof Polymer) {
311 Polymer c = (Polymer) o;
312 int index = Polymers.indexOf(c);
313 if (index == -1) {
314 getAtomNode().add(c);
315 setFinalized(false);
316 return c;
317 } else {
318 return Polymers.get(index);
319 }
320 } else if (o instanceof Molecule) {
321 Molecule m = (Molecule) o;
322 String key = m.getKey();
323 if (m.getAtomNode().getChildCount() == 1) {
324 ions.add(m);
325 if (ionHashMap.containsKey(key)) {
326 logger.info(" Ion map already contains " + m);
327 } else {
328 ionHashMap.put(m.getKey(), m);
329 }
330 return m;
331 } else if (Utilities.isWaterOxygen((Atom) m.getAtomNode().getChildAt(0))) {
332 water.add(m);
333 if (waterHashMap.containsKey(key)) {
334 logger.info(" Water map already contains " + m);
335 } else {
336 waterHashMap.put(m.getKey(), m);
337 }
338 return m;
339 } else {
340 molecules.add(m);
341 if (moleculeHashMap.containsKey(key)) {
342 logger.info(" Molecule map already contains " + m);
343 } else {
344 moleculeHashMap.put(m.getKey(), m);
345 }
346 return m;
347 }
348 } else {
349 String message = "Programming error in MolecularAssembly addNode";
350 logger.log(Level.SEVERE, message);
351 return o;
352 }
353 }
354
355
356
357
358
359
360 public void applyRandomDensity(double ucDensity) {
361 if (ucDensity > 0) {
362 logger.info(format("\n Applying random unit cell axes with target density %6.3f (g/cc).", ucDensity));
363 Crystal crystal = getCrystal();
364 if (!crystal.aperiodic()) {
365 double mass = getMass();
366 crystal.randomParameters(ucDensity, mass);
367 logger.info(crystal.toString());
368 potentialEnergy.setCrystal(crystal);
369 } else {
370 logger.fine(String.format(" Potential %s is an aperiodic system!", potentialEnergy));
371 }
372 }
373 }
374
375
376
377
378
379
380
381
382 public void applyRandomSymOp(double x) {
383
384 Crystal crystal = getCrystal().getUnitCell();
385 if (crystal.aperiodic() || x < 0) {
386 return;
387 }
388 double[] xyz = new double[3];
389 List<MSNode> molecules = getMolecules();
390 int moleculeNum = 1;
391 for (MSNode msNode : molecules) {
392 List<Atom> atoms = msNode.getAtomList();
393 SymOp symOp;
394 if (x == 0) {
395 double[] translation = crystal.getRandomCartTranslation();
396 symOp = SymOp.randomSymOpFactory(translation);
397 } else {
398 symOp = SymOp.randomSymOpFactory(x);
399 }
400 logger.info(
401 format(
402 "\n Applying random Cartesian SymOp to molecule %d:\n%s",
403 moleculeNum, symOp));
404 for (Atom atom : atoms) {
405 atom.getXYZ(xyz);
406 applyCartesianSymOp(xyz, xyz, symOp);
407 atom.setXYZ(xyz);
408 }
409 moleculeNum++;
410 }
411 }
412
413
414
415
416 public void center() {
417 double[] center = getMultiScaleCenter(false);
418 offset = new Vector3d(center);
419 if (vrml != null) {
420 vrmlTd.set(offset);
421 vrmlTG.setTransform(vrmlTd);
422 }
423 offset.negate();
424 originToRotV3D.set(offset);
425 originToRotT3D.setTranslation(originToRotV3D);
426 originToRot.setTransform(originToRotT3D);
427 rotToCOMT3D.setIdentity();
428 rotToCOM.setTransform(rotToCOMT3D);
429 offset.negate();
430 rotateAbout(offset);
431 originToRotT3D.get(offset);
432 }
433
434
435
436
437
438
439 public void centerAt(double[] d) {
440 double[] Rc = {0, 0, 0};
441 double[] c = new double[3];
442 ListIterator<Atom> li;
443 int i, num = getAtomList().size();
444 for (li = getAtomList().listIterator(); li.hasNext(); ) {
445 (li.next()).getXYZ(a);
446 Rc[0] += a[0];
447 Rc[1] += a[1];
448 Rc[2] += a[2];
449 }
450 for (i = 0; i < 3; i++) {
451 Rc[i] /= num;
452 }
453 sub(d, Rc, c);
454 for (li = getAtomList().listIterator(); li.hasNext(); ) {
455 (li.next()).move(c);
456 }
457 }
458
459
460
461
462
463
464
465 public void centerView(boolean rot, boolean trans) {
466 originToRot.getTransform(originToRotT3D);
467 if (rot) {
468 Matrix3d m3d = new Matrix3d();
469 m3d.setIdentity();
470 originToRotT3D.setRotation(m3d);
471
472 }
473 if (trans) {
474 originToRotV3D.set(offset);
475 originToRotT3D.set(originToRotV3D);
476 }
477 originToRot.setTransform(originToRotT3D);
478
479 }
480
481
482
483
484 public void computeFractionalCoordinates() {
485
486
487 fractionalCount();
488
489 Crystal unitCell = getCrystal().getUnitCell();
490 double[] com = new double[3];
491
492 switch (fractionalMode) {
493 case MOLECULE:
494 int iMolecule = 0;
495 Polymer[] polymers = getChains();
496 if (polymers != null && polymers.length > 0) {
497
498 for (Polymer polymer : polymers) {
499 List<Atom> list = polymer.getAtomList();
500 com[0] = 0.0;
501 com[1] = 0.0;
502 com[2] = 0.0;
503 double totalMass = 0.0;
504 for (Atom atom : list) {
505 double m = atom.getMass();
506 com[0] += atom.getX() * m;
507 com[1] += atom.getY() * m;
508 com[2] += atom.getZ() * m;
509 totalMass += m;
510 }
511 com[0] /= totalMass;
512 com[1] /= totalMass;
513 com[2] /= totalMass;
514 unitCell.toFractionalCoordinates(com, fractionalCoordinates[iMolecule++]);
515 }
516 }
517
518
519 List<MSNode> molecules = getMolecules();
520 for (MSNode molecule : molecules) {
521 List<Atom> list = molecule.getAtomList();
522
523 com[0] = 0.0;
524 com[1] = 0.0;
525 com[2] = 0.0;
526 double totalMass = 0.0;
527 for (Atom atom : list) {
528 double m = atom.getMass();
529 com[0] += atom.getX() * m;
530 com[1] += atom.getY() * m;
531 com[2] += atom.getZ() * m;
532 totalMass += m;
533 }
534 com[0] /= totalMass;
535 com[1] /= totalMass;
536 com[2] /= totalMass;
537 unitCell.toFractionalCoordinates(com, fractionalCoordinates[iMolecule++]);
538 }
539
540
541 List<MSNode> water = getWater();
542 for (MSNode wat : water) {
543 List<Atom> list = wat.getAtomList();
544
545 com[0] = 0.0;
546 com[1] = 0.0;
547 com[2] = 0.0;
548 double totalMass = 0.0;
549 for (Atom atom : list) {
550 double m = atom.getMass();
551 com[0] += atom.getX() * m;
552 com[1] += atom.getY() * m;
553 com[2] += atom.getZ() * m;
554 totalMass += m;
555 }
556 com[0] /= totalMass;
557 com[1] /= totalMass;
558 com[2] /= totalMass;
559 unitCell.toFractionalCoordinates(com, fractionalCoordinates[iMolecule++]);
560 }
561
562
563 List<MSNode> ions = getIons();
564 for (MSNode ion : ions) {
565 List<Atom> list = ion.getAtomList();
566
567 com[0] = 0.0;
568 com[1] = 0.0;
569 com[2] = 0.0;
570 double totalMass = 0.0;
571 for (Atom atom : list) {
572 double m = atom.getMass();
573 com[0] += atom.getX() * m;
574 com[1] += atom.getY() * m;
575 com[2] += atom.getZ() * m;
576 totalMass += m;
577 }
578 com[0] /= totalMass;
579 com[1] /= totalMass;
580 com[2] /= totalMass;
581 unitCell.toFractionalCoordinates(com, fractionalCoordinates[iMolecule++]);
582 }
583 break;
584 case ATOM:
585 Atom[] atoms = getAtomArray();
586 int nAtoms = atoms.length;
587 for (int i = 0; i < nAtoms; i++) {
588 atoms[i].getXYZ(com);
589 unitCell.toFractionalCoordinates(com, fractionalCoordinates[i]);
590 }
591 break;
592 case OFF:
593 break;
594 }
595 }
596
597
598
599
600 public void createBox() {
601 int vertices = 8;
602 LineArray la =
603 new LineArray(
604 4 * vertices,
605 GeometryArray.COORDINATES | GeometryArray.COLOR_4 | GeometryArray.NORMALS);
606 la.setCapability(LineArray.ALLOW_COORDINATE_WRITE);
607 la.setCapability(LineArray.ALLOW_COORDINATE_READ);
608 la.setCapability(LineArray.ALLOW_COLOR_WRITE);
609 la.setCapability(LineArray.ALLOW_COUNT_READ);
610 la.setCapability(LineArray.ALLOW_INTERSECT);
611 la.setCapability(LineArray.ALLOW_FORMAT_READ);
612
613 ColoringAttributes cola =
614 new ColoringAttributes(new Color3f(), ColoringAttributes.SHADE_GOURAUD);
615 Appearance app = new Appearance();
616 lineAttributes = new LineAttributes();
617 lineAttributes.setLineWidth(RendererCache.bondwidth);
618 lineAttributes.setCapability(LineAttributes.ALLOW_WIDTH_WRITE);
619 lineAttributes.setLineAntialiasingEnable(true);
620 app.setLineAttributes(lineAttributes);
621 app.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_READ);
622 app.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_WRITE);
623 RenderingAttributes ra = new RenderingAttributes();
624 ra.setAlphaTestValue(0.1f);
625 ra.setAlphaTestFunction(RenderingAttributes.GREATER);
626 ra.setDepthBufferEnable(true);
627 ra.setDepthBufferWriteEnable(true);
628 app.setRenderingAttributes(ra);
629 app.setColoringAttributes(cola);
630 Shape3D wireframe = new Shape3D(la, app);
631
632 wireframe.setUserData(this);
633 wireframe.setBounds(new BoundingSphere(new Point3d(0, 0, 0), 10.0));
634 try {
635 wireframe.setBoundsAutoCompute(false);
636 } catch (Exception e) {
637 logger.warning(" Exception in setting bounds for wireframe:\n" + e);
638 }
639 wireframe.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
640 wireframe.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
641
642 }
643
644
645
646
647
648
649 public void deleteMolecule(Molecule molecule) {
650 List<MSNode> list = ions.getChildList();
651 for (MSNode node : list) {
652 Molecule m = (Molecule) node;
653 if (molecule == m) {
654 ions.remove(m);
655 ionHashMap.remove(m.getKey());
656 return;
657 }
658 }
659 list = water.getChildList();
660 for (MSNode node : list) {
661 Molecule m = (Molecule) node;
662 if (molecule == m) {
663 water.remove(m);
664 waterHashMap.remove(m.getKey());
665 return;
666 }
667 }
668 list = molecules.getChildList();
669 for (MSNode node : list) {
670 Molecule m = (Molecule) node;
671 if (molecule == m) {
672 molecules.remove(m);
673 moleculeHashMap.remove(m.getKey());
674 return;
675 }
676 }
677 }
678
679
680
681
682 @Override
683 public boolean destroy() {
684 try {
685 if (potentialEnergy == null) {
686 finishDestruction();
687 return true;
688 } else {
689
690
691 return potentialEnergy.destroy();
692 }
693 } catch (Exception ex) {
694 logger.warning(String.format(" Exception in destroying a MolecularAssembly: %s", ex));
695 logger.info(Utilities.stackTraceToString(ex));
696 return false;
697 }
698 }
699
700
701
702
703 public void detach() {
704 synchronized (this) {
705 if (branchGroup != null && branchGroup.isLive()) {
706 branchGroup.detach();
707 }
708 }
709 }
710
711
712
713
714 @Override
715 public void finalize(boolean finalizeGroups, ForceField forceField) {
716 setFinalized(false);
717 if (finalizeGroups) {
718 bondTime = 0;
719 angleTime = 0;
720 stretchBendTime = 0;
721 ureyBradleyTime = 0;
722 outOfPlaneBendTime = 0;
723 torsionTime = 0;
724 piOrbitalTorsionTime = 0;
725 torsionTorsionTime = 0;
726 List<MSNode> Polymers = getAtomNodeList();
727 for (MSNode msNode : Polymers) {
728 MSGroup group = (MSGroup) msNode;
729 if (logger.isLoggable(Level.FINE)) {
730 logger.fine(" Finalizing bonded terms for polymer " + group.toString());
731 }
732 try {
733 group.finalize(true, forceField);
734 } catch (Exception e) {
735 String message = "Fatal exception finalizing " + group.toString();
736 logger.log(Level.SEVERE, message, e);
737 System.exit(-1);
738 }
739 if (logger.isLoggable(Level.FINE)) {
740 Runtime runtime = Runtime.getRuntime();
741 long occupiedMemory = runtime.totalMemory() - runtime.freeMemory();
742 long MB = 1024 * 1024;
743 logger.fine(
744 "\n In-Use Memory (Mb): "
745 + occupiedMemory / MB
746 + "\n Free Memory (Mb): "
747 + runtime.freeMemory() / MB
748 + "\n Total Memory (Mb): "
749 + runtime.totalMemory() / MB);
750 }
751 }
752 for (MSNode m : molecules.getChildList()) {
753 Molecule molecule = (Molecule) m;
754 molecule.finalize(true, forceField);
755 }
756 for (MSNode m : water.getChildList()) {
757 Molecule molecule = (Molecule) m;
758 molecule.finalize(true, forceField);
759 }
760 for (MSNode m : ions.getChildList()) {
761 Molecule molecule = (Molecule) m;
762 molecule.finalize(true, forceField);
763 }
764 if (logger.isLoggable(Level.FINE)) {
765 StringBuilder sb = new StringBuilder("\n Time to create bonded energy terms\n\n");
766 sb.append(format(" Bond Streching %10.3f\n", bondTime * 1.0e-9));
767 sb.append(format(" Angle Bending %10.3f\n", angleTime * 1.0e-9));
768 sb.append(format(" Stretch-Bend %10.3f\n", stretchBendTime * 1.0e-9));
769 sb.append(format(" Urey-Bradley %10.3f\n", ureyBradleyTime * 1.0e-9));
770 sb.append(format(" Out-of-Plane Bend %10.3f\n", outOfPlaneBendTime * 1.0e-9));
771 sb.append(format(" Torsionanl Angle %10.3f\n", torsionTime * 1.0e-9));
772 sb.append(format(" Pi-Orbital Torsion %10.3f\n", piOrbitalTorsionTime * 1.0e-9));
773 sb.append(format(" Torsion-Torsion %10.3f\n", torsionTorsionTime * 1.0e-9));
774 logger.fine(sb.toString());
775 }
776 }
777 if (!GraphicsEnvironment.isHeadless()) {
778 createScene(!finalizeGroups);
779 center();
780 }
781 removeLeaves();
782
783
784 boolean heavyHydrogen = forceField.getBoolean("HEAVY_HYDROGENS", false);
785 heavyHydrogen = forceField.getBoolean("HEAVY_HYDROGEN", heavyHydrogen);
786 if (heavyHydrogen) {
787 applyHeavyHydrogen();
788 }
789
790 setFinalized(true);
791 }
792
793
794
795
796
797
798
799 public Atom findAtom(Atom atom) {
800 return findAtom(atom, false);
801 }
802
803
804
805
806
807
808
809 public Atom findAtom(Atom atom, boolean matchDeuterium) {
810 if (!atom.isHetero() || atom.isModRes()) {
811 Polymer polymer = getPolymer(atom.getChainID(), atom.getSegID(), false);
812 if (polymer != null) {
813 Residue res = polymer.getResidue(atom.getResidueName(), atom.getResidueNumber(), false);
814 if (res != null) {
815 MSNode node = res.getAtomNode();
816 Atom foundAtom = (Atom) node.contains(atom);
817
818 if (foundAtom == null && matchDeuterium && atom.getAtomicNumber() == 1) {
819 String atomName = atom.getName().toUpperCase();
820 if (atomName.startsWith("H")) {
821 atom.setName(atomName.replaceFirst("H", "D"));
822 foundAtom = (Atom) node.contains(atom);
823 atom.setName(atomName);
824 } else if (atomName.startsWith("D")) {
825 atom.setName(atomName.replaceFirst("D", "H"));
826 foundAtom = (Atom) node.contains(atom);
827 atom.setName(atomName);
828 }
829 }
830 return foundAtom;
831 }
832 }
833 return null;
834 } else {
835 String resName = atom.getResidueName();
836 int resNum = atom.getResidueNumber();
837 String segID = atom.getSegID();
838 String key = resNum + resName + segID;
839 Molecule m = ionHashMap.get(key);
840 if (m == null) {
841 m = waterHashMap.get(key);
842 if (m == null) {
843 m = moleculeHashMap.get(key);
844 if (m == null) {
845 return null;
846 }
847 }
848 }
849 return (Atom) m.contains(atom);
850 }
851 }
852
853
854
855
856
857
858
859
860 public int fractionalCount() {
861 int count = 0;
862 switch (fractionalMode) {
863 case MOLECULE:
864
865 Polymer[] polymers = getChains();
866 if (polymers != null && polymers.length > 0) {
867 count += polymers.length;
868 }
869 List<MSNode> molecules = getMolecules();
870 if (molecules != null) {
871 count += molecules.size();
872 }
873
874 List<MSNode> water = getWater();
875 if (water != null) {
876 count += water.size();
877 }
878
879 List<MSNode> ions = getIons();
880 if (ions != null) {
881 count += ions.size();
882 }
883 break;
884 case ATOM:
885 count = getAtomArray().length;
886 break;
887 case OFF:
888 count = 0;
889 break;
890 }
891
892 if (fractionalCoordinates == null || fractionalCoordinates.length != count) {
893 fractionalCoordinates = new double[count][3];
894 }
895
896 return count;
897 }
898
899
900
901
902
903
904 public Atom[] getActiveAtomArray() {
905 List<Atom> atoms = getAtomList();
906 List<Atom> activeAtoms = new ArrayList<>();
907 for (Atom a : atoms) {
908 if (a.isActive()) {
909 activeAtoms.add(a);
910 }
911 }
912 Atom[] atomArray = activeAtoms.toArray(new Atom[0]);
913 Arrays.sort(atomArray);
914 return atomArray;
915 }
916
917
918
919
920
921
922
923 public List<MSNode> getAllBondedEntities() {
924
925 Set<MSNode> allBondedNodes = new HashSet<>(getIons());
926 allBondedNodes.addAll(getMolecules());
927 allBondedNodes.addAll(getWater());
928 Polymer[] polys = getChains();
929 if (polys != null && polys.length > 0) {
930 allBondedNodes.addAll(Arrays.asList(polys));
931 }
932 return new ArrayList<>(allBondedNodes);
933 }
934
935
936
937
938
939
940 public Atom[] getAtomArray() {
941 List<Atom> atoms = getAtomList();
942 Atom[] atomArray = atoms.toArray(new Atom[0]);
943 for (int i = 0; i < atoms.size(); i++) {
944 atomArray[i].setXyzIndex(i + 1);
945 }
946 return atomArray;
947 }
948
949
950
951
952
953
954
955 public Atom getAtomFromWireVertex(int i) {
956 if (atomLookUp != null && atomLookUp.length > i) {
957 return atomLookUp[i];
958 }
959 return null;
960 }
961
962
963
964
965
966
967 public List<Atom> getBackBoneAtoms() {
968 List<Atom> backbone = new ArrayList<>();
969 List<Residue> residues = getResidueList();
970 for (Residue residue : residues) {
971 backbone.addAll(residue.getBackboneAtoms());
972 }
973 return backbone;
974 }
975
976
977
978
979
980
981 public BranchGroup getBranchGroup() {
982 return branchGroup;
983 }
984
985
986
987
988
989
990
991 public Polymer getChain(String name) {
992 for (MSNode node : getAtomNodeList()) {
993 if (node instanceof Polymer) {
994 String chainName = node.getName();
995 if (chainName.equalsIgnoreCase(name)) {
996 return (Polymer) node;
997 } else if (name.contentEquals(" ")) {
998 return (Polymer) node;
999 }
1000
1001
1002 }
1003 }
1004 return null;
1005 }
1006
1007
1008
1009
1010
1011
1012 public String[] getChainNames() {
1013 List<String> temp = new ArrayList<>();
1014 for (MSNode node : getAtomNodeList()) {
1015 if (node instanceof Polymer) {
1016 temp.add(node.getName());
1017 }
1018 }
1019 if (temp.isEmpty()) {
1020 return null;
1021 }
1022
1023 String[] names = new String[temp.size()];
1024 for (int i = 0; i < temp.size(); i++) {
1025 names[i] = temp.get(i);
1026 }
1027
1028 return names;
1029 }
1030
1031
1032
1033
1034
1035
1036 public Polymer[] getChains() {
1037 List<Polymer> polymers = new ArrayList<>();
1038 for (MSNode node : getAtomNodeList()) {
1039 if (node instanceof Polymer) {
1040 polymers.add((Polymer) node);
1041 }
1042 }
1043 if (polymers.isEmpty()) {
1044 return null;
1045 }
1046 return polymers.toArray(new Polymer[0]);
1047 }
1048
1049
1050
1051
1052
1053
1054
1055 public double getCharge(boolean alwaysLog) {
1056 double totalCharge = 0;
1057 for (MSNode node : getNodeList()) {
1058 double charge = 0;
1059 boolean isNonstandard = false;
1060 for (Atom atom : node.getAtomList()) {
1061 charge += atom.getCharge(forceField);
1062 if (atom.isModRes()) {
1063 isNonstandard = true;
1064 }
1065 }
1066 if ((alwaysLog || isNonstandard) && (Math.abs(Math.round(charge) - charge) > 1.0E-5)) {
1067 logger.warning(
1068 String.format(" Node %s has non-unitary charge %12.8f", node, charge));
1069 }
1070 totalCharge += charge;
1071 }
1072 return totalCharge;
1073 }
1074
1075
1076
1077
1078
1079
1080 public boolean hasDeuterium() {
1081 Atom[] atoms = getAtomArray();
1082 for (Atom atom : atoms) {
1083 if (atom.isDeuterium()) {
1084 return true;
1085 }
1086 }
1087 return false;
1088 }
1089
1090
1091
1092
1093
1094
1095 public Crystal getCrystal() {
1096 if (potentialEnergy == null) {
1097 return null;
1098 }
1099 return potentialEnergy.getCrystal();
1100 }
1101
1102
1103
1104
1105
1106
1107 public void setCrystal(Crystal crystal) {
1108 if (potentialEnergy != null) {
1109 potentialEnergy.setCrystal(crystal);
1110 }
1111 }
1112
1113
1114
1115
1116
1117
1118 public int getCurrentCycle() {
1119 return currentCycle;
1120 }
1121
1122
1123
1124
1125
1126
1127 public void setCurrentCycle(int c) {
1128 if (c <= cycles && c > 0) {
1129 currentCycle = c;
1130 for (Atom atom : getAtomList()) {
1131 atom.setCurrentCycle(currentCycle);
1132 }
1133 }
1134 }
1135
1136
1137
1138
1139
1140
1141 public int getCycles() {
1142 return cycles;
1143 }
1144
1145
1146
1147
1148
1149
1150 public void setCycles(int c) {
1151 cycles = c;
1152 }
1153
1154
1155
1156
1157 @Override
1158 public double getExtent() {
1159 double[] Rc = {0, 0, 0};
1160 int num = getAtomList().size();
1161 for (Atom atom : getAtomList()) {
1162 atom.getXYZ(a);
1163 Rc[0] += a[0];
1164 Rc[1] += a[1];
1165 Rc[2] += a[2];
1166 }
1167
1168 for (int i = 0; i < 3; i++) {
1169 Rc[i] /= num;
1170 }
1171
1172 double r, d = 0;
1173 double[] xyz = new double[3];
1174 for (Atom atom : getAtomList()) {
1175 atom.getXYZ(xyz);
1176 sub(xyz, Rc, xyz);
1177 r = length(xyz);
1178 if (d < r) {
1179 d = r;
1180 }
1181 }
1182 return d;
1183 }
1184
1185
1186
1187
1188
1189
1190 public File getFile() {
1191 return file;
1192 }
1193
1194
1195
1196
1197
1198
1199 public void setFile(File file) {
1200 if (file == null) {
1201
1202 return;
1203 }
1204 this.file = file;
1205 }
1206
1207
1208
1209
1210
1211
1212 public File getArchiveFile() {
1213 return archiveFile;
1214 }
1215
1216
1217
1218
1219
1220
1221 public void setArchiveFile(File archiveFile) {
1222 if (archiveFile == null) {
1223
1224 return;
1225 }
1226 this.archiveFile = archiveFile;
1227 }
1228
1229
1230
1231
1232
1233
1234 public ForceField getForceField() {
1235 return forceField;
1236 }
1237
1238
1239
1240
1241
1242
1243 public void setForceField(ForceField forceField) {
1244 this.forceField = forceField;
1245 }
1246
1247
1248
1249
1250
1251
1252 public FractionalMode getFractionalMode() {
1253 return fractionalMode;
1254 }
1255
1256
1257
1258
1259
1260
1261 public void setFractionalMode(FractionalMode mode) {
1262 fractionalMode = mode;
1263 }
1264
1265
1266
1267
1268
1269
1270 public String[] getHeaderLines() {
1271 String[] ret = new String[headerLines.size()];
1272 headerLines.toArray(ret);
1273 return ret;
1274 }
1275
1276
1277
1278
1279
1280
1281 public List<MSNode> getIons() {
1282 return ions.getChildList();
1283 }
1284
1285
1286
1287
1288
1289
1290 public double getMass() {
1291 double mass = 0;
1292 for (Atom atom : getAtomArray()) {
1293 mass += atom.getMass();
1294 }
1295 return mass;
1296 }
1297
1298
1299
1300
1301
1302
1303 public boolean[] getNeuralNetworkIdentity() {
1304 Atom[] atomArray = getAtomArray();
1305 int nAtoms = atomArray.length;
1306 boolean[] neuralNetwork = new boolean[nAtoms];
1307 for (int i = 0; i < nAtoms; i++) {
1308 neuralNetwork[i] = atomArray[i].isNeuralNetwork();
1309 }
1310 return neuralNetwork;
1311 }
1312
1313
1314
1315
1316
1317
1318
1319 public int[] getMoleculeNumbers() {
1320 int[] moleculeNumber = new int[getAtomList().size()];
1321 int current = 0;
1322
1323 Polymer[] polymers = getChains();
1324 if (polymers != null) {
1325 for (Polymer polymer : polymers) {
1326 List<Atom> atomList = polymer.getAtomList();
1327 for (Atom atom : atomList) {
1328 moleculeNumber[atom.getXyzIndex() - 1] = current;
1329 atom.setMoleculeNumber(current);
1330 }
1331 current++;
1332 }
1333 }
1334
1335
1336 for (MSNode molecule : molecules.getChildList()) {
1337 List<Atom> atomList = molecule.getAtomList();
1338 for (Atom atom : atomList) {
1339 moleculeNumber[atom.getXyzIndex() - 1] = current;
1340 atom.setMoleculeNumber(current);
1341 }
1342 current++;
1343 }
1344
1345
1346 for (MSNode wat : water.getChildList()) {
1347 List<Atom> atomList = wat.getAtomList();
1348 for (Atom atom : atomList) {
1349 moleculeNumber[atom.getXyzIndex() - 1] = current;
1350 atom.setMoleculeNumber(current);
1351 }
1352 current++;
1353 }
1354
1355
1356 for (MSNode ion : ions.getChildList()) {
1357 List<Atom> atomList = ion.getAtomList();
1358 for (Atom atom : atomList) {
1359 moleculeNumber[atom.getXyzIndex() - 1] = current;
1360 atom.setMoleculeNumber(current);
1361 }
1362 current++;
1363 }
1364
1365 return moleculeNumber;
1366 }
1367
1368
1369
1370
1371
1372
1373 public List<MSNode> getMolecules() {
1374 return molecules.getChildList();
1375 }
1376
1377 public Molecule[] getMoleculeArray() {
1378 Molecule[] m = new Molecule[molecules.getChildCount()];
1379 int i = 0;
1380 for (MSNode msNode : molecules.getChildList()) {
1381 m[i++] = (Molecule) msNode;
1382 }
1383 return m;
1384 }
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397 public void setChainIDAndRenumberMolecules(Character chainID) {
1398 int resID = 1;
1399
1400 Polymer polymer = getPolymer(chainID, chainID.toString(), false);
1401 if (polymer != null) {
1402 List<Residue> residues = polymer.getResidues();
1403 for (Residue residue : residues) {
1404 int resID2 = residue.getResidueNumber();
1405 if (resID2 >= resID) {
1406 resID = resID2 + 1;
1407 }
1408 }
1409 }
1410 for (MSNode m : getMolecules()) {
1411 Molecule molecule = (Molecule) m;
1412 molecule.setChainID(chainID);
1413 molecule.setResidueNum(resID++);
1414 }
1415 for (MSNode ion : getIons()) {
1416 Molecule m = (Molecule) ion;
1417 m.setChainID(chainID);
1418 m.setResidueNum(resID++);
1419 }
1420 for (MSNode wat : getWater()) {
1421 Molecule water = (Molecule) wat;
1422 water.setChainID(chainID);
1423 water.setResidueNum(resID++);
1424 }
1425 }
1426
1427
1428
1429
1430
1431
1432 public List<MSNode> getNodeList() {
1433 return getNodeList(false);
1434 }
1435
1436
1437
1438
1439
1440
1441
1442 public List<MSNode> getNodeList(boolean ignorePolymers) {
1443 List<MSNode> nodeList = new ArrayList<>();
1444 if (!ignorePolymers) {
1445 Polymer[] polymers = getChains();
1446 if (polymers != null) {
1447 for (Polymer polymer : polymers) {
1448 nodeList.addAll(polymer.getResidues());
1449 }
1450 }
1451 }
1452 nodeList.addAll(ions.getChildList());
1453 nodeList.addAll(water.getChildList());
1454 nodeList.addAll(molecules.getChildList());
1455 return nodeList;
1456 }
1457
1458
1459
1460
1461
1462
1463 public Vector3d getOffset() {
1464 if (offset == null) {
1465 offset = new Vector3d(0.0, 0.0, 0.0);
1466 }
1467
1468 return offset;
1469 }
1470
1471
1472
1473
1474
1475
1476 public void setOffset(Vector3d o) {
1477 offset = o;
1478 }
1479
1480
1481
1482
1483
1484
1485 public TransformGroup getOriginToRot() {
1486 return originToRot;
1487 }
1488
1489
1490
1491
1492
1493
1494 public ParallelTeam getParallelTeam() {
1495 if (potentialEnergy != null) {
1496 return potentialEnergy.getParallelTeam();
1497 } else {
1498 return null;
1499 }
1500 }
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510 public Polymer getPolymer(Character chainID, String segID, boolean create) {
1511 for (MSNode node : getAtomNodeList()) {
1512 if (node instanceof Polymer) {
1513 Polymer polymer = (Polymer) node;
1514 if (polymer.getName().equals(segID) && polymer.getChainID().equals(chainID)) {
1515 return (Polymer) node;
1516 }
1517 }
1518 }
1519 if (create) {
1520 Polymer polymer = new Polymer(chainID, segID, true);
1521 addMSNode(polymer);
1522 return polymer;
1523 }
1524
1525 return null;
1526 }
1527
1528
1529
1530
1531
1532
1533 public ForceFieldEnergy getPotentialEnergy() {
1534 return potentialEnergy;
1535 }
1536
1537
1538
1539
1540
1541
1542 public CompositeConfiguration getProperties() {
1543 return properties == null ? forceField.getProperties() : properties;
1544 }
1545
1546
1547
1548
1549
1550
1551 public List<Residue> getResidueList() {
1552 List<Residue> residues = new ArrayList<>();
1553 ListIterator<MSNode> li, lj;
1554 MSNode o;
1555 Polymer c;
1556 for (li = getAtomNodeList().listIterator(); li.hasNext(); ) {
1557 o = li.next();
1558 if (o instanceof Polymer) {
1559 c = (Polymer) o;
1560 for (lj = c.getAtomNodeList().listIterator(); lj.hasNext(); ) {
1561 o = lj.next();
1562 if (o instanceof Residue) {
1563 residues.add((Residue) o);
1564 }
1565 }
1566 }
1567 }
1568 return residues;
1569 }
1570
1571
1572
1573
1574
1575
1576 public TransformGroup getTransformGroup() {
1577 return originToRot;
1578 }
1579
1580
1581
1582
1583
1584
1585 public List<MSNode> getWater() {
1586 return water.getChildList();
1587 }
1588
1589
1590
1591
1592
1593
1594 public Node getWireFrame() {
1595 return wire;
1596 }
1597
1598
1599
1600
1601
1602
1603 public boolean isVisible() {
1604 return visible;
1605 }
1606
1607
1608
1609
1610
1611
1612 public BranchGroup loadVRML() {
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635 return null;
1636 }
1637
1638
1639
1640
1641
1642 public void moveAllIntoUnitCell() {
1643 moveIntoUnitCell(getChains());
1644 moveIntoUnitCell(getWater());
1645 moveIntoUnitCell(getIons());
1646 moveIntoUnitCell(getMolecules());
1647 }
1648
1649
1650
1651
1652
1653
1654 public void moveCenter(double[] d) {
1655 for (Atom atom : getAtomList()) {
1656 atom.move(d);
1657 }
1658 }
1659
1660
1661
1662
1663 public void moveToFractionalCoordinates() {
1664
1665 if (fractionalCoordinates == null) {
1666 return;
1667 }
1668
1669 Crystal unitCell = getCrystal().getUnitCell();
1670 double[] com = new double[3];
1671
1672 switch (fractionalMode) {
1673 case MOLECULE:
1674 int iMolecule = 0;
1675 Polymer[] polymers = getChains();
1676 if (polymers != null && polymers.length > 0) {
1677
1678 for (Polymer polymer : polymers) {
1679 List<Atom> list = polymer.getAtomList();
1680 double totalMass = 0.9;
1681 com[0] = 0.0;
1682 com[1] = 0.0;
1683 com[2] = 0.0;
1684 for (Atom atom : list) {
1685 double m = atom.getMass();
1686 com[0] += atom.getX() * m;
1687 com[1] += atom.getY() * m;
1688 com[2] += atom.getZ() * m;
1689 totalMass += m;
1690 }
1691 com[0] /= totalMass;
1692 com[1] /= totalMass;
1693 com[2] /= totalMass;
1694
1695 unitCell.toFractionalCoordinates(com, com);
1696
1697 double[] frac = fractionalCoordinates[iMolecule++];
1698 com[0] = frac[0] - com[0];
1699 com[1] = frac[1] - com[1];
1700 com[2] = frac[2] - com[2];
1701
1702 unitCell.toCartesianCoordinates(com, com);
1703
1704 for (Atom atom : list) {
1705 atom.move(com);
1706 }
1707 }
1708 }
1709
1710
1711 List<MSNode> molecules = getMolecules();
1712 for (MSNode molecule : molecules) {
1713 List<Atom> list = molecule.getAtomList();
1714
1715 com[0] = 0.0;
1716 com[1] = 0.0;
1717 com[2] = 0.0;
1718 double totalMass = 0.0;
1719 for (Atom atom : list) {
1720 double m = atom.getMass();
1721 com[0] += atom.getX() * m;
1722 com[1] += atom.getY() * m;
1723 com[2] += atom.getZ() * m;
1724 totalMass += m;
1725 }
1726 com[0] /= totalMass;
1727 com[1] /= totalMass;
1728 com[2] /= totalMass;
1729
1730 unitCell.toFractionalCoordinates(com, com);
1731
1732 double[] frac = fractionalCoordinates[iMolecule++];
1733 com[0] = frac[0] - com[0];
1734 com[1] = frac[1] - com[1];
1735 com[2] = frac[2] - com[2];
1736
1737 unitCell.toCartesianCoordinates(com, com);
1738
1739 for (Atom atom : list) {
1740 atom.move(com);
1741 }
1742 }
1743
1744
1745 List<MSNode> water = getWater();
1746 for (MSNode wat : water) {
1747 List<Atom> list = wat.getAtomList();
1748
1749 com[0] = 0.0;
1750 com[1] = 0.0;
1751 com[2] = 0.0;
1752 double totalMass = 0.0;
1753 for (Atom atom : list) {
1754 double m = atom.getMass();
1755 com[0] += atom.getX() * m;
1756 com[1] += atom.getY() * m;
1757 com[2] += atom.getZ() * m;
1758 totalMass += m;
1759 }
1760 com[0] /= totalMass;
1761 com[1] /= totalMass;
1762 com[2] /= totalMass;
1763
1764 unitCell.toFractionalCoordinates(com, com);
1765
1766 double[] frac = fractionalCoordinates[iMolecule++];
1767 com[0] = frac[0] - com[0];
1768 com[1] = frac[1] - com[1];
1769 com[2] = frac[2] - com[2];
1770
1771 unitCell.toCartesianCoordinates(com, com);
1772
1773 double r = length(com);
1774
1775
1776 if (r > 1.0) {
1777 int i = iMolecule - 1;
1778 logger.info(String.format(" %d R: %16.8f", i, r));
1779 logger.info(
1780 String.format(" %d FRAC %16.8f %16.8f %16.8f", i, frac[0], frac[1], frac[2]));
1781 logger.info(String.format(" %d COM %16.8f %16.8f %16.8f", i, com[0], com[1], com[2]));
1782 }
1783
1784
1785 for (Atom atom : list) {
1786 atom.move(com);
1787 }
1788 }
1789
1790
1791 List<MSNode> ions = getIons();
1792 for (MSNode ion : ions) {
1793 List<Atom> list = ion.getAtomList();
1794
1795 com[0] = 0.0;
1796 com[1] = 0.0;
1797 com[2] = 0.0;
1798 double totalMass = 0.0;
1799 for (Atom atom : list) {
1800 double m = atom.getMass();
1801 com[0] += atom.getX() * m;
1802 com[1] += atom.getY() * m;
1803 com[2] += atom.getZ() * m;
1804 totalMass += m;
1805 }
1806 com[0] /= totalMass;
1807 com[1] /= totalMass;
1808 com[2] /= totalMass;
1809
1810 unitCell.toFractionalCoordinates(com, com);
1811
1812 double[] frac = fractionalCoordinates[iMolecule++];
1813 com[0] = frac[0] - com[0];
1814 com[1] = frac[1] - com[1];
1815 com[2] = frac[2] - com[2];
1816
1817 unitCell.toCartesianCoordinates(com, com);
1818
1819 for (Atom atom : list) {
1820 atom.move(com);
1821 }
1822 }
1823 break;
1824 case ATOM:
1825 Atom[] atoms = getAtomArray();
1826 int nAtoms = atoms.length;
1827 for (int i = 0; i < nAtoms; i++) {
1828
1829
1830 unitCell.toCartesianCoordinates(fractionalCoordinates[i], com);
1831 atoms[i].moveTo(com);
1832 }
1833 break;
1834 case OFF:
1835 break;
1836 }
1837 }
1838
1839
1840
1841
1842
1843
1844 public void rotateAbout(Vector3d v) {
1845 Vector3d newRotPoint = new Vector3d(v);
1846 originToRot.getTransform(originToRotT3D);
1847 originToRotT3D.get(originToRotV3D);
1848 originToRotT3D.setTranslation(new Vector3d(0, 0, 0));
1849 rotToCOM.getTransform(rotToCOMT3D);
1850 rotToCOMT3D.get(rotToCOMV3D);
1851 newRotPoint.add(rotToCOMV3D);
1852 originToRotT3D.transform(newRotPoint);
1853 newRotPoint.add(originToRotV3D);
1854 originToRotT3D.setTranslation(newRotPoint);
1855 rotToCOMV3D.set(v);
1856 rotToCOMV3D.negate();
1857 rotToCOMT3D.setTranslation(rotToCOMV3D);
1858 originToRot.setTransform(originToRotT3D);
1859 rotToCOM.setTransform(rotToCOMT3D);
1860 }
1861
1862
1863
1864
1865
1866
1867 public void sceneGraphChange(List<BranchGroup> newShapes) {
1868 if (newShapes == null) {
1869 newShapes = myNewShapes;
1870 }
1871
1872 if (newShapes.isEmpty()) {
1873 return;
1874 }
1875
1876 boolean reCompile = false;
1877
1878
1879 for (ListIterator<BranchGroup> li = newShapes.listIterator(); li.hasNext(); ) {
1880 BranchGroup group = li.next();
1881 li.remove();
1882
1883 if (group.getUserData() != null) {
1884 logger.info(format("%s %s", group, group.getUserData().toString()));
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896 } else {
1897
1898
1899
1900 group.setUserData(this);
1901 if (!reCompile) {
1902 if (childNodes.isLive()) {
1903 childNodes.detach();
1904 }
1905
1906 reCompile = true;
1907 }
1908
1909 childNodes.addChild(group);
1910 }
1911 }
1912 if (reCompile) {
1913 childNodes.compile();
1914 base.addChild(childNodes);
1915 }
1916 }
1917
1918
1919
1920
1921 @Override
1922 public void setColor(RendererCache.ColorModel newColorModel, Color3f color, Material mat) {
1923 for (MSNode msNode : getAtomNodeList()) {
1924 MSGroup group = (MSGroup) msNode;
1925 group.setColor(newColorModel, color, mat);
1926 }
1927
1928 for (MSNode m : molecules.getChildList()) {
1929 m.setColor(newColorModel, color, mat);
1930 }
1931
1932 for (MSNode m : water.getChildList()) {
1933 m.setColor(newColorModel, color, mat);
1934 }
1935
1936 for (MSNode m : ions.getChildList()) {
1937 m.setColor(newColorModel, color, mat);
1938 }
1939 }
1940
1941
1942
1943
1944
1945
1946 public void setPotential(ForceFieldEnergy potentialEnergy) {
1947 this.potentialEnergy = potentialEnergy;
1948 }
1949
1950
1951
1952
1953 @Override
1954 public void setView(RendererCache.ViewModel newViewModel, List<BranchGroup> newShapes) {
1955
1956 if (newViewModel == RendererCache.ViewModel.DESTROY) {
1957 if (switchGroup != null) {
1958 switchGroup.setWhichChild(Switch.CHILD_NONE);
1959 }
1960 visible = false;
1961 } else if (newViewModel == RendererCache.ViewModel.SHOWVRML) {
1962 switchGroup.setWhichChild(Switch.CHILD_ALL);
1963 } else if (newViewModel == RendererCache.ViewModel.HIDEVRML) {
1964 switchGroup.setWhichChild(0);
1965 } else {
1966 setWireWidth(RendererCache.bondwidth);
1967 if (newViewModel == RendererCache.ViewModel.DETAIL && childNodes.isLive()) {
1968 childNodes.detach();
1969 }
1970
1971
1972
1973
1974
1975 super.setView(newViewModel, myNewShapes);
1976 List<Molecule> moleculeList = getList(Molecule.class, new ArrayList<>());
1977 for (Molecule m : moleculeList) {
1978 m.setView(newViewModel, myNewShapes);
1979 }
1980 for (MSNode m : molecules.getChildList()) {
1981 m.setView(newViewModel, myNewShapes);
1982 }
1983 for (MSNode m : water.getChildList()) {
1984 m.setView(newViewModel, myNewShapes);
1985 }
1986 for (MSNode m : ions.getChildList()) {
1987 m.setView(newViewModel, myNewShapes);
1988 }
1989 if (newViewModel == RendererCache.ViewModel.INVISIBLE) {
1990 switchGroup.setWhichChild(0);
1991 }
1992 if (newViewModel == RendererCache.ViewModel.DETAIL) {
1993 childNodes.compile();
1994 base.addChild(childNodes);
1995 }
1996 }
1997 }
1998
1999
2000
2001
2002
2003
2004 public void setWireWidth(float f) {
2005 if (wire == null) {
2006 return;
2007 }
2008
2009 lineAttributes.setLineWidth(f);
2010 }
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023 private BranchGroup createScene(boolean zero) {
2024 originToRotT3D = new Transform3D();
2025 originToRotV3D = new Vector3d();
2026 originToRot = new TransformGroup(originToRotT3D);
2027 branchGroup = new BranchGroup();
2028 rotToCOM = new TransformGroup();
2029 rotToCOMT3D = new Transform3D();
2030 rotToCOMV3D = new Vector3d();
2031
2032 branchGroup.setCapability(BranchGroup.ALLOW_DETACH);
2033 originToRot.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
2034 originToRot.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
2035 originToRot.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
2036 rotToCOM.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
2037 rotToCOM.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
2038
2039 if (zero) {
2040 originToRotV3D.set(0.0, 0.0, 0.0);
2041 originToRotT3D.set(originToRotV3D);
2042 originToRot.setTransform(originToRotT3D);
2043 }
2044 wire = renderWire();
2045 switchGroup = new Switch(Switch.CHILD_NONE);
2046 switchGroup.setCapability(Switch.ALLOW_SWITCH_WRITE);
2047 base = new BranchGroup();
2048 base.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
2049 base.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
2050 childNodes = new BranchGroup();
2051 childNodes.setCapability(BranchGroup.ALLOW_DETACH);
2052 childNodes.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
2053 childNodes.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
2054 switchGroup.addChild(base);
2055 if (wire != null) {
2056 base.addChild(wire);
2057 }
2058 vrml = loadVRML();
2059 if (vrml != null) {
2060 vrmlTG = new TransformGroup();
2061 vrmlTd = new Transform3D();
2062 vrmlTG.setTransform(vrmlTd);
2063 vrmlTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
2064 vrmlTG.addChild(vrml);
2065 switchGroup.addChild(vrmlTG);
2066 setView(RendererCache.ViewModel.INVISIBLE, null);
2067 }
2068 switchGroup.setWhichChild(Switch.CHILD_ALL);
2069 rotToCOM.addChild(switchGroup);
2070 originToRot.addChild(rotToCOM);
2071 branchGroup.addChild(originToRot);
2072 branchGroup.compile();
2073 return branchGroup;
2074 }
2075
2076 void finishDestruction() {
2077 detach();
2078 super.destroy();
2079 }
2080
2081
2082
2083
2084
2085
2086
2087 private void applyHeavyHydrogen() {
2088 List<Bond> bonds = getBondList();
2089 for (Bond bond : bonds) {
2090 Atom a1 = bond.getAtom(0);
2091 Atom a2 = bond.getAtom(1);
2092 if (a1.isHydrogen() && a2.isHeavy()) {
2093 double hydrogenMass = a1.getMass();
2094 double heavyAtomMass = a2.getMass();
2095 if (hydrogenMass < 1.1) {
2096 a2.setMass(heavyAtomMass - 2.0 * hydrogenMass);
2097 a1.setMass(3.0 * hydrogenMass);
2098 }
2099 } else if (a1.isHeavy() && a2.isHydrogen()) {
2100 double heavyAtomMass = a1.getMass();
2101 double hydrogenMass = a2.getMass();
2102 if (hydrogenMass < 1.1) {
2103 a1.setMass(heavyAtomMass - 2.0 * hydrogenMass);
2104 a2.setMass(3.0 * hydrogenMass);
2105 }
2106 }
2107 }
2108 }
2109
2110 private Atom getResidue(Atom atom, boolean create) {
2111 return getResidue(atom, create, Residue.ResidueType.UNK);
2112 }
2113
2114 private Atom getResidue(Atom atom, boolean create, ResidueType defaultRT) {
2115 Character chainID = atom.getChainID();
2116 String resName = atom.getResidueName();
2117 int resNum = atom.getResidueNumber();
2118 String segID = atom.getSegID();
2119
2120 Polymer polymer = getPolymer(chainID, segID, create);
2121 if (polymer == null) {
2122 return null;
2123 }
2124
2125 Residue res;
2126 if (titrateConformer) {
2127 res = polymer.getResidue(atomInitial.getResidueName(), atomInitial.getResidueNumber(), create, defaultRT);
2128 res.setName(atom.getResidueName());
2129 } else {
2130 res = polymer.getResidue(resName, resNum, create, defaultRT);
2131 }
2132 if (create && res != null) {
2133 res.setTitrateConformers(titrateConformer);
2134 if (titrateConformer) {
2135 res.setAtomInitial(atomInitial);
2136 }
2137 return (Atom) res.addMSNode(atom);
2138 }
2139 return null;
2140 }
2141
2142 private Atom getMolecule(Atom atom, boolean create) {
2143 String resName = atom.getResidueName();
2144 int resNum = atom.getResidueNumber();
2145 Character chainID = atom.getChainID();
2146 String segID = atom.getSegID();
2147
2148 String key = resNum + resName + segID;
2149 Molecule m = ionHashMap.get(key);
2150 if (m == null) {
2151 m = waterHashMap.get(key);
2152 if (m == null) {
2153 m = moleculeHashMap.get(key);
2154 }
2155 }
2156 if (m != null) {
2157 return (Atom) m.addMSNode(atom);
2158 }
2159
2160 if (create) {
2161 boolean isWater = false;
2162 boolean isIon = false;
2163 if (StringUtils.looksLikeWater(resName)) {
2164 if (!resName.equalsIgnoreCase("DOD")) {
2165 resName = StringUtils.STANDARD_WATER_NAME;
2166 }
2167 isWater = true;
2168 } else if (StringUtils.looksLikeIon(resName)) {
2169 resName = StringUtils.tryParseIon(resName);
2170 isIon = true;
2171 }
2172 atom.setResName(resName);
2173 m = new Molecule(resName, resNum, chainID, segID);
2174 m.addMSNode(atom);
2175 if (resName == null) {
2176 logger.warning(format(" Attempting to create a molecule %s with a null name on atom %s! Defaulting to creating a generic Molecule.",
2177 m, atom));
2178 molecules.add(m);
2179 moleculeHashMap.put(key, m);
2180 } else if (isWater) {
2181 water.add(m);
2182 waterHashMap.put(key, m);
2183 } else if (isIon) {
2184 ions.add(m);
2185 ionHashMap.put(key, m);
2186 } else {
2187 molecules.add(m);
2188 moleculeHashMap.put(key, m);
2189 }
2190 return atom;
2191 } else {
2192 return null;
2193 }
2194 }
2195
2196 private void recurseVRML(Node node) {
2197 if (node instanceof Shape3D) {
2198 Shape3D s3d = (Shape3D) node;
2199 PickTool.setCapabilities(s3d, PickTool.INTERSECT_COORD);
2200 } else if (node instanceof SharedGroup) {
2201 SharedGroup sg = (SharedGroup) node;
2202 for (Iterator<Node> e = sg.getAllChildren(); e.hasNext(); ) {
2203 recurseVRML(e.next());
2204 }
2205 } else if (node instanceof BranchGroup) {
2206 BranchGroup bg = (BranchGroup) node;
2207 for (Iterator<Node> e = bg.getAllChildren(); e.hasNext(); ) {
2208 recurseVRML(e.next());
2209 }
2210 } else if (node instanceof TransformGroup) {
2211 TransformGroup vrmlTG1 = (TransformGroup) node;
2212 for (Iterator<Node> e = vrmlTG1.getAllChildren(); e.hasNext(); ) {
2213 node = e.next();
2214 recurseVRML(node);
2215 }
2216 } else if (node instanceof Link) {
2217 Link link = (Link) node;
2218 recurseVRML(link.getSharedGroup());
2219 } else if (node instanceof Group) {
2220 Group group = (Group) node;
2221 for (Iterator<Node> e = group.getAllChildren(); e.hasNext(); ) {
2222 recurseVRML(e.next());
2223 }
2224 }
2225 }
2226
2227
2228
2229
2230 @Override
2231 protected void removeLeaves() {
2232 super.removeLeaves();
2233 MSNode macroNode = getAtomNode();
2234 if (macroNode != null) {
2235 if (macroNode.getChildCount() > 0) {
2236 getAtomNode().setName("Macromolecules " + "(" + macroNode.getChildCount() + ")");
2237 } else if (macroNode.getParent() == this) {
2238 removeChild(macroNode);
2239 }
2240 }
2241
2242 if (molecules.getChildCount() == 0) {
2243 removeChild(molecules);
2244 } else {
2245 molecules.setName("Hetero Molecules " + "(" + molecules.getChildCount() + ")");
2246 }
2247
2248 if (ions.getChildCount() == 0) {
2249 removeChild(ions);
2250 } else {
2251 ions.setName("Ions " + "(" + ions.getChildCount() + ")");
2252 }
2253
2254 if (water.getChildCount() == 0) {
2255 removeChild(water);
2256 } else {
2257 water.setName("Water " + "(" + water.getChildCount() + ")");
2258 }
2259 }
2260
2261 private Shape3D renderWire() {
2262 List<Bond> bonds = getBondList();
2263 int numbonds = bonds.size();
2264 if (numbonds < 1) {
2265 return null;
2266 }
2267
2268 Vector3d bondmidpoint = new Vector3d();
2269 double[] mid = {0, 0, 0};
2270 Vector3d v1 = new Vector3d();
2271 Vector3d v2 = new Vector3d();
2272 float[] a1 = {0, 0, 0};
2273 float[] a2 = {0, 0, 0};
2274 float[] col = new float[4];
2275
2276 Atom atom1, atom2;
2277 LineArray la =
2278 new LineArray(
2279 4 * numbonds,
2280 GeometryArray.COORDINATES | GeometryArray.COLOR_4 | GeometryArray.NORMALS);
2281 la.setCapability(LineArray.ALLOW_COORDINATE_WRITE);
2282 la.setCapability(LineArray.ALLOW_COORDINATE_READ);
2283 la.setCapability(LineArray.ALLOW_COLOR_WRITE);
2284 la.setCapability(LineArray.ALLOW_COUNT_READ);
2285 la.setCapability(LineArray.ALLOW_INTERSECT);
2286 la.setCapability(LineArray.ALLOW_FORMAT_READ);
2287 atomLookUp = new Atom[4 * numbonds];
2288 int i = 0;
2289 col[3] = 0.9f;
2290 for (Bond bond : bonds) {
2291 bond.setWire(la, i);
2292 atom1 = bond.getAtom(0);
2293 atom2 = bond.getAtom(1);
2294 atom1.getV3D(v1);
2295 atom2.getV3D(v2);
2296 a1[0] = (float) v1.x;
2297 a1[1] = (float) v1.y;
2298 a1[2] = (float) v1.z;
2299 a2[0] = (float) v2.x;
2300 a2[1] = (float) v2.y;
2301 a2[2] = (float) v2.z;
2302
2303 bondmidpoint.add(v1, v2);
2304 bondmidpoint.scale(0.5d);
2305 bondmidpoint.get(mid);
2306
2307
2308 Atom.AtomColor.get(atom1.getAtomicNumber()).get(col);
2309 atomLookUp[i] = atom1;
2310 la.setCoordinate(i, a1);
2311 la.setColor(i, col);
2312 la.setNormal(i, a2);
2313 i++;
2314
2315 atomLookUp[i] = atom1;
2316 la.setCoordinate(i, mid);
2317 la.setColor(i, col);
2318 la.setNormal(i, a2);
2319 i++;
2320
2321
2322 Atom.AtomColor.get(atom2.getAtomicNumber()).get(col);
2323 atomLookUp[i] = atom2;
2324 la.setCoordinate(i, a2);
2325 la.setColor(i, col);
2326 la.setNormal(i, a1);
2327 i++;
2328
2329 atomLookUp[i] = atom2;
2330 la.setCoordinate(i, mid);
2331 la.setColor(i, col);
2332 la.setNormal(i, a1);
2333 i++;
2334 }
2335
2336 ColoringAttributes cola =
2337 new ColoringAttributes(new Color3f(), ColoringAttributes.SHADE_GOURAUD);
2338 Appearance app = new Appearance();
2339 lineAttributes = new LineAttributes();
2340 lineAttributes.setLineWidth(RendererCache.bondwidth);
2341 lineAttributes.setCapability(LineAttributes.ALLOW_WIDTH_WRITE);
2342 lineAttributes.setLineAntialiasingEnable(true);
2343 app.setLineAttributes(lineAttributes);
2344 app.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_READ);
2345 app.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_WRITE);
2346 RenderingAttributes ra = new RenderingAttributes();
2347 ra.setAlphaTestValue(0.1f);
2348 ra.setAlphaTestFunction(RenderingAttributes.GREATER);
2349 ra.setDepthBufferEnable(true);
2350 ra.setDepthBufferWriteEnable(true);
2351 app.setRenderingAttributes(ra);
2352 app.setColoringAttributes(cola);
2353 Shape3D wireframe = new Shape3D(la, app);
2354
2355 wireframe.setUserData(this);
2356 wireframe.setBounds(new BoundingSphere(new Point3d(0, 0, 0), 1000.0));
2357 try {
2358 wireframe.setBoundsAutoCompute(false);
2359 } catch (Exception e) {
2360 logger.warning("Unable to set boundsAutoCompute to false.\n" + e);
2361 }
2362
2363 wireframe.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
2364 wireframe.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
2365 wireframe.setCapability(Shape3D.ALLOW_LOCAL_TO_VWORLD_READ);
2366 return wireframe;
2367 }
2368
2369
2370
2371
2372
2373
2374
2375
2376 public Residue getResidue(int polymerID, int resID) {
2377 Polymer[] polymers = getChains();
2378 if (polymers == null || polymers.length <= polymerID) {
2379 return null;
2380 }
2381 Polymer polymer = polymers[polymerID];
2382 List<Residue> residues = polymer.getResidues();
2383 if (residues == null || residues.size() <= resID) {
2384 return null;
2385 }
2386 return residues.get(resID);
2387 }
2388
2389
2390
2391
2392
2393
2394
2395 private List<Molecule> getAllWaterInclMistyped() {
2396 Stream<Molecule> mistyped =
2397 getMolecules()
2398 .parallelStream()
2399 .map((MSNode m) -> (Molecule) m)
2400 .filter(
2401 (Molecule m) -> {
2402 List<Atom> atoms = m.getAtomList();
2403 if (atoms.size() != 3) {
2404 return false;
2405 }
2406 int nO = 0;
2407 int nH = 0;
2408 for (Atom atom : atoms) {
2409 int el = atom.getAtomicNumber();
2410 if (el == 1) {
2411 ++nH;
2412 } else if (nH == 8) {
2413 ++nO;
2414 }
2415 }
2416 return nO == 1 && nH == 2;
2417 });
2418 return Stream.concat(mistyped, getWater().stream().map((MSNode m) -> (Molecule) m))
2419 .distinct()
2420 .collect(Collectors.toList());
2421 }
2422
2423
2424
2425
2426 void renameWaterProtons() {
2427 for (Molecule water : getAllWaterInclMistyped()) {
2428 Atom H1 = water.getAtomByName("H1", false);
2429 Atom H2 = water.getAtomByName("H2", false);
2430 if (H1 != null && H2 != null) {
2431 continue;
2432 }
2433 for (Atom a : water.getAtomList()) {
2434 if (a.getAtomicNumber() == 1) {
2435 if (H1 == null) {
2436 H1 = a;
2437 H1.setName("H1");
2438 } else if (H2 == null) {
2439 H2 = a;
2440 H2.setName("H2");
2441 }
2442 }
2443 }
2444 }
2445 }
2446
2447 private void moveIntoUnitCell(MSNode[] groups) {
2448 if (groups != null && groups.length > 0) {
2449 moveIntoUnitCell(Arrays.asList(groups));
2450 }
2451 }
2452
2453
2454
2455
2456
2457
2458 private void moveIntoUnitCell(List<MSNode> groups) {
2459 Crystal cryst = getCrystal().getUnitCell();
2460 if (cryst.aperiodic()) {
2461 return;
2462 }
2463 for (MSNode group : groups) {
2464 double[] com = new double[3];
2465 double[] xyz = new double[3];
2466 double[] translate = new double[3];
2467 List<Atom> atoms = group.getAtomList();
2468 double totMass = 0;
2469 for (Atom atom : atoms) {
2470 double mass = atom.getMass();
2471 totMass += mass;
2472 xyz = atom.getXYZ(xyz);
2473 com[0] += mass * xyz[0];
2474 com[1] += mass * xyz[1];
2475 com[2] += mass * xyz[2];
2476 }
2477 com[0] /= totMass;
2478 com[1] /= totMass;
2479 com[2] /= totMass;
2480
2481
2482 cryst.toPrimaryCell(com, translate);
2483
2484
2485 translate[0] -= com[0];
2486 translate[1] -= com[1];
2487 translate[2] -= com[2];
2488
2489 for (Atom atom : atoms) {
2490 atom.move(translate);
2491 }
2492 }
2493 }
2494
2495 public enum FractionalMode {
2496 OFF,
2497 MOLECULE,
2498 ATOM
2499 }
2500 }