Relax requirement for bonded atom type names
authorEliane Briand <eliane.briand@mpibpc.mpg.de>
Wed, 29 Sep 2021 18:20:22 +0000 (18:20 +0000)
committerBerk Hess <hess@kth.se>
Wed, 29 Sep 2021 18:20:22 +0000 (18:20 +0000)
docs/reference-manual/topologies/topology-file-formats.rst
docs/release-notes/2022/major/miscellaneous.rst
src/gromacs/gmxpreprocess/tests/CMakeLists.txt
src/gromacs/gmxpreprocess/tests/directives.gro [new file with mode: 0644]
src/gromacs/gmxpreprocess/tests/directives.top [new file with mode: 0644]
src/gromacs/gmxpreprocess/tests/grompp_directives.cpp [new file with mode: 0644]
src/gromacs/gmxpreprocess/toppush.cpp

index 506a1dcca15f2aec423b4aec6b0e47d7c7b23208..6f8443aca5e184cea892c13ce14a576fb82aa7a7 100644 (file)
@@ -340,6 +340,8 @@ Description of the file layout:
 
 -  Atoms in the same charge group must be listed consecutively
 
+-  Bonded atom type name must contain at least one non-digit character.
+
 -  The file is parsed only once, which implies that no forward
    references can be treated: items must be defined before they can be
    used
index 1f050b2921ffff921008ad6211431a2c8d7885ce..65329895564771a67c88c1774a246463ab60d904 100644 (file)
@@ -13,3 +13,11 @@ grompp no longer modifies nstcomm
 grompp will no longer set nstcomm, the interval for center of mass motion
 removal, equal to nstcalcenergy when nstcomm < nstcalcenergy.
 A note is still printed in that case.
