ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
script_interface/walberla/EKContainer.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022-2023 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <config/config.hpp>
23
24#ifdef ESPRESSO_WALBERLA
25
26#include "EKFFT.hpp"
27#include "EKNone.hpp"
28#include "EKReactions.hpp"
29#include "EKSpecies.hpp"
30
33
36#include "core/ek/Solver.hpp"
38
42
43#include <cassert>
44#include <memory>
45#include <optional>
46#include <string>
47#include <variant>
48
50
51class EKContainer : public ObjectList<EKSpecies, EK::Container> {
53 using Base::value_type;
54
55 std::variant<
56#ifdef ESPRESSO_WALBERLA_FFT
57 std::shared_ptr<EKFFT>,
58#endif
59 std::shared_ptr<EKNone>>
60 m_poisson_solver;
61
62 std::shared_ptr<EKReactions> m_ek_reactions;
63 std::shared_ptr<::EK::EKWalberla> m_ek_instance;
64 std::shared_ptr<::EK::EKWalberla::ek_container_type> m_ek_container;
65 bool m_is_active;
66
67 auto get_precision(decltype(m_poisson_solver) const &solver) const {
68 std::optional<bool> result = std::nullopt;
69 std::visit(
70 [&](auto const &ptr) {
71 using SolverType = std::remove_cvref_t<decltype(ptr)>::element_type;
72 if (ptr and not std::is_same_v<SolverType, EKNone>) {
73 result = get_value<bool>(ptr->get_parameter("single_precision"));
74 }
75 },
76 solver);
77 return result;
78 }
79
80 auto get_precision(value_type const &species) const {
81 return get_value<bool>(species->get_parameter("single_precision"));
82 }
83
84 auto get_precision(std::vector<value_type> const &species_list) const {
85 std::optional<bool> result = std::nullopt;
86 for (auto const &species : species_list) {
87 result = get_precision(species);
88 }
89 return result;
90 }
91
92 bool has_in_core(value_type const &obj_ptr) const override {
93 return m_ek_container->contains(obj_ptr->get_ekinstance());
94 }
95 void add_in_core(value_type const &obj_ptr) override {
96 context()->parallel_try_catch([this, &obj_ptr]() {
97 auto const prec_new_species = get_precision(obj_ptr);
98 auto const prec_old_species = get_precision(elements());
99 auto const prec_solver = get_precision(m_poisson_solver);
102 throw std::runtime_error(
103 "Cannot mix single and double precision kernels");
104 }
105 ek_throw_if_expired(obj_ptr->get_mpi_cart_comm_observer());
106 m_ek_container->add(obj_ptr->get_ekinstance());
107 });
108 }
109 void remove_in_core(value_type const &obj_ptr) final {
110 m_ek_container->remove(obj_ptr->get_ekinstance());
111 }
112
113 struct GetPoissonSolverAsVariant {
114 template <typename T>
115 auto operator()(std::shared_ptr<T> const &solver) const {
116 return (solver) ? Variant{solver} : Variant{none};
117 }
118 };
119
120 Variant get_solver() const {
121 return std::visit(GetPoissonSolverAsVariant(), m_poisson_solver);
122 }
123
124 struct GetPoissonSolverCoreInstance {
125 template <typename T>
126 std::shared_ptr<::walberla::PoissonSolver>
127 operator()(std::shared_ptr<T> const &solver) const {
128 return solver->get_instance();
129 }
130 };
131
132 auto extract_solver(Variant const &v) {
133 std::optional<decltype(m_poisson_solver)> solver;
135 if (auto ptr = std::dynamic_pointer_cast<EKNone>(so_ptr)) {
136 solver = std::move(ptr);
137 }
138#ifdef ESPRESSO_WALBERLA_FFT
139 else if (auto ptr = std::dynamic_pointer_cast<EKFFT>(so_ptr)) {
140 solver = std::move(ptr);
141 }
142#endif // ESPRESSO_WALBERLA_FFT
143 assert(solver.has_value());
144 return *solver;
145 }
146
147 void set_solver(Variant const &v) {
148 auto new_solver = extract_solver(v);
149 auto handle = std::visit(GetPoissonSolverCoreInstance{}, new_solver);
150 context()->parallel_try_catch([&]() {
151 auto const prec_solver = get_precision(new_solver);
152 auto const prec_species = get_precision(elements());
154 throw std::runtime_error(
155 "Cannot mix single and double precision kernels");
156 }
157 m_ek_container->set_poisson_solver(handle);
158 });
159 m_poisson_solver = new_solver;
160 }
161
162public:
164 add_parameters({
166 [this]() { return m_ek_container->get_tau(); }},
167 {"solver", [this](Variant const &v) { set_solver(v); },
168 [this]() { return get_solver(); }},
169 {"reactions", AutoParameter::read_only,
170 [this]() { return m_ek_reactions; }},
171 {"is_active", AutoParameter::read_only,
172 [this]() { return m_is_active; }},
173 });
174 }
175
176 ~EKContainer() override { do_destruct(); }
177
178 void do_construct(VariantMap const &params) override {
179 m_is_active = false;
180 auto const tau = get_value<double>(params, "tau");
181 context()->parallel_try_catch([tau]() {
182 if (tau <= 0.) {
183 throw std::domain_error("Parameter 'tau' must be > 0");
184 }
185 });
186 m_poisson_solver = extract_solver(
187 params.contains("solver") ? params.at("solver") : Variant{none});
188 m_ek_container = std::make_shared<::EK::EKWalberla::ek_container_type>(
189 tau, std::visit(GetPoissonSolverCoreInstance{}, m_poisson_solver));
190 m_ek_reactions = get_value<decltype(m_ek_reactions)>(params, "reactions");
191 m_ek_instance = std::make_shared<::EK::EKWalberla>(
192 m_ek_container, m_ek_reactions->get_handle());
193 // EK species must be added after tau
194 Base::do_construct(params);
195 }
196
197protected:
198 Variant do_call_method(std::string const &method,
199 VariantMap const &parameters) override {
200 if (method == "activate") {
201 get_system().ek.set<::EK::EKWalberla>(m_ek_instance);
202 m_is_active = true;
203 return {};
204 }
205 if (method == "deactivate") {
206 get_system().ek.reset();
207 m_is_active = false;
208 return {};
209 }
210
212 }
213};
214
215} // namespace ScriptInterface::walberla
216
217#endif // ESPRESSO_WALBERLA
Owning list of object handles.
void do_construct(VariantMap const &params) override
Variant do_call_method(std::string const &method, VariantMap const &parameters) override
bool has_in_core(value_type const &obj_ptr) const override
Variant do_call_method(std::string const &method, VariantMap const &parameters) override
This file contains the asynchronous MPI communication.
void ek_throw_if_expired(std::optional< ResourceObserver > const &mpi_obs)
Definition EKSpecies.hpp:57
T get_value(Variant const &v)
Extract value of specific type T from a Variant.
std::unordered_map< std::string, Variant > VariantMap
Definition Variant.hpp:133
make_recursive_variant< ObjectRef > Variant
Possible types for parameters.
Definition Variant.hpp:131
constexpr const None none
None-"literal".
Definition Variant.hpp:126
void set(Args... args)
Set the EK solver.
void reset()
Remove the EK solver.
Definition ek/Solver.cpp:60
static constexpr const ReadOnly read_only
Recursive variant implementation.
Definition Variant.hpp:84