70 std::complex<Scalar> yi, std::complex<Scalar> dyi,
71 Scalar eps, Scalar epsilon_h, Scalar init_stepsize,
72 Vec &&x_eval,
bool hard_stop =
false) {
73 int sign = init_stepsize > 0 ? 1 : -1;
74 using complex_t = std::complex<Scalar>;
77 =
eval(info.alloc_,
scale(info.xn().array(), xi, init_stepsize).matrix());
79 auto omega_n =
eval(info.alloc_,
omega(info, xi_scaled));
80 auto gamma_n =
eval(info.alloc_,
gamma(info, xi_scaled));
84 if (sign * (xi + init_stepsize) > sign * xf) {
85 throw std::out_of_range(
86 std::string(
"Stepsize (") + std::to_string(init_stepsize)
87 + std::string(
") is too large for integration range (")
88 + std::to_string(xi) + std::string(
", ") + std::to_string(xf)
94 init_stepsize, yi, dyi, eps);
95 if (std::get<0>(osc_ret) == 0) {
96 return std::make_tuple(
false, xi, init_stepsize, osc_ret, vectorc_t(0),
97 vectorc_t(0),
static_cast<Eigen::Index
>(0),
98 static_cast<Eigen::Index
>(0));
100 Eigen::Index dense_size = 0;
101 Eigen::Index dense_start = 0;
102 if constexpr (dense_output) {
104 std::tie(dense_start, dense_size)
105 =
get_slice(x_eval, sign * xi, sign * (xi + init_stepsize));
106 if (dense_size != 0) {
107 auto x_eval_map = x_eval.segment(dense_start, dense_size);
108 auto x_eval_scaled =
eval(
110 (2.0 / init_stepsize * (x_eval_map.array() - xi) - 1.0).matrix());
111 auto Linterp =
interpolate(info.xn(), x_eval_scaled, info.alloc_);
114 (Linterp * std::get<5>(osc_ret)).array().exp().matrix());
115 yeval = std::get<7>(osc_ret).first * fdense
116 + std::get<7>(osc_ret).second * fdense.conjugate();
118 =
eval(info.alloc_, (Linterp * std::get<6>(osc_ret))).array();
120 = std::get<7>(osc_ret).first * (du_dense.array() * fdense.array())
121 + std::get<7>(osc_ret).second
122 * (du_dense.array() * fdense.array()).conjugate();
125 auto x_next = xi + init_stepsize;
127 auto wnext = omega_n[0];
128 auto gnext = gamma_n[0];
129 auto dwnext = 2.0 / init_stepsize * info.Dn().row(0).dot(omega_n);
130 auto dgnext = 2.0 / init_stepsize * info.Dn().row(0).dot(gamma_n);
132 * std::min(std::min(1e8, std::abs(wnext / dwnext)),
133 std::abs(gnext / dgnext));
134 if (sign * (x_next + hosc_ini) > sign * xf) {
135 hosc_ini = xf - x_next;
140 return std::make_tuple(
true, x_next, std::get<0>(h_next), osc_ret, yeval,
141 dyeval, dense_start, dense_size);
200 std::complex<Scalar> yi, std::complex<Scalar> dyi,
201 Scalar eps, Scalar epsilon_h, Scalar init_stepsize,
202 Vec &&x_eval,
bool hard_stop =
false) {
203 using complex_t = std::complex<Scalar>;
208 const int sign = init_stepsize > 0 ? 1 : -1;
209 if (sign * (xi + init_stepsize) > sign * xf) {
210 throw std::out_of_range(
211 std::string(
"Stepsize (") + std::to_string(init_stepsize)
212 + std::string(
") is too large for integration range (")
213 + std::to_string(xi) + std::string(
", ") + std::to_string(xf)
214 + std::string(
")!"));
216 auto nonosc_ret =
nonosc_step(info, xi, init_stepsize, yi, dyi, eps);
217 if (!std::get<0>(nonosc_ret)) {
218 return std::make_tuple(
false, xi, init_stepsize, nonosc_ret, vectorc_t(0),
219 vectorc_t(0),
static_cast<Eigen::Index
>(0),
220 static_cast<Eigen::Index
>(0));
222 Eigen::Index dense_size = 0;
223 Eigen::Index dense_start = 0;
226 std::tie(dense_start, dense_size)
227 =
get_slice(x_eval, sign * xi, sign * (xi + init_stepsize));
228 if (dense_size != 0) {
229 auto x_eval_map = x_eval.segment(dense_start, dense_size);
232 = (xi + init_stepsize / 2
233 + (init_stepsize / 2)
234 * std::get<2>(info.chebyshev_[std::get<6>(nonosc_ret)])
238 auto Linterp =
interpolate(xi_scaled, x_eval_map, info.alloc_);
239 yeval = Linterp * std::get<4>(nonosc_ret);
240 dyeval = Linterp * std::get<5>(nonosc_ret);
243 auto x_next = xi + init_stepsize;
244 auto wnext =
omega(info, xi + init_stepsize);
245 auto hslo_ini = sign * std::min(1e8, std::abs(1.0 / wnext));
246 if (sign * (x_next + hslo_ini) > sign * xf) {
247 hslo_ini = xf - x_next;
250 return std::make_tuple(
true, x_next, h_next, nonosc_ret, yeval, dyeval,
251 dense_start, dense_size);
320 std::complex<Scalar> yi, std::complex<Scalar> dyi,
321 Scalar eps, Scalar epsilon_h, Scalar init_stepsize,
322 Vec &&x_eval,
bool hard_stop =
false) {
324 Scalar direction = init_stepsize > 0 ? 1 : -1;
325 if (init_stepsize * (xf - xi) < 0) {
326 throw std::domain_error(
327 "Direction of integration does not match stepsize sign,"
328 " adjusting it so that integration happens from xi to xf.");
332 if constexpr (dense_output) {
333 if (!x_eval.size()) {
334 throw std::domain_error(
"Dense output requested but x_eval is size 0!");
337 auto x_eval_max = (direction * x_eval.maxCoeff());
338 auto x_eval_min = (direction * x_eval.minCoeff());
339 auto xi_intdir = direction * xi;
340 auto xf_intdir = direction * xf;
341 const bool high_range_err = xf_intdir < x_eval_max;
342 const bool low_range_err = xi_intdir > x_eval_min;
343 if (high_range_err || low_range_err) {
344 if (high_range_err && low_range_err) {
345 throw std::out_of_range(
346 std::string{
"The max and min of the output points ("}
347 + std::to_string(x_eval_min) + std::string{
", "}
348 + std::to_string(x_eval_max)
349 +
") lie outside the high and low of the integration range ("
350 + std::to_string(xi_intdir) + std::string{
", "}
351 + std::to_string(xf_intdir) +
")!");
353 if (high_range_err) {
354 throw std::out_of_range(
355 std::string{
"The max of the output points ("}
356 + std::to_string(x_eval_max)
357 +
") lies outside the high of the integration range ("
358 + std::to_string(xf_intdir) +
")!");
361 throw std::out_of_range(
362 std::string{
"The min of the output points ("}
363 + std::to_string(x_eval_min)
364 +
") lies outside the low of the integration range ("
365 + std::to_string(xi_intdir) +
")!");
371 std::size_t output_size = 100;
372 using stdvecd_t = std::vector<Scalar>;
374 xs.reserve(output_size);
375 using complex_t = std::complex<Scalar>;
376 using stdvecc_t = std::vector<complex_t>;
378 ys.reserve(output_size);
380 dys.reserve(output_size);
381 std::vector<int> successes;
382 successes.reserve(output_size);
383 std::vector<int> steptypes;
384 steptypes.reserve(output_size);
386 phases.reserve(output_size);
388 vectorc_t yeval(x_eval.size());
389 vectorc_t dyeval(x_eval.size());
394 complex_t dyprev = dy;
395 auto scale_xi =
scale(info.
xp().array(), xi, init_stepsize).eval();
396 auto omega_is =
omega(info, scale_xi).eval();
397 auto gamma_is =
gamma(info, scale_xi).eval();
398 Scalar wi = omega_is.mean();
399 Scalar gi = gamma_is.mean();
400 Scalar dwi = (2.0 / init_stepsize * (info.
Dn() * omega_is)).mean();
401 Scalar dgi = (2.0 / init_stepsize * (info.
Dn() * gamma_is)).mean();
402 Scalar hslo_ini = direction
403 * std::min(
static_cast<Scalar
>(1e8),
404 static_cast<Scalar
>(std::abs(1.0 / wi)));
407 * std::min(std::min(
static_cast<Scalar
>(1e8),
408 static_cast<Scalar
>(std::abs(wi / dwi))),
412 if (direction * (xi + hosc_ini) > direction * xf) {
415 if (direction * (xi + hslo_ini) > direction * xf) {
422 auto hosc = std::get<0>(osc_step_tup);
424 auto &&omega_n = std::get<1>(osc_step_tup);
425 auto &&gamma_n = std::get<2>(osc_step_tup);
426 Scalar xcurrent = xi;
433 std::pair<complex_t, complex_t> a_pair;
434 while (std::abs(xcurrent - xf) > Scalar(1e-8)
435 && direction * xcurrent < direction * xf) {
437 bool success =
false;
438 bool steptype =
true;
441 if ((direction * hosc > direction * hslo * 5.0)
442 && (direction * hosc * wnext / (2.0 *
pi<Scalar>()) > 1.0)) {
444 if (direction * (xcurrent + hosc) > direction * xf) {
445 hosc = xf - xcurrent;
446 auto xp_scaled =
scale(info.
xp().array(), xcurrent, hosc).eval();
447 omega_n =
omega(info, xp_scaled);
448 gamma_n =
gamma(info, xp_scaled);
450 if (direction * (xcurrent + hslo) > direction * xf) {
451 hslo = xf - xcurrent;
455 std::tie(success, y, dy, err, phase, un, d_un, a_pair)
461 std::tie(success, y, dy, err, y_eval, dy_eval, cheb_N)
462 =
nonosc_step(info, xcurrent, hslo, yprev, dyprev, eps);
467 if (direction * hslo < 1e-16) {
468 throw std::domain_error(
"Stepsize became to small error");
471 auto h = steptype ? hosc : hslo;
472 if constexpr (dense_output) {
473 Eigen::Index dense_size = 0;
474 Eigen::Index dense_start = 0;
476 std::tie(dense_start, dense_size)
477 =
get_slice(x_eval, xcurrent, (xcurrent + h));
478 if (dense_size != 0) {
480 = Eigen::Map<vectord_t>(x_eval.data() + dense_start, dense_size);
482 = Eigen::Map<vectorc_t>(yeval.data() + dense_start, dense_size);
484 = Eigen::Map<vectorc_t>(dyeval.data() + dense_start, dense_size);
486 auto x_eval_scaled =
eval(
488 (2.0 / h * (x_eval_map.array() - xcurrent) - 1.0).matrix());
491 =
eval(info.
alloc_, (Linterp * un).array().exp().matrix());
493 = a_pair.first * fdense + a_pair.second * fdense.conjugate();
494 auto du_dense =
eval(info.
alloc_, (Linterp * d_un));
495 dy_eval_map = a_pair.first * (du_dense.array() * fdense.array())
497 * (du_dense.array() * fdense.array()).conjugate();
504 y_eval_map = Linterp * y_eval;
505 dy_eval_map = Linterp * dy_eval;
512 xs.push_back(xcurrent + h);
513 phases.push_back(phase);
514 steptypes.push_back(steptype);
515 successes.push_back(success);
522 dwnext = 2.0 / h * info.
Dn().row(0).dot(omega_n);
523 dgnext = 2.0 / h * info.
Dn().row(0).dot(gamma_n);
525 wnext =
omega(info, xcurrent + h);
526 gnext =
gamma(info, xcurrent + h);
527 auto xn_scaled =
scale(info.
xn().array(), xcurrent, h).eval();
528 dwnext = 2.0 / h * info.
Dn().row(0).dot(
omega(info, xn_scaled).
matrix());
530 = 2.0 / h * info.
Dn().row(0).dot(
gamma(info, (xn_scaled).
matrix()));
533 if (direction * xcurrent < direction * xf) {
535 = direction * std::min(Scalar{1e8}, std::abs(Scalar{1.0} / wnext));
537 * std::min(std::min(Scalar{1e8}, std::abs(wnext / dwnext)),
538 std::abs(gnext / dgnext));
540 if (direction * (xcurrent + hosc_ini) > direction * xf) {
541 hosc_ini = xf - xcurrent;
543 if (direction * (xcurrent + hslo_ini) > direction * xf) {
544 hslo_ini = xf - xcurrent;
549 hosc = std::get<0>(osc_step_tup);
554 info.
alloc_.recover_memory();
556 return std::make_tuple(xs, ys, dys, successes, phases, steptypes, yeval,