1#ifndef MADNESS_MOLOPT_H
2#define MADNESS_MOLOPT_H
33 const double energy_precision;
34 const double gradient_precision;
35 const int print_level;
38 Tensor<double> hessian;
41 Tensor<double> new_search_direction(
const Tensor<double> &
g,
42 const Tensor<double> &
h)
const {
44 double tol = gradient_precision;
45 double trust = std::min(maxstep *
g.dim(0), 1.0);
50 print(
"hessian eigenvalues",
e);
53 Tensor<double> gv =
inner(
g,
v);
55 print(
"spectral gradient", gv);
58 int nneg = 0, nsmall = 0, nrestrict = 0;
59 for (
int i = 0; i <
e.dim(0); i++) {
63 print(
"skipping redundant mode", i);
67 printf(
" forcing negative eigenvalue to be positive %d %.1e\n", i,
71 }
else if (
e[i] < tol) {
73 printf(
" forcing small eigenvalue to be positive %d %.1e\n", i,
79 gv[i] = -gv[i] /
e[i];
82 double gvnew = trust *
std::abs(gv(i)) / gv[i];
84 printf(
" restricting step in spectral direction %d %.1e --> %.1e\n",
90 if (print_level > 0 && (nneg || nsmall || nrestrict))
91 printf(
" nneg=%d nsmall=%d nrestrict=%d\n", nneg, nsmall, nrestrict);
97 print(
"cartesian dx before restriction", gv);
100 bool printing =
false;
101 for (
int i = 0; i < gv.dim(0); i++) {
102 if (fabs(gv[i]) > maxstep) {
103 gv[i] = maxstep * gv[i] / fabs(gv[i]);
104 if (print_level > 0) {
106 printf(
" restricting step in Cartesian direction");
122 Tensor<double> make_projector(
const Molecule &
molecule) {
124 const Tensor<double> coords =
molecule.get_all_coords();
128 Tensor<double>
V(6, natom, 3);
130 for (
int k = 0;
k < 3;
k++)
131 V(
k, _,
k) = 1.0 / std::sqrt(
static_cast<double>(natom));
133 Tensor<double> centroid(3);
134 for (
int k = 0;
k < 3;
k++)
135 centroid(
k) = coords(_,
k).sum() / natom;
137 print(
"centroid", centroid);
139 for (
int i = 0; i < natom; i++) {
140 double x = coords(i, 0) - centroid[0];
141 double y = coords(i, 1) - centroid[1];
142 double z = coords(i, 2) - centroid[2];
157 V =
V.reshape(6, 3 * natom);
160 print(
"V before orthonormal");
166 for (
int i = 3; i < 6; i++) {
167 V(i, _).scale(1.0 /
V(i, _).normf());
168 for (
int j = 0; j < i; j++) {
169 double s =
V(i, _).trace(
V(j, _));
170 V(i, _) -=
V(j, _) *
s;
172 double vnorm =
V(i, _).normf();
174 V(i, _) *= 1.0 / vnorm;
182 for (
int i = 0; i < 3 * natom; i++)
201 void print_gradient(
const Molecule &
molecule,
const Tensor<double> &graw,
202 const Tensor<double> &
g)
const {
203 const size_t natom =
molecule.natom();
207 double net[3] = {0.0, 0.0, 0.0};
208 for (
size_t i = 0; i < natom; ++i)
209 for (
int c = 0;
c < 3; ++
c)
210 net[
c] += graw[i * 3 +
c];
212 print(
"\n Gradient (a.u.), translations and rotations projected out\n"
213 " ---------------------------------------------------------\n");
214 print(
" atom x y z dE/dx "
216 print(
" ------ ------------ ------------ ------------ ------------ "
217 "------------ ------------");
218 for (
size_t i = 0; i < natom; ++i) {
220 printf(
" %5d %12.6f %12.6f %12.6f %12.6f %12.6f %12.6f\n",
int(i), atom.
x,
221 atom.
y, atom.
z,
g[i * 3 + 0],
g[i * 3 + 1],
g[i * 3 + 2]);
223 printf(
" max element of the projected gradient %12.3e\n",
g.absmax());
224 printf(
" net force removed by the projection %12.3e %12.3e %12.3e\n",
225 net[0], net[1], net[2]);
232 template <
typename targetT>
234 const Tensor<double> &dx,
double energy0,
double dxgrad,
238 const char *lsmode =
"";
240 Tensor<double> x =
molecule.get_all_coords().flat();
243 if (dxgrad *
a1 > 0.0) {
245 print(
" line search gradient +ve ",
a1, dxgrad);
250 energy1 =
target.value(x +
a1 * dx);
253 hess = 2.0 * (energy1 - energy0 -
a1 * dxgrad) / (
a1 *
a1);
260 }
else if (hess > 0.0) {
261 if ((energy1 - energy0) <= -energy_precision) {
272 if ((energy1 - energy0) < energy_precision) {
288 double energy2 = energy0 + dxgrad *
a2 + 0.5 * hess *
a2 *
a2;
290 if (print_level > 0) {
291 printf(
"\n line search grad=%.2e hess=%.2e mode=%s newstep=%.3f\n",
292 dxgrad, hess, lsmode,
a2);
293 printf(
" predicted %.12e\n\n", energy2);
300 MolOpt(
int maxiter = 20,
double maxstep = 0.1,
double etol = 1
e-4,
301 double gtol = 1
e-3,
double xtol = 1
e-3,
double energy_precision = 1
e-5,
302 double gradient_precision = 1
e-4,
int print_level = 1,
303 std::string
update =
"BFGS")
305 etol(
std::
max(etol, energy_precision)),
306 gtol(
std::
max(gtol, gradient_precision)), xtol(xtol),
307 energy_precision(energy_precision),
308 gradient_precision(gradient_precision), print_level(print_level),
312 if (print_level > 0) {
317 print(
" maximum step", maxstep);
318 print(
" energy convergence", etol);
319 print(
" gradient convergence", gtol);
320 print(
" cartesian convergence", xtol);
321 print(
" energy precision", energy_precision);
322 print(
" gradient precision", gradient_precision);
327 void set_hessian(
const Tensor<double> &
h) { hessian =
h; }
329 const Tensor<double> &get_hessian()
const {
return hessian; }
331 void initialize_hessian(
const Molecule &
molecule) {
333 hessian = Tensor<double>(
N,
N);
334 for (
int i = 0; i <
N; i++)
338 template <
typename targetT>
339 Molecule optimize(Molecule
molecule,
346 if (hessian.size() == 0)
350 Tensor<double> gp(3 * natom);
351 Tensor<double> dx(3 * natom);
355 for (
int iter = 0; iter <
maxiter; iter++) {
357 print(
"\n\n Geometry optimization iteration", iter,
"\n");
369 Tensor<double>
P = make_projector(
molecule);
370 const Tensor<double> graw =
copy(
g);
378 double dxmax = dx.absmax();
379 double gmax =
g.absmax();
381 bool dxconv = (iter > 0) && (dxmax < xtol);
382 bool gconv = gmax < gtol;
383 bool econv = (iter > 0) && (
std::abs(de) < etol);
384 bool converged = econv && dxconv && gconv;
386 if (!converged && gmax < gradient_precision) {
388 print(
"\nInsufficient precision in gradient to proceed further -- "
389 "forcing convergence\n");
393 if (print_level > 0) {
394 const char *tf[] = {
"F",
"T"};
397 " energy delta-e max-dx max-g e dx g\n");
398 printf(
" ---------------- --------- --------- --------- --- --- "
400 printf(
" %15.6f %9.2e %9.2e %9.2e %s %s %s\n",
e, de, dxmax,
401 gmax, tf[econv], tf[dxconv], tf[gconv]);
409 print(
"\n Geometry optimization converged!\n");
416 if ((
g - gp).absmax() < 2.0 * gradient_precision) {
418 print(
" skipping hessian update due to insufficient precision in "
420 }
else if (
update ==
"bfgs") {
422 }
else if (
update ==
"sr1") {
425 throw "unknown update";
433 const double shift = 1000.0;
435 if (print_level > 1) {
439 for (
int i = 0; i < 3 * natom; i++)
441 if (print_level > 1) {
448 dx = new_search_direction(
g, PHPS);
458 print(
"scaled dx", dx);
461 Tensor<double> x =
molecule.get_all_coords().flat();
463 molecule.set_all_coords(x.reshape(natom, 3));
466 print(
"new molecular coords");
472 template <
typename targetT>
473 auto optimize_app(Molecule
molecule,
475 -> OptimizationResults {
480 OptimizationResults results;
482 if (hessian.size() == 0)
486 Tensor<double> gp(3 * natom);
487 Tensor<double> dx(3 * natom);
492 for (iter = 0; iter <
maxiter; iter++) {
494 print(
"\n\n Geometry optimization iteration", iter,
"\n");
506 Tensor<double>
P = make_projector(
molecule);
507 const Tensor<double> graw =
copy(
g);
515 double dxmax = dx.absmax();
516 results.max_gradient =
g.absmax();
518 bool dxconv = (iter > 0) && (dxmax < xtol);
519 bool gconv = results.max_gradient < gtol;
520 bool econv = (iter > 0) && (
std::abs(de) < etol);
521 bool converged = econv && dxconv && gconv;
523 if (!converged && results.max_gradient < gradient_precision) {
525 print(
"\nInsufficient precision in gradient to proceed further -- "
526 "forcing convergence\n");
530 if (print_level > 0) {
531 const char *tf[] = {
"F",
"T"};
534 " energy delta-e max-dx max-g e dx g\n");
535 printf(
" ---------------- --------- --------- --------- --- --- "
537 printf(
" %15.6f %9.2e %9.2e %9.2e %s %s %s\n",
e, de, dxmax,
538 results.max_gradient, tf[econv], tf[dxconv], tf[gconv]);
546 print(
"\n Geometry optimization converged!\n");
553 if ((
g - gp).absmax() < 2.0 * gradient_precision) {
555 print(
" skipping hessian update due to insufficient precision in "
557 }
else if (
update ==
"bfgs") {
559 }
else if (
update ==
"sr1") {
562 throw "unknown update";
570 const double shift = 1000.0;
572 if (print_level > 1) {
576 for (
int i = 0; i < 3 * natom; i++)
578 if (print_level > 1) {
585 dx = new_search_direction(
g, PHPS);
595 print(
"scaled dx", dx);
598 Tensor<double> x =
molecule.get_all_coords().flat();
600 molecule.set_all_coords(x.reshape(natom, 3));
603 print(
"new molecular coords");
606 results.final_energy = ep;
607 results.nsteps = iter;
double x
Definition mentity.h:73
double y
Definition mentity.h:73
double z
Definition mentity.h:73
void hessian_update_bfgs(const Tensor< double > &dx, const Tensor< double > &dg)
Definition kain.cc:329
void hessian_update_sr1(const Tensor< double > &s, const Tensor< double > &y)
Definition kain.cc:317
static double shift
Definition dirac-hatom.cc:19
std::complex< double > inner(const Fcwf &psi, const Fcwf &phi)
Definition fcwf.cc:311
Fcwf copy(Fcwf psi)
Definition fcwf.cc:374
Tensor< T > transpose(const Tensor< T > &t)
Returns a new deep copy of the transpose of the input tensor.
Definition tensor.h:2035
const int maxiter
Definition gygi_soltion.cc:68
static const double v
Definition hatom_sf_dirac.cc:20
#define max(a, b)
Definition lda.h:51
void print(const tensorT &t)
Definition mcpfit.cc:140
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:13
void print_justified(const char *s, int column, bool underline)
Print a string justified on the left to start at the given column with optional underlining.
Definition print.cc:75
void syev(const Tensor< T > &A, Tensor< T > &V, Tensor< typename Tensor< T >::scalar_type > &e)
Real-symmetric or complex-Hermitian eigenproblem.
Definition lapack.cc:969
static long abs(long a)
Definition tensor.h:219
static const double c
Definition relops.cc:10
static const long k
Definition rk.cc:44
Defines interfaces for optimization and non-linear equation solvers.
static double V(const coordT &r)
Definition tdse.cc:288
Defines and implements most of Tensor.
Prototypes for a partial interface from Tensor to LAPACK.
int P
Definition test_binsorter.cc:9
void e()
Definition test_sig.cc:75
#define N
Definition testconv.cc:37
vector_complex_function_3d update(World &world, const vector_complex_function_3d &psi, vector_complex_function_3d &vpsi, const tensor_real &e, int iter)
Definition testcosine.cc:210
static const double alpha
Definition testcosine.cc:10
double g(const coord_t &r)
Definition testgconv.cc:116
double h(const coord_1d &r)
Definition testgconv.cc:175
static Molecule molecule
Definition testperiodicdft.cc:39
const double a2
Definition vnucso.cc:86
const double a1
Definition vnucso.cc:85
FLOAT target(const FLOAT &x)
Definition y.cc:295