1 /* $RCSfile$ 2 * $Author: egonw $ 3 * $Date: 2005-11-10 09:52:44 -0600 (Thu, 10 Nov 2005) $ 4 * $Revision: 4255 $ 5 * 6 * Copyright (C) 2004-2005 The Jmol Development Team 7 * 8 * Contact: jmol-developers@lists.sf.net 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 23 */ 24 25 package org.jmol.modelsetbio; 26 27 import java.util.Arrays; 28 29 import java.util.Comparator; 30 import java.util.Hashtable; 31 import java.util.Map; 32 import java.util.Properties; 33 34 35 import javajs.util.BS; 36 import org.jmol.modelset.Atom; 37 import org.jmol.modelset.AtomCollection; 38 import org.jmol.modelset.Bond; 39 import org.jmol.modelset.Chain; 40 import org.jmol.modelset.Group; 41 import org.jmol.modelset.Model; 42 import org.jmol.modelset.ModelLoader; 43 import org.jmol.modelset.ModelSet; 44 import org.jmol.script.SV; 45 import org.jmol.script.T; 46 import org.jmol.util.BSUtil; 47 import org.jmol.util.Edge; 48 import org.jmol.util.Logger; 49 50 import javajs.util.AU; 51 import javajs.util.Measure; 52 import javajs.util.PT; 53 import javajs.util.SB; 54 import javajs.util.P3; 55 import javajs.util.P4; 56 import javajs.util.V3; 57 import org.jmol.viewer.JC; 58 import org.jmol.viewer.Viewer; 59 import org.jmol.api.JmolAdapter; 60 import org.jmol.api.JmolAdapterAtomIterator; 61 import org.jmol.api.JmolAdapterStructureIterator; 62 import org.jmol.c.STR; 63 64 /** 65 * a class used by ModelLoader to handle all loading 66 * of operations specific to PDB/mmCIF files. By loading 67 * only by class name, only loaded if PDB file is called. 68 * 69 * In addition, constants relating only to PDB files are here 70 * -- for coloring by chain, selecting by protein, etc. 71 * 72 * 73 */ 74 public final class BioResolver implements Comparator<String[]> { 75 76 public final static Map<String, Short> htGroup = new Hashtable<String, Short>(); 77 78 private Viewer vwr; 79 BioResolver()80 public BioResolver() { 81 // only implemented via reflection, and only for PDB/mmCIF files 82 } 83 84 private V3 vAB; 85 private V3 vNorm; 86 private P4 plane; 87 88 private ModelLoader ml; 89 private ModelSet ms; 90 91 private BS bsAddedMask; 92 private int lastSetH = Integer.MIN_VALUE; 93 private int maxSerial = 0; 94 private boolean haveHsAlready; 95 setLoader(ModelLoader modelLoader)96 public BioResolver setLoader(ModelLoader modelLoader) { 97 ml = modelLoader; 98 bsAddedMask = null; 99 lastSetH = Integer.MIN_VALUE; 100 maxSerial = 0; 101 haveHsAlready = false; 102 if (modelLoader == null) { 103 ms = null; 104 bsAddedHydrogens = bsAtomsForHs = bsAssigned = null; 105 htBondMap = null; 106 htGroupBonds = null; 107 hNames = null; 108 } else { 109 Group.specialAtomNames = specialAtomNames; 110 ms = modelLoader.ms; 111 vwr = modelLoader.ms.vwr; 112 modelLoader.specialAtomIndexes = new int[ATOMID_MAX]; 113 hasCONECT = (ms.getInfoM("someModelsHaveCONECT") == Boolean.TRUE); 114 } 115 return this; 116 } 117 setViewer(Viewer vwr)118 public BioResolver setViewer(Viewer vwr) { 119 this.vwr = vwr; 120 if (Group.standardGroupList == null) { 121 //generate a static list of common amino acids, nucleic acid bases, and solvent components 122 SB s = new SB(); 123 //for menu presentation order 124 for (int i = 1; i < JC.GROUPID_WATER; i++) 125 s.append(",[").append(predefinedGroup3Names[i]).append("]"); 126 s.append(allCarbohydrates); 127 group3Count = s.length() / 6; 128 Group.standardGroupList = s.toString(); 129 for (int i = 0, n = predefinedGroup3Names.length; i < n; ++i) 130 addGroup3Name(predefinedGroup3Names[i].trim()); 131 } 132 return this; 133 } 134 getBioModel(int modelIndex, int trajectoryBaseIndex, String jmolData, Properties modelProperties, Map<String, Object> modelAuxiliaryInfo)135 public Model getBioModel(int modelIndex, 136 int trajectoryBaseIndex, String jmolData, 137 Properties modelProperties, 138 Map<String, Object> modelAuxiliaryInfo) { 139 return new BioModel(ms, modelIndex, trajectoryBaseIndex, 140 jmolData, modelProperties, modelAuxiliaryInfo); 141 } 142 distinguishAndPropagateGroup(Chain chain, String group3, int seqcode, int firstAtomIndex, int lastAtomIndex, int[] specialAtomIndexes, Atom[] atoms)143 public Group distinguishAndPropagateGroup(Chain chain, String group3, 144 int seqcode, int firstAtomIndex, 145 int lastAtomIndex, 146 int[] specialAtomIndexes, 147 Atom[] atoms) { 148 /* 149 * called by finalizeGroupBuild() 150 * 151 * first: build array of special atom names, for example "CA" for the alpha 152 * carbon is assigned #2 see JmolConstants.specialAtomNames[] the special 153 * atoms all have IDs based on Atom.lookupSpecialAtomID(atomName) these will 154 * be the same for each conformation 155 * 156 * second: creates the monomers themselves based on this information thus 157 * building the byte offsets[] array for each monomer, indicating which 158 * position relative to the first atom in the group is which atom. Each 159 * monomer.offsets[i] then points to the specific atom of that type these 160 * will NOT be the same for each conformation 161 */ 162 163 int mask = 0; 164 165 // clear previous specialAtomIndexes 166 for (int i = ATOMID_MAX; --i >= 0;) 167 specialAtomIndexes[i] = Integer.MIN_VALUE; 168 169 // go last to first so that FIRST confirmation is default 170 for (int i = lastAtomIndex; i >= firstAtomIndex; --i) { 171 int specialAtomID = atoms[i].atomID; 172 if (specialAtomID <= 0) 173 continue; 174 if (specialAtomID < JC.ATOMID_DISTINGUISHING_ATOM_MAX) { 175 /* 176 * save for future option -- turns out the 1jsa bug was in relation to 177 * an author using the same group number for two different groups 178 * 179 * if ((distinguishingBits & (1 << specialAtomID) != 0) { 180 * 181 * //bh 9/21/2006: // 182 * "if the group has two of the same, that cannot be right." // Thus, 183 * for example, two C's doth not make a protein "carbonyl C" 184 * distinguishingBits = 0; break; } 185 */ 186 mask |= (1 << specialAtomID); 187 } 188 specialAtomIndexes[specialAtomID] = i; 189 } 190 191 Monomer m = null; 192 if ((mask & JC.ATOMID_PROTEIN_MASK) == JC.ATOMID_PROTEIN_MASK) 193 m = AminoMonomer.validateAndAllocate(chain, group3, seqcode, 194 firstAtomIndex, lastAtomIndex, specialAtomIndexes, atoms); 195 else if (mask == JC.ATOMID_ALPHA_ONLY_MASK) 196 m = AlphaMonomer.validateAndAllocateA(chain, group3, seqcode, 197 firstAtomIndex, lastAtomIndex, specialAtomIndexes); 198 else if (((mask & JC.ATOMID_NUCLEIC_MASK) == JC.ATOMID_NUCLEIC_MASK)) 199 m = NucleicMonomer.validateAndAllocate(chain, group3, seqcode, 200 firstAtomIndex, lastAtomIndex, specialAtomIndexes); 201 else if (mask == JC.ATOMID_PHOSPHORUS_ONLY_MASK) 202 m = PhosphorusMonomer.validateAndAllocateP(chain, group3, seqcode, 203 firstAtomIndex, lastAtomIndex, specialAtomIndexes); 204 else if (checkCarbohydrate(group3)) 205 m = CarbohydrateMonomer.validateAndAllocate(chain, group3, seqcode, 206 firstAtomIndex, lastAtomIndex); 207 return ( m != null && m.leadAtomIndex >= 0 ? m : null); 208 } 209 210 //////////// ADDITION OF HYDROGEN ATOMS ///////////// 211 // Bob Hanson and Erik Wyatt, Jmol 12.1.51, 7/1/2011 212 213 /* 214 * for each group, as it is finished in the file reading: 215 * 216 * 1) get and store atom/bond information for group type 217 * 2) add placeholder (deleted) hydrogen atoms to a group 218 * 219 * in the end: 220 * 221 * 3) set multiple bonding and charges 222 * 4) determine actual number of required hydrogen atoms 223 * 5) set hydrogen atom names, atom numbers, and positions 224 * 6) undelete those atoms 225 * 226 */ 227 setHaveHsAlready(boolean b)228 public void setHaveHsAlready(boolean b) { 229 haveHsAlready = b; 230 } 231 232 private BS bsAddedHydrogens; 233 private BS bsAtomsForHs; 234 private Map<String, String>htBondMap; 235 private Map<String, Boolean>htGroupBonds; 236 private String[] hNames; 237 private int baseBondIndex = 0; 238 239 private boolean hasCONECT; 240 initializeHydrogenAddition()241 public void initializeHydrogenAddition() { 242 baseBondIndex = ms.bondCount; 243 bsAddedHydrogens = new BS(); 244 bsAtomsForHs = new BS(); 245 htBondMap = new Hashtable<String, String>(); 246 htGroupBonds = new Hashtable<String, Boolean>(); 247 hNames = new String[3]; 248 vAB = new V3(); 249 vNorm = new V3(); 250 plane = new P4(); 251 } 252 253 /** 254 * Get bonding info for double bonds and add implicit hydrogen atoms, if needed. 255 * 256 * @param adapter 257 * @param iGroup this group 258 * @param nH legacy quirk 259 */ addImplicitHydrogenAtoms(JmolAdapter adapter, int iGroup, int nH)260 public void addImplicitHydrogenAtoms(JmolAdapter adapter, int iGroup, int nH) { 261 String group3 = ml.getGroup3(iGroup); 262 int nH1; 263 if (haveHsAlready && hasCONECT 264 || group3 == null 265 || (nH1 = getStandardPdbHydrogenCount(group3)) == 0) 266 return; 267 nH = (nH1 < 0 ? -1 : nH1 + nH); 268 Object model = null; 269 int iFirst = ml.getFirstAtomIndex(iGroup); 270 int ac = ms.ac; 271 if (nH < 0) { 272 if (ac - iFirst == 1) // CA or P-only, or simple metals, also HOH, DOD 273 return; 274 model = vwr.getLigandModel(group3, "ligand_", "_data", null); 275 if (model == null) 276 return; 277 nH = adapter.getHydrogenAtomCount(model); 278 if (nH < 1) 279 return; 280 } 281 getBondInfo(adapter, group3, model); 282 ms.am[ms.at[iFirst].mi].isPdbWithMultipleBonds = true; 283 if (haveHsAlready) 284 return; 285 bsAtomsForHs.setBits(iFirst, ac); 286 bsAddedHydrogens.setBits(ac, ac + nH); 287 boolean isHetero = ms.at[iFirst].isHetero(); 288 P3 xyz = P3.new3(Float.NaN, Float.NaN, Float.NaN); 289 Atom a = ms.at[iFirst]; 290 for (int i = 0; i < nH; i++) 291 ms.addAtom(a.mi, a.group, 1, "H", null, 0, a.getSeqID(), 0, xyz, 292 Float.NaN, null, 0, 0, 1, 0, null, isHetero, (byte) 0, null, Float.NaN) 293 .delete(null); 294 } 295 getBondInfo(JmolAdapter adapter, String group3, Object model)296 private void getBondInfo(JmolAdapter adapter, String group3, Object model) { 297 if (htGroupBonds.get(group3) != null) 298 return; 299 String[][] bondInfo = (model == null ? getPdbBondInfo(group3, 300 vwr.g.legacyHAddition) : getLigandBondInfo(adapter, model, group3)); 301 if (bondInfo == null) 302 return; 303 htGroupBonds.put(group3, Boolean.TRUE); 304 for (int i = 0; i < bondInfo.length; i++) { 305 if (bondInfo[i] == null) 306 continue; 307 if (bondInfo[i][1].charAt(0) == 'H') 308 htBondMap.put(group3 + "." + bondInfo[i][0], bondInfo[i][1]); 309 else 310 htBondMap.put(group3 + ":" + bondInfo[i][0] + ":" + bondInfo[i][1], 311 bondInfo[i][2]); 312 } 313 } 314 315 /** 316 * reads PDB ligand CIF info and creates a bondInfo object. 317 * 318 * @param adapter 319 * @param model 320 * @param group3 321 * @return [[atom1, atom2, order]...] 322 */ getLigandBondInfo(JmolAdapter adapter, Object model, String group3)323 private String[][] getLigandBondInfo(JmolAdapter adapter, Object model, String group3) { 324 String[][] dataIn = adapter.getBondList(model); 325 Map<String, P3> htAtoms = new Hashtable<String, P3>(); 326 JmolAdapterAtomIterator iterAtom = adapter.getAtomIterator(model); 327 while (iterAtom.hasNext()) 328 htAtoms.put(iterAtom.getAtomName(), iterAtom.getXYZ()); 329 String[][] bondInfo = new String[dataIn.length * 2][]; 330 int n = 0; 331 for (int i = 0; i < dataIn.length; i++) { 332 String[] b = dataIn[i]; 333 if (b[0].charAt(0) != 'H') 334 bondInfo[n++] = new String[] { b[0], b[1], b[2], 335 b[1].startsWith("H") ? "0" : "1" }; 336 if (b[1].charAt(0) != 'H') 337 bondInfo[n++] = new String[] { b[1], b[0], b[2], 338 b[0].startsWith("H") ? "0" : "1" }; 339 } 340 Arrays.sort(bondInfo, this); 341 // now look for 342 String[] t; 343 for (int i = 0; i < n;) { 344 t = bondInfo[i]; 345 String a1 = t[0]; 346 int nH = 0; 347 int nC = 0; 348 for (; i < n && (t = bondInfo[i])[0].equals(a1); i++) { 349 if (t[3].equals("0")) { 350 nH++; 351 continue; 352 } 353 if (t[3].equals("1")) 354 nC++; 355 } 356 int pt = i - nH - nC; 357 if (nH == 1) 358 continue; 359 switch (nC) { 360 case 1: 361 char sep = (nH == 2 ? '@' : '|'); 362 for (int j = 1; j < nH; j++) { 363 bondInfo[pt][1] += sep + bondInfo[pt + j][1]; 364 bondInfo[pt + j] = null; 365 } 366 continue; 367 case 2: 368 if (nH != 2) 369 continue; 370 String name = bondInfo[pt][0]; 371 String name1 = bondInfo[pt + nH][1]; 372 String name2 = bondInfo[pt + nH + 1][1]; 373 int factor = name1.compareTo(name2); 374 Measure.getPlaneThroughPoints(htAtoms.get(name1), htAtoms.get(name), htAtoms.get(name2), vNorm, vAB, 375 plane); 376 float d = Measure.distanceToPlane(plane, htAtoms.get(bondInfo[pt][1])) * factor; 377 bondInfo[pt][1] = (d > 0 ? bondInfo[pt][1] + "@" + bondInfo[pt + 1][1] 378 : bondInfo[pt + 1][1] + "@" + bondInfo[pt][1]); 379 bondInfo[pt + 1] = null; 380 } 381 } 382 for (int i = 0; i < n; i++) { 383 if ((t = bondInfo[i]) != null && t[1].charAt(0) != 'H' && t[0].compareTo(t[1]) > 0) { 384 bondInfo[i] = null; 385 continue; 386 } 387 if (t != null) 388 Logger.info(" ligand " + group3 + ": " + bondInfo[i][0] + " - " + bondInfo[i][1] + " order " + bondInfo[i][2]); 389 } 390 return bondInfo; 391 } 392 393 @Override compare(String[] a, String[] b)394 public int compare(String[] a, String[] b) { 395 return (b == null ? (a == null ? 0 : -1) : a == null ? 1 : a[0] 396 .compareTo(b[0]) < 0 ? -1 : a[0].compareTo(b[0]) > 0 ? 1 : a[3] 397 .compareTo(b[3]) < 0 ? -1 : a[3].compareTo(b[3]) > 0 ? 1 : a[1] 398 .compareTo(b[1]) < 0 ? -1 : a[1].compareTo(b[1]) > 0 ? 1 : 0); 399 } 400 finalizeHydrogens()401 public void finalizeHydrogens() { 402 vwr.getLigandModel(null, null, null, null); 403 finalizePdbMultipleBonds(); 404 addHydrogens(); 405 } 406 addHydrogens()407 private void addHydrogens() { 408 if (bsAddedHydrogens.nextSetBit(0) < 0) 409 return; 410 bsAddedMask = BSUtil.copy(bsAddedHydrogens); 411 finalizePdbCharges(); 412 int[] nTotal = new int[1]; 413 P3[][] pts = ms.calculateHydrogens(bsAtomsForHs, nTotal, null, AtomCollection.CALC_H_DOALL); 414 Group groupLast = null; 415 int ipt = 0; 416 Atom atom; 417 for (int i = 0; i < pts.length; i++) { 418 if (pts[i] == null || (atom = ms.at[i]) == null) 419 continue; 420 Group g = atom.group; 421 if (g != groupLast) { 422 groupLast = g; 423 ipt = g.lastAtomIndex; 424 while (bsAddedHydrogens.get(ipt)) 425 ipt--; 426 } 427 String gName = atom.getGroup3(false); 428 String aName = atom.getAtomName(); 429 String hName = htBondMap.get(gName + "." + aName); 430 if (hName == null) 431 continue; 432 boolean isChiral = hName.contains("@"); 433 boolean isMethyl = (hName.endsWith("?") || hName.indexOf("|") >= 0); 434 int n = pts[i].length; 435 if (n == 3 && !isMethyl && hName.equals("H@H2")) { 436 hName = "H|H2|H3"; 437 isMethyl = true; 438 isChiral = false; 439 } 440 if (isChiral && n == 3 || isMethyl != (n == 3)) { 441 Logger.info("Error adding H atoms to " + gName + g.getResno() + ": " 442 + pts[i].length + " atoms should not be added to " + aName); 443 continue; 444 } 445 int pt = hName.indexOf("@"); 446 switch (pts[i].length) { 447 case 1: 448 if (pt > 0) 449 hName = hName.substring(0, pt); 450 setHydrogen(i, ++ipt, hName, pts[i][0]); 451 break; 452 case 2: 453 String hName1, 454 hName2; 455 float d = -1; 456 Bond[] bonds = atom.bonds; 457 if (bonds != null) 458 switch (bonds.length) { 459 case 2: 460 // could be nitrogen? 461 Atom atom1 = bonds[0].getOtherAtom(atom); 462 Atom atom2 = bonds[1].getOtherAtom(atom); 463 int factor = atom1.getAtomName().compareTo(atom2.getAtomName()); 464 d = Measure.distanceToPlane(Measure.getPlaneThroughPoints(atom1, atom, atom2, vNorm, vAB, 465 plane), pts[i][0]) * factor; 466 break; 467 } 468 if (pt < 0) { 469 Logger.info("Error adding H atoms to " + gName + g.getResno() 470 + ": expected to only need 1 H but needed 2"); 471 hName1 = hName2 = "H"; 472 } else if (d < 0) { 473 hName2 = hName.substring(0, pt); 474 hName1 = hName.substring(pt + 1); 475 } else { 476 hName1 = hName.substring(0, pt); 477 hName2 = hName.substring(pt + 1); 478 } 479 setHydrogen(i, ++ipt, hName1, pts[i][0]); 480 setHydrogen(i, ++ipt, hName2, pts[i][1]); 481 break; 482 case 3: 483 int pt1 = hName.indexOf('|'); 484 if (pt1 >= 0) { 485 int pt2 = hName.lastIndexOf('|'); 486 hNames[0] = hName.substring(0, pt1); 487 hNames[1] = hName.substring(pt1 + 1, pt2); 488 hNames[2] = hName.substring(pt2 + 1); 489 } else { 490 hNames[0] = hName.replace('?', '1'); 491 hNames[1] = hName.replace('?', '2'); 492 hNames[2] = hName.replace('?', '3'); 493 } 494 // Measure.getPlaneThroughPoints(pts[i][0], pts[i][1], pts[i][2], vNorm, vAB, 495 // vAC, plane); 496 // d = Measure.distanceToPlane(plane, atom); 497 // int hpt = (d < 0 ? 1 : 2); 498 setHydrogen(i, ++ipt, hNames[0], pts[i][0]); 499 setHydrogen(i, ++ipt, hNames[1], pts[i][2]); 500 setHydrogen(i, ++ipt, hNames[2], pts[i][1]); 501 break; 502 } 503 } 504 deleteUnneededAtoms(); 505 ms.fixFormalCharges(BSUtil.newBitSet2(ml.baseAtomIndex, ml.ms.ac)); 506 } 507 508 /** 509 * Delete hydrogen atoms that are still in bsAddedHydrogens, 510 * because they were not actually added. 511 * Also delete ligand hydrogen atoms from CO2- and PO3(2-) 512 * 513 * Note that we do this AFTER all atoms have been added. That means that 514 * this operation will not mess up atom indexing 515 * 516 */ deleteUnneededAtoms()517 private void deleteUnneededAtoms() { 518 BS bsBondsDeleted = new BS(); 519 for (int i = bsAtomsForHs.nextSetBit(0); i >= 0; i = bsAtomsForHs 520 .nextSetBit(i + 1)) { 521 Atom atom = ms.at[i]; 522 // specifically look for neutral HETATM O with a bond count of 2: 523 if (!atom.isHetero() || atom.getElementNumber() != 8 || atom.getFormalCharge() != 0 524 || atom.getCovalentBondCount() != 2) 525 continue; 526 Bond[] bonds = atom.bonds; 527 Atom atom1 = bonds[0].getOtherAtom(atom); 528 Atom atomH = bonds[1].getOtherAtom(atom); 529 if (atom1.getElementNumber() == 1) { 530 Atom a = atom1; 531 atom1 = atomH; 532 atomH = a; 533 } 534 535 // Does it have an H attached? 536 if (atomH.getElementNumber() != 1) 537 continue; 538 // If so, does it have an attached atom that is doubly bonded to O? 539 // so this could be RSO4H or RPO3H2 or RCO2H 540 Bond[] bonds1 = atom1.bonds; 541 for (int j = 0; j < bonds1.length; j++) { 542 if (bonds1[j].order == 2) { 543 Atom atomO = bonds1[j].getOtherAtom(atom1); 544 if (atomO.getElementNumber() == 8) { 545 bsAddedHydrogens.set(atomH.i); 546 atomH.delete(bsBondsDeleted); 547 break; 548 } 549 } 550 551 } 552 } 553 ms.deleteBonds(bsBondsDeleted, true); 554 deleteAtoms(bsAddedHydrogens); 555 } 556 557 /** 558 * called from org.jmol.modelsetbio.resolver when adding hydrogens. 559 * 560 * @param bsDeletedAtoms 561 */ deleteAtoms(BS bsDeletedAtoms)562 private void deleteAtoms(BS bsDeletedAtoms) { 563 // get map 564 int[] mapOldToNew = new int[ms.ac]; 565 int[] mapNewToOld = new int[ms.ac - bsDeletedAtoms.cardinality()]; 566 int n = ml.baseAtomIndex; 567 Model[] models = ms.am; 568 Atom[] atoms = ms.at; 569 for (int i = ml.baseAtomIndex; i < ms.ac; i++) { 570 Atom a = atoms[i]; 571 if (a == null) 572 continue; 573 models[a.mi].bsAtoms.clear(i); 574 models[a.mi].bsAtomsDeleted.clear(i); 575 if (bsDeletedAtoms.get(i)) { 576 mapOldToNew[i] = n - 1; 577 models[atoms[i].mi].act--; 578 } else { 579 mapNewToOld[n] = i; 580 mapOldToNew[i] = n++; 581 } 582 } 583 ms.msInfo.put("bsDeletedAtoms", bsDeletedAtoms); 584 // adjust group pointers 585 for (int i = ml.baseGroupIndex; i < ml.groups.length; i++) { 586 Group g = ml.groups[i]; 587 if (g.firstAtomIndex >= ml.baseAtomIndex) { 588 g.firstAtomIndex = mapOldToNew[g.firstAtomIndex]; 589 g.lastAtomIndex = mapOldToNew[g.lastAtomIndex]; 590 if (g.leadAtomIndex >= 0) 591 g.leadAtomIndex = mapOldToNew[g.leadAtomIndex]; 592 } 593 } 594 // adjust atom arrays 595 ms.adjustAtomArrays(mapNewToOld, ml.baseAtomIndex, n); 596 ms.calcBoundBoxDimensions(null, 1); 597 ms.resetMolecules(); 598 ms.validateBspf(false); 599 bsAddedMask = BSUtil.deleteBits(bsAddedMask, bsDeletedAtoms); 600 //System.out.println("res bsAddedMask = " + bsAddedMask); 601 for (int i = ml.baseModelIndex; i < ms.mc; i++) { 602 fixAnnotations(i, "domains", T.domains); 603 fixAnnotations(i, "validation", T.validation); 604 } 605 } 606 fixAnnotations(int i, String name, int type)607 private void fixAnnotations(int i, String name, int type) { 608 Object o = ml.ms.getInfo(i, name); 609 if (o != null) { 610 Object dbObj = ((BioModel) ms.am[i]).getCachedAnnotationMap(name, o); 611 if (dbObj != null) 612 vwr.getAnnotationParser(false).fixAtoms(i, (SV) dbObj, bsAddedMask, type, 20); 613 } 614 } 615 finalizePdbCharges()616 private void finalizePdbCharges() { 617 Atom[] atoms = ms.at; 618 // fix terminal N groups as +1 619 for (int i = bsAtomsForHs.nextSetBit(0); i >= 0; i = bsAtomsForHs.nextSetBit(i + 1)) { 620 Atom a = atoms[i]; 621 if (a.group.getNitrogenAtom() == a && a.getCovalentBondCount() == 1) 622 a.setFormalCharge(1); 623 if ((i = bsAtomsForHs.nextClearBit(i + 1)) < 0) 624 break; 625 } 626 } 627 finalizePdbMultipleBonds()628 private void finalizePdbMultipleBonds() { 629 Map<String, Boolean> htKeysUsed = new Hashtable<String, Boolean>(); 630 int bondCount = ms.bondCount; 631 Bond[] bonds = ms.bo; 632 for (int i = baseBondIndex; i < bondCount; i++) { 633 Atom a1 = bonds[i].atom1; 634 Atom a2 = bonds[i].atom2; 635 Group g = a1.group; 636 if (g != a2.group) 637 continue; 638 SB key = new SB().append(g.getGroup3()); 639 key.append(":"); 640 String n1 = a1.getAtomName(); 641 String n2 = a2.getAtomName(); 642 if (n1.compareTo(n2) > 0) 643 key.append(n2).append(":").append(n1); 644 else 645 key.append(n1).append(":").append(n2); 646 String skey = key.toString(); 647 String type = htBondMap.get(skey); 648 if (type == null) 649 continue; 650 htKeysUsed.put(skey, Boolean.TRUE); 651 bonds[i].setOrder(PT.parseInt(type)); 652 } 653 654 for (String key : htBondMap.keySet()) { 655 if (htKeysUsed.get(key) != null) 656 continue; 657 if (key.indexOf(":") < 0) { 658 htKeysUsed.put(key, Boolean.TRUE); 659 continue; 660 } 661 String value = htBondMap.get(key); 662 Logger.info("bond " + key + " was not used; order=" + value); 663 if (htBondMap.get(key).equals("1")) { 664 htKeysUsed.put(key, Boolean.TRUE); 665 continue; // that's ok 666 } 667 } 668 Map<String, String> htKeysBad = new Hashtable<String, String>(); 669 for (String key : htBondMap.keySet()) { 670 if (htKeysUsed.get(key) != null) 671 continue; 672 htKeysBad.put(key.substring(0, key.lastIndexOf(":")), htBondMap.get(key)); 673 } 674 if (htKeysBad.isEmpty()) 675 return; 676 for (int i = 0; i < bondCount; i++) { 677 Atom a1 = bonds[i].atom1; 678 Atom a2 = bonds[i].atom2; 679 if (a1.group == a2.group) 680 continue; 681 String value; 682 if ((value = htKeysBad.get(a1.getGroup3(false) + ":" + a1.getAtomName())) == null 683 && ((value = htKeysBad.get(a2.getGroup3(false) + ":" + a2.getAtomName())) == null)) 684 continue; 685 bonds[i].setOrder(PT.parseInt(value)); 686 Logger.info("assigning order " + bonds[i].order + " to bond " + bonds[i]); 687 } 688 } 689 setHydrogen(int iTo, int iAtom, String name, P3 pt)690 private void setHydrogen(int iTo, int iAtom, String name, P3 pt) { 691 if (!bsAddedHydrogens.get(iAtom)) 692 return; 693 Atom[] atoms = ms.at; 694 if (lastSetH == Integer.MIN_VALUE || atoms[iAtom].mi != atoms[lastSetH].mi) 695 maxSerial = ((int[]) ms.getInfo(atoms[lastSetH = iAtom].mi, "PDB_CONECT_firstAtom_count_max"))[2]; 696 bsAddedHydrogens.clear(iAtom); 697 ms.setAtomName(iAtom, name, false); 698 atoms[iAtom].setT(pt); 699 ms.setAtomNumber(iAtom, ++maxSerial, false); 700 atoms[iAtom].atomSymmetry = atoms[iTo].atomSymmetry; 701 ml.undeleteAtom(iAtom); 702 703 ms.bondAtoms(atoms[iTo], atoms[iAtom], Edge.BOND_COVALENT_SINGLE, 704 ms.getDefaultMadFromOrder(Edge.BOND_COVALENT_SINGLE), null, 0, true, false); 705 } 706 fixPropertyValue(BS bsAtoms, Object data, boolean toHydrogens)707 public Object fixPropertyValue(BS bsAtoms, Object data, boolean toHydrogens) { 708 Atom[] atoms = ms.at; 709 // we aren't doing this anymore 710 // it was for TLS groups 711 // if (data instanceof String) { 712 // String[] sData = PT.split((String) data, "\n"); 713 // String[] newData = new String[bsAtoms.cardinality()]; 714 // String lastData = ""; 715 // for (int pt = 0, iAtom = 0, i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms 716 // .nextSetBit(i + 1), iAtom++) { 717 // if (atoms[i].getElementNumber() == 1) { 718 // if (!toHydrogens) 719 // continue; 720 // } else { 721 // lastData = sData[pt++]; 722 // } 723 // newData[iAtom] = lastData; 724 // } 725 // return PT.join(newData, '\n', 0); 726 // } 727 // already float data 728 float[] fData = (float[]) data; 729 float[] newData = new float[bsAtoms.cardinality()]; 730 float lastData = 0; 731 for (int pt = 0, iAtom = 0, i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms 732 .nextSetBit(i + 1), iAtom++) { 733 if (atoms[i].getElementNumber() == 1) { 734 if (!toHydrogens) 735 continue; 736 } else { 737 lastData = fData[pt++]; 738 } 739 newData[iAtom] = lastData; 740 } 741 return newData; 742 } 743 allocateBioPolymer(Group[] groups, int firstGroupIndex, boolean checkConnections, int pt0)744 static BioPolymer allocateBioPolymer(Group[] groups, int firstGroupIndex, 745 boolean checkConnections, int pt0) { 746 Monomer previous = null; 747 int count = 0; 748 for (int i = firstGroupIndex; i < groups.length; ++i) { 749 Group group = groups[i]; 750 Monomer current; 751 if (!(group instanceof Monomer) 752 || (current = (Monomer) group).bioPolymer != null || previous != null 753 && previous.getClass() != current.getClass() || checkConnections 754 && !current.isConnectedAfter(previous)) 755 break; 756 previous = current; 757 count++; 758 } 759 if (count < 2) 760 return null; 761 Monomer[] monomers = new Monomer[count]; 762 for (int j = 0; j < count; ++j) 763 monomers[j] = (Monomer) groups[firstGroupIndex + j]; 764 if (previous instanceof AminoMonomer) 765 return new AminoPolymer(monomers, pt0); 766 if (previous instanceof AlphaMonomer) 767 return new AlphaPolymer(monomers, pt0); 768 if (previous instanceof NucleicMonomer) 769 return new NucleicPolymer(monomers); 770 if (previous instanceof PhosphorusMonomer) 771 return new PhosphorusPolymer(monomers); 772 if (previous instanceof CarbohydrateMonomer) 773 return new CarbohydratePolymer(monomers); 774 Logger 775 .error("Polymer.allocatePolymer() ... no matching polymer for monomor " 776 + previous); 777 throw new NullPointerException(); 778 } 779 780 private BS bsAssigned; 781 782 /** 783 * Pull in all spans of helix, etc. in the file(s) 784 * 785 * We do turn first, because sometimes a group is defined twice, and this way 786 * it gets marked as helix or sheet if it is both one of those and turn. 787 * 788 * Jmol 14.3 - adds sequence ANNOTATION 789 * 790 * @param adapter 791 * @param atomSetCollection 792 */ iterateOverAllNewStructures(JmolAdapter adapter, Object atomSetCollection)793 public void iterateOverAllNewStructures(JmolAdapter adapter, 794 Object atomSetCollection) { 795 JmolAdapterStructureIterator iterStructure = adapter 796 .getStructureIterator(atomSetCollection); 797 if (iterStructure == null) 798 return; 799 BS bs = iterStructure.getStructuredModels(); 800 if (bs != null) 801 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) 802 ml.structuresDefinedInFile.set(ml.baseModelIndex + i); 803 while (iterStructure.hasNext()) 804 if (iterStructure.getStructureType() != STR.TURN) 805 setStructure(iterStructure); 806 807 // define turns LAST. (pulled by the iterator first) 808 // so that if they overlap they get overwritten: 809 810 iterStructure = adapter.getStructureIterator(atomSetCollection); 811 while (iterStructure.hasNext()) 812 if (iterStructure.getStructureType() == STR.TURN) 813 setStructure(iterStructure); 814 } 815 816 private static STR[] types = { STR.HELIXPI, STR.HELIXALPHA, 817 STR.SHEET, STR.HELIX310, STR.TURN }; 818 819 private static int[] mytypes = {0, 2, 3, 4, 6}; 820 821 /** 822 * note that istart and iend will be adjusted. 823 * 824 * @param iterStructure 825 */ setStructure(JmolAdapterStructureIterator iterStructure)826 private void setStructure(JmolAdapterStructureIterator iterStructure) { 827 STR t = iterStructure.getSubstructureType(); 828 String id = iterStructure.getStructureID(); 829 int serID = iterStructure.getSerialID(); 830 int count = iterStructure.getStrandCount(); 831 int[] atomRange = iterStructure.getAtomIndices(); 832 int[] modelRange = iterStructure.getModelIndices(); 833 BS[] bsAll = iterStructure.getBSAll(); 834 int m0, m1; 835 Model[] models = ms.am; 836 if (ml.isTrajectory) { //from PDB file 837 m0 = m1 = modelRange[0]; 838 } else { 839 m0 = modelRange[0] + ml.baseModelIndex; 840 m1 = modelRange[1] + ml.baseModelIndex; 841 } 842 ml.structuresDefinedInFile.setBits(m0, m1 + 1); 843 844 BS bs; 845 Model m; 846 if (bsAll != null) { 847 for (int i = m0, t0; i <= m1; i++) 848 if ((m = models[i]) instanceof BioModel) 849 for (int j = 0; j < 5; j++) 850 if ((bs = bsAll[t0 = mytypes[j]]) != null) 851 ((BioModel) m).addStructureByBS(0, t0, types[j], bs); 852 return; 853 } 854 855 int startChainID = iterStructure.getStartChainID(); 856 int startSequenceNumber = iterStructure.getStartSequenceNumber(); 857 char startInsertionCode = iterStructure.getStartInsertionCode(); 858 int endSequenceNumber = iterStructure.getEndSequenceNumber(); 859 int endChainID = iterStructure.getEndChainID(); 860 char endInsertionCode = iterStructure.getEndInsertionCode(); 861 STR type = (t == STR.NOT ? STR.NONE : t); 862 int startSeqCode = Group.getSeqcodeFor(startSequenceNumber, 863 startInsertionCode); 864 int endSeqCode = Group.getSeqcodeFor(endSequenceNumber, endInsertionCode); 865 if (bsAssigned == null) 866 bsAssigned = new BS(); 867 for (int i = m0, i0 = 0; i <= m1; i++) 868 if ((m = models[i]) instanceof BioModel) 869 ((BioModel) m).addSecondaryStructure(type, id, serID, count, 870 startChainID, startSeqCode, endChainID, endSeqCode, 871 (i0 = m.firstAtomIndex) + atomRange[0], i0 + atomRange[1], 872 bsAssigned); 873 } 874 setGroupLists(int ipt)875 public void setGroupLists(int ipt) { 876 ml.group3Lists[ipt + 1] = Group.standardGroupList; 877 ml.group3Counts[ipt + 1] = new int[group3Count + 10]; 878 if (ml.group3Lists[0] == null) { 879 ml.group3Lists[0] = Group.standardGroupList; 880 ml.group3Counts[0] = new int[group3Count + 10]; 881 } 882 } 883 884 /** 885 * @param g3 886 * @param max max ID (e.g. 20); can be Integer.MAX_VALUE to allow carbohydrate 887 * @return true if found 888 */ isKnownPDBGroup(String g3, int max)889 public boolean isKnownPDBGroup(String g3, int max) { 890 int pt = knownGroupID(g3); 891 return (pt > 0 ? pt < max : max == Integer.MAX_VALUE && checkCarbohydrate(g3)); 892 } 893 lookupSpecialAtomID(String name)894 public byte lookupSpecialAtomID(String name) { 895 if (htSpecialAtoms == null) { 896 htSpecialAtoms = new Hashtable<String, Byte>(); 897 for (int i = specialAtomNames.length; --i >= 0;) { 898 String specialAtomName = specialAtomNames[i]; 899 if (specialAtomName != null) 900 htSpecialAtoms.put(specialAtomName, Byte.valueOf((byte) i)); 901 } 902 } 903 Byte boxedAtomID = htSpecialAtoms.get(name); 904 return (boxedAtomID == null ? 0 : boxedAtomID.byteValue()); 905 } 906 907 private static Map<String, String[][]> htPdbBondInfo; 908 getPdbBondInfo(String group3, boolean isLegacy)909 private String[][] getPdbBondInfo(String group3, boolean isLegacy) { 910 if (htPdbBondInfo == null) 911 htPdbBondInfo = new Hashtable<String, String[][]>(); 912 String[][] info = htPdbBondInfo.get(group3); 913 if (info != null) 914 return info; 915 int pt = knownGroupID(group3); 916 if (pt < 0 || pt > pdbBondInfo.length) 917 return null; 918 String s = pdbBondInfo[pt]; 919 // unfortunately, this change is not backward compatible. 920 if (isLegacy && (pt = s.indexOf("O3'")) >= 0) 921 s = s.substring(0, pt); 922 String[] temp = PT.getTokens(s); 923 info = new String[temp.length / 2][]; 924 for (int i = 0, p = 0; i < info.length; i++) { 925 String source = temp[p++]; 926 String target = temp[p++]; 927 // a few shortcuts here: 928 if (target.length() == 1) 929 switch (target.charAt(0)) { 930 case 'N': 931 target = "H@H2"; 932 break; 933 case 'B': // CB 934 target = "HB3@HB2"; 935 break; 936 case 'D': // CD 937 target = "HD3@HD2"; 938 break; 939 case 'G': // CG 940 target = "HG3@HG2"; 941 break; 942 case '2': // C2' 943 target = "H2'@H2''"; 944 break; 945 case '5': // C5' 946 target = "H5''@H5'"; 947 break; 948 } 949 if (target.charAt(0) != 'H' && source.compareTo(target) > 0) { 950 s = target; 951 target = source; 952 source = s; 953 } 954 info[i] = new String[] { source, target, 955 (target.startsWith("H") ? "1" : "2") }; 956 } 957 htPdbBondInfo.put(group3, info); 958 return info; 959 } 960 /** 961 * pdbBondInfo describes in a compact way what the hydrogen atom 962 * names are for each standard amino acid. This list consists 963 * of pairs of attached atom/hydrogen atom names, with abbreviations 964 * N, C, O, B, D, G, 1, and 2 (for N, C, O, CB, CD, CG, C1', and C2', respectively) 965 * given in pdbHAttachments, above. Note that we never add HXT or NH3 966 * "?" here is for methyl groups with H1, H2, H3. 967 * "@" indicates a prochiral center, with the assignment order given here 968 * 969 */ 970 public final static String[] pdbBondInfo = { 971 // added O3' HO3' O5' HO5' for nucleic and added 1 H atom for res 1 for 13.1.17 972 // this could throw off states from previous versions 973 // CH2 and NH2 labeling revised 2015.02.07 974 975 "", 976 /*ALA*/ "N N CA HA C O CB HB?", 977 /*ARG*/ "N N CA HA C O CB B CG G CD D NE HE CZ NH1 NH1 HH11@HH12 NH2 HH22@HH21", 978 /*ASN*/ "N N CA HA C O CB B CG OD1 ND2 HD21@HD22", 979 /*ASP*/ "N N CA HA C O CB B CG OD1", 980 /*CYS*/ "N N CA HA C O CB B SG HG", 981 /*GLN*/ "N N CA HA C O CB B CG G CD OE1 NE2 HE22@HE21", 982 /*GLU*/ "N N CA HA C O CB B CG G CD OE1", 983 /*GLY*/ "N N CA HA2@HA3 C O", 984 /*HIS*/ "N N CA HA C O CB B CG CD2 ND1 CE1 ND1 HD1 CD2 HD2 CE1 HE1 NE2 HE2", 985 /*ILE*/ "N N CA HA C O CB HB CG1 HG13@HG12 CG2 HG2? CD1 HD1?", 986 /*LEU*/ "N N CA HA C O CB B CG HG CD1 HD1? CD2 HD2?", 987 /*LYS*/ "N N CA HA C O CB B CG G CD HD2@HD3 CE HE3@HE2 NZ HZ?", 988 /*MET*/ "N N CA HA C O CB B CG G CE HE?", 989 /*PHE*/ "N N CA HA C O CB B CG CD1 CD1 HD1 CD2 CE2 CD2 HD2 CE1 CZ CE1 HE1 CE2 HE2 CZ HZ", 990 /*PRO*/ "N H CA HA C O CB B CG G CD D", 991 /*SER*/ "N N CA HA C O CB B OG HG", 992 /*THR*/ "N N CA HA C O CB HB OG1 HG1 CG2 HG2?", 993 /*TRP*/ "N N CA HA C O CB B CG CD1 CD1 HD1 CD2 CE2 NE1 HE1 CE3 CZ3 CE3 HE3 CZ2 CH2 CZ2 HZ2 CZ3 HZ3 CH2 HH2", 994 /*TYR*/ "N N CA HA C O CB B CG CD1 CD1 HD1 CD2 CE2 CD2 HD2 CE1 CZ CE1 HE1 CE2 HE2 OH HH", 995 /*VAL*/ "N N CA HA C O CB HB CG1 HG1? CG2 HG2?", 996 /*ASX*/ "N N CA HA C O CB B", 997 /*GLX*/ "N N CA HA C O CB B CG G", 998 /*UNK*/ "", 999 /*G*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' H2' O2' HO2' C1' H1' C8 N7 C8 H8 C5 C4 C6 O6 N1 H1 C2 N3 N2 H22@H21 O3' HO3' O5' HO5'", 1000 /*C*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' H2' O2' HO2' C1' H1' C2 O2 N3 C4 N4 H41@H42 C5 C6 C5 H5 C6 H6 O3' HO3' O5' HO5'", 1001 /*A*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' H2' O2' HO2' C1' H1' C8 N7 C8 H8 C5 C4 C6 N1 N6 H61@H62 C2 N3 C2 H2 O3' HO3' O5' HO5'", 1002 /*T*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' 2 C1' H1' C2 O2 N3 H3 C4 O4 C5 C6 C7 H7? C6 H6 O3' HO3' O5' HO5'", 1003 /*U*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' H2' O2' HO2' C1' H1' C2 O2 N3 H3 C4 O4 C5 C6 C5 H5 C6 H6 O3' HO3' O5' HO5'", 1004 /*I*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' H2' O2' HO2' C1' H1' C8 N7 C8 H8 C5 C4 C6 O6 N1 H1 C2 N3 C2 H2 O3' HO3' O5' HO5'", 1005 /*DG*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' 2 C1' H1' C8 N7 C8 H8 C5 C4 C6 O6 N1 H1 C2 N3 N2 H22@H21 O3' HO3' O5' HO5'", 1006 /*DC*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' 2 C1' H1' C2 O2 N3 C4 N4 H41@H42 C5 C6 C5 H5 C6 H6 O3' HO3' O5' HO5'", 1007 /*DA*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' 2 C1' H1' C8 N7 C8 H8 C5 C4 C6 N1 N6 H61@H62 C2 N3 C2 H2 O3' HO3' O5' HO5'", 1008 /*DT*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' 2 C1' H1' C2 O2 N3 H3 C4 O4 C5 C6 C7 H7? C6 H6 O3' HO3' O5' HO5'", 1009 /*DU*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' 2 C1' H1' C2 O2 N3 H3 C4 O4 C5 C6 C5 H5 C6 H6 O3' HO3' O5' HO5'", 1010 /*DI*/ "P OP1 C5' 5 C4' H4' C3' H3' C2' 2 C1' H1' C8 N7 C8 H8 C5 C4 C6 O6 N1 H1 C2 N3 C2 H2 O3' HO3' O5' HO5'", 1011 }; 1012 private final static int[] pdbHydrogenCount = { 1013 0, 1014 /*ALA*/ 6, 1015 /*ARG*/ 16, 1016 /*ASN*/ 7, 1017 /*ASP*/ 6, 1018 /*CYS*/ 6, 1019 /*GLN*/ 9, 1020 /*GLU*/ 8, 1021 /*GLY*/ 4, 1022 /*HIS*/ 9, 1023 /*ILE*/ 12, 1024 /*LEU*/ 12, 1025 /*LYS*/ 14, 1026 /*MET*/ 10, 1027 /*PHE*/ 10, 1028 /*PRO*/ 8, 1029 /*SER*/ 6, 1030 /*THR*/ 8, 1031 /*TRP*/ 11, 1032 /*TYR*/ 10, 1033 /*VAL*/ 10, 1034 /*ASX*/ 3, 1035 /*GLX*/ 5, 1036 /*UNK*/ 0, 1037 /*G*/ 13, 1038 /*C*/ 13, 1039 /*A*/ 13, 1040 /*T*/ -1, 1041 /*U*/ 12, 1042 /*I*/ 12, 1043 /*DG*/ 13, 1044 /*DC*/ 13, 1045 /*DA*/ 13, 1046 /*DT*/ 14, 1047 /*DU*/ 12, 1048 /*DI*/ 12, 1049 }; 1050 1051 /** 1052 * this form is used for counting groups in ModelSet 1053 * 1054 * GLX added for 13.1.16 1055 * 1056 */ 1057 private final static String allCarbohydrates = 1058 ",[AHR],[ALL],[AMU],[ARA],[ARB],[BDF],[BDR],[BGC],[BMA]" + 1059 ",[FCA],[FCB],[FRU],[FUC],[FUL],[GAL],[GLA],[GLC],[GXL]" + 1060 ",[GUP],[LXC],[MAN],[RAM],[RIB],[RIP],[XYP],[XYS]" + 1061 ",[CBI],[CT3],[CTR],[CTT],[LAT],[MAB],[MAL],[MLR],[MTT]" + 1062 ",[SUC],[TRE],[GCU],[MTL],[NAG],[NDG],[RHA],[SOR],[SOL],[SOE]" + 1063 ",[XYL],[A2G],[LBT],[NGA],[SIA],[SLB]" + 1064 ",[AFL],[AGC],[GLB],[NAN],[RAA]"; //these 4 are deprecated in PDB 1065 1066 // from Eric Martz; revision by Angel Herraez knownGroupID(String group3)1067 public static short knownGroupID(String group3) { 1068 if (group3 == null || group3.length() == 0) 1069 return 0; 1070 Short boxedGroupID = htGroup.get(group3); 1071 return (boxedGroupID == null ? -1 : boxedGroupID.shortValue()); 1072 } 1073 /** 1074 * @param group3 a potential group3 name 1075 * @return whether this is a carbohydrate from the list 1076 */ checkCarbohydrate(String group3)1077 private final static boolean checkCarbohydrate(String group3) { 1078 return (group3 != null 1079 && allCarbohydrates.indexOf("[" + group3.toUpperCase() + "]") >= 0); 1080 } 1081 private static int group3Count; 1082 final static char[] predefinedGroup1Names = { 1083 /* rmh 1084 * 1085 * G Glycine Gly P Proline Pro 1086 * A Alanine Ala V Valine Val 1087 * L Leucine Leu I Isoleucine Ile 1088 * M Methionine Met C Cysteine Cys 1089 * F Phenylalanine Phe Y Tyrosine Tyr 1090 * W Tryptophan Trp H Histidine His 1091 * K Lysine Lys R Arginine Arg 1092 * Q Glutamine Gln N Asparagine Asn 1093 * E Glutamic Acid Glu D Aspartic Acid Asp 1094 * S Serine Ser T Threonine Thr 1095 */ 1096 '\0', // 0 this is the null group 1097 1098 'A', // 1 1099 'R', 1100 'N', 1101 'D', 1102 'C', // 5 Cysteine 1103 'Q', 1104 'E', 1105 'G', 1106 'H', 1107 'I', 1108 'L', 1109 'K', 1110 'M', 1111 'F', 1112 'P', // 15 Proline 1113 'S', 1114 'T', 1115 'W', 1116 'Y', 1117 'V', 1118 'A', // 21 ASP/ASN ambiguous 1119 'G', // 22 GLU/GLN ambiguous 1120 '?', // 23 unknown -- 23 1121 1122 'G', // X nucleics 1123 'C', 1124 'A', 1125 'T', 1126 'U', 1127 'I', 1128 1129 'G', // DX nucleics 1130 'C', 1131 'A', 1132 'T', 1133 'U', 1134 'I', 1135 1136 'G', // +X nucleics 1137 'C', 1138 'A', 1139 'T', 1140 'U', 1141 'I', 1142 }; 1143 1144 1145 /** 1146 * MMCif, Gromacs, MdTop, Mol2 readers only 1147 * @param group3 1148 * @return true if an identified hetero group 1149 * 1150 */ isHetero(String group3)1151 public boolean isHetero(String group3) { 1152 switch (group3.length()) { 1153 case 1: 1154 group3 += " "; 1155 break; 1156 case 2: 1157 group3 += " "; 1158 break; 1159 case 3: 1160 break; 1161 default: 1162 return true; 1163 } 1164 int pt = Group.standardGroupList.indexOf(group3); 1165 return (pt < 0 || pt / 6 + 1 >= JC.GROUPID_WATER); 1166 } 1167 1168 public static short group3NameCount; 1169 private final static String[] predefinedGroup3Names = { 1170 // taken from PDB spec 1171 " ", // 0 this is the null group 1172 "ALA", // 1 1173 "ARG", // 2 arginine -- hbond donor 1174 "ASN", // 3 asparagine -- hbond donor 1175 "ASP", // 4 aspartate -- hbond acceptor 1176 "CYS", 1177 "GLN", // 6 glutamine -- hbond donor 1178 "GLU", // 7 glutamate -- hbond acceptor 1179 "GLY", 1180 "HIS", // 9 histidine -- hbond ambiguous 1181 "ILE", 1182 "LEU", 1183 "LYS", // 12 lysine -- hbond donor 1184 "MET", 1185 "PHE", 1186 "PRO", // 15 proline -- no NH 1187 "SER", 1188 "THR", 1189 "TRP", 1190 "TYR", // 19 tryptophan -- hbond donor 1191 "VAL", 1192 "ASX", // 21 ASP/ASN ambiguous 1193 "GLX", // 22 GLU/GLN ambiguous 1194 "UNK", // 23 unknown -- 23 1195 1196 // if you change these numbers you *must* update 1197 // the predefined sets below 1198 1199 // with the deprecation of +X, we will need a new 1200 // way to handle these. 1201 1202 "G ", // 24 starts nucleics //0 1203 "C ", 1204 "A ", 1205 "T ", 1206 "U ", 1207 "I ", // 29 / 5 1208 1209 "DG ", // 30 / 6 1210 "DC ", 1211 "DA ", 1212 "DT ", 1213 "DU ", 1214 "DI ", // 35 / 11 1215 1216 "+G ", // 36 / 12 1217 "+C ", 1218 "+A ", 1219 "+T ", 1220 "+U ", 1221 "+I ", // 41 / 17 1222 /* removed bh 7/1/2011 this is isolated inosine, not a polymer "NOS", // inosine */ 1223 1224 // solvent types: -- if these numbers change, also change GROUPID_WATER,_SOLVENT,and_SULFATE 1225 1226 "HOH", // 42 water 1227 "DOD", // 43 1228 "WAT", // 44 1229 "UREA",// 45 urea, a cosolvent 1230 "PO4", // 46 phosphate ions -- from here on is "ligand" 1231 "SO4", // 47 sulphate ions 1232 "UNL", // 48 unknown ligand 1233 1234 }; 1235 1236 /* 1237 * Convert "AVG" to "ALA VAL GLY"; unknowns to UNK 1238 * 1239 */ toStdAmino3(String g1)1240 public String toStdAmino3(String g1) { 1241 if (g1.length() == 0) 1242 return ""; 1243 SB s = new SB(); 1244 int pt = knownGroupID("==A"); 1245 if (pt < 0) { 1246 // just the amino acids 1247 for (int i = 1; i <= 20; i++) { 1248 pt = knownGroupID(predefinedGroup3Names[i]); 1249 htGroup.put("==" + predefinedGroup1Names[i], Short.valueOf((short) pt)); 1250 } 1251 } 1252 for (int i = 0, n = g1.length(); i < n; i++) { 1253 char ch = g1.charAt(i); 1254 pt = knownGroupID("==" + ch); 1255 if (pt < 0) 1256 pt = 23; 1257 s.append(" ").append(predefinedGroup3Names[pt]); 1258 } 1259 return s.toString().substring(1); 1260 } 1261 getGroupID(String g3)1262 public short getGroupID(String g3) { 1263 return getGroupIdFor(g3); 1264 } 1265 getGroupIdFor(String group3)1266 static short getGroupIdFor(String group3) { 1267 if (group3 != null) 1268 group3 = group3.trim(); 1269 short groupID = knownGroupID(group3); 1270 return (groupID == -1 ? addGroup3Name(group3) : groupID); 1271 } 1272 1273 /** 1274 * These can overrun 3 characters; that is not significant. 1275 * 1276 * @param group3 1277 * @return a short group ID 1278 */ addGroup3Name(String group3)1279 private synchronized static short addGroup3Name(String group3) { 1280 if (group3NameCount == Group.group3Names.length) 1281 Group.group3Names = AU.doubleLengthS(Group.group3Names); 1282 short groupID = group3NameCount++; 1283 Group.group3Names[groupID] = group3; 1284 htGroup.put(group3, Short.valueOf(groupID)); 1285 return groupID; 1286 } 1287 getStandardPdbHydrogenCount(String group3)1288 private static int getStandardPdbHydrogenCount(String group3) { 1289 int pt = knownGroupID(group3); 1290 return (pt < 0 || pt >= pdbHydrogenCount.length ? -1 : pdbHydrogenCount[pt]); 1291 } 1292 //////////////////////////////////////////////////////////////// 1293 // static stuff for group ids 1294 //////////////////////////////////////////////////////////////// 1295 1296 private final static String[] specialAtomNames = { 1297 1298 //////////////////////////////////////////////////////////////// 1299 // The ordering of these entries can be changed ... BUT ... 1300 // the offsets must be kept consistent with the ATOMID definitions 1301 // below. 1302 // 1303 // Used in Atom to look up special atoms. Any "*" in a PDB entry is 1304 // changed to ' for comparison here 1305 // 1306 // null is entry 0 1307 // The first 32 entries are reserved for null + 31 'distinguishing atoms' 1308 // see definitions below. 32 is magical because bits are used in an 1309 // int to distinguish groups. If we need more then we can go to 64 1310 // bits by using a long ... but code must change. See Resolver.java 1311 // 1312 // All entries from 64 on are backbone entries 1313 //////////////////////////////////////////////////////////////// 1314 null, // 0 1315 1316 // protein backbone 1317 // 1318 "N", // 1 - amino nitrogen SPINE 1319 "CA", // 2 - alpha carbon SPINE 1320 "C", // 3 - carbonyl carbon SPINE 1321 "O", // 4 - carbonyl oxygen 1322 "O1", // 5 - carbonyl oxygen in some protein residues (4THN) 1323 1324 // nucleic acid backbone sugar 1325 // 1326 "O5'", // 6 - sugar 5' oxygen SPINE 1327 "C5'", // 7 - sugar 5' carbon SPINE 1328 "C4'", // 8 - sugar ring 4' carbon SPINE 1329 "C3'", // 9 - sugar ring 3' carbon SPINE 1330 "O3'", // 10 - sugar 3' oxygen SPINE 1331 "C2'", // 11 - sugar ring 2' carbon 1332 "C1'", // 12 - sugar ring 1' carbon 1333 // Phosphorus is not required for a nucleic group because 1334 // at the terminus it could have H5T or O5T ... 1335 "P", // 13 - phosphate phosphorus SPINE 1336 1337 // END OF FIRST BACKBONE SET 1338 1339 // ... But we need to distinguish phosphorus separately because 1340 // it could be found in phosphorus-only nucleic polymers 1341 1342 "OD1", // 14 ASP/ASN carbonyl/carbonate 1343 "OD2", // 15 ASP carbonyl/carbonate 1344 "OE1", // 16 GLU/GLN carbonyl/carbonate 1345 "OE2", // 17 GLU carbonyl/carbonate 1346 "SG", // 18 CYS sulfur 1347 // reserved for future expansion ... lipids & carbohydrates 1348 // 9/2006 -- carbohydrates are just handled as group3 codes 1349 // see below 1350 null, // 18 - 19 1351 null, null, null, null, // 20 - 23 1352 null, null, null, null, // 24 - 27 1353 null, null, null, null, // 28 - 31 1354 1355 // nucleic acid bases 1356 // 1357 "N1", // 32 1358 "C2", // 33 1359 "N3", // 34 1360 "C4", // 35 1361 "C5", // 36 1362 "C6", // 37 -- currently defined as the nucleotide wing 1363 // this determines the vector for the sheet 1364 // could be changed if necessary 1365 1366 // pyrimidine O2 1367 // 1368 "O2", // 38 1369 1370 // purine stuff 1371 // 1372 "N7", // 39 1373 "C8", // 40 1374 "N9", // 41 1375 1376 // nucleic acid base ring functional groups 1377 // DO NOT CHANGE THESE NUMBERS WITHOUT ALSO CHANGING 1378 // NUMBERS IN THE PREDEFINED SETS _a=... 1379 1380 "N4", // 42 - base ring N4, unique to C 1381 "N2", // 43 - base amino N2, unique to G 1382 "N6", // 44 - base amino N6, unique to A 1383 "C5M", // 45 - base methyl carbon, unique to T 1384 1385 "O6", // 46 - base carbonyl O6, only in G and I 1386 "O4", // 47 - base carbonyl O4, only in T and U 1387 "S4", // 48 - base thiol sulfur, unique to thio-U 1388 1389 "C7", // 49 - base methyl carbon, unique to DT 1390 1391 "H1", // 50 - NOT backbone 1392 "H2", // 51 - NOT backbone -- see 1jve 1393 "H3", // 52 - NOT backbone 1394 null, null, //53 1395 null, null, null, null, null, //55 1396 null, null, null, null, //60 - 63 1397 1398 // everything from here on is backbone 1399 1400 // protein backbone 1401 // 1402 "OXT", // 64 - second carbonyl oxygen, C-terminus only 1403 1404 // protein backbone hydrogens 1405 // 1406 "H", // 65 - amino hydrogen 1407 // these appear on the N-terminus end of 1ALE & 1LCD 1408 "1H", // 66 - N-terminus hydrogen 1409 "2H", // 67 - second N-terminus hydrogen 1410 "3H", // 68 - third N-terminus hydrogen 1411 "HA", // 69 - H on alpha carbon 1412 "1HA", // 70 - H on alpha carbon in Gly only 1413 "2HA", // 71 - 1ALE calls the two GLY hdrogens 1HA & 2HA 1414 1415 // Terminal nuclic acid 1416 1417 "H5T", // 72 - 5' terminus hydrogen which replaces P + O1P + O2P 1418 "O5T", // 73 - 5' terminus oxygen which replaces P + O1P + O2P 1419 "O1P", // 74 - first equivalent oxygen on phosphorus of phosphate 1420 "OP1", // 75 - first equivalent oxygen on phosphorus of phosphate -- new designation 1421 "O2P", // 76 - second equivalent oxygen on phosphorus of phosphate 1422 "OP2", // 77 - second equivalent oxygen on phosphorus of phosphate -- new designation 1423 1424 "O4'", // 78 - sugar ring 4' oxygen ... not present in +T ... maybe others 1425 "O2'", // 79 - sugar 2' oxygen, unique to RNA 1426 1427 // nucleic acid backbone hydrogens 1428 // 1429 "1H5'", // 80 - first equivalent H on sugar 5' carbon 1430 "2H5'", // 81 - second equivalent H on sugar 5' carbon 1431 "H4'", // 82 - H on sugar ring 4' carbon 1432 "H3'", // 83 - H on sugar ring 3' carbon 1433 "1H2'", // 84 - first equivalent H on sugar ring 2' carbon 1434 "2H2'", // 85 - second equivalent H on sugar ring 2' carbon 1435 "2HO'", // 86 - H on sugar 2' oxygen, unique to RNA 1436 "H1'", // 87 - H on sugar ring 1' carbon 1437 "H3T", // 88 - 3' terminus hydrogen 1438 1439 // add as many as necessary -- backbone only 1440 1441 "HO3'", // 89 - 3' terminus hydrogen (new) 1442 "HO5'", // 90 - 5' terminus hydrogen (new) 1443 "HA2", 1444 "HA3", 1445 "HA2", 1446 "H5'", 1447 "H5''", 1448 "H2'", 1449 "H2''", 1450 "HO2'", 1451 1452 "O3P", // 99 - third equivalent oxygen on phosphorus of phosphate 1453 "OP3", //100 - third equivalent oxygen on phosphorus of phosphate -- new designation 1454 1455 }; 1456 1457 public final static int ATOMID_MAX = specialAtomNames.length; 1458 getSpecialAtomName(int atomID)1459 final static String getSpecialAtomName(int atomID) { 1460 return specialAtomNames[atomID]; 1461 } 1462 1463 private static Map<String, Byte> htSpecialAtoms; 1464 1465 private final static int[] argbsAmino = { 1466 0xFFBEA06E, // default tan 1467 // note that these are the rasmol colors and names, not xwindows 1468 0xFFC8C8C8, // darkGrey ALA 1469 0xFF145AFF, // blue ARG 1470 0xFF00DCDC, // cyan ASN 1471 0xFFE60A0A, // brightRed ASP 1472 0xFFE6E600, // yellow CYS 1473 0xFF00DCDC, // cyan GLN 1474 0xFFE60A0A, // brightRed GLU 1475 0xFFEBEBEB, // lightGrey GLY 1476 0xFF8282D2, // paleBlue HIS 1477 0xFF0F820F, // green ILE 1478 0xFF0F820F, // green LEU 1479 0xFF145AFF, // blue LYS 1480 0xFFE6E600, // yellow MET 1481 0xFF3232AA, // midBlue PHE 1482 0xFFDC9682, // mauve PRO 1483 0xFFFA9600, // orange SER 1484 0xFFFA9600, // orange THR 1485 0xFFB45AB4, // purple TRP 1486 0xFF3232AA, // midBlue TYR 1487 0xFF0F820F, // green VAL 1488 1489 0xFFFF69B4, // pick a new color ASP/ASN ambiguous 1490 0xFFFF69B4, // pick a new color GLU/GLN ambiguous 1491 0xFFBEA06E, // default tan UNK 1492 }; 1493 1494 private final static int[] argbsNucleic = { 1495 0xFFBEA06E, // default tan 1496 0xFFA0A0A0, // grey P 1497 0xFF0F820F, // green G 1498 0xFFE6E600, // yellow C 1499 0xFFE60A0A, // brightRed A 1500 0xFF145AFF, // blue T 1501 0xFF00DCDC, // cyan U 1502 0xFF00DCDC, // cyan I 1503 1504 0xFF0F820F, // green DG 1505 0xFFE6E600, // yellow DC 1506 0xFFE60A0A, // brightRed DA 1507 0xFF145AFF, // blue DT 1508 0xFF00DCDC, // cyan DU 1509 0xFF00DCDC, // cyan DI 1510 1511 0xFF0F820F, // green +G 1512 0xFFE6E600, // yellow +C 1513 0xFFE60A0A, // brightRed +A 1514 0xFF145AFF, // blue +T 1515 0xFF00DCDC, // cyan +U 1516 0xFF00DCDC, // cyan +I 1517 }; 1518 1519 1520 1521 /** 1522 * colors used for chains 1523 * 1524 */ 1525 1526 /**************************************************************** 1527 * some pastel colors 1528 * 1529 * C0D0FF - pastel blue 1530 * B0FFB0 - pastel green 1531 * B0FFFF - pastel cyan 1532 * FFC0C8 - pink 1533 * FFC0FF - pastel magenta 1534 * FFFF80 - pastel yellow 1535 * FFDEAD - navajowhite 1536 * FFD070 - pastel gold 1537 1538 * FF9898 - light coral 1539 * B4E444 - light yellow-green 1540 * C0C000 - light olive 1541 * FF8060 - light tomato 1542 * 00FF7F - springgreen 1543 * 1544 cpk on; select atomno>100; label %i; color chain; select selected & hetero; cpk off 1545 ****************************************************************/ 1546 1547 private final static int[] argbsChainAtom = { 1548 // ' '->0 'A'->1, 'B'->2 1549 0xFFffffff, // ' ' & '0' white 1550 // 1551 0xFFC0D0FF, // skyblue 1552 0xFFB0FFB0, // pastel green 1553 0xFFFFC0C8, // pink 1554 0xFFFFFF80, // pastel yellow 1555 0xFFFFC0FF, // pastel magenta 1556 0xFFB0F0F0, // pastel cyan 1557 0xFFFFD070, // pastel gold 1558 0xFFF08080, // lightcoral 1559 1560 0xFFF5DEB3, // wheat 1561 0xFF00BFFF, // deepskyblue 1562 0xFFCD5C5C, // indianred 1563 0xFF66CDAA, // mediumaquamarine 1564 0xFF9ACD32, // yellowgreen 1565 0xFFEE82EE, // violet 1566 0xFF00CED1, // darkturquoise 1567 0xFF00FF7F, // springgreen 1568 0xFF3CB371, // mediumseagreen 1569 1570 0xFF00008B, // darkblue 1571 0xFFBDB76B, // darkkhaki 1572 0xFF006400, // darkgreen 1573 0xFF800000, // maroon 1574 0xFF808000, // olive 1575 0xFF800080, // purple 1576 0xFF008080, // teal 1577 0xFFB8860B, // darkgoldenrod 1578 0xFFB22222, // firebrick 1579 }; 1580 1581 private final static int[] argbsChainHetero = { 1582 // ' '->0 'A'->1, 'B'->2 1583 0xFFffffff, // ' ' & '0' white 1584 // 1585 0xFFC0D0FF - 0x00303030, // skyblue 1586 0xFFB0FFB0 - 0x00303018, // pastel green 1587 0xFFFFC0C8 - 0x00303018, // pink 1588 0xFFFFFF80 - 0x00303010, // pastel yellow 1589 0xFFFFC0FF - 0x00303030, // pastel magenta 1590 0xFFB0F0F0 - 0x00303030, // pastel cyan 1591 0xFFFFD070 - 0x00303010, // pastel gold 1592 0xFFF08080 - 0x00303010, // lightcoral 1593 1594 0xFFF5DEB3 - 0x00303030, // wheat 1595 0xFF00BFFF - 0x00001830, // deepskyblue 1596 0xFFCD5C5C - 0x00181010, // indianred 1597 0xFF66CDAA - 0x00101818, // mediumaquamarine 1598 0xFF9ACD32 - 0x00101808, // yellowgreen 1599 0xFFEE82EE - 0x00301030, // violet 1600 0xFF00CED1 - 0x00001830, // darkturquoise 1601 0xFF00FF7F - 0x00003010, // springgreen 1602 0xFF3CB371 - 0x00081810, // mediumseagreen 1603 1604 0xFF00008B + 0x00000030, // darkblue 1605 0xFFBDB76B - 0x00181810, // darkkhaki 1606 0xFF006400 + 0x00003000, // darkgreen 1607 0xFF800000 + 0x00300000, // maroon 1608 0xFF808000 + 0x00303000, // olive 1609 0xFF800080 + 0x00300030, // purple 1610 0xFF008080 + 0x00003030, // teal 1611 0xFFB8860B + 0x00303008, // darkgoldenrod 1612 0xFFB22222 + 0x00101010, // firebrick 1613 }; 1614 1615 private final static int[] argbsShapely = { 1616 0xFFFF00FF, // default 1617 // these are rasmol values, not xwindows colors 1618 0xFF00007C, // ARG 1619 0xFFFF7C70, // ASN 1620 0xFF8CFF8C, // ALA 1621 0xFFA00042, // ASP 1622 0xFFFFFF70, // CYS 1623 0xFFFF4C4C, // GLN 1624 0xFF660000, // GLU 1625 0xFFFFFFFF, // GLY 1626 0xFF7070FF, // HIS 1627 0xFF004C00, // ILE 1628 0xFF455E45, // LEU 1629 0xFF4747B8, // LYS 1630 0xFF534C52, // PHE 1631 0xFFB8A042, // MET 1632 0xFF525252, // PRO 1633 0xFFFF7042, // SER 1634 0xFFB84C00, // THR 1635 0xFF4F4600, // TRP 1636 0xFF8C704C, // TYR 1637 0xFFFF8CFF, // VAL 1638 1639 0xFFFF00FF, // ASX ASP/ASN ambiguous 1640 0xFFFF00FF, // GLX GLU/GLN ambiguous 1641 0xFFFF00FF, // UNK unknown -- 23 1642 1643 0xFFFF7070, // G 1644 0xFFFF8C4B, // C 1645 0xFFA0A0FF, // A 1646 0xFFA0FFA0, // T 1647 0xFFFF8080, // U miguel made up this color 1648 0xFF80FFFF, // I miguel made up this color 1649 1650 0xFFFF7070, // DG 1651 0xFFFF8C4B, // DC 1652 0xFFA0A0FF, // DA 1653 0xFFA0FFA0, // DT 1654 0xFFFF8080, // DU 1655 0xFF80FFFF, // DI 1656 1657 0xFFFF7070, // +G 1658 0xFFFF8C4B, // +C 1659 0xFFA0A0FF, // +A 1660 0xFFA0FFA0, // +T 1661 0xFFFF8080, // +U 1662 0xFF80FFFF, // +I 1663 1664 // what to do about remediated +X names? 1665 // we will need a map 1666 1667 }; 1668 1669 static { 1670 /** 1671 * @j2sNative 1672 * 1673 */ 1674 { 1675 if (argbsShapely.length != JC.GROUPID_WATER) { 1676 Logger.error("argbsShapely wrong length"); NullPointerException()1677 throw new NullPointerException(); 1678 } 1679 if (argbsAmino.length != JC.GROUPID_AMINO_MAX) { 1680 Logger.error("argbsAmino wrong length"); NullPointerException()1681 throw new NullPointerException(); 1682 } 1683 if (argbsChainHetero.length != argbsChainAtom.length) { 1684 Logger.error("argbsChainHetero wrong length"); NullPointerException()1685 throw new NullPointerException(); 1686 } 1687 } 1688 1689 } 1690 getArgbs(int tok)1691 public int[] getArgbs(int tok) { 1692 switch (tok) { 1693 case T.nucleic: 1694 return argbsNucleic; 1695 case T.amino: 1696 return argbsAmino; 1697 case T.shapely: 1698 return argbsShapely; 1699 case T.atoms: 1700 return argbsChainAtom; 1701 case T.hetero: 1702 return argbsChainHetero; 1703 } 1704 return null; 1705 } 1706 getBioModelSet(ModelSet modelSet)1707 public BioModelSet getBioModelSet(ModelSet modelSet) { 1708 if (modelSet.bioModelset == null) 1709 modelSet.bioModelset = new BioModelSet().set(vwr, modelSet); 1710 return modelSet.bioModelset; 1711 } 1712 1713 } 1714 1715 1716