JAL-2296 parse Chimera atomspec to AtomSpec
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 14 Nov 2016 12:29:24 +0000 (12:29 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 14 Nov 2016 12:29:24 +0000 (12:29 +0000)
src/jalview/structure/AtomSpec.java
test/jalview/structure/AtomSpecTest.java [new file with mode: 0644]

index 271bf1d..f20cd31 100644 (file)
@@ -29,6 +29,8 @@ package jalview.structure;
  */
 public class AtomSpec
 {
+  int modelNo;
+
   private String pdbFile;
 
   private String chain;
@@ -38,6 +40,60 @@ public class AtomSpec
   private int atomIndex;
 
   /**
+   * Parses a Chimera atomspec e.g. #1:12.A to construct an AtomSpec model (with
+   * null pdb file name)
+   * 
+   * @param spec
+   * @return
+   * @throw IllegalArgumentException if the spec cannot be parsed, or represents
+   *        more than one residue
+   */
+  public static AtomSpec fromChimeraAtomspec(String spec)
+  {
+    int colonPos = spec.indexOf(":");
+    if (colonPos == -1)
+    {
+      throw new IllegalArgumentException(spec);
+    }
+
+    int hashPos = spec.indexOf("#");
+    if (hashPos == -1 && colonPos != 0)
+    {
+      // # is missing but something precedes : - reject
+      throw new IllegalArgumentException(spec);
+    }
+
+    String modelSubmodel = spec.substring(hashPos + 1, colonPos);
+    int dotPos = modelSubmodel.indexOf(".");
+    int modelId = 0;
+    try
+    {
+      modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
+              : modelSubmodel.substring(0, dotPos));
+    } catch (NumberFormatException e)
+    {
+      // ignore, default to model 0
+    }
+
+    String residueChain = spec.substring(colonPos + 1);
+    dotPos = residueChain.indexOf(".");
+    int resNum = 0;
+    try
+    {
+      resNum = Integer.parseInt(dotPos == -1 ? residueChain
+              : residueChain.substring(0, dotPos));
+    } catch (NumberFormatException e)
+    {
+      // could be a range e.g. #1:4-7.B
+      throw new IllegalArgumentException(spec);
+    }
+
+    String chainId = dotPos == -1 ? "" : residueChain.substring(dotPos + 1);
+
+    return new AtomSpec(modelId, chainId, resNum, 0);
+  }
+
+  /**
    * Constructor
    * 
    * @param pdbFile
@@ -53,6 +109,22 @@ public class AtomSpec
     this.atomIndex = atomNo;
   }
 
+  /**
+   * Constructor
+   * 
+   * @param modelId
+   * @param chainId
+   * @param resNo
+   * @param atomNo
+   */
+  public AtomSpec(int modelId, String chainId, int resNo, int atomNo)
+  {
+    this.modelNo = modelId;
+    this.chain = chainId;
+    this.pdbResNum = resNo;
+    this.atomIndex = atomNo;
+  }
+
   public String getPdbFile()
   {
     return pdbFile;
@@ -73,6 +145,16 @@ public class AtomSpec
     return atomIndex;
   }
 
+  public int getModelNumber()
+  {
+    return modelNo;
+  }
+
+  public void setPdbFile(String file)
+  {
+    pdbFile = file;
+  }
+
   @Override
   public String toString()
   {
diff --git a/test/jalview/structure/AtomSpecTest.java b/test/jalview/structure/AtomSpecTest.java
new file mode 100644 (file)
index 0000000..ea53131
--- /dev/null
@@ -0,0 +1,74 @@
+package jalview.structure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.Test;
+
+public class AtomSpecTest
+{
+  @Test
+  public void testFromChimeraAtomSpec()
+  {
+    AtomSpec as = AtomSpec.fromChimeraAtomspec("#1:12.B");
+    assertEquals(as.getModelNumber(), 1);
+    assertEquals(as.getPdbResNum(), 12);
+    assertEquals(as.getChain(), "B");
+    assertNull(as.getPdbFile());
+
+    // no model - default to zero
+    as = AtomSpec.fromChimeraAtomspec(":13.C");
+    assertEquals(as.getModelNumber(), 0);
+    assertEquals(as.getPdbResNum(), 13);
+    assertEquals(as.getChain(), "C");
+    assertNull(as.getPdbFile());
+
+    // model.submodel
+    as = AtomSpec.fromChimeraAtomspec("#3.2:15");
+    assertEquals(as.getModelNumber(), 3);
+    assertEquals(as.getPdbResNum(), 15);
+    assertEquals(as.getChain(), "");
+    assertNull(as.getPdbFile());
+
+    String spec = "3:12.B";
+    try
+    {
+      as = AtomSpec.fromChimeraAtomspec(spec);
+      fail("Expected exception for " + spec);
+    } catch (IllegalArgumentException e)
+    {
+      // ok
+    }
+
+    spec = "#3:12-14.B";
+    try
+    {
+      as = AtomSpec.fromChimeraAtomspec(spec);
+      fail("Expected exception for " + spec);
+    } catch (IllegalArgumentException e)
+    {
+      // ok
+    }
+
+    spec = "";
+    try
+    {
+      as = AtomSpec.fromChimeraAtomspec(spec);
+      fail("Expected exception for " + spec);
+    } catch (IllegalArgumentException e)
+    {
+      // ok
+    }
+
+    spec = null;
+    try
+    {
+      as = AtomSpec.fromChimeraAtomspec(spec);
+      fail("Expected exception for " + spec);
+    } catch (NullPointerException e)
+    {
+      // ok
+    }
+  }
+}