37 std::span<Cell *const> ghost_cells) {
41 std::unordered_set<ParticleList const *>
ghost_set;
42 for (
Cell *c : ghost_cells) {
75 for (
Cell *c : local_cells) {
76 for (
Cell *n : c->neighbors().all()) {
85 std::unordered_map<ParticleList const *, int>
fill_count;
91 std::ostringstream
oss;
92 oss <<
"peer " <<
nc.peer <<
" appears in more than one NeighborComm";
97 if (
nc.send.size() !=
nc.recv.size()) {
98 std::ostringstream
oss;
99 oss <<
"NeighborComm peer=" <<
nc.peer
100 <<
" has send.size()=" <<
nc.send.size()
101 <<
" != recv.size()=" <<
nc.recv.size();
108 std::ostringstream
oss;
109 oss <<
"NeighborComm peer=" <<
nc.peer
110 <<
" recv target is not a ghost cell";
118 for (
auto const &
lc : plan.
local) {
121 violations.emplace_back(
"LocalComm dst target is not a ghost cell");
135 for (
Cell *c : ghost_cells) {
142 "ghost cell is never filled (missing recv/dst)");
144 }
else if (count > 1) {
145 std::ostringstream
oss;
146 oss <<
"ghost cell is filled " << count <<
" times (expected 1)";
153 for (
Cell *c : local_cells) {
154 for (
Cell *n : c->neighbors().all()) {
166 "local cell has ghost neighbor that is not a covered recv/dst "
167 "target (referenced-but-uncommunicated ghost)");
174 for (
Cell *c : local_cells) {
175 if (c->is_boundary()) {
178 for (
Cell *n : c->neighbors().all()) {
179 if (
ghost_set.contains(&n->particles())) {
180 violations.emplace_back(
"interior cell has a ghost neighbor");
196 for (
Cell *c : local_cells) {
197 if (!c->is_boundary()) {
203 for (
auto const &
sr :
nc.send) {
205 std::ostringstream
oss;
206 oss <<
"interior cell appears as NeighborComm send source (peer="
207 <<
nc.peer <<
") — overlap-safety invariant violated";
212 for (
auto const &
lc : plan.
local) {
215 "interior cell appears as LocalComm src — overlap-safety invariant "
std::vector< std::string > validate_halo_plan(HaloPlan const &plan, std::span< Cell *const > local_cells, std::span< Cell *const > ghost_cells)
Validate a HaloPlan for correctness.