votca 2024.2-dev
Loading...
Searching...
No Matches
dlpolytopologyreader.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2023 The VOTCA Development Team (http://www.votca.org)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18// Standard includes
19#include <filesystem>
20#include <fstream>
21#include <iomanip>
22#include <iostream>
23
24// Third party includes
25#include <boost/algorithm/string.hpp>
26#include <boost/lexical_cast.hpp>
27
28// VOTCA includes
29#include <votca/tools/getline.h>
31
32// Local VOTCA includes
33#include "votca/csg/topology.h"
34
35// Local private VOTCA includes
37
38using namespace votca::tools;
39using namespace std;
40
41namespace votca {
42namespace csg {
43
44string DLPOLYTopologyReader::NextKeyline_(ifstream &fs, const char *wspace)
45// function to find and read the next line starting with a keyword/directive
46// (skipping comments starting with "#" or ";") NOTE: the line is returned
47// case-preserved, not to alter molecule/atom names (consider if --no-map is
48// used)
49{
50 string line;
51 size_t i_nws = 0;
52
53 do {
54 tools::getline(fs, line);
55
56 if (fs.eof()) {
57 throw std::runtime_error("Error: unexpected end of dlpoly file '" +
58 fname_ + "'");
59 }
60
61 i_nws = line.find_first_not_of(wspace);
62 } while (line.substr(i_nws, 1) == "#" || line.substr(i_nws, 1) == ";");
63
64 return line.substr(i_nws, line.size() - i_nws);
65}
66
67string DLPOLYTopologyReader::NextKeyInt_(ifstream &fs, const char *wspace,
68 const string &word, Index &ival)
69// function to read the next line containing only a given keyword and an integer
70// value after it (only skipping comments!) NOTE: this function must only be
71// called when the next directive line has to contain the given keyword and an
72// integer value
73{
74 stringstream sl(NextKeyline_(fs, wspace));
75 string line, sval;
76
77 sl >> line; // allow user not to bother about the case
78 boost::to_upper(line);
79
80 if (line.substr(0, word.size()) != word) {
81 throw std::runtime_error("Error: unexpected line from dlpoly file '" +
82 fname_ + "', expected '" + word + "' but got '" +
83 line + "'");
84 }
85
86 sl >> sval;
87
88 size_t i_num = sval.find_first_of(
89 "0123456789"); // assume integer number straight after the only keyword
90
91 if (i_num > 0) {
92 throw std::runtime_error("Error: missing integer number in directive '" +
93 line + "' in topology file '" + fname_ + "'");
94 }
95
96 ival = boost::lexical_cast<Index>(sval);
97
98 return sl.str();
99}
100
101bool DLPOLYTopologyReader::isKeyInt_(const string &line, const char *wspace,
102 const string &word, Index &ival)
103// function to check if the given (last read) directive line starts with a given
104// keyword and has an integer value at the end NOTE: comments are allowed beyond
105// the integer (anything after the first integer is ignored)
106{
107 // split directives consisting of a few words: the sought keyword must be the
108 // first one!
109
110 vector<string> fields = Tokenizer(line, wspace).ToVector();
111
112 ival = 0;
113
114 if (fields.size() < 2) {
115 return false;
116 }
117
118 boost::to_upper(fields[0]);
119
120 if (fields[0].substr(0, word.size()) != word) {
121 throw std::runtime_error("Error: unexpected directive from dlpoly file '" +
122 fname_ + "', expected keyword '" + word +
123 "' but got '" + fields[0] + "'");
124 }
125
126 size_t i_num = string::npos;
127
128 Index i = 1;
129 do { // find integer number in the field with the lowest index (closest to
130 // the keyword)
131 i_num = fields[i++].find_first_of("0123456789");
132 } while (i_num > 0 && i < Index(fields.size()));
133
134 if (i_num > 0) {
135 return false;
136 }
137
138 ival = boost::lexical_cast<Index>(fields[i - 1]);
139
140 return true;
141}
142
144
145 Index natoms = 0;
146
147 std::filesystem::path filepath(file.c_str());
148
149 string line;
150
151 // TODO: fix residue naming / assignment - DL_POLY has no means to recognise
152 // residues!
153 const Residue &res = top.CreateResidue("no");
154
155 if (!filepath.has_stem()) {
156 if (filepath.parent_path().string().size() == 0) {
157 fname_ = "FIELD"; // DL_POLY uses fixed file names in current/working
158 // directory
159 } else {
160 fname_ = filepath.parent_path().string() + "/FIELD";
161 }
162 } else {
163 fname_ = file;
164 }
165 std::ifstream fl;
166 fl.open(fname_);
167
168 if (!fl.is_open()) {
169 throw std::runtime_error("Error on opening dlpoly file '" + fname_ + "'");
170 } else {
171 const char *WhiteSpace = " \t";
172 NextKeyline_(fl, WhiteSpace); // read title line and skip it
173 line = NextKeyline_(fl, WhiteSpace); // read next directive line
174 boost::to_upper(line);
175
176 if (line.substr(0, 4) == "UNIT") { // skip 'unit' line
177 line = NextKeyline_(fl, WhiteSpace); // read next directive line
178 boost::to_upper(line);
179 }
180
181 if (line.substr(0, 4) == "NEUT") { // skip 'neutral groups' line (DL_POLY
182 // Classic FIELD format)
183 line = NextKeyline_(fl, WhiteSpace); // look for next directive line
184 boost::to_upper(line);
185 }
186
187 Index nmol_types;
188
189 if (!isKeyInt_(line, WhiteSpace, "MOLEC", nmol_types)) {
190 throw std::runtime_error("Error: missing integer number in directive '" +
191 line + "' in topology file '" + fname_ + "'");
192 }
193
194#ifndef NDEBUG
195 cout << "Read from dlpoly file '" << fname_ << "' : '" << line << "' - "
196 << nmol_types << endl;
197#endif
198
199 string mol_name;
200
201 for (Index nmol_type = 0; nmol_type < nmol_types; nmol_type++) {
202
203 mol_name = NextKeyline_(fl, WhiteSpace);
204 Molecule *mi = top.CreateMolecule(mol_name);
205
206 Index nreplica = 1;
207 line = NextKeyInt_(fl, WhiteSpace, "NUMMOL", nreplica);
208
209#ifndef NDEBUG
210 cout << "Read from dlpoly file '" << fname_ << "' : '" << mol_name
211 << "' - '" << line << "' - " << nreplica << endl;
212#endif
213
214 line = NextKeyInt_(fl, WhiteSpace, "ATOMS", natoms);
215
216#ifndef NDEBUG
217 cout << "Read from dlpoly file '" << fname_ << "' : '" << line << "' - "
218 << natoms << endl;
219#endif
220 std::vector<Index> id_map(natoms);
221 for (Index i = 0; i < natoms;) { // i is altered in repeater loop
222 stringstream sl(NextKeyline_(fl, WhiteSpace));
223
224#ifndef NDEBUG
225 cout << "Read atom specs from dlpoly topology : '" << sl.str() << "'"
226 << endl;
227#endif
228 string beadtype;
229 sl >> beadtype;
230 if (!top.BeadTypeExist(beadtype)) {
231 top.RegisterBeadType(beadtype);
232 }
233 double mass;
234 sl >> mass;
235 double charge;
236 sl >> charge;
237
238 line = " ";
239 sl >> line; // rest of the atom line
240
241 vector<string> fields = Tokenizer(line, WhiteSpace).ToVector();
242
243#ifndef NDEBUG
244 cout << "Rest atom specs from dlpoly topology : '" << line << "'"
245 << endl;
246#endif
247
248 Index repeater = 1;
249 if (fields.size() > 1) {
250 repeater = boost::lexical_cast<Index>(fields[0]);
251 }
252
253 for (Index j = 0; j < repeater; j++) {
254
255 string beadname = beadtype + "#" + boost::lexical_cast<string>(i + 1);
256 Bead *bead = top.CreateBead(Bead::spherical, beadname, beadtype,
257 res.getId(), mass, charge);
258
259 stringstream nm;
260 nm << bead->getResnr() + 1 << ":"
261 << top.getResidue(bead->getResnr()).getName() << ":"
262 << bead->getName();
263 mi->AddBead(bead, nm.str());
264 id_map[i] = bead->getId();
265 i++;
266#ifndef NDEBUG
267 cout << "Atom identification in maps '" << nm.str() << "'" << endl;
268#endif
269 }
270 }
271
272 while (line != "FINISH") {
273
274 stringstream nl(NextKeyline_(fl, WhiteSpace));
275 nl >> line;
276
277#ifndef NDEBUG
278 cout << "Read unit type# from dlpoly topology : '" << nl.str() << "'"
279 << endl;
280#endif
281
282 boost::to_upper(line);
283 line = line.substr(0, 6);
284 if ((line == "BONDS") || (line == "ANGLES") || (line == "DIHEDR")) {
285 string type = line;
286 Index count;
287 nl >> count;
288 for (Index i = 0; i < count; i++) {
289
290 stringstream sl(NextKeyline_(fl, WhiteSpace));
291#ifndef NDEBUG
292 cout << "Read unit specs from dlpoly topology : '" << sl.str()
293 << "'" << endl;
294#endif
295 sl >> line; // internal dlpoly bond/angle/dihedral function types
296 // are merely skipped (ignored)
297 Index ids[4];
298 Interaction *ic = nullptr;
299 sl >> ids[0];
300 sl >> ids[1];
301 if (type == "BONDS") {
302 ic = new IBond(id_map[ids[0] - 1],
303 id_map[ids[1] - 1]); // -1 due to fortran vs c
304 } else if (type == "ANGLES") {
305 sl >> ids[2];
306 ic = new IAngle(id_map[ids[0] - 1], id_map[ids[1] - 1],
307 id_map[ids[2] - 1]); // -1 due to fortran vs c
308 } else if (type.substr(0, 6) == "DIHEDR") {
309 type = "DIHEDRALS";
310 sl >> ids[2];
311 sl >> ids[3];
312 ic = new IDihedral(id_map[ids[0] - 1], id_map[ids[1] - 1],
313 id_map[ids[2] - 1],
314 id_map[ids[3] - 1]); // -1 due to fortran vs c
315 } else {
316 throw std::runtime_error(
317 "Error: type should be BONDS, ANGLES or DIHEDRALS");
318 }
319 // could one use bond/angle/dihedral function types for 1:1 mapping?
320 // (CG map overwrites ic->Group anyway)
321 // ic->setGroup(line);
322 ic->setGroup(type);
323 ic->setIndex(i);
324 ic->setMolecule(mi->getId());
325 top.AddBondedInteraction(ic);
326 mi->AddInteraction(ic);
327 }
328 }
329 }
330
331#ifndef NDEBUG
332 cout << "Read from dlpoly file '" << fname_ << "' : '" << line
333 << "' - done with '" << mol_name << "'" << endl;
334#endif
335
336 // replicate molecule
337 for (Index replica = 1; replica < nreplica; replica++) {
338 Molecule *mi_replica = top.CreateMolecule(mol_name);
339 for (Index i = 0; i < mi->BeadCount(); i++) {
340 Bead *bead = mi->getBead(i);
341 string type = bead->getType();
342 Bead *bead_replica =
343 top.CreateBead(Bead::spherical, bead->getName(), type,
344 res.getId(), bead->getMass(), bead->getQ());
345 mi_replica->AddBead(bead_replica, bead->getName());
346 }
348 for (auto &ic : ics) {
349 Interaction *ic_replica = nullptr;
350 Index offset =
351 mi_replica->getBead(0)->getId() - mi->getBead(0)->getId();
352 if (ic->BeadCount() == 2) {
353 ic_replica =
354 new IBond(ic->getBeadId(0) + offset, ic->getBeadId(1) + offset);
355 } else if (ic->BeadCount() == 3) {
356 ic_replica =
357 new IAngle(ic->getBeadId(0) + offset, ic->getBeadId(1) + offset,
358 ic->getBeadId(2) + offset);
359 } else if (ic->BeadCount() == 4) {
360 ic_replica = new IDihedral(
361 ic->getBeadId(0) + offset, ic->getBeadId(1) + offset,
362 ic->getBeadId(2) + offset, ic->getBeadId(3) + offset);
363 } else {
364 throw std::runtime_error("Error: BeadCount not equal 2, 3 or 4");
365 }
366 ic_replica->setGroup(ic->getGroup());
367 ic_replica->setIndex(ic->getIndex());
368 ic_replica->setMolecule(mi_replica->getId());
369 top.AddBondedInteraction(ic_replica);
370 mi_replica->AddInteraction(ic_replica);
371 }
372 }
373 }
374 top.RebuildExclusions();
375 }
376
377#ifndef NDEBUG
378 tools::getline(fl, line); // is "close" found?
379 if (line == "close") {
380 cout << "Read from dlpoly file '" << fname_ << "' : '" << line
381 << "' - done with topology" << endl;
382 } else {
383 cout << "Read from dlpoly file '" << fname_
384 << "' : 'EOF' - done with topology (directive 'close' not read!)"
385 << endl;
386 }
387#endif
388
389 // we don't need the rest
390 fl.close();
391
392 return true;
393}
394
395} // namespace csg
396} // namespace votca
virtual const std::string getType() const noexcept
Definition basebead.h:84
std::string getName() const
Gets the name of the bead.
Definition basebead.h:58
virtual const double & getMass() const noexcept
Definition basebead.h:104
Index getId() const noexcept
Gets the id of the bead.
Definition basebead.h:52
information about a bead
Definition bead.h:50
const Index & getResnr() const
Definition bead.h:61
virtual const double & getQ() const
Definition bead.h:67
std::string NextKeyline_(std::ifstream &fs, const char *wspace)
bool isKeyInt_(const std::string &line, const char *wspace, const std::string &word, Index &ival)
std::string NextKeyInt_(std::ifstream &fs, const char *wspace, const std::string &word, Index &ival)
bool ReadTopology(std::string file, Topology &top) override
read a topology file
angle interaction
bond interaction
dihedral interaction
base class for all interactions
Definition interaction.h:40
void setGroup(const std::string &group)
Definition interaction.h:49
void setIndex(const Index &index)
Definition interaction.h:67
void setMolecule(const Index &mol)
Definition interaction.h:76
information about molecules
Definition molecule.h:45
void AddBead(Bead *bead, const std::string &name)
Add a bead to the molecule.
Definition molecule.cc:29
Bead * getBead(Index bead)
get the id of a bead in the molecule
Definition molecule.h:59
void AddInteraction(Interaction *ic)
Add an interaction to the molecule.
Definition molecule.h:77
std::vector< Interaction * > Interactions()
Definition molecule.h:79
Index BeadCount() const
get the number of beads in the molecule
Definition molecule.h:65
Index getId() const
get the molecule ID
Definition molecule.h:48
class for a residue
Definition residue.h:35
Index getId() const
get the name of the residue
Definition residue.h:41
const std::string & getName() const
get the name of the residue
Definition residue.h:52
topology of the whole system
Definition topology.h:81
Residue & CreateResidue(std::string name)
Create a new resiude.
Definition topology.h:462
bool BeadTypeExist(std::string type) const
Determine if a bead type exists.
Definition topology.cc:210
Bead * CreateBead(Bead::Symmetry symmetry, std::string name, std::string type, Index resnr, double m, double q)
Creates a new Bead.
Definition topology.h:441
void AddBondedInteraction(Interaction *ic)
Definition topology.cc:188
void RegisterBeadType(std::string type)
Register the bead type with the topology object.
Definition topology.cc:214
Molecule * CreateMolecule(std::string name)
Creates a new molecule.
Definition topology.h:449
Residue & getResidue(const Index i)
Definition topology.h:229
break string into words
Definition tokenizer.h:72
std::vector< T > ToVector()
store all words in a vector of type T, does type conversion.
Definition tokenizer.h:109
STL namespace.
std::vector< Interaction * > InteractionContainer
Definition topology.h:72
std::istream & getline(std::istream &is, std::string &str)
Wrapper for a getline function.
Definition getline.h:35
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26