peclet.voro 1.0.0
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
dynamic_validate.hpp
Go to the documentation of this file.
1
30#ifndef PECLET_VORO_DYNAMIC_VALIDATE_HPP
31#define PECLET_VORO_DYNAMIC_VALIDATE_HPP
32
33#include <cmath>
34#include <Kokkos_Core.hpp>
35
36#include "peclet/core/common/view.hpp"
38#include "peclet/voro/transpose.hpp" // AuxMaps, buildAuxMaps
39
40namespace peclet::voro {
41
43struct Invariants {
44 double volRelErr = 0;
45 double maxAreaAsym = 0;
46 double sumAreaMag = 0;
47 double sumForceMag = 0;
48 long nNonRecip = 0;
49};
50
53template <class Real>
55 double boxVolume) {
56 using Exec = peclet::core::ExecSpace;
57 const int N = view.numCells();
58 const int nF = view.numFacets();
59 Invariants inv;
60
61 // Σ cellVolume.
62 double sumV = 0;
63 Kokkos::parallel_reduce(
64 "inv.sumVol", Kokkos::RangePolicy<Exec>(0, N),
65 KOKKOS_LAMBDA(const int i, double& a) { a += (double)view.volume(i); }, sumV);
66 inv.volRelErr = boxVolume > 0 ? std::abs(sumV - boxVolume) / boxVolume : std::abs(sumV);
67
68 // Reciprocal area antisymmetry + global area/force sums + non-reciprocal interior facet count.
69 auto recip = aux.recip;
70 double maxAsym = 0;
71 Kokkos::parallel_reduce(
72 "inv.areaAsym", Kokkos::RangePolicy<Exec>(0, nF),
73 KOKKOS_LAMBDA(const int g, double& m) {
74 const int h = recip(g);
75 if (h < 0)
76 return;
77 double e = 0, a2 = 0;
78 for (int c = 0; c < 3; ++c) {
79 const double ag = view.area(g, c), ah = view.area(h, c);
80 const double s = ag + ah;
81 e += s * s;
82 a2 += ag * ag;
83 }
84 const double rel = a2 > 0 ? std::sqrt(e / a2) : std::sqrt(e);
85 if (rel > m)
86 m = rel;
87 },
88 Kokkos::Max<double>(maxAsym));
89 inv.maxAreaAsym = maxAsym;
90
91 double sax = 0, say = 0, saz = 0, sfx = 0, sfy = 0, sfz = 0;
92 Kokkos::parallel_reduce(
93 "inv.sumArea", Kokkos::RangePolicy<Exec>(0, nF),
94 KOKKOS_LAMBDA(const int g, double& ax, double& ay, double& az, double& fx, double& fy,
95 double& fz) {
96 ax += (double)view.area(g, 0);
97 ay += (double)view.area(g, 1);
98 az += (double)view.area(g, 2);
99 fx += (double)view.connect(g, 0);
100 fy += (double)view.connect(g, 1);
101 fz += (double)view.connect(g, 2);
102 },
103 sax, say, saz, sfx, sfy, sfz);
104 inv.sumAreaMag = std::sqrt(sax * sax + say * say + saz * saz);
105 inv.sumForceMag = std::sqrt(sfx * sfx + sfy * sfy + sfz * sfz);
106
107 long nonRecip = 0;
108 Kokkos::parallel_reduce(
109 "inv.nonRecip", Kokkos::RangePolicy<Exec>(0, N),
110 KOKKOS_LAMBDA(const int i, long& a) {
111 for (int g = view.facetBegin(i); g < view.facetEnd(i); ++g) {
112 const int j = (int)view.facetNbr(g);
113 if (j >= 0 && j < N && recip(g) < 0)
114 ++a;
115 }
116 },
117 nonRecip);
118 inv.nNonRecip = nonRecip;
119 return inv;
120}
121
124 double meanVolRelErr = 0;
125 double maxVolRelErr = 0;
126 long volMismatch = 0;
128 0;
129 long missedNbr = 0;
130};
131
133template <class Real>
134void compareVolumes(const Kokkos::View<Real*, peclet::core::MemSpace>& volCurrent,
135 const TessellationView<Real>& oracle, OracleDiff& out) {
136 using Exec = peclet::core::ExecSpace;
137 const int N = oracle.numCells();
138 double sum = 0, mx = 0;
139 long mm = 0;
140 Kokkos::parallel_reduce(
141 "diff.vol", Kokkos::RangePolicy<Exec>(0, N),
142 KOKKOS_LAMBDA(const int i, double& s, double& m, long& c) {
143 const double vo = (double)oracle.volume(i);
144 const double r = vo > 0 ? std::abs((double)volCurrent(i) - vo) / vo : 0;
145 s += r;
146 if (r > m)
147 m = r;
148 if (r > 1e-3)
149 ++c;
150 },
151 sum, Kokkos::Max<double>(mx), mm);
152 out.meanVolRelErr = sum / (N > 0 ? N : 1);
153 out.maxVolRelErr = mx;
154 out.volMismatch = mm;
155}
156
163template <class Real>
164void compareNeighbours(const Kokkos::View<int*, peclet::core::MemSpace>& storeNp,
165 const Kokkos::View<int*, peclet::core::MemSpace>& storeNt,
166 const Kokkos::View<int*, peclet::core::MemSpace>& storePnbr,
167 const Kokkos::View<unsigned*, peclet::core::MemSpace>& storeTri, int MAXP,
168 int MAXT, const TessellationView<Real>& oracle, OracleDiff& out) {
169 using Exec = peclet::core::ExecSpace;
170 const int N = oracle.numCells();
171 long changed = 0, missed = 0;
172 Kokkos::parallel_reduce(
173 "diff.nbr", Kokkos::RangePolicy<Exec>(0, N),
174 KOKKOS_LAMBDA(const int i, long& chg, long& mis) {
175 const int snp = storeNp(i), snt = storeNt(i);
176 bool diff = false, miss = false;
177 // every true (oracle) neighbour must be a store FACE neighbour (≥3 incident live
178 // triangles).
179 for (int g = oracle.facetBegin(i); g < oracle.facetEnd(i); ++g) {
180 const int j = (int)oracle.facetNbr(g);
181 if (j < 0)
182 continue;
183 bool inStore = false;
184 for (int k = 6; k < snp && !inStore; ++k) {
185 if (storePnbr((size_t)i * MAXP + k) != j)
186 continue;
187 int cnt = 0;
188 for (int t = 0; t < snt; ++t) {
189 const unsigned w = storeTri((size_t)i * MAXT + t);
190 if (!((w >> 24) & 1u))
191 continue;
192 const int t0 = (int)(w & 0xffu), t1 = (int)((w >> 8) & 0xffu),
193 t2 = (int)((w >> 16) & 0xffu);
194 if (t0 == k || t1 == k || t2 == k)
195 ++cnt;
196 }
197 if (cnt >= 3)
198 inStore = true;
199 }
200 if (!inStore) {
201 diff = true;
202 miss = true;
203 }
204 }
205 // every store FACE neighbour must be a true (oracle) neighbour (set differs the other way).
206 for (int k = 6; k < snp && !diff; ++k) {
207 const int j = storePnbr((size_t)i * MAXP + k);
208 if (j < 0)
209 continue;
210 int cnt = 0;
211 for (int t = 0; t < snt; ++t) {
212 const unsigned w = storeTri((size_t)i * MAXT + t);
213 if (!((w >> 24) & 1u))
214 continue;
215 const int t0 = (int)(w & 0xffu), t1 = (int)((w >> 8) & 0xffu),
216 t2 = (int)((w >> 16) & 0xffu);
217 if (t0 == k || t1 == k || t2 == k)
218 ++cnt;
219 }
220 if (cnt < 3)
221 continue; // not a face
222 bool inOracle = false;
223 for (int g = oracle.facetBegin(i); g < oracle.facetEnd(i); ++g)
224 if ((int)oracle.facetNbr(g) == j) {
225 inOracle = true;
226 break;
227 }
228 if (!inOracle)
229 diff = true;
230 }
231 if (diff)
232 ++chg;
233 if (miss)
234 ++mis;
235 },
236 changed, missed);
237 out.changedNbrFrac = (double)changed / (N > 0 ? N : 1);
238 out.missedNbr = missed;
239}
240
241} // namespace peclet::voro
242
243#endif // PECLET_VORO_DYNAMIC_VALIDATE_HPP
Definition convex_cell.hpp:40
void compareNeighbours(const Kokkos::View< int *, peclet::core::MemSpace > &storeNp, const Kokkos::View< int *, peclet::core::MemSpace > &storeNt, const Kokkos::View< int *, peclet::core::MemSpace > &storePnbr, const Kokkos::View< unsigned *, peclet::core::MemSpace > &storeTri, int MAXP, int MAXT, const TessellationView< Real > &oracle, OracleDiff &out)
Definition dynamic_validate.hpp:164
void compareVolumes(const Kokkos::View< Real *, peclet::core::MemSpace > &volCurrent, const TessellationView< Real > &oracle, OracleDiff &out)
Compare a current per-cell volume array against the oracle view's volumes (cell i == seed i).
Definition dynamic_validate.hpp:134
Invariants checkInvariants(const TessellationView< Real > &view, const AuxMaps< Real > &aux, double boxVolume)
Definition dynamic_validate.hpp:54
Definition transpose.hpp:26
Kokkos::View< int *, peclet::core::MemSpace > recip
Definition transpose.hpp:27
Per-step invariant residuals (all should be ~0 / ~machine-precision for a correct tessellation).
Definition dynamic_validate.hpp:43
double maxAreaAsym
max interior facet |A(g)+A(recip)| / |A(g)|
Definition dynamic_validate.hpp:45
double sumAreaMag
|Σ_g A(g)| over all facets
Definition dynamic_validate.hpp:46
double sumForceMag
|Σ_g dV(g)| over all facets
Definition dynamic_validate.hpp:47
double volRelErr
|Σvol − boxVol| / boxVol
Definition dynamic_validate.hpp:44
long nNonRecip
interior facets with no reciprocal
Definition dynamic_validate.hpp:48
Result of comparing the current updated state against a fresh cold-build oracle.
Definition dynamic_validate.hpp:123
double changedNbrFrac
fraction of cells whose stored neighbour set differs from the oracle
Definition dynamic_validate.hpp:127
double maxVolRelErr
Definition dynamic_validate.hpp:125
double meanVolRelErr
Definition dynamic_validate.hpp:124
long missedNbr
cells with a TRUE (oracle) neighbour absent from the stored set
Definition dynamic_validate.hpp:129
long volMismatch
cells with vol rel err > 1e-3
Definition dynamic_validate.hpp:126
Definition tessellation_view.hpp:111
KOKKOS_INLINE_FUNCTION Real area(int f, int c) const
Definition tessellation_view.hpp:144
KOKKOS_INLINE_FUNCTION int facetEnd(int i) const
Definition tessellation_view.hpp:140
KOKKOS_INLINE_FUNCTION gid_t facetNbr(int f) const
Definition tessellation_view.hpp:143
KOKKOS_INLINE_FUNCTION int facetBegin(int i) const
Definition tessellation_view.hpp:139
KOKKOS_INLINE_FUNCTION Real volume(int i) const
Definition tessellation_view.hpp:138
KOKKOS_INLINE_FUNCTION int numFacets() const
Definition tessellation_view.hpp:136
KOKKOS_INLINE_FUNCTION int numCells() const
Definition tessellation_view.hpp:131
KOKKOS_INLINE_FUNCTION Real connect(int f, int c) const
Definition tessellation_view.hpp:145
Published, read-only device data layer for the tessellation (migration §2.1, §3).