Coverage Report

Created: 2025-08-29 06:48

/src/openbabel/src/ops/readconformers.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
read-conformers.cpp - A OBOp for combining conformers during conversion.
3
4
Copyright (C) 2010 by Chris Morley
5
6
This file is part of the Open Babel project.
7
For more information, see <http://openbabel.org/>
8
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation version 2 of the License.
12
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
***********************************************************************/
18
#include <openbabel/babelconfig.h>
19
#include <openbabel/op.h>
20
#include <openbabel/mol.h>
21
#include <openbabel/obconversion.h>
22
#include "deferred.h"
23
#include <algorithm>
24
25
namespace OpenBabel
26
{
27
28
class OpReadConformers : public OBOp
29
{
30
public:
31
6
  OpReadConformers(const char* ID) : OBOp(ID, false){};
32
0
  const char* Description() override { return
33
0
    "Adjacent conformers combined into a single molecule\n"
34
0
    "If a molecule has the same structure as the preceding molecule, as determined\n"
35
0
    "from its SMILES, it is not output but its coordinates are added to the\n"
36
0
    "preceding molecule as an additional conformer. There can be multiple groups\n"
37
0
    "of conformers, but the molecules in each group must be adjacent.\n"
38
0
    ; }
39
40
0
  bool WorksWith(OBBase* pOb) const override { return dynamic_cast<OBMol*>(pOb) != nullptr; }
41
  bool Do(OBBase* pOb, const char* OptionText=nullptr, OpMap* pOptions=nullptr, OBConversion* pConv=nullptr) override;
42
  bool ProcessVec(std::vector<OBBase*>& vec) override;
43
};
44
45
/////////////////////////////////////////////////////////////////
46
OpReadConformers theOpReadConformers("readconformer"); //Global instance
47
48
/////////////////////////////////////////////////////////////////
49
bool OpReadConformers::Do(OBBase* pOb, const char* OptionText, OpMap* pOptions, OBConversion* pConv)
50
0
{
51
  //Make a deferred format and divert the output to it
52
0
  if(pConv && pConv->IsFirstInput())
53
0
    new DeferredFormat(pConv, this); //it will delete itself
54
55
0
  return true;
56
0
}
57
58
bool OpReadConformers::ProcessVec(std::vector<OBBase*>& vec)
59
0
{
60
  // DeferredFormat collects all the molecules, they are processed here, and Deferred Format outputs them
61
0
  OBConversion smconv;
62
0
  smconv.AddOption("n");
63
0
  if(!smconv.SetOutFormat("smi"))
64
0
  {
65
0
    obErrorLog.ThrowError(__FUNCTION__, "SmilesFormat is not loaded" , obError, onceOnly);
66
0
    return false;
67
0
  }
68
69
0
  std::string smiles, stored_smiles;
70
0
  OBMol* stored_pmol=nullptr;
71
0
  std::vector<OBBase*>::iterator iter;
72
0
  for(iter= vec.begin();iter!=vec.end();++iter)
73
0
  {
74
0
    OBMol* pmol = dynamic_cast<OBMol*>(*iter);
75
0
    if(!pmol)
76
0
      continue;
77
0
    smiles = smconv.WriteString(pmol);
78
0
    Trim(smiles);
79
80
0
    if(stored_smiles==smiles)
81
0
    {
82
      //add the coordinates of the current mol to the stored one as a conformer, and delete current mol
83
0
      double *confCoord = new double [pmol->NumAtoms() * 3];
84
0
      memcpy((char*)confCoord,(char*)pmol->GetCoordinates(),sizeof(double)*3*pmol->NumAtoms());
85
0
      stored_pmol->AddConformer(confCoord);
86
0
      delete pmol;
87
0
      *iter = nullptr;
88
0
    }
89
0
    else
90
0
    {
91
0
      stored_pmol = pmol;
92
0
      stored_smiles = smiles;
93
0
    }
94
0
  }
95
96
  //erase the NULLS
97
0
  vec.erase(std::remove(vec.begin(), vec.end(), nullptr), vec.end());
98
0
  return true;
99
0
}
100
101
} //namespace
102
103
/*
104
    To use with OBConversion::Read(), etc.
105
    OBMol mol;
106
    vector<OBBase*> vec;
107
    while(pConv->Read(&mol))
108
      vec.push_back(&mol);
109
    OBOp* pOp = OBOp::FindType("readconformers");
110
    if(!pOp)
111
      pOp->ProcessVec(vec);
112
    vec now contains one or more molecules with multiple conformers
113
*/