+
+Bonded atom types names can now start with a digit
+""""""""""""""""""""""""""""""""""""""""""""""""""
+
+Bonded atom types names in topologies were not allowed to start with a number.
+Now all names are supported that contain at least one non-digit character.
+
+:issue:`4120`
index 677aaa6ed64edcf6a6106601c3840e72d15fe2d6..5db15f0859fa3981ab97ba2431753b14370e9866 100644 (file)
@@ -40,6 +40,7 @@ gmx_add_gtest_executable(gmxpreprocess-test
         genrestr.cpp
         gpp_atomtype.cpp
         gpp_bond_atomtype.cpp
+        grompp_directives.cpp
         insert_molecules.cpp
         readir.cpp
         solvate.cpp
diff --git a/src/gromacs/gmxpreprocess/tests/directives.gro b/src/gromacs/gmxpreprocess/tests/directives.gro
new file mode 100644 (file)
index 0000000..ab05d7c
--- /dev/null
@@ -0,0 +1,7 @@
+UNNAMED
+   4
+    1  A    N    1   0.305   0.792  -0.052
+    2  A    C    1   1.305   0.792  -0.052
+    3  A    O    1   2.305   0.792  -0.052
+    4  A    S    1   3.305   0.792  -0.052
+   5.25681   5.26870   5.05080
diff --git a/src/gromacs/gmxpreprocess/tests/directives.top b/src/gromacs/gmxpreprocess/tests/directives.top
new file mode 100644 (file)
index 0000000..e1ceed8
--- /dev/null
@@ -0,0 +1,44 @@
+; Minimal topology file to test edge-cases for directive parsing
+
+[ defaults ]
+; nbfunc        comb-rule       gen-pairs       fudgeLJ fudgeQQ
+1               2               yes             0.5     0.8333
+
+
+[ atomtypes ] 
+; Cover all combinations of optional [bname] [at.num]
+; name  bname     at.num  mass  charge ptype  sigma      epsilon
+2C_     2Cbonded          12.01 0.0000 A     0.339967 0.45773 
+_       _bonded     6     12.01 0.0000 A     0.349967 0.45773 
+4_                  7     12.01 0.0000 A     0.359967 0.45773 
+5_                        12.01 0.0000 A     0.369967 0.45773 
+
+[ bondtypes ]
+;   i         j          func       b0          kb
+2Cbonded _bonded         1    0.10900   284512.0
+
+
+[ moleculetype ]
+; Name            nrexcl
+A                    0
+
+[ atoms ]
+;   nr       type  resnr residue  atom   cgnr     charge       mass  typeB    chargeB      massB
+     1         2C_      1    RES    N      1         0.0      14.01
+     2           _      1    RES    C      2         0.0      14.01
+     3          4_      1    RES    O      2         0.0      14.01
+     4          5_      1    RES    S      2         0.0      14.01
+
+[ bonds ]
+;  ai    aj funct            c0            c1            c2            c3
+; Bond without values: will result in "No default Bond types" if bonded name were not parsed
+    1     2     1 
+
+[ system ]
+; Name
+minimal edge case system
+
+[ molecules ]
+; Compound  #mols
+A         1
diff --git a/src/gromacs/gmxpreprocess/tests/grompp_directives.cpp b/src/gromacs/gmxpreprocess/tests/grompp_directives.cpp
new file mode 100644 (file)
index 0000000..877033a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021 by the GROMACS development team.
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for grompp directives parsing
+ *
+ * \author Eliane Briand <eliane@br.iand.fr>
+ */
+
+#include "gmxpre.h"
+
+#include "gromacs/fileio/tpxio.h"
+#include "gromacs/gmxpreprocess/grompp.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/state.h"
+#include "gromacs/utility/futil.h"
+#include "gromacs/utility/textreader.h"
+#include "gromacs/utility/textwriter.h"
+#include "gromacs/topology/topology.h"
+
+#include "testutils/cmdlinetest.h"
+#include "testutils/conftest.h"
+#include "testutils/refdata.h"
+#include "testutils/testfilemanager.h"
+#include "testutils/textblockmatchers.h"
+
+namespace
+{
+
+using gmx::test::CommandLine;
+using gmx::test::TestFileManager;
+
+class GromppDirectiveTest : public ::testing::Test
+{
+public:
+    GromppDirectiveTest() = default;
+
+protected:
+    gmx::test::TestFileManager fileManager_;
+    std::string                mdpContentString_ =
+            "title                   = Directive edge case test \n"
+            "integrator              = md \n"
+            "nsteps                  = 1 \n"
+            "dt                      = 0.002 \n"
+            "vdwtype                 = cutoff \n"
+            "coulombtype             = cutoff \n"
+            "tcoupl                  = no \n"
+            "pcoupl                  = no \n"
+            "pbc                     = xyz \n"
+            "gen_vel                 = yes \n";
+};
+
+TEST_F(GromppDirectiveTest, edgeCaseAtomTypeNames)
+{
+    CommandLine cmdline;
+    cmdline.addOption("grompp");
+
+    const std::string mdpInputFileName = fileManager_.getTemporaryFilePath("directives.mdp");
+    gmx::TextWriter::writeFileFromString(mdpInputFileName, mdpContentString_);
+    cmdline.addOption("-f", mdpInputFileName);
+
+
+    cmdline.addOption("-c", TestFileManager::getInputFilePath("directives.gro"));
+    cmdline.addOption("-p", TestFileManager::getInputFilePath("directives.top"));
+
+    std::string outTprFilename = fileManager_.getTemporaryFilePath("directives.tpr");
+    cmdline.addOption("-o", outTprFilename);
+
+    ASSERT_EQ(0, gmx_grompp(cmdline.argc(), cmdline.argv()));
+
+    {
+        gmx_mtop_t top_after;
+        t_inputrec ir_after;
+        t_state    state;
+        read_tpx_state(outTprFilename.c_str(), &ir_after, &state, &top_after);
+
+        // Check atomic numbers (or lack thereof coded as -1)
+        ASSERT_EQ(top_after.atomtypes.nr, 4);
+        EXPECT_EQ(top_after.atomtypes.atomnumber[0], -1);
+        EXPECT_EQ(top_after.atomtypes.atomnumber[1], 6);
+        EXPECT_EQ(top_after.atomtypes.atomnumber[2], 7);
+        EXPECT_EQ(top_after.atomtypes.atomnumber[3], -1);
+    }
+}
+
+} // namespace
index ebce88d3839e029fbb1ec5d80de1c1465a17ed95..da45441cbee947ae295ef4792724e99e5ae2d666 100644 (file)
@@ -385,7 +385,12 @@ void push_at(t_symtab*                  symtab,
     }
     else
     {
-        have_bonded_type   = (isalpha(tmpfield[1][0]) != 0);
+        // Attempt parsing field 1 to integer. If successful, *end == '\0'
+        char* end;
+        strtol(tmpfield[1], &end, 10);
+
+        // If conversion fails, we do not have an atomic number but a bonded type
+        have_bonded_type   = (*end != 0);
         have_atomic_number = !have_bonded_type;
     }