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 "EKFFT_GPU.hpp"
28#include "EKNone.hpp"
29#include "EKReactions.hpp"
30#include "EKSpecies.hpp"
31
34
37#include "core/ek/Solver.hpp"
39
42
43#include <cassert>
44#include <memory>
45#include <optional>
46#include <string>
47#include <variant>
48
50
51class EKContainer : public ObjectList<EKSpecies> {
53 using Base::value_type;
54
55 std::variant<
56#ifdef ESPRESSO_WALBERLA_FFT
57 std::shared_ptr<EKFFT>,
58#ifdef ESPRESSO_CUDA
59 std::shared_ptr<EKFFTGPU>,
60#endif
61#endif
62 std::shared_ptr<EKNone>>
63 m_poisson_solver;
64
65 std::shared_ptr<EKReactions> m_ek_reactions;
66 std::shared_ptr<::EK::EKWalberla> m_ek_instance;
67 std::shared_ptr<::EK::EKWalberla::ek_container_type> m_ek_container;
68 bool m_is_active;
69
70 auto get_precision(decltype(m_poisson_solver) const &solver) const {
71 std::optional<bool> result = std::nullopt;
72 std::visit(
73 [&](auto const &ptr) {
74 using SolverType = std::remove_cvref_t<decltype(ptr)>::element_type;
75 if (ptr and not std::is_same_v<SolverType, EKNone>) {
76 result = get_value<bool>(ptr->get_parameter("single_precision"));
77 }
78 },
79 solver);
80 return result;
81 }
82
83 auto get_precision(value_type const &species) const {
84 return get_value<bool>(species->get_parameter("single_precision"));
85 }
86
87 auto get_precision(std::vector<value_type> const &species_list) const {
88 std::optional<bool> result = std::nullopt;
89 for (auto const &species : species_list) {
90 result = get_precision(species);
91 }
92 return result;
93 }
94
95 bool has_in_core(value_type const &obj_ptr) const override {
96 return m_ek_container->contains(obj_ptr->get_ekinstance());
97 }
98 void add_in_core(value_type const &obj_ptr) override {
99 context()->parallel_try_catch([this, &obj_ptr]() {
100 auto const prec_new_species = get_precision(obj_ptr);
101 auto const prec_old_species = get_precision(elements());
102 auto const prec_solver = get_precision(m_poisson_solver);
105 throw std::runtime_error(
106 "Cannot mix single and double precision kernels");
107 }
108 m_ek_container->add(obj_ptr->get_ekinstance());
109 });
110 }
111 void remove_in_core(value_type const &obj_ptr) final {
112 m_ek_container->remove(obj_ptr->get_ekinstance());
113 }
114
115 struct GetPoissonSolverAsVariant {
116 template <typename T>
117 auto operator()(std::shared_ptr<T> const &solver) const {
118 return (solver) ? Variant{solver} : Variant{none};
119 }
120 };
121
122 Variant get_solver() const {
123 return std::visit(GetPoissonSolverAsVariant(), m_poisson_solver);
124 }
125
126 struct GetPoissonSolverCoreInstance {
127 template <typename T>
128 std::shared_ptr<::walberla::PoissonSolver>
129 operator()(std::shared_ptr<T> const &solver) const {
130 return solver->get_instance();
131 }
132 };
133
134 auto extract_solver(Variant const &v) {
135 std::optional<decltype(m_poisson_solver)> solver;
137 if (auto ptr = std::dynamic_pointer_cast<EKNone>(so_ptr)) {
138 solver = std::move(ptr);
139 }
140#ifdef ESPRESSO_WALBERLA_FFT
141#ifdef ESPRESSO_CUDA
142 else if (auto ptr = std::dynamic_pointer_cast<EKFFTGPU>(so_ptr)) {
143 solver = std::move(ptr);
144 }
145#endif // ESPRESSO_CUDA
146 else if (auto ptr = std::dynamic_pointer_cast<EKFFT>(so_ptr)) {
147 solver = std::move(ptr);
148 }
149#endif // ESPRESSO_WALBERLA_FFT
150 assert(solver.has_value());
151 return *solver;
152 }
153
154 void set_solver(Variant const &v) {
155 auto new_solver = extract_solver(v);
156 auto handle = std::visit(GetPoissonSolverCoreInstance{}, new_solver);
157 context()->parallel_try_catch([&]() {
158 auto const prec_solver = get_precision(new_solver);
159 auto const prec_species = get_precision(elements());
161 throw std::runtime_error(
162 "Cannot mix single and double precision kernels");
163 }
164 m_ek_container->set_poisson_solver(handle);
165 });
166 m_poisson_solver = new_solver;
167 }
168
169public:
171 add_parameters({
173 [this]() { return m_ek_container->get_tau(); }},
174 {"solver", [this](Variant const &v) { set_solver(v); },
175 [this]() { return get_solver(); }},
176 {"reactions", AutoParameter::read_only,
177 [this]() { return m_ek_reactions; }},
178 {"is_active", AutoParameter::read_only,
179 [this]() { return m_is_active; }},
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([tau]() {
189 if (tau <= 0.) {
190 throw std::domain_error("Parameter 'tau' must be > 0");
191 }
192 });
193 m_poisson_solver = extract_solver(
194 params.contains("solver") ? params.at("solver") : Variant{none});
195 m_ek_container = std::make_shared<::EK::EKWalberla::ek_container_type>(
196 tau, std::visit(GetPoissonSolverCoreInstance{}, m_poisson_solver));
197 m_ek_reactions = get_value<decltype(m_ek_reactions)>(params, "reactions");
198 m_ek_instance = std::make_shared<::EK::EKWalberla>(
199 m_ek_container, m_ek_reactions->get_handle());
200 // EK species must be added after tau
202 }
203
204protected:
205 Variant do_call_method(std::string const &method,
206 VariantMap const &parameters) override {
207 if (method == "activate") {
208 context()->parallel_try_catch([this]() {
210 });
211 m_is_active = true;
212 return {};
213 }
214 if (method == "deactivate") {
215 if (m_is_active) {
217 m_is_active = false;
218 }
219 return {};
220 }
221
223 }
224};
225
226} // namespace ScriptInterface::walberla
227
228#endif // ESPRESSO_WALBERLA
Owning list of object handles.
auto const & elements() const
List elements.
void do_construct(VariantMap const &params) override
Variant do_call_method(std::string const &method, VariantMap const &parameters) override
std::shared_ptr< EKSpecies > value_type
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.
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
System & get_system()
static SteepestDescentParameters params
Currently active steepest descent instance.
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