/src/openbabel/src/molchrg.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************** |
2 | | molchrg.cpp - Assign Gasteiger partial charges. |
3 | | |
4 | | Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc. |
5 | | Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison |
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 | | #include <openbabel/babelconfig.h> |
20 | | |
21 | | #include <openbabel/mol.h> |
22 | | #include <openbabel/atom.h> |
23 | | #include <openbabel/bond.h> |
24 | | #include <openbabel/generic.h> |
25 | | #include <openbabel/oberror.h> |
26 | | #include <openbabel/molchrg.h> |
27 | | #include <openbabel/elements.h> |
28 | | |
29 | | #include <cstring> |
30 | | |
31 | | using namespace std; |
32 | | namespace OpenBabel |
33 | | { |
34 | | |
35 | | /*! \class OBGastChrg molchrg.h <openbabel/molchrg.h> |
36 | | \brief Assigns Gasteiger partial charges |
37 | | |
38 | | The OBGastChrg class is responsible for the assignment of partial |
39 | | charges to a molecule according to the Gasteiger charge model (sigma). When |
40 | | the partial charge of an atom is requested and partial charges do not |
41 | | yet exist for the molecule the OBGastChrg class will automatically be |
42 | | called to assign charges for the molecule. If charges have been read |
43 | | in for a molecule the following code shows how to force the |
44 | | recalculation of partial charges: |
45 | | \code |
46 | | OBMol mol; |
47 | | |
48 | | mol.UnsetPartialChargesPerceived(); |
49 | | FOR_ATOMS_IN_MOL(atom, mol) |
50 | | { |
51 | | cout << "atom number = " << atom->GetIdx(); |
52 | | cout << " charge = " << atom->GetPartialCharge() << endl; |
53 | | } |
54 | | \endcode |
55 | | Formal charges are used as seed values of the initial charge of atoms, |
56 | | and the partial charge is propagated to neighboring atoms. For |
57 | | example, quaternary amines would have a +1 charge, and the effect of |
58 | | the positive charge would be felt by neighboring atoms according to |
59 | | the Gasteiger model (sigma). |
60 | | |
61 | | For more information, see: |
62 | | J. Gasteiger & M. Marsili, "A New Model for Calculating Atomic Charges in Molecules" Tetrahedron Lett., (1978) 3181-3184. |
63 | | */ |
64 | | |
65 | | bool OBGastChrg::AssignPartialCharges(OBMol &mol) |
66 | 0 | { |
67 | | //InitialPartialCharges(mol); |
68 | 0 | obErrorLog.ThrowError(__FUNCTION__, |
69 | 0 | "Ran OpenBabel::AssignPartialCharges", obAuditMsg); |
70 | | |
71 | | // Annotate that partial charges come from Gasteiger |
72 | 0 | OBPairData *dp = new OBPairData; |
73 | 0 | dp->SetAttribute("PartialCharges"); |
74 | 0 | dp->SetValue("Gasteiger"); |
75 | 0 | dp->SetOrigin(perceived); |
76 | 0 | mol.SetData(dp); |
77 | |
|
78 | 0 | OBAtom *atom; |
79 | 0 | vector<OBAtom*>::iterator i; |
80 | |
|
81 | 0 | GSVResize(mol.NumAtoms()+1); |
82 | 0 | double a,b,c; |
83 | 0 | for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) |
84 | 0 | { |
85 | 0 | if (!GasteigerSigmaChi(atom,a,b,c)) |
86 | 0 | return(false); |
87 | 0 | _gsv[atom->GetIdx()]->SetValues(a,b,c,atom->GetPartialCharge()); |
88 | 0 | } |
89 | | |
90 | 0 | double alpha,charge,denom; |
91 | 0 | unsigned j; |
92 | 0 | int iter; |
93 | 0 | OBBond *bond; |
94 | 0 | OBAtom *src,*dst; |
95 | 0 | vector<OBBond*>::iterator k; |
96 | 0 | alpha = 1.0; |
97 | 0 | for(iter = 0;iter < OB_GASTEIGER_ITERS;++iter) |
98 | 0 | { |
99 | 0 | alpha *= OB_GASTEIGER_DAMP; |
100 | |
|
101 | 0 | for( j=1;j < _gsv.size();++j) |
102 | 0 | { |
103 | 0 | charge = _gsv[j]->q; |
104 | 0 | _gsv[j]->chi = (_gsv[j]->c*charge+_gsv[j]->b)*charge+_gsv[j]->a; |
105 | 0 | } |
106 | |
|
107 | 0 | for (bond = mol.BeginBond(k);bond;bond = mol.NextBond(k)) |
108 | 0 | { |
109 | 0 | src = bond->GetBeginAtom(); |
110 | 0 | dst = bond->GetEndAtom(); |
111 | |
|
112 | 0 | if (_gsv[src->GetIdx()]->chi >= _gsv[dst->GetIdx()]->chi) |
113 | 0 | { |
114 | 0 | if (dst->GetAtomicNum() == OBElements::Hydrogen) |
115 | 0 | denom = double(OB_GASTEIGER_DENOM); |
116 | 0 | else |
117 | 0 | denom = _gsv[dst->GetIdx()]->denom; |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | if (src->GetAtomicNum() == OBElements::Hydrogen) |
122 | 0 | denom = double(OB_GASTEIGER_DENOM); |
123 | 0 | else |
124 | 0 | denom = _gsv[src->GetIdx()]->denom; |
125 | 0 | } |
126 | |
|
127 | 0 | charge = (_gsv[src->GetIdx()]->chi - _gsv[dst->GetIdx()]->chi)/denom; |
128 | 0 | _gsv[src->GetIdx()]->q -= alpha*charge; |
129 | 0 | _gsv[dst->GetIdx()]->q += alpha*charge; |
130 | 0 | } |
131 | 0 | } |
132 | |
|
133 | 0 | for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) |
134 | 0 | atom->SetPartialCharge(_gsv[atom->GetIdx()]->q); |
135 | |
|
136 | 0 | return(true); |
137 | 0 | } |
138 | | |
139 | | //! Set initial partial charges in @p mol |
140 | | //! Carbonyl O => -0.5 |
141 | | //! Phosphate O => -0.666 |
142 | | //! Sulfate O => -0.5 |
143 | | //! All other atoms are set to have their initial charge from their formal charge |
144 | | void OBGastChrg::InitialPartialCharges(OBMol &mol) |
145 | 0 | { |
146 | 0 | OBAtom *atom; |
147 | 0 | vector<OBAtom*>::iterator i; |
148 | |
|
149 | 0 | for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) |
150 | 0 | { |
151 | 0 | if (atom->IsCarboxylOxygen()) |
152 | 0 | atom->SetPartialCharge(-0.500); |
153 | 0 | else if (atom->IsPhosphateOxygen() && |
154 | 0 | atom->GetHvyDegree() == 1) |
155 | 0 | atom->SetPartialCharge(-0.666); |
156 | 0 | else if (atom->IsSulfateOxygen()) |
157 | 0 | atom->SetPartialCharge(-0.500); |
158 | 0 | else |
159 | 0 | atom->SetPartialCharge((double)atom->GetFormalCharge()); |
160 | 0 | } |
161 | 0 | } |
162 | | |
163 | | bool OBGastChrg::GasteigerSigmaChi(OBAtom *atom,double &a,double &b,double &c ) |
164 | 0 | { |
165 | 0 | int count; |
166 | 0 | double val[3] = {0.0,0.0,0.0}; |
167 | |
|
168 | 0 | switch(atom->GetAtomicNum()) |
169 | 0 | { |
170 | 0 | case 1: //H |
171 | 0 | val[0] = 0.37; |
172 | 0 | val[1] = 7.17; |
173 | 0 | val[2] = 12.85; |
174 | 0 | break; |
175 | 0 | case 6: //C |
176 | 0 | if (atom->GetHyb() == 3) |
177 | 0 | { |
178 | 0 | val[0] = 0.68; |
179 | 0 | val[1] = 7.98; |
180 | 0 | val[2] = 19.04; |
181 | 0 | } |
182 | 0 | if (atom->GetHyb() == 2) |
183 | 0 | { |
184 | 0 | val[0] = 0.98; |
185 | 0 | val[1] = 8.79; |
186 | 0 | val[2] = 19.62; |
187 | 0 | } |
188 | 0 | if (atom->GetHyb() == 1) |
189 | 0 | { |
190 | 0 | val[0] = 1.67; |
191 | 0 | val[1] = 10.39; |
192 | 0 | val[2] = 20.57; |
193 | 0 | } |
194 | 0 | break; |
195 | 0 | case 7: //N |
196 | 0 | if (atom->GetHyb() == 3) |
197 | 0 | { |
198 | 0 | if (atom->GetExplicitDegree() == 4 || atom->GetFormalCharge()) |
199 | 0 | { |
200 | 0 | val[0] = 0.0; |
201 | 0 | val[1] = 0.0; |
202 | 0 | val[2] = 23.72; |
203 | 0 | } |
204 | 0 | else |
205 | 0 | { |
206 | 0 | val[0] = 2.08; |
207 | 0 | val[1] = 11.54; |
208 | 0 | val[2] = 23.72; |
209 | 0 | } |
210 | 0 | } |
211 | |
|
212 | 0 | if (atom->GetHyb() == 2) |
213 | 0 | { |
214 | 0 | if (EQ(atom->GetType(),"Npl") || EQ(atom->GetType(),"Nam")) |
215 | 0 | { |
216 | 0 | val[0] = 2.46; |
217 | 0 | val[1] = 12.32; |
218 | 0 | val[2] = 24.86; |
219 | 0 | } |
220 | 0 | else |
221 | 0 | { |
222 | 0 | val[0] = 2.57; |
223 | 0 | val[1] = 12.87; |
224 | 0 | val[2] = 24.87; |
225 | 0 | } |
226 | 0 | } |
227 | |
|
228 | 0 | if (atom->GetHyb() == 1) |
229 | 0 | { |
230 | 0 | val[0] = 3.71; |
231 | 0 | val[1] = 15.68; |
232 | 0 | val[2] = 27.11; |
233 | 0 | } |
234 | 0 | break; |
235 | 0 | case 8: //O |
236 | 0 | if (atom->GetHyb() == 3) |
237 | 0 | { |
238 | 0 | val[0] = 2.65; |
239 | 0 | val[1] = 14.18; |
240 | 0 | val[2] = 28.49; |
241 | 0 | } |
242 | 0 | if (atom->GetHyb() == 2) |
243 | 0 | { |
244 | 0 | val[0] = 3.75; |
245 | 0 | val[1] = 17.07; |
246 | 0 | val[2] = 31.33; |
247 | 0 | } |
248 | 0 | break; |
249 | 0 | case 9: //F |
250 | 0 | val[0] = 3.12; |
251 | 0 | val[1] = 14.66; |
252 | 0 | val[2] = 30.82; |
253 | 0 | break; |
254 | 0 | case 15: //P |
255 | 0 | val[0] = 1.62; |
256 | 0 | val[1] = 8.90; |
257 | 0 | val[2] = 18.10; |
258 | 0 | break; |
259 | 0 | case 16: //S |
260 | 0 | count = atom->CountFreeOxygens(); |
261 | 0 | if (count == 0 || count == 1) |
262 | 0 | { |
263 | 0 | val[0] = 2.39; |
264 | 0 | val[1] = 10.14; |
265 | 0 | val[2] = 20.65; |
266 | 0 | } |
267 | 0 | if (count > 1) |
268 | 0 | { |
269 | 0 | val[0] = 2.39; |
270 | 0 | val[1] = 12.00; |
271 | 0 | val[2] = 24.00; |
272 | 0 | } |
273 | | /*S2? if (count == 0) {val[0] = 2.72;val[1] = 10.88;val[2] = 21.69;}*/ |
274 | 0 | break; |
275 | 0 | case 17: //Cl |
276 | 0 | val[0] = 2.66; |
277 | 0 | val[1] = 11.00; |
278 | 0 | val[2] = 22.04; |
279 | 0 | break; |
280 | 0 | case 35: //Br |
281 | 0 | val[0] = 2.77; |
282 | 0 | val[1] = 10.08; |
283 | 0 | val[2] = 19.71; |
284 | 0 | break; |
285 | 0 | case 53: //I |
286 | 0 | val[0] = 2.90; |
287 | 0 | val[1] = 9.90; |
288 | 0 | val[2] = 18.82; |
289 | 0 | break; |
290 | 0 | case 13: //Al |
291 | 0 | val[0] = 1.06; |
292 | 0 | val[1] = 5.47; |
293 | 0 | val[2] = 11.65; |
294 | 0 | break; |
295 | 0 | } |
296 | | |
297 | 0 | if (!IsNearZero(val[2])) |
298 | 0 | { |
299 | 0 | a = val[1]; |
300 | 0 | b = (val[2]-val[0])/2; |
301 | 0 | c = (val[2]+val[0])/2 - val[1]; |
302 | 0 | } |
303 | 0 | else |
304 | 0 | return(false); |
305 | | |
306 | 0 | return(true); |
307 | 0 | } |
308 | | |
309 | | void OBGastChrg::GSVResize(int size) |
310 | 0 | { |
311 | 0 | vector <GasteigerState*>::iterator i; |
312 | 0 | for (i = _gsv.begin();i != _gsv.end();++i) |
313 | 0 | delete *i; |
314 | 0 | _gsv.clear(); |
315 | |
|
316 | 0 | for (int j = 0;j < size;++j) |
317 | 0 | _gsv.push_back(new GasteigerState); |
318 | 0 | } |
319 | | |
320 | | OBGastChrg::~OBGastChrg() |
321 | 0 | { |
322 | 0 | vector <GasteigerState*>::iterator i; |
323 | 0 | for (i = _gsv.begin();i != _gsv.end();++i) |
324 | 0 | delete *i; |
325 | 0 | } |
326 | | |
327 | | GasteigerState::GasteigerState() |
328 | 0 | { |
329 | 0 | a = 0.0; |
330 | 0 | b = 0.0; |
331 | 0 | c = 0.0; |
332 | 0 | denom = 0.0; |
333 | 0 | chi = 0.0; |
334 | 0 | q = 0.0; |
335 | 0 | } |
336 | | |
337 | | } // end namespace OpenBabel |
338 | | |
339 | | //! \file molchrg.cpp |
340 | | //! \brief Assign Gasteiger partial charges. |