1 /**********************************************************************
2 Copyright (C) 2000-2006 by Geoffrey Hutchison
3 Some portions Copyright (C) 2004 by Chris Morley
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 ***********************************************************************/
14 #include <openbabel/babelconfig.h>
15 
16 #include <openbabel/obmolecformat.h>
17 #include <openbabel/mol.h>
18 #include <openbabel/atom.h>
19 #include <openbabel/bond.h>
20 #include <openbabel/obiter.h>
21 #include <openbabel/elements.h>
22 #include <openbabel/generic.h>
23 #include <cstdlib>
24 
25 using namespace std;
26 namespace OpenBabel
27 {
28 
29 #define BOHR_TO_ANGSTROM 0.529177249
30 #define ANGSTROM_TO_BOHR 1.889725989
31 
32 
33   class DMolFormat : public OBMoleculeFormat
34   {
35   public:
36     //Register this format type ID
DMolFormat()37     DMolFormat()
38     {
39       OBConversion::RegisterFormat("dmol",this);
40       OBConversion::RegisterFormat("outmol",this, "chemical/x-dmol");
41     }
42 
Description()43     virtual const char* Description() //required
44     {
45       return
46         "DMol3 coordinates format\n"
47         "Read Options e.g. -as\n"
48         "  s  Output single bonds only\n"
49         "  b  Disable bonding entirely\n\n";
50     };
51 
SpecificationURL()52     virtual const char* SpecificationURL()
53     { return "" ;}; //optional
54 
55     //Flags() can return be any the following combined by | or be omitted if none apply
56     // NOTREADABLE  READONEONLY  NOTWRITABLE  WRITEONEONLY
Flags()57     virtual unsigned int Flags()
58     {
59       return READONEONLY | WRITEONEONLY;
60     };
61 
62     //*** This section identical for most OBMol conversions ***
63     ////////////////////////////////////////////////////
64     /// The "API" interface functions
65     virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
66     virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
67   };
68   //***
69 
70   //Make an instance of the format class
71   DMolFormat theDMolFormat;
72 
73   /////////////////////////////////////////////////////////////////
ReadMolecule(OBBase * pOb,OBConversion * pConv)74   bool DMolFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
75   {
76 
77     OBMol* pmol = pOb->CastAndClear<OBMol>();
78     if (pmol == nullptr)
79       return false;
80 
81     //Define some references so we can use the old parameter names
82     istream &ifs = *pConv->GetInStream();
83     OBMol &mol = *pmol;
84     const char* title = pConv->GetTitle();
85 
86     char buffer[BUFF_SIZE];
87     string str;
88     double x,y,z;
89     OBAtom *atom;
90     vector3 v1,v2,v3;
91     vector<string> vs;
92 
93     ifs.getline(buffer,BUFF_SIZE);
94     while (strstr(buffer, "$coordinates") == nullptr &&
95            strstr(buffer, "$cell vectors") == nullptr)
96       {
97         if (ifs.peek() == EOF || !ifs.good())
98           return false;
99         ifs.getline(buffer,BUFF_SIZE);
100       }
101 
102     if (strstr(buffer, "$cell vectors") != nullptr)
103       {
104         ifs.getline(buffer,BUFF_SIZE);
105         tokenize(vs,buffer); // we really need to check that it's 3 entries only
106 	if (vs.size() < 3) return false; // timvdm 18/06/2008
107         x = atof((char*)vs[0].c_str()) * BOHR_TO_ANGSTROM;
108         y = atof((char*)vs[1].c_str()) * BOHR_TO_ANGSTROM;
109         z = atof((char*)vs[2].c_str()) * BOHR_TO_ANGSTROM;
110         v1.Set(x,y,z);
111         ifs.getline(buffer,BUFF_SIZE);
112         tokenize(vs,buffer);
113 	if (vs.size() < 3) return false; // timvdm 18/06/2008
114         x = atof((char*)vs[0].c_str()) * BOHR_TO_ANGSTROM;
115         y = atof((char*)vs[1].c_str()) * BOHR_TO_ANGSTROM;
116         z = atof((char*)vs[2].c_str()) * BOHR_TO_ANGSTROM;
117         v2.Set(x,y,z);
118         ifs.getline(buffer,BUFF_SIZE);
119         tokenize(vs,buffer);
120 	if (vs.size() < 3) return false; // timvdm 18/06/2008
121         x = atof((char*)vs[0].c_str()) * BOHR_TO_ANGSTROM;
122         y = atof((char*)vs[1].c_str()) * BOHR_TO_ANGSTROM;
123         z = atof((char*)vs[2].c_str()) * BOHR_TO_ANGSTROM;
124         v3.Set(x,y,z);
125 
126         OBUnitCell *uc = new OBUnitCell;
127         uc->SetOrigin(fileformatInput);
128         uc->SetData(v1,v2,v3);
129         mol.SetData(uc);
130 
131         ifs.getline(buffer,BUFF_SIZE); // next line
132       }
133 
134     mol.BeginModify();
135 
136     while (strstr(buffer, "$end") == nullptr)
137       {
138         if (!ifs.getline(buffer,BUFF_SIZE))
139           break;
140         tokenize(vs,buffer);
141         if (vs.size() != 4)
142           break;
143         atom = mol.NewAtom();
144         //set atomic number
145         atom->SetAtomicNum(OBElements::GetAtomicNum(vs[0].c_str()));
146         x = atof((char*)vs[1].c_str()) * BOHR_TO_ANGSTROM;
147         y = atof((char*)vs[2].c_str()) * BOHR_TO_ANGSTROM;
148         z = atof((char*)vs[3].c_str()) * BOHR_TO_ANGSTROM;
149         atom->SetVector(x,y,z); //set coordinates
150       }
151 
152     if (!pConv->IsOption("b",OBConversion::INOPTIONS))
153       mol.ConnectTheDots();
154     if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS))
155       mol.PerceiveBondOrders();
156 
157     // clean out any remaining blank lines
158     std::streampos ipos;
159     do
160     {
161       ipos = ifs.tellg();
162       ifs.getline(buffer,BUFF_SIZE);
163     }
164     while(strlen(buffer) == 0 && !ifs.eof() );
165     ifs.seekg(ipos);
166 
167     mol.EndModify();
168     mol.SetTitle(title);
169     return(true);
170   }
171 
172   ////////////////////////////////////////////////////////////////
173 
WriteMolecule(OBBase * pOb,OBConversion * pConv)174   bool DMolFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
175   {
176     OBMol* pmol = dynamic_cast<OBMol*>(pOb);
177     if (pmol == nullptr)
178       return false;
179 
180     //Define some references so we can use the old parameter names
181     ostream &ofs = *pConv->GetOutStream();
182     OBMol &mol = *pmol;
183 
184     unsigned int i;
185     char buffer[BUFF_SIZE];
186 
187     if (mol.HasData(OBGenericDataType::UnitCell))
188       {
189         OBUnitCell *uc = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell);
190         vector<vector3> v = uc->GetCellVectors();
191         vector3 v1;
192 
193         ofs << "$cell vectors" << endl;
194         v1 = v[0] * ANGSTROM_TO_BOHR;
195         snprintf(buffer, BUFF_SIZE,
196                  "%-3s% 27.14f% 20.14f% 20.14f","", v1.x(), v1.y(), v1.z());
197         ofs << buffer << endl;
198         v1 = v[1] * ANGSTROM_TO_BOHR;
199         snprintf(buffer, BUFF_SIZE,
200                  "%-3s% 27.14f% 20.14f% 20.14f","", v1.x(), v1.y(), v1.z());
201         ofs << buffer << endl;
202         v1 = v[2] * ANGSTROM_TO_BOHR;
203         snprintf(buffer, BUFF_SIZE,
204                  "%-3s% 27.14f% 20.14f% 20.14f","", v1.x(), v1.y(), v1.z());
205         ofs << buffer << endl;
206       }
207 
208     ofs << "$coordinates" << endl;
209 
210     OBAtom *atom;
211     for(i = 1;i <= mol.NumAtoms(); i++)
212       {
213         atom = mol.GetAtom(i);
214         snprintf(buffer, BUFF_SIZE, "%-3s% 27.14f% 20.14f% 20.14f",
215                  OBElements::GetSymbol(atom->GetAtomicNum()),
216                  atom->GetX() * ANGSTROM_TO_BOHR,
217                  atom->GetY() * ANGSTROM_TO_BOHR,
218                  atom->GetZ() * ANGSTROM_TO_BOHR);
219         ofs << buffer << endl;
220       }
221 
222     ofs << "$end" << endl;
223 
224     return(true);
225   }
226 
227 } //namespace OpenBabel
228