ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/applications/atom2md/openmdformat.cpp
Revision: 1390
Committed: Wed Nov 25 20:02:06 2009 UTC (15 years, 5 months ago) by gezelter
Original Path: trunk/src/applications/atom2md/openmdformat.cpp
File size: 15166 byte(s)
Log Message:
Almost all of the changes necessary to create OpenMD out of our old
project (OOPSE-4)

File Contents

# User Rev Content
1 gezelter 1390 /**********************************************************************
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 << "}\n";
357     atomMap[&(*atom)] = ai++;
358     }
359     os << "\n";
360    
361     //bond
362    
363     int b1, b2;
364     FOR_BONDS_OF_MOL(bond, *pmol ) {
365     b1 = atomMap[bond->GetBeginAtom()];
366     b2 = atomMap[bond->GetEndAtom()];
367    
368     os << " bond { ";
369    
370     if (b1 < b2)
371     os << "members(" << b1 << ", " << b2 << "); ";
372     else
373     os << "members(" << b2 << ", " << b1 << "); ";
374    
375     os << "}" << endl;
376     }
377    
378     os << endl;
379    
380     os << "}" << endl;
381     os << endl;
382     }
383     }
384    
385     os << endl;
386    
387     for(i=0; i < mols.size(); ++i) {
388     OBMol* pmol = mols[i];
389     os << "component{" << endl;
390     if (std::string(pmol->GetTitle()).compare("HOH") == 0) {
391     os << " type = " << "HOH" << ";" << endl;
392     } else {
393     sprintf(buffer, "%d", i);
394     os << " type = " << molPrefix << buffer << ";" << endl;
395     }
396     os << " nMol = " << numMols[i]<< ";" << endl;
397     os << "}" << endl;
398     }
399    
400     os << " </MetaData>" << endl;
401     os << " <Snapshot>" << endl;
402     os << " <FrameData>" << endl;
403    
404     sprintf(buffer, " Time: %.10g", 0.0);
405    
406     os << buffer << endl;
407    
408     CalcBoundingBox(mol, min_x, max_x, min_y, max_y, min_z, max_z);
409    
410     // still to do: should compute a bounding box here
411     sprintf(buffer, " Hmat: {{ %.10g, %.10g, %.10g }, { %.10g, %.10g, %.10g }, { %.10g, %.10g, %.10g }}",
412     max_x - min_x, 0.0, 0.0, 0.0, max_y - min_y, 0.0, 0.0, 0.0, max_z - min_z);
413    
414     os << buffer << endl;
415     os << " </FrameData>" << endl;
416     os << " <StuntDoubles>" << endl;
417    
418     OBAtom *atom;
419    
420     // still to do: intercept waters and recompute pvqj lines
421    
422     for(vector<int>::iterator i = indices.begin();i != indices.end(); ++i) {
423     atom = mol.GetAtom(*i);
424     sprintf(buffer, "%10d %7s %18.10g %18.10g %18.10g %13e %13e %13e", *i - 1,
425     "pv", atom->GetX(), atom->GetY(), atom->GetZ(), 0.0, 0.0, 0.0);
426     os << buffer << endl;
427     }
428     os << " </StuntDoubles>" << endl;
429     os << " </Snapshot>" << endl;
430     os << "</OpenMD>" << endl;
431     }
432    
433     void OpenMDFormat::CalcBoundingBox(OBMol &mol,
434     double &min_x, double &max_x,
435     double &min_y, double &max_y,
436     double &min_z, double &max_z
437     )
438     {
439     /* ---- Init bounding-box variables ---- */
440     min_x = (double) 0.0;
441     max_x = (double) 0.0;
442     min_y = (double) 0.0;
443     max_y = (double) 0.0;
444     min_z = (double) 0.0;
445     max_z = (double) 0.0;
446    
447     /* ---- Check all atoms ---- */
448     for(unsigned int i = 1; i <= mol.NumAtoms(); ++i)
449     {
450    
451     /* ---- Get a pointer to ith atom ---- */
452     OBAtom *atom = mol.GetAtom(i);
453    
454     /* ---- Check for minimal/maximal x-position ---- */
455     if (atom -> GetX() < min_x)
456     min_x = atom -> GetX();
457     if (atom -> GetX() > max_x)
458     max_x = atom -> GetX();
459    
460     /* ---- Check for minimal/maximal y-position ---- */
461     if (atom -> GetY() < min_y)
462     min_y = atom -> GetY();
463     if (atom -> GetY() > max_y)
464     max_y = atom -> GetY();
465    
466     /* ---- Check for minimal/maximal z-position ---- */
467     if (atom -> GetZ() < min_z)
468     min_z = atom -> GetZ();
469     if (atom -> GetZ() > max_z)
470     max_z = atom -> GetZ();
471    
472     }
473     }
474     } //namespace OpenBabel
475