1#ifndef DUNE_COPASI_MODEL_DIFFUSION_REACTION_MULTI_COMPARTMENT_IMPL_HH
2#define DUNE_COPASI_MODEL_DIFFUSION_REACTION_MULTI_COMPARTMENT_IMPL_HH
12#include <dune/pdelab/basis/backend/istl.hh>
13#include <dune/pdelab/basis/basis.hh>
14#include <dune/pdelab/basis/discrete_global_function.hh>
15#include <dune/pdelab/common/trace.hh>
16#include <dune/pdelab/common/partition/identity.hh>
17#include <dune/pdelab/concepts/multiindex.hh>
19#include <dune/grid/io/file/vtk.hh>
21#include <spdlog/spdlog.h>
25#ifdef DUNE_COPASI_PRECOMPILED_MODE
26#warning "Including this file in pre-compiled mode may defeat the purpose of pre-compilation"
35 const std::unordered_map<std::string, GridFunction>& initial)
const
37 using MultiCompartmentBasis =
38 PDELab::Basis<PDELab::EntitySetPartitioner::Identity<MultiCompartmentEntitySet>,
MultiCompartmentPreBasis, TypeTree::HybridTreePath<>>;
40 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
41 using Coefficients =
typename MultiCompartmentBasis::template Container<CoefficientsBackend>;
42 using MultiCompartmentBasis =
43 PDELab::Basis<PDELab::EntitySetPartitioner::Identity<MultiCompartmentEntitySet>,
MultiCompartmentPreBasis, TypeTree::HybridTreePath<>>;
45 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
46 using Coefficients =
typename MultiCompartmentBasis::template Container<CoefficientsBackend>;
47 const auto& basis = any_cast<const MultiCompartmentBasis&>(state.basis);
48 auto& coefficients = any_cast<Coefficients&>(state.coefficients);
50 Dune::Copasi::interpolate(basis, coefficients, initial);
57 const ParameterTree& config,
60 TRACE_EVENT(
"dune",
"Basis::SetUp");
61 spdlog::info(
"Setup basis functions");
63 const auto& compartments_config = config.sub(
"compartments",
true);
65 std::vector<CompartmentPreBasis> compartment_pre_basis_vec;
67 std::map<std::string, std::vector<std::string>> compartment2componets;
68 const auto& scalar_fields_config = config.sub(
"scalar_field");
69 for (
const auto& component : scalar_fields_config.getSubKeys())
70 compartment2componets[config[fmt::format(
"scalar_field.{}.compartment", component)]].push_back(component);
72 for (
const auto& compartment : compartments_config.getSubKeys()) {
73 using SubDomainIndex =
typename Grid::SubDomainIndex;
74 const auto& components = compartment2componets[compartment];
75 SubDomainIndex domain_id =
76 compartments_config.sub(compartment,
true).template get<SubDomainIndex>(
"id");
78 CompartmentEntitySet sub_grid_view = grid.subDomain(domain_id).leafGridView();
80 CompartmentPreBasis compartment_pre_basis =
82 sub_grid_view, compartment, components, scalar_fields_config, functor_factory);
83 compartment_pre_basis_vec.emplace_back(compartment_pre_basis);
86 spdlog::info(
"Setup of multi-compartment grid function space");
88 MultiCompartmentPreBasis multi_compartment_pre_basis =
89 composite(MultiCompartmentMergingStrategy{}, compartment_pre_basis_vec);
91 multi_compartment_pre_basis.name(
"compartments");
92 return multi_compartment_pre_basis;
97ModelMultiCompartment<Traits>::setup_coefficient_vector(State& state)
99 using MultiCompartmentBasis =
100 PDELab::Basis<PDELab::EntitySetPartitioner::Identity<MultiCompartmentEntitySet>, MultiCompartmentPreBasis, TypeTree::HybridTreePath<>>;
101 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
102 using Coefficients =
typename MultiCompartmentBasis::template Container<CoefficientsBackend>;
104 spdlog::info(
"Setup coefficient vector");
105 const auto& basis = any_cast<const MultiCompartmentBasis&>(state.basis);
106 state.coefficients = Coefficients{ basis.makeContainer(CoefficientsBackend{}) };
109template<
class Traits>
112 const ParameterTree& config)
const
113 -> std::unique_ptr<State>
115 auto state_ptr = std::make_unique<State>();
116 state_ptr->basis = makeBasis(grid->leafGridView(),
117 make_multi_compartment_pre_basis(*grid, config, _functor_factory));
118 setup_coefficient_vector(*state_ptr);
119 state_ptr->grid = grid;
124template<
class Traits>
127 const std::shared_ptr<const State>& state,
130 using MultiCompartmentBasis =
131 PDELab::Basis<PDELab::EntitySetPartitioner::Identity<MultiCompartmentEntitySet>,
MultiCompartmentPreBasis, TypeTree::HybridTreePath<>>;
132 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
133 using Coefficients =
typename MultiCompartmentBasis::template Container<CoefficientsBackend>;
135 const auto& basis = any_cast<const MultiCompartmentBasis&>(state->basis);
136 const auto& coeff = any_cast<const Coefficients&>(state->coefficients);
137 std::shared_ptr<const Coefficients> coeff_ptr(state, &coeff);
139 MultiCompartmentBasis multi_compartment_basis = basis.subSpace(TypeTree::treePath());
140 for (std::size_t compartment = 0; compartment != multi_compartment_basis.degree();
142 auto compartment_basis =
143 multi_compartment_basis.subSpace(TypeTree::treePath(compartment));
144 for (std::size_t species = 0; species != compartment_basis.degree(); ++species) {
145 auto species_basis = compartment_basis.subSpace(TypeTree::treePath(species));
146 if (species_basis.name() == name)
147 return makeDiscreteGlobalBasisFunction(species_basis, coeff_ptr);
150 throw format_exception(RangeError{},
"State doesn't contain any function with name: {}", name);
153template<
class Traits>
156 const ParameterTree& config)
const
157 -> std::unordered_map<std::string, GridFunction>
159 return Dune::Copasi::make_initial<GridFunction>(grid, config, *_functor_factory);
162template<
class Traits>
165 -> std::map<std::string, double>
167 using MultiCompartmentBasis =
168 PDELab::Basis<PDELab::EntitySetPartitioner::Identity<MultiCompartmentEntitySet>,
MultiCompartmentPreBasis, TypeTree::HybridTreePath<>>;
169 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
170 using Coefficients =
typename MultiCompartmentBasis::template Container<CoefficientsBackend>;
173 const auto& basis = any_cast<const MultiCompartmentBasis&>(state.basis);
174 const auto& coeff = any_cast<const Coefficients&>(state.coefficients);
176 return Dune::Copasi::DiffusionReaction::reduce(PDELab::Execution::seq, basis, coeff, state.time, reduce_cfg, domain_cfg, _functor_factory);
179template<
class Traits>
183 const ParameterTree& config)
const -> std::unique_ptr<PDELab::OneStep<State>>
185 using MultiCompartmentBasis =
186 PDELab::Basis<PDELab::EntitySetPartitioner::Identity<MultiCompartmentEntitySet>,
MultiCompartmentPreBasis, TypeTree::HybridTreePath<>>;
187 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
188 using Coefficients =
typename MultiCompartmentBasis::template Container<CoefficientsBackend>;
189 using ResidualBackend = PDELab::ISTLUniformBackend<ResidualQuantity>;
190 using Residual =
typename MultiCompartmentBasis::template Container<ResidualBackend>;
191 using LocalBasisTraits =
typename ScalarFiniteElementMap::Traits::FiniteElement::Traits::LocalBasisType::Traits;
193 const auto& basis = any_cast<const MultiCompartmentBasis&>(state.basis);
194 std::shared_ptr one_step = DiffusionReaction::make_step_operator<LocalBasisTraits, Coefficients, Residual, ResidualQuantity, TimeQuantity>(config, basis, 2, _functor_factory, _cell_data);
197 auto type_erased_one_step = std::make_unique<PDELab::OperatorAdapter<State, State>>(
198 [one_step](PDELab::Operator<State, State>& self,
State& domain,
State& range)
mutable {
201 static_cast<PDELab::PropertyTree&
>(*one_step) =
202 static_cast<const PDELab::PropertyTree&
>(self);
203 Coefficients& domain_coeff = any_cast<Coefficients&>(domain.coefficients);
204 Residual& range_coeff = any_cast<Residual&>(range.coefficients);
205 return one_step->apply(domain_coeff, range_coeff);
209 static_cast<PDELab::PropertyTree&
>(*type_erased_one_step) =
210 static_cast<const PDELab::PropertyTree&
>(*one_step);
212 auto residual_ptr = std::make_shared<Residual>(basis.makeContainer(ResidualBackend{}));
213 type_erased_one_step->get(
"initial_residual") = residual_ptr;
214 type_erased_one_step->get(
"time") = state.time;
215 return type_erased_one_step;
218template<
class Traits>
221 const std::filesystem::path& path,
224 using MultiCompartmentBasis =
225 PDELab::Basis<PDELab::EntitySetPartitioner::Identity<MultiCompartmentEntitySet>,
MultiCompartmentPreBasis, TypeTree::HybridTreePath<>>;
226 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
227 using Coefficients =
typename MultiCompartmentBasis::template Container<CoefficientsBackend>;
229 const auto& basis = any_cast<const MultiCompartmentBasis&>(state.basis);
230 const auto& coeff = any_cast<const Coefficients&>(state.coefficients);
233 std::shared_ptr<const Coefficients> coeff_ptr = Dune::stackobject_to_shared_ptr(coeff);
236 auto path_entry = std::filesystem::directory_entry{ path };
237 if (not path_entry.exists()) {
238 spdlog::info(
"Creating output directory '{}'", path_entry.path().string());
239 std::error_code ec{ 0, std::generic_category() };
240 std::filesystem::create_directories(path_entry.path(), ec);
246 ec.category().name(),
251 spdlog::info(
"Writing solution for {:.2f}s time stamp", state.time);
252 MultiCompartmentBasis multi_compartment_basis = basis.subSpace(TypeTree::treePath());
255 auto& timesteps = _writer_timesteps[path.string()];
256 std::vector<double> tmp_timesteps;
258 for (std::size_t compartment = 0; compartment != multi_compartment_basis.degree();
260 auto compartment_basis =
261 multi_compartment_basis.subSpace(TypeTree::treePath(compartment));
262 std::string name = fmt::format(
"{}-{}", path.filename().string(), compartment_basis.name());
265 spdlog::info(
"Creating a time sequence file: '{}.pvd'", name);
267 spdlog::info(
"Overriding time sequence file: '{}.pvd'", name);
271 auto writer = std::make_shared<VTKWriter<CompartmentEntitySet>>(compartment_basis.entitySet(),
272 Dune::VTK::conforming);
273 auto sequential_writer =
274 VTKSequenceWriter<CompartmentEntitySet>{ writer, name, path.string(), path.string() };
275 sequential_writer.setTimeSteps(timesteps);
277 for (std::size_t species = 0; species != compartment_basis.degree(); ++species) {
279 compartment_basis.subSpace(TypeTree::treePath(std::size_t{ species }));
280 sequential_writer.vtkWriter()->addVertexData(
281 makeDiscreteGlobalBasisFunction(species_basis, coeff_ptr),
282 VTK::FieldInfo{ species_basis.name(), VTK::FieldInfo::Type::scalar, 1 });
284 spdlog::info(
"Writing vtu file: '{0}/{0}-{1:0>5}.vtu'", name, timesteps.size());
285 TRACE_EVENT(
"dune",
"WriteVTK");
286 sequential_writer.write(state.time, Dune::VTK::base64);
287 sequential_writer.vtkWriter()->clear();
289 tmp_timesteps = sequential_writer.getTimeSteps();
292 timesteps = tmp_timesteps;
294 if (coeff_ptr.use_count() != 1)
296 InvalidStateException{},
297 "Fake shared pointer from coefficient vector may have been leaked outsie of this function!");
Definition: model_multi_compartment.hh:28
void write_vtk(const State &, const std::filesystem::path &, bool) const override
Definition: model_multi_compartment.impl.hh:220
GridFunction make_compartment_function(const std::shared_ptr< const State > &, std::string_view) const override
Definition: model_multi_compartment.impl.hh:126
typename Base::State State
Definition: model_multi_compartment.hh:35
void interpolate(State &, const std::unordered_map< std::string, GridFunction > &) const override
Definition: model_multi_compartment.impl.hh:33
std::unordered_map< std::string, GridFunction > make_initial(const Grid &, const ParameterTree &) const override
Definition: model_multi_compartment.impl.hh:155
std::map< std::string, double > reduce(const State &, const ParameterTree &, const ParameterTree &={}) const override
Definition: model_multi_compartment.impl.hh:164
typename Traits::Grid Grid
Definition: model_multi_compartment.hh:36
typename Base::GridFunction GridFunction
Definition: model_multi_compartment.hh:56
typename Traits::TimeQuantity TimeQuantity
Definition: model_multi_compartment.hh:37
PDELab::PreBasisVector< MultiCompartmentMergingStrategy, CompartmentPreBasis > MultiCompartmentPreBasis
Definition: model_multi_compartment.hh:52
std::unique_ptr< State > make_state(const std::shared_ptr< const Grid > &, const ParameterTree &) const override
Definition: model_multi_compartment.impl.hh:111
std::unique_ptr< PDELab::OneStep< State > > make_step_operator(const State &, const ParameterTree &) const override
Definition: model_multi_compartment.impl.hh:181
static CompartmentPreBasis make_compartment_pre_basis(const CompartmentEntitySet &, std::string_view, const std::vector< std::string > &, const ParameterTree &={}, std::shared_ptr< const FunctorFactory< Grid::dimensionworld > >=nullptr)
Definition: model_single_compartment.impl.hh:82
Definition: functor_factory.hh:24
Definition: factory.hh:28
auto format_exception(Exception &&e, fmt::format_string< Args... > format, Args &&... args)
Definition: exceptions.hh:23
auto ostream2spdlog()
Standard output redirection to spdlog.
Definition: ostream_to_spdlog.hh:20