Coverage Report

Created: 2025-07-13 06:44

/src/openbabel/src/charges/fromfile.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
  fromfile.cpp - A OBChargeModel to apply charges specified in a file
3
4
  Copyright (C) 2015 M J Harvey, Acellera Ltd
5
  m.j.harvey (at) acellera.com
6
7
  This file is part of the Open Babel project.
8
  For more information, see <http://openbabel.org/>
9
10
  This program is free software; you can redistribute it and/or modify
11
  it under the terms of the GNU General Public License as published by
12
  the Free Software Foundation version 2 of the License.
13
14
  This program is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
  GNU General Public License for more details.
18
 ***********************************************************************/
19
20
#include <openbabel/babelconfig.h>
21
#include <openbabel/chargemodel.h>
22
#include <openbabel/mol.h>
23
#include <openbabel/atom.h>
24
#include <openbabel/obiter.h>
25
#include <openbabel/oberror.h>
26
#include <openbabel/elements.h>
27
#include <openbabel/generic.h>
28
29
#include <openbabel/molchrg.h>
30
#include <openbabel/obconversion.h>
31
#include <openbabel/obmolecformat.h>
32
33
#include <openbabel/obiter.h>
34
#include <openbabel/data.h>
35
36
37
using namespace std;
38
39
namespace OpenBabel
40
{
41
42
  class FromFileCharges : public OBChargeModel
43
  {
44
    public:
45
2
      FromFileCharges(const char* ID) : OBChargeModel(ID, false){
46
2
      };
47
48
0
      const char* Description() override { return "Assign charges from file containing {'atom-name', charge} pairs"; }
49
50
      bool ComputeCharges(OBMol &mol, const char *arg ) override;
51
52
  };
53
54
  /////////////////////////////////////////////////////////////////
55
  FromFileCharges theFromFileCharges("fromfile"); //Global instance
56
57
0
  bool read_file( const char *file, std::map< std::string, double> &q_by_name ) {
58
0
    char name[17];
59
0
    double q;
60
61
0
    FILE *fin = fopen( file, "r" );
62
63
0
    if( !fin ) {
64
0
      stringstream msg;
65
0
      msg << "Cannot open file " << file << endl;
66
0
      obErrorLog.ThrowError(__FUNCTION__, msg.str(), obError);
67
0
      return false;
68
0
    }
69
0
    while( 2 == fscanf( fin, "%16s %lf\n", name, &q ) ) {
70
0
      q_by_name.insert( std::pair<std::string, double>( string(name), q) );
71
0
    }
72
0
    fclose( fin );
73
74
0
    return true;
75
0
  }
76
77
  /////////////////////////////////////////////////////////////////
78
79
  bool FromFileCharges::ComputeCharges(OBMol &mol, const char *arg )
80
0
  {
81
82
0
    if( !arg ) {
83
0
      stringstream msg;
84
0
      msg << "Charge file argument required:" << endl
85
0
        << "\tbabel --partialcharge fromfile:/path/to/file"<< endl
86
0
        << "File format is one 'atom-name charge' pair per line, eg:"<<endl
87
0
        << "\tC1\t1.0" << endl
88
0
        << "\tO2\t-1.5" << endl;
89
0
      obErrorLog.ThrowError(__FUNCTION__, msg.str(), obError);
90
0
      return false;
91
0
    }
92
93
0
    std::map< std::string,  double> q_by_name;
94
0
    if( !read_file( arg, q_by_name ) ) {
95
0
      return false;
96
0
    }
97
98
99
0
    mol.SetPartialChargesPerceived();
100
101
102
0
    for ( int i = 1; i <= mol.NumAtoms(); i++)
103
0
    {
104
0
      OBAtom *a = mol.GetAtom(i);
105
106
0
      OBResidue *res;
107
0
      double q   = 0.;
108
0
      bool found = false;
109
0
      char *name = nullptr;
110
111
      // First try atom type name
112
0
      if ((res = a->GetResidue()) != nullptr)
113
0
      {
114
0
        char *f = name  = (char*)res->GetAtomID( a ).c_str();
115
0
        for( int j = strlen(f)-1; j>=0; j-- ) { if( f[j]==' ' ){ f[j]='\0'; } } // trim trailing whitespace
116
0
        std::string ff = string(f);
117
0
        if( q_by_name.count( ff ) ) {
118
0
          q = q_by_name[ string(ff) ];
119
0
          found = true;
120
0
        }
121
0
      }
122
      // Then try the element symbol
123
0
      if( !found ) {
124
0
        std::string ff  = string( OBElements::GetSymbol(a->GetAtomicNum()) );
125
0
        if( q_by_name.count( ff ) ) {
126
0
          q = q_by_name[ string(ff) ];
127
0
          found = true;
128
0
        }
129
0
      }
130
      // Finally "*" wildcard
131
0
      if( !found ) {
132
0
        std::string ff  = string("*");
133
0
        if( q_by_name.count( "*" ) ) {
134
0
          q = q_by_name[ string(ff) ];
135
0
          found = true;
136
0
        }
137
0
      }
138
139
0
      if( !found ) {
140
0
        stringstream msg;
141
0
        msg << "Charge mapping for atom # " << i ;
142
0
        if( name ) {
143
0
          msg << " (" << name <<") ";
144
0
        }
145
0
        msg << "not found " <<  endl;  
146
0
        obErrorLog.ThrowError(__FUNCTION__, msg.str(), obError);
147
0
        return false;
148
0
      }
149
150
0
      a->SetPartialCharge( q );
151
152
0
    }
153
154
0
    OBPairData *dp = new OBPairData;
155
0
    dp->SetAttribute("PartialCharges");
156
0
    dp->SetValue("User Charges");
157
0
    dp->SetOrigin(perceived);
158
0
    mol.SetData(dp);
159
160
0
    OBChargeModel::FillChargeVectors(mol);
161
162
0
    return true;
163
0
  }
164
165
}//namespace