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 ffx.numerics.math.DoubleMath;
41 import ffx.potential.bonded.Residue.ResidueType;
42 import ffx.potential.parameters.ForceField;
43
44 import java.io.Serial;
45 import java.util.ArrayList;
46 import java.util.Enumeration;
47 import java.util.HashMap;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Objects;
51 import javax.swing.tree.TreeNode;
52 import org.jogamp.java3d.BranchGroup;
53 import org.jogamp.java3d.Material;
54 import org.jogamp.vecmath.Color3f;
55
56
57
58
59
60
61
62 public class Polymer extends MSGroup {
63
64 @Serial
65 private static final long serialVersionUID = 1L;
66
67
68 private static final Map<Integer, Color3f> polymerColor = new HashMap<>();
69
70 private static int count = 0;
71
72 static {
73 polymerColor.put(0, RendererCache.RED);
74 polymerColor.put(1, RendererCache.ORANGE);
75 polymerColor.put(2, RendererCache.YELLOW);
76 polymerColor.put(3, RendererCache.GREEN);
77 polymerColor.put(4, RendererCache.BLUE);
78 polymerColor.put(5, RendererCache.MAGENTA);
79 polymerColor.put(6, RendererCache.CYAN);
80 polymerColor.put(7, RendererCache.WHITE);
81 polymerColor.put(8, RendererCache.GRAY);
82 polymerColor.put(9, RendererCache.PINK);
83 }
84
85 public static final String CHAIN_IDS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
86
87
88 private boolean link = false;
89
90 private final int polymerNumber;
91
92 private Character chainID;
93
94
95
96
97
98
99
100 public Polymer(Character chainID, String segID) {
101 super(segID);
102 this.chainID = chainID;
103 this.polymerNumber = ++count;
104 }
105
106
107
108
109
110
111
112
113 public Polymer(Character chainID, String segID, boolean link) {
114 this(chainID, segID);
115 this.link = link;
116 }
117
118
119
120
121
122
123
124
125 public Polymer(Character chainID, String segID, MSNode residues) {
126 super(segID, residues);
127 this.chainID = chainID;
128 polymerNumber = ++count;
129 }
130
131
132
133
134
135
136 @Override
137 public MSNode addMSNode(MSNode msNode) {
138 assert (msNode instanceof Residue);
139
140 Residue residue = (Residue) msNode;
141 int resNumber = residue.getResidueNumber();
142
143 MSNode residueNode = getAtomNode();
144 int n = residueNode.getChildCount();
145 int childIndex = n;
146
147 for (int i = 0; i < n; i++) {
148 Residue current = (Residue) residueNode.getChildAt(i);
149 if (current.getResidueNumber() > resNumber) {
150 childIndex = i;
151 break;
152 }
153 }
154
155 residueNode.insert(residue, childIndex);
156
157 residue.setChainID(chainID);
158
159 return msNode;
160 }
161
162
163
164
165
166
167 public void setChainID(Character chainID) {
168 this.chainID = chainID;
169 for (Residue residue : getResidues()) {
170 residue.setChainID(chainID);
171 }
172 }
173
174
175
176
177
178
179 public void setSegID(String segID) {
180 setName(segID);
181 for (Residue residue : getResidues()) {
182 residue.setSegID(segID);
183 }
184 }
185
186
187
188
189
190
191 public void addMultiResidue(MultiResidue multiResidue) {
192 Residue residue = multiResidue.getActive();
193 MSNode residueNode = getAtomNode();
194 int index = residueNode.getIndex(residue);
195
196 if (index < 0) {
197 System.err.println(
198 "WARNING! Polymer::addMultiResidue did not find a corresponding Residue on Polymer.");
199 residueNode.add(multiResidue);
200 } else {
201 residue.removeFromParent();
202 residueNode.insert(multiResidue, index);
203 multiResidue.add(residue);
204 }
205 }
206
207
208
209
210
211
212
213
214
215 public Joint createJoint(Residue residue1, Residue residue2, ForceField forceField) {
216 Joint joint = null;
217 double[] da = new double[3];
218 double[] db = new double[3];
219 for (Enumeration<TreeNode> e = residue1.getAtomNode().children(); e.hasMoreElements(); ) {
220 Atom a1 = (Atom) e.nextElement();
221 a1.getXYZ(da);
222 for (Enumeration<TreeNode> e2 = residue2.getAtomNode().children(); e2.hasMoreElements(); ) {
223 Atom a2 = (Atom) e2.nextElement();
224 a2.getXYZ(db);
225 double d1 = DoubleMath.dist(da, db);
226 double d2 = Bond.BUFF + a1.getVDWR() / 2 + a2.getVDWR() / 2;
227 if (d1 < d2) {
228 Bond b = new Bond(a1, a2);
229 Joint newJoint = createJoint(b, residue1, residue2, forceField);
230 if (joint != null) {
231 joint.merge(newJoint);
232 } else {
233 joint = newJoint;
234 }
235 }
236 }
237 }
238 return joint;
239 }
240
241
242
243
244
245
246 @Override
247 public boolean equals(Object o) {
248 if (this == o) {
249 return true;
250 }
251 if (o == null || getClass() != o.getClass()) {
252 return false;
253 }
254 Polymer polymer = (Polymer) o;
255 return polymerNumber == polymer.polymerNumber && Objects.equals(getName(), polymer.getName());
256 }
257
258
259
260
261
262
263
264
265 @Override
266 public void finalize(boolean finalizeGroups, ForceField forceField) {
267 List<MSNode> residues = getAtomNodeList();
268 setFinalized(false);
269
270
271 if (finalizeGroups) {
272 for (MSNode node : residues) {
273 Residue residue = (Residue) node;
274 residue.finalize(true, forceField);
275 }
276 }
277
278 if (link) {
279 Residue residue = getFirstResidue();
280 if (residue.residueType == Residue.ResidueType.AA) {
281 getAtomNode().setName("Amino Acids " + "(" + residues.size() + ")");
282 } else if (residue.residueType == Residue.ResidueType.NA) {
283 getAtomNode().setName("Nucleic Acids " + "(" + residues.size() + ")");
284 } else {
285 getAtomNode().setName("Residues " + "(" + residues.size() + ")");
286 }
287
288 Joint j;
289 MSNode joints = getTermNode();
290 joints.removeAllChildren();
291 List<Atom> atoms = getAtomList();
292 for (Atom a : atoms) {
293 if (a.getNumBonds() > 0) {
294 for (Bond b : a.getBonds()) {
295 if (!b.sameGroup() && b.getParent() == null) {
296 Residue r1 = a.getMSNode(Residue.class);
297 Residue r2 = b.get1_2(a).getMSNode(Residue.class);
298 j = createJoint(b, r1, r2, forceField);
299 joints.add(j);
300 }
301 }
302 }
303 }
304
305 if (residue.residueType == Residue.ResidueType.AA) {
306 getTermNode().setName("Peptide Bonds " + "(" + joints.getChildCount() + ")");
307 } else {
308 getTermNode().setName("Linkages " + "(" + joints.getChildCount() + ")");
309 }
310
311 } else {
312 getAtomNode().setName("Sub-Groups " + "(" + residues.size() + ")");
313 if (getTermNode().getParent() != null) {
314 removeChild(getTermNode());
315 }
316 }
317 removeLeaves();
318 setFinalized(true);
319 }
320
321
322
323
324
325
326 public Character getChainID() {
327 return chainID;
328 }
329
330
331
332
333
334
335 public Residue getFirstResidue() {
336 MSNode atomNode = getAtomNode();
337 if (atomNode == null) {
338 return null;
339 }
340 return (Residue) atomNode.getChildAt(0);
341 }
342
343
344
345
346
347
348 public boolean getLink() {
349 return link;
350 }
351
352
353
354
355
356
357 public void setLink(boolean link) {
358 this.link = link;
359 }
360
361
362
363
364
365
366 public List<List<Torsion>> getPhiPsiList() {
367 List<List<Torsion>> phiPsi = new ArrayList<>();
368 List<Torsion> phi = new ArrayList<>();
369 List<Torsion> psi = new ArrayList<>();
370 phiPsi.add(phi);
371 phiPsi.add(psi);
372 for (Residue residue : this.getResidues()) {
373 for (Torsion torsion : residue.getTorsionList()) {
374 Atom[] atoms = torsion.atoms;
375 StringBuilder s = new StringBuilder(atoms[0].getName());
376 for (int i = 1; i < 4; i++) {
377 s.append("-").append(atoms[i].getName());
378 }
379
380 if (s.toString().equals("C-N-CA-C") || s.toString().equals("C-CA-N-C")) {
381 phi.add(torsion);
382 }
383 else if (s.toString().equals("N-C-CA-N") || s.toString().equals("N-CA-C-N")) {
384 psi.add(torsion);
385 }
386 }
387 }
388 return phiPsi;
389 }
390
391
392
393
394
395
396
397 public Residue getResidue(int resNum) {
398 if (resNum > 0 && getAtomNode().getChildCount() >= resNum) {
399 Residue r = (Residue) getAtomNode().getChildAt(resNum - 1);
400 if (r.getResidueNumber() == resNum) {
401 return r;
402 }
403 }
404
405 for (Enumeration<TreeNode> e = getAtomNode().children(); e.hasMoreElements(); ) {
406 Residue r = (Residue) e.nextElement();
407 if (r.getResidueNumber() == resNum) {
408 return r;
409 }
410 }
411 return null;
412 }
413
414
415
416
417
418
419
420
421
422 public Residue getResidue(String resName, int resNum, boolean create) {
423 return getResidue(resName, resNum, create, Residue.ResidueType.UNK);
424 }
425
426
427
428
429
430
431
432
433
434
435 public Residue getResidue(String resName, int resNum, boolean create, ResidueType defaultRT) {
436 for (Enumeration<TreeNode> e = getAtomNode().children(); e.hasMoreElements(); ) {
437 Residue r = (Residue) e.nextElement();
438 if (r.getResidueNumber() == resNum && r.getName().equalsIgnoreCase(resName)) {
439 return r;
440 } else if (resName.equals(AminoAcidUtils.AminoAcid3.UNK.name())
441 && resNum == r.getResidueNumber()) {
442 return r;
443 }
444 }
445 if (!create) {
446 return null;
447 }
448 Residue residue = null;
449 resName = resName.toUpperCase();
450 if (resName.length() == 1) {
451 try {
452 NucleicAcidUtils.NucleicAcid1.valueOf(resName);
453 residue = new Residue(resName, resNum, Residue.ResidueType.NA, chainID, getName());
454 } catch (Exception e) {
455 try {
456 AminoAcidUtils.AminoAcid1.valueOf(resName);
457 residue = new Residue(resName, resNum, Residue.ResidueType.AA, chainID, getName());
458 } catch (Exception ex) {
459
460 }
461 }
462 } else if (resName.length() >= 2) {
463 try {
464 NucleicAcidUtils.NucleicAcid3.valueOf(resName);
465 residue = new Residue(resName, resNum, Residue.ResidueType.NA, chainID, getName());
466 } catch (Exception e) {
467 try {
468 AminoAcidUtils.AminoAcid3.valueOf(resName);
469 residue = new Residue(resName, resNum, Residue.ResidueType.AA, chainID, getName());
470 } catch (Exception ex) {
471
472 }
473 }
474 }
475 if (residue == null) {
476 residue = new Residue(resName, resNum, defaultRT, chainID, getName());
477 }
478 addMSNode(residue);
479 return residue;
480 }
481
482
483
484
485
486
487 public List<Residue> getResidues() {
488 List<Residue> residues = new ArrayList<>();
489 for (Enumeration<TreeNode> e = getAtomNode().children(); e.hasMoreElements(); ) {
490 Residue r = (Residue) e.nextElement();
491 residues.add(r);
492 }
493 return residues;
494 }
495
496
497 @Override
498 public int hashCode() {
499 return Objects.hash(polymerNumber, getName());
500 }
501
502
503 @Override
504 public void setColor(RendererCache.ColorModel newColorModel, Color3f color, Material mat) {
505
506 if (newColorModel == RendererCache.ColorModel.POLYMER) {
507 int index = polymerNumber % 10;
508 color = polymerColor.get(index);
509 mat = RendererCache.materialFactory(color);
510 }
511 for (MSNode node : getAtomNodeList()) {
512 MSGroup atomGroup = (MSGroup) node;
513 atomGroup.setColor(newColorModel, color, mat);
514 }
515 for (Enumeration<TreeNode> e = getTermNode().children(); e.hasMoreElements(); ) {
516 Joint joint = (Joint) e.nextElement();
517 joint.setColor(newColorModel);
518 }
519 }
520
521
522 @Override
523 public void setView(RendererCache.ViewModel newViewModel, List<BranchGroup> newShapes) {
524 for (MSNode node : getAtomNodeList()) {
525 MSGroup atomGroup = (MSGroup) node;
526 atomGroup.setView(newViewModel, newShapes);
527 }
528 for (Enumeration<TreeNode> e = getTermNode().children(); e.hasMoreElements(); ) {
529 Joint joint = (Joint) e.nextElement();
530 joint.setView(newViewModel, newShapes);
531 }
532 }
533 }