1 /********************************************************************** 2 Copyright (C) 2007 by Daniel Mansfield 3 Some portions Copyright (C) 2004-2006 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 15 /* 16 * File extension module for CaRIne's ASCII Crystal (ACR) 17 * By Daniel Mansfield 18 * 30th January 2007 19 */ 20 21 #include <openbabel/babelconfig.h> 22 23 #include <openbabel/mol.h> 24 #include <openbabel/atom.h> 25 #include <openbabel/elements.h> 26 #include <openbabel/obmolecformat.h> 27 #include <stdio.h> 28 #include <cstdlib> 29 30 using namespace std; 31 namespace OpenBabel 32 { 33 34 class ACRFormat : public OBMoleculeFormat 35 { 36 public: 37 //Register this format type ID in the constructor ACRFormat()38 ACRFormat() 39 { 40 OBConversion::RegisterFormat("acr", this, "chemical/x-acr"); 41 // OBConversion::RegisterOptionParam("f", this, 1); 42 // OBConversion::RegisterOptionParam("n", this); 43 OBConversion::RegisterOptionParam("s", this, 0, OBConversion::INOPTIONS); 44 45 } 46 Description()47 virtual const char* Description() //required 48 { 49 return 50 "ACR format\n" 51 "CaRIne ASCII Crystal format (ACR)\n" 52 // "Write Options e.g. -xf3 \n" 53 // " f# Number of (fictional) levels \n" 54 // " n Omit (virtual) title\n" 55 "Read Options e.g. -as\n" 56 " s Consider single bonds only\n"; 57 }; 58 SpecificationURL()59 virtual const char* SpecificationURL() 60 {return "http://pros.orange.fr/carine.crystallography/books/31/carine_31_us.pdf";}; 61 GetMIMEType()62 virtual const char* GetMIMEType() { return "chemical/x-acr"; }; 63 64 Flags()65 virtual unsigned int Flags() 66 { 67 return READONEONLY | NOTWRITABLE; 68 }; 69 SkipObjects(int n,OBConversion * pConv)70 virtual int SkipObjects(int n, OBConversion* pConv) 71 { 72 return 0; 73 }; 74 75 virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv); 76 //virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv); 77 78 private: 79 }; 80 81 ACRFormat theACRFormat; 82 ReadMolecule(OBBase * pOb,OBConversion * pConv)83 bool ACRFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv) 84 { 85 OBMol* pmol = pOb->CastAndClear<OBMol>(); 86 if (pmol == nullptr) 87 return false; 88 89 istream& ifs = *pConv->GetInStream(); 90 91 pmol->BeginModify(); 92 93 /** Parse the input stream and use the OpenBabel API to populate the OBMol **/ 94 char buf[BUFF_SIZE]; 95 unsigned int atoms, bonds, tmp; 96 float scale, dtmp; 97 bool atom_input = false, bond_input = false; 98 string type; 99 //int from, to; 100 double X,Y,Z; 101 vector<string> vs; 102 103 // read in one at a time 104 /* WARNING: Atom id starts from zero in Carine; not so in openbabel. 105 * Solution: Let Open Babel to set them. */ 106 107 while (true) { 108 ifs.getline(buf, BUFF_SIZE); 109 if (ifs.eof()) { 110 break; 111 } 112 113 if (sscanf(buf, "General Scale=%f\n", &dtmp)) { 114 scale = dtmp; 115 continue; 116 } else if (sscanf(buf, "Number of Atoms in Crystal=%d\n", &tmp)) { 117 atoms = tmp; 118 atom_input = true; 119 120 // read table column names 121 ifs.getline(buf, BUFF_SIZE); 122 continue; 123 } else if (sscanf(buf, "Number of Links in Crystal=%d\n", &tmp)) { 124 atom_input = false; 125 bond_input = true; 126 bonds = tmp; 127 128 // read table column names 129 ifs.getline(buf, BUFF_SIZE); 130 continue; 131 } else if ( '#' == buf[0] || '\r' == buf[0] || '\n' == buf[0] ) { 132 // between sections, in both windows and unix. 133 continue; 134 } 135 tokenize(vs, buf, " \t\r\n"); 136 137 if (atom_input) { 138 if (vs.size() < 9) return false; // timvdm 18/06/2008 139 type = vs[1]; 140 X = atof((char*)vs[6].c_str())/scale; 141 Y = atof((char*)vs[7].c_str())/scale; 142 Z = atof((char*)vs[8].c_str())/scale; 143 144 OBAtom* a = pmol->NewAtom(); 145 if (*(type.c_str()) != '*') 146 a->SetAtomicNum(OBElements::GetAtomicNum(type.c_str())); 147 a->SetVector(X,Y,Z); 148 149 } else if (bond_input) { 150 if (vs.size() < 2) return false; // timvdm 18/06/2008 151 // add to pmol 152 if (!pmol->AddBond(atoi((char*)vs[0].c_str()) + 1, atoi((char*)vs[1].c_str()) + 1, 153 1 /* bond order not specified in Carine, use PerceiveBondOrder later */)) 154 { 155 obErrorLog.ThrowError(__FUNCTION__, "addition of bond between " + vs[0] + " and " + vs[1] + " failed", obError); 156 return false; 157 } 158 } 159 } 160 161 /* got sanity? */ 162 if ( pmol->NumBonds() != bonds ) { 163 // then we read a different number of bonds than those promised. 164 obErrorLog.ThrowError(__FUNCTION__, "Number of bonds read does not match the number promised", obError); 165 return false; 166 } else if ( pmol->NumAtoms() != atoms ) { 167 obErrorLog.ThrowError(__FUNCTION__, "Number of atoms read does not match the number promised", obError); 168 return false; 169 } 170 171 pmol->PerceiveBondOrders(); 172 173 pmol->EndModify(); 174 175 return true; 176 } 177 178 } //namespace OpenBabel 179 180