Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions docs/design/SPECIFICATION_TECHNIQUE_FINALE_POPS_ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1418,13 +1418,19 @@ taille/header de table et opérations requises avant de conserver le handle de b
sont résolues une fois à l'installation ; aucun `dlsym`, nom de classe ou dispatch Python n'entre dans
une boucle de cellules.

Le contrat `Reflux` v1 est volontairement livré avant son branchement dans
`PreparedAmrProgramRefluxTransition` : catalogue, manifest, loader et consumer typé peuvent qualifier
un conformer, mais le runtime AMR continue d'utiliser son kernel interne tant qu'un adaptateur préparé
ne peut pas fournir les vues locales sans dupliquer le ledger ni transférer l'autorité collective. Une
configuration AMR ne prétend donc pas encore avoir sélectionné un provider `Reflux` externe. Cette
première qualification est limitée à la cible 2D, `float64`, CPU déjà admise par le loader de
composants ; elle ne constitue pas une promesse GPU.
Le contrat `Reflux` v1 possède maintenant un adaptateur préparé interne vers
`PreparedAmrProgramRefluxTransition`. Pour chaque patch enfant local, l'adaptateur reçoit quatre
paires de flux déjà intégrés et écrit quatre corrections dans des buffers persistants empoisonnés
avant l'appel. PoPS vérifie que chaque valeur a été écrite et reste finie, atteint un consensus
d'échec entre rangs, puis applique seul périodicité, masque de couverture, réduction MPI et
publication transactionnelle. La présence et le contrat exact du provider sont également comparés
entre rangs avant toute exécution.

Cette tranche ne publie pas encore la sélection `Reflux` dans la résolution normalisée des providers
AMR : le seam d'installation demeure interne et les configurations publiques continuent donc
d'utiliser le kernel builtin. La qualification initiale de l'adaptateur reste limitée à la cible 2D,
`float64`, CPU avec stockage hôte. Le chemin n'est pas encore prouvé par compilation native, exécution
MPI avec un composant externe, mesure de conservation ni backend GPU.

Les champs sémantiques inconnus, capacités sans preuve, collisions d'identité et entry points manquants
sont refusés. Un vieux manifest n'est pas « réparé » silencieusement.
Expand Down
92 changes: 92 additions & 0 deletions include/pops/numerics/time/amr/levels/amr_patch_range.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,29 @@ struct RefluxStripConstView {
int components = 0;
};

/// Four already-computed, signed coarse-cell corrections around one fine-patch footprint.
///
/// A native Reflux component may fill these contiguous face buffers, but it never receives the
/// sparse global register, coverage mask, periodicity or MPI communicator. PoPS alone maps the
/// values onto canonical uncovered parent cells.
struct RefluxFaceCorrectionView {
int I0 = 0, I1 = -1, J0 = 0, J1 = -1;
Real* x_low = nullptr;
Real* x_high = nullptr;
Real* y_low = nullptr;
Real* y_high = nullptr;
int components = 0;
};

struct RefluxFaceCorrectionConstView {
int I0 = 0, I1 = -1, J0 = 0, J1 = -1;
const Real* x_low = nullptr;
const Real* x_high = nullptr;
const Real* y_low = nullptr;
const Real* y_high = nullptr;
int components = 0;
};

template <class Strip>
inline RefluxStripView reflux_strip_view(Strip& strip, int components) {
return {strip.I0, strip.I1, strip.J0, strip.J1, strip.cL.data(),
Expand Down Expand Up @@ -821,6 +844,64 @@ struct RouteRefluxStripKernel {
}
};

/// Deposit one external/local Reflux result into PoPS' sparse correction authority. The provider
/// has already applied side*(fine-coarse)/spacing; this kernel owns only topology canonicalisation,
/// coverage exclusion and deterministic face order.
struct RoutePreparedRefluxCorrectionKernel {
RefluxFaceCorrectionConstView faces;
FluxRegisterView correction;
CoverageMaskView coverage;
Box2D coarse_domain;
Periodicity periodicity;

POPS_HD static int wrap_index(int value, int lo, int extent) {
const std::int64_t relative = static_cast<std::int64_t>(value) - lo;
std::int64_t quotient = relative / extent;
if (relative % extent < 0)
--quotient;
return static_cast<int>(static_cast<std::int64_t>(lo) + relative - quotient * extent);
}

POPS_HD bool canonicalize(int& I, int& J) const {
if (I < coarse_domain.lo[0] || I > coarse_domain.hi[0]) {
if (!periodicity.x)
return false;
I = wrap_index(I, coarse_domain.lo[0], coarse_domain.nx());
}
if (J < coarse_domain.lo[1] || J > coarse_domain.hi[1]) {
if (!periodicity.y)
return false;
J = wrap_index(J, coarse_domain.lo[1], coarse_domain.ny());
}
return true;
}

POPS_HD void add_if_uncovered(int I, int J, int component, Real amount) const {
if (!canonicalize(I, J) || coverage.covered(I, J))
return;
correction.add(I, J, component, amount);
}

POPS_HD void operator()(int, int) const {
for (int J = faces.J0; J <= faces.J1; ++J)
for (int component = 0; component < faces.components; ++component) {
const std::size_t index =
static_cast<std::size_t>(J - faces.J0) * static_cast<std::size_t>(faces.components) +
static_cast<std::size_t>(component);
add_if_uncovered(faces.I0 - 1, J, component, faces.x_low[index]);
add_if_uncovered(faces.I1 + 1, J, component, faces.x_high[index]);
}
for (int I = faces.I0; I <= faces.I1; ++I)
for (int component = 0; component < faces.components; ++component) {
const std::size_t index =
static_cast<std::size_t>(I - faces.I0) * static_cast<std::size_t>(faces.components) +
static_cast<std::size_t>(component);
add_if_uncovered(I, faces.J0 - 1, component, faces.y_low[index]);
add_if_uncovered(I, faces.J1 + 1, component, faces.y_high[index]);
}
}
};

} // namespace detail

inline void sample_coarse_x_strip(const ConstArray4& left, const ConstArray4& right,
Expand Down Expand Up @@ -1087,6 +1168,17 @@ struct CoarseFineInterface {
Real(1) / dx, Real(1) / dy, Real(1)});
}

void route_prepared_reflux_correction_(const RefluxFaceCorrectionConstView& faces,
FluxRegister& ref, int nc) const {
if (nc <= 0 || ref.nc != nc || faces.components != nc || faces.I1 < faces.I0 ||
faces.J1 < faces.J0 || faces.x_low == nullptr || faces.x_high == nullptr ||
faces.y_low == nullptr || faces.y_high == nullptr)
throw std::invalid_argument("prepared Reflux correction view is incomplete");
for_each_cell(Box2D{{0, 0}, {0, 0}},
detail::RoutePreparedRefluxCorrectionKernel{faces, ref.view(), cmask.view(),
coarse_region, periodicity});
}

template <class Reg>
static void validate_route_inputs_(const Reg& coarse, const Reg& fine, Real dx, Real dy,
Real coarse_scale, const FluxRegister& ref, int nc,
Expand Down
Loading
Loading