From 0dc3676ff1344d593cf12df83a2cc4091689d3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20David--Cl=C3=A9ris?= Date: Thu, 27 Aug 2026 19:47:35 +0000 Subject: [PATCH 1/3] Migrate SinkParticlesUpdate predictor/corrector to ForwardEulerHost Add ForwardEulerHost, a solver-graph INode mirroring ForwardEuler but operating on plain host std::vector data instead of patch-distributed GPU field spans, matching how sink particle data (MPI-replicated, host-only) is stored. predictor_step and corrector_step now wire up and evaluate this node for the velocity half-kicks and position drift instead of hand-rolled loops, following the same node-per-operation wiring pattern already used for the gas particle leapfrog predictor. Assisted-by: Claude --- .../common/modules/ForwardEulerHost.hpp | 69 +++++++++++++++++++ .../sph/src/modules/SinkParticlesUpdate.cpp | 44 ++++++++++-- 2 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp diff --git a/src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp b/src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp new file mode 100644 index 000000000..298783850 --- /dev/null +++ b/src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp @@ -0,0 +1,69 @@ +// -------------------------------------------------------// +// +// SHAMROCK code for hydrodynamics +// Copyright (c) 2021-2026 Timothée David--Cléris +// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1 +// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information +// +// -------------------------------------------------------// + +#pragma once + +/** + * @file ForwardEulerHost.hpp + * @author Timothée David--Cléris (tim.shamrock@proton.me) + * @brief Implements a forward Euler integration step as a solver graph node, operating on + * host-side std::vector data (e.g. MPI-replicated sink particles) rather than patch-distributed + * GPU field spans. + * + */ + +#include "shambackends/vec.hpp" +#include "shambase/SourceLocation.hpp" +#include "shambase/stacktrace.hpp" +#include "shamsolvergraph/edge/IDataEdge.hpp" +#include "shamsolvergraph/node/INode.hpp" +#include + +#define NODE_EDGES(X_RO, X_RW) \ + /* ------------------- inputs ------------------- */ \ + X_RO(shamrock::solvergraph::IDataEdge, dt) \ + X_RO(shamrock::solvergraph::IDataEdge>, time_derivative) \ + \ + /* ------------------- outputs ------------------- */ \ + X_RW(shamrock::solvergraph::IDataEdge>, field) + +namespace shammodels::common::modules { + template + class ForwardEulerHost : public shamrock::solvergraph::INode { + + using Tscal = shambase::VecComponent; + + public: + ForwardEulerHost() = default; + + EXPAND_NODE_EDGES(NODE_EDGES) + + inline void _impl_evaluate_internal() { + + __shamrock_stack_entry(); + + auto edges = get_edges(); + + Tscal dt = edges.dt.data; + + auto &field = edges.field.data; + const std::vector &deriv = edges.time_derivative.data; + + for (size_t i = 0; i < field.size(); i++) { + field[i] = field[i] + dt * deriv[i]; + } + } + + inline virtual std::string _impl_get_label() const { return "ForwardEulerHost"; } + + inline virtual std::string _impl_get_tex() const { return "TODO"; } + }; +} // namespace shammodels::common::modules + +#undef NODE_EDGES diff --git a/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp b/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp index 745299854..109be19be 100644 --- a/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp +++ b/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp @@ -15,6 +15,7 @@ * */ +#include "shammodels/common/modules/ForwardEulerHost.hpp" #include "shammodels/sph/modules/SinkParticlesUpdate.hpp" #include "shammath/sphkernels.hpp" #include "shammodels/sph/sink_edges_helper.hpp" @@ -37,13 +38,31 @@ void shammodels::sph::modules::SinkParticlesUpdate::predictor_s compute_ext_forces(); + std::vector acc(pos.size()); for (size_t i = 0; i < pos.size(); i++) { - vel[i] += (dt / 2) * (acc_sph[i] + acc_ext[i]); + acc[i] = acc_sph[i] + acc_ext[i]; } - for (size_t i = 0; i < pos.size(); i++) { - pos[i] += dt * vel[i]; - } + using namespace shamrock::solvergraph; + using FEHost = shammodels::common::modules::ForwardEulerHost; + + auto pos_edge = sync.get_edge_ptr>>("sink_pos"); + auto vel_edge = sync.get_edge_ptr>>("sink_vel"); + + auto acc_edge = IDataEdge>::make_shared("sink_acc_predictor", "a"); + acc_edge->data = std::move(acc); + auto dt_half_edge = IDataEdge::make_shared("dt_half", "dt/2"); + dt_half_edge->data = dt / 2; + auto dt_edge = IDataEdge::make_shared("dt", "dt"); + dt_edge->data = dt; + + FEHost half_kick{}; + half_kick.set_edges(dt_half_edge, acc_edge, vel_edge); + half_kick.evaluate(); + + FEHost drift{}; + drift.set_edges(dt_edge, vel_edge, pos_edge); + drift.evaluate(); } template class SPHKernel> @@ -60,9 +79,24 @@ void shammodels::sph::modules::SinkParticlesUpdate::corrector_s auto &acc_sph = get_sink_acc_sph(sync); auto &acc_ext = get_sink_acc_ext(sync); + std::vector acc(vel.size()); for (size_t i = 0; i < vel.size(); i++) { - vel[i] += (dt / 2) * (acc_sph[i] + acc_ext[i]); + acc[i] = acc_sph[i] + acc_ext[i]; } + + using namespace shamrock::solvergraph; + using FEHost = shammodels::common::modules::ForwardEulerHost; + + auto vel_edge = sync.get_edge_ptr>>("sink_vel"); + + auto acc_edge = IDataEdge>::make_shared("sink_acc_corrector", "a"); + acc_edge->data = std::move(acc); + auto dt_half_edge = IDataEdge::make_shared("dt_half", "dt/2"); + dt_half_edge->data = dt / 2; + + FEHost half_kick{}; + half_kick.set_edges(dt_half_edge, acc_edge, vel_edge); + half_kick.evaluate(); } template class SPHKernel> From ce1a3bbb981c5d9470e0813d255f6e1830f94904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20David--Cl=C3=A9ris?= Date: Thu, 27 Aug 2026 20:11:22 +0000 Subject: [PATCH 2/3] Fix dependent-name lookup for sync.get_edge_ptr in SinkParticlesUpdate sync's type is a dependent name inside SinkParticlesUpdate, so calling its get_edge_ptr member template requires the 'template' disambiguator, same as sink_edges_helper.hpp's existing sync.template get_edge_ref<...> usage. Assisted-by: Claude --- src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp b/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp index 109be19be..65faeba12 100644 --- a/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp +++ b/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp @@ -46,8 +46,10 @@ void shammodels::sph::modules::SinkParticlesUpdate::predictor_s using namespace shamrock::solvergraph; using FEHost = shammodels::common::modules::ForwardEulerHost; - auto pos_edge = sync.get_edge_ptr>>("sink_pos"); - auto vel_edge = sync.get_edge_ptr>>("sink_vel"); + auto pos_edge = sync.template get_edge_ptr>>( + "sink_pos"); + auto vel_edge = sync.template get_edge_ptr>>( + "sink_vel"); auto acc_edge = IDataEdge>::make_shared("sink_acc_predictor", "a"); acc_edge->data = std::move(acc); @@ -87,7 +89,8 @@ void shammodels::sph::modules::SinkParticlesUpdate::corrector_s using namespace shamrock::solvergraph; using FEHost = shammodels::common::modules::ForwardEulerHost; - auto vel_edge = sync.get_edge_ptr>>("sink_vel"); + auto vel_edge = sync.template get_edge_ptr>>( + "sink_vel"); auto acc_edge = IDataEdge>::make_shared("sink_acc_corrector", "a"); acc_edge->data = std::move(acc); From ebcb0f15ffcddbe33e71495da49d19988107a84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20David--Cl=C3=A9ris?= Date: Thu, 27 Aug 2026 20:18:05 +0000 Subject: [PATCH 3/3] Apply clang-format Auto-formats include ordering and line wrapping per .clang-format. Assisted-by: Claude --- .../shammodels/common/modules/ForwardEulerHost.hpp | 6 +++--- .../sph/src/modules/SinkParticlesUpdate.cpp | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp b/src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp index 298783850..ddcd7efc6 100644 --- a/src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp +++ b/src/shammodels/common/include/shammodels/common/modules/ForwardEulerHost.hpp @@ -18,15 +18,15 @@ * */ -#include "shambackends/vec.hpp" #include "shambase/SourceLocation.hpp" #include "shambase/stacktrace.hpp" +#include "shambackends/vec.hpp" #include "shamsolvergraph/edge/IDataEdge.hpp" #include "shamsolvergraph/node/INode.hpp" #include -#define NODE_EDGES(X_RO, X_RW) \ - /* ------------------- inputs ------------------- */ \ +#define NODE_EDGES(X_RO, X_RW) \ + /* ------------------- inputs ------------------- */ \ X_RO(shamrock::solvergraph::IDataEdge, dt) \ X_RO(shamrock::solvergraph::IDataEdge>, time_derivative) \ \ diff --git a/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp b/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp index 65faeba12..b48c31b82 100644 --- a/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp +++ b/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp @@ -15,9 +15,9 @@ * */ -#include "shammodels/common/modules/ForwardEulerHost.hpp" #include "shammodels/sph/modules/SinkParticlesUpdate.hpp" #include "shammath/sphkernels.hpp" +#include "shammodels/common/modules/ForwardEulerHost.hpp" #include "shammodels/sph/sink_edges_helper.hpp" #include @@ -46,10 +46,10 @@ void shammodels::sph::modules::SinkParticlesUpdate::predictor_s using namespace shamrock::solvergraph; using FEHost = shammodels::common::modules::ForwardEulerHost; - auto pos_edge = sync.template get_edge_ptr>>( - "sink_pos"); - auto vel_edge = sync.template get_edge_ptr>>( - "sink_vel"); + auto pos_edge + = sync.template get_edge_ptr>>("sink_pos"); + auto vel_edge + = sync.template get_edge_ptr>>("sink_vel"); auto acc_edge = IDataEdge>::make_shared("sink_acc_predictor", "a"); acc_edge->data = std::move(acc); @@ -89,8 +89,8 @@ void shammodels::sph::modules::SinkParticlesUpdate::corrector_s using namespace shamrock::solvergraph; using FEHost = shammodels::common::modules::ForwardEulerHost; - auto vel_edge = sync.template get_edge_ptr>>( - "sink_vel"); + auto vel_edge + = sync.template get_edge_ptr>>("sink_vel"); auto acc_edge = IDataEdge>::make_shared("sink_acc_corrector", "a"); acc_edge->data = std::move(acc);