8#ifndef PECLET_FLOW_FLOW_IBM_DIAGNOSTICS_HPP
9#define PECLET_FLOW_FLOW_IBM_DIAGNOSTICS_HPP
20 const int dims[3] = {e.x, e.y, e.z};
21 const long st[3] = {1, e.x, (
long)e.x * e.y};
29 const double rho = u_.
rhoRef * rho_;
30 for (
int a = 0; a < 3; ++a)
31 for (
int s = 0; s < 2; ++s) {
32 if (bc_[2 * a + s] != 3 || !touchesGlobalFace(2 * a + s))
34 const int b = (a + 1) % 3, c = (a + 2) % 3;
36 const long sa = st[a],
sb = st[b], sc = st[c];
37 const int bf = (s == 0) ?
G : (
dims[a] -
G);
38 const int bic = (s == 0) ?
G : (
dims[a] -
G - 1);
39 const double sgn = (s == 0) ? 1.0 : -1.0;
43 double mx = 0.0,
en = 0.0;
45 Kokkos::parallel_reduce(
48 const long base = (
long)p0 *
sb + (
long)
p1 * sc;
49 const double back = sgn *
un(base + (
long)
bf *
sa);
52 const double tb = kb *
ub(
ic), tc = kc *
uc(
ic);
55 len += rho *
bp * 0.5 * (
bp *
bp + tb * tb + tc * tc);
59 Kokkos::Max<double>(mx), Kokkos::Sum<double>(
en), Kokkos::Sum<long>(
nrev));
60 ob.maxReverse = std::max(
ob.maxReverse, mx);
61 ob.energyInflux +=
en;
67 double d[2] = {
ob.energyInflux, 0.0},
dg[2];
70 long l[2] = {
ob.reversed,
ob.total},
lg[2];
73 ob.energyInflux =
dg[0];
78 ob.fraction =
ob.total > 0 ? (
double)
ob.reversed / (
double)
ob.total : 0.0;
96 std::vector<double>
vi(v.size());
97 for (std::size_t i = 0; i < v.size(); ++i)
109 std::vector<double> out;
110 if constexpr (Grid::collocated) {
118 for (
double& x : out)
125 CCField o[3] = {ox_, oy_, oz_};
131 auto h = Kokkos::create_mirror_view(C[c].
AC);
132 Kokkos::deep_copy(h, C[c].
AC);
133 std::vector<double> out((std::size_t)nx_ * ny_ * nz_);
134 for (
int z = 0; z < nz_; ++z)
135 for (
int y = 0; y < ny_; ++y)
136 for (
int x = 0; x < nx_; ++x)
137 out[(std::size_t)x + (std::size_t)y * nx_ + (std::size_t)z * (std::size_t)nx_ * ny_] =
138 (
double)h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y);
144 const bool gp = ghostProjection_ && oxb_.extent(0) > 0;
145 CCField o[3] = {
gp ? oxb_ : ox_,
gp ? oyb_ : oy_,
gp ? ozb_ : oz_};
154 std::vector<double> out =
gatherInner(incremental_ ? P_ : phi_);
156 const double ct = (incremental_ ? 1.0 : rho_ / dt_) * u_.
pToPhys();
158 for (
double& x : out)
170 if (!cutcellPressure_)
172 if constexpr (Grid::collocated)
179 for (
int c = 0; c < 3; ++c)
185#ifdef PECLET_FLOW_MPI
202 if (!cutcellPressure_)
204 if constexpr (Grid::collocated) {
218 if (ghostProjection_ && gpNRows_ >= 0) {
222 gpDivergDelta(div_, du, dv, dw, gpOv_, gpNRows_,
C3{nx_, ny_, nz_}, e_,
G, distributed_);
226 for (
int c = 0; c < 3; ++c)
228 if (ghostProjection_ && gpNRows_ >= 0) {
235 C3{nx_, ny_, nz_}, e_,
G, distributed_);
245#ifdef PECLET_FLOW_MPI
257 if (!porous_ || !cutcellPressure_)
259 for (
int c = 0; c < 3; ++c)
268 CCField d = div_, dd = depsdt_;
269 const bool useDt = porousDepsDt_;
271 Kokkos::parallel_for(
272 "peclet::flow::porous_resid",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
274 const long i = (
long)x + (
long)y * e.x + (
long)z * e.x * e.y;
280#ifdef PECLET_FLOW_MPI
292 return lastPressureIters_;
297 std::vector<std::array<int, 3>> out;
299 out.push_back({r.x, r.y, r.z});
305 return lastPressureFailed_;
310 using peclet::core::solver::AndersonRole;
315 auto refuse = [](
const std::string&
why) {
316 throw std::runtime_error(
"steady acceleration (march_to_steady / anderson_accelerator): " +
317 why +
"; pass accelerate=False");
319 if constexpr (Grid::collocated) {
320 if (!(ghostProjection_ && faceInterp_ == 0))
322 "the collocated scheme is not the fluid-only 'ghost' projection -- for this scheme the "
323 "fixed point is not unique / the march is unstable (select "
324 "set_collocated_scheme('ghost') before the geometry)");
327 refuse(
"phase change (enable_phase_change) has no steady fixed point");
328 if (vofEnabled_ || vofMomEnabled_ || vofBlocks_)
329 refuse(
"VoF (enable_vof / enable_vof_momentum / VoF blocks) is time-accurate, not steady");
330 if (!scalars_.empty())
331 refuse(
"a transported scalar (add_scalar) is not in the march state");
333 refuse(
"the porous (volume-averaged) continuity is not supported");
335 for (
const auto&
cl : closures_)
337 if (varRho_ || varProps_ ||
propClosure || hasField(
"rho") || hasField(
"mu"))
338 refuse(
"variable density or viscosity (a property closure or a rho/mu field) is not supported");
340 refuse(
"a drag_beta field (implicit drag, CFD-DEM) is not supported");
342 refuse(
"cell force fields (force_x/force_y/force_z) are not supported");
344 refuse(
"moving scene instances have no steady fixed point");
345 if (superficialAxis_ >= 0)
346 refuse(
"set_superficial_velocity is not supported");
348 refuse(
"the pressure warm start (set_pressure_warmstart(True)) diverges on the steady march");
349 if (balancedForceActive())
350 refuse(
"the balanced-force projection is not supported");
353 for (
int c = 0; c < 3; ++c) {
354 ms.
fields.push_back(C[c].u);
355 ms.
roles.push_back(AndersonRole::Velocity);
358 ms.
roles.push_back(AndersonRole::Carried);
359 if constexpr (Grid::collocated) {
361 if (advect_ && ufAdvect_)
362 for (
CCField f : {uf_, vf_, wf_}) {
364 ms.
roles.push_back(AndersonRole::Carried);
376 static_cast<double>(advScheme_),
377 implicitFou_ ? 1.0 : 0.0};
378#ifdef PECLET_FLOW_MPI
380 ms.distributed = distributed_;
407 return mg_.allreduceSeconds();
412 return mg_.allreduceCount();
std::vector< C3 > levelRatios() const
The per-level coarsening ratio actually chosen (the level table of §5, gate §8.5).
std::vector< double > getFaceVelocity(int c)
void fillVelGhosts(int comp, int fold)
double maxOpenDivergenceInternal()
The same diagnostic in INDEX units (per tRef), which is what the solver's own guards read.
void scatterInner(CCField fld, const std::vector< double > &in)
void seedFaceFieldFromCells()
std::vector< std::array< int, 3 > > pressureMgLevelRatios() const
double maxOpenDivergence()
OutflowBackflow outflowBackflow()
double maxPorousResidual()
double maxOpenDivergenceProjectedInternal()
The same diagnostic in INDEX units (per tRef), which is what the solver's own guards read.
CCConst openFaceView(int c) const
Component c of the face field AS THE ADVECTION AND THE DIVERGENCE DIAGNOSTIC MUST READ IT: advFaceVie...
void addWallFluxDivergence(CCField d)
double maxOpenDivergenceProjected()
std::vector< double > getOpenness(int c)
void fillVelGhostsTo(CCField f, int comp, int fold, bool doOutflow=true)
std::vector< double > getMomentumDiagonal(int c)
void setVelocity(int c, const std::vector< double > &v)
Write a component's inner velocity from a host vector (x-fastest, inner region) and re-impose the sol...
std::vector< double > getOpennessProj(int c)
std::vector< double > getVelocity(int c)
long lastPressureIterations() const
double reduceMaxAbsInner(CCConst f)
std::vector< double > gatherInner(CCField fld)
void fillPorousEpsGhosts()
std::vector< double > getPressure()
void gpDivergDelta(CCField d, CCConst u, CCConst v, CCConst w, const GpOverlayReal< Real > &ov, int nOv, C3 nn, C3 extb, int gb, bool useGhost=false)
Overlay divergence correction: d(r) = rho_r * (d(r) + closure/BC/explicit face values),...
void divergOpen(CCConst u, CCConst v, CCConst w, CCConst ox, CCConst oy, CCConst oz, CCField d, C3 e, int g)
Kokkos::View< double *, CCMem > CCField
Kokkos::DefaultExecutionSpace CCExec
void divergOpenEps(CCConst u, CCConst v, CCConst w, CCConst ox, CCConst oy, CCConst oz, CCConst eps, CCField d, C3 e, int g)
Kokkos::View< const double *, CCMem > CCConst
std::vector< peclet::core::solver::AndersonRole > roles
std::array< double, 9 > signature
std::vector< CCField > fields
OUTFLOW REVERSAL CENSUS – the regime in which the zero-gradient (do-nothing) outflow is only conditio...
double rhoRef
reference density = the first set_rho
double velToPhys(int a) const
double velToInt(int a) const
static constexpr double AC