ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/applications/atom2md/openmdformat.cpp
Revision: 1397
Committed: Mon Dec 7 22:11:59 2009 UTC (15 years, 4 months ago) by gezelter
File size: 15280 byte(s)
Log Message:
more changes to fix build process and divorce ourselves from CVS

File Contents

# Content
1 /**********************************************************************
2 Copyright (C) 2000 by OpenEye Scientific Software, Inc.
3 Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
4 Some portions Copyright (C) 2004 by Chris Morley
5 Some portions Copyright (C) 2008 by J. Daniel Gezelter
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation version 2 of the License.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 ***********************************************************************/
16
17 #include <openbabel/babelconfig.h>
18 #include <openbabel/obmolecformat.h>
19 #include <openbabel/obiter.h>
20 #include <openbabel/mol.h>
21 #include <openbabel/chains.h>
22 #include <openbabel/data.h>
23 #include <fstream>
24
25 #include "utils/StringUtils.hpp"
26
27 using namespace std;
28 namespace OpenBabel
29 {
30
31 class OpenMDFormat : public OBMoleculeFormat
32 {
33 public:
34 //Register this format type ID
35 OpenMDFormat()
36 {
37 OBConversion::RegisterFormat("md",this);
38 }
39
40 virtual const char* Description() //required
41 {
42 return
43 "OpenMD combined meta-data / cartesian coordinates format\nNo comments yet\n";
44 };
45
46 virtual const char* SpecificationURL()
47 {return "http://www.openmd.net";}; //optional
48
49 virtual const char* GetMIMEType()
50 {return "chemical/x-md"; };
51
52 virtual unsigned int Flags()
53 {
54 return NOTREADABLE | WRITEONEONLY;
55 }
56
57 virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
58
59 private:
60 bool AreSameFragments(OBMol& mol, vector<int>& frag1, vector<int>& frag2);
61 OBMol* createMolFromFragment(OBMol& mol, vector<int>& fragment);
62 void WriteMDFile(vector<OBMol*> mols, vector<int> numMols, ostream& os,
63 OBMol& mol, vector<int>& indices);
64 void CalcBoundingBox(OBMol &mol,
65 double &min_x, double &max_x,
66 double &min_y, double &max_y,
67 double &min_z, double &max_z);
68
69 };
70
71 //Make an instance of the format class
72 OpenMDFormat theOpenMDFormat;
73
74 bool OpenMDFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) {
75 OBMol* pmol = dynamic_cast<OBMol*>(pOb);
76 if(pmol==NULL)
77 return false;
78
79 vector<vector<int> > fragmentLists;
80 pmol->ContigFragList(fragmentLists);
81 OBBitVec unused;
82 vector<bool> used(fragmentLists.size(), 0);
83 vector<vector<int> > molecules;
84 vector<int> indices;
85 for(int i =0; i < used.size(); ++i) {
86 if (used[i])
87 continue;
88
89 used[i] = true;
90 vector<int> sameMolTypes;
91 sameMolTypes.push_back(i);
92 indices.insert(indices.end(), fragmentLists[i].begin(),
93 fragmentLists[i].end());
94 for (int j = i + 1;j < used.size(); ++j) {
95 if (used[j])
96 continue;
97
98 if (AreSameFragments(*pmol, fragmentLists[i], fragmentLists[j])) {
99 sameMolTypes.push_back(j);
100 indices.insert(indices.end(), fragmentLists[j].begin(),
101 fragmentLists[j].end());
102 used[j]=true;
103 }
104 }
105 molecules.push_back(sameMolTypes);
106 }
107
108 vector<OBMol*> mdMols;
109 vector<int> numMols;
110 for(vector<vector<int> >::iterator i = molecules.begin();
111 i != molecules.end(); ++i) {
112
113 mdMols.push_back(createMolFromFragment(*pmol,
114 fragmentLists[i->front()]));
115 numMols.push_back((*i).size());
116 }
117
118 string OutputFileName = pConv->GetInFilename();
119 size_t pos = OutputFileName.rfind(".");
120 if(pos!=string::npos)
121 OutputFileName = OutputFileName.substr(0, pos) + ".md";
122 else
123 OutputFileName += ".md";
124
125 ofstream ofs(OutputFileName.c_str());
126 if(!ofs) {
127 cerr << "Cannot write to " << OutputFileName <<endl;
128 return false;
129 }
130
131 WriteMDFile(mdMols, numMols, ofs, *pmol, indices);
132
133 for(vector<OBMol*>::iterator i = mdMols.begin(); i != mdMols.end(); ++i) {
134 delete *i;
135 }
136
137 return(true);
138 }
139
140 bool OpenMDFormat::AreSameFragments(OBMol& mol, vector<int>& frag1,
141 vector<int>& frag2) {
142 if (frag1.size() != frag2.size())
143 return false;
144
145 // Exact graph matching is an NP complete problem.
146 // This just matches all of the atom atomic numbers and may falsely
147 // detect identical fragments which aren't really identical.
148 // @todo using sparse matrix to store the connectivities
149
150 for (unsigned int i =0 ; i < frag1.size(); ++i) {
151 OBAtom* atom1 = mol.GetAtom(frag1[i]);
152 OBAtom* atom2 = mol.GetAtom(frag2[i]);
153
154 if (atom1->GetAtomicNum() != atom2->GetAtomicNum())
155 return false;
156
157 }
158 return true;
159 }
160
161 struct SameAngle {
162 bool operator()(const triple<OBAtom*,OBAtom*,OBAtom*> t1,
163 const triple<OBAtom*,OBAtom*,OBAtom*> t2) const {
164 return (t1.second == t2.second) && ( (t1.first == t2.first && t1.third == t2.third) || (t1.first == t2.third && t1.third == t2.first));
165 }
166 };
167
168
169 OBMol* OpenMDFormat::createMolFromFragment(OBMol& mol,
170 vector<int>& fragment) {
171
172 OBMol* newMol = new OBMol();
173 newMol->ReserveAtoms(fragment.size());
174 newMol->BeginModify();
175 for(vector<int>::iterator i = fragment.begin(); i != fragment.end(); ++i) {
176 OBAtom* newAtom = newMol->NewAtom();
177 *newAtom = *mol.GetAtom(*i);
178 }
179
180 newMol->EndModify();
181 newMol->ConnectTheDots();
182 newMol->PerceiveBondOrders();
183
184 return newMol;
185 }
186
187 void OpenMDFormat::WriteMDFile(vector<OBMol*> mols, vector<int> numMols,
188 ostream& os, OBMol& mol,
189 vector<int>& indices) {
190
191 std::string molPrefix("MolName");
192 std::string resName;
193 unsigned int i;
194 const int BUFFLEN = 1024;
195 char buffer[BUFFLEN];
196 string str, str1, str2, str3;
197 OBAtom *a, *b, *c, *d;
198 bool molIsWater = false;
199 OBResidue *r;
200 int resKey, myserial;
201 char type_name[10];
202 char *element_name;
203 int res_num;
204 OBChainsParser* chainParser = new OBChainsParser();
205 double min_x, max_x, min_y, max_y, min_z, max_z; /* Edges of bounding box */
206
207 os << "<OpenMD version=1>" << endl;
208 os << " <MetaData>" << endl << endl;
209
210 for(i = 0; i < mols.size(); ++i) {
211 OBMol* pmol = mols[i];
212 map<OBAtom*, int> atomMap;
213
214 chainParser->PerceiveChains(*pmol, false);
215 molIsWater = false;
216 FOR_RESIDUES_OF_MOL(residue, *pmol) {
217 std::cerr << "residue = " << residue->GetName() << "\n";
218 if (residue->GetName().compare("HOH") == 0) {
219 molIsWater = true;
220 }
221 }
222
223 if (molIsWater) {
224 // water include files define all of the known water types
225 os << "#include \"water.md\";\n";
226 pmol->SetTitle("HOH");
227 } else {
228
229 os << "molecule {\n";
230 sprintf(buffer, "%d", i);
231 os << " name = \"" << molPrefix << buffer << "\";\n";
232
233 int ai = 0;
234 FOR_ATOMS_OF_MOL(atom, *pmol ) {
235 str = atom->GetType();
236 r = atom->GetResidue();
237
238 if (r == NULL)
239 resName = "NULL";
240 else
241 resName = r->GetName();
242
243 if (resName.compare("NULL") ==0 ||
244 resName.compare("LIG") == 0 ||
245 resName.compare("UNK") == 0) {
246 // Either couldn't find a residue at all or couldn't find a
247 // reasonable residue name to use. We'll punt and use
248 // OpenBabel's internal atom typing:
249 ttab.SetFromType("INT");
250 ttab.SetToType("INT");
251 ttab.Translate(str1, str);
252 } else {
253
254 // If we know what residue we've got, the specific atom name can
255 // be used to help specify partial charges.
256
257 //resdat.SetResName(resName);
258
259 // atom type from residue:
260 str = r->GetAtomID(&*atom);
261
262 // arginine has separate indices for chemically-identical
263 // nitrogen atoms:
264 if (resName.compare("ARG") == 0) {
265 if (str.compare("NH1") == 0 || str.compare("NH2") == 0) {
266 str = "NH";
267 }
268 }
269 if (resName.compare("VAL") == 0) {
270 if (str.compare("CG1") == 0 || str.compare("CG2") == 0) {
271 str = "CG";
272 }
273 }
274 if (resName.compare("LEU") == 0) {
275 if (str.compare("CD1") == 0 || str.compare("CD2") == 0) {
276 str = "CD";
277 }
278 }
279 if (resName.compare("ASP") == 0) {
280 if (str.compare("OD1") == 0 || str.compare("OD2") == 0) {
281 str = "OD";
282 }
283 }
284 if (resName.compare("GLU") == 0) {
285 if (str.compare("OE1") == 0 || str.compare("OE2") == 0) {
286 str = "OE";
287 }
288 }
289 if (resName.compare("TYR") == 0) {
290 if (str.compare("CD1") == 0 || str.compare("CD2") == 0) {
291 str = "CD";
292 }
293 if (str.compare("CE1") == 0 || str.compare("CE2") == 0) {
294 str = "CE";
295 }
296 }
297
298
299 if ((&*atom)->IsHydrogen()) {
300 FOR_NBORS_OF_ATOM(nbr, *atom) {
301 str2 = r->GetAtomID(&*nbr);
302 size_t startpos = str2.find_first_not_of(" ");
303 size_t endpos = str2.find_last_not_of(" ");
304 if ((endpos - startpos) < 1) {
305 // if the bonded atom type has only one character (i.e. N)
306 // then the hydrogen will be labeled "HN" to show what
307 // kind of proton it is:
308 str3 = str2;
309 } else {
310 if (str2.compare("OH") == 0) {
311 str3 = "O";
312 } else {
313 // When the bonded atom type is more specific, we drop
314 // the first character: i.e. H bonded to OG1 is HG1 type:
315 str3 = str2.substr(startpos+1, endpos-startpos);
316 }
317 }
318 str = "H" + str3;
319 }
320 // same problem with arginine NH atoms, but now for connected hydrogens
321 if (resName.compare("ARG") == 0) {
322 if (str.compare("HH1") == 0 || str.compare("HH2") == 0) {
323 str = "HH";
324 }
325 }
326 if (resName.compare("VAL") == 0) {
327 if (str.compare("HG1") == 0 || str.compare("HG2") == 0) {
328 str = "HG";
329 }
330 }
331 if (resName.compare("LEU") == 0) {
332 if (str.compare("HD1") == 0 || str.compare("HD2") == 0) {
333 str = "HD";
334 }
335 }
336 if (resName.compare("TYR") == 0) {
337 if (str.compare("HD1") == 0 || str.compare("HD2") == 0) {
338 str = "HD";
339 }
340 if (str.compare("HE1") == 0 || str.compare("HE2") == 0) {
341 str = "HE";
342 }
343 }
344
345 }
346
347 // atom type from residue table:
348 //resdat.LookupType(str, str2, hyb);
349 size_t startpos = str.find_first_not_of(" ");
350 size_t endpos = str.find_last_not_of(" ");
351 str = str.substr( startpos, endpos-startpos+1 );
352 str1 = resName + "-" + str;
353 }
354 os << " atom[" << ai << "] { ";
355 os << "type = " << "\"" << str1 << "\"" << "; ";
356 os << "position( " << (&*atom)->GetX() << ", " << (&*atom)->GetY() << ", " << (&*atom)->GetZ() << ");";
357 os << "}\n";
358 atomMap[&(*atom)] = ai++;
359 }
360 os << "\n";
361
362 //bond
363
364 int b1, b2;
365 FOR_BONDS_OF_MOL(bond, *pmol ) {
366 b1 = atomMap[bond->GetBeginAtom()];
367 b2 = atomMap[bond->GetEndAtom()];
368
369 os << " bond { ";
370
371 if (b1 < b2)
372 os << "members(" << b1 << ", " << b2 << "); ";
373 else
374 os << "members(" << b2 << ", " << b1 << "); ";
375
376 os << "}" << endl;
377 }
378
379 os << endl;
380
381 os << "}" << endl;
382 os << endl;
383 }
384 }
385
386 os << endl;
387
388 for(i=0; i < mols.size(); ++i) {
389 OBMol* pmol = mols[i];
390 os << "component{" << endl;
391 if (std::string(pmol->GetTitle()).compare("HOH") == 0) {
392 os << " type = " << "HOH" << ";" << endl;
393 } else {
394 sprintf(buffer, "%d", i);
395 os << " type = " << molPrefix << buffer << ";" << endl;
396 }
397 os << " nMol = " << numMols[i]<< ";" << endl;
398 os << "}" << endl;
399 }
400
401 os << " </MetaData>" << endl;
402 os << " <Snapshot>" << endl;
403 os << " <FrameData>" << endl;
404
405 sprintf(buffer, " Time: %.10g", 0.0);
406
407 os << buffer << endl;
408
409 CalcBoundingBox(mol, min_x, max_x, min_y, max_y, min_z, max_z);
410
411 // still to do: should compute a bounding box here
412 sprintf(buffer, " Hmat: {{ %.10g, %.10g, %.10g }, { %.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, max_z - min_z);
414
415 os << buffer << endl;
416 os << " </FrameData>" << endl;
417 os << " <StuntDoubles>" << endl;
418
419 OBAtom *atom;
420
421 // still to do: intercept waters and recompute pvqj lines
422
423 for(vector<int>::iterator i = indices.begin();i != indices.end(); ++i) {
424 atom = mol.GetAtom(*i);
425 sprintf(buffer, "%10d %7s %18.10g %18.10g %18.10g %13e %13e %13e", *i - 1,
426 "pv", atom->GetX(), atom->GetY(), atom->GetZ(), 0.0, 0.0, 0.0);
427 os << buffer << endl;
428 }
429 os << " </StuntDoubles>" << endl;
430 os << " </Snapshot>" << endl;
431 os << "</OpenMD>" << endl;
432 }
433
434 void OpenMDFormat::CalcBoundingBox(OBMol &mol,
435 double &min_x, double &max_x,
436 double &min_y, double &max_y,
437 double &min_z, double &max_z
438 )
439 {
440 /* ---- Init bounding-box variables ---- */
441 min_x = (double) 0.0;
442 max_x = (double) 0.0;
443 min_y = (double) 0.0;
444 max_y = (double) 0.0;
445 min_z = (double) 0.0;
446 max_z = (double) 0.0;
447
448 /* ---- Check all atoms ---- */
449 for(unsigned int i = 1; i <= mol.NumAtoms(); ++i)
450 {
451
452 /* ---- Get a pointer to ith atom ---- */
453 OBAtom *atom = mol.GetAtom(i);
454
455 /* ---- Check for minimal/maximal x-position ---- */
456 if (atom -> GetX() < min_x)
457 min_x = atom -> GetX();
458 if (atom -> GetX() > max_x)
459 max_x = atom -> GetX();
460
461 /* ---- Check for minimal/maximal y-position ---- */
462 if (atom -> GetY() < min_y)
463 min_y = atom -> GetY();
464 if (atom -> GetY() > max_y)
465 max_y = atom -> GetY();
466
467 /* ---- Check for minimal/maximal z-position ---- */
468 if (atom -> GetZ() < min_z)
469 min_z = atom -> GetZ();
470 if (atom -> GetZ() > max_z)
471 max_z = atom -> GetZ();
472
473 }
474 }
475 } //namespace OpenBabel
476