Coverage Report

Created: 2025-11-11 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openbabel/src/formats/abinitformat.cpp
Line
Count
Source
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
0
#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
38
    ABINITFormat()
39
6
    {
40
6
      OBConversion::RegisterFormat("abinit",this);
41
6
    }
42
43
    const char* Description() override  // required
44
0
    {
45
0
      return
46
0
        "ABINIT Output Format\n"
47
0
        "Read Options e.g. -as\n"
48
0
        "  s  Output single bonds only\n"
49
0
        "  b  Disable bonding entirely\n\n";
50
0
    }
51
52
    const char* SpecificationURL() override
53
0
    { 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
57
    unsigned int Flags() override
58
6
    {
59
6
      return READONEONLY | NOTWRITABLE;
60
6
    }
61
62
    //*** This section identical for most OBMol conversions ***
63
    ////////////////////////////////////////////////////
64
    /// The "API" interface functions
65
    bool ReadMolecule(OBBase* pOb, OBConversion* pConv) override;
66
  };
67
  //***
68
69
  //Make an instance of the format class
70
  ABINITFormat theABINITFormat;
71
72
  /////////////////////////////////////////////////////////////////
73
  bool ABINITFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
74
0
  {
75
76
0
    OBMol* pmol = pOb->CastAndClear<OBMol>();
77
0
    if (pmol == nullptr)
78
0
      return false;
79
80
    //Define some references so we can use the old parameter names
81
0
    istream &ifs = *pConv->GetInStream();
82
0
    OBMol &mol = *pmol;
83
0
    const char* title = pConv->GetTitle();
84
85
0
    char buffer[BUFF_SIZE];
86
0
    string str;
87
0
    vector<string> vs;
88
89
0
    OBAtom *atom;
90
0
    int natom;
91
0
    vector<int> atomicNumbers, atomTypes;
92
0
    double x, y, z;
93
0
    vector<vector3> atomPositions;
94
0
    vector<double> energies;
95
96
    // Translation vectors (if present)
97
    // aka rprim
98
0
    vector3 translationVectors[3];
99
0
    double acell[3]; // scale of lattice vectors
100
0
    int numTranslationVectors = 0;
101
0
    int symmetryCode = 0;
102
0
    bool last = false;
103
0
    mol.BeginModify();
104
105
0
    while (ifs.getline(buffer,BUFF_SIZE))
106
0
      {
107
0
  if(strstr(buffer,"outvars")){
108
0
       last = true;
109
0
       continue;
110
0
     }
111
0
  if(! last){
112
0
    continue;
113
0
  }
114
        // tokens are listed in alphabetical order for code clarity
115
0
        if (strstr(buffer, "acell")) {
116
0
          tokenize(vs, buffer);
117
0
          if (vs.size() < 4)
118
0
            continue; // invalid line
119
120
          // acell=  7.6967369631E+00  7.6967369631E+00  7.6967369631E+00
121
0
          for (int i = 0; i < 3; ++i) {
122
0
            acell[i] = atof(vs[i+1].c_str());
123
0
          }
124
0
        }
125
0
        else if (strstr(buffer, " xcart ")) {
126
0
          double unit = BOHR_TO_ANGSTROM;
127
0
          if (strstr(buffer, "ngstrom"))
128
0
            unit = 1.0; // no conversion needed
129
130
    //          ifs.getline(buffer,BUFF_SIZE);
131
0
          tokenize(vs, buffer);
132
133
          // first line, rprim takes up a token
134
0
          x = atof((char*)vs[1].c_str()) * unit;
135
0
          y = atof((char*)vs[2].c_str()) * unit;
136
0
    z = atof((char*)vs[3].c_str()) * unit;
137
0
    atomPositions.push_back(vector3(x, y, z));
138
    // get next line
139
0
    ifs.getline(buffer,BUFF_SIZE);
140
0
    tokenize(vs, buffer);
141
    //rest of lines
142
0
    while(vs.size() == 3) {
143
0
      x = atof(vs[0].c_str()) * unit;
144
0
      y = atof(vs[1].c_str()) * unit;
145
0
      z = atof(vs[2].c_str()) * unit;
146
0
            atomPositions.push_back(vector3(x, y, z));
147
            // get next line
148
0
            ifs.getline(buffer,BUFF_SIZE);
149
0
            tokenize(vs, buffer);
150
0
          }
151
0
      }
152
0
        else if (strstr(buffer, "natom")) {
153
0
          tokenize(vs, buffer);
154
0
          if (vs.size() != 2)
155
0
            continue;
156
0
          natom = atoi(vs[1].c_str());
157
0
        }
158
0
        else if (strstr(buffer, "rprim")) {
159
0
          numTranslationVectors = 0;
160
0
          int column;
161
0
    ifs.getline(buffer,BUFF_SIZE);
162
0
          for (int i = 1; i < 4; ++i) {
163
0
            tokenize(vs, buffer);
164
0
            if (vs.size() < 3)
165
0
              break;
166
167
            // first line, rprim takes up a token
168
      //            if (i == 0)
169
      // column = 1;
170
            //else
171
0
              column = 0;
172
173
0
            x = atof((char*)vs[column].c_str()) * BOHR_TO_ANGSTROM;
174
0
            y = atof((char*)vs[column+1].c_str()) * BOHR_TO_ANGSTROM;
175
0
            z = atof((char*)vs[column+2].c_str()) * BOHR_TO_ANGSTROM;
176
0
            translationVectors[numTranslationVectors++].Set(x, y,z);
177
0
            ifs.getline(buffer,BUFF_SIZE);
178
0
          }
179
0
        }
180
0
        else if (strstr(buffer, "Symmetries")) {
181
0
          tokenize(vs, buffer, "()");
182
          // Should be something like (#160)
183
0
          symmetryCode = atoi(vs[1].substr(1).c_str());
184
0
        }
185
0
        else if (strstr(buffer, "typat")) {
186
0
          atomTypes.clear();
187
0
    int n=0;
188
0
      while( n<=natom){
189
0
        tokenize(vs, buffer);
190
0
        for (unsigned int i = 1; i < vs.size(); ++i) {
191
0
    atomTypes.push_back(atoi(vs[i].c_str()));
192
0
        }
193
0
        n+=vs.size();
194
0
        ifs.getline(buffer,BUFF_SIZE);
195
0
      }
196
0
        }
197
0
        else if (strstr(buffer, "znucl")) {
198
0
          tokenize(vs, buffer);
199
          // make sure znucl is first token
200
0
          if (vs[0] != "znucl")
201
0
            continue;
202
          // push back the remaining tokens into atomicNumbers
203
0
          atomicNumbers.clear();
204
0
          atomicNumbers.push_back(0); // abinit starts typat with 1
205
0
          for (unsigned int i = 1; i < vs.size(); ++i)
206
0
            atomicNumbers.push_back(int(atof(vs[i].c_str())));
207
0
        }
208
        // xangst
209
        // forces
210
0
      }
211
212
0
    for (int i = 0; i < natom; ++i) {
213
0
      atom = mol.NewAtom();
214
      //set atomic number
215
0
      int idx = atom->GetIdx();
216
0
      int type = atomTypes[idx - 1];
217
0
      atom->SetAtomicNum(atomicNumbers[type]);
218
      // we set the coordinates by conformers in another loop
219
0
    }
220
221
0
    mol.EndModify();
222
223
0
    if (natom == 0)
224
0
      return false;
225
226
0
    int numConformers = atomPositions.size() / natom;
227
0
    for (int i = 0; i < numConformers; ++i) {
228
0
      double *coordinates = new double[natom * 3];
229
0
      for (int j = 0; j < natom; ++j) {
230
0
        vector3 currentPosition = atomPositions[i*natom + j];
231
0
        coordinates[j*3] = currentPosition.x();
232
0
        coordinates[j*3 + 1] = currentPosition.y();
233
0
        coordinates[j*3 + 2] = currentPosition.z();
234
0
      }
235
0
      mol.AddConformer(coordinates);
236
0
    }
237
    // Delete first conformer, created by EndModify, bunch of 0s
238
0
    mol.DeleteConformer(0);
239
    // Set geometry to last one
240
0
    mol.SetConformer(mol.NumConformers() - 1);
241
242
0
    if (!pConv->IsOption("b",OBConversion::INOPTIONS))
243
0
      mol.ConnectTheDots();
244
0
    if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS))
245
0
      mol.PerceiveBondOrders();
246
247
    // Attach unit cell translation vectors if found
248
0
    if (numTranslationVectors > 0) {
249
0
      OBUnitCell* uc = new OBUnitCell;
250
      //      uc->SetData(acell[0] * translationVectors[0], acell[1] * translationVectors[1], acell[2] * translationVectors[2]);
251
0
      uc->SetData(translationVectors[0], translationVectors[1], translationVectors[2]);
252
0
      uc->SetOrigin(fileformatInput);
253
0
      if (symmetryCode)
254
0
        uc->SetSpaceGroup(symmetryCode);
255
0
      mol.SetData(uc);
256
0
    }
257
258
0
    mol.SetTitle(title);
259
0
    return(true);
260
0
  }
261
262
} //namespace OpenBabel