/src/openbabel/src/formats/cacaoformat.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc. |
3 | | Some portions Copyright (C) 2001-2006 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 | | #include <openbabel/babelconfig.h> |
16 | | |
17 | | #include <openbabel/obmolecformat.h> |
18 | | #include <openbabel/mol.h> |
19 | | #include <openbabel/atom.h> |
20 | | #include <openbabel/elements.h> |
21 | | #include <openbabel/generic.h> |
22 | | #include <openbabel/internalcoord.h> |
23 | | #include <openbabel/math/matrix3x3.h> |
24 | | #include <cstdlib> |
25 | | |
26 | | using namespace std; |
27 | | namespace OpenBabel |
28 | | { |
29 | | |
30 | | class CacaoFormat : public OBMoleculeFormat |
31 | | { |
32 | | public: |
33 | | //Register this format type ID |
34 | | CacaoFormat() |
35 | 6 | { |
36 | 6 | OBConversion::RegisterFormat("caccrt",this); |
37 | 6 | } |
38 | | |
39 | | const char* Description() override // required |
40 | 0 | { |
41 | 0 | return |
42 | 0 | "Cacao Cartesian format\n" |
43 | 0 | "Read Options e.g. -as\n" |
44 | 0 | " s Output single bonds only\n" |
45 | 0 | " b Disable bonding entirely\n\n"; |
46 | 0 | } |
47 | | |
48 | | const char* SpecificationURL() override |
49 | 0 | { return "http://www.chembio.uoguelph.ca/oakley/310/cacao/cacao.htm"; } // optional |
50 | | |
51 | | //Flags() can return be any the following combined by | or be omitted if none apply |
52 | | // NOTREADABLE READONEONLY NOTWRITABLE WRITEONEONLY |
53 | | unsigned int Flags() override |
54 | 10 | { |
55 | 10 | return READONEONLY | WRITEONEONLY; |
56 | 10 | } |
57 | | |
58 | | //////////////////////////////////////////////////// |
59 | | /// The "API" interface functions |
60 | | bool ReadMolecule(OBBase* pOb, OBConversion* pConv) override; |
61 | | bool WriteMolecule(OBBase* pOb, OBConversion* pConv) override; |
62 | | |
63 | | static void SetHilderbrandt(OBMol&,vector<OBInternalCoord*>&); |
64 | | }; |
65 | | |
66 | | //Make an instance of the format class |
67 | | CacaoFormat theCacaoFormat; |
68 | | |
69 | | ///////////////////////////////////////////////////////////////// |
70 | | bool CacaoFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv) |
71 | 1 | { |
72 | | |
73 | 1 | OBMol* pmol = pOb->CastAndClear<OBMol>(); |
74 | 1 | if (pmol == nullptr) |
75 | 0 | return false; |
76 | | |
77 | | //Define some references so we can use the old parameter names |
78 | 1 | istream &ifs = *pConv->GetInStream(); |
79 | 1 | OBMol &mol = *pmol; |
80 | 1 | mol.SetTitle( pConv->GetTitle()); //default title is the filename |
81 | | |
82 | 1 | char buffer[BUFF_SIZE]; |
83 | 1 | int natoms; |
84 | 1 | double A,B,C,Alpha,Beta,Gamma; |
85 | 1 | matrix3x3 m; |
86 | | |
87 | 1 | ifs.getline(buffer,BUFF_SIZE); |
88 | 1 | mol.SetTitle(buffer); |
89 | 1 | ifs.getline(buffer,BUFF_SIZE); |
90 | 1 | sscanf(buffer,"%d",&natoms); |
91 | | |
92 | 161 | while (ifs.getline(buffer,BUFF_SIZE) &&!EQn(buffer,"CELL",4)) |
93 | 160 | ; |
94 | | |
95 | 1 | if (!EQn(buffer,"CELL",4)) |
96 | 1 | return(false); |
97 | 0 | vector<string> vs; |
98 | 0 | tokenize(vs,buffer," \n\t,"); |
99 | 0 | if (vs.size() != 7) |
100 | 0 | return(false); |
101 | | |
102 | | //parse cell values |
103 | 0 | A = atof((char*)vs[1].c_str()); |
104 | 0 | B = atof((char*)vs[2].c_str()); |
105 | 0 | C = atof((char*)vs[3].c_str()); |
106 | 0 | Alpha = atof((char*)vs[4].c_str()); |
107 | 0 | Beta = atof((char*)vs[5].c_str()); |
108 | 0 | Gamma = atof((char*)vs[6].c_str()); |
109 | |
|
110 | 0 | OBUnitCell *uc = new OBUnitCell; |
111 | 0 | uc->SetData(A, B, C, Alpha, Beta, Gamma); |
112 | 0 | uc->SetOrigin(fileformatInput); |
113 | 0 | mol.SetData(uc); |
114 | |
|
115 | 0 | int i; |
116 | 0 | double x,y,z; |
117 | 0 | OBAtom *atom; |
118 | 0 | vector3 v; |
119 | |
|
120 | 0 | mol.BeginModify(); |
121 | |
|
122 | 0 | for (i = 1; i <= natoms;i++) |
123 | 0 | { |
124 | 0 | if (!ifs.getline(buffer,BUFF_SIZE)) |
125 | 0 | return(false); |
126 | 0 | tokenize(vs,buffer," \n\t,"); |
127 | 0 | if (vs.size() < 4) |
128 | 0 | return(false); |
129 | 0 | atom = mol.NewAtom(); |
130 | |
|
131 | 0 | x = atof((char*)vs[1].c_str()); |
132 | 0 | y = atof((char*)vs[2].c_str()); |
133 | 0 | z = atof((char*)vs[3].c_str()); |
134 | 0 | v.Set(x,y,z); |
135 | 0 | v = uc->FractionalToCartesian(v); |
136 | |
|
137 | 0 | atom->SetAtomicNum(OBElements::GetAtomicNum(vs[0].c_str())); |
138 | 0 | atom->SetVector(v); |
139 | 0 | } |
140 | | |
141 | 0 | if (!pConv->IsOption("b",OBConversion::INOPTIONS)) |
142 | 0 | mol.ConnectTheDots(); |
143 | 0 | if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS)) |
144 | 0 | mol.PerceiveBondOrders(); |
145 | | |
146 | | // clean out remaining blank lines |
147 | 0 | std::streampos ipos; |
148 | 0 | do |
149 | 0 | { |
150 | 0 | ipos = ifs.tellg(); |
151 | 0 | ifs.getline(buffer,BUFF_SIZE); |
152 | 0 | } |
153 | 0 | while(strlen(buffer) == 0 && !ifs.eof() ); |
154 | 0 | ifs.seekg(ipos); |
155 | |
|
156 | 0 | mol.EndModify(); |
157 | 0 | return(true); |
158 | 0 | } |
159 | | |
160 | | //////////////////////////////////////////////////////////////// |
161 | | |
162 | | bool CacaoFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) |
163 | 0 | { |
164 | 0 | OBMol* pmol = dynamic_cast<OBMol*>(pOb); |
165 | 0 | if (pmol == nullptr) |
166 | 0 | return false; |
167 | | |
168 | | //Define some references so we can use the old parameter names |
169 | 0 | ostream &ofs = *pConv->GetOutStream(); |
170 | 0 | OBMol &mol = *pmol; |
171 | |
|
172 | 0 | OBAtom *atom; |
173 | 0 | char buffer[BUFF_SIZE]; |
174 | 0 | vector<OBAtom*>::iterator i; |
175 | |
|
176 | 0 | snprintf(buffer, BUFF_SIZE, "%s\n",mol.GetTitle()); |
177 | 0 | ofs << buffer; |
178 | 0 | snprintf(buffer, BUFF_SIZE, "%3d DIST 0 0 0\n",mol.NumAtoms()); |
179 | 0 | ofs << buffer; |
180 | |
|
181 | 0 | if (!mol.HasData(OBGenericDataType::UnitCell)) |
182 | 0 | ofs << "CELL 1.,1.,1.,90.,90.,90.\n"; |
183 | 0 | else |
184 | 0 | { |
185 | 0 | OBUnitCell *uc = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell); |
186 | 0 | snprintf(buffer, BUFF_SIZE, "CELL %f,%f,%f,%f,%f,%f\n", |
187 | 0 | uc->GetA(), uc->GetB(), uc->GetC(), |
188 | 0 | uc->GetAlpha(), uc->GetBeta(), uc->GetGamma()); |
189 | 0 | ofs << buffer; |
190 | 0 | } |
191 | |
|
192 | 0 | for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) |
193 | 0 | { |
194 | 0 | snprintf(buffer,BUFF_SIZE,"%2s %7.4f, %7.4f, %7.4f\n", |
195 | 0 | OBElements::GetSymbol(atom->GetAtomicNum()), |
196 | 0 | atom->x(), |
197 | 0 | atom->y(), |
198 | 0 | atom->z()); |
199 | 0 | ofs << buffer; |
200 | 0 | } |
201 | |
|
202 | 0 | return(true); |
203 | 0 | } |
204 | | |
205 | | //! \todo Make this method bulletproof. Currently it causes segfaults sometimes |
206 | | void CacaoFormat::SetHilderbrandt(OBMol &mol,vector<OBInternalCoord*> &vit) |
207 | 0 | { |
208 | | // Roundtrip testing shows that some atoms are NULL |
209 | | // which causes segfaults when dereferencing later |
210 | | // (e.g. in the last "segment" of this routine) |
211 | 0 | double sum,r; |
212 | |
|
213 | 0 | OBAtom dummy1,dummy2; |
214 | 0 | dummy1.SetVector(0.0,0.0,1.0); |
215 | 0 | dummy2.SetVector(1.0,0.0,0.0); |
216 | |
|
217 | 0 | OBAtom *atom,*a1,*a2,*ref; |
218 | 0 | vector<OBAtom*>::iterator ai; |
219 | |
|
220 | 0 | vit.push_back(nullptr); |
221 | 0 | for (atom = mol.BeginAtom(ai);atom;atom = mol.NextAtom(ai)) |
222 | 0 | vit.push_back(new OBInternalCoord (atom)); |
223 | |
|
224 | 0 | vit[1]->_a = &dummy1; |
225 | 0 | vit[1]->_b = &dummy2; |
226 | 0 | if (vit.size() > 2) { |
227 | 0 | vit[2]->_b = &dummy1; |
228 | 0 | vit[2]->_c = &dummy2; |
229 | 0 | if (vit.size() > 3) { |
230 | 0 | vit[3]->_c = &dummy1; |
231 | 0 | } |
232 | 0 | } |
233 | |
|
234 | 0 | unsigned int i,j; |
235 | 0 | for (i = 2;i <= mol.NumAtoms();i++) |
236 | 0 | { |
237 | 0 | ref = nullptr; |
238 | 0 | a1 = mol.GetAtom(i); |
239 | 0 | sum = 100.0; |
240 | 0 | for (j = 1;j < i;j++) |
241 | 0 | { |
242 | 0 | a2 = mol.GetAtom(j); |
243 | 0 | r = (a1->GetVector()-a2->GetVector()).length_2(); |
244 | 0 | if ((r < sum) && (vit[j]->_a != a2) && (vit[j]->_b != a2)) |
245 | 0 | { |
246 | 0 | sum = r; |
247 | 0 | ref = a2; |
248 | 0 | } |
249 | 0 | } |
250 | 0 | vit[i]->_a = ref; |
251 | 0 | } |
252 | |
|
253 | 0 | for (i = 3;i <= mol.NumAtoms();i++) |
254 | 0 | vit[i]->_b = vit[vit[i]->_a->GetIdx()]->_a; |
255 | |
|
256 | 0 | for (i = 4;i <= mol.NumAtoms();i++) |
257 | 0 | { |
258 | 0 | if (vit[i]->_b && vit[i]->_b->GetIdx()) |
259 | 0 | vit[i]->_c = vit[vit[i]->_b->GetIdx()]->_b; |
260 | 0 | else |
261 | 0 | vit[i]->_c = &dummy1; |
262 | 0 | } |
263 | |
|
264 | 0 | OBAtom *a,*b,*c; |
265 | 0 | vector3 v1,v2; |
266 | 0 | for (i = 2;i <= mol.NumAtoms();i++) |
267 | 0 | { |
268 | 0 | atom = mol.GetAtom(i); |
269 | 0 | a = vit[i]->_a; |
270 | 0 | b = vit[i]->_b; |
271 | 0 | c = vit[i]->_c; |
272 | | // TODO: fix explicit calculations for PBC? |
273 | 0 | v1 = atom->GetVector() - a->GetVector(); |
274 | 0 | v2 = b->GetVector() - a->GetVector(); |
275 | 0 | vit[i]->_ang = vectorAngle(v1,v2); |
276 | 0 | vit[i]->_tor = CalcTorsionAngle(atom->GetVector(), |
277 | 0 | a->GetVector(), |
278 | 0 | b->GetVector(), |
279 | 0 | c->GetVector()); |
280 | 0 | vit[i]->_dst = (vit[i]->_a->GetVector() - atom->GetVector()).length(); |
281 | 0 | } |
282 | |
|
283 | 0 | } |
284 | | //*************************************************************** |
285 | | class CacaoInternalFormat : public OBMoleculeFormat |
286 | | { |
287 | | public: |
288 | | //Register this format type ID |
289 | | CacaoInternalFormat() |
290 | 6 | { |
291 | 6 | OBConversion::RegisterFormat("cacint",this); |
292 | 6 | } |
293 | | |
294 | | const char* Description() override // required |
295 | 0 | { |
296 | 0 | return |
297 | 0 | "Cacao Internal format\n" |
298 | 0 | "No comments yet\n"; |
299 | 0 | } |
300 | | |
301 | 0 | const char* SpecificationURL() override { |
302 | 0 | return "http://www.chembio.uoguelph.ca/oakley/310/cacao/cacao.htm"; |
303 | 0 | } //optional |
304 | | |
305 | | //Flags() can return be any the following combined by | or be omitted if none apply |
306 | | // NOTREADABLE READONEONLY NOTWRITABLE WRITEONEONLY |
307 | | unsigned int Flags() override |
308 | 6 | { |
309 | 6 | return NOTREADABLE | WRITEONEONLY; |
310 | 6 | } |
311 | | |
312 | | //////////////////////////////////////////////////// |
313 | | /// The "API" interface functions |
314 | | bool WriteMolecule(OBBase* pOb, OBConversion* pConv) override; |
315 | | }; |
316 | | |
317 | | //Make an instance of the format class |
318 | | CacaoInternalFormat theCacaoInternalFormat; |
319 | | |
320 | | bool CacaoInternalFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) |
321 | 0 | { |
322 | 0 | OBMol* pmol = dynamic_cast<OBMol*>(pOb); |
323 | 0 | if (pmol == nullptr) |
324 | 0 | return false; |
325 | | |
326 | | //Define some references so we can use the old parameter names |
327 | 0 | ostream &ofs = *pConv->GetOutStream(); |
328 | 0 | OBMol &mol = *pmol; |
329 | |
|
330 | 0 | unsigned int i; |
331 | 0 | vector3 v; |
332 | 0 | char tmptype[16],buffer[BUFF_SIZE]; |
333 | |
|
334 | 0 | if (mol.Empty()) |
335 | 0 | return(false); |
336 | | |
337 | | //translate first atom to origin |
338 | 0 | v = mol.GetAtom(1)->GetVector(); |
339 | 0 | v *= -1.0; |
340 | 0 | mol.Translate(v); |
341 | |
|
342 | 0 | vector<OBInternalCoord*> vit; |
343 | 0 | CacaoFormat::SetHilderbrandt(mol,vit); |
344 | 0 | strncpy(tmptype,OBElements::GetSymbol(mol.GetAtom(1)->GetAtomicNum()), sizeof(tmptype)); |
345 | 0 | tmptype[sizeof(tmptype) - 1] = '\0'; |
346 | |
|
347 | 0 | ofs << " # TITLE\n"; |
348 | 0 | snprintf(buffer, BUFF_SIZE, "%3d 0DIST 0 0 0\n",mol.NumAtoms()); |
349 | 0 | ofs << " EL\n"; |
350 | 0 | snprintf(buffer, BUFF_SIZE, "0.,0.,0., %s\n",tmptype); |
351 | 0 | ofs << buffer; |
352 | 0 | for (i = 2; i <= mol.NumAtoms(); i++) |
353 | 0 | { |
354 | 0 | strncpy(tmptype,OBElements::GetSymbol(mol.GetAtom(i)->GetAtomicNum()), sizeof(tmptype)); |
355 | 0 | tmptype[sizeof(tmptype) - 1] = '\0'; |
356 | |
|
357 | 0 | if (vit[i]->_tor < 0.0) |
358 | 0 | vit[i]->_tor += 360.0; |
359 | 0 | snprintf(buffer, BUFF_SIZE, "%2d,%d,%2s%7.3f,%7.3f,%7.3f", |
360 | 0 | vit[i]->_a->GetIdx(),i,tmptype, |
361 | 0 | vit[i]->_dst, |
362 | 0 | vit[i]->_ang, |
363 | 0 | vit[i]->_tor); |
364 | 0 | ofs << buffer << endl; |
365 | 0 | } |
366 | |
|
367 | 0 | vector<OBInternalCoord*>::iterator j; |
368 | 0 | for (j = vit.begin();j != vit.end();++j) |
369 | 0 | if (*j) |
370 | 0 | { |
371 | 0 | delete *j; |
372 | 0 | *j = nullptr; |
373 | 0 | } |
374 | |
|
375 | 0 | return(true); |
376 | 0 | } |
377 | | |
378 | | } //namespace OpenBabel |