1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2011-08-05 21:10:46 -0500 (Fri, 05 Aug 2011) $ 4 * $Revision: 15943 $ 5 * 6 * Copyright (C) 2002-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 package org.jmol.modelsetbio; 25 26 import java.util.Hashtable; 27 import java.util.Map; 28 import java.util.Properties; 29 30 import javajs.util.AU; 31 import javajs.util.Lst; 32 import javajs.util.OC; 33 import javajs.util.SB; 34 35 import org.jmol.api.Interface; 36 import org.jmol.c.STR; 37 import org.jmol.dssx.DSSP; 38 import javajs.util.BS; 39 import org.jmol.modelset.Atom; 40 import org.jmol.modelset.Bond; 41 import org.jmol.modelset.Group; 42 import org.jmol.modelset.HBond; 43 import org.jmol.modelset.LabelToken; 44 import org.jmol.modelset.Model; 45 import org.jmol.modelset.ModelSet; 46 import org.jmol.script.SV; 47 import org.jmol.util.Edge; 48 import org.jmol.util.Escape; 49 import org.jmol.viewer.JC; 50 import org.jmol.viewer.Viewer; 51 52 53 public final class BioModel extends Model { 54 55 /* 56 * 57 * Note that "monomer" extends group. A group only becomes a 58 * monomer if it can be identified as one of the following 59 * PDB/mmCIF types: 60 * 61 * amino -- has an N, a C, and a CA 62 * alpha -- has just a CA 63 * nucleic -- has C1',C2',C3',C4',C5',O3', and O5' 64 * phosphorus -- has P 65 * 66 * The term "conformation" is a bit loose. It means "what you get 67 * when you go with one or another set of alternative locations. 68 * 69 * 70 */ 71 72 private Viewer vwr; 73 74 int bioPolymerCount = 0; 75 public BioPolymer[] bioPolymers; 76 boolean isMutated; 77 78 String defaultStructure; 79 BioModel(ModelSet modelSet, int modelIndex, int trajectoryBaseIndex, String jmolData, Properties properties, Map<String, Object> auxiliaryInfo)80 BioModel(ModelSet modelSet, int modelIndex, int trajectoryBaseIndex, 81 String jmolData, Properties properties, Map<String, Object> auxiliaryInfo) { 82 vwr = modelSet.vwr; 83 set(modelSet, modelIndex, trajectoryBaseIndex, jmolData, properties, auxiliaryInfo); 84 85 isBioModel = true; 86 vwr.getJBR().getBioModelSet(modelSet); 87 clearBioPolymers(); 88 modelSet.am[modelIndex] = this; 89 pdbID = (String) auxiliaryInfo.get("name"); 90 } 91 addBioPolymer(BioPolymer polymer)92 int addBioPolymer(BioPolymer polymer) { 93 if (bioPolymers.length == 0) 94 clearBioPolymers(); 95 if (bioPolymerCount == bioPolymers.length) 96 bioPolymers = (BioPolymer[])AU.doubleLength(bioPolymers); 97 polymer.bioPolymerIndexInModel = bioPolymerCount; 98 bioPolymers[bioPolymerCount++] = polymer; 99 return polymer.monomerCount; 100 } 101 102 addSecondaryStructure(STR type, String structureID, int serialID, int strandCount, int startChainID, int startSeqcode, int endChainID, int endSeqcode, int istart, int iend, BS bsAssigned)103 void addSecondaryStructure(STR type, String structureID, 104 int serialID, int strandCount, 105 int startChainID, int startSeqcode, 106 int endChainID, int endSeqcode, int istart, 107 int iend, BS bsAssigned) { 108 for (int i = bioPolymerCount; --i >= 0;) 109 if (bioPolymers[i] instanceof AlphaPolymer) 110 ((AlphaPolymer) bioPolymers[i]).addStructure(type, structureID, 111 serialID, strandCount, startChainID, startSeqcode, endChainID, 112 endSeqcode, istart, iend, bsAssigned); 113 } 114 addStructureByBS(int count, int dsspType, STR type, BS bs)115 void addStructureByBS(int count, int dsspType, STR type, BS bs) { 116 for (int i = bioPolymerCount; --i >= 0;) { 117 BioPolymer b = bioPolymers[i]; 118 if (b instanceof AlphaPolymer) 119 count = ((AlphaPolymer) bioPolymers[i]).setStructureBS(++count, dsspType, type, bs, true); 120 } 121 } 122 calculateDssx(Lst<Bond> vHBonds, boolean doReport, boolean dsspIgnoreHydrogen, boolean setStructure, int version)123 private String calculateDssx(Lst<Bond> vHBonds, boolean doReport, 124 boolean dsspIgnoreHydrogen, boolean setStructure, int version) { 125 boolean haveProt = false; 126 boolean haveNucl = false; 127 for (int i = 0; i < bioPolymerCount && !(haveProt && haveNucl); i++) { 128 if (bioPolymers[i].isNucleic()) 129 haveNucl = true; 130 else if (bioPolymers[i] instanceof AminoPolymer) 131 haveProt = true; 132 } 133 String s = ""; 134 if (haveProt) 135 s += ((DSSP) Interface.getOption("dssx.DSSP", vwr, "ms")) 136 .calculateDssp(bioPolymers, bioPolymerCount, vHBonds, doReport, 137 dsspIgnoreHydrogen, setStructure, version); 138 if (haveNucl && auxiliaryInfo.containsKey("dssr") && vHBonds != null) 139 s += vwr.getAnnotationParser(true).getHBonds(ms, modelIndex, vHBonds, doReport); 140 return s; 141 } 142 calculateStructures(boolean asDSSP, boolean doReport, boolean dsspIgnoreHydrogen, boolean setStructure, boolean includeAlpha, int version)143 String calculateStructures(boolean asDSSP, boolean doReport, 144 boolean dsspIgnoreHydrogen, 145 boolean setStructure, boolean includeAlpha, int version) { 146 if (bioPolymerCount == 0 || !setStructure && !asDSSP) 147 return ""; 148 ms.proteinStructureTainted = structureTainted = true; 149 if (setStructure) 150 for (int i = bioPolymerCount; --i >= 0;) 151 if (!asDSSP || bioPolymers[i].monomers[0].getNitrogenAtom() != null) 152 bioPolymers[i].clearStructures(); 153 if (!asDSSP || includeAlpha) 154 for (int i = bioPolymerCount; --i >= 0;) 155 if (bioPolymers[i] instanceof AlphaPolymer) 156 ((AlphaPolymer) bioPolymers[i]).calculateStructures(includeAlpha); 157 return (asDSSP ? calculateDssx(null, doReport, dsspIgnoreHydrogen, setStructure, version) : ""); 158 } 159 160 clearBioPolymers()161 void clearBioPolymers() { 162 bioPolymers = new BioPolymer[8]; 163 bioPolymerCount = 0; 164 } 165 166 @Override fixIndices(int modelIndex, int nAtomsDeleted, BS bsDeleted)167 public void fixIndices(int modelIndex, int nAtomsDeleted, BS bsDeleted) { 168 fixIndicesM(modelIndex, nAtomsDeleted, bsDeleted); 169 recalculateLeadMidpointsAndWingVectors(); 170 } 171 172 @Override freeze()173 public boolean freeze() { 174 freezeM(); 175 bioPolymers = (BioPolymer[])AU.arrayCopyObject(bioPolymers, bioPolymerCount); 176 return true; 177 } 178 getBioBranches(Lst<BS> biobranches)179 public Lst<BS> getBioBranches(Lst<BS> biobranches) { 180 // scan through biopolymers quickly -- 181 BS bsBranch; 182 for (int j = 0; j < bioPolymerCount; j++) { 183 bsBranch = new BS(); 184 bioPolymers[j].getRange(bsBranch, isMutated); 185 int iAtom = bsBranch.nextSetBit(0); 186 if (iAtom >= 0) { 187 if (biobranches == null) 188 biobranches = new Lst<BS>(); 189 biobranches.addLast(bsBranch); 190 } 191 } 192 return biobranches; 193 } 194 getBioPolymerCount()195 public int getBioPolymerCount() { 196 return bioPolymerCount; 197 } 198 getCachedAnnotationMap(String key, Object ann)199 Object getCachedAnnotationMap(String key, Object ann) { 200 Map<String, Object> cache = (dssrCache == null && ann != null ? dssrCache = new Hashtable<String, Object>() 201 : dssrCache); 202 if (cache == null) 203 return null; 204 Object annotv = cache.get(key); 205 if (annotv == null && ann != null) { 206 annotv = (ann instanceof SV || ann instanceof Hashtable ? ann 207 : vwr.parseJSONMap((String) ann)); 208 cache.put(key, annotv); 209 } 210 return (annotv instanceof SV || annotv instanceof Hashtable ? annotv : null); 211 } 212 213 /** 214 * @param conformationIndex0 215 * @param doSet 216 * @param bsAtoms 217 * @param bsRet 218 * @return true; 219 */ getConformation(int conformationIndex0, boolean doSet, BS bsAtoms, BS bsRet)220 public boolean getConformation(int conformationIndex0, boolean doSet, BS bsAtoms, BS bsRet) { 221 if (conformationIndex0 >= 0) { 222 int nAltLocs = altLocCount; 223 if (nAltLocs > 0) { 224 Atom[] atoms = ms.at; 225 Group g = null; 226 char ch = '\0'; 227 int conformationIndex = conformationIndex0; 228 BS bsFound = new BS(); 229 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) { 230 Atom atom = atoms[i]; 231 char altloc = atom.altloc; 232 // ignore (include) atoms that have no designation 233 if (altloc == '\0') 234 continue; 235 if (atom.group != g) { 236 g = atom.group; 237 ch = '\0'; 238 conformationIndex = conformationIndex0; 239 bsFound.clearAll(); 240 } 241 // count down until we get the desired index into the list 242 if (conformationIndex >= 0 && altloc != ch && !bsFound.get(altloc)) { 243 ch = altloc; 244 conformationIndex--; 245 bsFound.set(altloc); 246 } 247 if (conformationIndex >= 0 || altloc != ch) 248 bsAtoms.clear(i); 249 } 250 } 251 } 252 if (bsAtoms.nextSetBit(0) >= 0) { 253 bsRet.or(bsAtoms); 254 if (doSet) 255 for (int j = bioPolymerCount; --j >= 0;) 256 bioPolymers[j].setConformation(bsAtoms); 257 } 258 return true; 259 } 260 getDefaultLargePDBRendering(SB sb, int maxAtoms)261 public void getDefaultLargePDBRendering(SB sb, int maxAtoms) { 262 BS bs = new BS(); 263 if (getBondCount() == 0) 264 bs = bsAtoms; 265 // all biopolymer atoms... 266 if (bs != bsAtoms) 267 for (int i = 0; i < bioPolymerCount; i++) 268 bioPolymers[i].getRange(bs, isMutated); 269 if (bs.nextSetBit(0) < 0) 270 return; 271 // ...and not connected to backbone: 272 BS bs2 = new BS(); 273 if (bs == bsAtoms) { 274 bs2 = bs; 275 } else { 276 for (int i = 0; i < bioPolymerCount; i++) 277 if (bioPolymers[i].getType() == BioPolymer.TYPE_NOBONDING) 278 bioPolymers[i].getRange(bs2, isMutated); 279 } 280 if (bs2.nextSetBit(0) >= 0) 281 sb.append("select ").append(Escape.eBS(bs2)).append(";backbone only;"); 282 if (act <= maxAtoms) 283 return; 284 // ...and it's a large model, to wireframe: 285 sb.append("select ").append(Escape.eBS(bs)).append(" & connected; wireframe only;"); 286 // ... and all non-biopolymer and not connected to stars... 287 if (bs != bsAtoms) { 288 bs2.clearAll(); 289 bs2.or(bsAtoms); 290 bs2.andNot(bs); 291 if (bs2.nextSetBit(0) >= 0) 292 sb.append("select " + Escape.eBS(bs2) + " & !connected;stars 0.5;spacefill off;"); 293 } 294 } 295 getFullPDBHeader()296 public String getFullPDBHeader() { 297 if (modelIndex < 0) 298 return ""; 299 String info = (String) auxiliaryInfo.get("fileHeader"); 300 if (info != null) 301 return info; 302 return ms.bioModelset.getBioExt().getFullPDBHeader(auxiliaryInfo); 303 } 304 getPdbData(String type, char ctype, boolean isDraw, BS bsSelected, OC out, LabelToken[] tokens, SB pdbCONECT, BS bsWritten)305 public void getPdbData(String type, char ctype, boolean isDraw, 306 BS bsSelected, OC out, 307 LabelToken[] tokens, SB pdbCONECT, BS bsWritten) { 308 ms.bioModelset.getBioExt().getPdbDataM(this, vwr, type, ctype, isDraw, bsSelected, out, tokens, pdbCONECT, bsWritten); 309 } 310 getRasmolHydrogenBonds(BS bsA, BS bsB, Lst<Bond> vHBonds, boolean nucleicOnly, int nMax, boolean dsspIgnoreHydrogens, BS bsHBonds, int version)311 void getRasmolHydrogenBonds(BS bsA, BS bsB, Lst<Bond> vHBonds, 312 boolean nucleicOnly, int nMax, 313 boolean dsspIgnoreHydrogens, BS bsHBonds, int version) { 314 boolean doAdd = (vHBonds == null); 315 if (doAdd) 316 vHBonds = new Lst<Bond>(); 317 if (nMax < 0) 318 nMax = Integer.MAX_VALUE; 319 boolean asDSSX = (bsB == null); 320 BioPolymer bp, bp1; 321 if (asDSSX && bioPolymerCount > 0) { 322 calculateDssx(vHBonds, false, dsspIgnoreHydrogens, false, version); 323 } else { 324 for (int i = bioPolymerCount; --i >= 0;) { 325 bp = bioPolymers[i]; 326 if (bp.monomerCount == 0) 327 continue; 328 int type = bp.getType(); 329 boolean isRNA = false; 330 switch (type) { 331 case BioPolymer.TYPE_AMINO: 332 if (nucleicOnly) 333 continue; 334 bp.calcRasmolHydrogenBonds(null, bsA, bsB, vHBonds, nMax, null, true, 335 false); 336 break; 337 case BioPolymer.TYPE_NUCLEIC: 338 isRNA = bp.monomers[0].isRna(); 339 break; 340 default: 341 continue; 342 } 343 for (int j = bioPolymerCount; --j >= 0;) { 344 if ((bp1 = bioPolymers[j]) != null && (isRNA || i != j) 345 && type == bp1.getType()) { 346 bp1.calcRasmolHydrogenBonds(bp, bsA, bsB, vHBonds, nMax, null, 347 true, false); 348 } 349 } 350 } 351 } 352 353 if (vHBonds.size() == 0 || !doAdd) 354 return; 355 hasRasmolHBonds = true; 356 for (int i = 0; i < vHBonds.size(); i++) { 357 HBond bond = (HBond) vHBonds.get(i); 358 Atom atom1 = bond.atom1; 359 Atom atom2 = bond.atom2; 360 if (atom1.isBonded(atom2)) 361 continue; 362 int index = ms.addHBond(atom1, atom2, bond.order, bond.getEnergy()); 363 if (bsHBonds != null) 364 bsHBonds.set(index); 365 } 366 } 367 368 /** 369 * Get a unitID. Note that we MUST go through the | after InsCode, because 370 * if we do not do that we cannot match residues only using string matching. 371 * 372 * @param atom 373 * @param flags 374 * @return a unitID 375 */ getUnitID(Atom atom, int flags)376 public String getUnitID(Atom atom, int flags) { 377 378 // type: (ID)|model|chain|resid|resno|(atomName)|(altID)|(InsCode)|(symmetry) 379 // res: ID|model|chain|resid|resno|atomName|altID|InsCode|symmetry 380 SB sb = new SB(); 381 Group m = atom.group; 382 boolean noTrim =((flags & JC.UNITID_TRIM) != JC.UNITID_TRIM); 383 char ch = ((flags & JC.UNITID_INSCODE) == JC.UNITID_INSCODE ? m.getInsertionCode() : '\0'); 384 boolean isAll = (ch != '\0'); 385 if ((flags & JC.UNITID_MODEL) == JC.UNITID_MODEL && (pdbID != null)) 386 sb.append(pdbID); 387 sb.append("|").appendO(ms.getInfo(modelIndex, "modelNumber")) 388 .append("|").append(vwr.getChainIDStr(m.chain.chainID)) 389 .append("|").append(m.getGroup3()) 390 .append("|").appendI(m.getResno()); 391 if ((flags & JC.UNITID_ATOM) == JC.UNITID_ATOM) { 392 sb.append("|").append(atom.getAtomName()); 393 if (atom.altloc != '\0') 394 sb.append("|").appendC(atom.altloc); 395 else if (noTrim || isAll) 396 sb.append("|"); 397 } else if (noTrim || isAll) { 398 sb.append("||"); 399 } 400 if (isAll) 401 sb.append("|").appendC(ch); 402 else if (noTrim) 403 sb.append("|"); 404 if (noTrim) 405 sb.append("|"); 406 return sb.toString(); 407 } 408 recalculateLeadMidpointsAndWingVectors()409 void recalculateLeadMidpointsAndWingVectors() { 410 for (int ip = 0; ip < bioPolymerCount; ip++) 411 bioPolymers[ip].recalculateLeadMidpointsAndWingVectors(); 412 } 413 414 415 /** 416 * from Trajectory.setAtomPositions 417 * 418 * base models only; not trajectories 419 * @param bs 420 * @param dsspVersion 421 */ resetRasmolBonds(BS bs, int dsspVersion)422 public void resetRasmolBonds(BS bs, int dsspVersion) { 423 BS bsDelete = new BS(); 424 hasRasmolHBonds = false; 425 Model[] am = ms.am; 426 Bond[] bo = ms.bo; 427 for (int i = ms.bondCount; --i >= 0;) { 428 Bond bond = bo[i]; 429 // trajectory atom .mi will be pointing to the trajectory; 430 // here we check to see if their base model is this model 431 if ((bond.order & Edge.BOND_H_CALC_MASK) != 0 432 && am[bond.atom1.mi].trajectoryBaseIndex == modelIndex) 433 bsDelete.set(i); 434 } 435 if (bsDelete.nextSetBit(0) >= 0) 436 ms.deleteBonds(bsDelete, false); 437 getRasmolHydrogenBonds(bs, bs, null, false, Integer.MAX_VALUE, false, null, dsspVersion); 438 } 439 getAtomicDSSRData(float[] dssrData, String dataType)440 public void getAtomicDSSRData(float[] dssrData, String dataType) { 441 if (auxiliaryInfo.containsKey("dssr")) 442 vwr.getAnnotationParser(true).getAtomicDSSRData(ms, modelIndex, dssrData, dataType); 443 } 444 445 } 446