Program Listing for File newton_with_extension.cpp#

↰ Return to documentation for file (source/newton_with_extension.cpp)

#include "pele/newton_with_extension.hpp"
#include <memory>

#include "pele/array.hpp"
#include "pele/eigen_interface.hpp"
#include "pele/optimizer.hpp"
// Lapack for cholesky
extern "C" {
}

using pele::Array;
using namespace std;

// value at which we assume the value is zero
namespace pele {

NewtonWithExtendedPotential::NewtonWithExtendedPotential(
    std::shared_ptr<BasePotential> potential, const pele::Array<double> &x0,
    double tol, std::shared_ptr<BasePotential> potential_extension,
    double translation_offset, double max_step)
    : GradientOptimizer(potential, x0, tol),
      _hessian(x0.size(), x0.size()),
      _gradient(x0.size()),
      _x(x0.size()),
      _x_old(x0.size()),
      _gradient_old(x0.size()),
      _line_search(this, 1.0),
      _translation_offset(translation_offset),
      _max_step(max_step),
      _potential_extension(potential_extension) {
  // Setup the extended potential
  _potential_extension = potential_extension;
  _extended_potential_wrapper =
      std::make_shared<ExtendedPotential>(potential, potential_extension);
  set_potential(
      _potential_extension);  // write pele array data into the Eigen array

  // Save coordinates as an Eigen vector
  for (size_t i = 0; i < x0.size(); ++i) {
    _x(i) = x0[i];
  }
}

void NewtonWithExtendedPotential::reset(pele::Array<double> x) {
  // write pele array data into the Eigen array
  for (size_t i = 0; i < x.size(); ++i) {
    _x(i) = x[i];
    // TODO: Hacky, find a way to remove pele arrays in the base class
    x_[i] = x[i];
  }
  initialize_func_gradient();
}

void NewtonWithExtendedPotential::one_iteration() {
  // copy in from pele to make sure initialization is taken care of
  eig_eq_pele(_x_old, x_);
  eig_eq_pele(_gradient_old, g_);

  // Wrap pele array data into the Eigen array
  Array<double> hessian_pele(_hessian.data(),
                             _hessian.rows() * _hessian.cols());
  Array<double> gradient_pele(_gradient.data(), _gradient.size());
  Array<double> x_pele(_x.data(), _x.size());

  if (hessian_calculated) {
    // do nothing
  } else {
    _energy = potential_->get_energy_gradient_hessian(x_pele, gradient_pele,
                                                      hessian_pele);
    nhev_ += 1;
  }

  // assign negative hessian;
  _hessian = -_hessian;

  double starting_norm = _step.norm();

  _x = _x_old + _step;

  // use line search to find the step size
  Array<double> gradient_old_pele(_gradient_old.data(), _gradient_old.size());
  Array<double> x_old_pele(_x_old.data(), _x_old.size());

  // Execution of the line search TODO: Clean up
  _line_search.set_xold_gold_(x_old_pele, gradient_old_pele);
  _line_search.set_g_f_ptr(gradient_pele);
  Array<double> step_pele(_step.data(), _step.size());
  double stepnorm = _line_search.line_search(x_pele, step_pele);

  if (stepnorm / starting_norm < 1e-10) {
    throw std::runtime_error(
        "rescaled step decreased by too much. Newton "
        "might be in the wrong direction");
  }
  // Careful about assignment
  x_.assign(x_pele);
  g_.assign(gradient_pele);

  iter_number_ += 1;
}

}  // namespace pele