Add pdbname selection keyword.
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 24 Sep 2012 04:48:01 +0000 (07:48 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Mon, 24 Sep 2012 15:47:56 +0000 (18:47 +0300)
As a supporting change, remove trailing space from t_pdbinfo.atomnm, as
the trailing whitespace does not seem to be used anywhere.
This makes it possible to use it easily in the selection code.

Fixes #1007 in master, will backport to 4.5 branch separately.

Change-Id: Iac36bda8a84d0a6c131445e7f47ad91d7209fb10

src/gromacs/gmxlib/pdbio.c
src/gromacs/legacyheaders/types/atoms.h
src/gromacs/selection/selhelp.cpp
src/gromacs/selection/selmethod.cpp
src/gromacs/selection/sm_simple.cpp
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPdbAtomname.xml [new file with mode: 0644]
src/gromacs/selection/tests/selectioncollection.cpp
src/gromacs/selection/tests/simple.pdb

index 0c2689dd6ae233a49e0904f06713f8eefdeea465..9537383434d27c32842645004e2e9f06af3f2873 100644 (file)
@@ -503,6 +503,7 @@ static int read_atom(t_symtab *symtab,
   for(k=0; (k<4); k++,j++) anm[k]=line[j];
   anm[k]=nc;
   strcpy(anm_copy,anm);
+  rtrim(anm_copy);
   atomnumber = NOTSET;
   trim(anm);
   altloc=line[j];
index ea31d9db53e6f579197922b1b06776bbafe5983d..ce5eb7d80ebd5f82ac65855cd8e3b16df1f2757a 100644 (file)
@@ -71,7 +71,7 @@ typedef struct {
   int  type;                    /* PDB record name                      */
   int  atomnr;                  /* PDB atom number                      */
   char altloc;                  /* Alternate location indicator         */
-  char atomnm[6];               /* True atom name including spaces      */
+  char atomnm[6];               /* True atom name including leading spaces */
   real occup;                   /* Occupancy                            */
   real bfac;                    /* B-factor                             */
   gmx_bool bAnisotropic;        /* (an)isotropic switch                 */
index 96cffea7ca4d25828cf9a0331e9fc2e495d67d55..f5f6826284b0fa0794ab92ffb06040ee23d5d47c 100644 (file)
@@ -282,7 +282,14 @@ const char *const LimitationsHelpText::text[] = {
     "[TT]charge -1 to -0.7[tt][BR]",
     "result in a syntax error. A workaround is to write[BR]",
     "[TT]charge {-1 to -0.7}[tt][BR]",
-    "instead.",
+    "instead.[PAR]",
+
+    "When [TT]name[tt] selection keyword is used together with PDB input",
+    "files, the behavior may be unintuitive. When Gromacs reads in a PDB",
+    "file, 4 character atom names that start with a digit are transformed",
+    "such that, e.g., 1HG2 becomes HG21, and the latter is what is matched",
+    "by the [TT]name[tt] keyword. Use [TT]pdbname[tt] to match the atom name",
+    "as it appears in the input PDB file.",
 };
 
 struct PositionsHelpText
@@ -430,14 +437,15 @@ class KeywordDetailsHelpTopic : public AbstractSimpleHelpTopic
 {
     public:
         //! Initialize help topic for the given selection method.
-        explicit KeywordDetailsHelpTopic(const gmx_ana_selmethod_t &method)
-            : method_(method)
+        KeywordDetailsHelpTopic(const std::string &name,
+                                const gmx_ana_selmethod_t &method)
+            : name_(name), method_(method)
         {
         }
 
         virtual const char *name() const
         {
-            return method_.name;
+            return name_.c_str();
         }
         virtual const char *title() const
         {
@@ -451,6 +459,7 @@ class KeywordDetailsHelpTopic : public AbstractSimpleHelpTopic
         }
 
     private:
+        std::string                name_;
         const gmx_ana_selmethod_t &method_;
 
         GMX_DISALLOW_COPY_AND_ASSIGN(KeywordDetailsHelpTopic);
@@ -514,7 +523,8 @@ KeywordsHelpTopic::KeywordsHelpTopic()
         methods_.push_back(std::make_pair(std::string(symname), method));
         if (method->help.nlhelp > 0 && method->help.help != NULL)
         {
-            addSubTopic(HelpTopicPointer(new KeywordDetailsHelpTopic(*method)));
+            addSubTopic(HelpTopicPointer(
+                        new KeywordDetailsHelpTopic(symname, *method)));
         }
         ++symbol;
     }
index 8f351e1df523481321a4b8be4a25cca639b73049..529c13db7dc9e01f5fd41e39b3ec25ca5989566c 100644 (file)
@@ -80,6 +80,7 @@ extern gmx_ana_selmethod_t sm_resnr;
 extern gmx_ana_selmethod_t sm_resindex;
 extern gmx_ana_selmethod_t sm_molindex;
 extern gmx_ana_selmethod_t sm_atomname;
+extern gmx_ana_selmethod_t sm_pdbatomname;
 extern gmx_ana_selmethod_t sm_atomtype;
 extern gmx_ana_selmethod_t sm_resname;
 extern gmx_ana_selmethod_t sm_insertcode;
@@ -139,6 +140,8 @@ static const t_register_method smtable_def[] = {
     {"molecule",   &sm_molindex},
     {NULL,         &sm_atomname},
     {"name",       &sm_atomname},
+    {NULL,         &sm_pdbatomname},
+    {"pdbname",    &sm_pdbatomname},
     {NULL,         &sm_atomtype},
     {"type",       &sm_atomtype},
     {NULL,         &sm_resname},
index 1c52cb030eee09975cb1bebb26685bbb872c18f1..d30003082a872a14211c746c8ddb77aa45038aa5 100644 (file)
 #include <config.h>
 #endif
 
+#include <cctype>
+
+#include "gromacs/legacyheaders/macros.h"
+
 #include "gromacs/selection/position.h"
 #include "gromacs/selection/selmethod.h"
 #include "gromacs/utility/exceptions.h"
@@ -74,6 +78,10 @@ evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
 static void
 evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p pdbatomname selection keyword. */
+static void
+evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Checks whether atom types are present in the topology. */
 static void
 check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
@@ -130,6 +138,26 @@ static void
 evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 
+/** Help text for atom name selection keywords. */
+static const char *help_atomname[] = {
+    "ATOM NAME SELECTION KEYWORDS[PAR]",
+
+    "[TT]name[tt] [TT]pdbname[tt] [TT]atomname[tt] [TT]pdbatomname[tt][PAR]",
+
+    "These keywords select atoms by name. [TT]name[tt] selects atoms using",
+    "the Gromacs atom naming convention.",
+    "For input formats other than PDB, the atom names are matched exactly",
+    "as they appear in the input file. For PDB files, 4 character atom names",
+    "that start with a digit are matched after moving the digit to the end",
+    "(e.g., to match 3HG2 from a PDB file, use [TT]name HG23[tt]).",
+    "[TT]pdbname[tt] can only be used with a PDB input file, and selects",
+    "atoms based on the exact name given in the input file, without the",
+    "transformation described above.[PAR]",
+
+    "[TT]atomname[tt] and [TT]pdbatomname[tt] are synonyms for the above two",
+    "keywords."
+};
+
 /** \internal Selection method data for \p all selection keyword. */
 gmx_ana_selmethod_t sm_all = {
     "all", GROUP_VALUE, 0,
@@ -226,6 +254,22 @@ gmx_ana_selmethod_t sm_atomname = {
     NULL,
     &evaluate_atomname,
     NULL,
+    {NULL, asize(help_atomname), help_atomname}
+};
+
+/** \internal Selection method data for \p pdbatomname selection keyword. */
+gmx_ana_selmethod_t sm_pdbatomname = {
+    "pdbatomname", STR_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    &check_pdbinfo,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_pdbatomname,
+    NULL,
+    {NULL, asize(help_atomname), help_atomname}
 };
 
 /** \internal Selection method data for \p atomtype selection keyword. */
@@ -541,6 +585,30 @@ evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
     }
 }
 
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the PDB atom name for each atom in \p out->u.s.
+ */
+static void
+evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        char *s = top->atoms.pdbinfo[g->index[i]].atomnm;
+        while (std::isspace(*s))
+        {
+            ++s;
+        }
+        out->u.s[i] = s;
+    }
+}
+
 /*!
  * \param[in] top  Topology structure.
  * \param     npar Not used.
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPdbAtomname.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPdbAtomname.xml
new file mode 100644 (file)
index 0000000..8bfe632
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">name HG21</String>
+      <String Name="Name">name HG21</String>
+      <String Name="Text">name HG21</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">name 1HG2</String>
+      <String Name="Name">name 1HG2</String>
+      <String Name="Text">name 1HG2</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">pdbname HG21 CB</String>
+      <String Name="Name">pdbname HG21 CB</String>
+      <String Name="Text">pdbname HG21 CB</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection4">
+      <String Name="Input">pdbatomname 1HG2</String>
+      <String Name="Name">pdbatomname 1HG2</String>
+      <String Name="Text">pdbatomname 1HG2</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>4</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">0</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <Sequence Name="Atoms">
+        <Int Name="Length">7</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>9</Int>
+        <Int>12</Int>
+        <Int>15</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
index 6452971dae6d4672f718ba6b218138eabfcb9b7d..a28502ef5f84872999856f3b63676a629251b7ff 100644 (file)
@@ -523,6 +523,18 @@ TEST_F(SelectionCollectionDataTest, HandlesAtomname)
     runTest("simple.gro", selections);
 }
 
+TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
+{
+    static const char * const selections[] = {
+        "name HG21",
+        "name 1HG2",
+        "pdbname HG21 CB",
+        "pdbatomname 1HG2",
+        NULL
+    };
+    runTest("simple.pdb", selections);
+}
+
 // TODO: Add test for atomtype
 
 TEST_F(SelectionCollectionDataTest, HandlesChain)
index 7de15fc156349799b82af28f363325ea1d083292..04c005ed38aeb0a0d496d3fe24f550863bfab102 100644 (file)
@@ -5,11 +5,11 @@ ATOM      1  CB   RA A   1      10.000  10.000   0.000  1.00  0.00
 ATOM      2  S1   RA A   1      10.000  20.000   0.000  1.00  0.00            
 ATOM      3  S2   RA A   1      10.000  30.000   0.000  1.00  0.00            
 ATOM      4  CB   RB A   2      10.000  40.000   0.000  1.00  0.50            
-ATOM      5  S1   RB A   2      20.000  10.000   0.000  1.00  0.50            
-ATOM      6  S2   RB A   2      20.000  20.000   0.000  1.00  0.50            
+ATOM      5 1HG2  RB A   2      20.000  10.000   0.000  1.00  0.50            
+ATOM      6 2HG2  RB A   2      20.000  20.000   0.000  1.00  0.50            
 ATOM      7  CB   RA B   1      20.000  30.000   0.000  1.00  0.00            
-ATOM      8  S1   RA B   1      20.000  40.000   0.000  1.00  0.30            
-ATOM      9  S2   RA B   1      30.000  10.000   0.000  1.00  0.30            
+ATOM      8 HG21  RA B   1      20.000  40.000   0.000  1.00  0.30            
+ATOM      9 HG22  RA B   1      30.000  10.000   0.000  1.00  0.30            
 ATOM     10  CB   RC B   1A     30.000  20.000   0.000  1.00  0.00            
 ATOM     11  S1   RC B   1A     30.000  30.000   0.000  1.00  0.00            
 ATOM     12  S2   RC B   1A     30.000  40.000   0.000  1.00  0.30