1 /*
2  * Copyright 2009-2021 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 <cstddef>
20 #include <iostream>
21 #include <memory>
22 #include <stdexcept>
23 #include <string>
24 
25 // Third party includes
26 #include <boost/lexical_cast.hpp>
27 
28 // VOTCA includes
29 #include <votca/tools/property.h>
30 #include <votca/tools/tokenizer.h>
31 
32 // Local VOTCA includes
33 #include "votca/csg/cgmoleculedef.h"
34 #include "votca/csg/interaction.h"
35 #include "votca/csg/map.h"
36 #include "votca/csg/topology.h"
37 
38 namespace votca {
39 namespace csg {
40 class Molecule;
41 class Residue;
42 }  // namespace csg
43 }  // namespace votca
44 
45 namespace votca {
46 namespace csg {
47 
48 using namespace std;
49 using boost::lexical_cast;
50 
~CGMoleculeDef()51 CGMoleculeDef::~CGMoleculeDef() {
52   for (beaddef_t *def : beads_) {
53     delete def;
54   }
55   beads_.clear();
56 }
57 
Load(string filename)58 void CGMoleculeDef::Load(string filename) {
59   options_.LoadFromXML(filename);
60   // parse xml tree
61   name_ = options_.get("cg_molecule.name").as<string>();
62   ident_ = options_.get("cg_molecule.ident").as<string>();
63 
64   ParseTopology(options_.get("cg_molecule.topology"));
65   ParseMapping(options_.get("cg_molecule.maps"));
66 }
67 
ParseTopology(tools::Property & options)68 void CGMoleculeDef::ParseTopology(tools::Property &options) {
69   ParseBeads(options.get("cg_beads"));
70   if (options.exists("cg_bonded")) {
71     ParseBonded(options.get("cg_bonded"));
72   }
73 }
74 
ParseBeads(tools::Property & options)75 void CGMoleculeDef::ParseBeads(tools::Property &options) {
76 
77   for (tools::Property *p : options.Select("cg_bead")) {
78     beaddef_t *beaddef = new beaddef_t;
79     beaddef->options_ = p;
80 
81     beaddef->name_ = p->get("name").as<string>();
82     beaddef->type_ = p->get("type").as<string>();
83     beaddef->mapping_ = p->get("mapping").as<string>();
84     if (p->exists("symmetry")) {
85       Index sym = p->get("symmetry").as<Index>();
86       if (sym == 1) {
87         beaddef->symmetry_ = Bead::spherical;
88       } else if (sym == 3) {
89         beaddef->symmetry_ = Bead::ellipsoidal;
90       } else {
91         throw std::runtime_error(
92             "Only beads with spherical(1) or ellipsoidal(3) symmetry "
93             "implemented.");
94       }
95     } else {
96       beaddef->symmetry_ = Bead::spherical;
97     }
98 
99     if (beads_by_name_.find(beaddef->name_) != beads_by_name_.end()) {
100       throw std::runtime_error(string("bead name ") + beaddef->name_ +
101                                " not unique in mapping");
102     }
103     beads_.push_back(beaddef);
104     beads_by_name_[beaddef->name_] = beaddef;
105   }
106 }
107 
ParseBonded(tools::Property & options)108 void CGMoleculeDef::ParseBonded(tools::Property &options) {
109   bonded_ = options.Select("*");
110 }
111 
ParseMapping(tools::Property & options)112 void CGMoleculeDef::ParseMapping(tools::Property &options) {
113 
114   for (tools::Property *p : options.Select("map")) {
115     maps_[p->get("name").as<string>()] = p;
116   }
117 }
CreateMolecule(Topology & top)118 Molecule *CGMoleculeDef::CreateMolecule(Topology &top) {
119   // add the residue names
120   const Residue &res = top.CreateResidue(name_);
121   Molecule *minfo = top.CreateMolecule(name_);
122 
123   // create the atoms
124   for (auto &bead_def : beads_) {
125 
126     string type = bead_def->type_;
127     if (!top.BeadTypeExist(type)) {
128       top.RegisterBeadType(type);
129     }
130     Bead *bead = top.CreateBead(bead_def->symmetry_, bead_def->name_, type,
131                                 res.getId(), 0, 0);
132     minfo->AddBead(bead, bead->getName());
133   }
134 
135   // create the bonds
136   map<string, string> had_iagroup;
137 
138   for (tools::Property *prop : bonded_) {
139     std::list<Index> atoms;
140     string iagroup = prop->get("name").as<string>();
141 
142     if (had_iagroup[iagroup] == "yes") {
143       throw runtime_error(
144           string("double occurence of interactions with name ") + iagroup);
145     }
146     had_iagroup[iagroup] = "yes";
147 
148     tools::Tokenizer tok(prop->get("beads").value(), " \n\t");
149     for (auto &atom : tok) {
150       Index i = minfo->getBeadIdByName(atom);
151       if (i < 0) {
152         throw runtime_error(
153             string("error while trying to create bonded interaction, "
154                    "bead " +
155                    atom + " not found"));
156       }
157 
158       atoms.push_back(i);
159     }
160 
161     Index NrBeads = 1;
162     if (prop->name() == "bond") {
163       NrBeads = 2;
164     } else if (prop->name() == "angle") {
165       NrBeads = 3;
166     } else if (prop->name() == "dihedral") {
167       NrBeads = 4;
168     }
169 
170     if ((atoms.size() % NrBeads) != 0) {
171       throw runtime_error("Number of atoms in interaction '" +
172                           prop->get("name").as<string>() +
173                           "' is not a multiple of " +
174                           lexical_cast<string>(NrBeads) + "! Missing beads?");
175     }
176 
177     Index index = 0;
178     while (!atoms.empty()) {
179       Interaction *ic;
180 
181       if (prop->name() == "bond") {
182         ic = new IBond(atoms);
183       } else if (prop->name() == "angle") {
184         ic = new IAngle(atoms);
185       } else if (prop->name() == "dihedral") {
186         ic = new IDihedral(atoms);
187       } else {
188         throw runtime_error("unknown bonded type in map: " + prop->name());
189       }
190 
191       ic->setGroup(iagroup);
192       ic->setIndex(index);
193       ic->setMolecule(minfo->getId());
194       top.AddBondedInteraction(ic);
195       minfo->AddInteraction(ic);
196       index++;
197     }
198   }
199   return minfo;
200 }
201 
CreateMap(const Molecule & in,Molecule & out)202 Map CGMoleculeDef::CreateMap(const Molecule &in, Molecule &out) {
203   if (out.BeadCount() != Index(beads_.size())) {
204     throw runtime_error(
205         "number of beads for cg molecule and mapping definition do "
206         "not match, check your molecule naming.");
207   }
208 
209   Map map(in, out);
210   for (auto &bead : beads_) {
211 
212     Index iout = out.getBeadByName(bead->name_);
213     if (iout < 0) {
214       throw runtime_error(string("mapping error: reference molecule " +
215                                  bead->name_ + " does not exist"));
216     }
217 
218     tools::Property *mdef = getMapByName(bead->mapping_);
219     if (!mdef) {
220       throw runtime_error(string("mapping " + bead->mapping_ + " not found"));
221     }
222 
223     /// TODO: change this to factory, do not hardcode!!
224     BeadMap *bmap;
225     switch (bead->symmetry_) {
226       case 1:
227         bmap = map.CreateBeadMap(BeadMapType::Spherical);
228         break;
229       case 3:
230         bmap = map.CreateBeadMap(BeadMapType::Ellipsoidal);
231         break;
232       default:
233         throw runtime_error(string("unknown symmetry in bead definition!"));
234     }
235     ////////////////////////////////////////////////////
236 
237     bmap->Initialize(&in, out.getBead(iout), (bead->options_), mdef);
238   }
239   return map;
240 }
241 
getBeadByName(const string & name)242 CGMoleculeDef::beaddef_t *CGMoleculeDef::getBeadByName(const string &name) {
243   map<string, beaddef_t *>::iterator iter = beads_by_name_.find(name);
244   if (iter == beads_by_name_.end()) {
245     std::cout << "cannot find: <" << name << "> in " << name_ << "\n";
246     return nullptr;
247   }
248   return (*iter).second;
249 }
250 
getMapByName(const string & name)251 tools::Property *CGMoleculeDef::getMapByName(const string &name) {
252   map<string, tools::Property *>::iterator iter = maps_.find(name);
253   if (iter == maps_.end()) {
254     std::cout << "cannot find map " << name << "\n";
255     return nullptr;
256   }
257   return (*iter).second;
258 }
259 
260 }  // namespace csg
261 }  // namespace votca
262