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-2026 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 <stdexcept>
47#include <string>
48#include <variant>
49
51
52class EKContainer : public ObjectList<EKSpecies, EK::Container> {
54 using Base::value_type;
55
56 std::variant<
57#ifdef ESPRESSO_WALBERLA_FFT
58 std::shared_ptr<EKFFT>,
59#endif
60 std::shared_ptr<EKNone>>
61 m_poisson_solver;
62
63 std::shared_ptr<EKReactions> m_ek_reactions;
64 std::shared_ptr<::EK::EKWalberla> m_ek_instance;
65 std::shared_ptr<::EK::EKWalberla::ek_container_type> m_ek_container;
66 bool m_is_active;
67
68 auto get_precision(decltype(m_poisson_solver) const &solver) const {
69 std::optional<bool> result = std::nullopt;
70 std::visit(
71 [&](auto const &ptr) {
72 using SolverType = std::remove_cvref_t<decltype(ptr)>::element_type;
73 if (ptr and not std::is_same_v<SolverType, EKNone>) {
74 result = get_value<bool>(ptr->get_parameter("single_precision"));
75 }
76 },
77 solver);
78 return result;
79 }
80
81 auto get_precision(value_type const &species) const {
82 return get_value<bool>(species->get_parameter("single_precision"));
83 }
84
85 auto get_precision(std::vector<value_type> const &species_list) const {
86 std::optional<bool> result = std::nullopt;
87 for (auto const &species : species_list) {
88 result = get_precision(species);
89 }
90 return result;
91 }
92
93 bool has_in_core(value_type const &obj_ptr) const override {
94 return m_ek_container->contains(obj_ptr->get_ekinstance());
95 }
96 void add_in_core(value_type const &obj_ptr) override {
97 context()->parallel_try_catch([this, &obj_ptr]() {
98 auto const prec_new_species = get_precision(obj_ptr);
99 auto const prec_old_species = get_precision(elements());
100 auto const prec_solver = get_precision(m_poisson_solver);
103 throw std::runtime_error(
104 "Cannot mix single and double precision kernels");
105 }
106 ek_throw_if_expired(obj_ptr->get_mpi_cart_comm_observer());
107 m_ek_container->add(obj_ptr->get_ekinstance());
108 });
109 }
110 void remove_in_core(value_type const &obj_ptr) final {
111 m_ek_container->remove(obj_ptr->get_ekinstance());
112 }
113
114 struct GetPoissonSolverAsVariant {
115 template <typename T>
116 auto operator()(std::shared_ptr<T> const &solver) const {
117 return (solver) ? Variant{solver} : Variant{none};
118 }
119 };
120
121 Variant get_solver() const {
122 return std::visit(GetPoissonSolverAsVariant(), m_poisson_solver);
123 }
124
125 struct GetPoissonSolverCoreInstance {
126 template <typename T>
127 std::shared_ptr<::walberla::PoissonSolver>
128 operator()(std::shared_ptr<T> const &solver) const {
129 return solver->get_instance();
130 }
131 };
132
133 auto extract_solver(Variant const &v) {
134 std::optional<decltype(m_poisson_solver)> solver;
136 if (auto ptr = std::dynamic_pointer_cast<EKNone>(so_ptr)) {
137 solver = std::move(ptr);
138 }
139#ifdef ESPRESSO_WALBERLA_FFT
140 else if (auto ptr = std::dynamic_pointer_cast<EKFFT>(so_ptr)) {
141 solver = std::move(ptr);
142 }
143#endif // ESPRESSO_WALBERLA_FFT
144 if (not solver.has_value()) {
145 context()->parallel_try_catch([]() {
146 throw std::invalid_argument("EK solver is of the wrong type");
147 });
148 }
149 return *solver;
150 }
151
152 void set_solver(Variant const &v) {
153 auto new_solver = extract_solver(v);
154 auto handle = std::visit(GetPoissonSolverCoreInstance{}, new_solver);
155 context()->parallel_try_catch([&]() {
156 auto const prec_solver = get_precision(new_solver);
157 auto const prec_species = get_precision(elements());
159 throw std::runtime_error(
160 "Cannot mix single and double precision kernels");
161 }
162 m_ek_container->set_poisson_solver(handle);
163 });
164 m_poisson_solver = new_solver;
165 }
166
167public:
169 add_parameters({
171 [this]() { return m_ek_container->get_tau(); }},
172 {"solver", [this](Variant const &v) { set_solver(v); },
173 [this]() { return get_solver(); }},
174 {"reactions", AutoParameter::read_only,
175 [this]() { return m_ek_reactions; }},
176 {"is_active", AutoParameter::read_only,
177 [this]() { return m_is_active; }},
179 [this]() { return m_ek_container->is_gpu(); }},
180 });
181 }
182
183 ~EKContainer() override { do_destruct(); }
184
185 void do_construct(VariantMap const &params) override {
186 m_is_active = false;
187 auto const tau = get_value<double>(params, "tau");
188 context()->parallel_try_catch([&]() {
189 if (tau <= 0.) {
190 throw std::domain_error("Parameter 'tau' must be > 0");
191 }
192 if (not params.contains("solver")) {
193 throw std::runtime_error("Parameter 'solver' is required; use EKNone "
194 "if all species are electrically neutral");
195 }
196 });
197 m_poisson_solver = extract_solver(params.at("solver"));
198 m_ek_container = std::make_shared<::EK::EKWalberla::ek_container_type>(
199 tau, std::visit(GetPoissonSolverCoreInstance{}, m_poisson_solver));
200 m_ek_reactions = get_value<decltype(m_ek_reactions)>(params, "reactions");
201 m_ek_instance = std::make_shared<::EK::EKWalberla>(
202 m_ek_container, m_ek_reactions->get_handle());
203 // EK species must be added after tau
204 Base::do_construct(params);
205 }
206
207protected:
208 Variant do_call_method(std::string const &method,
209 VariantMap const &parameters) override {
210 if (method == "activate") {
211 get_system().ek.set<::EK::EKWalberla>(m_ek_instance);
212 m_is_active = true;
213 return {};
214 }
215 if (method == "deactivate") {
216 get_system().ek.reset();
217 m_is_active = false;
218 return {};
219 }
220
222 }
223};
224
225} // namespace ScriptInterface::walberla
226
227#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
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
This file contains the asynchronous MPI communication.
void ek_throw_if_expired(std::optional< ResourceObserver > const &mpi_obs)
Definition EKSpecies.hpp:57
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