/src/openbabel/src/ops/forcefield.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | forcefield.cpp - A OBOp to calculate and minimize the energy using a |
3 | | forcefield (re-wrap of obminimize and obenergy) |
4 | | |
5 | | Copyright (C) 2006-2007 by Tim Vandermeersch |
6 | | (C) 2009 by Chris Morley |
7 | | |
8 | | This file is part of the Open Babel project. |
9 | | For more information, see <http://openbabel.org/> |
10 | | |
11 | | This program is free software; you can redistribute it and/or modify |
12 | | it under the terms of the GNU General Public License as published by |
13 | | the Free Software Foundation version 2 of the License. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, |
16 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | GNU General Public License for more details. |
19 | | ***********************************************************************/ |
20 | | |
21 | | /****************************************************************************** |
22 | | **** CURRENTLY ONLY SUITABLE FOR USE WITH THE OBABEL COMMANDLINE INTERFACE **** |
23 | | This allows options to have parameters, e.g. --ff Ghemical |
24 | | Compile with tools/obabel.cpp rather than tools/babel.cpp |
25 | | |
26 | | *******************************************************************************/ |
27 | | |
28 | | #include <openbabel/babelconfig.h> |
29 | | #include <iostream> |
30 | | #include <cstdlib> |
31 | | #include<openbabel/op.h> |
32 | | #include<openbabel/mol.h> |
33 | | #include<openbabel/forcefield.h> |
34 | | #include<openbabel/generic.h> |
35 | | |
36 | | namespace OpenBabel |
37 | | { |
38 | | using namespace std; |
39 | | |
40 | | ////////////////////////////////////////////////////////// |
41 | | // |
42 | | // OpEnergy |
43 | | // |
44 | | ////////////////////////////////////////////////////////// |
45 | | |
46 | | class OpEnergy : public OBOp |
47 | | { |
48 | | public: |
49 | 2 | OpEnergy(const char *ID) : OBOp(ID, false) {} |
50 | | |
51 | | const char* Description() override |
52 | 0 | { |
53 | 0 | return "ForceField Energy Evaluation (not displayed in GUI)\n" |
54 | 0 | "Typical usage: obabel infile.xxx -O outfile.yy --energy --log\n" |
55 | 0 | " options: description\n" |
56 | 0 | " --log output a log of the energies (default = no log)\n" |
57 | 0 | " --epsilon # set the dielectric constant for electrostatics\n" |
58 | 0 | " --noh don't add explicit hydrogens (default = make explicit)\n" |
59 | 0 | " --ff # select a forcefield (default = MMFF94)\n" |
60 | 0 | " The hydrogens are made explicit by default before energy evaluation.\n" |
61 | 0 | " The energy is put in an OBPairData object \"Energy\" which is\n" |
62 | 0 | " accessible via an SDF or CML property or --append (to title).\n" |
63 | 0 | ; |
64 | 0 | } |
65 | | |
66 | | bool WorksWith(OBBase* pOb) const override |
67 | 0 | { |
68 | 0 | return dynamic_cast<OBMol*>(pOb) != nullptr; |
69 | 0 | } |
70 | | bool Do(OBBase* pOb, const char* OptionText, OpMap* pmap, OBConversion*) override; |
71 | | }; |
72 | | |
73 | | ////////////////////////////////////////////////////////// |
74 | | OpEnergy theOpEnergy("energy"); //Global instance |
75 | | |
76 | | ////////////////////////////////////////////////////////// |
77 | | bool OpEnergy::Do(OBBase* pOb, const char* OptionText, OpMap* pmap, OBConversion*) |
78 | 0 | { |
79 | 0 | OBMol* pmol = dynamic_cast<OBMol*>(pOb); |
80 | 0 | if(!pmol) |
81 | 0 | return false; |
82 | | |
83 | 0 | bool log = false; |
84 | 0 | bool addh = true; |
85 | |
|
86 | 0 | string ff = "MMFF94"; |
87 | 0 | double epsilon = 1.0; |
88 | 0 | OpMap::const_iterator iter = pmap->find("ff"); |
89 | 0 | if(iter!=pmap->end()) |
90 | 0 | ff = iter->second; |
91 | 0 | OBForceField* pFF = OBForceField::FindForceField(ff); |
92 | 0 | iter = pmap->find("epsilon"); |
93 | 0 | if (iter!=pmap->end()) |
94 | 0 | epsilon = atof(iter->second.c_str()); |
95 | |
|
96 | 0 | iter = pmap->find("log"); |
97 | 0 | if(iter!=pmap->end()) |
98 | 0 | log=true; |
99 | |
|
100 | 0 | iter = pmap->find("noh"); |
101 | 0 | if(iter!=pmap->end()) |
102 | 0 | addh=false; |
103 | |
|
104 | 0 | if (addh) |
105 | 0 | pmol->AddHydrogens(false, false); |
106 | | |
107 | | // set some force field variables |
108 | 0 | pFF->SetLogFile(&clog); |
109 | 0 | pFF->SetLogLevel(log ? OBFF_LOGLVL_MEDIUM : OBFF_LOGLVL_NONE); |
110 | |
|
111 | 0 | pFF->SetDielectricConstant(epsilon); |
112 | 0 | if (!pFF->Setup(*pmol)) { |
113 | 0 | cerr << "Could not setup force field." << endl; |
114 | 0 | return false; |
115 | 0 | } |
116 | | |
117 | | //Put the energy in a OBPairData object |
118 | 0 | OBPairData *dp = new OBPairData; |
119 | 0 | dp->SetAttribute("Energy"); |
120 | 0 | stringstream ss; |
121 | 0 | ss << pFF->Energy(false); |
122 | 0 | dp->SetValue(ss.str()); |
123 | 0 | dp->SetOrigin(fileformatInput); |
124 | 0 | pmol->SetData(dp); |
125 | |
|
126 | 0 | return true; |
127 | 0 | } |
128 | | |
129 | | ////////////////////////////////////////////////////////// |
130 | | // |
131 | | // OpMinimize |
132 | | // |
133 | | ////////////////////////////////////////////////////////// |
134 | | |
135 | | class OpMinimize : public OBOp |
136 | | { |
137 | | public: |
138 | 2 | OpMinimize(const char* ID) : OBOp(ID, false) {} |
139 | | |
140 | | const char* Description() override |
141 | 0 | { |
142 | 0 | return "ForceField Energy Minimization (not displayed in GUI)\n" |
143 | 0 | "Typical usage: obabel infile.xxx -O outfile.yyy --minimize --steps 1500 --sd\n" |
144 | 0 | " options: description:\n" |
145 | 0 | " --log output a log of the minimization process(default= no log)\n" |
146 | 0 | " --crit # set convergence criteria (default=1e-6)\n" |
147 | 0 | " --sd use steepest descent algorithm (default = conjugate gradient)\n" |
148 | 0 | " --newton use Newton2Num linesearch (default = Simple)\n" |
149 | 0 | " --ff # select a forcefield (default = Ghemical)\n" |
150 | 0 | " --steps # specify the maximum number of steps (default = 2500)\n" |
151 | 0 | " --cut use cut-off (default = don't use cut-off)\n" |
152 | 0 | " --noh don't add explicit hydrogens (default = make explicit)\n" |
153 | 0 | " --epsilon # relative dielectric constant (default = 1.0)\n" |
154 | 0 | " --rvdw # specify the VDW cut-off distance (default = 6.0)\n" |
155 | 0 | " --rele # specify the Electrostatic cut-off distance (default = 10.0)\n" |
156 | 0 | " --freq # specify the frequency to update the non-bonded pairs (default = 10)\n" |
157 | 0 | " The hydrogens are made explicit before minimization by default.\n" |
158 | 0 | " The energy is put in an OBPairData object \"Energy\" which is\n" |
159 | 0 | " accessible via an SDF or CML property or --append (to title).\n" |
160 | 0 | ; |
161 | 0 | } |
162 | | |
163 | | bool WorksWith(OBBase* pOb) const override |
164 | 0 | { |
165 | 0 | return dynamic_cast<OBMol*>(pOb) != nullptr; |
166 | 0 | } |
167 | | bool Do(OBBase* pOb, const char* OptionText, OpMap* pmap, OBConversion*) override; |
168 | | }; |
169 | | |
170 | | ////////////////////////////////////////////////////////// |
171 | | OpMinimize theOpMinimize("minimize"); //Global instance |
172 | | |
173 | | ////////////////////////////////////////////////////////// |
174 | | bool OpMinimize::Do(OBBase* pOb, const char* OptionText, OpMap* pmap, OBConversion*) |
175 | 0 | { |
176 | 0 | OBMol* pmol = dynamic_cast<OBMol*>(pOb); |
177 | 0 | if(!pmol) |
178 | 0 | return false; |
179 | | |
180 | 0 | int steps = 2500; |
181 | 0 | double crit = 1e-6; |
182 | 0 | bool sd = false; |
183 | 0 | bool cut = false; |
184 | 0 | bool addh = true; |
185 | 0 | bool newton = true; |
186 | 0 | double epsilon = 1.0; |
187 | 0 | double rvdw = 6.0; |
188 | 0 | double rele = 10.0; |
189 | 0 | int freq = 10; |
190 | 0 | bool log = false; |
191 | |
|
192 | 0 | string ff = "MMFF94"; |
193 | 0 | OpMap::const_iterator iter = pmap->find("ff"); |
194 | 0 | if(iter!=pmap->end()) |
195 | 0 | ff = iter->second; |
196 | 0 | OBForceField* pFF = OBForceField::FindForceField(ff); |
197 | |
|
198 | 0 | iter = pmap->find("sd"); |
199 | 0 | if(iter!=pmap->end()) |
200 | 0 | sd=true; |
201 | |
|
202 | 0 | iter = pmap->find("newton"); |
203 | 0 | if(iter!=pmap->end()) |
204 | 0 | newton=true; |
205 | |
|
206 | 0 | iter = pmap->find("cut"); |
207 | 0 | if(iter!=pmap->end()) |
208 | 0 | cut=true; |
209 | |
|
210 | 0 | iter = pmap->find("noh"); |
211 | 0 | if(iter!=pmap->end()) |
212 | 0 | addh=false; |
213 | |
|
214 | 0 | iter = pmap->find("crit"); |
215 | 0 | if(iter!=pmap->end()) |
216 | 0 | crit = atof(iter->second.c_str()); |
217 | |
|
218 | 0 | iter = pmap->find("steps"); |
219 | 0 | if(iter!=pmap->end()) |
220 | 0 | steps = atoi(iter->second.c_str()); |
221 | |
|
222 | 0 | iter = pmap->find("epsilon"); |
223 | 0 | if(iter!=pmap->end()) |
224 | 0 | epsilon = atof(iter->second.c_str()); |
225 | |
|
226 | 0 | iter = pmap->find("rvdw"); |
227 | 0 | if(iter!=pmap->end()) |
228 | 0 | rvdw = atof(iter->second.c_str()); |
229 | |
|
230 | 0 | iter = pmap->find("rele"); |
231 | 0 | if(iter!=pmap->end()) |
232 | 0 | rele = atof(iter->second.c_str()); |
233 | |
|
234 | 0 | iter = pmap->find("pf"); |
235 | 0 | if(iter!=pmap->end()) { |
236 | 0 | freq = atoi(iter->second.c_str()); |
237 | 0 | if (freq < 1) |
238 | 0 | freq = 10; // don't divide by zero |
239 | 0 | } |
240 | |
|
241 | 0 | iter = pmap->find("log"); |
242 | 0 | if(iter!=pmap->end()) |
243 | 0 | log=true; |
244 | |
|
245 | 0 | if (newton) |
246 | 0 | pFF->SetLineSearchType(LineSearchType::Newton2Num); |
247 | | |
248 | | // set some force field variables |
249 | 0 | pFF->SetLogFile(&clog); |
250 | 0 | pFF->SetLogLevel(log ? OBFF_LOGLVL_LOW : OBFF_LOGLVL_NONE); |
251 | 0 | pFF->SetVDWCutOff(rvdw); |
252 | 0 | pFF->SetElectrostaticCutOff(rele); |
253 | 0 | pFF->SetUpdateFrequency(freq); |
254 | 0 | pFF->SetDielectricConstant(epsilon); |
255 | 0 | pFF->EnableCutOff(cut); |
256 | |
|
257 | 0 | if (addh) |
258 | 0 | pmol->AddHydrogens(false, false); |
259 | |
|
260 | 0 | if (!pFF->Setup(*pmol)) { |
261 | 0 | cerr << "Could not setup force field." << endl; |
262 | 0 | return false; |
263 | 0 | } |
264 | | |
265 | 0 | bool done = true; |
266 | 0 | if (sd) |
267 | 0 | pFF->SteepestDescent(steps, crit); |
268 | 0 | else |
269 | 0 | pFF->ConjugateGradients(steps, crit); |
270 | |
|
271 | 0 | pFF->GetCoordinates(*pmol); |
272 | | |
273 | | //Put the energy in a OBPairData object |
274 | 0 | OBPairData *dp = new OBPairData; |
275 | 0 | dp->SetAttribute("Energy"); |
276 | 0 | stringstream ss; |
277 | 0 | ss << pFF->Energy(false); |
278 | 0 | dp->SetValue(ss.str()); |
279 | 0 | dp->SetOrigin(fileformatInput); |
280 | 0 | pmol->SetData(dp); |
281 | |
|
282 | 0 | return true; |
283 | 0 | } |
284 | | |
285 | | }//namespace |