1#ifndef MADNESS_MOLOPT_H
2#define MADNESS_MOLOPT_H
21 const double energy_precision;
22 const double gradient_precision;
23 const int print_level;
26 Tensor<double> hessian;
29 Tensor<double> new_search_direction(
const Tensor<double>&
g,
const Tensor<double>&
h)
const {
31 double tol = gradient_precision;
32 double trust = std::min(maxstep*
g.dim(0),1.0);
36 if (print_level>1)
print(
"hessian eigenvalues",
e);
40 if (print_level>1)
print(
"spectral gradient", gv);
43 int nneg=0, nsmall=0, nrestrict=0;
44 for (
int i=0; i<
e.dim(0); i++) {
47 if (print_level>1)
print(
"skipping redundant mode",i);
49 else if (
e[i] < -tol) {
50 if (print_level > 0) printf(
" forcing negative eigenvalue to be positive %d %.1e\n", i,
e[i]);
54 else if (
e[i] < tol) {
55 if (print_level > 0) printf(
" forcing small eigenvalue to be positive %d %.1e\n", i,
e[i]);
60 gv[i] = -gv[i] /
e[i];
63 double gvnew = trust*
std::abs(gv(i))/gv[i];
64 if (print_level > 0) printf(
" restricting step in spectral direction %d %.1e --> %.1e\n", i, gv[i], gvnew);
69 if (print_level>0 && (nneg || nsmall || nrestrict))
70 printf(
" nneg=%d nsmall=%d nrestrict=%d\n", nneg, nsmall, nrestrict);
75 if (print_level>1)
print(
"cartesian dx before restriction", gv);
78 bool printing =
false;
79 for (
int i=0; i<gv.dim(0); i++) {
80 if (fabs(gv[i]) > maxstep) {
81 gv[i] = maxstep * gv[i]/fabs(gv[i]);
82 if (print_level > 0) {
83 if (!printing) printf(
" restricting step in Cartesian direction");
89 if (printing) printf(
"\n");
99 Tensor<double> make_projector(
const Molecule&
molecule) {
101 const Tensor<double> coords =
molecule.get_all_coords();
104 Tensor<double>
V(6,natom,3);
106 for (
int k=0;
k<3;
k++)
107 V(
k,_,
k) = 1.0/std::sqrt(
double(natom));
109 Tensor<double> centroid(3);
110 for (
int k=0;
k<3;
k++) centroid(
k) = coords(_,
k).sum()/natom;
111 if (print_level>1)
print(
"centroid", centroid);
113 for (
int i=0; i<natom; i++) {
114 double x = coords(i,0) - centroid[0];
115 double y = coords(i,1) - centroid[1];
116 double z = coords(i,2) - centroid[2];
131 V =
V.reshape(6,3*natom);
133 if (print_level>1)
print(
"V before orthonormal");
134 if (print_level>1)
print(
V);
138 for (
int i=3; i<6; i++) {
139 V(i,_).scale(1.0/
V(i,_).normf());
140 for (
int j=0; j<i; j++) {
141 double s =
V(i,_).trace(
V(j,_));
144 double vnorm =
V(i,_).normf();
155 for (
int i=0; i<3*natom; i++)
V(i,i) += 1.0;
164 template <
typename targetT>
165 double line_search(Molecule&
molecule, targetT&
target,
const Tensor<double>& dx,
166 double energy0,
double dxgrad,
double a1=1.0) {
170 const char* lsmode =
"";
172 Tensor<double> x =
molecule.get_all_coords().flat();
175 if (dxgrad*
a1 > 0.0) {
176 if(print_level > 0)
print(
" line search gradient +ve ",
a1, dxgrad);
181 energy1 =
target.value(x +
a1 * dx);
184 hess = 2.0*(energy1-energy0-
a1*dxgrad)/(
a1*
a1);
187 if (
std::abs(energy1-energy0) < energy_precision) {
191 else if (hess > 0.0) {
192 if ((energy1 - energy0) <= -energy_precision) {
204 if ((energy1 - energy0) < energy_precision) {
221 double energy2 = energy0 + dxgrad*
a2 + 0.5*hess*
a2*
a2;
223 if (print_level > 0) {
224 printf(
"\n line search grad=%.2e hess=%.2e mode=%s newstep=%.3f\n", dxgrad, hess, lsmode,
a2);
225 printf(
" predicted %.12e\n\n", energy2);
239 double energy_precision = 1
e-5,
240 double gradient_precision = 1
e-4,
242 std::string
update =
"BFGS")
245 , etol(
std::
max(etol,energy_precision))
246 , gtol(
std::
max(gtol,gradient_precision))
248 , energy_precision(energy_precision)
249 , gradient_precision(gradient_precision)
250 , print_level(print_level)
254 if (print_level > 0) {
259 print(
" maximum step", maxstep);
260 print(
" energy convergence", etol);
261 print(
" gradient convergence", gtol);
262 print(
" cartesian convergence", xtol);
263 print(
" energy precision", energy_precision);
264 print(
" gradient precision", gradient_precision);
269 void set_hessian(
const Tensor<double>&
h) {
273 const Tensor<double>& get_hessian()
const {
277 void initialize_hessian(
const Molecule&
molecule) {
279 hessian = Tensor<double>(
N,
N);
280 for (
int i=0; i<
N; i++) hessian(i,i) = 0.5;
283 template <
typename targetT>
289 if (hessian.size() == 0) initialize_hessian(
molecule);
292 Tensor<double> gp(3*natom);
293 Tensor<double> dx(3*natom);
297 for (
int iter=0; iter<
maxiter; iter++) {
299 if (print_level > 0)
print(
"\n\n Geometry optimization iteration", iter,
"\n");
300 if (print_level > 0)
molecule.print();
308 double dxmax = dx.absmax();
309 double gmax =
g.absmax();
311 bool dxconv = (iter>0) && (dxmax < xtol);
312 bool gconv = gmax < gtol;
313 bool econv = (iter>0) && (
std::abs(de) < etol);
314 bool converged = econv && dxconv && gconv;
316 if (!converged && gmax < gradient_precision) {
317 if (print_level > 0)
print(
"\nInsufficient precision in gradient to proceed further -- forcing convergence\n");
321 if (print_level > 0) {
322 const char* tf[] = {
"F",
"T"};
324 printf(
" energy delta-e max-dx max-g e dx g\n");
325 printf(
" ---------------- --------- --------- --------- --- --- ---\n");
326 printf(
" %15.6f %9.2e %9.2e %9.2e %s %s %s\n",
327 e, de, dxmax, gmax, tf[econv], tf[dxconv], tf[gconv]);
333 if (print_level > 0)
print(
"\n Geometry optimization converged!\n");
334 if (print_level > 0)
molecule.print();
339 Tensor<double>
P = make_projector(
molecule);
343 if (print_level>1)
print(
"gradient after projection",
g);
346 if ((
g-gp).absmax() < 2.0*gradient_precision) {
347 if (print_level > 0)
print(
" skipping hessian update due to insufficient precision in gradient");
349 else if (
update ==
"bfgs") {
352 else if (
update ==
"sr1") {
356 throw "unknown update";
364 const double shift = 1000.0;
366 if (print_level > 1) {
print(
"projector");
print(
P);}
367 for (
int i=0; i<3*natom; i++) PHPS(i,i) +=
shift;
368 if (print_level > 1) {
print(
"PHPS");
print(PHPS);}
371 dx = new_search_direction(
g, PHPS);
372 if (print_level > 1)
print(
"dx", dx);
378 if (print_level > 1)
print(
"scaled dx", dx);
381 Tensor<double> x =
molecule.get_all_coords().flat();
383 molecule.set_all_coords(x.reshape(natom,3));
385 if (print_level > 1)
print(
"new molecular coords");
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:275
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:10
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:218
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.
template Tensor< int > transpose(const Tensor< int > &t)
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 h(const coord_1d &r)
Definition testgconv.cc:68
double g(const coord_1d &r)
Definition testgconv.cc:49
static Molecule molecule
Definition testperiodicdft.cc:38
const double a2
Definition vnucso.cc:86
const double a1
Definition vnucso.cc:85
FLOAT target(const FLOAT &x)
Definition y.cc:295