19#include <openbabel/atom.h>
20#include <openbabel/babelconfig.h>
21#include <openbabel/bond.h>
22#include <openbabel/chains.h>
23#include <openbabel/data.h>
24#include <openbabel/mol.h>
25#include <openbabel/obiter.h>
26#include <openbabel/obmolecformat.h>
27#include <openbabel/obutil.h>
34 class OpenMDFormat :
public OBMoleculeFormat {
37 OpenMDFormat() { OBConversion::RegisterFormat(
"omd",
this); }
39 virtual const char* Description()
41 return "OpenMD combined meta-data / cartesian coordinates format\n\
45 virtual const char* SpecificationURL() {
46 return "http://openmd.org";
49 virtual const char* GetMIMEType() {
return "chemical/x-omd"; };
51 virtual unsigned int Flags() {
return NOTREADABLE | WRITEONEONLY; }
53 virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
56 bool AreSameFragments(OBMol& mol, vector<int>& frag1, vector<int>& frag2);
57 OBMol* createMolFromFragment(OBMol& mol, vector<int>& fragment);
58 void WriteMDFile(vector<OBMol*> mols, vector<int> numMols, ostream& os,
59 OBMol& mol, vector<int>& indices);
60 void CalcBoundingBox(OBMol& mol,
double& min_x,
double& max_x,
61 double& min_y,
double& max_y,
double& min_z,
66 OpenMDFormat theOpenMDFormat;
68 bool OpenMDFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) {
69 OBMol* pmol =
dynamic_cast<OBMol*
>(pOb);
70 if (pmol == NULL)
return false;
72 vector<vector<int>> fragmentLists;
73 pmol->ContigFragList(fragmentLists);
75 vector<bool> used(fragmentLists.size(), 0);
76 vector<vector<int>> molecules;
78 for (std::size_t i = 0; i < used.size(); ++i) {
79 if (used[i])
continue;
82 vector<int> sameMolTypes;
83 sameMolTypes.push_back(i);
84 indices.insert(indices.end(), fragmentLists[i].begin(),
85 fragmentLists[i].end());
86 for (std::size_t j = i + 1; j < used.size(); ++j) {
87 if (used[j])
continue;
89 if (AreSameFragments(*pmol, fragmentLists[i], fragmentLists[j])) {
90 sameMolTypes.push_back(j);
91 indices.insert(indices.end(), fragmentLists[j].begin(),
92 fragmentLists[j].end());
96 molecules.push_back(sameMolTypes);
99 vector<OBMol*> mdMols;
101 for (vector<vector<int>>::iterator i = molecules.begin();
102 i != molecules.end(); ++i) {
103 mdMols.push_back(createMolFromFragment(*pmol, fragmentLists[i->front()]));
104 numMols.push_back((*i).size());
107 string OutputFileName = pConv->GetInFilename();
108 size_t pos = OutputFileName.rfind(
".");
109 if (pos != string::npos)
110 OutputFileName = OutputFileName.substr(0, pos) +
".omd";
112 OutputFileName +=
".omd";
114 ofstream ofs(OutputFileName.c_str());
116 cerr <<
"Cannot write to " << OutputFileName << endl;
120 WriteMDFile(mdMols, numMols, ofs, *pmol, indices);
122 for (vector<OBMol*>::iterator i = mdMols.begin(); i != mdMols.end(); ++i) {
129 bool OpenMDFormat::AreSameFragments(OBMol& mol, vector<int>& frag1,
130 vector<int>& frag2) {
131 if (frag1.size() != frag2.size())
return false;
138 for (
unsigned int i = 0; i < frag1.size(); ++i) {
139 OBAtom* atom1 = mol.GetAtom(frag1[i]);
140 OBAtom* atom2 = mol.GetAtom(frag2[i]);
142 if (atom1->GetAtomicNum() != atom2->GetAtomicNum())
return false;
148 bool operator()(
const triple<OBAtom*, OBAtom*, OBAtom*> t1,
149 const triple<OBAtom*, OBAtom*, OBAtom*> t2)
const {
150 return (t1.second == t2.second) &&
151 ((t1.first == t2.first && t1.third == t2.third) ||
152 (t1.first == t2.third && t1.third == t2.first));
156 OBMol* OpenMDFormat::createMolFromFragment(OBMol& mol,
157 vector<int>& fragment) {
158 OBMol* newMol =
new OBMol();
160 newMol->ReserveAtoms(fragment.size());
161 newMol->BeginModify();
162 for (vector<int>::iterator i = fragment.begin(); i != fragment.end(); ++i) {
163 OBAtom* newAtom = newMol->NewAtom();
164 *newAtom = *mol.GetAtom(*i);
168 newMol->ConnectTheDots();
169 newMol->PerceiveBondOrders();
174 void OpenMDFormat::WriteMDFile(vector<OBMol*> mols, vector<int> numMols,
175 ostream& os, OBMol& mol,
176 vector<int>& indices) {
177 std::string molPrefix(
"MolName");
180 const int BUFFLEN = 1024;
181 char buffer[BUFFLEN];
182 string str, str1, str2, str3;
183 bool molIsWater =
false;
185 double min_x, max_x, min_y, max_y, min_z, max_z;
187 os <<
"<OpenMD version=2>" << endl;
188 os <<
" <MetaData>" << endl << endl;
190 for (i = 0; i < mols.size(); ++i) {
191 OBMol* pmol = mols[i];
192 map<OBAtom*, int> atomMap;
195 FOR_RESIDUES_OF_MOL(residue, *pmol) {
196 if (residue->GetName().compare(
"HOH") == 0) { molIsWater =
true; }
201 os <<
"#include \"water.omd\";\n";
202 pmol->SetTitle(
"HOH");
204 os <<
"molecule {\n";
205 snprintf(buffer, BUFFLEN,
"%u", i);
206 os <<
" name = \"" << molPrefix << buffer <<
"\";\n";
209 FOR_ATOMS_OF_MOL(atom, *pmol) {
210 str = atom->GetType();
212 r = atom->GetResidue();
217 resName = r->GetName();
219 if (resName.compare(
"NULL") == 0 || resName.compare(
"LIG") == 0 ||
220 resName.compare(
"UNL") == 0 || resName.compare(
"UNK") == 0) {
224 ttab.SetFromType(
"INT");
225 ttab.SetToType(
"INT");
226 ttab.Translate(str1, str);
234 str = r->GetAtomID(&*atom);
238 if (resName.compare(
"ARG") == 0) {
239 if (str.compare(
"NH1") == 0 || str.compare(
"NH2") == 0) {
243 if (resName.compare(
"VAL") == 0) {
244 if (str.compare(
"CG1") == 0 || str.compare(
"CG2") == 0) {
248 if (resName.compare(
"LEU") == 0) {
249 if (str.compare(
"CD1") == 0 || str.compare(
"CD2") == 0) {
253 if (resName.compare(
"ASP") == 0) {
254 if (str.compare(
"OD1") == 0 || str.compare(
"OD2") == 0) {
258 if (resName.compare(
"GLU") == 0) {
259 if (str.compare(
"OE1") == 0 || str.compare(
"OE2") == 0) {
263 if (resName.compare(
"TYR") == 0) {
264 if (str.compare(
"CD1") == 0 || str.compare(
"CD2") == 0) {
267 if (str.compare(
"CE1") == 0 || str.compare(
"CE2") == 0) {
272 if ((&*atom)->GetAtomicNum() == 1) {
273 FOR_NBORS_OF_ATOM(nbr, *atom) {
274 str2 = r->GetAtomID(&*nbr);
275 size_t startpos = str2.find_first_not_of(
" ");
276 size_t endpos = str2.find_last_not_of(
" ");
277 if ((endpos - startpos) < 1) {
283 if (str2.compare(
"OH") == 0) {
288 str3 = str2.substr(startpos + 1, endpos - startpos);
295 if (resName.compare(
"ARG") == 0) {
296 if (str.compare(
"HH1") == 0 || str.compare(
"HH2") == 0) {
300 if (resName.compare(
"VAL") == 0) {
301 if (str.compare(
"HG1") == 0 || str.compare(
"HG2") == 0) {
305 if (resName.compare(
"LEU") == 0) {
306 if (str.compare(
"HD1") == 0 || str.compare(
"HD2") == 0) {
310 if (resName.compare(
"TYR") == 0) {
311 if (str.compare(
"HD1") == 0 || str.compare(
"HD2") == 0) {
314 if (str.compare(
"HE1") == 0 || str.compare(
"HE2") == 0) {
322 size_t startpos = str.find_first_not_of(
" ");
323 size_t endpos = str.find_last_not_of(
" ");
324 str = str.substr(startpos, endpos - startpos + 1);
325 str1 = resName +
"-" + str;
327 os <<
" atom[" << ai <<
"] { ";
329 <<
"\"" << str1 <<
"\""
331 os <<
"position( " << (&*atom)->GetX() <<
", " << (&*atom)->GetY()
332 <<
", " << (&*atom)->GetZ() <<
");";
334 atomMap[&(*atom)] = ai++;
344 FOR_BONDS_OF_MOL(bond, *pmol) {
345 a = bond->GetBeginAtom();
346 b = bond->GetEndAtom();
350 bo = bond->GetBondOrder();
351 if (bond->IsAromatic()) bo = 1.5;
355 if ((a->GetType()[2] ==
'R' && b->GetType()[2] ==
'R') &&
356 (a->ExplicitHydrogenCount() == 1 &&
357 b->ExplicitHydrogenCount() == 1))
359 if (bond->IsAmide()) bo = 1.41;
364 os <<
"members(" << ai <<
", " << bi <<
"); ";
366 os <<
"members(" << bi <<
", " << ai <<
"); ";
368 if (bo != 1) os <<
"bondOrder = " << bo <<
"; ";
382 for (i = 0; i < mols.size(); ++i) {
383 OBMol* pmol = mols[i];
384 os <<
"component{" << endl;
385 if (std::string(pmol->GetTitle()).compare(
"HOH") == 0) {
388 <<
"; // change to appropriate water model" << endl;
390 snprintf(buffer, BUFFLEN,
"%u", i);
391 os <<
" type = " << molPrefix << buffer <<
";" << endl;
393 os <<
" nMol = " << numMols[i] <<
";" << endl;
397 os <<
" </MetaData>" << endl;
398 os <<
" <Snapshot>" << endl;
399 os <<
" <FrameData>" << endl;
401 snprintf(buffer, BUFFLEN,
" Time: %.10g", 0.0);
403 os << buffer << endl;
405 CalcBoundingBox(mol, min_x, max_x, min_y, max_y, min_z, max_z);
410 " Hmat: {{ %.10g, %.10g, %.10g }, { %.10g, %.10g, %.10g }, { "
413 max_x - min_x, 0.0, 0.0, 0.0, max_y - min_y, 0.0, 0.0, 0.0,
416 os << buffer << endl;
417 os <<
" </FrameData>" << endl;
418 os <<
" <StuntDoubles>" << endl;
422 for (vector<int>::iterator i = indices.begin(); i != indices.end(); ++i) {
423 atom = mol.GetAtom(*i);
424 snprintf(buffer, BUFFLEN,
425 "%10d %7s %18.10g %18.10g %18.10g %13e %13e %13e", *i - 1,
"pv",
426 atom->GetX(), atom->GetY(), atom->GetZ(), 0.0, 0.0, 0.0);
427 os << buffer << endl;
429 os <<
" </StuntDoubles>" << endl;
430 os <<
" </Snapshot>" << endl;
431 os <<
"</OpenMD>" << endl;
434 void OpenMDFormat::CalcBoundingBox(OBMol& mol,
double& min_x,
double& max_x,
435 double& min_y,
double& max_y,
436 double& min_z,
double& max_z) {
446 for (
unsigned int i = 1; i <= mol.NumAtoms(); ++i) {
448 OBAtom* atom = mol.GetAtom(i);
451 if (atom->GetX() < min_x) min_x = atom->GetX();
452 if (atom->GetX() > max_x) max_x = atom->GetX();
455 if (atom->GetY() < min_y) min_y = atom->GetY();
456 if (atom->GetY() > max_y) max_y = atom->GetY();
459 if (atom->GetZ() < min_z) min_z = atom->GetZ();
460 if (atom->GetZ() > max_z) max_z = atom->GetZ();