Revision: 20251
          http://sourceforge.net/p/jmol/code/20251
Author:   hansonr
Date:     2015-01-28 16:16:02 +0000 (Wed, 28 Jan 2015)
Log Message:
-----------
Jmol.___JmolVersion="14.3.12_2015.01.28"

new feature: MUTATE command
 -- replaces one amino acid group with another
 -- can read from RCSB or from user-specified file
 -- examples: 
      mutate 33 lys          // uses last occurrence of resno=33
      mutate @@3 arg         // replaces group of atom 3 in current model
      mutate @r @g           // replaces resno in variable r with group in 
variable g
      mutate {r} his         // same as above; r must be an atom selection
      mutate 22 "myfile.cif" // user-defined replacement
      
new feature: resno is user settable

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/api/JmolBioResolver.java
    trunk/Jmol/src/org/jmol/api/JmolPropertyManager.java
    trunk/Jmol/src/org/jmol/modelset/Atom.java
    trunk/Jmol/src/org/jmol/modelset/AtomCollection.java
    trunk/Jmol/src/org/jmol/modelset/BondCollection.java
    trunk/Jmol/src/org/jmol/modelset/Group.java
    trunk/Jmol/src/org/jmol/modelset/Model.java
    trunk/Jmol/src/org/jmol/modelset/ModelSet.java
    trunk/Jmol/src/org/jmol/modelsetbio/BioModel.java
    trunk/Jmol/src/org/jmol/modelsetbio/BioPolymer.java
    trunk/Jmol/src/org/jmol/modelsetbio/Monomer.java
    trunk/Jmol/src/org/jmol/modelsetbio/Resolver.java
    trunk/Jmol/src/org/jmol/script/ScriptEval.java
    trunk/Jmol/src/org/jmol/script/ScriptExpr.java
    trunk/Jmol/src/org/jmol/script/T.java
    trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
    trunk/Jmol/src/org/jmol/viewer/Jmol.properties
    trunk/Jmol/src/org/jmol/viewer/PropertyManager.java
    trunk/Jmol/src/org/jmol/viewer/StateCreator.java
    trunk/Jmol/src/org/jmol/viewer/Viewer.java
    trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/NBODialog.java
    trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java

Modified: trunk/Jmol/src/org/jmol/api/JmolBioResolver.java
===================================================================
--- trunk/Jmol/src/org/jmol/api/JmolBioResolver.java    2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/api/JmolBioResolver.java    2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -55,6 +55,8 @@
   Resolver setViewer(Viewer vwr);
 
   public short getGroupID(String g3);
+
+  public boolean mutate(int iatom, String fileName);
   
   }
 

Modified: trunk/Jmol/src/org/jmol/api/JmolPropertyManager.java
===================================================================
--- trunk/Jmol/src/org/jmol/api/JmolPropertyManager.java        2015-01-28 
00:19:08 UTC (rev 20250)
+++ trunk/Jmol/src/org/jmol/api/JmolPropertyManager.java        2015-01-28 
16:16:02 UTC (rev 20251)
@@ -42,5 +42,7 @@
 
   String getModelCml(BS bs, int nAtomsMax, boolean addBonds);
 
+  String getCoordinateFileData(String atomExpression, String type);
 
+
 }

Modified: trunk/Jmol/src/org/jmol/modelset/Atom.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/Atom.java  2015-01-28 00:19:08 UTC (rev 
20250)
+++ trunk/Jmol/src/org/jmol/modelset/Atom.java  2015-01-28 16:16:02 UTC (rev 
20251)
@@ -419,7 +419,7 @@
     return !Float.isNaN(userDefinedVanDerWaalRadius = (radius > 0 ? radius : 
Float.NaN));  
   }
   
