Coverage Report

Created: 2023-06-07 06:20

/src/openbabel/src/formats/ghemicalformat.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
  Copyright (C) 2000-2006 by Geoffrey Hutchison
3
  Some portions Copyright (C) 2004 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
#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/obiter.h>
22
#include <openbabel/generic.h>
23
#include <openbabel/bond.h>
24
#include <cstdlib>
25
26
27
using namespace std;
28
namespace OpenBabel
29
{
30
31
  class GhemicalFormat : public OBMoleculeFormat
32
  {
33
    public:
34
      //Register this format type ID
35
      GhemicalFormat()
36
4
      {
37
        //        OBConversion::RegisterFormat("mm1gp",this);
38
        //        OBConversion::RegisterFormat("qm1gp",this);
39
4
        OBConversion::RegisterFormat("gpr",this);
40
4
      }
41
42
      const char* Description() override  // required
43
0
      {
44
0
        return
45
0
          "Ghemical format\n"
46
0
          "Open source molecular modelling\n";
47
0
      }
48
49
      const char* SpecificationURL() override
50
0
      { return "http://www.uku.fi/~thassine/ghemical/"; } //optional
51
52
      //Flags() can return be any the following combined by | or be omitted if none apply
53
      // NOTREADABLE  READONEONLY  NOTWRITABLE  WRITEONEONLY
54
      unsigned int Flags() override
55
4
      {
56
4
        return READONEONLY | WRITEONEONLY;
57
4
      }
58
59
      //*** This section identical for most OBMol conversions ***
60
      ////////////////////////////////////////////////////
61
      /// The "API" interface functions
62
      bool ReadMolecule(OBBase* pOb, OBConversion* pConv) override;
63
      bool WriteMolecule(OBBase* pOb, OBConversion* pConv) override;
64
  };
65
  //***
66
67
  //Make an instance of the format class
68
  GhemicalFormat theGhemicalFormat;
69
70
  /////////////////////////////////////////////////////////////////
71
  bool GhemicalFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
72
0
  {
73
74
0
    OBMol* pmol = pOb->CastAndClear<OBMol>();
75
0
    if (pmol == nullptr)
76
0
      return false;
77
78
    //Define some references so we can use the old parameter names
79
0
    istream &ifs = *pConv->GetInStream();
80
0
    OBMol &mol = *pmol;
81
0
    const char* title = pConv->GetTitle();
82
83
0
    int i;
84
0
    int natoms, nbonds;
85
0
    char buffer[BUFF_SIZE];
86
0
    string str,str1;
87
0
    double x,y,z;
88
0
    OBAtom *atom;
89
0
    vector<string> vs;
90
0
    char bobuf[100];
91
0
    string bostr;
92
0
    int bgn,end,order;
93
0
    bool hasPartialCharges = false;
94
95
0
    mol.BeginModify();
96
97
    // Get !Header line with version number
98
0
    ifs.getline(buffer,BUFF_SIZE);
99
0
    sscanf(buffer,"%*s %*s %d", &i);
100
0
    if (!i)
101
0
      return false;
102
103
    // Get !Info line with number of coord sets
104
0
    ifs.getline(buffer,BUFF_SIZE);
105
0
    sscanf(buffer,"%*s %d", &i);
106
0
    if (!i)
107
0
      return false;
108
109
    // Get !Atoms line with number
110
0
    ifs.getline(buffer,BUFF_SIZE);
111
0
    sscanf(buffer,"%*s %d", &natoms);
112
0
    if (!natoms)
113
0
      return(false);
114
115
0
    for (i = 1; i <= natoms; i ++)
116
0
    {
117
0
      if (!ifs.getline(buffer,BUFF_SIZE))
118
0
        return(false);
119
0
      tokenize(vs,buffer);
120
0
      if (vs.size() < 2)
121
0
        return(false);
122
0
      atom = mol.NewAtom();
123
0
      atom->SetAtomicNum(atoi(vs[1].c_str()));
124
0
    }
125
126
    // Get !Bonds line with number
127
0
    ifs.getline(buffer,BUFF_SIZE);
128
0
    sscanf(buffer,"%*s %d", &nbonds);
129
0
    if (nbonds != 0)
130
0
      for (i = 0; i < nbonds; i++)
131
0
      {
132
0
        if (!ifs.getline(buffer,BUFF_SIZE))
133
0
          return(false);
134
0
        if (!sscanf(buffer,"%d%d%2s",&bgn,&end,bobuf))
135
0
          return (false);
136
0
        bostr = bobuf;
137
0
        order = 1;
138
0
        if      (bostr == "D")
139
0
          order = 2;
140
0
        else if (bostr == "T")
141
0
          order = 3;
142
0
        else if (bostr == "C")
143
0
          order = 5; // Conjugated ~= Aromatic
144
0
        mol.AddBond(bgn+1,end+1,order);
145
0
      }
146
147
    // Get !Coord line
148
0
    ifs.getline(buffer,BUFF_SIZE);
149
0
    for (i = 1; i <= natoms; i ++)
150
0
    {
151
0
      if (!ifs.getline(buffer,BUFF_SIZE))
152
0
        return(false);
153
0
      tokenize(vs,buffer);
154
0
      if (vs.size() != 4)
155
0
        return(false);
156
0
      atom = mol.GetAtom(i);
157
0
      x = 10.0*atof((char*)vs[1].c_str());
158
0
      y = 10.0*atof((char*)vs[2].c_str());
159
0
      z = 10.0*atof((char*)vs[3].c_str());
160
0
      atom->SetVector(x,y,z); //set coordinates
161
0
    }
162
163
0
    if (ifs.getline(buffer, BUFF_SIZE) && (strstr(buffer, "!Charges") != nullptr
164
0
          || strstr(buffer, "!PartialCharges") != nullptr))
165
0
    {
166
0
      hasPartialCharges = true;
167
0
      for (i = 1; i <= natoms; i ++)
168
0
      {
169
0
        if (!ifs.getline(buffer,BUFF_SIZE))
170
0
          return(false);
171
0
        tokenize(vs,buffer);
172
0
        if (vs.size() != 2)
173
0
          return(false);
174
0
        atom = mol.GetAtom(i);
175
0
        atom->SetPartialCharge(atof((char*)vs[1].c_str()));
176
0
      }
177
0
    }
178
179
    // look for the !End block if it exists
180
0
    while (ifs.getline(buffer,BUFF_SIZE))
181
0
    {
182
0
      if (strstr(buffer, "!End") != nullptr)
183
0
        break;
184
0
    }
185
186
    // clean out remaining blank lines
187
0
    std::streampos ipos;
188
0
    do
189
0
    {
190
0
      ipos = ifs.tellg();
191
0
      ifs.getline(buffer,BUFF_SIZE);
192
0
    }
193
0
    while(strlen(buffer) == 0 && !ifs.eof() );
194
0
    ifs.seekg(ipos);
195
196
0
    mol.EndModify();
197
0
    if (hasPartialCharges)
198
0
      mol.SetPartialChargesPerceived();
199
0
    mol.SetTitle(title);
200
0
    return(true);
201
0
  }
202
203
  ////////////////////////////////////////////////////////////////
204
205
  bool GhemicalFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
206
0
  {
207
0
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
208
0
    if (pmol == nullptr)
209
0
      return false;
210
211
    //Define some references so we can use the old parameter names
212
0
    ostream &ofs = *pConv->GetOutStream();
213
0
    OBMol &mol = *pmol;
214
215
    // delete dummy atoms
216
0
    FOR_ATOMS_OF_MOL(atom, pmol)
217
0
      if (atom->GetAtomicNum() == 0)
218
0
        mol.DeleteAtom(&*atom);
219
220
    // Ghemical header -- here "version 1.0" format
221
0
    ofs << "!Header gpr 100\n";
222
223
    // Number of coordinate sets
224
0
    ofs << "!Info 1\n";
225
226
    // Atom definitions
227
0
    ofs << "!Atoms " << mol.NumAtoms() << '\n';
228
229
0
    FOR_ATOMS_OF_MOL(atom, mol)
230
0
      ofs << (atom->GetIdx() - 1) << " " << atom->GetAtomicNum() << '\n';
231
232
    // Bond definitions
233
0
    ofs << "!Bonds " << mol.NumBonds() << '\n';
234
235
0
    char bond_char;
236
0
    FOR_BONDS_OF_MOL(bond, mol)
237
0
    {
238
0
      switch(bond->GetBondOrder())
239
0
      {
240
0
        case 1 :
241
0
          bond_char = 'S';
242
0
          break;
243
0
        case 2 :
244
0
          bond_char = 'D';
245
0
          break;
246
0
        case 3 :
247
0
          bond_char = 'T';
248
0
          break;
249
0
        case 5 :
250
0
          bond_char = 'C';
251
0
          break;
252
0
        default :
253
0
          bond_char = 'S';
254
0
      }
255
0
      if (bond->IsAromatic())
256
0
        bond_char = 'C';
257
0
      ofs << bond->GetBeginAtomIdx()-1 << ' '
258
0
        << bond->GetEndAtomIdx()-1 << ' '
259
0
        <<  bond_char << '\n';
260
0
    }
261
262
    // Coordinate sets (here only 1)
263
0
    ofs << "!Coord\n";
264
265
0
    FOR_ATOMS_OF_MOL(atom, mol)
266
0
    {
267
0
      ofs << atom->GetIdx()-1 << ' '
268
0
        << atom->GetX()/10.0 << ' '
269
0
        << atom->GetY()/10.0 << ' '
270
0
        << atom->GetZ()/10.0 << '\n';
271
0
    }
272
273
    // Calculated charges
274
0
    ofs << "!Charges\n";
275
276
0
    FOR_ATOMS_OF_MOL(atom, mol)
277
0
    {
278
0
      ofs << atom->GetIdx()-1 << ' '
279
0
        << atom->GetPartialCharge() << '\n';
280
0
    }
281
282
0
    OBSetData *gmsset = (OBSetData *)pmol->GetData("gamess");
283
0
    if(gmsset)
284
0
    {
285
0
      ofs << "!GAMESS" << endl;
286
0
      std::vector<OBGenericData*>::iterator i,j;
287
288
0
      for(i = gmsset->GetBegin(); i != gmsset->GetEnd(); ++i)
289
0
      {
290
0
        OBSetData *cset = (OBSetData *)(*i);
291
0
        if(cset)
292
0
        {
293
0
          string section = cset->GetAttribute();
294
0
          for(j = cset->GetBegin(); j != cset->GetEnd(); ++j)
295
0
          {
296
0
            OBPairData *pd = (OBPairData *) (*j);
297
0
            if(pd)
298
0
            {
299
0
              ofs << section << " " << pd->GetAttribute() << " " << pd->GetValue() << endl;
300
0
            }
301
0
          }
302
0
        }
303
0
      }
304
0
    }
305
306
0
    ofs << "!End\n";
307
308
0
    return(true);
309
0
  }
310
311
} //namespace OpenBabel