1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_INTERPOLATE_IMPLEMENTATION_H_
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_INTERPOLATE_IMPLEMENTATION_H_
4#include <molpro/linalg/itsolv/Interpolate.h>
6#include <molpro/linalg/itsolv/IterativeSolver.h>
7#include <molpro/linalg/itsolv/SolverFactory-implementation.h>
8#include <molpro/linalg/itsolv/SolverFactory.h>
9#include <molpro/linalg/itsolv/helper.h>
18namespace interpolate_detail {
21template <
typename value_type>
27 result.f = parameters[0] +
28 (parameters[1] / 2) * pow((1 - exp(-parameters[2] * (y - parameters[3]))) / parameters[2], 2);
29 result.f1 = (parameters[1] / parameters[2]) * exp(-parameters[2] * (y - parameters[3])) *
30 (1 - exp(-parameters[2] * (y - parameters[3])));
31 result.f2 = -parameters[1] * (1 - 2 * exp(-parameters[2] * (y - parameters[3])));
36template <
typename value_type>
38 using R = std::vector<value_type>;
49 auto pp0 = Morse<value_type>(p0.x, parameters);
50 auto pp1 = Morse<value_type>(p1.x, parameters);
61template <
typename value_type>
63 : m_p0(std::move(p0)), m_p1(std::move(p1)), m_interpolant(std::move(interpolant)), m_parameters(4) {
65 if (m_interpolant ==
"cubic") {
67 auto x1mx0 = m_p1.
x - m_p0.
x;
68 auto f1pf0 = m_p1.
f + m_p0.
f;
69 auto f1mf0 = m_p1.
f - m_p0.
f;
70 auto g1pg0 = m_p1.
f1 + m_p0.
f1;
71 auto g1mg0 = m_p1.
f1 - m_p0.
f1;
72 m_parameters[0] = value_type(0.5) * f1pf0 - value_type(0.125) * g1mg0 * x1mx0;
73 m_parameters[1] = value_type(-0.25) * g1pg0 + value_type(1.5) * f1mf0 / x1mx0;
74 m_parameters[2] = value_type(0.5) * g1mg0 / x1mx0;
75 m_parameters[3] = (-2 * f1mf0 + g1pg0 * x1mx0) / pow(x1mx0, 3);
76 }
else if (m_interpolant ==
"morse") {
79 using R = std::vector<value_type>;
81 auto solver = molpro::linalg::itsolv::create_NonLinearEquations<R>(
"DIIS");
83 auto cubic_minimum = cubic.minimize(p0.
x, p1.
x);
84 auto cubic_at_minimum = cubic(cubic_minimum.x);
85 m_parameters[1] = cubic_at_minimum.f2;
86 m_parameters[2] = -3 * cubic.parameters()[3] / (cubic_at_minimum.f2);
87 m_parameters[3] = cubic_minimum.x;
88 m_parameters[0] = cubic_at_minimum.f;
90 solver->set_verbosity(verbosity);
91 if (!solver->solve(m_parameters, residual, problem))
92 throw std::runtime_error(
"Cannot find Morse interpolant");
93 solver->solution(m_parameters, residual);
95 throw std::runtime_error(
"Unknown interpolant: " + m_interpolant);
98template <
typename value_type>
100 return std::vector<std::string>{
"cubic",
"morse"};
103template <
typename value_type>
105 if (m_interpolant ==
"cubic") {
106 auto xbar = value_type(0.5) * (m_p1.x + m_p0.x);
107 auto f = m_parameters[0] +
108 (x - xbar) * (m_parameters[1] + (x - xbar) * (m_parameters[2] + (x - xbar) * m_parameters[3]));
109 auto f1 = m_parameters[1] + (x - xbar) * (2 * m_parameters[2] + 3 * (x - xbar) * m_parameters[3]);
110 auto f2 = 2 * m_parameters[2] + 6 * (x - xbar) * m_parameters[3];
111 return point{x, f, f1, f2};
112 }
else if (m_interpolant ==
"morse") {
113 return interpolate_detail::Morse<value_type>(x, m_parameters);
115 throw std::logic_error(
"Unknown interpolant: " + m_interpolant);
118template <
typename value_type>
123 if (m_interpolant !=
"cubic")
124 throw std::logic_error(
"minimize_cubic called with non-cubic interpolant");
125 const auto c = m_parameters[1];
126 const auto b = 2 * m_parameters[2];
127 const auto a = 3 * m_parameters[3];
129 if (abs(a) < precision_scaled<value_type>(1e-10) * std::max(abs(c), abs(b))) {
130 return point{-c / b};
132 auto discriminant = b * b / (4 * a * a) - c / a;
133 if (isnan(discriminant) || discriminant < 0)
134 return {std::numeric_limits<value_type>::quiet_NaN()};
135 auto xbar = value_type(0.5) * (m_p1.x + m_p0.x);
136 point pm = (*this)(xbar - (b / (2 * a)) + sqrt(discriminant));
137 point pp = (*this)(xbar - (b / (2 * a)) - sqrt(discriminant));
138 return pm.
f < pp.f ? pm : pp;
141template <
typename value_type>
144 size_t max_bracket_grid,
145 bool analytic)
const {
149 if (analytic && m_interpolant ==
"cubic")
150 return minimize_cubic();
151 for (
size_t ngrid = bracket_grid; ngrid < std::max(bracket_grid, max_bracket_grid) + 1; ngrid *= 2) {
152 auto gridstep = (xb - xa) / ngrid;
153 auto plow = (*this)(xa);
154 auto p0 = (*this)(xa).f > (*
this)(xb).f ? plow : (*
this)(xb);
156 for (
size_t igrid = 0; igrid < ngrid; igrid++) {
157 auto phigh = (*this)(plow.x + gridstep);
158 if (std::min(phigh.f, plow.f) < p0.f and plow.f1 <= 0 and phigh.f1 >= 0) {
162 std::swap(plow, phigh);
164 if (p0.f1 < 0 and p1.
f1 > 0) {
169 2 * std::numeric_limits<value_type>::epsilon() * std::max(value_type(1), abs(pnew.x));
170 while (abs(p0.x - pnew.x) > tolerance) {
171 pnew = (*this)((p1.
x * p0.f1 - p0.x * p1.
f1) / (p0.f1 - p1.
f1));
172 if (pnew.f1 * p0.f1 < 0)
180 return (*
this)(xa).f > (*
this)(xb).f ? (*
this)(xb) : (*
this)(xa);
The interpolant, in the precision of the problem it is used for.
Definition: Interpolate.h:31
Interpolator(point p0, point p1, std::string interpolant="cubic", int verbosity=0)
Construct the interpolant.
Definition: Interpolate-implementation.h:62
static std::vector< std::string > interpolants()
Definition: Interpolate-implementation.h:99
Abstract class defining the problem-specific interface for the simplified solver interface to Iterati...
Definition: IterativeSolver.h:85
typename R::value_type value_t
Definition: IterativeSolver.h:91
Fits the four Morse parameters to the two defining points.
Definition: Interpolate-implementation.h:37
Morse_problem(point p0, point p1)
Definition: Interpolate-implementation.h:43
Problem< R >::value_t residual(const R ¶meters, R &residual) const override
Calculate the residual vector. Used by non-linear solvers (NonLinearEquations, Optimize) only.
Definition: Interpolate-implementation.h:48
Interpolator< value_type >::point Morse(value_type y, const std::vector< value_type > ¶meters)
The Morse interpolant and its first two derivatives at y.
Definition: Interpolate-implementation.h:22
4-parameter interpolation of a 1-dimensional function given two points for which function values and ...
Definition: helper.h:14
Definition: Interpolate.h:39
value_type f
Definition: Interpolate.h:41
value_type f1
Definition: Interpolate.h:42
value_type x
Definition: Interpolate.h:40