1 // FILETRANS.CPP : Handle import/export through use of the Babel external lib.
2
3 // Copyright (C) 2000 Geoffrey Hutchison.
4
5 // This package 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; either version 2 of the License, or
8 // (at your option) any later version.
9
10 // This package 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 // You should have received a copy of the GNU General Public License
16 // along with this package; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 /*################################################################################################*/
20
21 #include "filetrans.h"
22
23 #ifdef ENABLE_OPENBABEL
24
25 #include <ghemical/libghemicaldefine.h>
26
27 #include "project.h"
28
29 #include <fstream>
30 #include <sstream>
31 using namespace std;
32
33 // Babel lib includes
34 // ^^^^^^^^^^^^^^^^^^
35
36 #include <openbabel/mol.h>
37 #include <openbabel/obutil.h>
38 #include <openbabel/data.h>
39 #include <openbabel/typer.h>
40 #include <openbabel/obconversion.h>
41 #include <openbabel/atom.h>
42 #include <openbabel/bond.h>
43
44 using namespace std;
45 using namespace OpenBabel;
46
47 #ifndef FORMAT_PATH
48 #define FORMAT_PATH (char *) project::appdata_path
49 #endif // FORMAT_PATH
50
51 #if 0
52 namespace OpenBabel
53 {
54 extern OBAromaticTyper aromtyper;
55 extern OBAtomTyper atomtyper;
56 extern OBElementTable etab;
57 extern OBTypeTable ettab;
58 extern OBChainsParser chainsparser;
59 extern OBIsotopeTable isotab;
60 }
61 #endif
62
63 /*################################################################################################*/
64
65 // Constructor
66 // Requires: None
67 // Provides: import, export vectors for future use
file_trans()68 file_trans::file_trans()
69 {
70 format_record current;
71
72 // it seems that under Open Babel these objects (aromtyper, atomtyper,
73 // extab, etab, ttab) are global, so here we could initialize them
74 // multiple times is case we create multiple file_trans objects.
75 // could this be risky and/or problematic??? 2001-05-28 TH
76
77 // Certainly not risky -- the objects track whether they have been
78 // initialized. It may or may not be problematic in terms of running
79 // the library multiple times, but debugging should show that.
80
81 // But this actually shouldn't be necessary -- since Ghemical isn't
82 // building and installing Open Babel itself. Instead, let the library
83 // find its own data files! -GRH 2005-09-27
84
85 //aromtyper.SetReadDirectory(FORMAT_PATH); // aromatic typer
86 //aromtyper.SetEnvironmentVariable("GHEMICAL_DIR");
87 //atomtyper.SetReadDirectory(FORMAT_PATH); // atom typer
88 //atomtyper.SetEnvironmentVariable("GHEMICAL_DIR");
89 //etab.SetReadDirectory(FORMAT_PATH);
90 //etab.SetEnvironmentVariable("GHEMICAL_DIR");
91 //ttab.SetReadDirectory(FORMAT_PATH);
92 //ttab.SetEnvironmentVariable("GHEMICAL_DIR");
93 //isotab.SetReadDirectory(FORMAT_PATH);
94 //isotab.SetEnvironmentVariable("GHEMICAL_DIR");
95
96 OBConversion conv;
97 Formatpos pos;
98 OBFormat * pFormat;
99 const char * str = NULL;
100 while(OBConversion::GetNextFormat(pos,str,pFormat))
101 {
102 if ((pFormat->Flags() & NOTWRITABLE) && (pFormat->Flags() & NOTREADABLE)) continue;
103
104 current.format = pFormat;
105 std::string tempDescription(pFormat->Description());
106
107 current.description = tempDescription.substr(0, tempDescription.find('\n'));
108
109 if ( !(pFormat->Flags() & NOTREADABLE) ) imports.push_back(current);
110 if ( !(pFormat->Flags() & NOTWRITABLE) ) exports.push_back(current);
111 }
112
113 // the rest is for compatibility part...
114 // the rest is for compatibility part...
115 // the rest is for compatibility part...
116
117 obm = NULL;
118 prj = NULL;
119
120 name_tag_count = -1;
121 tagtab = NULL;
122 }
123
~file_trans()124 file_trans::~file_trans()
125 {
126 // we will delete the OBMol and name tags!!!
127
128 if (obm != NULL) delete obm;
129 if (tagtab != NULL) delete[] tagtab;
130 }
131
132 // Import
133 // Requires: filename (for typing) and an istream to read
134 // Provides:
Import(const char * filename,istream & input,ostream & output)135 int file_trans::Import(const char *filename, istream &input, ostream &output)
136 {
137 OBConversion conv;
138 OBFormat * inFormat = conv.FormatFromExt(filename);
139 if (inFormat == NULL) return -1; // cannot find that format
140
141 OBFormat * outFormat = conv.FindFormat("gpr"); // GHEMICAL
142
143 if (! conv.SetInAndOutFormats(inFormat, outFormat) ) return -1; // cannot read/write these formats
144
145 conv.Convert(&input, &output);
146 return(0);
147 }
148
Export(const char * filename,istream & input,ostream & output)149 int file_trans::Export(const char *filename, istream &input, ostream &output)
150 {
151 OBConversion conv;
152 OBFormat * inFormat = conv.FindFormat("gpr"); // GHEMICAL
153 OBFormat * outFormat = conv.FormatFromExt(filename);
154
155 if (outFormat == NULL) return -1; // cannot write that format
156
157 if (! conv.SetInAndOutFormats(inFormat, outFormat) ) return -1; // cannot read/write these formats
158
159 conv.Convert(&input, &output);
160 return(0);
161 }
162
CanImport(const char * filename)163 bool file_trans::CanImport(const char *filename)
164 {
165 OBConversion conv;
166 OBFormat * pFormat = conv.FormatFromExt(filename);
167 bool canRead = ( pFormat && !(pFormat->Flags() & NOTREADABLE) );
168 return canRead;
169 }
170
CanExport(const char * filename)171 bool file_trans::CanExport(const char *filename)
172 {
173 OBConversion conv;
174 OBFormat * pFormat = conv.FormatFromExt(filename);
175 bool canWrite = ( pFormat && !(pFormat->Flags() & NOTWRITABLE) );
176 return canWrite;
177 }
178
GetExportDescription(unsigned int index)179 string file_trans::GetExportDescription(unsigned int index)
180 {
181 string temp;
182 if (index < exports.size())
183 temp = exports[index].description;
184 return temp;
185 }
186
GetImportDescription(unsigned int index)187 string file_trans::GetImportDescription(unsigned int index)
188 {
189 string temp;
190 if (index < imports.size())
191 temp = imports[index].description;
192 return temp;
193 }
194
195 // Import
196 // Requires: filename, a type and an istream to read
197 // Provides: an imported file using Babel
Import(const char * filename,unsigned int type,istream & input,ostream & output)198 int file_trans::Import(const char *filename, unsigned int type, istream &input, ostream &output)
199 {
200 OBConversion conv;
201 OBFormat * inFormat;
202
203 if (type < imports.size()) inFormat = imports[type].format;
204 else
205 {
206 inFormat = conv.FormatFromExt(filename);
207 if (inFormat == NULL) return -1; // cannot find that format
208 }
209
210 OBFormat * outFormat = conv.FindFormat("gpr"); // GHEMICAL
211
212 if (! conv.SetInAndOutFormats(inFormat, outFormat) ) return -1; // cannot read/write these formats
213
214 conv.Convert(&input, &output);
215 return(0);
216 }
217
218 // Export
219 // Requires: filename, a type and an istream to read
220 // Provides: an exported file using Babel
Export(const char * filename,unsigned int type,istream & input,ostream & output)221 int file_trans::Export(const char *filename, unsigned int type, istream &input, ostream &output)
222 {
223 OBConversion conv;
224 OBFormat * outFormat;
225
226 if (type < exports.size()) outFormat = exports[type].format;
227 else
228 {
229 OBFormat * outFormat = conv.FormatFromExt(filename);
230 if (outFormat == NULL) return -1; // cannot write that format
231 }
232
233 OBFormat * inFormat = conv.FindFormat("gpr"); // GHEMICAL
234
235 if (! conv.SetInAndOutFormats(inFormat, outFormat) ) return -1; // cannot read/write these formats
236
237 conv.Convert(&input, &output);
238 return(0);
239 }
240
241 /*################*/
242 /*################*/
243
Copy(project * p1,iter_al p2,iter_al p3)244 OBMol * file_trans::Copy(project * p1, iter_al p2, iter_al p3)
245 {
246 prj = p1; obm = new OBMol(); itb = p2; ite = p3;
247
248 // count the atoms and reserve memory for the name tags.
249 // count the atoms and reserve memory for the name tags.
250 // count the atoms and reserve memory for the name tags.
251
252 name_tag_count = 0;
253 for (iter_al it1 = itb;it1 != ite;it1++)
254 {
255 name_tag_count++;
256 }
257
258 tagtab = new atom_name_tag[name_tag_count];
259
260 // copy the atoms/bonds to OBMol...
261
262 obm->BeginModify();
263
264 // copy the atoms.
265
266 int tag_counter = 0;
267 for (iter_al it1 = itb;it1 != ite;it1++)
268 {
269 OBAtom * oba = obm->NewAtom();
270 oba->SetAtomicNum((* it1).el.GetAtomicNumber());
271
272 const fGL * cdata = (* it1).GetCRD(0);
273 float xcrd = cdata[0] * 10.0;
274 float ycrd = cdata[1] * 10.0;
275 float zcrd = cdata[2] * 10.0;
276
277 oba->SetVector(xcrd, ycrd, zcrd);
278
279 // now set the "name tag" for this atom...
280 // now set the "name tag" for this atom...
281 // now set the "name tag" for this atom...
282
283 tagtab[tag_counter].atmr = & (* it1);
284 tagtab[tag_counter].oba = oba;
285 tag_counter++;
286 }
287
288 // copy the bonds.
289
290 // WE ASSUME HERE THAT ATOM ITERATORS COVER THE WHOLE SYSTEM!!!
291 // WE ASSUME HERE THAT ATOM ITERATORS COVER THE WHOLE SYSTEM!!!
292 // WE ASSUME HERE THAT ATOM ITERATORS COVER THE WHOLE SYSTEM!!!
293 prj->UpdateIndex();
294
295 for (iter_bl it1 = prj->GetBondsBegin();it1 != prj->GetBondsEnd();it1++)
296 {
297 i32s ind1 = (* it1).atmr[0]->index + 1;
298 i32s ind2 = (* it1).atmr[1]->index + 1;
299
300 i32s bt;
301 switch ((* it1).bt.GetValue())
302 {
303 case BONDTYPE_SINGLE: bt = 1; break;
304 case BONDTYPE_DOUBLE: bt = 2; break;
305 case BONDTYPE_TRIPLE: bt = 3; break;
306 case BONDTYPE_CNJGTD: bt = 5; break;
307 default: bt = 1;
308 }
309
310 obm->AddBond(ind1, ind2, bt);
311 }
312
313 // ok, it's ready!
314
315 obm->EndModify();
316 return obm;
317 }
318
CopyMolecule(project *,int)319 OBMol * file_trans::CopyMolecule(project *, int)
320 {
321 return NULL;
322 }
323
CopyAll(project * prj)324 OBMol * file_trans::CopyAll(project * prj)
325 {
326 return Copy(prj, prj->GetAtomsBegin(), prj->GetAtomsEnd());
327 }
328
Synchronize(void)329 void file_trans::Synchronize(void)
330 {
331 // create a new tagtab for the current situation (for bonds)...
332
333 atom_name_tag * tagtab2 = new atom_name_tag[obm->NumAtoms()];
334
335 for (i32u n1 = 1;n1 <= obm->NumAtoms();n1++)
336 {
337 OBAtom * oba = obm->GetAtom(n1);
338 atom * atmr = NULL;
339
340 // try to find the matching name tag; if you find it, get it and remove the original.
341
342 for (i32s n2 = 0;n2 < name_tag_count;n2++)
343 {
344 if (tagtab[n2].oba != oba) continue;
345
346 // match found!!!
347 // match found!!!
348 // match found!!!
349
350 atmr = tagtab[n2].atmr;
351 tagtab[n2].atmr = NULL;
352 tagtab[n2].oba = NULL;
353 break;
354 }
355
356 // if atmr is still NULL, we did not have a matching tag -> this must be a new atom!
357 // otherwise, we have this pair of corresponding objects and we can synchronize.
358
359 if (!atmr)
360 {
361 element el(oba->GetAtomicNum());
362
363 fGL crd[3] =
364 {
365 oba->GetX() / 10.0,
366 oba->GetY() / 10.0,
367 oba->GetZ() / 10.0
368 };
369
370 atom newatom(el, crd, prj->GetCRDSetCount());
371 prj->AddAtom_lg(newatom); atmr = & prj->GetLastAtom();
372
373 // this seems to crash -> disabled!!!!!!!!!!
374 // atmr->charge = oba->GetPartialCharge();
375 }
376 else
377 {
378 atmr->el = element(oba->GetAtomicNum());
379 atmr->SetCRD(0, oba->GetX() / 10.0, oba->GetY() / 10.0, oba->GetZ() / 10.0);
380
381 // this seems to crash -> disabled!!!!!!!!!!
382 // atmr->charge = oba->GetPartialCharge();
383 }
384
385 // save the new tagtab entry...
386
387 tagtab2[n1 - 1].atmr = atmr;
388 tagtab2[n1 - 1].oba = oba;
389 }
390
391 // in the above loop, we discarded the name tags that had corresponding atoms.
392 // so if there still are name tags left, it means we should remove those atoms!
393 // removing atoms will also remove bonds connected to them automagically...
394
395 for (i32s n1 = 0;n1 < name_tag_count;n1++)
396 {
397 if (!tagtab[n1].atmr) continue;
398
399 // ok, remove this atom.
400 // ok, remove this atom.
401 // ok, remove this atom.
402
403 iter_al it1 = itb;
404 while (it1 != ite) if (& (* it1) == tagtab[n1].atmr) break;
405 if (it1 == itb)
406 {
407 assertion_failed(__FILE__, __LINE__, "iterator lost!");
408 }
409
410 tagtab[n1].atmr = NULL;
411 tagtab[n1].oba = NULL;
412
413 prj->RemoveAtom(it1);
414 }
415
416 // now we should have the atoms in sync; do the same for bonds.
417 // for each OBBond, find or create the equivalent, and check the type.
418 // we assume that for a pair of atoms, there is no more than 1 bond!!!
419
420 for (i32u n1 = 0;n1 < obm->NumBonds();n1++)
421 {
422 OBBond * obb = obm->GetBond(n1);
423 i32u ind1 = obb->GetBeginAtomIdx() - 1;
424 i32u ind2 = obb->GetEndAtomIdx() - 1;
425
426 atom * atmr1 = tagtab2[ind1].atmr;
427 atom * atmr2 = tagtab2[ind2].atmr;
428
429 bond * bndr = NULL;
430
431 for (iter_bl it1 = prj->GetBondsBegin();it1 != prj->GetBondsEnd();it1++)
432 {
433 bool match = false;
434 if ((* it1).atmr[0] == atmr1 && (* it1).atmr[1] == atmr2) match = true;
435 if ((* it1).atmr[1] == atmr1 && (* it1).atmr[0] == atmr2) match = true;
436 if (!match) continue;
437
438 // match found; mark it and check the bondtype.
439 // match found; mark it and check the bondtype.
440 // match found; mark it and check the bondtype.
441
442 bndr = & (* it1);
443
444 i32s bt;
445 switch (obb->GetBO())
446 {
447 case 1: bt = BONDTYPE_SINGLE; break;
448 case 2: bt = BONDTYPE_DOUBLE; break;
449 case 3: bt = BONDTYPE_TRIPLE; break;
450 default: bt = BONDTYPE_CNJGTD;
451 }
452
453 if (obb->IsAromatic()) bt = BONDTYPE_CNJGTD;
454
455 bndr->bt = bondtype(bt);
456
457 break;
458 }
459
460 // if there were no match, then create the bond!
461
462 if (!bndr)
463 {
464 i32s bt;
465 switch (obb->GetBO())
466 {
467 case 1: bt = BONDTYPE_SINGLE; break;
468 case 2: bt = BONDTYPE_DOUBLE; break;
469 case 3: bt = BONDTYPE_TRIPLE; break;
470 default: bt = BONDTYPE_CNJGTD;
471 }
472
473 if (obb->IsAromatic()) bt = BONDTYPE_CNJGTD;
474
475 bond newbond(atmr1, atmr2, bondtype(bt));
476 prj->AddBond(newbond);
477 }
478 }
479
480 // get rid of the new tagtab...
481
482 delete[] tagtab2;
483 }
484
485 #endif // ENABLE_OPENBABEL
486
487 /*################################################################################################*/
488
489 // eof
490