Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
SolverGraph.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
18
20#include "shambase/memory.hpp"
23#include <unordered_map>
24#include <algorithm>
25#include <functional>
26#include <memory>
27#include <optional>
28#include <stdexcept>
29#include <string>
30#include <utility>
31#include <vector>
32
33namespace shamrock::solvergraph {
34
35 using SolverGraphNodeCheck = std::function<bool(const std::shared_ptr<INode> &node)>;
36 using SolverGraphEdgeCheck = std::function<bool(const std::shared_ptr<IEdge> &edge)>;
37
39 std::string name;
40 SolverGraphNodeCheck node_check;
41 SolverGraphEdgeCheck edge_check;
42
43 inline static SolverGraphConstraint no_constraint() {
44 return {.name = {}, .node_check = nullptr, .edge_check = nullptr};
45 }
46
47 inline bool check_node(const std::shared_ptr<INode> &node) const {
48 if (!bool(node)) {
50 "node == nullptr is not allowed, please pass a shared pointer with a valid "
51 "node"));
52 }
53 if (!node_check) {
54 return true;
55 }
56 return (node_check) (node);
57 }
58
59 inline bool check_edge(const std::shared_ptr<IEdge> &edge) const {
60 if (!bool(edge)) {
62 "edge == nullptr is not allowed, please pass a shared pointer with a valid "
63 "edge"));
64 }
65 if (!edge_check) {
66 return true;
67 }
68 return (edge_check) (edge);
69 }
70
71 inline bool is_active() const { return bool(node_check) || bool(edge_check); }
72 };
73
110 class SolverGraph {
112 std::unordered_map<std::string, std::shared_ptr<INode>> nodes = {};
113
115 std::unordered_map<std::string, std::shared_ptr<IEdge>> edges = {};
116
117 SolverGraphConstraint constraint = SolverGraphConstraint::no_constraint();
118
119 protected:
120 explicit SolverGraph(SolverGraphConstraint graph_constraint)
121 : constraint(std::move(graph_constraint)) {}
122
123 public:
125 // base getters and setters
127
128 SolverGraph() = default;
129
135 inline static SolverGraph with_constraint(SolverGraphConstraint graph_constraint) {
136 return SolverGraph{std::move(graph_constraint)};
137 }
138
147 inline std::shared_ptr<INode> register_node_ptr_base(
148 const std::string &name, std::shared_ptr<INode> node) {
149
150 if (!constraint.check_node(node)) {
152 "Solvergraph constraint '{}' rejected node '{}' (label='{}', uuid={})",
153 constraint.name,
154 name,
155 node->get_label(),
156 node->get_uuid()));
157 }
158
159 const auto [it, inserted] = nodes.try_emplace(name, std::move(node));
160 if (!inserted) {
162 shambase::format("Node already exists: {}", name));
163 }
164 return it->second;
165 }
166
175 inline std::shared_ptr<IEdge> register_edge_ptr_base(
176 const std::string &name, std::shared_ptr<IEdge> edge) {
177
178 if (!constraint.check_edge(edge)) {
180 "Solvergraph constraint '{}' rejected edge '{}' (label='{}', uuid={})",
181 constraint.name,
182 name,
183 edge->get_label(),
184 edge->get_uuid()));
185 }
186
187 const auto [it, inserted] = edges.try_emplace(name, std::move(edge));
188 if (!inserted) {
190 shambase::format("Edge already exists: {}", name));
191 }
192 return it->second;
193 }
194
202 inline std::shared_ptr<INode> &get_node_ptr_base(const std::string &name) {
203 auto it = nodes.find(name);
204 if (it == nodes.end()) {
206 shambase::format("Node does not exist: {}", name));
207 }
208 return it->second;
209 }
210
212 inline const std::shared_ptr<INode> &get_node_ptr_base(const std::string &name) const {
213 auto it = nodes.find(name);
214 if (it == nodes.end()) {
216 shambase::format("Node does not exist: {}", name));
217 }
218 return it->second;
219 }
220
228 inline std::shared_ptr<IEdge> &get_edge_ptr_base(const std::string &name) {
229 auto it = edges.find(name);
230 if (it == edges.end()) {
232 shambase::format("Edge does not exist: {}", name));
233 }
234 return it->second;
235 }
236
238 inline const std::shared_ptr<IEdge> &get_edge_ptr_base(const std::string &name) const {
239 auto it = edges.find(name);
240 if (it == edges.end()) {
242 shambase::format("Edge does not exist: {}", name));
243 }
244 return it->second;
245 }
246
253 inline bool has_node(const std::string &name) const {
254 return nodes.find(name) != nodes.end();
255 }
256
263 inline bool has_edge(const std::string &name) const {
264 return edges.find(name) != edges.end();
265 }
266
268 // generic getters
270
278 inline INode &get_node_ref_base(const std::string &name) {
280 }
281
283 inline const INode &get_node_ref_base(const std::string &name) const {
285 }
286
294 inline IEdge &get_edge_ref_base(const std::string &name) {
296 }
297
299 inline const IEdge &get_edge_ref_base(const std::string &name) const {
301 }
302
304 // templated register and getters
306
320 template<class T>
321 inline std::shared_ptr<T> register_node(const std::string &name, T &&node) {
322 static_assert(std::is_base_of<INode, T>::value, "T must derive from INode");
323 register_node_ptr_base(name, std::make_shared<T>(std::forward<T>(node)));
324 return get_node_ptr<T>(name);
325 }
326
340 template<class T>
341 inline std::shared_ptr<T> register_edge(const std::string &name, T &&edge) {
342 static_assert(std::is_base_of<IEdge, T>::value, "T must derive from IEdge");
343 register_edge_ptr_base(name, std::make_shared<T>(std::forward<T>(edge)));
344 return get_edge_ptr<T>(name);
345 }
346
358 template<class T>
359 inline std::shared_ptr<T> get_node_ptr(const std::string &name) {
360 auto tmp = std::dynamic_pointer_cast<T>(get_node_ptr_base(name));
361 if (!bool(tmp)) {
363 shambase::format("Node exists but is not from the requested type: {}", name));
364 }
365 return tmp;
366 }
367
369 template<class T>
370 inline std::shared_ptr<T> get_node_ptr(const std::string &name) const {
371 auto tmp = std::dynamic_pointer_cast<T>(get_node_ptr_base(name));
372 if (!bool(tmp)) {
374 shambase::format("Node exists but is not from the requested type: {}", name));
375 }
376 return tmp;
377 }
378
390 template<class T>
391 inline std::shared_ptr<T> get_edge_ptr(const std::string &name) {
392 auto tmp = std::dynamic_pointer_cast<T>(get_edge_ptr_base(name));
393 if (!bool(tmp)) {
395 shambase::format("Edge exists but is not from the requested type: {}", name));
396 }
397 return tmp;
398 }
399
401 template<class T>
402 inline std::shared_ptr<T> get_edge_ptr(const std::string &name) const {
403 auto tmp = std::dynamic_pointer_cast<T>(get_edge_ptr_base(name));
404 if (!bool(tmp)) {
406 shambase::format("Edge exists but is not from the requested type: {}", name));
407 }
408 return tmp;
409 }
410
422 template<class T>
423 inline T &get_node_ref(const std::string &name) {
425 }
426
428 template<class T>
429 inline const T &get_node_ref(const std::string &name) const {
431 }
432
444 template<class T>
445 inline T &get_edge_ref(const std::string &name) {
447 }
448
450 template<class T>
451 inline const T &get_edge_ref(const std::string &name) const {
453 }
454
456 inline std::vector<std::string> get_edge_names() const {
457 std::vector<std::string> ret{};
458 ret.reserve(edges.size());
459
460 for (const auto &entry : edges) {
461 ret.push_back(entry.first);
462 }
463 std::sort(ret.begin(), ret.end());
464 return ret;
465 }
466
468 inline std::vector<std::string> get_node_names() const {
469 std::vector<std::string> ret{};
470 ret.reserve(nodes.size());
471
472 for (const auto &entry : nodes) {
473 ret.push_back(entry.first);
474 }
475 std::sort(ret.begin(), ret.end());
476 return ret;
477 }
478 };
479
480} // namespace shamrock::solvergraph
Inode is node between data edges, takes multiple inputs, multiple outputs.
Definition INode.hpp:31
std::shared_ptr< INode > & get_node_ptr_base(const std::string &name)
Retrieve a node by name as a shared pointer to the base interface.
std::vector< std::string > get_edge_names() const
Returns edge registration keys in lexicographic order (deterministic).
T & get_edge_ref(const std::string &name)
Get a typed reference to an edge by name.
const std::shared_ptr< INode > & get_node_ptr_base(const std::string &name) const
const variant
std::shared_ptr< T > get_edge_ptr(const std::string &name)
Get a typed shared pointer to an edge by name.
IEdge & get_edge_ref_base(const std::string &name)
Get a reference to an edge by name through the base interface.
bool has_edge(const std::string &name) const
Check whether an edge with the given name exists.
std::shared_ptr< T > get_edge_ptr(const std::string &name) const
const variant
std::shared_ptr< T > register_edge(const std::string &name, T &&edge)
Register an edge with automatic type deduction and shared pointer creation.
const std::shared_ptr< IEdge > & get_edge_ptr_base(const std::string &name) const
const variant
bool has_node(const std::string &name) const
Check whether a node with the given name exists.
std::shared_ptr< T > get_node_ptr(const std::string &name)
Get a typed shared pointer to a node by name.
std::shared_ptr< INode > register_node_ptr_base(const std::string &name, std::shared_ptr< INode > node)
Register a node with the graph using a shared pointer.
const T & get_edge_ref(const std::string &name) const
const variant
std::shared_ptr< T > get_node_ptr(const std::string &name) const
const variant
const INode & get_node_ref_base(const std::string &name) const
const variant
std::shared_ptr< IEdge > & get_edge_ptr_base(const std::string &name)
Retrieve an edge by name as a shared pointer to the base interface.
std::shared_ptr< T > register_node(const std::string &name, T &&node)
Register a node with automatic type deduction and shared pointer creation.
const IEdge & get_edge_ref_base(const std::string &name) const
const variant
std::vector< std::string > get_node_names() const
Returns node registration keys in lexicographic order (deterministic).
INode & get_node_ref_base(const std::string &name)
Get a reference to a node by name through the base interface.
const T & get_node_ref(const std::string &name) const
const variant
T & get_node_ref(const std::string &name)
Get a typed reference to a node by name.
std::shared_ptr< IEdge > register_edge_ptr_base(const std::string &name, std::shared_ptr< IEdge > edge)
Register an edge with the graph using a shared pointer.
static SolverGraph with_constraint(SolverGraphConstraint graph_constraint)
Create a solver graph with registration constraints.
This header file contains utility functions related to exception handling in the code.
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
Definition memory.hpp:110
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.