ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
script_interface/walberla/VTKHandle.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021-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
28
31
32#include <boost/algorithm/string/join.hpp>
33
34#include <algorithm>
35#include <filesystem>
36#include <memory>
37#include <sstream>
38#include <stdexcept>
39#include <string>
40#include <unordered_map>
41#include <vector>
42
44
45template <class Field>
46class VTKHandleBase : public AutoParameters<VTKHandleBase<Field>> {
47private:
48 int m_delta_N;
49 int m_obs_flag;
50 bool m_force_pvtu;
51 bool m_include_boundaries;
52 std::string m_identifier;
53 std::filesystem::path m_base_folder;
54 std::string m_prefix;
55 std::shared_ptr<::VTKHandle> m_vtk_handle;
56 std::weak_ptr<Field> m_field;
58 std::vector<Variant> m_pending_arguments;
59
60 [[nodiscard]] auto get_vtk_uid() const {
61 return m_base_folder.generic_string() + "/" + m_identifier;
62 }
63
64 [[nodiscard]] std::shared_ptr<Field> get_field_instance() const {
65 if (auto const field = m_field.lock()) {
66 return field;
67 }
68 auto const has_lattice_expired = m_pending_arguments.empty();
69 auto const err_expired = "Attempted access to an expired lattice object";
70 auto const err_detached = "This VTK object isn't attached to a lattice";
71 throw std::runtime_error(has_lattice_expired ? err_expired : err_detached);
72 }
73
74 virtual std::unordered_map<std::string, int> const &get_obs_map() const = 0;
75
76 [[nodiscard]] auto get_valid_observable_names() const {
77 auto const view = std::views::elements<0>(get_obs_map());
78 std::vector<std::string> names{view.begin(), view.end()};
79 std::ranges::sort(names);
80 return names;
81 }
82
83 [[nodiscard]] int
84 deserialize_obs_flag(std::vector<std::string> const &names) const {
85 int obs_flag{0};
86 auto const &obs_map = get_obs_map();
87 for (auto const &name : names) {
88 if (not obs_map.contains(name)) {
89 auto const valid_names = get_valid_observable_names();
90 std::stringstream message;
91 message << "Only the following VTK observables are supported: ['"
92 << boost::algorithm::join(valid_names, "', '") << "'], got '"
93 << name << "'";
94 throw std::invalid_argument(message.str());
95 }
96 obs_flag |= obs_map.at(name);
97 }
98 return obs_flag;
99 }
100
101 [[nodiscard]] Variant serialize_obs_flag(int obs_flag) const {
102 std::vector<Variant> observables{};
103 for (auto const &[name, flag] : get_obs_map()) {
104 if (flag & obs_flag) {
105 observables.emplace_back(name);
106 }
107 }
108 return observables;
109 }
110
111public:
113 constexpr auto read_only = AutoParameter::read_only;
115 {"enabled", read_only, [this]() { return m_vtk_handle->enabled; }},
116 {"delta_N", read_only, [this]() { return m_delta_N; }},
117 {"vtk_uid", read_only, [this]() { return get_vtk_uid(); }},
118 {"identifier", read_only, [this]() { return m_identifier; }},
119 {"base_folder", read_only, [this]() { return m_base_folder; }},
120 {"prefix", read_only, [this]() { return m_prefix; }},
121 {"force_pvtu", read_only, [this]() { return m_force_pvtu; }},
122 {"include_boundaries", read_only,
123 [this]() { return m_include_boundaries; }},
124 {"observables", read_only,
125 [this]() { return serialize_obs_flag(m_obs_flag); }},
126 {"execution_count", read_only,
127 [this]() { return m_vtk_handle->execution_count; }},
128 {"units", read_only,
129 [this]() { return make_unordered_map_of_variants(m_units); }},
130 });
131 }
132
133private:
134 void do_construct(VariantMap const &params) override {
135 m_delta_N = get_value<int>(params, "delta_N");
136 m_identifier = get_value<std::string>(params, "identifier");
137 m_base_folder = get_value<std::filesystem::path>(params, "base_folder");
138 m_prefix = get_value<std::string>(params, "prefix");
139 m_force_pvtu = get_value_or<bool>(params, "force_pvtu", false);
140 m_include_boundaries =
141 get_value_or<bool>(params, "include_boundaries", false);
142 auto const is_enabled = get_value<bool>(params, "enabled");
143 auto const execution_count = get_value<int>(params, "execution_count");
145 m_obs_flag = deserialize_obs_flag(
146 get_value<std::vector<std::string>>(params, "observables"));
147 if (m_delta_N < 0) {
148 throw std::domain_error("Parameter 'delta_N' must be >= 0");
149 }
150 if (m_identifier.empty()) {
151 throw std::domain_error("Parameter 'identifier' cannot be empty");
152 }
153 if (m_identifier.find(std::filesystem::path::preferred_separator) !=
154 std::string::npos) {
155 throw std::invalid_argument(
156 "Parameter 'identifier' cannot be a filepath");
157 }
158 });
159 m_pending_arguments.emplace_back(is_enabled);
160 m_pending_arguments.emplace_back(execution_count);
161 }
162
163protected:
164 Variant do_call_method(std::string const &name, VariantMap const &) override {
165 if (name == "enable") {
167 if (m_delta_N == 0) {
168 throw std::runtime_error("Manual VTK callbacks cannot be enabled");
169 }
170 get_field_instance()->switch_vtk(get_vtk_uid(), true);
171 });
172 return {};
173 }
174 if (name == "disable") {
176 if (m_delta_N == 0) {
177 throw std::runtime_error("Manual VTK callbacks cannot be disabled");
178 }
179 get_field_instance()->switch_vtk(get_vtk_uid(), false);
180 });
181 return {};
182 }
183 if (name == "write") {
185 if (m_delta_N) {
186 throw std::runtime_error("Automatic VTK callbacks cannot be "
187 "triggered manually");
188 }
189 get_field_instance()->write_vtk(get_vtk_uid());
190 });
191 return {};
192 }
193 if (name == "get_valid_observable_names") {
194 return make_vector_of_variants(get_valid_observable_names());
195 }
196
197 return {};
198 }
199
200public:
201 void detach_from_lattice() { m_field.reset(); }
202
203 void attach_to_lattice(std::weak_ptr<Field> field,
205 auto const was_attached_once = m_pending_arguments.empty();
206 if (not m_field.expired()) {
207 throw std::runtime_error("Cannot attach VTK object to multiple lattices");
208 }
209 if (was_attached_once) {
210 throw std::runtime_error("Detached VTK objects cannot be attached again");
211 }
212 assert(m_pending_arguments.size() == 2u);
213 auto const is_enabled = get_value<bool>(m_pending_arguments[0]);
214 auto const execution_count = get_value<int>(m_pending_arguments[1]);
215 auto const base_folder = m_base_folder.generic_string();
216 m_units = units;
217 m_field = field;
218 auto instance = get_field_instance();
219 m_vtk_handle = instance->create_vtk(
220 m_delta_N, execution_count, m_obs_flag, m_units, m_identifier,
221 base_folder, m_prefix, m_force_pvtu, m_include_boundaries);
222 if (m_delta_N and not is_enabled) {
223 instance->switch_vtk(get_vtk_uid(), false);
224 }
225 m_pending_arguments.clear();
226 }
227};
228
229} // namespace ScriptInterface::walberla
230
231#endif // ESPRESSO_WALBERLA
std::unordered_map< std::string, double > units_map
Bind parameters in the script interface.
void add_parameters(std::vector< AutoParameter > &&params)
virtual void parallel_try_catch(std::function< void()> const &cb) const =0
Context * context() const
Responsible context.
std::string_view name() const
Variant do_call_method(std::string const &name, VariantMap const &) override
void attach_to_lattice(std::weak_ptr< Field > field, ::LatticeModel::units_map const &units)
virtual std::unordered_map< std::string, int > const & get_obs_map() const =0
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
auto make_unordered_map_of_variants(std::unordered_map< K, V > const &v)
Definition Variant.hpp:144
auto make_vector_of_variants(std::vector< T > const &v)
Definition Variant.hpp:148
make_recursive_variant< ObjectRef > Variant
Possible types for parameters.
Definition Variant.hpp:131
static constexpr const ReadOnly read_only
Recursive variant implementation.
Definition Variant.hpp:84