Dune::Copasi
Loading...
Searching...
No Matches
model_single_compartment.impl.hh
Go to the documentation of this file.
1#ifndef DUNE_COPASI_MODEL_DIFFUSION_REACTION_SINGLE_COMPARTMENT_IMPL_HH
2#define DUNE_COPASI_MODEL_DIFFUSION_REACTION_SINGLE_COMPARTMENT_IMPL_HH
3
9
16
17#include <dune/pdelab/basis/backend/istl.hh>
18#include <dune/pdelab/basis/basis.hh>
19#include <dune/pdelab/basis/discrete_global_function.hh>
20#include <dune/pdelab/common/partition/identity.hh>
21#include <dune/pdelab/common/trace.hh>
22#include <dune/pdelab/concepts/multiindex.hh>
23
24#include <dune/grid/io/file/vtk.hh>
25
26#include <spdlog/spdlog.h>
27
28#ifdef DUNE_COPASI_PRECOMPILED_MODE
29#warning "Including this file in pre-compiled mode may defeat the purpose of pre-compilation"
30#endif
31
33
34template<class Traits>
35auto
36ModelSingleCompartment<Traits>::get_entity_set(const Grid& grid, std::size_t subdomain)
37 -> CompartmentEntitySet
38{
39 if constexpr (std::same_as<typename Grid::LeafGridView, CompartmentEntitySet>) {
40 return grid.leafGridView();
41 } else if constexpr (Concept::SubDomainGrid<typename CompartmentEntitySet::Grid>) {
42 static_assert(std::same_as<typename Grid::SubDomainGrid::LeafGridView, CompartmentEntitySet>);
43 return grid.subDomain(subdomain).leafGridView();
44 }
45 throw format_exception(NotImplemented{}, "Not known mapping from Grid to CompartmentEntitySet");
46}
47
48template<class Traits>
49void
51 State& state,
52 const std::unordered_map<std::string, GridFunction>& initial) const
53{
54 using CompartmentBasis = PDELab::Basis<PDELab::EntitySetPartitioner::Identity<CompartmentEntitySet>, CompartmentPreBasis>;
55 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
56 using Coefficients = typename CompartmentBasis::template Container<CoefficientsBackend>;
57 const auto& basis = any_cast<const CompartmentBasis&>(state.basis);
58 auto& coefficients = any_cast<Coefficients&>(state.coefficients);
59
60 Dune::Copasi::interpolate(basis, coefficients, initial);
61}
62
63template<class Traits>
64auto
66 const CompartmentEntitySet& entity_set,
67 std::string_view name,
69 std::shared_ptr<const FunctorFactory<Grid::dimensionworld>> functor_factory) -> ScalarPreBasis
70{
71 spdlog::info("Setup basis functions for component '{}'", name);
73 ScalarPreBasis{ ScalarMergingStrategy{ entity_set },
74 std::make_shared<ScalarFiniteElementMap>(entity_set),
76 scalar_field_pre_basis.name(name);
78}
79
80template<class Traits>
81auto
84 std::string_view compartment_name,
85 const std::vector<std::string>& scalar_field_names,
88{
89 spdlog::info("Setup compartment basis functions for compartment '{}'", compartment_name);
90
91 if (entity_set.size(0) == 0)
92 spdlog::warn("Compartment '{}' is empty", compartment_name);
93
94 auto boundary_mapper = std::make_shared<BoundaryEntityMapper<CompartmentEntitySet>>(entity_set);
95 std::vector<ScalarPreBasis> scalar_field_pre_basis;
96 for (const auto& name : scalar_field_names) {
97 scalar_field_pre_basis.push_back(make_scalar_field_pre_basis(boundary_mapper, entity_set, name, scalar_fields_config.sub(name), functor_factory));
98 }
99
103
104 spdlog::info("No. of components on '{}' compartment: {}",
106 compartment_pre_basis.degree());
107
109}
110
111template<class Traits>
112void
114 const Grid& grid,
115 const ParameterTree& config,
117{
118 TRACE_EVENT("dune", "Basis::SetUp");
119 using CompartmentBasis = PDELab::Basis<PDELab::EntitySetPartitioner::Identity<CompartmentEntitySet>, CompartmentPreBasis>;
120 const auto& compartments_config = config.sub("compartments", true);
121 const auto& compartments = compartments_config.getSubKeys();
122 if (compartments.size() != 1) {
123 throw format_exception(InvalidStateException{}, "Config file should only have one compartment");
124 }
125 auto compartment = compartments.front();
126 auto entity_set = get_entity_set(
127 grid, compartments_config.sub(compartment, true).template get<std::size_t>("id"));
128
129 std::vector<std::string> components;
130 const auto& scalar_fields_config = config.sub("scalar_field", true);
131 for (const auto& scalar_field : scalar_fields_config.getSubKeys()) {
132 if (scalar_fields_config.sub(scalar_field)["compartment"] == compartment) {
133 components.push_back(scalar_field);
134 }
135 }
138}
139
140template<class Traits>
141void
142ModelSingleCompartment<Traits>::setup_coefficient_vector(State& state)
143{
144 spdlog::info("Setup coefficient vector");
145 using CompartmentBasis = PDELab::Basis<PDELab::EntitySetPartitioner::Identity<CompartmentEntitySet>, CompartmentPreBasis>;
146 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
147 using Coefficients = typename CompartmentBasis::template Container<CoefficientsBackend>;
148 const auto& basis = any_cast<const CompartmentBasis&>(state.basis);
149 state.coefficients = Coefficients{ basis.makeContainer(CoefficientsBackend{}) };
150}
151
152template<class Traits>
153auto
154ModelSingleCompartment<Traits>::make_state(const std::shared_ptr<const Grid>& grid,
155 const ParameterTree& config) const
156 -> std::unique_ptr<State>
157{
158 auto state_ptr = std::make_unique<State>();
159 setup_basis(*state_ptr, *grid, config, _functor_factory);
160 setup_coefficient_vector(*state_ptr);
161 state_ptr->grid = grid;
162 state_ptr->time = TimeQuantity{ 0. };
163 return state_ptr;
164}
165
166template<class Traits>
169 std::string_view name) const
170{
171 using CompartmentBasis = PDELab::Basis<PDELab::EntitySetPartitioner::Identity<CompartmentEntitySet>, CompartmentPreBasis>;
172 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
173 using Coefficients = typename CompartmentBasis::template Container<CoefficientsBackend>;
174 const auto& basis = any_cast<const CompartmentBasis&>(state->basis);
175 const auto& coeff = any_cast<const Coefficients&>(state->coefficients);
176 std::shared_ptr<const Coefficients> const coeff_ptr(state, &coeff);
177
178 for (std::size_t component = 0; component != basis.degree(); ++component) {
179 auto leaf_space = basis.subSpace(TypeTree::treePath(std::size_t{ component }));
180 if (leaf_space.name() == name) {
182 }
183 }
184 throw format_exception(RangeError{}, "State doesn't contain any function with name: {}", name);
185}
186
187template<class Traits>
188auto
190 -> std::unordered_map<std::string, GridFunction>
191{
192 return Dune::Copasi::make_initial<GridFunction>(grid, config, *_functor_factory);
193}
194
195template<class Traits>
196auto
198 const ParameterTree& config) const
199 -> std::unique_ptr<PDELab::OneStep<State>>
200{
201 using CompartmentBasis = PDELab::Basis<PDELab::EntitySetPartitioner::Identity<CompartmentEntitySet>, CompartmentPreBasis>;
202 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
203 using Coefficients = typename CompartmentBasis::template Container<CoefficientsBackend>;
204 using ResidualBackend = PDELab::ISTLUniformBackend<ResidualQuantity>;
205 using Residual = typename CompartmentBasis::template Container<ResidualBackend>;
206 using LocalBasisTraits = typename ScalarFiniteElementMap::Traits::FiniteElement::Traits::LocalBasisType::Traits;
207
208 const auto& basis = any_cast<const CompartmentBasis&>(state.basis);
209
210 std::shared_ptr one_step = DiffusionReaction::make_step_operator<LocalBasisTraits, Coefficients, Residual, ResidualQuantity, TimeQuantity>(config, basis, 1, _functor_factory, _cell_data);
211
212 // type erase the original runge kutta operator
213 auto type_erased_one_step = std::make_unique<PDELab::OperatorAdapter<State, State>>(
214 [one_step](PDELab::Operator<State, State>& self, State& domain, State& range) mutable {
215 auto log_guard = ostream2spdlog();
216 // copy contents of this operator into runge-kutta operator
217 static_cast<PDELab::PropertyTree&>(*one_step) =
218 static_cast<const PDELab::PropertyTree&>(self);
219 auto& domain_coeff = any_cast<Coefficients&>(domain.coefficients);
220 auto& range_coeff = any_cast<Residual&>(range.coefficients);
221 return one_step->apply(domain_coeff, range_coeff);
222 });
223
224 // assign properties of the original one step to the type erased one
225 static_cast<PDELab::PropertyTree&>(*type_erased_one_step) =
226 static_cast<const PDELab::PropertyTree&>(*one_step);
227
228 auto residual_ptr = std::make_shared<Residual>(basis.makeContainer(ResidualBackend{}));
229 type_erased_one_step->get("initial_residual") = residual_ptr;
230 type_erased_one_step->get("time") = state.time;
232}
233
234template<class Traits>
235auto
237 -> std::map<std::string, double>
238{
239 using CompartmentBasis = PDELab::Basis<PDELab::EntitySetPartitioner::Identity<CompartmentEntitySet>, CompartmentPreBasis>;
240 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
241 using Coefficients = typename CompartmentBasis::template Container<CoefficientsBackend>;
242
243 // TODO(sospinar): set/get basis with concurrent entity set partition
244 const auto& basis = any_cast<const CompartmentBasis&>(state.basis);
245 const auto& coeff = any_cast<const Coefficients&>(state.coefficients);
246
247 return Dune::Copasi::DiffusionReaction::reduce(PDELab::Execution::seq, basis, coeff, state.time, config, _functor_factory);
248}
249
250template<class Traits>
251void
253 const std::filesystem::path& path,
254 bool append) const
255{
256 using CompartmentBasis = PDELab::Basis<PDELab::EntitySetPartitioner::Identity<CompartmentEntitySet>, CompartmentPreBasis>;
257 using CoefficientsBackend = PDELab::ISTLUniformBackend<ScalarQuantity>;
258 using Coefficients = typename CompartmentBasis::template Container<CoefficientsBackend>;
259 const auto& basis = any_cast<const CompartmentBasis&>(state.basis);
260 const auto& coeff = any_cast<const Coefficients&>(state.coefficients);
261 // warning: we use Dune::stackobject_to_shared_ptr to avoid copying the coefficients vector,
262 // be we need to check that no one else took ownership of this pointer when we leave this
263 // function!
264 std::shared_ptr<const Coefficients> const coeff_ptr = Dune::stackobject_to_shared_ptr(coeff);
265
266 // create directory if necessary
267 auto path_entry = std::filesystem::directory_entry{ path };
268 if (not path_entry.exists()) {
269 spdlog::info("Creating output directory '{}'", path_entry.path().string());
270 std::error_code ec{ 0, std::generic_category() };
271 std::filesystem::create_directories(path_entry.path(), ec);
272 if (ec) {
274 "\n Category: {}\nValue: {}\nMessage: {}\n",
275 ec.category().name(),
276 ec.value(),
277 ec.message());
278 }
279 }
280
281 // Recover old timestesps in case something was written before
282 auto& timesteps = _writer_timesteps[path.string()];
283 std::string name = fmt::format("{}-{}", path.filename().string(), basis.name());
284 if (not append) {
285 timesteps.clear();
286 spdlog::info("Creating a time sequence file: '{}.pvd'", name);
287 } else {
288 spdlog::info("Overriding time sequence file: '{}.pvd'", name);
289 }
290
291 // setup writer again with old timesteps if necessary
292 auto writer =
293 std::make_shared<VTKWriter<CompartmentEntitySet>>(basis.entitySet(), Dune::VTK::conforming);
294 auto sequential_writer =
295 VTKSequenceWriter<CompartmentEntitySet>{ writer, name, path.string(), path.string() };
296 sequential_writer.setTimeSteps(timesteps);
297
298 for (std::size_t component = 0; component != basis.degree(); ++component) {
299 auto const component_basis =
300 basis.subSpace(TypeTree::treePath(std::size_t{ component }));
301 sequential_writer.vtkWriter()->addVertexData(
303 VTK::FieldInfo{ component_basis.name(), VTK::FieldInfo::Type::scalar, 1 });
304 }
305
306 spdlog::info("Writing solution for {:.2f}s time stamp", state.time);
307 spdlog::info("Writing vtu file: '{0}/{0}-{1:0>5}.vtu'", name, timesteps.size());
308 TRACE_EVENT("dune", "WriteVTK");
309 sequential_writer.write(state.time, Dune::VTK::base64);
310 sequential_writer.vtkWriter()->clear();
311 timesteps = sequential_writer.getTimeSteps();
312
313 if (coeff_ptr.use_count() != 1) {
314 throw format_exception(
316 "Fake shared pointer from coefficient vector may have been leaked outside of this"
317 "function!");
318 }
319}
320
321} // namespace Dune::Copasi::DiffusionReaction
322
323#endif // DUNE_COPASI_MODEL_DIFFUSION_REACTION_SINGLE_COMPARTMENT_IMPL_HH
Mapper of boundary entities.
Definition boundary_entity_mapper.hh:26
Constraints parser and operator for a leaf basis.
Definition constraints.hh:29
Definition model_single_compartment.hh:26
std::unique_ptr< State > make_state(const std::shared_ptr< const Grid > &, const ParameterTree &) const override
Definition model_single_compartment.impl.hh:154
typename Traits::CompartmentEntitySet CompartmentEntitySet
Definition model_single_compartment.hh:37
typename Traits::CompartmentMergingStrategy CompartmentMergingStrategy
Definition model_single_compartment.hh:42
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
typename Traits::Grid Grid
Definition model_single_compartment.hh:34
typename Base::State State
Definition model_single_compartment.hh:33
GridFunction make_compartment_function(const std::shared_ptr< const State > &, std::string_view) const override
Definition model_single_compartment.impl.hh:168
std::map< std::string, double > reduce(const State &, const ParameterTree &) const override
Definition model_single_compartment.impl.hh:236
PDELab::PreBasisVector< CompartmentMergingStrategy, ScalarPreBasis > CompartmentPreBasis
Definition model_single_compartment.hh:43
typename Base::GridFunction GridFunction
Definition model_single_compartment.hh:46
void interpolate(State &, const std::unordered_map< std::string, GridFunction > &) const override
Definition model_single_compartment.impl.hh:50
void write_vtk(const State &, const std::filesystem::path &, bool=true) const override
Definition model_single_compartment.impl.hh:252
typename Traits::TimeQuantity TimeQuantity
Definition model_single_compartment.hh:35
std::unordered_map< std::string, GridFunction > make_initial(const Grid &, const ParameterTree &) const override
Definition model_single_compartment.impl.hh:189
std::unique_ptr< PDELab::OneStep< State > > make_step_operator(const State &, const ParameterTree &) const override
Definition model_single_compartment.impl.hh:197
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
constexpr bool is_bitflags_v
Alias for Bitflag indicator.
Definition bit_flags.hh:24
auto ostream2spdlog()
Standard output redirection to spdlog.
Definition ostream_to_spdlog.hh:20