1#ifndef DUNE_COPASI_MODEL_MAKE_STEP_OPERATOR_HH
2#define DUNE_COPASI_MODEL_MAKE_STEP_OPERATOR_HH
4#include <dune/pdelab/common/algebra.hh>
5#include <dune/pdelab/common/container_entry.hh>
6#include <dune/pdelab/common/convergence/reason.hh>
7#include <dune/pdelab/common/error_condition.hh>
8#include <dune/pdelab/common/trace.hh>
9#include <dune/pdelab/common/execution.hh>
10#include <dune/pdelab/concepts/basis.hh>
11#include <dune/pdelab/operator/adapter.hh>
12#include <dune/pdelab/operator/forward/instationary/assembler.hh>
13#include <dune/pdelab/operator/forward/instationary/coefficients.hh>
14#include <dune/pdelab/operator/forward/runge_kutta.hh>
15#include <dune/pdelab/operator/inverse/newton.hh>
16#include <dune/pdelab/operator/operator.hh>
17#include <dune/pdelab/pattern/basis_to_pattern.hh>
18#include <dune/pdelab/pattern/pattern_to_matrix.hh>
19#include <dune/pdelab/pattern/sparsity_pattern.hh>
22#include <dune/istl/io.hh>
23#include <dune/istl/operators.hh>
24#include <dune/istl/preconditioners.hh>
25#include <dune/istl/scalarproducts.hh>
26#include <dune/istl/solvers.hh>
27#include <dune/istl/superlu.hh>
28#include <dune/istl/umfpack.hh>
30#include <dune/common/overloadset.hh>
32#include <dune/istl/bvector.hh>
34#include <spdlog/spdlog.h>
40#if (__cpp_lib_memory_resource >= 201603L) && (__cpp_lib_polymorphic_allocator >= 201902L)
41#include <memory_resource>
47inline auto jacobian_selector =
55template<
class Domain, std::copy_constructible Range>
59 using Jacobian =
decltype(Impl::jacobian_selector(Range{}));
62 class MatrixFreeAdapter :
public Dune::LinearOperator<Domain, Range>
65 MatrixFreeAdapter(PDELab::Operator<Domain, Range>&
forward_op)
70 void apply(
const Domain&
x, Range&
y)
const override
72 PDELab::forEachContainerEntry(
73 PDELab::Execution::par_unseq,
y, []<
class T>(
T&
v) {
v =
T{ 0 }; });
74 _forward.apply(
x,
y).or_throw();
77 using typename Dune::LinearOperator<Domain, Range>::field_type;
84 Dune::PDELab::axpy(PDELab::Execution::par_unseq,
y,
alpha, tmp);
87 SolverCategory::Category category()
const override
89 return SolverCategory::Category::sequential;
93 PDELab::Operator<Domain, Range>& _forward;
106 static_assert(std::is_same_v<Range, Domain>);
109 Jacobian
const *
jac =
nullptr;
110 if (
forward.hasKey(
"container"))
114#if (__cpp_lib_memory_resource >= 201603L) && (__cpp_lib_polymorphic_allocator >= 201902L)
115 auto mr = std::pmr::monotonic_buffer_resource{};
116 std::pmr::polymorphic_allocator<std::byte>
alloc{&
mr};
118 auto alloc = std::allocator<void>{};
120 std::shared_ptr<InverseOperator<Domain, Range>>
solver;
122 using Op = Dune::MatrixAdapter<Jacobian, Domain, Range>;
125 using Op = MatrixFreeAdapter;
132 auto rel_tol = this->
template get<double>(
"convergence_condition.relative_tolerance");
134 Dune::InverseOperatorResult
result;
142 return PDELab::ErrorCondition{};
155 std::shared_ptr<Preconditioner<Domain, Range>> _preconditioner;
161 class ResidualQuantity,
163 PDELab::Concept::Basis
Basis>
164[[
nodiscard]]
inline static std::unique_ptr<PDELab::OneStep<Coefficients>>
173 using RKResidual = Dune::BlockVector<Residual>;
175 if (basis.dimension() == 0) {
177 "Basis has dimension 0, make sure to have at least one 'scalar_field' "
178 "with a non-empty 'compartment'");
186 spdlog::info(
"Local operator is linear");
188 spdlog::info(
"Local operator is non-linear");
191 static_assert(std::same_as<Coefficients, Residual>);
197 std::shared_ptr<PDELab::Operator<RKResidual, RKCoefficients>>
const linear_solver =
198 std::make_shared<LinearSolver<RKResidual, RKCoefficients>>(
lsover_config);
207 spdlog::warn(
"Using conjugate gradient in a non-linear solver is not recommended");
212 std::shared_ptr<PDELab::Operator<RKCoefficients, RKResidual>>
derivative;
214 std::make_unique<PDELab::OperatorAdapter<RKResidual, RKCoefficients>>(
218 TRACE_EVENT(
"dune",
"LinearSolver::DefectCorrection");
219 static_assert(std::is_same_v<Coefficients, Residual>);
227 PDELab::forEachContainerEntry(*
coeff_zero, []<
class T>(
T&
v) {
v =
T{ 0 }; });
241 PDELab::axpy(
x, -1.,
z);
242 return Dune::PDELab::ErrorCondition{};
247 spdlog::info(
"Creating non-linear solver with 'Newton' type");
249 std::make_unique<PDELab::NewtonOperator<RKCoefficients, RKResidual, ResidualQuantity>>();
255 std::array<std::size_t, 2>{ 0, 40 });
263 if (
nlsover_config.hasKey(
"convergence_condition.absolute_tolerance")) {
264 newton_op->get(
"convergence_condition.absolute_tolerance") =
272 if (
nnorm ==
"l_2") {
274 [](
const auto&
residual) -> ResidualQuantity {
return residual.two_norm2(); });
275 }
else if (
nnorm ==
"l_inf") {
277 [](
const auto&
residual) -> ResidualQuantity {
return residual.infinity_norm(); });
278 }
else if (
nnorm ==
"l_1") {
280 [](
const auto&
residual) -> ResidualQuantity {
return residual.one_norm(); });
288 std::shared_ptr<PDELab::Operator<RKCoefficients, RKResidual>>
instationary_op;
290 instationary_op = PDELab::makeInstationaryMatrixFreeAssembler<RKCoefficients, RKResidual>(
296 if (
jac.buildStage() == RKJacobian::BuildStage::notAllocated) {
297 jac.setBuildMode(RKJacobian::implicit);
298 jac.setImplicitBuildModeParameters(1,1.);
312 std::vector<std::size_t>
comp_size(basis.degree(), 0);
314 comp_size[
i] = basis.subSpace(TypeTree::treePath(
i )).degree();
316 using SizePrefix =
typename Basis::SizePrefix;
321 if (basis.degree() == basis.size()) {
364 return { basis, {}, basis, {},
comp_max * 6 };
367 -> PDELab::BlockedSparsePattern<PDELab::LeafSparsePattern<Basis, Basis>> {
371 -> PDELab::BlockedSparsePattern<
372 PDELab::BlockedSparsePattern<PDELab::LeafSparsePattern<Basis, Basis>>> {
385 for (std::size_t
i = 0;
i !=
jac.N(); ++
i) {
386 for (std::size_t
j = 0;
j !=
jac.M(); ++
j) {
387 if (
i == 0
and j == 0)
394 auto path = std::filesystem::path{
svg_path }.replace_extension(
"svg");
395 spdlog::info(
"Writing matrix pattern in svg file: '{}'", path.string());
396 std::ofstream
file{ path.string() };
402 PDELab::makeInstationaryMatrixBasedAssembler<RKCoefficients, RKResidual, RKJacobian>(
406 using RungeKutta = PDELab::RungeKutta<RKCoefficients, RKResidual, TimeQuantity, TimeQuantity>;
411 const auto&
type =
config.get(
"type",
"Alexander2");
412 std::shared_ptr<PDELab::InstationaryCoefficients>
inst_coeff;
415 return std::make_unique<PDELab::InstationaryCoefficients>(
pdlab_param);
418 spdlog::info(
"Creating time-stepping solver with '{}' type",
type);
420 if (
type ==
"ExplicitEuler") {
422 }
else if (
type ==
"ImplicitEuler") {
424 }
else if (
type ==
"Heun") {
426 }
else if (
type ==
"Shu3") {
428 }
else if (
type ==
"RungeKutta4") {
430 }
else if (
type ==
"Alexander2") {
432 }
else if (
type ==
"FractionalStepTheta") {
434 }
else if (
type ==
"Alexander3") {
Definition make_step_operator.hh:57
virtual PDELab::ErrorCondition apply(Range &range, Domain &domain) override
Definition make_step_operator.hh:102
LinearSolver(const ParameterTree &config)
Definition make_step_operator.hh:98
virtual PDELab::ErrorCondition apply(const Range &range, Domain &domain) override
Definition make_step_operator.hh:148
std::shared_ptr< InverseOperator< typename Op::domain_type, typename Op::range_type > > makeInverseOperator(const std::shared_ptr< Op > &op, const ParameterTree &config, const Alloc &alloc=Alloc())
Definition inverse.hh:65
Definition axis_names.hh:7
auto format_exception(Exception &&e, fmt::format_string< Args... > format, Args &&... args)
Definition exceptions.hh:23
constexpr bool is_bitflags_v
Alias for Bitflag indicator.
Definition bit_flags.hh:24