51 YScalar dy0, Scalar epsres) {
52 using complex_t = std::complex<Scalar>;
54 Scalar maxerr = 10 * epsres;
56 auto Nmax = info.nmax_;
58 auto yprev = std::get<0>(cheby);
59 auto dyprev = std::get<1>(cheby);
60 auto xprev = std::get<2>(cheby);
62 while (maxerr > epsres) {
66 return std::make_tuple(
false, complex_t(0.0, 0.0), complex_t(0.0, 0.0),
67 maxerr, yprev, dyprev, iter);
69 auto cheb_num =
static_cast<int>(std::log2(N / info.nini_));
71 auto y = std::get<0>(std::move(cheby2));
72 auto dy = std::get<1>(std::move(cheby2));
73 auto x = std::get<2>(std::move(cheby2));
74 maxerr = std::abs((yprev(0) - y(0)) / y(0));
75 if (std::isnan(maxerr)) {
76 maxerr = std::numeric_limits<Scalar>::infinity();
79 dyprev = std::move(dy);
82 return std::make_tuple(
true, yprev(0), dyprev(0), maxerr, yprev, dyprev,
139 Scalar x0, Scalar h, YScalar y0, YScalar dy0,
141 using complex_t = std::complex<Scalar>;
144 auto &&Dn = info.Dn();
145 auto y =
eval(info.alloc_, complex_t(0.0, 1.0) * omega_s);
146 auto delta = [&](
const auto &r,
const auto &y) {
147 return (-r.array() / (Scalar{2.0} * (y.array() + gamma_s.array())))
151 auto R = [&](
const auto &d) {
152 return Scalar{2.0} / h * (Dn * d) + d.array().square().matrix();
155 = (complex_t(0.0, 1.0) * Scalar{2.0}
156 * (Scalar{1.0} / h * (Dn * omega_s) + gamma_s.cwiseProduct(omega_s)))
158 Scalar maxerr = Ry.array().abs().maxCoeff();
161 Scalar prev_err = std::numeric_limits<Scalar>::infinity();
162 while (maxerr > epsres) {
163 deltay = delta(Ry, y);
166 maxerr = Ry.array().abs().maxCoeff();
167 if (maxerr >= (Scalar{2.0} * prev_err)) {
173 if constexpr (DenseOut) {
175 =
eval(info.alloc_, h / Scalar{2.0} * (info.integration_matrix_ * y));
176 auto f1 =
eval(info.alloc_, (u1).array().exp().matrix());
177 auto f2 =
eval(info.alloc_, f1.conjugate());
178 auto du2 =
eval(info.alloc_, y.conjugate());
179 auto ap_top = (dy0 - y0 * du2(du2.size() - 1));
180 auto ap_bottom = (y(y.size() - 1) - du2(du2.size() - 1));
181 auto ap = ap_top / ap_bottom;
182 auto am = (dy0 - y0 * y(y.size() - 1))
183 / (du2(du2.size() - 1) - y(y.size() - 1));
184 auto y1 =
eval(info.alloc_, ap * f1 + am * f2);
185 auto dy1 =
eval(info.alloc_,
186 ap * y.cwiseProduct(f1) + am * du2.cwiseProduct(f2));
187 Scalar phase = std::imag(f1(0));
188 return std::make_tuple(success, y1(0), dy1(0), maxerr, phase, u1, y,
189 std::make_pair(ap, am));
191 complex_t f1 = std::exp(h / Scalar{2.0} * (info.quadwts_.dot(y)));
192 auto f2 = std::conj(f1);
193 auto du2 = y.conjugate().eval();
194 auto ap_top = (dy0 - y0 * du2(du2.size() - 1));
195 auto ap_bottom = (y(y.size() - 1) - du2(du2.size() - 1));
196 auto ap = ap_top / ap_bottom;
197 auto am = (dy0 - y0 * y(y.size() - 1))
198 / (du2(du2.size() - 1) - y(y.size() - 1));
199 auto y1 = (ap * f1 + am * f2);
200 auto dy1 = (ap * y * f1 + am * du2 * f2).
eval();
201 Scalar phase = std::imag(f1);
202 return std::make_tuple(success, y1, dy1(0), maxerr, phase,
205 std::make_pair(ap, am));
274 std::complex<Scalar> yi, std::complex<Scalar> dyi, Scalar eps,
275 Scalar epsilon_h, Scalar init_stepsize, Vec &&x_eval,
276 bool hard_stop =
false) {
278 using complex_t = std::complex<Scalar>;
280 Scalar direction = init_stepsize > 0 ? 1 : -1;
281 if (init_stepsize * (xf - xi) < 0) {
282 throw std::domain_error(
283 "Direction of integration does not match stepsize sign,"
284 " adjusting it so that integration happens from xi to xf.");
288 if constexpr (dense_output) {
289 if (!x_eval.size()) {
290 throw std::domain_error(
"Dense output requested but x_eval is size 0!");
293 auto x_eval_max = (direction * x_eval.maxCoeff());
294 auto x_eval_min = (direction * x_eval.minCoeff());
295 auto xi_intdir = direction * xi;
296 auto xf_intdir = direction * xf;
297 const bool high_range_err = xf_intdir < x_eval_max;
298 const bool low_range_err = xi_intdir > x_eval_min;
299 if (high_range_err || low_range_err) {
300 if (high_range_err && low_range_err) {
301 throw std::out_of_range(
302 std::string{
"The max and min of the output points ("}
303 + std::to_string(x_eval_min) + std::string{
", "}
304 + std::to_string(x_eval_max)
305 +
") lie outside the high and low of the integration range ("
306 + std::to_string(xi_intdir) + std::string{
", "}
307 + std::to_string(xf_intdir) +
")!");
309 if (high_range_err) {
310 throw std::out_of_range(
311 std::string{
"The max of the output points ("}
312 + std::to_string(x_eval_max)
313 +
") lies outside the high of the integration range ("
314 + std::to_string(xf_intdir) +
")!");
317 throw std::out_of_range(
318 std::string{
"The min of the output points ("}
319 + std::to_string(x_eval_min)
320 +
") lies outside the low of the integration range ("
321 + std::to_string(xi_intdir) +
")!");
333 Eigen::Matrix<complex_t, -1, 1> yeval;
334 Eigen::Matrix<complex_t, -1, 1> dyeval;
339 complex_t dyprev = dy;
340 auto scale_xi =
scale(info.
xp().array(), xi, init_stepsize).eval();
341 auto omega_is =
omega(info, scale_xi).eval();
342 auto gamma_is =
gamma(info, scale_xi).eval();
343 Scalar wi = omega_is.mean();
344 Scalar gi = gamma_is.mean();
345 Scalar dwi = (2.0 / init_stepsize * (info.
Dn() * omega_is)).mean();
346 Scalar dgi = (2.0 / init_stepsize * (info.
Dn() * gamma_is)).mean();
347 Scalar hslo_ini = direction
348 * std::min(
static_cast<Scalar
>(1e8),
349 static_cast<Scalar
>(std::abs(1.0 / wi)));
352 * std::min(std::min(
static_cast<Scalar
>(1e8),
353 static_cast<Scalar
>(std::abs(wi / dwi))),
357 if (direction * (xi + hosc_ini) > direction * xf) {
360 if (direction * (xi + hslo_ini) > direction * xf) {
367 auto hosc = std::get<0>(osc_step_tup);
369 auto &&omega_n = std::get<1>(osc_step_tup);
370 auto &&gamma_n = std::get<2>(osc_step_tup);
371 Scalar xcurrent = xi;
378 std::pair<complex_t, complex_t> a_pair;
380 bool success =
false;
381 bool steptype =
true;
384 if ((direction * hosc > direction * hslo * 5.0)
385 && (direction * hosc * wnext / (2.0 *
pi<Scalar>()) > 1.0)) {
387 if (direction * (xcurrent + hosc) > direction * xf) {
388 hosc = xf - xcurrent;
389 auto xp_scaled =
scale(info.
xp().array(), xcurrent, hosc).eval();
390 omega_n =
omega(info, xp_scaled);
391 gamma_n =
gamma(info, xp_scaled);
393 if (direction * (xcurrent + hslo) > direction * xf) {
394 hslo = xf - xcurrent;
398 std::tie(success, y, dy, err, phase, un, d_un, a_pair)
404 std::tie(success, y, dy, err, y_eval, dy_eval, cheb_N)
405 =
nonosc_step(info, xcurrent, hslo, yprev, dyprev, eps);
410 if (direction * hslo < 1e-16) {
411 throw std::domain_error(
"Stepsize became to small error");
414 auto h = steptype ? hosc : hslo;
415 if constexpr (dense_output) {
416 Eigen::Index dense_size = 0;
417 Eigen::Index dense_start = 0;
419 std::tie(dense_start, dense_size)
420 =
get_slice(x_eval, direction * xcurrent, direction * (xcurrent + h));
421 yeval = Eigen::Matrix<complex_t, -1, 1>(dense_size);
422 dyeval = Eigen::Matrix<complex_t, -1, 1>(dense_size);
423 if (dense_size != 0) {
425 = Eigen::Map<vectord_t>(x_eval.data() + dense_start, dense_size);
427 = Eigen::Map<vectorc_t>(yeval.data() + dense_start, dense_size);
429 = Eigen::Map<vectorc_t>(dyeval.data() + dense_start, dense_size);
433 (2.0 / h * (x_eval_map.array() - xcurrent) - 1.0).matrix());
435 auto fdense =
eval(info.
alloc_, (Linterp * un).array().exp().matrix());
436 y_eval_map = a_pair.first * fdense + a_pair.second * fdense.conjugate();
437 auto du_dense =
eval(info.
alloc_, (Linterp * d_un));
439 = a_pair.first * (du_dense.array() * fdense.array())
440 + a_pair.second * (du_dense.array() * fdense.array()).conjugate();
442 auto xc_scaled =
eval(
446 y_eval_map = Linterp * y_eval;
455 steptypes = steptype;
463 dwnext = 2.0 / h * info.
Dn().row(0).dot(omega_n);
464 dgnext = 2.0 / h * info.
Dn().row(0).dot(gamma_n);
466 wnext =
omega(info, xcurrent + h);
467 gnext =
gamma(info, xcurrent + h);
468 auto xn_scaled =
scale(info.
xn().array(), xcurrent, h).eval();
469 dwnext = 2.0 / h * info.
Dn().row(0).dot(
omega(info, xn_scaled).
matrix());
470 dgnext = 2.0 / h * info.
Dn().row(0).dot(
gamma(info, (xn_scaled).
matrix()));
473 if (direction * xcurrent < direction * xf) {
474 hslo_ini = direction * std::min(Scalar{1e8}, std::abs(Scalar{1.0} / wnext));
476 * std::min(std::min(Scalar{1e8}, std::abs(wnext / dwnext)),
477 std::abs(gnext / dgnext));
479 if (direction * (xcurrent + hosc_ini) > direction * xf) {
480 hosc_ini = xf - xcurrent;
482 if (direction * (xcurrent + hslo_ini) > direction * xf) {
483 hslo_ini = xf - xcurrent;
488 hosc = std::get<0>(osc_step_tup);
493 info.
alloc_.recover_memory();
494 return std::make_tuple(xs, ys, dys, hosc, hslo, successes, phases, steptypes,