source: ThirdParty/mpqc_open/src/lib/math/optimize/gdiis.cc@ 23612c

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests AutomationFragmentation_failures Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_levmar Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 23612c was 860145, checked in by Frederik Heber <heber@…>, 8 years ago

Merge commit '0b990dfaa8c6007a996d030163a25f7f5fc8a7e7' as 'ThirdParty/mpqc_open'

  • Property mode set to 100644
File size: 10.1 KB
Line 
1//
2// gdiis.cc
3//
4// Copyright (C) 1996 Limit Point Systems, Inc.
5//
6// Author: Edward Seidl <seidl@janed.com>
7// Maintainer: LPS
8//
9// This file is part of the SC Toolkit.
10//
11// The SC Toolkit is free software; you can redistribute it and/or modify
12// it under the terms of the GNU Library General Public License as published by
13// the Free Software Foundation; either version 2, or (at your option)
14// any later version.
15//
16// The SC Toolkit is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Library General Public License for more details.
20//
21// You should have received a copy of the GNU Library General Public License
22// along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24//
25// The U.S. Government is granted a limited license as per AL 91-7.
26//
27
28#ifdef __GNUC__
29#pragma implementation
30#endif
31
32#include <math.h>
33
34#include <util/state/stateio.h>
35#include <math/optimize/gdiis.h>
36#include <util/keyval/keyval.h>
37#include <math/scmat/local.h>
38#include <util/misc/formio.h>
39
40using namespace std;
41using namespace sc;
42
43/////////////////////////////////////////////////////////////////////////
44// GDIISOpt
45
46static ClassDesc GDIISOpt_cd(
47 typeid(GDIISOpt),"GDIISOpt",1,"public Optimize",
48 0, create<GDIISOpt>, create<GDIISOpt>);
49
50GDIISOpt::GDIISOpt(const Ref<KeyVal>&keyval):
51 Optimize(keyval),
52 diis_iter(0),
53 maxabs_gradient(-1.0)
54{
55 nsave = keyval->intvalue("ngdiis");
56 if (keyval->error() != KeyVal::OK) nsave = 5;
57
58 update_ << keyval->describedclassvalue("update");
59 update_->set_inverse();
60
61 convergence_ = keyval->doublevalue("convergence");
62 if (keyval->error() != KeyVal::OK) convergence_ = 1.0e-6;
63
64 accuracy_ = keyval->doublevalue("accuracy");
65 if (keyval->error() != KeyVal::OK) accuracy_ = 0.0001;
66
67 RefSymmSCMatrix hessian(dimension(),matrixkit());
68 // get a guess hessian from the function
69 function()->guess_hessian(hessian);
70
71 // see if any hessian matrix elements have been given in the input
72 if (keyval->exists("hessian")) {
73 int n = hessian.n();
74 for (int i=0; i<n; i++) {
75 if (keyval->exists("hessian",i)) {
76 for (int j=0; j<=i; j++) {
77 double tmp = keyval->doublevalue("hessian",i,j);
78 if (keyval->error() == KeyVal::OK) hessian(i,j) = tmp;
79 }
80 }
81 }
82 }
83 ihessian_ = function()->inverse_hessian(hessian);
84
85 coords_ = new RefSCVector[nsave];
86 grad_ = new RefSCVector[nsave];
87 error_ = new RefSCVector[nsave];
88
89 for (int i=0; i < nsave; i++) {
90 coords_[i] = matrixkit()->vector(dimension()); coords_[i]->assign(0.0);
91 grad_[i] = matrixkit()->vector(dimension()); grad_[i]->assign(0.0);
92 error_[i] = matrixkit()->vector(dimension()); error_[i]->assign(0.0);
93 }
94}
95
96GDIISOpt::GDIISOpt(StateIn&s):
97 SavableState(s),
98 Optimize(s)
99{
100 s.get(nsave);
101 s.get(diis_iter);
102 ihessian_ = matrixkit()->symmmatrix(dimension());
103 ihessian_.restore(s);
104 update_ << SavableState::restore_state(s);
105 s.get(convergence_);
106 s.get(accuracy_);
107 s.get(maxabs_gradient);
108 coords_ = new RefSCVector[nsave];
109 grad_ = new RefSCVector[nsave];
110 error_ = new RefSCVector[nsave];
111 for (int i=0; i < nsave; i++) {
112 coords_[i] = matrixkit()->vector(dimension());
113 grad_[i] = matrixkit()->vector(dimension());
114 error_[i] = matrixkit()->vector(dimension());
115 coords_[i].restore(s);
116 grad_[i].restore(s);
117 error_[i].restore(s);
118 }
119}
120
121GDIISOpt::~GDIISOpt()
122{
123 delete[] coords_;
124 delete[] grad_;
125 delete[] error_;
126}
127
128void
129GDIISOpt::save_data_state(StateOut&s)
130{
131 Optimize::save_data_state(s);
132 s.put(nsave);
133 s.put(diis_iter);
134 ihessian_.save(s);
135 SavableState::save_state(update_.pointer(),s);
136 s.put(convergence_);
137 s.put(accuracy_);
138 s.put(maxabs_gradient);
139 for (int i=0; i < nsave; i++) {
140 coords_[i].save(s);
141 grad_[i].save(s);
142 error_[i].save(s);
143 }
144}
145
146void
147GDIISOpt::init()
148{
149 Optimize::init();
150 maxabs_gradient = -1.0;
151}
152
153int
154GDIISOpt::update()
155{
156 int i,j,ii,jj;
157
158 // these are good candidates to be input options
159 const double maxabs_gradient_to_desired_accuracy = 0.05;
160 const double maxabs_gradient_to_next_desired_accuracy = 0.005;
161 const double roundoff_error_factor = 1.1;
162
163 // the gradient convergence criterion.
164 double old_maxabs_gradient = maxabs_gradient;
165 RefSCVector xcurrent;
166 RefSCVector gcurrent;
167
168 // get the next gradient at the required level of accuracy.
169 // usually only one pass is needed, unless we happen to find
170 // that the accuracy was set too low.
171 int accurate_enough;
172 do {
173 // compute the current point
174 function()->set_desired_gradient_accuracy(accuracy_);
175
176 xcurrent = function()->get_x();
177 gcurrent = function()->gradient().copy();
178
179 // compute the gradient convergence criterion now so i can see if
180 // the accuracy needs to be tighter
181 maxabs_gradient = gcurrent.maxabs();
182 // compute the required accuracy
183 accuracy_ = maxabs_gradient * maxabs_gradient_to_desired_accuracy;
184
185 // The roundoff_error_factor is thrown in to allow for round off making
186 // the current gcurrent.maxabs() a bit smaller than the previous,
187 // which would make the current required accuracy less than the
188 // gradient's actual accuracy and cause everything to be recomputed.
189 accurate_enough = (function()->actual_gradient_accuracy() <=
190 accuracy_*roundoff_error_factor);
191
192 if (!accurate_enough) {
193 ExEnv::out0() << indent
194 << "NOTICE: function()->actual_gradient_accuracy() > accuracy_:\n"
195 << indent
196 << scprintf(
197 " function()->actual_gradient_accuracy() = %15.8e",
198 function()->actual_gradient_accuracy()) << endl << indent
199 << scprintf(
200 " accuracy_ = %15.8e",
201 accuracy_) << endl;
202 }
203 } while(!accurate_enough);
204
205 if (old_maxabs_gradient >= 0.0 && old_maxabs_gradient < maxabs_gradient) {
206 ExEnv::out0() << indent
207 << scprintf("NOTICE: maxabs_gradient increased from %8.4e to %8.4e",
208 old_maxabs_gradient, maxabs_gradient) << endl;
209 }
210
211 // update the hessian
212 if (update_.nonnull()) {
213 update_->update(ihessian_,function(),xcurrent,gcurrent);
214 }
215
216 diis_iter++;
217
218 int howmany = (diis_iter < nsave) ? diis_iter : nsave;
219
220 if (diis_iter <= nsave) {
221 coords_[diis_iter-1] = xcurrent;
222 grad_[diis_iter-1] = gcurrent;
223 } else {
224 for (i=0; i < nsave-1; i++) {
225 coords_[i] = coords_[i+1];
226 grad_[i] = grad_[i+1];
227 }
228 coords_[nsave-1] = xcurrent;
229 grad_[nsave-1] = gcurrent;
230 }
231
232 // take the step
233 if (diis_iter==1 || maxabs_gradient > 0.05) {
234 // just take the Newton-Raphson step first iteration
235 RefSCVector xdisp = -1.0*(ihessian_ * gcurrent);
236 // try steepest descent
237 // RefSCVector xdisp = -1.0*gcurrent;
238
239 // scale displacement vector if it's too large
240 double tot = sqrt(xdisp.scalar_product(xdisp));
241 if (tot > max_stepsize_) {
242 double scal = max_stepsize_/tot;
243 ExEnv::out0() << endl << indent
244 << scprintf("stepsize of %f is too big, scaling by %f",tot,scal)
245 << endl;
246 xdisp.scale(scal);
247 tot *= scal;
248 }
249
250 RefSCVector xnext = xcurrent + xdisp;
251
252 conv_->reset();
253 conv_->get_grad(function());
254 conv_->get_x(function());
255 conv_->set_nextx(xnext);
256
257 // check for conergence before resetting the geometry
258 int converged = conv_->converged();
259 if (converged)
260 return converged;
261
262 ExEnv::out0() << endl << indent
263 << scprintf("taking step of size %f", tot) << endl;
264
265 function()->set_x(xnext);
266
267 // make the next gradient computed more accurate, since it will
268 // be smaller
269 accuracy_ = maxabs_gradient * maxabs_gradient_to_next_desired_accuracy;
270
271 return converged;
272 }
273
274 // form the error vectors
275 for (i=0; i < howmany; i++)
276 error_[i] = -1.0*(ihessian_ * grad_[i]);
277
278 // and form the A matrix
279 RefSCMatrix A;
280 RefSCVector coeff;
281 int ntry=0;
282
283 do {
284 int num = howmany-ntry;
285
286 RefSCDimension size = new SCDimension(num+1);
287 Ref<SCMatrixKit> lkit = new LocalSCMatrixKit;
288 A = lkit->matrix(size,size);
289 coeff = lkit->vector(size);
290
291 for (ii=0, i=ntry; i < howmany; i++,ii++) {
292 coeff(ii) = 0;
293 for (j=ntry,jj=0; j <= i; j++,jj++) {
294 A(ii,jj) = error_[i].scalar_product(error_[j]);
295 A(jj,ii) = A(ii,jj);
296 }
297 }
298
299 A->scale(1.0/A(0,0));
300
301 coeff(num) = 1.0;
302 for (i=0; i < num; i++)
303 A(num,i) = A(i,num) = 1.0;
304
305 A(num,num) = 0;
306
307 ntry++;
308
309 } while (fabs(A.solve_lin(coeff)) < 1.0e-12);
310
311 RefSCVector xstar = matrixkit()->vector(dimension());
312 RefSCVector delstar = matrixkit()->vector(dimension());
313
314 xstar.assign(0.0);
315 delstar.assign(0.0);
316
317 for (i=0,ii=ntry-1; ii < howmany; i++,ii++) {
318 RefSCVector tmp = grad_[ii].copy(); tmp.scale(coeff[i]);
319 delstar.accumulate(tmp);
320 tmp = coords_[ii].copy(); tmp.scale(coeff[i]);
321 xstar.accumulate(tmp);
322 }
323
324 RefSCVector xdisp = xstar - xcurrent - ihessian_*delstar;
325 // scale displacement vector if it's too large
326 double tot = sqrt(xdisp.scalar_product(xdisp));
327 if (tot > max_stepsize_) {
328 double scal = max_stepsize_/tot;
329 ExEnv::out0() << endl << indent
330 << scprintf("stepsize of %f is too big, scaling by %f",tot,scal)
331 << endl;
332 xdisp.scale(scal);
333 tot *= scal;
334 }
335
336 RefSCVector xnext = xcurrent + xdisp;
337
338 conv_->reset();
339 conv_->get_grad(function());
340 conv_->get_x(function());
341 conv_->set_nextx(xnext);
342
343 // check for conergence before resetting the geometry
344 int converged = conv_->converged();
345 if (converged)
346 return converged;
347
348 ExEnv::out0() << endl << indent
349 << scprintf("taking step of size %f", tot) << endl;
350
351 function()->set_x(xnext);
352
353 // make the next gradient computed more accurate, since it will
354 // be smaller
355 accuracy_ = maxabs_gradient * maxabs_gradient_to_next_desired_accuracy;
356
357 return converged;
358}
359
360/////////////////////////////////////////////////////////////////////////////
361
362// Local Variables:
363// mode: c++
364// c-file-style: "ETS"
365// End:
Note: See TracBrowser for help on using the repository browser.