-  public void deleteBonds(BS bsBonds) {
+  public void delete(BS bsBonds) {
     valence = -1;
     if (bonds != null)
       for (int i = bonds.length; --i >= 0; ) {

Modified: trunk/Jmol/src/org/jmol/modelset/AtomCollection.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/AtomCollection.java        2015-01-28 
00:19:08 UTC (rev 20250)
+++ trunk/Jmol/src/org/jmol/modelset/AtomCollection.java        2015-01-28 
16:16:02 UTC (rev 20251)
@@ -88,6 +88,7 @@
   String[] atomNames;
   String[] atomTypes;
   int[] atomSerials;
+  int[] atomResnos;
   int[] atomSeqIDs;
   public Vibration[] vibrations;
   float[] occupancies;
@@ -147,7 +148,8 @@
   final public static byte TAINT_VIBRATION = 12;
   final public static byte TAINT_ATOMNO = 13;
   final public static byte TAINT_SEQID = 14;
-  final public static byte TAINT_MAX = 15; // 1 more than last number, above
+  final public static byte TAINT_RESNO = 15;
+  final public static byte TAINT_MAX = 16; // 1 more than last number, above
   
   public static String[] userSettableValues;
   
@@ -167,7 +169,7 @@
     bsClickable = new BS();
     // this allows the Google Closure compiler to skip all the TAINTED defs in 
Clazz.defineStatics
     if (userSettableValues == null)
-      userSettableValues = "atomName atomType coord element formalCharge 
hydrophobicity ionic occupancy partialCharge temperature valence vanderWaals 
vibrationVector atomNo seqID".split(" ");
+      userSettableValues = "atomName atomType coord element formalCharge 
hydrophobicity ionic occupancy partialCharge temperature valence vanderWaals 
vibrationVector atomNo seqID resNo".split(" ");
   }
   
   protected void releaseModelSet() {
@@ -185,6 +187,7 @@
 
     atomNames = null;
     atomTypes = null;
+    atomResnos = null;
     atomSerials = null;
     atomSeqIDs = null;
     vibrations = null;
@@ -199,6 +202,7 @@
     tainted = mergeModelSet.tainted;
     atomNames = mergeModelSet.atomNames;
     atomTypes = mergeModelSet.atomTypes;
+    atomResnos = mergeModelSet.atomResnos;
     atomSerials = mergeModelSet.atomSerials;
     atomSeqIDs = mergeModelSet.atomSeqIDs;
     vibrations = mergeModelSet.vibrations;
@@ -655,6 +659,10 @@
         if (setBFactor(i, fValue))
           taintAtom(i, TAINT_TEMPERATURE);
         break;
+      case T.resno:
+        setAtomResno(i,  iValue);
+        taintAtom(i, TAINT_RESNO);
+        break;
       case T.valence:
         atom.setValence(iValue);
         taintAtom(i, TAINT_VALENCE);
@@ -796,6 +804,15 @@
     return true;
   }
   
+  public boolean setAtomResno(int atomIndex, int resno) {
+    if (atomResnos == null) {
+      atomResnos = new int[at.length];
+    }
+    atomResnos[atomIndex] = resno;
+    at[atomIndex].group.setResno(resno);
+    return true;
+  }
+  
   public boolean setAtomSeqID(int atomIndex, int seqID) {
     if (atomSeqIDs == null) {
       atomSeqIDs = new int[at.length];
@@ -903,6 +920,9 @@
         case TAINT_ATOMNO:
           setAtomNumber(atomIndex, (int) x);
           break;
+        case TAINT_RESNO:
+          setAtomResno(atomIndex, (int) x);
+          break;
         case TAINT_SEQID:
           setAtomSeqID(atomIndex, (int) x);
           break;
@@ -2045,7 +2065,7 @@
    * @param specInfo
    * @return BitSet; or null if we mess up the type
    */
-  protected BS getAtomBitsMDa(int tokType, Object specInfo) {
+  public BS getAtomBitsMDa(int tokType, Object specInfo) {
     BS bs = new BS()  ;
     BS bsInfo;
     BS bsTemp;
@@ -2619,6 +2639,8 @@
         nAtoms);
     atomTypes = (String[]) AU.deleteElements(atomTypes, firstAtomIndex,
         nAtoms);
+    atomResnos = (int[]) AU.deleteElements(atomResnos, firstAtomIndex,
+        nAtoms);
     atomSerials = (int[]) AU.deleteElements(atomSerials, firstAtomIndex,
         nAtoms);
     atomSeqIDs = (int[]) AU.deleteElements(atomSeqIDs, firstAtomIndex,

Modified: trunk/Jmol/src/org/jmol/modelset/BondCollection.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/BondCollection.java        2015-01-28 
00:19:08 UTC (rev 20250)
+++ trunk/Jmol/src/org/jmol/modelset/BondCollection.java        2015-01-28 
16:16:02 UTC (rev 20251)
@@ -802,5 +802,43 @@
         bo[i].setShapeVisibility(isDisplay);
   }
 
+  public BS getAtomsConnected(float min, float max, int intType, BS bs) {
+    boolean isBonds = bs instanceof BondSet;
+    BS bsResult = (isBonds ? new BondSet() : new BS());
+    int[] nBonded = new int[ac];
+    int i;
+    boolean ishbond = (intType == Edge.BOND_HYDROGEN_MASK);
+    boolean isall = (intType == Edge.BOND_ORDER_ANY);
+    for (int ibond = 0; ibond < bondCount; ibond++) {
+      Bond bond = bo[ibond];
+      if (isall || bond.is(intType) || ishbond && bond.isHydrogen()) {
+        if (isBonds) {
+          bsResult.set(ibond);
+        } else {
+        if (bs.get(bond.atom1.i)) {
+          nBonded[i = bond.atom2.i]++;
+          bsResult.set(i);
+        }
+        if (bs.get(bond.atom2.i)) {
+          nBonded[i = bond.atom1.i]++;
+          bsResult.set(i);
+        }
+        }
+      }
+    }
+    if (isBonds)
+      return bsResult;
+    boolean nonbonded = (min == 0);
+    for (i = ac; --i >= 0;) {
+      int n = nBonded[i];
+      if (n < min || n > max)
+        bsResult.clear(i);
+      else if (nonbonded && n == 0)
+        bsResult.set(i);
+    }
+    return bsResult;
+  }
+
+
 }
 

Modified: trunk/Jmol/src/org/jmol/modelset/Group.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/Group.java 2015-01-28 00:19:08 UTC (rev 
20250)
+++ trunk/Jmol/src/org/jmol/modelset/Group.java 2015-01-28 16:16:02 UTC (rev 
20251)
@@ -110,10 +110,6 @@
     return -1;
   }
 
-  public Group[] getGroups() {
-    return null;
-  }
-
   public Object getStructure() {
     return null;
   }
@@ -165,6 +161,10 @@
     return (seqcode == Integer.MIN_VALUE ? 0 : seqcode >> 
SEQUENCE_NUMBER_SHIFT); 
   }
 
+  public void setResno(int i) {
+    seqcode = getSeqcodeFor(i, getInsertionCode());
+  }
+
   public final static int getSeqNumberFor(int seqcode) {
     return (haveSequenceNumber(seqcode)? seqcode >> SEQUENCE_NUMBER_SHIFT 
         : Integer.MAX_VALUE);
@@ -204,9 +204,7 @@
   }
 
   public char getInsertionCode() {
-    if (seqcode == Integer.MIN_VALUE)
-      return '\0';
-    return (char)(seqcode & INSERTION_CODE_MASK);
+    return (seqcode == Integer.MIN_VALUE ? '\0' :(char)(seqcode & 
INSERTION_CODE_MASK));
   }
   
   public static int getInsertionCodeFor(int seqcode) {
@@ -246,11 +244,6 @@
         || bsAdded != null &&  bsAdded.intersects(bs));
   }
 
-  boolean isHetero() {
-    // just look at the first atom of the group
-    return chain.getAtom(firstAtomIndex).isHetero();
-  }
-  
   @Override
   public String toString() {
     return "[" + getGroup3() + "-" + getSeqcodeString() + "]";

Modified: trunk/Jmol/src/org/jmol/modelset/Model.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/Model.java 2015-01-28 00:19:08 UTC (rev 
20250)
+++ trunk/Jmol/src/org/jmol/modelset/Model.java 2015-01-28 16:16:02 UTC (rev 
20251)
@@ -150,7 +150,7 @@
   public int nAltLocs;
   int nInsertions;
 
-  int groupCount = -1;
+  public int groupCount = -1;
 
   protected int chainCount = 0;
   public Chain[] chains = new Chain[8];
@@ -212,15 +212,6 @@
     return chainCount;
   }
 
-  public int getGroupCountHetero(boolean isHetero) {
-    int n = 0;
-    for (int i = chainCount; --i >= 0;)
-      for (int j = chains[i].groupCount; --j >= 0;)
-        if (chains[i].groups[j].isHetero() == isHetero)
-          n++;
-    return n;
-  }
-
   void calcSelectedGroupsCount(BS bsSelected) {
     for (int i = chainCount; --i >= 0;)
       chains[i].calcSelectedGroupsCount(bsSelected);
@@ -341,8 +332,8 @@
   public void setStructureList(Map<STR, float[]> structureList) {
   }
 
-  public void getChimeInfo(SB sb, int nHetero) {
-    getChimeInfoM(sb, nHetero);
+  public void getChimeInfo(SB sb) {
+    getChimeInfoM(sb, 0);
   }
 
   protected void getChimeInfoM(SB sb, int nHetero) {
@@ -360,15 +351,6 @@
     //
   }
 
-  /**
-   * @param bsConformation
-   * @param conformationIndex
-   * @return true for BioModel
-   */
-  public boolean getPdbConformation(BS bsConformation, int conformationIndex) {
-    return false;
-  }
-
   public String getFullPDBHeader() {
     return null;
   }
@@ -529,4 +511,15 @@
     // biomodel only
   }
 
+  /**
+   * @param conformationIndex  
+   * @param doSet 
+   * @param bsAtoms 
+   * @param bs 
+   */
+  public void getConformation(int conformationIndex, boolean doSet, BS bsAtoms,
+                              BS bs) {
+    // biomodel only
+  }
+
  }

Modified: trunk/Jmol/src/org/jmol/modelset/ModelSet.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelset/ModelSet.java      2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/modelset/ModelSet.java      2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -984,7 +984,7 @@
    * 
    * @return full array of groups in modelSet
    */
-  public Group[] getGroups() {
+  Group[] getGroups() {
     int n = 0;
     for (int i = 0; i < mc; i++)
       n += am[i].getGroupCount();
@@ -1379,28 +1379,11 @@
     return bsAtoms;
   }
 
-  public BS getConformation(int modelIndex, int conformationIndex, boolean 
doSet) {
+  public BS getConformation(int modelIndex, int conformationIndex, boolean 
doSet, BS bsAtoms) {
     BS bs = new BS();
     for (int i = mc; --i >= 0;)
-      if (i == modelIndex || modelIndex < 0) {
-        String altLocs = getAltLocListInModel(i);
-        int nAltLocs = getAltLocCountInModel(i);
-        if (conformationIndex > 0 && conformationIndex >= nAltLocs)
-          continue;
-        BS bsConformation = vwr.getModelUndeletedAtomsBitSet(i);
-        if (conformationIndex >= 0) {
-          if (am[i].getPdbConformation(bsConformation, conformationIndex))
-            for (int c = nAltLocs; --c >= 0;)
-              if (c != conformationIndex)
-                bsConformation.andNot(getAtomBitsMDa(T.spec_alternate,
-                    altLocs.substring(c, c + 1)));
-        }
-        if (bsConformation.nextSetBit(0) >= 0) {
-          bs.or(bsConformation);
-          if (doSet)
-            am[i].setConformation(bsConformation);
-        }
-      }
+      if (i == modelIndex || modelIndex < 0) 
+        am[i].getConformation(conformationIndex, doSet, bsAtoms, bs);
     return bs;
   }
 
@@ -2979,42 +2962,6 @@
     return sb.toString();
   }
 
-  public BS getAtomsConnected(float min, float max, int intType, BS bs) {
-    boolean isBonds = bs instanceof BondSet;
-    BS bsResult = (isBonds ? new BondSet() : new BS());
-    int[] nBonded = new int[ac];
-    int i;
-    boolean ishbond = (intType == Edge.BOND_HYDROGEN_MASK);
-    boolean isall = (intType == Edge.BOND_ORDER_ANY);
-    for (int ibond = 0; ibond < bondCount; ibond++) {
-      Bond bond = bo[ibond];
-      if (isall || bond.is(intType) || ishbond && bond.isHydrogen()) {
-        if (isBonds) {
-          bsResult.set(ibond);
-        } else {
-        if (bs.get(bond.atom1.i)) {
-          nBonded[i = bond.atom2.i]++;
-          bsResult.set(i);
-        }
-        if (bs.get(bond.atom2.i)) {
-          nBonded[i = bond.atom1.i]++;
-          bsResult.set(i);
-        }
-        }
-      }
-    }
-    if (isBonds)
-      return bsResult;
-    boolean nonbonded = (min == 0);
-    for (i = ac; --i >= 0;) {
-      int n = nBonded[i];
-      if (n < min || n > max)
-        bsResult.clear(i);
-      else if (nonbonded && n == 0)
-        bsResult.set(i);
-    }
-    return bsResult;
-  }
   public SymmetryInterface getSymTemp(boolean forceNew) {
     return (symTemp == null || forceNew ? (symTemp = 
Interface.getSymmetry(vwr, "ms")) : symTemp);
   }
@@ -3198,7 +3145,7 @@
     BS bsBonds = new BS();
     for (int i = bs.nextSetBit(0); i >= 0 && i < ac; i = bs
         .nextSetBit(i + 1))
-      at[i].deleteBonds(bsBonds);
+      at[i].delete(bsBonds);
     for (int i = 0; i < mc; i++) {
       am[i].bsAtomsDeleted.or(bs);
       am[i].bsAtomsDeleted.and(am[i].bsAtoms);
@@ -3223,15 +3170,6 @@
     if (vibrations != null)
       for (int i = i0; i < ac; i++)
         vibrations[i] = vibrations[map[i]];
-    if (occupancies != null)
-      for (int i = i0; i < ac; i++)
-        occupancies[i] = occupancies[map[i]];
-    if (bfactor100s != null)
-      for (int i = i0; i < ac; i++)
-        bfactor100s[i] = bfactor100s[map[i]];
-    if (partialCharges != null)
-      for (int i = i0; i < ac; i++)
-        partialCharges[i] = partialCharges[map[i]];
     if (atomTensorList != null) {
       for (int i = i0; i < ac; i++) {
         Object[] list = atomTensorList[i] = atomTensorList[map[i]];
@@ -3250,12 +3188,27 @@
     if (atomTypes != null)
       for (int i = i0; i < ac; i++)
         atomTypes[i] = atomTypes[map[i]];
+
+    if (atomResnos != null)
+      for (int i = i0; i < ac; i++)
+        atomResnos[i] = atomResnos[map[i]];
     if (atomSerials != null)
       for (int i = i0; i < ac; i++)
         atomSerials[i] = atomSerials[map[i]];
     if (atomSeqIDs != null)
       for (int i = i0; i < ac; i++)
         atomSeqIDs[i] = atomSeqIDs[map[i]];
+    
+    if (bfactor100s != null)
+      for (int i = i0; i < ac; i++)
+        bfactor100s[i] = bfactor100s[map[i]];
+
+    if (occupancies != null)
+      for (int i = i0; i < ac; i++)
+        occupancies[i] = occupancies[map[i]];
+    if (partialCharges != null)
+      for (int i = i0; i < ac; i++)
+        partialCharges[i] = partialCharges[map[i]];
   }
 
   protected void growAtomArrays(int newLength) {
@@ -3275,6 +3228,8 @@
       atomNames = AU.arrayCopyS(atomNames, newLength);
     if (atomTypes != null)
       atomTypes = AU.arrayCopyS(atomTypes, newLength);
+    if (atomResnos != null)
+      atomResnos = AU.arrayCopyI(atomResnos, newLength);
     if (atomSerials != null)
       atomSerials = AU.arrayCopyI(atomSerials, newLength);
     if (atomSeqIDs != null)
@@ -4067,16 +4022,20 @@
     if (!setStructure)
       return calculateStructuresAllExcept(bsModelsExcluded, asDSSP, doReport,
           dsspIgnoreHydrogen, false, false);
-    for (int i = 0; i < mc; i++)
-      if (!bsModelsExcluded.get(i))
-        am[i].clearBioPolymers();
-    calculatePolymers(null, 0, 0, bsModelsExcluded);
+    recalculatePolymers(bsModelsExcluded);
     String ret = calculateStructuresAllExcept(bsModelsExcluded, asDSSP, 
doReport,
         dsspIgnoreHydrogen, true, false);
     vwr.shm.resetBioshapes(bsAllAtoms);
     setStructureIndexes();
     return ret;
   }
+  
+  public void recalculatePolymers(BS bsModelsExcluded) {
+    for (int i = 0; i < mc; i++)
+      if (!bsModelsExcluded.get(i))
+        am[i].clearBioPolymers();
+    calculatePolymers(getGroups(), -1, 0, bsModelsExcluded);
+  }
 
 }
 

Modified: trunk/Jmol/src/org/jmol/modelsetbio/BioModel.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelsetbio/BioModel.java   2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/modelsetbio/BioModel.java   2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -135,7 +135,6 @@
       else if (bioPolymers[i] instanceof AminoPolymer)
         haveProt = true;
     }
-    
     String s = "";
     if (haveProt)
       s += ((DSSPInterface) Interface.getOption("dssx.DSSP", ms.vwr, "ms"))
@@ -153,12 +152,36 @@
         bioPolymers[i].setConformation(bsConformation);
   }
 
+  /**
+   * @param conformationIndex
+   * @param bs
+   * @param bsSelected
+   */
   @Override
-  public boolean getPdbConformation(BS bsConformation, int conformationIndex) {
-    if (nAltLocs > 0)
-      for (int i = bioPolymerCount; --i >= 0;)
-        bioPolymers[i].getConformation(bsConformation, conformationIndex);
-    return true;
+  public void getConformation(int conformationIndex, boolean doSet, BS 
bsSelected, BS bs) {
+    String altLocs = ms.getAltLocListInModel(modelIndex);
+    int nAltLocs = ms.getAltLocCountInModel(modelIndex);
+    if (conformationIndex > 0 && conformationIndex >= nAltLocs)
+      return;
+    BS bsConformation = ms.vwr.getModelUndeletedAtomsBitSet(modelIndex);
+    if (bsSelected != null)
+      bsConformation.and(bsSelected);
+    if (bsConformation.nextSetBit(0) < 0)
+      return;
+    if (conformationIndex >= 0) {
+      if (nAltLocs > 0)
+        for (int i = bioPolymerCount; --i >= 0;)
+          bioPolymers[i].getConformation(bsConformation, conformationIndex);
+      for (int c = nAltLocs; --c >= 0;)
+        if (c != conformationIndex)
+          bsConformation.andNot(ms.getAtomBitsMDa(T.spec_alternate,
+              altLocs.substring(c, c + 1)));
+    }
+    if (bsConformation.nextSetBit(0) >= 0) {
+      bs.or(bsConformation);      
+      if (doSet)
+        setConformation(bsConformation);
+    }
   }
 
   @Override
@@ -283,55 +306,60 @@
   
   @SuppressWarnings("incomplete-switch")
   @Override
-  public void getChimeInfo(SB sb, int nHetero) {
+  public void getChimeInfo(SB sb) {
     int n = 0;
     Model[] models = ms.am;
     int modelCount = ms.mc;
     int ac = ms.ac;
     Atom[] atoms = ms.at;
-    sb.append("\nMolecule name ....... "
-        + ms.getInfoM("COMPND"));
+    sb.append("\nMolecule name ....... " + ms.getInfoM("COMPND"));
     sb.append("\nSecondary Structure . PDB Data Records");
     sb.append("\nBrookhaven Code ..... " + ms.modelSetName);
     for (int i = modelCount; --i >= 0;)
       n += models[i].getChainCount(false);
     sb.append("\nNumber of Chains .... " + n);
-    n = 0;
-    for (int i = modelCount; --i >= 0;)
-      n += models[i].getGroupCountHetero(false);
-    nHetero = 0;
-    for (int i = modelCount; --i >= 0;)
-      nHetero += models[i].getGroupCountHetero(true);
-    sb.append("\nNumber of Groups .... " + n);
-    if (nHetero > 0)
-      sb.append(" (" + nHetero + ")");
-    for (int i = ac; --i >= 0;)
-      if (atoms[i].isHetero())
-        nHetero++;
-    getChimeInfoM(sb, nHetero);
+    int ng = 0;
+    int ngHetero = 0;
+    int nHetero = 0;
+    Map<Group, Boolean> map = new Hashtable<Group, Boolean>();
     int nH = 0;
     int nS = 0;
     int nT = 0;
     int id;
     int lastid = -1;
-    for (int i = 0; i < ac; i++) {
-      if (atoms[i].mi != 0)
-        break;
-      if ((id = atoms[i].group.getStrucNo()) != lastid && id != 0) {
-        lastid = id;
-        switch (atoms[i].group.getProteinStructureType()) {
-        case HELIX:
-          nH++;
-          break;
-        case SHEET:
-          nS++;
-          break;
-        case TURN:
-          nT++;
-          break;
+    for (int i = ac; --i >= 0;) {
+      boolean isHetero = atoms[i].isHetero();
+      if (isHetero)
+        nHetero++;
+      Group g = atoms[i].group;
+      if (!map.containsKey(g)) {
+        map.put(g, Boolean.TRUE);
+        if (isHetero)
+          ngHetero++;
+        else
+          ng++;
+      }
+      if (atoms[i].mi == 0) {
+        if ((id = g.getStrucNo()) != lastid && id != 0) {
+          lastid = id;
+          switch (g.getProteinStructureType()) {
+          case HELIX:
+            nH++;
+            break;
+          case SHEET:
+            nS++;
+            break;
+          case TURN:
+            nT++;
+            break;
+          }
         }
       }
     }
+    sb.append("\nNumber of Groups .... " + ng);
+    if (ngHetero > 0)
+      sb.append(" (" + ngHetero + ")");
+    getChimeInfoM(sb, nHetero);
     sb.append("\nNumber of Helices ... " + nH);
     sb.append("\nNumber of Strands ... " + nS);
     sb.append("\nNumber of Turns ..... " + nT);
@@ -755,10 +783,8 @@
                                         int groupCount, int baseGroupIndex,
                                         BS modelsExcluded) {
     boolean checkConnections = !ms.vwr.getBoolean(T.pdbsequential);
-    if (groups == null) {
-      groups = ms.getGroups();
+    if (groupCount < 0)
       groupCount = groups.length;
-    }
     if (modelsExcluded != null)
       for (int j = 0; j < groupCount; ++j) {
         Group group = groups[j];

Modified: trunk/Jmol/src/org/jmol/modelsetbio/BioPolymer.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelsetbio/BioPolymer.java 2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/modelsetbio/BioPolymer.java 2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -164,8 +164,34 @@
 
   public void getConformation(BS bsConformation, int conformationIndex) {
     Atom[] atoms = model.getModelSet().at;
-    for (int i = monomerCount; --i >= 0;)
-      monomers[i].getConformation(atoms, bsConformation, conformationIndex);
+    for (int j = monomerCount; --j >= 0;) {
+      Monomer m = monomers[j];
+      //clear out bits that are not associated with the nth conformation
+      // counting for each residue from the beginning of the file listing
+
+      // A        A
+      // A        B
+      // A        A
+      // B  or    B
+      // B        A
+      // B        B
+
+      char ch = '\0';
+      for (int i = m.firstAtomIndex, n = m.lastAtomIndex; i <= n; i++) {
+        Atom atom = atoms[i];
+        char altloc = atom.altloc;
+        // ignore atoms that have no designation
+        if (altloc == '\0')
+          continue;
+        // count down until we get the desired index into the list
+        if (conformationIndex >= 0 && altloc != ch) {
+          ch = altloc;
+          conformationIndex--;
+        }
+        if (conformationIndex < 0 && altloc != ch)
+          bsConformation.clear(i);
+      }
+    }
     recalculateLeadMidpointsAndWingVectors();
   }
 

Modified: trunk/Jmol/src/org/jmol/modelsetbio/Monomer.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelsetbio/Monomer.java    2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/modelsetbio/Monomer.java    2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -78,11 +78,6 @@
 
   int monomerIndex;
 
-  @Override
-  public Group[] getGroups() {
-    return bioPolymer.monomers;
-  }
-  
   void setBioPolymer(BioPolymer polymer, int index) {
     this.bioPolymer = polymer;
     monomerIndex = index;
@@ -110,7 +105,7 @@
 
   @Override
   public int getAtomIndex(String name, int offset) {
-    Group[] groups = getGroups();
+    Group[] groups = bioPolymer.monomers;
     int ipt = monomerIndex + offset;
     if (ipt >= 0 && ipt < groups.length) {
       Group m = groups[ipt];
@@ -335,41 +330,6 @@
     return (structure instanceof ProteinStructure ? 
((ProteinStructure)structure).type.getBioStructureTypeName(false) : "");
   }
 
-  /**
-   * clear out bits that are not associated with the nth conformation
-   * counting for each residue from the beginning of the file listing
-   * 
-   * 
-   * @param atoms
-   * @param bsConformation
-   * @param conformationIndex   will be >= 0
-   */
-  void getConformation(Atom[] atoms, BS bsConformation, int conformationIndex) 
{
-
-    // A        A
-    // A        B
-    // A        A
-    // B  or    B
-    // B        A
-    // B        B
-    
-    char ch = '\0';
-    for (int i = firstAtomIndex; i <= lastAtomIndex; i++) {
-      Atom atom = atoms[i];
-      char altloc = atom.altloc;
-      // ignore atoms that have no designation
-      if (altloc == '\0')
-        continue;
-      // count down until we get the desired index into the list
-      if (conformationIndex >= 0 && altloc != ch) {
-        ch = altloc;
-        conformationIndex--;
-      }
-      if (conformationIndex < 0 && altloc != ch)
-        bsConformation.clear(i);
-    }
-  }
-
   final void updateOffsetsForAlternativeLocations(Atom[] atoms, BS bsSelected) 
{
       for (int offsetIndex = offsets.length; --offsetIndex >= 0;) {
         int offset = offsets[offsetIndex] & 0xFF;

Modified: trunk/Jmol/src/org/jmol/modelsetbio/Resolver.java
===================================================================
--- trunk/Jmol/src/org/jmol/modelsetbio/Resolver.java   2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/modelsetbio/Resolver.java   2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -41,6 +41,7 @@
 import org.jmol.modelset.ModelLoader;
 import org.jmol.modelset.ModelSet;
 import org.jmol.script.SV;
+import org.jmol.script.ScriptException;
 import org.jmol.script.T;
 import org.jmol.util.BSUtil;
 import org.jmol.util.Edge;
@@ -282,7 +283,7 @@
     for (int i = 0; i < nH; i++)
       ms.addAtom(a.mi, a.group, 1, "H", null, 0, a.getSeqID(), 0, xyz,
           Float.NaN, null, 0, 0, 1, 0, null, isHetero, (byte) 0, null)
-          .deleteBonds(null);
+          .delete(null);
   }
 
   private void getBondInfo(JmolAdapter adapter, String group3, Object model) {
@@ -539,7 +540,7 @@
           Atom atomO = bonds1[j].getOtherAtom(atom1);
           if (atomO.getElementNumber() == 8) {
             bsAddedHydrogens.set(atomH.i);
-            atomH.deleteBonds(bsBondsDeleted);
+            atomH.delete(bsBondsDeleted);
             break;
           }
         }
@@ -1733,6 +1734,88 @@
     return (groupID == -1 ? addGroup3Name(group3) : groupID);
   }
 
+  @Override
+  public boolean mutate(int iatom, String fileName) {
+    boolean b = vwr.getBoolean(T.appendnew);
+    Group g = vwr.ms.at[iatom].group;
+    //try {
+      // get the initial group -- protein for now
+      if (!(g instanceof AminoMonomer))
+        return false;
+      AminoMonomer res0 = (AminoMonomer) g;
+      int ac = vwr.ms.ac;
+      BS bsRes0 = new BS();
+      res0.selectAtoms(bsRes0);
+      int r = g.getResno();
+      // just use a script -- it is much easier!
+      
+      String script = "try{var atoms0 = {*}\n"
+          + "var res0 = " + BS.escape(bsRes0,'(',')')  + "\n"
+          + "set appendNew false\n"
+          + "load append \""+fileName+"\"\n"
+          + "set appendNew " + b + "\n"
+          + "var res1 = {!atoms0};var r1 = res1[1];var r0 = res1[0]\n"
+          + "if ({r1 & within(group, r0)}){" 
+          + "var haveHs = ({_H and connected(res0)} != 0)\n"
+          + "if (!haveHs) {delete _H and res1}\n"
+          + "var sm = '[*.N][*.CA][*.C][*.O]'\n"
+          + "var keyatoms = res1.find(sm)\n"
+          + "var x = compare(res1,res0,sm,'BONDS')\n"
+          + "if(x){\n"
+          + "rotate branch @x 1\n"
+          + "compare res1 res0 SMARTS @sm rotate translate 0\n"
+          + "var N2 = {*.N and !res0 && connected(res0)}\n"
+          + "var C0 = {*.C and !res0 && connected(res0)}\n"
+          + "delete res0\n"
+          + "if (N2) {\n"
+          + "delete *.OXT and res1\n"
+          + "connect {N2} {res1 & *.C}\n"
+          + "}\n"
+          + "if (C0) {\n"
+          + "connect {C0} {res1 & *.N}\n"
+          + "}\n"
+          + "}\n"
+          + "}}catch(e){print e}\n";
+      try {
+        vwr.eval.runScript(script);
+      } catch (ScriptException e) {
+        // TODO
+      }
+      if (vwr.ms.ac == ac)
+        return false;
+      // check for protein monomer
+      g = vwr.ms.at[vwr.ms.ac - 1].group;
+      if (g != vwr.ms.at[ac + 1].group || !(g instanceof AminoMonomer)) {
+        BS bsAtoms = new BS();
+        g.selectAtoms(bsAtoms);
+        vwr.deleteAtoms(bsAtoms, false);
+        return  false;
+      }
+      AminoMonomer res1 = (AminoMonomer) g;
+      
+      // must get new group into old chain
+      
+      Group[] groups = res0.chain.groups;
+      for (int i = groups.length; --i >= 0;)
+        if (groups[i] == res0) {
+          groups[i] = res1;
+          break;
+        }
+      res1.setResno(r);
+      res1.chain.groupCount = 0;
+      res1.chain = res0.chain;
+      BS bsExclude = BSUtil.newBitSet2(0, vwr.ms.mc);
+      bsExclude.clear(res1.chain.model.modelIndex);
+      res1.chain.model.groupCount = -1;
+      vwr.ms.recalculatePolymers(bsExclude);      
+    //} catch (Exception e) {
+     // System.out.println("" + e);
+   // }
+    vwr.setBooleanProperty("appendNew", b);
+    return true;
+
+  }
+
 }
 
 

Modified: trunk/Jmol/src/org/jmol/script/ScriptEval.java
===================================================================
--- trunk/Jmol/src/org/jmol/script/ScriptEval.java      2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/script/ScriptEval.java      2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -2518,6 +2518,7 @@
     case T.mapproperty:
     case T.minimize:
     case T.modulation:
+    case T.mutate:
     case T.data:
     case T.navigate:
     case T.plot:

Modified: trunk/Jmol/src/org/jmol/script/ScriptExpr.java
===================================================================
--- trunk/Jmol/src/org/jmol/script/ScriptExpr.java      2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/script/ScriptExpr.java      2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -1295,8 +1295,7 @@
         case T.opGT:
           return BSUtil.newBitSet2(ival + 1, ac);
         case T.opEQ:
-          return (ival < ac ? BSUtil.newBitSet2(
-              ival, ival + 1) : new BS());
+          return (ival < ac ? BSUtil.newBitSet2(ival, ival + 1) : new BS());
         case T.opNE:
         default:
           bs = BSUtil.setAll(ac);
@@ -1319,8 +1318,7 @@
       case T.subsystem:
       case T.configuration:
         // these are all-inclusive; no need to do a by-atom comparison
-        return BSUtil.copy(vwr.ms.getConformation(-1, ival - 1,
-            false));
+        return BSUtil.copy(vwr.ms.getConformation(-1, ival - 1, false, null));
       case T.symop:
         propertyBitSet = atom.atomSymmetry;
         if (propertyBitSet == null)
@@ -1360,8 +1358,7 @@
           }
           bitsetComparator = T.none;
           if (symop < 0)
-            ia = atom.getCellTranslation(ival, cellRange,
-                nOps);
+            ia = atom.getCellTranslation(ival, cellRange, nOps);
           else
             ia = atom.getSymmetryTranslation(symop, cellRange, nOps);
         } else if (nOps > 0) {
@@ -1370,8 +1367,7 @@
               continue;
           }
           if (bitsetComparator == T.opNE) {
-            if (ival > 0 && ival <= nOps
-                && !propertyBitSet.get(ival)) {
+            if (ival > 0 && ival <= nOps && !propertyBitSet.get(ival)) {
               bs.set(i);
             }
             continue;

Modified: trunk/Jmol/src/org/jmol/script/T.java
===================================================================
--- trunk/Jmol/src/org/jmol/script/T.java       2015-01-28 00:19:08 UTC (rev 
20250)
+++ trunk/Jmol/src/org/jmol/script/T.java       2015-01-28 16:16:02 UTC (rev 
20251)
@@ -334,8 +334,9 @@
 //public final static int model        see mathfunc
 //public final static int measure      see mathfunc
   public final static int move         = scriptCommand | 32;
-  public final static int moveto = scriptCommand | 34;
-  public final static int navigate = scriptCommand | 35;
+  public final static int moveto       = scriptCommand | 33;
+  public final static int mutate       = scriptCommand | 34;
+  public final static int navigate     = scriptCommand | 35;
 //public final static int quaternion   see mathfunc
   public final static int parallel     = flowCommand   | 36;
   public final static int plot         = scriptCommand | 37;
@@ -604,7 +605,7 @@
   public final static int molecule      = intproperty | 16;
   public final static int polymer       = intproperty | 17;
   public final static int polymerlength = intproperty | 18;
-  public final static int resno         = intproperty | 19;
+  public final static int resno         = intproperty | 19 | settable;
   public final static int seqid         = intproperty | 20;
   public final static int site          = intproperty | 21;
   public final static int strucno       = intproperty | 22;
@@ -1756,6 +1757,7 @@
         "modulation",
         "move",
         "moveTo",
+        "mutate",
         "navigate",
         "navigation",
         "nbo",
@@ -2779,6 +2781,7 @@
         modulation,                         // "modulation"
         move,                               // "move"
         moveto,                             // "moveTo"
+        mutate,                             // "mutate"
         navigate,                           // "navigate"
         -1,                                 // "navigation"
         nbo,                                // "nbo"

Modified: trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -158,6 +158,9 @@
     case T.modulation:
       modulation();
       break;
+    case T.mutate:
+      mutate();
+      break;
     case T.navigate:
       navigate();
       break;
@@ -934,22 +937,30 @@
   private void configuration() throws ScriptException {
     // if (!chk && vwr.getDisplayModelIndex() <= -2)
     // error(ERROR_backgroundModelError, "\"CONFIGURATION\"");
-    BS bsAtoms;
+    BS bsAtoms = null;
     BS bsSelected = vwr.bsA();
     if (slen == 1) {
+      // configuration
       bsAtoms = vwr.ms.setConformation(bsSelected);
-      vwr.ms.addStateScript("select", null, bsSelected, null,
-          "configuration", true, false);
-    } else {
-      int n = intParameter(e.checkLast(1));
+      vwr.ms.addStateScript("select", null, bsSelected, null, "configuration",
+          true, false);
       if (chk)
         return;
-      bsAtoms = vwr.ms.getConformation(vwr.am.cmi, n - 1,
-          true);
-      vwr.addStateScript("configuration " + n + ";", true, false);
+    } else {
+      int n;
+      if (isFloatParameter(1)) {
+        n = intParameter(e.checkLast(1));
+        if (chk)
+          return;
+        bsAtoms = vwr.ms.getConformation(vwr.am.cmi, n - 1, true, null);
+        vwr.addStateScript("configuration " + n + ";", true, false);
+      } else {
+        bsAtoms = atomExpressionAt(1);
+        n = intParameter(e.checkLast(e.iToken + 1));
+        vwr.addStateScript("configuration " + bsAtoms + " " + n + ";", true, 
false);
+        bsAtoms = vwr.ms.getConformation(vwr.am.cmi, n - 1, true, bsAtoms);
+      }
     }
-    if (chk)
-      return;
     setShapeProperty(JC.SHAPE_STICKS, "type",
         Integer.valueOf(Edge.BOND_HYDROGEN_MASK));
     e.setShapeSizeBs(JC.SHAPE_STICKS, 0, bsAtoms);
@@ -1567,7 +1578,7 @@
     }
   }
 
-  public void data() throws ScriptException {
+  private void data() throws ScriptException {
     ScriptEval eval = e;
     String dataString = null;
     String dataLabel = null;
@@ -2175,7 +2186,25 @@
     }
   }
 
-  public void navigate() throws ScriptException {
+  private void mutate() throws ScriptException {
+    // mutate {resno} "LYS" or "file identifier"
+    if (tokAt(1) == T.integer)
+      st[1] =T.o(T.string,  "" + st[1].value); // allows @x 
+    int iatom = atomExpressionAt(1).length() - 1;
+    
+    // check for last model 
+    if (iatom < 0 || vwr.ms.mc != vwr.ms.at[iatom].mi + 1)
+      return;
+    int i = ++e.iToken;
+    String group = e.optParameterAsString(e.checkLast(i));
+    if (chk)
+      return;
+    if (tokAt(i) != T.string)
+      group = "==" + group;
+    vwr.getJBR().mutate(iatom, group);
+  }
+
+  private void navigate() throws ScriptException {
     /*
      * navigation on/off navigation depth p # would be as a depth value, like
      * slab, in percent, but could be negative navigation nSec translate X Y #

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -12,13 +12,25 @@
 #  The quotes above     look odd for a parameter file, but they are 
 #  important for the JavaScript version of Jmol.
 
-TODO: design and implement sidechain mutation -- MUTATE command ?
 TODO: remove HTML5 dependency on synchronous file loading (check SCRIPT 
command for problems)
 TODO: add 2D graphics panel for Ramachandran and NBO-style 2D graphics -- send 
to browser as data uri?
 
+Jmol.___JmolVersion="14.3.12_2015.01.28"
 
-Jmol.___JmolVersion="14.3.12_2015.01.27"
+new feature: MUTATE command
+ -- replaces one amino acid group with another
+ -- can read from RCSB or from user-specified file
+ -- examples: 
+      mutate 33 lys          // uses last occurrence of resno=33
+      mutate @@3 arg         // replaces group of atom 3 in current model
+      mutate @r @g           // replaces resno in variable r with group in 
variable g
+      mutate {r} his         // same as above; r must be an atom selection
+      mutate 22 "myfile.cif" // user-defined replacement
+      
+new feature: resno is user settable
 
+JmolVersion="14.3.12_2015.01.27"
+
 bug fix: select thisModel does not select all atoms in visible frame set
 
 new feature: @@3 for "atomno=3 and thisModel"

Modified: trunk/Jmol/src/org/jmol/viewer/PropertyManager.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/PropertyManager.java 2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/viewer/PropertyManager.java 2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -41,6 +41,7 @@
 
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.Hashtable;
@@ -82,7 +83,7 @@
 
 
 @J2SIgnoreImport({ javajs.util.XmlUtil.class })
-public class PropertyManager implements JmolPropertyManager {
+public class PropertyManager implements JmolPropertyManager, 
Comparator<String> {
 
   public PropertyManager() {
     // required for reflection
@@ -1209,7 +1210,7 @@
       return getChimeInfoA(vwr.ms.at, tok, bs);
     }
     SB sb = new SB();
-    vwr.ms.am[0].getChimeInfo(sb, 0);
+    vwr.ms.am[0].getChimeInfo(sb);
     return sb.appendC('\n').toString().substring(1);
   }
 
@@ -1657,6 +1658,7 @@
     int iModel = atoms[bs.nextSetBit(0)].mi;
     int iModelLast = -1;
     boolean isPQR = "PQR".equals(out.getType());
+    boolean isBiomodel = false;
     String occTemp = "%6.2Q%6.2b          ";
     if (isPQR) {
       occTemp = "%8.4P%7.4V       ";
@@ -1675,21 +1677,23 @@
     int lastAtomIndex = bs.length() - 1;
     boolean showModels = (iModel != atoms[lastAtomIndex].mi);
     SB sbCONECT = (showModels ? null : new SB());
+    SB sbATOMS = new SB();
     boolean isMultipleBondPDB = models[iModel].isPdbWithMultipleBonds;
     LabelToken[] tokens;
     P3 ptTemp = new P3();
     for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
       Atom a = atoms[i];
+      isBiomodel = models[a.mi].isBioModel;
       if (showModels && a.mi != iModelLast) {
         if (iModelLast != -1)
           out.append("ENDMDL\n");
         iModelLast = a.mi;
         out.append("MODEL     " + (iModelLast + 1) + "\n");
+        sbATOMS = new SB();
       }
       String sa = a.getAtomName();
       boolean leftJustify = (a.getElementSymbol().length() == 2
           || sa.length() >= 4 || PT.isDigit(sa.charAt(0)));
-      boolean isBiomodel = models[a.mi].isBioModel;
       boolean isHetero = a.isHetero();
       if (!isBiomodel)
         tokens = (leftJustify ? LabelToken.compile(vwr,
@@ -1713,38 +1717,52 @@
             "ATOM  %5.-5i  %-3.3a%1A%3.-3n %1c%4.-4R%1E   %8.3x%8.3y%8.3z"
                 + occTemp, '\0', null));
       String XX = a.getElementSymbolIso(false).toUpperCase();
-      out.append(LabelToken.formatLabelAtomArray(vwr, a, tokens, '\0', null, 
ptTemp))
+      sbATOMS
+          .append(
+              LabelToken.formatLabelAtomArray(vwr, a, tokens, '\0', null,
+                  ptTemp))
           .append(XX.length() == 1 ? " " + XX : XX.substring(0, 2))
           .append("  \n");
-      if (!showModels && (!isBiomodel || isHetero || isMultipleBondPDB)) {
-        Bond[] bonds = a.bonds;
-        if (bonds != null)
-          for (int j = 0; j < bonds.length; j++) {
-            int iThis = a.getAtomNumber();
-            Atom a2 = bonds[j].getOtherAtom(a);
-            if (!bs.get(a2.i))
-              continue;
-            int n = bonds[j].getCovalentOrder();
-            if (n == 1 && isMultipleBondPDB && !isHetero)
-              continue;
-            int iOther = a2.getAtomNumber();
-            switch (n) {
-            case 2:
-            case 3:
-              if (iOther < iThis)
-                continue; // only one entry in this case -- pseudo-PDB style
-              //$FALL-THROUGH$
-            case 1:
-              sbCONECT.append("CONECT").append(
-                  PT.formatStringI("%5i", "i", iThis));
-              for (int k = 0; k < n; k++)
-                sbCONECT.append(PT.formatStringI("%5i", "i", iOther));
-              sbCONECT.appendC('\n');
-              break;
+    }
+    boolean doConnect = (!showModels && isBiomodel);
+    Map<Integer, Integer> map = (doConnect ? new Hashtable<Integer, Integer>() 
: null);
+    String sAtoms = fixPDBFormat(sbATOMS.toString(), map);
+    if (doConnect) {
+      for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
+        Atom a = atoms[i];
+        boolean isHetero = a.isHetero();
+        if (isHetero || isMultipleBondPDB) {
+          Bond[] bonds = a.bonds;
+          if (bonds != null)
+            for (int j = 0; j < bonds.length; j++) {
+              int iThis = a.getAtomNumber();
+              Atom a2 = bonds[j].getOtherAtom(a);
+              if (!bs.get(a2.i))
+                continue;
+              int n = bonds[j].getCovalentOrder();
+              if (n == 1 && isMultipleBondPDB && !isHetero)
+                continue;
+              int iOther = a2.getAtomNumber();
+              switch (n) {
+              case 2:
+              case 3:
+                if (iOther < iThis)
+                  continue; // only one entry in this case -- pseudo-PDB style
+                //$FALL-THROUGH$
+              case 1:
+                sbCONECT.append("CONECT").append(
+                    PT.formatStringI("%5i", "i", 
map.get(Integer.valueOf(iThis)).intValue()));
+                String s = PT.formatStringI("%5i", "i", 
map.get(Integer.valueOf(iOther)).intValue());
+                for (int k = 0; k < n; k++)
+                  sbCONECT.append(s);
+                sbCONECT.appendC('\n');
+                break;
+              }
             }
-          }
+        }
       }
     }
+    out.append(sAtoms);
     if (showModels)
       out.append("ENDMDL\n");
     else
@@ -1752,6 +1770,38 @@
     return out.toString();
   }
 
+  /**
+   * must re-order by resno and then renumber atoms
+   * @param s
+   * @param map 
+   * @return fixed string
+   */
+  private String fixPDBFormat(String s, Map<Integer, Integer> map) {
+    String[] lines = PT.split(s, "\n");
+    Arrays.sort(lines, this);
+      SB sb = new SB();
+      for (int i = 0; i < lines.length; i++) {
+        s = lines[i];
+        int p = PT.parseInt(lines[i].substring(6, 12));
+        if (map != null)
+          map.put(Integer.valueOf(p), Integer.valueOf(i));
+        String si = "     " + (i + 1);
+        sb.append(s.substring(0, 6))
+        .append(si.substring(si.length() - 5))
+        .append(s.substring(11)).append("\n");
+      }
+    return sb.toString();
+  }
+
+  @Override
+  public int compare(String s1, String s2) {
+    int atA = PT.parseInt(s1.substring(6, 12));
+    int atB = PT.parseInt(s2.substring(6, 12));
+    int resA = PT.parseInt(s1.substring(22, 26));
+    int resB = PT.parseInt(s2.substring(22, 26));
+    return (resA < resB ? -1 : resA > resB ? 1 : atA < atB ? -1
+        : atA > atB ? 1 : 0);
+  }
   /* **********************
    * 
    * Jmol Data Frame methods
@@ -1941,4 +1991,35 @@
     return sb.toString();
   }
 
+  @Override
+  public String getCoordinateFileData(String atomExpression, String type) {
+    String exp = "";
+    if (type.equalsIgnoreCase("MOL") || type.equalsIgnoreCase("SDF")
+        || type.equalsIgnoreCase("V2000") || type.equalsIgnoreCase("V3000")
+        || type.equalsIgnoreCase("XYZVIB") || type.equalsIgnoreCase("CD") || 
type.equalsIgnoreCase("JSON"))
+      return vwr.getModelExtract(atomExpression, false, false, type);
+    if (type.toLowerCase().indexOf("property_") == 0)
+      exp = "{selected}.label(\"%{" + type + "}\")";
+    else if (type.equalsIgnoreCase("CML"))
+      return getModelCml(vwr.getAtomBitSet(atomExpression), Integer.MAX_VALUE, 
true);
+    else if (type.equalsIgnoreCase("PDB"))
+      // very crude - no connections -- not used
+      exp = "{selected and not hetero}.label(\"ATOM  %5i %-4a%1A%3.3n 
%1c%4R%1E   %8.3x%8.3y%8.3z%6.2Q%6.2b          %2e  \").lines"
+             + "+{selected and hetero}.label(\"HETATM%5i %-4a%1A%3.3n 
%1c%4R%1E   %8.3x%8.3y%8.3z%6.2Q%6.2b          %2e  \").lines";
+    else if (type.equalsIgnoreCase("XYZRN"))
+      exp = "\"\" + {selected}.size + \"\n\n\"+{selected}.label(\"%-2e %8.3x 
%8.3y %8.3z %4.2[vdw] 1 [%n]%r.%a#%i\").lines";
+    else if (type.startsWith("USER:"))
+      exp = "{selected}.label(\"" + type.substring(5) + "\").lines";
+    else
+      // if(type.equals("XYZ"))
+      exp = "\"\" + {selected}.size + \"\n\n\"+{selected}.label(\"%-2e %10.5x 
%10.5y %10.5z\").lines";
+    if (!atomExpression.equals("selected"))
+      exp = PT.rep(exp, "selected", atomExpression);
+    String s = (String) vwr.evaluateExpression(exp);
+    if (type.equalsIgnoreCase("PDB"))
+      s = fixPDBFormat(s, null);
+    return s;
+  }
+
+
 }

Modified: trunk/Jmol/src/org/jmol/viewer/StateCreator.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/StateCreator.java    2015-01-28 00:19:08 UTC 
(rev 20250)
+++ trunk/Jmol/src/org/jmol/viewer/StateCreator.java    2015-01-28 16:16:02 UTC 
(rev 20251)
@@ -1539,6 +1539,8 @@
     BS[] tainted = vwr.ms.tainted;
     if (bs != null)
       for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
+        if (atoms[i].isDeleted())
+          continue;
         s.appendI(i + 1).append(" ").append(atoms[i].getElementSymbol())
             .append(" ").append(atoms[i].getInfo().replace(' ', '_')).append(
                 " ");
@@ -1551,6 +1553,9 @@
         case AtomCollection.TAINT_ATOMNO:
           s.appendI(atoms[i].getAtomNumber());
           break;
+        case AtomCollection.TAINT_RESNO:
+          s.appendI(atoms[i].group.getResno());
+          break;
         case AtomCollection.TAINT_SEQID:
           s.appendI(atoms[i].getSeqID());
           break;

Modified: trunk/Jmol/src/org/jmol/viewer/Viewer.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Viewer.java  2015-01-28 00:19:08 UTC (rev 
20250)
+++ trunk/Jmol/src/org/jmol/viewer/Viewer.java  2015-01-28 16:16:02 UTC (rev 
20251)
@@ -7166,29 +7166,7 @@
 
   @Override
   public String getData(String atomExpression, String type) {
-    String exp = "";
-    if (type.equalsIgnoreCase("MOL") || type.equalsIgnoreCase("SDF")
-        || type.equalsIgnoreCase("V2000") || type.equalsIgnoreCase("V3000")
-        || type.equalsIgnoreCase("XYZVIB") || type.equalsIgnoreCase("CD") || 
type.equalsIgnoreCase("JSON"))
-      return getModelExtract(atomExpression, false, false, type);
-    if (type.toLowerCase().indexOf("property_") == 0)
-      exp = "{selected}.label(\"%{" + type + "}\")";
-    else if (type.equalsIgnoreCase("CML"))
-      return getModelCml(getAtomBitSet(atomExpression), Integer.MAX_VALUE, 
true);
-    else if (type.equalsIgnoreCase("PDB"))
-      // old crude
-      exp = "{selected and not hetero}.label(\"ATOM  %5i %-4a%1A%3.3n 
%1c%4R%1E   %8.3x%8.3y%8.3z%6.2Q%6.2b          %2e  \").lines"
-          + "+{selected and hetero}.label(\"HETATM%5i %-4a%1A%3.3n %1c%4R%1E   
%8.3x%8.3y%8.3z%6.2Q%6.2b          %2e  \").lines";
-    else if (type.equalsIgnoreCase("XYZRN"))
-      exp = "\"\" + {selected}.size + \"\n\n\"+{selected}.label(\"%-2e %8.3x 
%8.3y %8.3z %4.2[vdw] 1 [%n]%r.%a#%i\").lines";
-    else if (type.startsWith("USER:"))
-      exp = "{selected}.label(\"" + type.substring(5) + "\").lines";
-    else
-      // if(type.equals("XYZ"))
-      exp = "\"\" + {selected}.size + \"\n\n\"+{selected}.label(\"%-2e %10.5x 
%10.5y %10.5z\").lines";
-    if (!atomExpression.equals("selected"))
-      exp = PT.rep(exp, "selected", atomExpression);
-    return (String) evaluateExpression(exp);
+    return getPropertyManager().getCoordinateFileData(atomExpression, type);
   }
 
   public String getModelCml(BS bs, int nAtomsMax, boolean addBonds) {

Modified: trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/NBODialog.java
===================================================================
--- trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/NBODialog.java    
2015-01-28 00:19:08 UTC (rev 20250)
+++ trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/NBODialog.java    
2015-01-28 16:16:02 UTC (rev 20251)
@@ -326,7 +326,11 @@
 
   public void nboReport(String s) {
     nboOutput.setText(s == null ? "" : nboOutput.getText() + s + "\n");
-    editPane2.getVerticalScrollBar().setValue(Integer.MAX_VALUE);
+    try {
+      editPane2.getVerticalScrollBar().setValue(Integer.MAX_VALUE);
+    } catch (Exception e) {
+      //
+    }
   }
 
   protected void modelCmd() {

Modified: 
trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java
===================================================================
--- trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java   
2015-01-28 00:19:08 UTC (rev 20250)
+++ trunk/Jmol/src/org/openscience/jmol/app/jmolpanel/console/AppConsole.java   
2015-01-28 16:16:02 UTC (rev 20251)
@@ -877,7 +877,12 @@
 
         pt = caretPosition.getOffset();
         consoleTextPane.setCaretPosition(pt);
-        vBar.setValue(Integer.MAX_VALUE);
+        try {
+          vBar.setValue(Integer.MAX_VALUE);
+        } catch (Exception e) {
+          //
+        }
+        
       } catch (Exception e) {
         e.printStackTrace();
         consoleTextPane.setCaretPosition(getLength());

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Jmol-commits mailing list
Jmol-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jmol-commits

Reply via email to