1 /********************************************************************** 2 Copyright (C) 2011 by Geoffrey Hutchison 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation version 2 of the License. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 ***********************************************************************/ 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 24 #include <cstdlib> 25 26 using namespace std; 27 namespace OpenBabel 28 { 29 30 #define BOHR_TO_ANGSTROM 0.5291772108 31 #define ANGSTROM_TO_BOHR 1.0 / BOHR_TO_ANGSTROM 32 33 34 class ABINITFormat : public OBMoleculeFormat 35 { 36 public: 37 //Register this format type ID ABINITFormat()38 ABINITFormat() 39 { 40 OBConversion::RegisterFormat("abinit",this); 41 } 42 Description()43 virtual const char* Description() //required 44 { 45 return 46 "ABINIT Output 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 "http://abinit.org/" ;}; //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 | NOTWRITABLE; 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 }; 67 //*** 68 69 //Make an instance of the format class 70 ABINITFormat theABINITFormat; 71 72 ///////////////////////////////////////////////////////////////// ReadMolecule(OBBase * pOb,OBConversion * pConv)73 bool ABINITFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv) 74 { 75 76 OBMol* pmol = pOb->CastAndClear<OBMol>(); 77 if (pmol == nullptr) 78 return false; 79 80 //Define some references so we can use the old parameter names 81 istream &ifs = *pConv->GetInStream(); 82 OBMol &mol = *pmol; 83 const char* title = pConv->GetTitle(); 84 85 char buffer[BUFF_SIZE]; 86 string str; 87 vector<string> vs; 88 89 OBAtom *atom; 90 int natom; 91 vector<int> atomicNumbers, atomTypes; 92 double x, y, z; 93 vector<vector3> atomPositions; 94 vector<double> energies; 95 96 // Translation vectors (if present) 97 // aka rprim 98 vector3 translationVectors[3]; 99 double acell[3]; // scale of lattice vectors 100 int numTranslationVectors = 0; 101 int symmetryCode = 0; 102 bool last = false; 103 mol.BeginModify(); 104 105 while (ifs.getline(buffer,BUFF_SIZE)) 106 { 107 if(strstr(buffer,"outvars")){ 108 last = true; 109 continue; 110 } 111 if(! last){ 112 continue; 113 } 114 // tokens are listed in alphabetical order for code clarity 115 if (strstr(buffer, "acell")) { 116 tokenize(vs, buffer); 117 if (vs.size() < 4) 118 continue; // invalid line 119 120 // acell= 7.6967369631E+00 7.6967369631E+00 7.6967369631E+00 121 for (int i = 0; i < 3; ++i) { 122 acell[i] = atof(vs[i+1].c_str()); 123 } 124 } 125 else if (strstr(buffer, " xcart ")) { 126 double unit = BOHR_TO_ANGSTROM; 127 if (strstr(buffer, "ngstrom")) 128 unit = 1.0; // no conversion needed 129 130 // ifs.getline(buffer,BUFF_SIZE); 131 tokenize(vs, buffer); 132 133 // first line, rprim takes up a token 134 x = atof((char*)vs[1].c_str()) * unit; 135 y = atof((char*)vs[2].c_str()) * unit; 136 z = atof((char*)vs[3].c_str()) * unit; 137 atomPositions.push_back(vector3(x, y, z)); 138 // get next line 139 ifs.getline(buffer,BUFF_SIZE); 140 tokenize(vs, buffer); 141 //rest of lines 142 while(vs.size() == 3) { 143 x = atof(vs[0].c_str()) * unit; 144 y = atof(vs[1].c_str()) * unit; 145 z = atof(vs[2].c_str()) * unit; 146 atomPositions.push_back(vector3(x, y, z)); 147 // get next line 148 ifs.getline(buffer,BUFF_SIZE); 149 tokenize(vs, buffer); 150 } 151 } 152 else if (strstr(buffer, "natom")) { 153 tokenize(vs, buffer); 154 if (vs.size() != 2) 155 continue; 156 natom = atoi(vs[1].c_str()); 157 } 158 else if (strstr(buffer, "rprim")) { 159 numTranslationVectors = 0; 160 int column; 161 ifs.getline(buffer,BUFF_SIZE); 162 for (int i = 1; i < 4; ++i) { 163 tokenize(vs, buffer); 164 if (vs.size() < 3) 165 break; 166 167 // first line, rprim takes up a token 168 // if (i == 0) 169 // column = 1; 170 //else 171 column = 0; 172 173 x = atof((char*)vs[column].c_str()) * BOHR_TO_ANGSTROM; 174 y = atof((char*)vs[column+1].c_str()) * BOHR_TO_ANGSTROM; 175 z = atof((char*)vs[column+2].c_str()) * BOHR_TO_ANGSTROM; 176 translationVectors[numTranslationVectors++].Set(x, y,z); 177 ifs.getline(buffer,BUFF_SIZE); 178 } 179 } 180 else if (strstr(buffer, "Symmetries")) { 181 tokenize(vs, buffer, "()"); 182 // Should be something like (#160) 183 symmetryCode = atoi(vs[1].substr(1).c_str()); 184 } 185 else if (strstr(buffer, "typat")) { 186 atomTypes.clear(); 187 int n=0; 188 while( n<=natom){ 189 tokenize(vs, buffer); 190 for (unsigned int i = 1; i < vs.size(); ++i) { 191 atomTypes.push_back(atoi(vs[i].c_str())); 192 } 193 n+=vs.size(); 194 ifs.getline(buffer,BUFF_SIZE); 195 } 196 } 197 else if (strstr(buffer, "znucl")) { 198 tokenize(vs, buffer); 199 // make sure znucl is first token 200 if (vs[0] != "znucl") 201 continue; 202 // push back the remaining tokens into atomicNumbers 203 atomicNumbers.clear(); 204 atomicNumbers.push_back(0); // abinit starts typat with 1 205 for (unsigned int i = 1; i < vs.size(); ++i) 206 atomicNumbers.push_back(int(atof(vs[i].c_str()))); 207 } 208 // xangst 209 // forces 210 } 211 212 for (int i = 0; i < natom; ++i) { 213 atom = mol.NewAtom(); 214 //set atomic number 215 int idx = atom->GetIdx(); 216 int type = atomTypes[idx - 1]; 217 atom->SetAtomicNum(atomicNumbers[type]); 218 // we set the coordinates by conformers in another loop 219 } 220 221 mol.EndModify(); 222 223 int numConformers = atomPositions.size() / natom; 224 for (int i = 0; i < numConformers; ++i) { 225 double *coordinates = new double[natom * 3]; 226 for (int j = 0; j < natom; ++j) { 227 vector3 currentPosition = atomPositions[i*natom + j]; 228 coordinates[j*3] = currentPosition.x(); 229 coordinates[j*3 + 1] = currentPosition.y(); 230 coordinates[j*3 + 2] = currentPosition.z(); 231 } 232 mol.AddConformer(coordinates); 233 } 234 // Delete first conformer, created by EndModify, bunch of 0s 235 mol.DeleteConformer(0); 236 // Set geometry to last one 237 mol.SetConformer(mol.NumConformers() - 1); 238 239 if (!pConv->IsOption("b",OBConversion::INOPTIONS)) 240 mol.ConnectTheDots(); 241 if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS)) 242 mol.PerceiveBondOrders(); 243 244 // Attach unit cell translation vectors if found 245 if (numTranslationVectors > 0) { 246 OBUnitCell* uc = new OBUnitCell; 247 // uc->SetData(acell[0] * translationVectors[0], acell[1] * translationVectors[1], acell[2] * translationVectors[2]); 248 uc->SetData(translationVectors[0], translationVectors[1], translationVectors[2]); 249 uc->SetOrigin(fileformatInput); 250 if (symmetryCode) 251 uc->SetSpaceGroup(symmetryCode); 252 mol.SetData(uc); 253 } 254 255 mol.SetTitle(title); 256 return(true); 257 } 258 259 } //namespace OpenBabel 260