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 public Joint createJoint(Residue residue1, Residue residue2, ForceField forceField) {
213 Joint joint = null;
214 double[] da = new double[3];
215 double[] db = new double[3];
216 for (Enumeration<TreeNode> e = residue1.getAtomNode().children(); e.hasMoreElements(); ) {
217 Atom a1 = (Atom) e.nextElement();
218 a1.getXYZ(da);
219 for (Enumeration<TreeNode> e2 = residue2.getAtomNode().children(); e2.hasMoreElements(); ) {
220 Atom a2 = (Atom) e2.nextElement();
221 a2.getXYZ(db);
222 double d1 = DoubleMath.dist(da, db);
223 double d2 = Bond.BUFF + a1.getVDWR() / 2 + a2.getVDWR() / 2;
224 if (d1 < d2) {
225 Bond b = new Bond(a1, a2);
226 Joint newJoint = createJoint(b, residue1, residue2, forceField);
227 if (joint != null) {
228 joint.merge(newJoint);
229 } else {
230 joint = newJoint;
231 }
232 }
233 }
234 }
235 return joint;
236 }
237
238
239
240
241
242
243 @Override
244 public boolean equals(Object o) {
245 if (this == o) {
246 return true;
247 }
248 if (o == null || getClass() != o.getClass()) {
249 return false;
250 }
251 Polymer polymer = (Polymer) o;
252 return polymerNumber == polymer.polymerNumber && Objects.equals(getName(), polymer.getName());
253 }
254
255
256
257
258
259
260
261
262 @Override
263 public void finalize(boolean finalizeGroups, ForceField forceField) {
264 List<MSNode> residues = getAtomNodeList();
265 setFinalized(false);
266
267
268 if (finalizeGroups) {
269 for (MSNode node : residues) {
270 Residue residue = (Residue) node;
271 residue.finalize(true, forceField);
272 }
273 }
274
275 if (link) {
276 Residue residue = getFirstResidue();
277 if (residue.residueType == Residue.ResidueType.AA) {
278 getAtomNode().setName("Amino Acids " + "(" + residues.size() + ")");
279 } else if (residue.residueType == Residue.ResidueType.NA) {
280 getAtomNode().setName("Nucleic Acids " + "(" + residues.size() + ")");
281 } else {
282 getAtomNode().setName("Residues " + "(" + residues.size() + ")");
283 }
284
285 Joint j;
286 MSNode joints = getTermNode();
287 joints.removeAllChildren();
288 List<Atom> atoms = getAtomList();
289 for (Atom a : atoms) {
290 if (a.getNumBonds() > 0) {
291 for (Bond b : a.getBonds()) {
292 if (!b.sameGroup() && b.getParent() == null) {
293 Residue r1 = a.getMSNode(Residue.class);
294 Residue r2 = b.get1_2(a).getMSNode(Residue.class);
295 j = createJoint(b, r1, r2, forceField);
296 joints.add(j);
297 }
298 }
299 }
300 }
301
302 if (residue.residueType == Residue.ResidueType.AA) {
303 getTermNode().setName("Peptide Bonds " + "(" + joints.getChildCount() + ")");
304 } else {
305 getTermNode().setName("Linkages " + "(" + joints.getChildCount() + ")");
306 }
307
308 } else {
309 getAtomNode().setName("Sub-Groups " + "(" + residues.size() + ")");
310 if (getTermNode().getParent() != null) {
311 removeChild(getTermNode());
312 }
313 }
314 removeLeaves();
315 setFinalized(true);
316 }
317
318
319
320
321
322
323 public Character getChainID() {
324 return chainID;
325 }
326
327
328
329
330
331
332 public Residue getFirstResidue() {
333 MSNode atomNode = getAtomNode();
334 if (atomNode == null) {
335 return null;
336 }
337 return (Residue) atomNode.getChildAt(0);
338 }
339
340
341
342
343
344
345 public boolean getLink() {
346 return link;
347 }
348
349
350
351
352
353
354 public void setLink(boolean link) {
355 this.link = link;
356 }
357
358
359
360
361
362
363 public List<List<Torsion>> getPhiPsiList() {
364 List<List<Torsion>> phiPsi = new ArrayList<>();
365 List<Torsion> phi = new ArrayList<>();
366 List<Torsion> psi = new ArrayList<>();
367 phiPsi.add(phi);
368 phiPsi.add(psi);
369 for (Residue residue : this.getResidues()) {
370 for (Torsion torsion : residue.getTorsionList()) {
371 Atom[] atoms = torsion.atoms;
372 StringBuilder s = new StringBuilder(atoms[0].getName());
373 for (int i = 1; i < 4; i++) {
374 s.append("-").append(atoms[i].getName());
375 }
376
377 if (s.toString().equals("C-N-CA-C") || s.toString().equals("C-CA-N-C")) {
378 phi.add(torsion);
379 }
380 else if (s.toString().equals("N-C-CA-N") || s.toString().equals("N-CA-C-N")) {
381 psi.add(torsion);
382 }
383 }
384 }
385 return phiPsi;
386 }
387
388
389
390
391
392
393
394 public Residue getResidue(int resNum) {
395 if (resNum > 0 && getAtomNode().getChildCount() >= resNum) {
396 Residue r = (Residue) getAtomNode().getChildAt(resNum - 1);
397 if (r.getResidueNumber() == resNum) {
398 return r;
399 }
400 }
401
402 for (Enumeration<TreeNode> e = getAtomNode().children(); e.hasMoreElements(); ) {
403 Residue r = (Residue) e.nextElement();
404 if (r.getResidueNumber() == resNum) {
405 return r;
406 }
407 }
408 return null;
409 }
410
411
412
413
414
415
416
417
418
419 public Residue getResidue(String resName, int resNum, boolean create) {
420 return getResidue(resName, resNum, create, Residue.ResidueType.UNK);
421 }
422
423
424
425
426
427
428
429
430
431
432 public Residue getResidue(String resName, int resNum, boolean create, ResidueType defaultRT) {
433 for (Enumeration<TreeNode> e = getAtomNode().children(); e.hasMoreElements(); ) {
434 Residue r = (Residue) e.nextElement();
435 if (r.getResidueNumber() == resNum && r.getName().equalsIgnoreCase(resName)) {
436 return r;
437 } else if (resName.equals(AminoAcidUtils.AminoAcid3.UNK.name())
438 && resNum == r.getResidueNumber()) {
439 return r;
440 }
441 }
442 if (!create) {
443 return null;
444 }
445 Residue residue = null;
446 resName = resName.toUpperCase();
447 if (resName.length() == 1) {
448 try {
449 NucleicAcidUtils.NucleicAcid1.valueOf(resName);
450 residue = new Residue(resName, resNum, Residue.ResidueType.NA, chainID, getName());
451 } catch (Exception e) {
452 try {
453 AminoAcidUtils.AminoAcid1.valueOf(resName);
454 residue = new Residue(resName, resNum, Residue.ResidueType.AA, chainID, getName());
455 } catch (Exception ex) {
456
457 }
458 }
459 } else if (resName.length() >= 2) {
460 try {
461 NucleicAcidUtils.NucleicAcid3.valueOf(resName);
462 residue = new Residue(resName, resNum, Residue.ResidueType.NA, chainID, getName());
463 } catch (Exception e) {
464 try {
465 AminoAcidUtils.AminoAcid3.valueOf(resName);
466 residue = new Residue(resName, resNum, Residue.ResidueType.AA, chainID, getName());
467 } catch (Exception ex) {
468
469 }
470 }
471 }
472 if (residue == null) {
473 residue = new Residue(resName, resNum, defaultRT, chainID, getName());
474 }
475 addMSNode(residue);
476 return residue;
477 }
478
479
480
481
482
483
484 public List<Residue> getResidues() {
485 List<Residue> residues = new ArrayList<>();
486 for (Enumeration<TreeNode> e = getAtomNode().children(); e.hasMoreElements(); ) {
487 Residue r = (Residue) e.nextElement();
488 residues.add(r);
489 }
490 return residues;
491 }
492
493
494 @Override
495 public int hashCode() {
496 return Objects.hash(polymerNumber, getName());
497 }
498
499
500 @Override
501 public void setColor(RendererCache.ColorModel newColorModel, Color3f color, Material mat) {
502
503 if (newColorModel == RendererCache.ColorModel.POLYMER) {
504 int index = polymerNumber % 10;
505 color = polymerColor.get(index);
506 mat = RendererCache.materialFactory(color);
507 }
508 for (MSNode node : getAtomNodeList()) {
509 MSGroup atomGroup = (MSGroup) node;
510 atomGroup.setColor(newColorModel, color, mat);
511 }
512 for (Enumeration<TreeNode> e = getTermNode().children(); e.hasMoreElements(); ) {
513 Joint joint = (Joint) e.nextElement();
514 joint.setColor(newColorModel);
515 }
516 }
517
518
519 @Override
520 public void setView(RendererCache.ViewModel newViewModel, List<BranchGroup> newShapes) {
521 for (MSNode node : getAtomNodeList()) {
522 MSGroup atomGroup = (MSGroup) node;
523 atomGroup.setView(newViewModel, newShapes);
524 }
525 for (Enumeration<TreeNode> e = getTermNode().children(); e.hasMoreElements(); ) {
526 Joint joint = (Joint) e.nextElement();
527 joint.setView(newViewModel, newShapes);
528 }
529 }
530 }