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