Coverage Report

Created: 2026-01-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openbabel/src/formats/chem3dformat.cpp
Line
Count
Source
1
/**********************************************************************
2
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
3
Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
4
Some portions Copyright (C) 2004 by Chris Morley
5
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation version 2 of the License.
9
10
This program 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
#include <openbabel/babelconfig.h>
16
17
#include <openbabel/math/matrix3x3.h>
18
#include <openbabel/obmolecformat.h>
19
#include <openbabel/mol.h>
20
#include <openbabel/atom.h>
21
#include <openbabel/elements.h>
22
#include <openbabel/data.h>
23
#include <cstdlib>
24
25
26
using namespace std;
27
namespace OpenBabel
28
{
29
30
  class CHEM3D1Format : public OBMoleculeFormat
31
  {
32
  public:
33
    //Register this format type ID
34
    CHEM3D1Format()
35
6
    {
36
6
      OBConversion::RegisterFormat("c3d1",this);
37
6
    }
38
39
    const char* Description() override  // required
40
0
    {
41
0
      return
42
0
        "Chem3D Cartesian 1 format\n"
43
0
        "No comments yet\n";
44
0
    }
45
46
    const char* SpecificationURL() override
47
0
    { return ""; }  // optional
48
49
    //Flags() can return be any the following combined by | or be omitted if none apply
50
    // NOTREADABLE  READONEONLY  NOTWRITABLE  WRITEONEONLY
51
    unsigned int Flags() override
52
7
    {
53
7
      return READONEONLY;
54
7
    }
55
56
    //*** This section identical for most OBMol conversions ***
57
    ////////////////////////////////////////////////////
58
    /// The "API" interface functions
59
    bool ReadMolecule(OBBase* pOb, OBConversion* pConv) override;
60
    bool WriteMolecule(OBBase* pOb, OBConversion* pConv) override;
61
62
    static bool ReadChem3d(istream &ifs,OBMol &mol,bool mmads,const char *type_key);
63
    static bool WriteChem3d(ostream &ofs,OBMol &mol, const char *mol_typ);
64
65
  };
66
  //***
67
68
  //Make an instance of the format class
69
  CHEM3D1Format theCHEM3D1Format;
70
71
  /////////////////////////////////////////////////////////////////
72
  bool CHEM3D1Format::ReadMolecule(OBBase* pOb, OBConversion* pConv)
73
0
  {
74
75
0
    OBMol* pmol = pOb->CastAndClear<OBMol>();
76
0
    if (pmol == nullptr)
77
0
      return false;
78
79
    //Define some references so we can use the old parameter names
80
0
    istream &ifs = *pConv->GetInStream();
81
0
    OBMol &mol = *pmol;
82
0
    mol.SetTitle( pConv->GetTitle()); //default title is the filename
83
84
0
    return(ReadChem3d(ifs,mol,false,"MM2"));
85
0
  }
86
87
  ////////////////////////////////////////////////////////////////
88
89
  bool CHEM3D1Format::WriteMolecule(OBBase* pOb, OBConversion* pConv)
90
0
  {
91
0
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
92
0
    if (pmol == nullptr)
93
0
      return false;
94
95
    //Define some references so we can use the old parameter names
96
0
    ostream &ofs = *pConv->GetOutStream();
97
0
    OBMol &mol = *pmol;
98
99
0
    return(WriteChem3d(ofs,mol,"MM2"));
100
0
  }
101
102
  //***********************************************************
103
  class CHEM3D2Format : public OBMoleculeFormat
104
  {
105
  public:
106
    //Register this format type ID
107
    CHEM3D2Format()
108
6
    {
109
6
      OBConversion::RegisterFormat("c3d2",this);
110
6
    }
111
112
    const char* Description() override  // required
113
0
    {
114
0
      return
115
0
        "Chem3D Cartesian 2 format\n"
116
0
        "No comments yet\n";
117
0
    }
118
119
    const char* SpecificationURL() override
120
0
    { return ""; }  // optional
121
122
    //Flags() can return be any the following combined by | or be omitted if none apply
123
    // NOTREADABLE  READONEONLY  NOTWRITABLE  WRITEONEONLY
124
    unsigned int Flags() override
125
6
    {
126
6
      return READONEONLY;
127
6
    }
128
129
    //*** This section identical for most OBMol conversions ***
130
    ////////////////////////////////////////////////////
131
    /// The "API" interface functions
132
    bool ReadMolecule(OBBase* pOb, OBConversion* pConv) override;
133
    bool WriteMolecule(OBBase* pOb, OBConversion* pConv) override;
134
  };
135
  //***
136
137
  //Make an instance of the format class
138
  CHEM3D2Format theCHEM3D2Format;
139
140
  /////////////////////////////////////////////////////////////////
141
  bool CHEM3D2Format::ReadMolecule(OBBase* pOb, OBConversion* pConv)
142
0
  {
143
144
0
    OBMol* pmol = pOb->CastAndClear<OBMol>();
145
0
    if (pmol == nullptr)
146
0
      return false;
147
148
    //Define some references so we can use the old parameter names
149
0
    istream &ifs = *pConv->GetInStream();
150
0
    OBMol &mol = *pmol;
151
0
    mol.SetTitle( pConv->GetTitle()); //default title is the filename
152
153
0
    return(CHEM3D1Format::ReadChem3d(ifs,mol,false,"C3D"));
154
0
  }
155
156
  ////////////////////////////////////////////////////////////////
157
158
  bool CHEM3D2Format::WriteMolecule(OBBase* pOb, OBConversion* pConv)
159
0
  {
160
0
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
161
0
    if (pmol == nullptr)
162
0
      return false;
163
164
    //Define some references so we can use the old parameter names
165
0
    ostream &ofs = *pConv->GetOutStream();
166
0
    OBMol &mol = *pmol;
167
168
0
    return(CHEM3D1Format::WriteChem3d(ofs,mol,"C3D"));
169
0
  }
170
171
  //****************************************************************
172
173
  bool CHEM3D1Format::ReadChem3d(istream &ifs,OBMol &mol,bool mmads,const char *type_key)
174
0
  {
175
0
    char buffer[BUFF_SIZE];
176
0
    int natoms,i;
177
0
    char tmp[16],tmp1[16];
178
0
    char atomic_type[16];
179
0
    double exponent = 0.0;
180
0
    double divisor = 1.0;
181
0
    double Alpha,Beta,Gamma,A,B,C;
182
0
    bool has_fractional = false, has_divisor = false;
183
0
    matrix3x3 m;
184
185
0
    vector<string> vs;
186
0
    ifs.getline(buffer,BUFF_SIZE);
187
0
    tokenize(vs,buffer);
188
189
0
    if (mmads)
190
0
      {
191
0
        if (vs.empty())
192
0
          return(false);
193
0
        natoms = atoi((char*)vs[0].c_str());
194
0
        if (vs.size() == 2)
195
0
          mol.SetTitle(vs[1]);
196
0
      }
197
0
    else
198
0
      {
199
0
        switch(vs.size())
200
0
          {
201
0
          case 7 :
202
0
            sscanf(buffer,"%d%lf%lf%lf%lf%lf%lf",
203
0
                   &natoms,&Alpha,&Beta,&Gamma,&A,&B,&C);
204
0
            m.FillOrth(Alpha,Beta,Gamma,A,B,C);
205
0
            has_fractional = true;
206
0
            break;
207
0
          case 8 :
208
0
            sscanf(buffer,"%d%lf%lf%lf%lf%lf%lf%lf",
209
0
                   &natoms,&Alpha,&Beta,&Gamma,&A,&B,&C,&exponent);
210
0
            m.FillOrth(Alpha,Beta,Gamma,A,B,C);
211
0
            has_fractional = true;
212
0
            has_divisor = true;
213
0
            break;
214
0
          default :
215
0
            sscanf(buffer,"%d",&natoms);
216
0
            break;
217
0
          }
218
0
      }
219
220
0
    if (!natoms)
221
0
      return(false);
222
0
    divisor = pow(10.0,exponent);
223
0
    mol.ReserveAtoms(natoms);
224
225
0
    ttab.SetToType("INT");
226
0
    ttab.SetFromType(type_key);
227
228
0
    OBAtom *atom;
229
0
    double x,y,z;
230
0
    vector3 v;
231
232
0
    unsigned int k;
233
0
    for (i = 1; i <= natoms; i++)
234
0
      {
235
0
        ifs.getline(buffer,BUFF_SIZE);
236
0
        sscanf(buffer,"%15s%*d%lf%lf%lf%15s",
237
0
               atomic_type,
238
0
               &x,
239
0
               &y,
240
0
               &z,
241
0
               tmp);
242
0
        v.Set(x,y,z);
243
0
        if (has_fractional)
244
0
          v *= m;
245
0
        if (has_divisor)
246
0
          v/= divisor;
247
248
0
        tokenize(vs,buffer);
249
0
        if (vs.empty())
250
0
          return(false);
251
252
0
        atom = mol.NewAtom();
253
0
        ttab.Translate(tmp1,tmp);
254
0
        atom->SetType(tmp1);
255
0
        atom->SetVector(v);
256
0
        atom->SetAtomicNum(OBElements::GetAtomicNum(atomic_type));
257
258
0
        for (k = 6;k < vs.size(); k++)
259
0
          mol.AddBond(atom->GetIdx(),atoi((char*)vs[k].c_str()),1);
260
0
      }
261
262
    // clean out remaining blank lines
263
0
    std::streampos ipos;
264
0
    do
265
0
    {
266
0
      ipos = ifs.tellg();
267
0
      ifs.getline(buffer,BUFF_SIZE);
268
0
    }
269
0
    while(strlen(buffer) == 0 && !ifs.eof() );
270
0
    ifs.seekg(ipos);
271
272
0
    mol.PerceiveBondOrders();
273
274
0
    return(true);
275
0
  }
276
277
  bool CHEM3D1Format::WriteChem3d(ostream &ofs,OBMol &mol, const char *mol_typ)
278
0
  {
279
0
    int atnum;
280
0
    int type_num;
281
0
    char buffer[BUFF_SIZE],type_name[16],ele_type[16];
282
283
0
    ofs << mol.NumAtoms();
284
0
    if (EQ(mol_typ,"MMADS"))
285
0
      {
286
0
        ofs << " " << mol.GetTitle();
287
0
        ttab.SetToType("MM2");
288
0
      }
289
0
    else
290
0
      ttab.SetToType(mol_typ);
291
0
    ofs << endl;
292
293
0
    ttab.SetFromType("INT");
294
295
0
    OBAtom *atom,*nbr;
296
0
    vector<OBAtom*>::iterator i;
297
0
    vector<OBBond*>::iterator j;
298
299
0
    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
300
0
      {
301
0
        if (!ttab.Translate(type_name,atom->GetType()))
302
0
          {
303
0
            snprintf(buffer, BUFF_SIZE,
304
0
                     "Unable to assign %s type to atom %d type = %s\n",
305
0
                     mol_typ,atom->GetIdx(),atom->GetType());
306
0
            obErrorLog.ThrowError(__FUNCTION__, buffer, obInfo);
307
0
            atnum = atom->GetAtomicNum();
308
0
            type_num = atnum * 10 + atom->GetExplicitDegree();
309
0
            snprintf(type_name, sizeof(type_num), "%d",type_num);
310
0
          }
311
0
        strncpy(ele_type, OBElements::GetSymbol(atom->GetAtomicNum()), sizeof(ele_type));
312
0
        ele_type[sizeof(ele_type) - 1] = '\0';
313
0
        snprintf(buffer, BUFF_SIZE, "%-3s %-5d %8.4f  %8.4f  %8.4f %5s",
314
0
                ele_type,
315
0
                atom->GetIdx(),
316
0
                atom->x(),
317
0
                atom->y(),
318
0
                atom->z(),
319
0
                type_name);
320
0
        ofs << buffer;
321
322
0
        for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
323
0
          {
324
0
            snprintf(buffer, BUFF_SIZE, "%6d",nbr->GetIdx());
325
0
            ofs << buffer;
326
0
          }
327
0
        ofs << endl;
328
0
      }
329
0
    return(true);
330
0
  }
331
332
} //namespace OpenBabel