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..ddcd7efc6 --- /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 "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 ------------------- */ \ + 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..b48c31b82 100644 --- a/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp +++ b/src/shammodels/sph/src/modules/SinkParticlesUpdate.cpp @@ -17,6 +17,7 @@ #include "shammodels/sph/modules/SinkParticlesUpdate.hpp" #include "shammath/sphkernels.hpp" +#include "shammodels/common/modules/ForwardEulerHost.hpp" #include "shammodels/sph/sink_edges_helper.hpp" #include @@ -37,13 +38,33 @@ 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.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); + 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 +81,25 @@ 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.template 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>