numAtomsTotal <= numAtomsLocal*c_memoryRatioHashedVersusDirect);
}
-/*! \brief Returns the base size of the hash table
- *
- * Make the direct list twice as long as the number of local atoms.
- * The fraction of entries in the list with:
- * 0 size lists: e^-1/f
- * >=1 size lists: 1 - e^-1/f
- * where f is: the direct list length / nr. of local atoms
- * The fraction of atoms not in the direct list is: 1-f(1-e^-1/f).
- */
-static int baseTableSizeForHashTable(int numAtomsLocal)
-{
- return 2*numAtomsLocal;
-}
-
gmx_ga2la_t::gmx_ga2la_t(int numAtomsTotal,
int numAtomsLocal) :
usingDirect_(directListIsFaster(numAtomsTotal, numAtomsLocal))
}
else
{
- new(&(data_.hashed))HashedMap<Entry>(baseTableSizeForHashTable(numAtomsLocal));
+ new(&(data_.hashed)) gmx::HashedMap<Entry>(numAtomsLocal);
}
}
private:
union Data
{
- std::vector<Entry> direct;
- HashedMap<Entry> hashed;
+ std::vector<Entry> direct;
+ gmx::HashedMap<Entry> hashed;
// constructor and destructor function in parent class
Data() {}
~Data() {}
#ifndef GMX_DOMDEC_HASHEDMAP_H
#define GMX_DOMDEC_HASHEDMAP_H
+#include <climits>
+
#include <algorithm>
#include <vector>
#include "gromacs/compat/utility.h"
#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/exceptions.h"
+
+namespace gmx
+{
/*! \libinternal \brief Unordered key to value mapping
*
- * Efficiently manages mapping from non-negative integer keys to values.
+ * Efficiently manages mapping from integer keys to values.
* Note that this basically implements a subset of the functionality of
* std::unordered_map, but is an order of magnitude faster.
*/
int next = -1; /**< Index in the list of the next element with the same hash, -1 if none */
};
+ /*! \brief The table size is set to at least this factor time the nr of keys */
+ static constexpr float c_relTableSizeSetMin = 1.5;
+ /*! \brief Threshold for increasing the table size */
+ static constexpr float c_relTableSizeThresholdMin = 1.3;
+ /*! \brief Threshold for decreasing the table size */
+ static constexpr float c_relTableSizeThresholdMax = 3.5;
+
+ /*! \brief Resizes the table
+ *
+ * \param[in] numElementsEstimate An estimate of the number of elements that will be stored
+ */
+ void resize(int numElementsEstimate)
+ {
+ GMX_RELEASE_ASSERT(numElements_ == 0, "Table needs to be empty for resize");
+
+ /* The fraction of table entries with 0 size lists is e^-f.
+ * The fraction of table entries with >=1 size lists is 1 - e^-f
+ * where f is: the #elements / tableSize
+ * The fraction of elements not in the direct list is: 1 - (1 - e^-f)/f.
+ * Thus the optimal table size is roughly double #elements.
+ */
+ /* Make the hash table a power of 2 and at least 1.5 * #elements */
+ int tableSize = 64;
+ while (tableSize <= INT_MAX/2 &&
+ numElementsEstimate*c_relTableSizeSetMin > tableSize)
+ {
+ tableSize *= 2;
+ }
+ table_.resize(tableSize);
+
+ /* Table size is a power of 2, so a binary mask gives the hash */
+ bitMask_ = tableSize - 1;
+ startIndexForSpaceForListEntry_ = tableSize;
+ }
+
public:
/*! \brief Constructor
*
- * \param[in] baseTableSize The size of the base table, optimal is around twice the number of expected entries
+ * \param[in] numElementsEstimate An estimate of the number of elements that will be stored, used for optimizing initial performance
+ *
+ * Note that the estimate of the number of elements is only relevant
+ * for the performance up until the first call to clear(), after which
+ * table size is optimized based on the actual number of elements.
*/
- HashedMap(int baseTableSize) :
- table_(baseTableSize),
- mod_(baseTableSize),
- startSpaceSearch_(baseTableSize)
+ HashedMap(int numElementsEstimate)
+ {
+ resize(numElementsEstimate);
+ }
+
+ /*! \brief Returns the number of elements */
+ int size() const
+ {
+ return numElements_;
+ }
+
+ /*! \brief Returns the number of buckets, i.e. the number of possible hashes */
+ int bucket_count() const
{
+ return bitMask_ + 1;
}
- /*! \brief Inserts entry, key should not already be present (checked by assertion)
+ /*! \brief Inserts entry, key should not already be present
*
* \param[in] key The key for the entry
* \param[in] value The value for the entry
+ * \throws InvalidInputError from a debug build when attempting to insert a duplicate key
*/
void insert(int key,
const T &value)
{
- GMX_ASSERT(key >= 0, "Only keys >= 0 are supported");
-
- size_t ind = key % mod_;
+ size_t ind = (key & bitMask_);
if (table_[ind].key >= 0)
{
* If we find the matching key, return the value.
*/
int ind_prev = ind;
- GMX_ASSERT(table_[ind_prev].key != key, "The key to be inserted should not be present");
+// Note: This is performance critical, so we only throw in debug mode
+#ifndef NDEBUG
+ if (table_[ind_prev].key == key)
+ {
+ GMX_THROW(InvalidInputError("Attempt to insert duplicate key"));
+ }
+#endif
while (table_[ind_prev].next >= 0)
{
ind_prev = table_[ind_prev].next;
- GMX_ASSERT(table_[ind_prev].key != key, "The key to be inserted should not be present");
+#ifndef NDEBUG
+ if (table_[ind_prev].key == key)
+ {
+ GMX_THROW(InvalidInputError("Attempt to insert duplicate key"));
+ }
+#endif
}
- /* Search for space in the array */
- ind = startSpaceSearch_;
+ /* Search for space in table_ */
+ ind = startIndexForSpaceForListEntry_;
while (ind < table_.size() && table_[ind].key >= 0)
{
ind++;
{
table_.resize(table_.size() + 1);
}
- table_[ind_prev].next = ind;
+ table_[ind_prev].next = ind;
- startSpaceSearch_ = ind + 1;
+ startIndexForSpaceForListEntry_ = ind + 1;
}
- table_[ind].key = key;
- table_[ind].value = value;
+ table_[ind].key = key;
+ table_[ind].value = value;
+
+ numElements_ += 1;
}
- /*! \brief Delete the entry for key \p key
+ /*! \brief Delete the entry for key \p key, when present
*
* \param[in] key The key
*/
void erase(int key)
{
int ind_prev = -1;
- int ind = key % mod_;
+ int ind = (key & bitMask_);
do
{
if (table_[ind].key == key)
/* This index is a linked entry, so we free an entry.
* Check if we are creating the first empty space.
*/
- if (ind < startSpaceSearch_)
+ if (ind < startIndexForSpaceForListEntry_)
{
- startSpaceSearch_ = ind;
+ startIndexForSpaceForListEntry_ = ind;
}
}
- table_[ind].key = -1;
- table_[ind].next = -1;
+ table_[ind].key = -1;
+ table_[ind].next = -1;
+
+ numElements_ -= 1;
return;
}
*/
const T *find(int key) const
{
- int ind = key % mod_;
+ int ind = (key & bitMask_);
do
{
if (table_[ind].key == key)
return nullptr;
}
- /*! \brief Clear all the entries in the list */
+ /*! \brief Clear all the entries in the list
+ *
+ * Also optimizes the size of the table based on the current
+ * number of elements stored.
+ */
void clear()
{
+ const int oldNumElements = numElements_;
+
for (hashEntry &entry : table_)
{
entry.key = -1;
entry.next = -1;
}
- startSpaceSearch_ = mod_;
+ startIndexForSpaceForListEntry_ = bucket_count();
+ numElements_ = 0;
+
+ /* Resize the hash table when the occupation is far from optimal.
+ * Do not resize with 0 elements to avoid minimal size when clear()
+ * is called twice in a row.
+ */
+ if (oldNumElements > 0 && (oldNumElements*c_relTableSizeThresholdMax < bucket_count() ||
+ oldNumElements*c_relTableSizeThresholdMin > bucket_count()))
+ {
+ resize(oldNumElements);
+ }
}
private:
- std::vector<hashEntry> table_; /**< The hash table list */
- int mod_; /**< The hash size */
- int startSpaceSearch_; /**< Index in lal at which to start looking for empty space */
+ /*! \brief The hash table list */
+ std::vector<hashEntry> table_;
+ /*! \brief The bit mask for computing the hash of a key */
+ int bitMask_ = 0;
+ /*! \brief Index in table_ at which to start looking for empty space for a new linked list entry */
+ int startIndexForSpaceForListEntry_ = 0;
+ /*! \brief The number of elements currently stored in the table */
+ int numElements_ = 0;
};
+} // namespace gmx
+
#endif
# the research papers on the package. Check out http://www.gromacs.org.
gmx_add_unit_test(DomDecTests domdec-test
+ hashedmap.cpp
localatomsetmanager.cpp)
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2018, by the GROMACS development team, led by
+ * 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 the HashedMap class.
+ *
+ * \author berk Hess <hess@kth.se>
+ * \ingroup module_domdec
+ */
+#include "gmxpre.h"
+
+#include "gromacs/domdec/hashedmap.h"
+
+#include <gtest/gtest.h>
+
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+/*! \brief Checks that the key is found and if so also checks the value */
+void checkFinds(const gmx::HashedMap<char> &map,
+ int key,
+ char value)
+{
+ const char *pointer = map.find(key);
+ EXPECT_FALSE(pointer == nullptr);
+ if (pointer)
+ {
+ EXPECT_EQ(*pointer, value);
+ }
+}
+
+/*! \brief Checks that the key is not found */
+void checkDoesNotFind(const gmx::HashedMap<char> &map,
+ int key)
+{
+ const char *pointer = map.find(key);
+ EXPECT_TRUE(pointer == nullptr);
+}
+
+TEST(HashedMap, InsertsFinds)
+{
+ gmx::HashedMap<char> map(2);
+
+ map.insert(10, 'a');
+ map.insert(5, 'b');
+ map.insert(7, 'c');
+
+ checkFinds(map, 10, 'a');
+ checkFinds(map, 5, 'b');
+ checkFinds(map, 7, 'c');
+ checkDoesNotFind(map, 4);
+}
+
+TEST(HashedMap, NegativeKeysWork)
+{
+ gmx::HashedMap<char> map(5);
+
+ map.insert(-1, 'a');
+ map.insert(1, 'b');
+ map.insert(-3, 'c');
+
+ checkFinds(map, -1, 'a');
+ checkFinds(map, 1, 'b');
+ checkFinds(map, -3, 'c');
+}
+
+TEST(HashedMap, InsertsErases)
+{
+ gmx::HashedMap<char> map(3);
+
+ map.insert(10, 'a');
+ map.insert(5, 'b');
+ map.insert(7, 'c');
+
+ checkFinds(map, 10, 'a');
+ map.erase(10);
+ checkDoesNotFind(map, 10);
+}
+
+TEST(HashedMap, Clears)
+{
+ gmx::HashedMap<char> map(3);
+
+ map.insert(10, 'a');
+ map.insert(5, 'b');
+ map.insert(7, 'c');
+
+ map.clear();
+ checkDoesNotFind(map, 10);
+ checkDoesNotFind(map, 5);
+ checkDoesNotFind(map, 7);
+}
+
+// Check that entries with the same hash are handled correctly
+TEST(HashedMap, LinkedEntries)
+{
+ // HashedMap uses bit masking, so keys that differ by exactly
+ // a power of 2 larger than the table size will have the same hash
+
+ gmx::HashedMap<char> map(20);
+
+ const int largePowerOf2 = 2048;
+
+ map.insert(3 + 0*largePowerOf2, 'a');
+ map.insert(3 + 1*largePowerOf2, 'b');
+ map.insert(3 + 2*largePowerOf2, 'c');
+
+ checkFinds(map, 3 + 0*largePowerOf2, 'a');
+ checkFinds(map, 3 + 1*largePowerOf2, 'b');
+ checkFinds(map, 3 + 2*largePowerOf2, 'c');
+
+ // Erase the middle entry in the linked list
+ map.erase(3 + 1*largePowerOf2);
+
+ checkFinds(map, 3 + 0*largePowerOf2, 'a');
+ checkDoesNotFind(map, 3 + 1*largePowerOf2);
+ checkFinds(map, 3 + 2*largePowerOf2, 'c');
+}
+
+// HashedMap only throws in debug mode, so only test in debug mode
+#ifndef NDEBUG
+
+TEST(HashedMap, CatchesDuplicateKey)
+{
+ gmx::HashedMap<char> map(15);
+
+ map.insert(10, 'a');
+ map.insert(5, 'b');
+ EXPECT_THROW_GMX(map.insert(10, 'c'), gmx::InvalidInputError);
+}
+
+#endif // NDEBUG
+
+// Check the table is resized after clear()
+TEST(HashedMap, ResizesTable)
+{
+ gmx::HashedMap<char> map(1);
+
+ // This test assumes the minimum bucket count is 64 or less
+ EXPECT_LT(map.bucket_count(), 128);
+
+ for (int i = 0; i < 60; i++)
+ {
+ map.insert(2*i + 3, 'a');
+ }
+ EXPECT_LT(map.bucket_count(), 128);
+
+ // Check that the table size is double #elements after clear()
+ map.clear();
+ EXPECT_EQ(map.bucket_count(), 128);
+
+ // Check that calling clear() a second time does not resize
+ map.clear();
+ EXPECT_EQ(map.bucket_count(), 128);
+
+ map.insert(2, 'b');
+ EXPECT_EQ(map.bucket_count(), 128);
+
+ // Check that calling clear with 1 elements sizes down
+ map.clear();
+ EXPECT_LT(map.bucket_count(), 128);
+}
+
+} // namespace
}
}
-int fflib_search_file_end(const char *ffdir,
- const char *file_end,
- bool bFatalError,
- char ***filenames)
+std::vector<std::string> fflib_search_file_end(const char *ffdir,
+ const char *file_end,
+ bool bFatalError)
{
try
{
file_end, ffdir);
GMX_THROW(gmx::InvalidInputError(message));
}
- const int count = static_cast<int>(result.size());
- for (int i = 0; i < count; ++i)
+ for (std::string &filename : result)
{
- result[i] = gmx::Path::join(ffdir, result[i]);
+ filename = gmx::Path::join(ffdir, filename);
}
- char **fns;
- snew(fns, count);
- for (int i = 0; i < count; ++i)
- {
- fns[i] = gmx_strdup(result[i].c_str());
- }
- *filenames = fns;
- return count;
+ return result;
}
GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
}
return result;
}
-bool fflib_fexist(const char *file)
+bool fflib_fexist(const std::string &file)
{
char *file_fullpath;
- file_fullpath = low_gmxlibfn(file, TRUE, FALSE);
+ file_fullpath = low_gmxlibfn(file.c_str(), TRUE, FALSE);
if (file_fullpath == nullptr)
{
}
-FILE *fflib_open(const char *file)
+FILE *fflib_open(const std::string &file)
{
char *file_fullpath;
FILE *fp;
- file_fullpath = gmxlibfn(file);
+ file_fullpath = gmxlibfn(file.c_str());
fprintf(stderr, "Opening force field file %s\n", file_fullpath);
fp = gmx_ffopen(file_fullpath, "r");
sfree(file_fullpath);
#include <stdio.h>
+#include <string>
#include <vector>
#include "gromacs/utility/basedefinitions.h"
* base should be at least of size maxlen.
*/
-int fflib_search_file_end(const char *ffdir,
- const char *file_end,
- bool bFatalError,
- char ***filenames);
+std::vector<std::string> fflib_search_file_end(const char *ffdir,
+ const char *file_end,
+ bool bFatalError);
/* Search for files ending on file_end in the force field directory fflib.
* fflib should be in the GROMACS lib.path.
* Return the number of files and the file names in filenames.
*/
-bool fflib_fexist(const char *file);
+bool fflib_fexist(const std::string &file);
/* Check if a file exists in the force field library */
-FILE *fflib_open(const char *file);
+FILE *fflib_open(const std::string &file);
/* Open force field library file "file" for reading.
* "file" should contain the whole path to the force field library,
* either absolute or relative to the current dir.
#include <cstdlib>
#include <cstring>
+#include <string>
+#include <vector>
+
#include "gromacs/fileio/pdbio.h"
#include "gromacs/gmxpreprocess/add_par.h"
#include "gromacs/gmxpreprocess/fflibutil.h"
t_params *params;
char ***newatomname;
char *resnm = nullptr;
- int ndb, f;
- char **db;
int nvsiteconf, nvsitetop, cmplength;
bool isN, planarN, bFound;
gmx_residuetype_t*rt;
fprintf(debug, "# # # VSITES # # #\n");
}
- ndb = fflib_search_file_end(ffdir, ".vsd", FALSE, &db);
+ std::vector<std::string> db = fflib_search_file_end(ffdir, ".vsd", FALSE);
nvsiteconf = 0;
vsiteconflist = nullptr;
nvsitetop = 0;
vsitetop = nullptr;
- for (f = 0; f < ndb; f++)
+ for (const auto &filename : db)
{
- read_vsite_database(db[f], &vsiteconflist, &nvsiteconf, &vsitetop, &nvsitetop);
- sfree(db[f]);
+ read_vsite_database(filename.c_str(), &vsiteconflist, &nvsiteconf, &vsitetop, &nvsitetop);
}
- sfree(db);
bFirstWater = TRUE;
nvsite = 0;
if (ch == nullptr)
{
- if (ndb > 0)
+ if (!db.empty())
{
gmx_fatal(FARGS, "Can't find dummy mass for type %s bonded to type %s in the virtual site database (.vsd files). Add it to the database!\n", tpname, nexttpname);
}
#include <cstdlib>
#include <cstring>
+#include <string>
+#include <vector>
+
#include "gromacs/gmxpreprocess/fflibutil.h"
#include "gromacs/gmxpreprocess/notset.h"
#include "gromacs/utility/arraysize.h"
int read_h_db(const char *ffdir, t_hackblock **ah)
{
- int nhdbf, f;
- char **hdbf;
- int nah;
-
/* Read the hydrogen database file(s).
* Do not generate an error when no files are found.
*/
- nhdbf = fflib_search_file_end(ffdir, ".hdb", FALSE, &hdbf);
- nah = 0;
+
+ std::vector<std::string> hdbf = fflib_search_file_end(ffdir, ".hdb", FALSE);
+ int nah = 0;
*ah = nullptr;
- for (f = 0; f < nhdbf; f++)
+ for (const auto &filename : hdbf)
{
- read_h_db_file(hdbf[f], &nah, ah);
- sfree(hdbf[f]);
+ read_h_db_file(filename.c_str(), &nah, ah);
}
- sfree(hdbf);
-
return nah;
}
#include <cstring>
#include <algorithm>
+#include <string>
+#include <vector>
#include "gromacs/fileio/confio.h"
#include "gromacs/gmxpreprocess/fflibutil.h"
#include "gromacs/utility/futil.h"
#include "gromacs/utility/smalloc.h"
-static void rd_nm2type_file(const char *fn, int *nnm, t_nm2type **nmp)
+static void rd_nm2type_file(const std::string &filename, int *nnm, t_nm2type **nmp)
{
FILE *fp;
bool bCont;
double qq, mm;
t_nm2type *nm2t = nullptr;
- fp = fflib_open(fn);
+ fp = fflib_open(filename);
if (nullptr == fp)
{
- gmx_fatal(FARGS, "Can not find %s in library directory", fn);
+ gmx_fatal(FARGS, "Can not find %s in library directory", filename.c_str());
}
nnnm = *nnm;
t_nm2type *rd_nm2type(const char *ffdir, int *nnm)
{
- int nff, f;
- char **ff;
- t_nm2type *nm;
-
- nff = fflib_search_file_end(ffdir, ".n2t", FALSE, &ff);
+ std::vector<std::string> ff = fflib_search_file_end(ffdir, ".n2t", FALSE);
*nnm = 0;
- nm = nullptr;
- for (f = 0; f < nff; f++)
+ t_nm2type *nm = nullptr;
+ for (const auto &filename : ff)
{
- rd_nm2type_file(ff[f], nnm, &nm);
- sfree(ff[f]);
+ rd_nm2type_file(filename, nnm, &nm);
}
- sfree(ff);
-
return nm;
}
#include <ctime>
#include <algorithm>
+#include <string>
+#include <vector>
#include "gromacs/commandline/pargs.h"
#include "gromacs/fileio/confio.h"
char ffname[STRLEN], suffix[STRLEN], buf[STRLEN];
char *watermodel;
const char *watres;
- int nrtpf;
- char **rtpf;
- int nrrn;
- char **rrn;
int nrtprename;
rtprename_t *rtprename = nullptr;
int nah, nNtdb, nCtdb, ntdblist;
gmx_residuetype_init(&rt);
/* Read residue renaming database(s), if present */
- nrrn = fflib_search_file_end(ffdir, ".r2b", FALSE, &rrn);
+ std::vector<std::string> rrn = fflib_search_file_end(ffdir, ".r2b", FALSE);
nrtprename = 0;
rtprename = nullptr;
- for (i = 0; i < nrrn; i++)
+ for (const auto &filename : rrn)
{
- fp = fflib_open(rrn[i]);
- read_rtprename(rrn[i], fp, &nrtprename, &rtprename);
+ fp = fflib_open(filename);
+ read_rtprename(filename.c_str(), fp, &nrtprename, &rtprename);
gmx_ffclose(fp);
- sfree(rrn[i]);
}
- sfree(rrn);
/* Add all alternative names from the residue renaming database to the list of recognized amino/nucleic acids. */
for (i = 0; i < nrtprename; i++)
/* read residue database */
printf("Reading residue database... (%s)\n", forcefield);
- nrtpf = fflib_search_file_end(ffdir, ".rtp", TRUE, &rtpf);
+ std::vector<std::string> rtpf = fflib_search_file_end(ffdir, ".rtp", TRUE);
nrtp = 0;
restp = nullptr;
- for (i = 0; i < nrtpf; i++)
+ for (const auto &filename : rtpf)
{
- read_resall(rtpf[i], &nrtp, &restp, atype, &symtab, FALSE);
- sfree(rtpf[i]);
+ read_resall(filename.c_str(), &nrtp, &restp, atype, &symtab, FALSE);
}
- sfree(rtpf);
if (bNewRTP)
{
/* Not correct with multiple rtp input files with different bonded types */
char **watermodel)
{
const char *fn_watermodels = "watermodels.dat";
- char fn_list[STRLEN];
FILE *fp;
char buf[STRLEN];
int nwm, sel, i;
return;
}
- sprintf(fn_list, "%s%c%s", ffdir, DIR_SEPARATOR, fn_watermodels);
-
- if (!fflib_fexist(fn_list))
+ std::string filename = gmx::Path::join(ffdir, fn_watermodels);
+ if (!fflib_fexist(filename))
{
fprintf(stderr, "No file '%s' found, will not include a water model\n",
fn_watermodels);
return;
}
- fp = fflib_open(fn_list);
+ fp = fflib_open(filename);
printf("\nSelect the Water Model:\n");
nwm = 0;
model = nullptr;
#include <cstring>
#include <algorithm>
+#include <string>
+#include <vector>
#include "gromacs/gmxpreprocess/fflibutil.h"
#include "gromacs/gmxpreprocess/notset.h"
gpp_atomtype_t read_atype(const char *ffdir, t_symtab *tab)
{
- int nfile, f;
- char **file;
- FILE *in;
- char buf[STRLEN], name[STRLEN];
- double m;
- int nratt = 0;
- gpp_atomtype_t at;
- t_atom *a;
- t_param *nb;
-
- nfile = fflib_search_file_end(ffdir, ".atp", TRUE, &file);
+ FILE *in;
+ char buf[STRLEN], name[STRLEN];
+ double m;
+ int nratt = 0;
+ gpp_atomtype_t at;
+ t_atom *a;
+ t_param *nb;
+
+ std::vector<std::string> files = fflib_search_file_end(ffdir, ".atp", TRUE);
at = init_atomtype();
snew(a, 1);
snew(nb, 1);
- for (f = 0; f < nfile; f++)
+ for (const auto &filename : files)
{
- in = fflib_open(file[f]);
+ in = fflib_open(filename);
while (!feof(in))
{
/* Skip blank or comment-only lines */
}
}
gmx_ffclose(in);
- sfree(file[f]);
}
fprintf(stderr, "\n");
- sfree(file);
return at;
}
}
}
-static void check_rtp(int nrtp, t_restp rtp[], char *libfn)
+static void check_rtp(int nrtp, t_restp rtp[], const char *libfn)
{
int i;
}
}
-void read_resall(char *rrdb, int *nrtpptr, t_restp **rtp,
+void read_resall(const char *rrdb, int *nrtpptr, t_restp **rtp,
gpp_atomtype_t atype, t_symtab *tab,
bool bAllowOverrideRTP)
{
gpp_atomtype_t read_atype(const char *ffdir, struct t_symtab *tab);
/* read atom type database(s) */
-void read_resall(char *resdb, int *nrtp, t_restp **rtp,
+void read_resall(const char *resdb, int *nrtp, t_restp **rtp,
gpp_atomtype_t atype, struct t_symtab *tab,
bool bAllowOverrideRTP);
/* read rtp database, append to the existing database */
#include <cctype>
#include <cstring>
+#include <string>
+#include <vector>
+
#include "gromacs/fileio/gmxfio.h"
#include "gromacs/gmxpreprocess/fflibutil.h"
#include "gromacs/gmxpreprocess/h_db.h"
gmx_fio_fclose(out);
}
-static void read_ter_db_file(char *fn,
+static void read_ter_db_file(const char *fn,
int *ntbptr, t_hackblock **tbptr,
gpp_atomtype_t atype)
{
t_hackblock **tbptr, gpp_atomtype_t atype)
{
char ext[STRLEN];
- int ntdbf, f;
- char **tdbf;
int ntb;
sprintf(ext, ".%c.tdb", ter);
/* Search for termini database files.
* Do not generate an error when none are found.
*/
- ntdbf = fflib_search_file_end(ffdir, ext, FALSE, &tdbf);
+ std::vector<std::string> tdbf = fflib_search_file_end(ffdir, ext, FALSE);
ntb = 0;
*tbptr = nullptr;
- for (f = 0; f < ntdbf; f++)
+ for (const auto &filename : tdbf)
{
- read_ter_db_file(tdbf[f], &ntb, tbptr, atype);
- sfree(tdbf[f]);
+ read_ter_db_file(filename.c_str(), &ntb, tbptr, atype);
}
- sfree(tdbf);
if (debug)
{
#include <cctype>
#include <cstring>
+#include <string>
+#include <vector>
+
#include "gromacs/gmxpreprocess/fflibutil.h"
#include "gromacs/gmxpreprocess/hackblock.h"
#include "gromacs/topology/residuetypes.h"
char *replace;
} t_xlate_atom;
-static void get_xlatoms(const char *fn, FILE *fp,
+static void get_xlatoms(const std::string &filename, FILE *fp,
int *nptr, t_xlate_atom **xlptr)
{
char filebase[STRLEN];
int n, na, idum;
t_xlate_atom *xl;
- fflib_filename_base(fn, filebase, STRLEN);
+ fflib_filename_base(filename.c_str(), filebase, STRLEN);
n = *nptr;
xl = *xlptr;
}
if (na != 3)
{
- gmx_fatal(FARGS, "Expected a residue name and two atom names in file '%s', not '%s'", fn, line);
+ gmx_fatal(FARGS, "Expected a residue name and two atom names in file '%s', not '%s'", filename.c_str(), line);
}
srenew(xl, n+1);
sfree(xlatom);
}
-void rename_atoms(const char *xlfile, const char *ffdir,
+void rename_atoms(const char* xlfile, const char *ffdir,
t_atoms *atoms, t_symtab *symtab, const t_restp *restp,
bool bResname, gmx_residuetype_t *rt, bool bReorderNum,
bool bVerbose)
FILE *fp;
int nxlate, a, i, resind;
t_xlate_atom *xlatom;
- int nf;
- char **f;
char c, *rnm, atombuf[32], *ptr0, *ptr1;
bool bReorderedNum, bRenamed, bMatch;
bool bStartTerm, bEndTerm;
}
else
{
- nf = fflib_search_file_end(ffdir, ".arn", FALSE, &f);
- for (i = 0; i < nf; i++)
+ std::vector<std::string> fns = fflib_search_file_end(ffdir, ".arn", FALSE);
+ for (const auto &filename : fns)
{
- fp = fflib_open(f[i]);
- get_xlatoms(f[i], fp, &nxlate, &xlatom);
+ fp = fflib_open(filename);
+ get_xlatoms(filename, fp, &nxlate, &xlatom);
gmx_ffclose(fp);
- sfree(f[i]);
}
- sfree(f);
}
for (a = 0; (a < atoms->nr); a++)
/* If bResname is true renames atoms based on residue names,
* otherwise renames atoms based on rtp entry names.
*/
-void rename_atoms(const char *xlfile, const char *ffdir,
+void rename_atoms(const char* xlfile, const char *ffdir,
struct t_atoms *atoms, struct t_symtab *symtab, const t_restp *restp,
bool bResname, struct gmx_residuetype_t *rt, bool bReorderNum,
bool bVerbose);