ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/openbabel/xyzformat.cpp
Revision: 2440
Committed: Wed Nov 16 19:42:11 2005 UTC (18 years, 9 months ago) by tim
File size: 8514 byte(s)
Log Message:
adding openbabel

File Contents

# User Rev Content
1 tim 2440 /**********************************************************************
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    
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation version 2 of the License.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14     ***********************************************************************/
15    
16     #include "mol.hpp"
17     #include "obconversion.hpp"
18     #include "obmolecformat.hpp"
19    
20     #ifdef HAVE_SSTREAM
21     #include <sstream>
22     #else
23     #include <strstream>
24     #endif
25    
26     using namespace std;
27     namespace OpenBabel
28     {
29    
30     class XYZFormat : public OBMoleculeFormat
31     {
32     public:
33     //Register this format type ID
34     XYZFormat()
35     {
36     OBConversion::RegisterFormat("xyz", this, "chemical/x-xyz");
37     }
38    
39     virtual const char* Description() //required
40     {
41     return
42     "XYZ cartesian coordinates format\n \
43     Read Options e.g. -as\n\
44     s Output single bonds only\n\
45     b Disable bonding entirely\n\n";
46     };
47    
48     virtual const char* SpecificationURL()
49     {return "http://openbabel.sourceforge.net/formats/xyz.shtml";}; //optional
50    
51     virtual const char* GetMIMEType()
52     { return "chemical/x-xyz"; };
53    
54     //*** This section identical for most OBMol conversions ***
55     ////////////////////////////////////////////////////
56     /// The "API" interface functions
57     virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
58     virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
59     };
60     //***
61    
62     //Make an instance of the format class
63     XYZFormat theXYZFormat;
64    
65     /////////////////////////////////////////////////////////////////
66     bool XYZFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
67     {
68     OBMol* pmol = dynamic_cast<OBMol*>(pOb);
69     if(pmol==NULL)
70     return false;
71    
72     //Define some references so we can use the old parameter names
73     istream &ifs = *pConv->GetInStream();
74     OBMol &mol = *pmol;
75     const char* title = pConv->GetTitle();
76     char buffer[BUFF_SIZE];
77    
78     #ifdef HAVE_SSTREAM
79     stringstream errorMsg;
80     #else
81     strstream errorMsg;
82     #endif
83    
84     unsigned int natoms; // [ejk] assumed natoms could not be -ve
85    
86     if (!ifs.getline(buffer,BUFF_SIZE))
87     {
88     obErrorLog.ThrowError(__FUNCTION__,
89     "Problems reading an XYZ file: Cannot read the first line.", obWarning);
90     return(false);
91     }
92    
93     if (sscanf(buffer, "%d", &natoms) == 0 || !natoms)
94     {
95     obErrorLog.ThrowError(__FUNCTION__,
96     "Problems reading an XYZ file: The first line must contain the number of atoms.", obWarning);
97     return(false);
98     }
99    
100     mol.ReserveAtoms(natoms);
101    
102     // The next line contains a title string for the molecule. Use this
103     // as the title for the molecule if the line is not
104     // empty. Otherwise, use the title given by the calling function.
105     if (!ifs.getline(buffer,BUFF_SIZE))
106     {
107     obErrorLog.ThrowError(__FUNCTION__,
108     "Problems reading an XYZ file: Could not read the second line (title/comments).", obWarning);
109     return(false);
110     }
111     if (strlen(buffer) != 0)
112     mol.SetTitle(buffer);
113     else
114     mol.SetTitle(title);
115    
116     mol.BeginModify();
117    
118     // The next lines contain four items each, separated by white
119     // spaces: the atom type, and the coordinates of the atom
120     vector<string> vs;
121     for (unsigned int i = 1; i <= natoms; i ++)
122     {
123     if (!ifs.getline(buffer,BUFF_SIZE))
124     {
125     errorMsg << "Problems reading an XYZ file: "
126     << "Could not read line #" << i+2 << ", file error." << endl
127     << " According to line one, there should be " << natoms
128     << " atoms, and therefore " << natoms+2 << " lines in the file.";
129    
130     obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
131     return(false);
132     }
133     tokenize(vs,buffer);
134     if (vs.size() != 4)
135     {
136     errorMsg << "Problems reading an XYZ file: "
137     << "Could not read line #" << i+2 << "." << endl
138     << "OpenBabel found the line '" << buffer << "'" << endl
139     << "According to the specifications, this line should contain exactly 4 entries, separated by white space." << endl
140     << "However, OpenBabel found " << vs.size() << " items.";
141    
142     obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
143     return(false);
144     }
145    
146     // Atom Type: get the atomic number from the element table, using
147     // the first entry in the currently read line. If the entry makes
148     // sense, set the atomic number and leave the atomic type open
149     // (the type is then later faulted in when atom->GetType() is
150     // called). If the entry does not make sense to use, set the atom
151     // type manually, assuming that the author of the xyz-file had
152     // something "special" in mind.
153     OBAtom *atom = mol.NewAtom();
154     int atomicNum = etab.GetAtomicNum(vs[0].c_str());
155     atom->SetAtomicNum(atomicNum); //set atomic number, or '0' if the atom type is not recognized
156     if (atomicNum == 0)
157     atom->SetType(vs[0]);
158    
159     // Read the atom coordinates
160     char *endptr;
161     double x = strtod((char*)vs[1].c_str(),&endptr);
162     if (endptr == (char*)vs[1].c_str())
163     {
164     errorMsg << "Problems reading an XYZ file: "
165     << "Could not read line #" << i+2 << "." << endl
166     << "OpenBabel found the line '" << buffer << "'" << endl
167     << "According to the specifications, this line should contain exactly 4 entries, separated by white space." << endl
168     << "OpenBabel could not interpret item #1 as a number.";
169    
170     obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
171     return(false);
172     }
173     double y = strtod((char*)vs[2].c_str(),&endptr);
174     if (endptr == (char*)vs[2].c_str())
175     {
176     errorMsg << "Problems reading an XYZ file: "
177     << "Could not read line #" << i+2 << "." << endl
178     << "OpenBabel found the line '" << buffer << "'" << endl
179     << "According to the specifications, this line should contain exactly 4 entries, separated by white space." << endl
180     << "OpenBabel could not interpret item #2 as a number.";
181    
182     obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
183     return(false);
184     }
185     double z = strtod((char*)vs[3].c_str(),&endptr);
186     if (endptr == (char*)vs[3].c_str())
187     {
188     errorMsg << "Problems reading an XYZ file: "
189     << "Could not read line #" << i+2 << "." << endl
190     << "OpenBabel found the line '" << buffer << "'" << endl
191     << "According to the specifications, this line should contain exactly 4 entries, separated by white space." << endl
192     << "OpenBabel could not interpret item #3 as a number.";
193    
194     obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
195     return(false);
196     }
197     atom->SetVector(x,y,z); //set coordinates
198     }
199    
200     // clean out any remaining blank lines
201     while(ifs.peek() != EOF && ifs.good() &&
202     (ifs.peek() == '\n' || ifs.peek() == '\r'))
203     ifs.getline(buffer,BUFF_SIZE);
204    
205     if (!pConv->IsOption("b",OBConversion::INOPTIONS))
206     mol.ConnectTheDots();
207     if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS))
208     mol.PerceiveBondOrders();
209    
210     mol.EndModify();
211    
212     return(true);
213     }
214    
215     ////////////////////////////////////////////////////////////////
216    
217     bool XYZFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
218     {
219     OBMol* pmol = dynamic_cast<OBMol*>(pOb);
220     if(pmol==NULL)
221     return false;
222    
223     //Define some references so we can use the old parameter names
224     ostream &ofs = *pConv->GetOutStream();
225     OBMol &mol = *pmol;
226    
227     unsigned int i;
228     char buffer[BUFF_SIZE];
229    
230     sprintf(buffer,"%d", mol.NumAtoms());
231     ofs << buffer << endl;
232     sprintf(buffer,"%s\tEnergy: %15.7f", mol.GetTitle(), mol.GetEnergy());
233     ofs << buffer << endl;
234    
235     OBAtom *atom;
236     string str,str1;
237     for(i = 1;i <= mol.NumAtoms(); i++)
238     {
239     atom = mol.GetAtom(i);
240     sprintf(buffer,"%3s%15.5f%15.5f%15.5f",
241     etab.GetSymbol(atom->GetAtomicNum()),
242     atom->GetX(),
243     atom->GetY(),
244     atom->GetZ());
245     ofs << buffer << endl;
246     }
247    
248     return(true);
249     }
250    
251     } //namespace OpenBabel