peclet.voro 1.0.0
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
simulation.hpp
Go to the documentation of this file.
1
15#ifndef PECLET_VORO_PHYSICS_SIMULATION_HPP
16#define PECLET_VORO_PHYSICS_SIMULATION_HPP
17
18#include <array>
19#include <Kokkos_Core.hpp>
20
21#include "peclet/core/common/view.hpp"
24#include "peclet/voro/reeval_tessellation.hpp" // reevalPublish (E1 repair -> force geometry)
25#include "peclet/voro/repair.hpp" // MovingTessellation (incremental update)
28
29namespace peclet::voro {
30namespace physics {
31
32template <class Real>
34 public:
35 using DView = Kokkos::View<Real*, peclet::core::MemSpace>;
36
39 void init(const DView& posFlat, const DView& vel, const DView& invMass,
40 const std::array<Real, 3>& L, Real pressEq) {
41 N_ = static_cast<int>(invMass.extent(0));
42 pos_ = posFlat;
43 vel_ = vel;
44 invMass_ = invMass;
45 L_ = L;
46 pressEq_ = pressEq;
47 w_ = DView("w", N_);
48 force_ = DView("force", 3 * N_);
49 buildAndForce();
50 }
51
53 void setViscous(const DView& visc, const DView& bulkVisc) {
54 visc_ = visc;
55 bulkVisc_ = bulkVisc;
56 viscous_ = true;
57 // Persistent viscous scratch (9*N each), allocated once here rather than every buildAndForce
58 // (E4).
59 viscGrad_ = DView(Kokkos::view_alloc("visc.grad", Kokkos::WithoutInitializing),
60 static_cast<std::size_t>(9) * N_);
61 viscStress_ = DView(Kokkos::view_alloc("visc.stress", Kokkos::WithoutInitializing),
62 static_cast<std::size_t>(9) * N_);
63 buildAndForce();
64 }
65
66 void step(int nSteps, Real dt) {
67 using Exec = peclet::core::ExecSpace;
68 const Real halfDt = Real(0.5) * dt;
69 const Real Lx = L_[0], Ly = L_[1], Lz = L_[2];
70 auto pos = pos_;
71 auto vel = vel_;
72 auto im = invMass_;
73 auto force = force_;
74 for (int s = 0; s < nSteps; ++s) {
75 Kokkos::parallel_for(
76 "ee.kick1", Kokkos::RangePolicy<Exec>(0, N_), KOKKOS_LAMBDA(const int i) {
77 for (int k = 0; k < 3; ++k)
78 vel(3 * i + k) += force(3 * i + k) * im(i) * halfDt;
79 });
80 Kokkos::parallel_for(
81 "ee.drift", Kokkos::RangePolicy<Exec>(0, N_), KOKKOS_LAMBDA(const int i) {
82 Real x = pos(3 * i + 0) + vel(3 * i + 0) * dt;
83 Real y = pos(3 * i + 1) + vel(3 * i + 1) * dt;
84 Real z = pos(3 * i + 2) + vel(3 * i + 2) * dt;
85 pos(3 * i + 0) = x - Lx * Kokkos::floor(x / Lx);
86 pos(3 * i + 1) = y - Ly * Kokkos::floor(y / Ly);
87 pos(3 * i + 2) = z - Lz * Kokkos::floor(z / Lz);
88 });
89 buildAndForce();
90 force = force_;
91 Kokkos::parallel_for(
92 "ee.kick2", Kokkos::RangePolicy<Exec>(0, N_), KOKKOS_LAMBDA(const int i) {
93 for (int k = 0; k < 3; ++k)
94 vel(3 * i + k) += force(3 * i + k) * im(i) * halfDt;
95 });
96 time_ += dt;
97 }
98 Kokkos::fence();
99 }
100
101 Real kineticEnergy(const DView& mass) const {
102 using Exec = peclet::core::ExecSpace;
103 auto vel = vel_;
104 Real e = 0;
105 Kokkos::parallel_reduce(
106 "ee.ke", Kokkos::RangePolicy<Exec>(0, N_),
107 KOKKOS_LAMBDA(const int i, Real& acc) {
108 acc += mass(i) * (vel(3 * i + 0) * vel(3 * i + 0) + vel(3 * i + 1) * vel(3 * i + 1) +
109 vel(3 * i + 2) * vel(3 * i + 2));
110 },
111 e);
112 return Real(0.5) * e;
113 }
114
115 Real internalEnergy() const {
116 using Exec = peclet::core::ExecSpace;
117 auto vol = view_.cellVolume;
118 const Real pe = pressEq_, va = volAvg_;
119 Real e = 0;
120 Kokkos::parallel_reduce(
121 "ee.ie", Kokkos::RangePolicy<Exec>(0, N_),
122 KOKKOS_LAMBDA(const int i, Real& acc) { acc -= pe * va * Kokkos::log(vol(i) / va); }, e);
123 return e;
124 }
125
126 const DView& positions() const { return pos_; }
127 const DView& velocities() const { return vel_; }
128 const DView& force() const { return force_; }
129 const TessellationView<Real>& view() const { return view_; }
130 int numParticles() const { return N_; }
131 Real time() const { return time_; }
132
133 public:
138 void setRepair(bool on) { useRepair_ = on; }
139 bool repair() const { return useRepair_; }
140
141 private:
142 void buildAndForce() {
143 const Real Larr[3] = {L_[0], L_[1], L_[2]};
144 if (useRepair_) {
145 // Incremental path: cold-build the resident tessellation once (establishes the topology store
146 // + volumes), then repair it in place each subsequent step. Either way the force geometry is
147 // re-evaluated from the store and published into the same facet-CSR view the full build
148 // emits.
149 if (!mtInit_) {
150 const double boxVol = static_cast<double>(L_[0]) * L_[1] * L_[2];
151 const Real spacing = static_cast<Real>(std::cbrt(boxVol / (N_ > 0 ? N_ : 1)));
152 mt_.alloc(N_, Larr, Real(1e-4) * spacing, Real(0.25) * spacing, /*sw=*/4, /*density=*/N_);
153 mt_.rebuild(pos_);
154 mtInit_ = true;
155 } else {
156 mt_.step(pos_);
157 }
158 view_ = peclet::voro::reevalPublish<Real, 64, 112>(mt_.store, pos_, mt_.vol, N_, Larr);
159 } else {
160 // Pass the persistent worklist cache (last arg) so the step-invariant worklist table is built
161 // once and reused across steps (E3). All intermediate args are the buildTessellation
162 // defaults; the Sdf template arg is named explicitly because a defaulted `{}` Sdf cannot be
163 // deduced.
164 auto res = peclet::voro::buildTessellation<Real, false, peclet::voro::NoSdf>(
165 pos_, w_, N_, Larr, /*sw=*/4, /*densityCount=*/-1, /*gid=*/{}, peclet::voro::NoSdf{},
166 /*withForceGeom=*/true, /*nBuild=*/-1, /*outNp=*/{}, /*outNt=*/{}, /*outPnbr=*/{},
167 /*outTri=*/{}, /*outCand=*/{}, /*outCandCnt=*/{}, /*candCap=*/0, &wlCache_);
168 view_ = res.view;
169 }
170 aux_ = peclet::voro::buildAuxMaps(view_);
171 volAvg_ = (L_[0] * L_[1] * L_[2]) / static_cast<Real>(N_);
172 Kokkos::deep_copy(force_, Real(0));
173 eulerPressureForce(view_, aux_.recip, aux_.cellOfFacet, pressEq_, volAvg_, force_);
174 if (viscous_)
175 viscousForce(view_, aux_.recip, aux_.cellOfFacet, vel_, visc_, bulkVisc_, force_, viscGrad_,
176 viscStress_);
177 }
178
179 int N_ = 0;
180 std::array<Real, 3> L_{};
181 Real pressEq_ = 0, volAvg_ = 0, time_ = 0;
182 bool viscous_ = false;
183 DView pos_, vel_, invMass_, w_, force_, visc_, bulkVisc_;
184 DView viscGrad_, viscStress_; // persistent 9*N viscous scratch (E4)
186 wlCache_; // step-invariant worklist table, reused across steps (E3)
187 TessellationView<Real> view_;
189 // E1 opt-in incremental path (default off): resident moving-point tessellation + its cold/repair
190 // state. Kept as members (Views free before Kokkos::finalize).
191 bool useRepair_ = false, mtInit_ = false;
193};
194
195} // namespace physics
196} // namespace peclet::voro
197
198#endif // PECLET_VORO_PHYSICS_SIMULATION_HPP
Definition simulation.hpp:33
int numParticles() const
Definition simulation.hpp:130
void setViscous(const DView &visc, const DView &bulkVisc)
Enable the viscous term (NavierStokes); per-particle viscosities (size N).
Definition simulation.hpp:53
const DView & force() const
Definition simulation.hpp:128
void init(const DView &posFlat, const DView &vel, const DView &invMass, const std::array< Real, 3 > &L, Real pressEq)
Definition simulation.hpp:39
Kokkos::View< Real *, peclet::core::MemSpace > DView
Definition simulation.hpp:35
void setRepair(bool on)
Definition simulation.hpp:138
bool repair() const
Definition simulation.hpp:139
Real internalEnergy() const
Definition simulation.hpp:115
Real time() const
Definition simulation.hpp:131
const DView & velocities() const
Definition simulation.hpp:127
Real kineticEnergy(const DView &mass) const
Definition simulation.hpp:101
void step(int nSteps, Real dt)
Definition simulation.hpp:66
const DView & positions() const
Definition simulation.hpp:126
const TessellationView< Real > & view() const
Definition simulation.hpp:129
Reference physics consumer: compressible-Euler pressure force (Phase 4).
void viscousForce(const TessellationView< Real > &view, const Kokkos::View< int *, peclet::core::MemSpace > &recip, const Kokkos::View< int *, peclet::core::MemSpace > &cellOfFacet, const Kokkos::View< Real *, peclet::core::MemSpace > &vel, const Kokkos::View< Real *, peclet::core::MemSpace > &visc, const Kokkos::View< Real *, peclet::core::MemSpace > &bulkVisc, const Kokkos::View< Real *, peclet::core::MemSpace > &force, const Kokkos::View< Real *, peclet::core::MemSpace > &grad, const Kokkos::View< Real *, peclet::core::MemSpace > &stress)
Definition viscous.hpp:119
void eulerPressureForce(const TessellationView< Real > &view, const Kokkos::View< int *, peclet::core::MemSpace > &recip, const Kokkos::View< int *, peclet::core::MemSpace > &cellOfFacet, Real pressEq, Real volAvg, const Kokkos::View< Real *, peclet::core::MemSpace > &force)
Definition euler_pressure.hpp:40
Definition convex_cell.hpp:40
AuxMaps< Real > buildAuxMaps(const TessellationView< Real > &view)
Build {recip, cellOfFacet} on device from a published view (dense single-domain).
Definition transpose.hpp:33
Definition transpose.hpp:26
Definition repair.hpp:64
Kokkos::View< Real *, Mem > vol
Definition repair.hpp:135
void rebuild(const Kokkos::View< Real *, Mem > &pos, bool eagerAdj=true)
Definition repair.hpp:198
RepairStats step(const Kokkos::View< Real *, Mem > &pos)
One moving-point update step. Updates store + vol in place from pos.
Definition repair.hpp:626
Store store
Definition repair.hpp:134
void alloc(int n, const Real Lbox[3], Real tol_, Real skin_, int sw_=4, int densityCount_=-1, int nProc_=-1)
Definition repair.hpp:153
Sentinel "no geometry" provider — the default; the clip stage is skipped.
Definition sdf.hpp:36
Definition tessellation_view.hpp:111
Definition tess_grid.hpp:82
Viscous Navier-Stokes force over the published view (de-legacy Phase 2).
Kokkos::View< real_t *, peclet::core::MemSpace > DView
Definition voro_bindings.cpp:68