PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
test_momentum_convective_candidates.c File Reference

A4a focused convective-candidate study (states A-C only). More...

#include "test_support.h"
#include "momentumsolvers.h"
#include "rhs.h"
#include "setup.h"
#include "Boundaries.h"
#include <petscblaslapack.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
Include dependency graph for test_momentum_convective_candidates.c:

Go to the source code of this file.

Data Structures

struct  DofMap
 
struct  SeamDiagnostics
 
struct  GlobalVecStats
 
struct  StableCFLResult
 

Macros

#define HAVE_I(ii)   InGhostRange((ii), info.gxs, info.gxm)
 
#define HAVE_J(jj)   InGhostRange((jj), info.gys, info.gym)
 
#define HAVE_K(kk)   InGhostRange((kk), info.gzs, info.gzm)
 
#define HAVE_I(ii)   InGhostRange((ii), info.gxs, info.gxm)
 
#define HAVE_J(jj)   InGhostRange((jj), info.gys, info.gym)
 
#define HAVE_K(kk)   InGhostRange((kk), info.gzs, info.gzm)
 
#define ROWSUM(cmp)
 

Enumerations

enum  StableCFLStatus { STABLE_CFL_NONE , STABLE_CFL_FINITE , STABLE_CFL_EXCEEDS_SCAN }
 
enum  CandState { STATE_A , STATE_B , STATE_C }
 
enum  PMetric { METRIC_RHO , METRIC_NORM }
 

Functions

static PetscInt PeriodicRepCount (PetscInt npts)
 Returns the number of independent periodic representatives in one direction.
 
static PetscInt DofMapExpectedCount (DMDALocalInfo info)
 Counts all independent component-staggered representatives used by ComputeRHS.
 
static PetscErrorCode DofMapBuild (UserCtx *user, DofMap *map)
 Builds the serial periodic independent face-DOF map used by dense Jacobians.
 
static PetscErrorCode DofMapBuildOwned (UserCtx *user, DofMap *map)
 Builds the rank-owned periodic independent face-DOF map for MPI checks.
 
static PetscErrorCode DofMapDestroy (DofMap *map)
 Releases storage owned by an active-DOF map.
 
static PetscReal CmpGet (Cmpnts c, PetscInt comp)
 
static PetscErrorCode EvalConvResidual (UserCtx *user, Vec Ucont_in, Vec Rhs, const DofMap *map, PetscReal *Ract)
 
static PetscErrorCode PerturbDof (UserCtx *user, Vec Ucont, const DofMap *map, PetscInt m, PetscReal delta)
 
static PetscErrorCode GetDof (UserCtx *user, Vec Ucont, const DofMap *map, PetscInt m, PetscReal *val)
 Reads one active contravariant component from a global vector.
 
static PetscReal PeriodicCellAngle (PetscInt idx, PetscInt npts)
 Returns the cell-centered periodic angle using duplicated endpoint planes.
 
static PetscReal PeriodicFaceAngle (PetscInt idx, PetscInt npts)
 Returns a face-representative periodic angle for component-staggered Ucont.
 
static Cmpnts AnalyticVelocity (CandState st, PetscInt i, PetscInt j, PetscInt k, PetscInt mx, PetscInt my, PetscInt mz)
 Evaluates one of the three analytic Cartesian candidate states.
 
static Cmpnts DirectUcontVelocity (CandState st, PetscInt i, PetscInt j, PetscInt k, PetscInt mx, PetscInt my, PetscInt mz)
 Evaluates the declared direct component-staggered State B Ucont field.
 
static PetscReal CmpDiffInf (Cmpnts a, Cmpnts b)
 Computes the componentwise infinity norm of the difference between two vectors.
 
static PetscErrorCode ComputeDeclaredSeamMismatch (CandState st, DMDALocalInfo info, PetscReal seam[3])
 Computes analytic periodic seam mismatches for each coordinate direction.
 
static PetscBool InGhostRange (PetscInt idx, PetscInt lo, PetscInt n)
 Reports whether a global index is present in a rank's local ghosted range.
 
static PetscErrorCode ComputeLocalDuplicateMismatch (UserCtx *user, Vec local, PetscReal seam[3])
 Computes duplicate-plane mismatch in a local vector view.
 
static PetscErrorCode ComputeLocalOuterGhostMismatch (UserCtx *user, Vec local, PetscReal seam[3])
 Computes outer periodic ghost mismatch for local Ucat.
 
static PetscErrorCode ConfigureCandidateFixture (SimCtx *simCtx, UserCtx *user)
 Configures the minimal context for centered inviscid periodic convection tests.
 
static PetscErrorCode SetUcatField (UserCtx *user, CandState st)
 
static PetscErrorCode SetDirectUcontField (UserCtx *user, CandState st)
 Sets the direct State B component-staggered Ucont field on owned entries.
 
static PetscErrorCode ComputeMaxDiscreteDivergence (UserCtx *user, PetscReal *maxdiv)
 Computes max discrete divergence of the current local Ucont field.
 
static PetscErrorCode BuildBaseState (UserCtx *user, CandState st, Vec Ubase, PetscReal *repeat_inf, PetscReal *maxdiv, SeamDiagnostics *seam)
 
static PetscErrorCode ComputeMaxGradientContribution (UserCtx *user, PetscReal *gradmax)
 Computes the global maximum Cartesian velocity-gradient row-sum used by Candidate D.
 
static PetscErrorCode DenseSpectralRadius (const PetscReal *A, PetscInt n, PetscReal *rho, PetscReal *maxRealPart)
 
static PetscErrorCode DenseRKPolynomialSpectralRadius (const PetscReal *J, PetscInt n, PetscReal dtau, PetscReal *rho)
 Computes the spectral radius of the RK polynomial by applying it to eig(J).
 
static PetscErrorCode DenseSigmaMax (const PetscReal *A, PetscInt n, PetscReal *smax, PetscReal *v1)
 
static PetscReal DenseNonNormality (const PetscReal *A, PetscInt n)
 
static PetscReal DenseSkewnessDefect (const PetscReal *A, PetscInt n)
 Computes the normalized Frobenius defect from skew symmetry.
 
static PetscErrorCode DenseShiftIdentity (const PetscReal *A, PetscInt n, PetscReal shift, PetscReal *B)
 Copies a dense matrix and adds a scalar shift to its diagonal.
 
static void MatMul (const PetscReal *A, const PetscReal *B, PetscReal *out, PetscInt n)
 
static PetscErrorCode RKPolynomial (const PetscReal *J, PetscReal dtau, PetscInt n, PetscReal *P)
 
static PetscErrorCode AmplificationMetric (const PetscReal *J, PetscInt n, PetscReal dtau, PMetric which, PetscReal *metric)
 Evaluates either spectral-radius or 2-norm amplification for one pseudo-time step.
 
static PetscErrorCode StableCFL (const PetscReal *J, PetscInt n, PetscReal lam, PMetric which, StableCFLResult *result)
 
static const char * StableCFLStatusText (StableCFLResult r)
 Returns human-readable text for a stable-CFL search result.
 
static PetscErrorCode PrintStableCFLLine (const char *candidate, StableCFLResult eig, StableCFLResult norm)
 Prints one candidate's eigenvalue and norm stable-CFL statuses.
 
static void ApplyP (const PetscReal *P, const PetscReal *x, PetscReal *out, PetscInt n)
 
static PetscErrorCode PrintFrozenAmplificationTable (const char *title, const PetscReal *J, PetscInt n, const PetscReal lams[3], const char *cn[3])
 Prints frozen RK amplification tables for the supplied operator and candidates.
 
static PetscReal VecNorm2Array (const PetscReal *x, PetscInt n)
 Computes the Euclidean norm of a dense vector.
 
static PetscReal VecNormInfArray (const PetscReal *x, PetscInt n)
 Computes the infinity norm of a dense vector.
 
static PetscReal DenseFrobenius (const PetscReal *A, PetscInt n)
 Computes the Frobenius norm of a dense column-major matrix.
 
static PetscReal DenseRelativeDiff (const PetscReal *A, const PetscReal *B, PetscInt n, PetscReal denom_ref)
 Computes a normalized Frobenius difference between two dense matrices.
 
static PetscErrorCode AddActiveVector (UserCtx *user, Vec U, const DofMap *map, const PetscReal *x, PetscReal scale)
 Adds a dense active-space vector into a global contravariant vector.
 
static PetscErrorCode ExtractActiveVector (UserCtx *user, Vec U, const DofMap *map, PetscReal *x)
 Extracts active-space entries from a global contravariant vector.
 
static PetscReal DofWeight (const DofMap *map, PetscInt m)
 Returns a deterministic checksum weight for an active DOF.
 
static PetscErrorCode ActiveStats (const DofMap *map, const PetscReal *x, GlobalVecStats *stats)
 Computes global active-vector norms and checksum.
 
static PetscErrorCode FillDeterministicDirection (UserCtx *user, Vec V, const DofMap *map, PetscReal *x)
 Fills a globally normalized deterministic active-space perturbation direction.
 
static PetscErrorCode FourStage (UserCtx *user, Vec U0full, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Uwork, Vec Uout)
 
static PetscErrorCode SetAnchoredStage (UserCtx *user, Vec U0full, PetscReal scale, const DofMap *map, const PetscReal *Ract, Vec Ustage)
 Forms one anchored RK stage state from the base state and active residual.
 
static PetscErrorCode BuildStageStates (UserCtx *user, Vec U0full, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Y1, Vec Y2, Vec Y3)
 Builds the first three anchored RK stage states for a base vector.
 
static PetscErrorCode BuildFDJacobian (UserCtx *user, Vec Ucenter, PetscReal epsrel, Vec Rhs, const DofMap *map, PetscReal *Rp, PetscReal *Rm, Vec Uwork, PetscReal *J)
 Builds a centered finite-difference Jacobian of the production convective residual.
 
static PetscErrorCode BuildStageTangent (const PetscReal *J0, const PetscReal *J1, const PetscReal *J2, const PetscReal *J3, PetscReal dtau, PetscInt n, PetscReal *T4)
 Builds the exact four-stage tangent from stage-dependent Jacobians.
 
static PetscErrorCode BuildPhiJacobian (UserCtx *user, Vec Ucenter, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Upert, Vec Ustage, Vec PhiP, Vec PhiM, PetscReal *xp, PetscReal *xm, PetscReal epsrel, PetscReal *JPhi)
 Builds a finite-difference Jacobian of the complete nonlinear four-stage map.
 
static PetscErrorCode RunRKTangentDiagnostics (UserCtx *user, CandState st, Vec Ubase, Vec Rhs, const DofMap *map, PetscReal epsrel, const PetscReal lams[3], const char *cn[3], const PetscReal *J0)
 Runs stage-dependent RK tangent and direct nonlinear perturbation diagnostics.
 
static PetscErrorCode RunState (CandState st, const char *name)
 
static PetscErrorCode TestStateA (void)
 Runs the State A candidate harness.
 
static PetscErrorCode TestStateB (void)
 Runs the State B candidate harness.
 
static PetscErrorCode TestStateC (void)
 Runs the State C candidate harness.
 
static PetscErrorCode RunStateAGridAuditOne (PetscInt N)
 Runs one State A grid-size audit case.
 
static PetscErrorCode TestStateAGridAudit (void)
 Runs the State A grid-dependence and active-space audit.
 
static PetscErrorCode WriteStateADecompReference (GlobalVecStats r0, GlobalVecStats jv, GlobalVecStats phi, const MomStabilityReport *rep)
 Writes the one-rank State A matrix-free decomposition reference.
 
static PetscErrorCode ReadAndCompareStateADecompReference (GlobalVecStats r0, GlobalVecStats jv, GlobalVecStats phi, const MomStabilityReport *rep)
 Compares a distributed State A matrix-free check against the one-rank reference.
 
static PetscErrorCode StateADecompDirectionalCheck (UserCtx *user, Vec Ubase, Vec Rhs, PetscReal lcC, const MomStabilityReport *rep)
 Runs State A matrix-free residual, Jv, and four-stage MPI decomposition checks.
 
static PetscErrorCode RunDecompBaseline (CandState st, const char *name, PetscReal expB, PetscReal expC, PetscReal expD)
 Runs one decomp baseline and compares scalar estimates with regenerated references.
 
static PetscErrorCode TestDecompA (void)
 Runs the State A decomposition baseline.
 
static PetscErrorCode TestDecompB (void)
 Runs the State B decomposition baseline.
 
static PetscErrorCode TestDecompC (void)
 Runs the State C decomposition baseline.
 
static PetscErrorCode ConfigureMPIReferenceOptions (void)
 Reads optional paired-run MPI reference path and token.
 
int main (int argc, char **argv)
 PETSc entry point for the focused convective-candidate harness.
 

Variables

static char g_ref_path [PETSC_MAX_PATH_LEN] = ""
 
static char g_ref_token [128] = ""
 
static PetscBool g_ref_path_set = PETSC_FALSE
 
static PetscBool g_ref_token_set = PETSC_FALSE
 

Detailed Description

A4a focused convective-candidate study (states A-C only).

Builds the finite-difference Jacobian of the ACTUAL production convection-only residual (ComputeRHS with inviscid, P=0, centered, periodic, single block) on a tiny periodic Cartesian grid, then compares the B/C/D estimator candidates against rho(J), sigma_max(J), the exact 4-stage RK matrix polynomial P(z)=1+z+z^2/2+z^3/6+z^4/24, and a direct anchored 4-stage perturbation cross-check. Shadow-only: changes no production default.

States: A uniform divergence-free; B nonzero discrete divergence; C divergence-free shear.

Definition in file test_momentum_convective_candidates.c.


Data Structure Documentation

◆ DofMap

struct DofMap

Definition at line 27 of file test_momentum_convective_candidates.c.

Data Fields
PetscInt n
PetscInt expected_n
PetscInt * comp
PetscInt * ci
PetscInt * cj
PetscInt * ck

◆ SeamDiagnostics

struct SeamDiagnostics

Definition at line 28 of file test_momentum_convective_candidates.c.

Data Fields
PetscReal declared[3]
PetscReal ucat_global[3]
PetscReal ucat_ghost[3]
PetscReal ucont_global[3]

◆ GlobalVecStats

struct GlobalVecStats

Definition at line 34 of file test_momentum_convective_candidates.c.

Data Fields
PetscReal n2
PetscReal ninf
PetscReal checksum

◆ StableCFLResult

struct StableCFLResult

Definition at line 47 of file test_momentum_convective_candidates.c.

Data Fields
StableCFLStatus status
PetscReal cfl

Macro Definition Documentation

◆ HAVE_I [1/2]

#define HAVE_I (   ii)    InGhostRange((ii), info.gxs, info.gxm)

◆ HAVE_J [1/2]

#define HAVE_J (   jj)    InGhostRange((jj), info.gys, info.gym)

◆ HAVE_K [1/2]

#define HAVE_K (   kk)    InGhostRange((kk), info.gzs, info.gzm)

◆ HAVE_I [2/2]

#define HAVE_I (   ii)    InGhostRange((ii), info.gxs, info.gxm)

◆ HAVE_J [2/2]

#define HAVE_J (   jj)    InGhostRange((jj), info.gys, info.gym)

◆ HAVE_K [2/2]

#define HAVE_K (   kk)    InGhostRange((kk), info.gzs, info.gzm)

◆ ROWSUM

#define ROWSUM (   cmp)
Value:
( \
PetscAbsReal(Ajc*(C.x*duc.cmp + E.x*due.cmp + Z.x*duz.cmp)) + \
PetscAbsReal(Ajc*(C.y*duc.cmp + E.y*due.cmp + Z.y*duz.cmp)) + \
PetscAbsReal(Ajc*(C.z*duc.cmp + E.z*due.cmp + Z.z*duz.cmp)) )

Enumeration Type Documentation

◆ StableCFLStatus

Enumerator
STABLE_CFL_NONE 
STABLE_CFL_FINITE 
STABLE_CFL_EXCEEDS_SCAN 

Definition at line 41 of file test_momentum_convective_candidates.c.

◆ CandState

enum CandState

◆ PMetric

enum PMetric
Enumerator
METRIC_RHO 
METRIC_NORM 

Definition at line 741 of file test_momentum_convective_candidates.c.

Function Documentation

◆ PeriodicRepCount()

static PetscInt PeriodicRepCount ( PetscInt  npts)
inlinestatic

Returns the number of independent periodic representatives in one direction.

Definition at line 55 of file test_momentum_convective_candidates.c.

55{ return npts - 2; }
Here is the caller graph for this function:

◆ DofMapExpectedCount()

static PetscInt DofMapExpectedCount ( DMDALocalInfo  info)
inlinestatic

Counts all independent component-staggered representatives used by ComputeRHS.

Definition at line 60 of file test_momentum_convective_candidates.c.

61{
62 return 3 * PeriodicRepCount(info.mx) * PeriodicRepCount(info.my) * PeriodicRepCount(info.mz);
63}
static PetscInt PeriodicRepCount(PetscInt npts)
Returns the number of independent periodic representatives in one direction.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DofMapBuild()

static PetscErrorCode DofMapBuild ( UserCtx user,
DofMap map 
)
static

Builds the serial periodic independent face-DOF map used by dense Jacobians.

Production periodic synchronization copies global plane 0 from mx-2 and plane mx-1 from 1 (and analogously in y/z), so representatives 1..m-2 contain each independent component-staggered Ucont face DOF exactly once. Perturbations only touch these reps; EvalConvResidual() then calls SynchronizePeriodicStaggeredFields() to update duplicates.

Definition at line 73 of file test_momentum_convective_candidates.c.

74{
75 DMDALocalInfo info = user->info;
76 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
77 const PetscInt lxs = 1, lxe = mx-1, lys = 1, lye = my-1, lzs = 1, lze = mz-1;
78 PetscInt cnt = 0;
79 PetscFunctionBeginUser;
81 map->n = (lxe-lxs)*(lye-lys)*(lze-lzs)*3;
82 PetscCall(PetscMalloc4(map->n, &map->comp, map->n, &map->ci, map->n, &map->cj, map->n, &map->ck));
83 for (PetscInt k = lzs; k < lze; k++)
84 for (PetscInt j = lys; j < lye; j++)
85 for (PetscInt i = lxs; i < lxe; i++)
86 for (PetscInt c = 0; c < 3; c++) {
87 map->comp[cnt] = c; map->ci[cnt] = i; map->cj[cnt] = j; map->ck[cnt] = k; cnt++;
88 }
89 PetscCheck(map->n == map->expected_n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
90 "periodic independent DOF count mismatch: got %" PetscInt_FMT ", expected %" PetscInt_FMT,
91 map->n, map->expected_n);
92 PetscFunctionReturn(0);
93}
static PetscInt DofMapExpectedCount(DMDALocalInfo info)
Counts all independent component-staggered representatives used by ComputeRHS.
DMDALocalInfo info
Definition variables.h:881
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DofMapBuildOwned()

static PetscErrorCode DofMapBuildOwned ( UserCtx user,
DofMap map 
)
static

Builds the rank-owned periodic independent face-DOF map for MPI checks.

Definition at line 98 of file test_momentum_convective_candidates.c.

99{
100 DMDALocalInfo info = user->info;
101 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
102 const PetscInt xs = info.xs, xe = info.xs + info.xm;
103 const PetscInt ys = info.ys, ye = info.ys + info.ym;
104 const PetscInt zs = info.zs, ze = info.zs + info.zm;
105 const PetscInt lxs = PetscMax(xs, 1), lxe = PetscMin(xe, mx-1);
106 const PetscInt lys = PetscMax(ys, 1), lye = PetscMin(ye, my-1);
107 const PetscInt lzs = PetscMax(zs, 1), lze = PetscMin(ze, mz-1);
108 PetscInt cnt = 0;
109 PetscFunctionBeginUser;
110 map->expected_n = DofMapExpectedCount(info);
111 map->n = PetscMax(0,lxe-lxs)*PetscMax(0,lye-lys)*PetscMax(0,lze-lzs)*3;
112 PetscCall(PetscMalloc4(map->n, &map->comp, map->n, &map->ci, map->n, &map->cj, map->n, &map->ck));
113 for (PetscInt k = lzs; k < lze; k++)
114 for (PetscInt j = lys; j < lye; j++)
115 for (PetscInt i = lxs; i < lxe; i++)
116 for (PetscInt c = 0; c < 3; c++) {
117 map->comp[cnt] = c; map->ci[cnt] = i; map->cj[cnt] = j; map->ck[cnt] = k; cnt++;
118 }
119 PetscFunctionReturn(0);
120}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DofMapDestroy()

static PetscErrorCode DofMapDestroy ( DofMap map)
static

Releases storage owned by an active-DOF map.

Definition at line 125 of file test_momentum_convective_candidates.c.

126{ PetscFunctionBeginUser; PetscCall(PetscFree4(map->comp, map->ci, map->cj, map->ck)); PetscFunctionReturn(0); }
Here is the caller graph for this function:

◆ CmpGet()

static PetscReal CmpGet ( Cmpnts  c,
PetscInt  comp 
)
inlinestatic

Definition at line 129 of file test_momentum_convective_candidates.c.

129{ const PetscReal *p = (const PetscReal*)&c; return p[comp]; }
Here is the caller graph for this function:

◆ EvalConvResidual()

static PetscErrorCode EvalConvResidual ( UserCtx user,
Vec  Ucont_in,
Vec  Rhs,
const DofMap map,
PetscReal *  Ract 
)
static

Definition at line 134 of file test_momentum_convective_candidates.c.

135{
136 Cmpnts ***r;
137 PetscFunctionBeginUser;
138 PetscCall(VecCopy(Ucont_in, user->Ucont));
139 {
140 const char *fld[] = {"Ucont"};
141 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fld)); /* global->local + periodic */
142 }
143 PetscCall(ComputeRHS(user, Rhs)); /* Contra2Cart + Convection + mapping */
144 PetscCall(DMDAVecGetArrayRead(user->fda, Rhs, &r));
145 for (PetscInt m = 0; m < map->n; m++)
146 Ract[m] = CmpGet(r[map->ck[m]][map->cj[m]][map->ci[m]], map->comp[m]);
147 PetscCall(DMDAVecRestoreArrayRead(user->fda, Rhs, &r));
148 PetscFunctionReturn(0);
149}
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode ComputeRHS(UserCtx *user, Vec Rhs)
Computes the Right-Hand Side (RHS) of the momentum equations.
Definition rhs.c:1100
static PetscReal CmpGet(Cmpnts c, PetscInt comp)
Vec Ucont
Definition variables.h:902
A 3D point or vector with PetscScalar components.
Definition variables.h:100
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PerturbDof()

static PetscErrorCode PerturbDof ( UserCtx user,
Vec  Ucont,
const DofMap map,
PetscInt  m,
PetscReal  delta 
)
static

Definition at line 152 of file test_momentum_convective_candidates.c.

153{
154 Cmpnts ***a;
155 PetscFunctionBeginUser;
156 PetscCall(DMDAVecGetArray(user->fda, Ucont, &a));
157 { PetscReal *p = (PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]]; p[map->comp[m]] += delta; }
158 PetscCall(DMDAVecRestoreArray(user->fda, Ucont, &a));
159 PetscFunctionReturn(0);
160}
Here is the caller graph for this function:

◆ GetDof()

static PetscErrorCode GetDof ( UserCtx user,
Vec  Ucont,
const DofMap map,
PetscInt  m,
PetscReal *  val 
)
static

Reads one active contravariant component from a global vector.

Definition at line 165 of file test_momentum_convective_candidates.c.

166{
167 Cmpnts ***a;
168 PetscFunctionBeginUser;
169 PetscCall(DMDAVecGetArray(user->fda, Ucont, &a));
170 { const PetscReal *p = (const PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]]; *val = p[map->comp[m]]; }
171 PetscCall(DMDAVecRestoreArray(user->fda, Ucont, &a));
172 PetscFunctionReturn(0);
173}
Here is the caller graph for this function:

◆ PeriodicCellAngle()

static PetscReal PeriodicCellAngle ( PetscInt  idx,
PetscInt  npts 
)
inlinestatic

Returns the cell-centered periodic angle using duplicated endpoint planes.

Definition at line 183 of file test_momentum_convective_candidates.c.

184{
185 const PetscInt nuniq = npts - 1;
186 const PetscInt ip = (idx == npts - 1) ? 0 : idx;
187 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
188}
Here is the caller graph for this function:

◆ PeriodicFaceAngle()

static PetscReal PeriodicFaceAngle ( PetscInt  idx,
PetscInt  npts 
)
inlinestatic

Returns a face-representative periodic angle for component-staggered Ucont.

Definition at line 193 of file test_momentum_convective_candidates.c.

194{
195 const PetscInt nuniq = PeriodicRepCount(npts);
196 PetscInt ip = idx - 1;
197 if (idx == 0) ip = nuniq - 1;
198 else if (idx == npts - 1) ip = 0;
199 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
200}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AnalyticVelocity()

static Cmpnts AnalyticVelocity ( CandState  st,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscInt  mx,
PetscInt  my,
PetscInt  mz 
)
inlinestatic

Evaluates one of the three analytic Cartesian candidate states.

Definition at line 205 of file test_momentum_convective_candidates.c.

207{
208 Cmpnts v;
209 const PetscReal x = PeriodicCellAngle(i, mx);
210 const PetscReal y = PeriodicCellAngle(j, my);
211 (void)k; (void)mz;
212 if (st == STATE_A) {
213 v.x = 0.7; v.y = -0.4; v.z = 0.0;
214 } else if (st == STATE_B) {
215 (void)x; v.x = 0.0; v.y = 0.0; v.z = 0.0;
216 } else {
217 v.x = 1.0 + 0.5*PetscSinReal(y); v.y = 0.0; v.z = 0.0;
218 }
219 return v;
220}
static PetscReal PeriodicCellAngle(PetscInt idx, PetscInt npts)
Returns the cell-centered periodic angle using duplicated endpoint planes.
PetscScalar x
Definition variables.h:101
PetscScalar z
Definition variables.h:101
PetscScalar y
Definition variables.h:101
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DirectUcontVelocity()

static Cmpnts DirectUcontVelocity ( CandState  st,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscInt  mx,
PetscInt  my,
PetscInt  mz 
)
inlinestatic

Evaluates the declared direct component-staggered State B Ucont field.

Definition at line 225 of file test_momentum_convective_candidates.c.

227{
228 Cmpnts v = {0.0, 0.0, 0.0};
229 (void)j; (void)k; (void)my; (void)mz;
230 if (st == STATE_B) v.x = PetscSinReal(PeriodicFaceAngle(i, mx));
231 return v;
232}
static PetscReal PeriodicFaceAngle(PetscInt idx, PetscInt npts)
Returns a face-representative periodic angle for component-staggered Ucont.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CmpDiffInf()

static PetscReal CmpDiffInf ( Cmpnts  a,
Cmpnts  b 
)
inlinestatic

Computes the componentwise infinity norm of the difference between two vectors.

Definition at line 237 of file test_momentum_convective_candidates.c.

238{
239 return PetscMax(PetscAbsReal(a.x-b.x), PetscMax(PetscAbsReal(a.y-b.y), PetscAbsReal(a.z-b.z)));
240}
Here is the caller graph for this function:

◆ ComputeDeclaredSeamMismatch()

static PetscErrorCode ComputeDeclaredSeamMismatch ( CandState  st,
DMDALocalInfo  info,
PetscReal  seam[3] 
)
static

Computes analytic periodic seam mismatches for each coordinate direction.

Definition at line 245 of file test_momentum_convective_candidates.c.

246{
247 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
248 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
249 PetscFunctionBeginUser;
250 if (st == STATE_B) {
251 for (PetscInt k = 1; k < mz-1; k++)
252 for (PetscInt j = 1; j < my-1; j++) {
253 loc[0] = PetscMax(loc[0], CmpDiffInf(DirectUcontVelocity(st, 0, j, k, mx, my, mz),
254 DirectUcontVelocity(st, mx-2, j, k, mx, my, mz)));
255 loc[0] = PetscMax(loc[0], CmpDiffInf(DirectUcontVelocity(st, mx-1, j, k, mx, my, mz),
256 DirectUcontVelocity(st, 1, j, k, mx, my, mz)));
257 }
258 for (PetscInt k = 1; k < mz-1; k++)
259 for (PetscInt i = 1; i < mx-1; i++) {
260 loc[1] = PetscMax(loc[1], CmpDiffInf(DirectUcontVelocity(st, i, 0, k, mx, my, mz),
261 DirectUcontVelocity(st, i, my-2, k, mx, my, mz)));
262 loc[1] = PetscMax(loc[1], CmpDiffInf(DirectUcontVelocity(st, i, my-1, k, mx, my, mz),
263 DirectUcontVelocity(st, i, 1, k, mx, my, mz)));
264 }
265 for (PetscInt j = 1; j < my-1; j++)
266 for (PetscInt i = 1; i < mx-1; i++) {
267 loc[2] = PetscMax(loc[2], CmpDiffInf(DirectUcontVelocity(st, i, j, 0, mx, my, mz),
268 DirectUcontVelocity(st, i, j, mz-2, mx, my, mz)));
269 loc[2] = PetscMax(loc[2], CmpDiffInf(DirectUcontVelocity(st, i, j, mz-1, mx, my, mz),
270 DirectUcontVelocity(st, i, j, 1, mx, my, mz)));
271 }
272 } else {
273 for (PetscInt k = 0; k < mz; k++)
274 for (PetscInt j = 0; j < my; j++)
275 loc[0] = PetscMax(loc[0], CmpDiffInf(AnalyticVelocity(st, 0, j, k, mx, my, mz),
276 AnalyticVelocity(st, mx-1, j, k, mx, my, mz)));
277 for (PetscInt k = 0; k < mz; k++)
278 for (PetscInt i = 0; i < mx; i++)
279 loc[1] = PetscMax(loc[1], CmpDiffInf(AnalyticVelocity(st, i, 0, k, mx, my, mz),
280 AnalyticVelocity(st, i, my-1, k, mx, my, mz)));
281 for (PetscInt j = 0; j < my; j++)
282 for (PetscInt i = 0; i < mx; i++)
283 loc[2] = PetscMax(loc[2], CmpDiffInf(AnalyticVelocity(st, i, j, 0, mx, my, mz),
284 AnalyticVelocity(st, i, j, mz-1, mx, my, mz)));
285 }
286 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
287 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
288 PetscFunctionReturn(0);
289}
static Cmpnts DirectUcontVelocity(CandState st, PetscInt i, PetscInt j, PetscInt k, PetscInt mx, PetscInt my, PetscInt mz)
Evaluates the declared direct component-staggered State B Ucont field.
static PetscReal CmpDiffInf(Cmpnts a, Cmpnts b)
Computes the componentwise infinity norm of the difference between two vectors.
static Cmpnts AnalyticVelocity(CandState st, PetscInt i, PetscInt j, PetscInt k, PetscInt mx, PetscInt my, PetscInt mz)
Evaluates one of the three analytic Cartesian candidate states.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InGhostRange()

static PetscBool InGhostRange ( PetscInt  idx,
PetscInt  lo,
PetscInt  n 
)
inlinestatic

Reports whether a global index is present in a rank's local ghosted range.

Definition at line 294 of file test_momentum_convective_candidates.c.

295{ return (PetscBool)(idx >= lo && idx < lo + n); }

◆ ComputeLocalDuplicateMismatch()

static PetscErrorCode ComputeLocalDuplicateMismatch ( UserCtx user,
Vec  local,
PetscReal  seam[3] 
)
static

Computes duplicate-plane mismatch in a local vector view.

Definition at line 300 of file test_momentum_convective_candidates.c.

301{
302 DMDALocalInfo info = user->info;
303 Cmpnts ***a;
304 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
305 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
306 PetscFunctionBeginUser;
307 PetscCall(DMDAVecGetArrayRead(user->fda, local, &a));
308#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
309#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
310#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
311 if (HAVE_I(0) && HAVE_I(mx-2))
312 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
313 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
314 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][0], a[k][j][mx-2]));
315 if (HAVE_I(mx-1) && HAVE_I(1))
316 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
317 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
318 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][mx-1], a[k][j][1]));
319 if (HAVE_J(0) && HAVE_J(my-2))
320 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
321 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
322 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][0][i], a[k][my-2][i]));
323 if (HAVE_J(my-1) && HAVE_J(1))
324 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
325 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
326 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][my-1][i], a[k][1][i]));
327 if (HAVE_K(0) && HAVE_K(mz-2))
328 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
329 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
330 loc[2] = PetscMax(loc[2], CmpDiffInf(a[0][j][i], a[mz-2][j][i]));
331 if (HAVE_K(mz-1) && HAVE_K(1))
332 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
333 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
334 loc[2] = PetscMax(loc[2], CmpDiffInf(a[mz-1][j][i], a[1][j][i]));
335#undef HAVE_I
336#undef HAVE_J
337#undef HAVE_K
338 PetscCall(DMDAVecRestoreArrayRead(user->fda, local, &a));
339 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
340 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
341 PetscFunctionReturn(0);
342}
#define HAVE_I(ii)
#define HAVE_K(kk)
#define HAVE_J(jj)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeLocalOuterGhostMismatch()

static PetscErrorCode ComputeLocalOuterGhostMismatch ( UserCtx user,
Vec  local,
PetscReal  seam[3] 
)
static

Computes outer periodic ghost mismatch for local Ucat.

Definition at line 347 of file test_momentum_convective_candidates.c.

348{
349 DMDALocalInfo info = user->info;
350 Cmpnts ***a;
351 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
352 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
353 PetscFunctionBeginUser;
354 PetscCall(DMDAVecGetArrayRead(user->fda, local, &a));
355#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
356#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
357#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
358 if (HAVE_I(-1) && HAVE_I(1))
359 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
360 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
361 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][-1], a[k][j][1]));
362 if (HAVE_I(mx) && HAVE_I(mx-2))
363 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
364 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
365 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][mx], a[k][j][mx-2]));
366 if (HAVE_J(-1) && HAVE_J(1))
367 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
368 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
369 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][-1][i], a[k][1][i]));
370 if (HAVE_J(my) && HAVE_J(my-2))
371 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
372 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
373 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][my][i], a[k][my-2][i]));
374 if (HAVE_K(-1) && HAVE_K(1))
375 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
376 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
377 loc[2] = PetscMax(loc[2], CmpDiffInf(a[-1][j][i], a[1][j][i]));
378 if (HAVE_K(mz) && HAVE_K(mz-2))
379 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
380 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
381 loc[2] = PetscMax(loc[2], CmpDiffInf(a[mz][j][i], a[mz-2][j][i]));
382#undef HAVE_I
383#undef HAVE_J
384#undef HAVE_K
385 PetscCall(DMDAVecRestoreArrayRead(user->fda, local, &a));
386 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
387 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
388 PetscFunctionReturn(0);
389}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ConfigureCandidateFixture()

static PetscErrorCode ConfigureCandidateFixture ( SimCtx simCtx,
UserCtx user 
)
static

Configures the minimal context for centered inviscid periodic convection tests.

Definition at line 394 of file test_momentum_convective_candidates.c.

395{
396 PetscFunctionBeginUser;
397 for (int f = 0; f < 6; f++) user->boundary_faces[f].mathematical_type = PERIODIC;
398 simCtx->dt = 0.1; simCtx->step = 5; simCtx->StartStep = 0; /* BDF2 -> a0=1.5 */
399 simCtx->ren = 1.0e6; simCtx->invicid = 1; simCtx->les = 0; simCtx->rans = 0;
400 simCtx->central = 1; simCtx->clark = 0; simCtx->TwoD = 0; simCtx->block_number = 1;
401 simCtx->bulkVelocityCorrection = 0.0; simCtx->moveframe = 0; simCtx->rotateframe = 0;
402 if (!user->lNu_t) PetscCall(DMCreateLocalVector(user->da, &user->lNu_t));
403 PetscCall(VecSet(user->P, 0.0)); PetscCall(UpdateLocalGhosts(user, "P"));
404 PetscCall(VecSet(user->lNvert, 0.0)); PetscCall(VecSet(user->Nvert, 0.0));
405 PetscFunctionReturn(0);
406}
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1751
PetscInt clark
Definition variables.h:788
@ PERIODIC
Definition variables.h:290
PetscInt moveframe
Definition variables.h:714
PetscInt TwoD
Definition variables.h:714
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:894
PetscInt block_number
Definition variables.h:766
Vec lNvert
Definition variables.h:902
PetscInt rans
Definition variables.h:787
PetscReal ren
Definition variables.h:731
PetscReal dt
Definition variables.h:698
PetscReal bulkVelocityCorrection
Definition variables.h:779
PetscInt StartStep
Definition variables.h:693
PetscInt invicid
Definition variables.h:714
Vec lNu_t
Definition variables.h:933
PetscInt central
Definition variables.h:729
PetscInt step
Definition variables.h:691
PetscInt les
Definition variables.h:787
Vec Nvert
Definition variables.h:902
BCType mathematical_type
Definition variables.h:366
PetscInt rotateframe
Definition variables.h:714
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetUcatField()

static PetscErrorCode SetUcatField ( UserCtx user,
CandState  st 
)
static

Definition at line 409 of file test_momentum_convective_candidates.c.

410{
411 Cmpnts ***u;
412 DMDALocalInfo info = user->info;
413 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
414 PetscFunctionBeginUser;
415 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &u));
416 /* only owned region for a GLOBAL vec */
417 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
418 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
419 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
420 u[k][j][i] = AnalyticVelocity(st, i, j, k, mx, my, mz);
421 }
422 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &u));
423 PetscFunctionReturn(0);
424}
Vec Ucat
Definition variables.h:902
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetDirectUcontField()

static PetscErrorCode SetDirectUcontField ( UserCtx user,
CandState  st 
)
static

Sets the direct State B component-staggered Ucont field on owned entries.

Definition at line 429 of file test_momentum_convective_candidates.c.

430{
431 Cmpnts ***u;
432 DMDALocalInfo info = user->info;
433 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
434 PetscFunctionBeginUser;
435 PetscCall(VecSet(user->Ucont, 0.0));
436 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &u));
437 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
438 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
439 for (PetscInt i = info.xs; i < info.xs+info.xm; i++)
440 u[k][j][i] = DirectUcontVelocity(st, i, j, k, mx, my, mz);
441 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &u));
442 PetscFunctionReturn(0);
443}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeMaxDiscreteDivergence()

static PetscErrorCode ComputeMaxDiscreteDivergence ( UserCtx user,
PetscReal *  maxdiv 
)
static

Computes max discrete divergence of the current local Ucont field.

Definition at line 448 of file test_momentum_convective_candidates.c.

449{
450 DMDALocalInfo info = user->info;
451 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
452 Cmpnts ***uc;
453 PetscReal dv = 0.0, dv_global;
454 PetscFunctionBeginUser;
455 PetscCall(UpdateLocalGhosts(user, "Ucont"));
456 PetscCall(DMDAVecGetArrayRead(user->fda, user->lUcont, &uc));
457 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
458 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
459 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
460 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2) continue;
461 const PetscReal d = (uc[k][j][i].x - uc[k][j][i-1].x)
462 + (uc[k][j][i].y - uc[k][j-1][i].y)
463 + (uc[k][j][i].z - uc[k-1][j][i].z);
464 dv = PetscMax(dv, PetscAbsReal(d));
465 }
466 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lUcont, &uc));
467 PetscCallMPI(MPI_Allreduce(&dv, &dv_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
468 *maxdiv = dv_global;
469 PetscFunctionReturn(0);
470}
Vec lUcont
Definition variables.h:902
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildBaseState()

static PetscErrorCode BuildBaseState ( UserCtx user,
CandState  st,
Vec  Ubase,
PetscReal *  repeat_inf,
PetscReal *  maxdiv,
SeamDiagnostics seam 
)
static

Definition at line 474 of file test_momentum_convective_candidates.c.

477{
478 DMDALocalInfo info = user->info;
479 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
480 PetscReal err = 0.0, err_global;
481 Vec target;
482 Cmpnts ***ur, ***ut;
483 PetscFunctionBeginUser;
484
485 PetscCall(VecDuplicate(user->Ucat, &target));
486
487 if (seam) PetscCall(ComputeDeclaredSeamMismatch(st, info, seam->declared));
488
489 if (st == STATE_B) {
490 const char *ufld[] = {"Ucont"};
491 const char *cfld[] = {"Ucat"};
492 PetscCall(SetDirectUcontField(user, st));
493 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, ufld));
494 PetscCall(VecCopy(user->Ucont, Ubase));
495 if (seam) PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcont, seam->ucont_global));
496 PetscCall(Contra2Cart(user));
497 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
498 PetscCall(VecCopy(user->Ucat, target)); /* saved recovered Cartesian state */
499 PetscCall(Contra2Cart(user));
500 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
501 } else {
502 const char *cfld[] = {"Ucat"};
503 const char *ufld[] = {"Ucont"};
504 PetscCall(SetUcatField(user, st));
505 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
506 PetscCall(VecCopy(user->Ucat, target)); /* saved declared Cartesian state */
507 PetscCall(Cart2Contra(user)); /* global Ucont from lUcat + metrics */
508 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, ufld));
509 PetscCall(VecCopy(user->Ucont, Ubase));
510 if (seam) PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcont, seam->ucont_global));
511 PetscCall(Contra2Cart(user)); /* recovered Cartesian from Ucont */
512 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
513 }
514
515 if (seam) {
516 PetscCall(UpdateLocalGhosts(user, "Ucat"));
517 PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcat, seam->ucat_global));
518 PetscCall(ComputeLocalOuterGhostMismatch(user, user->lUcat, seam->ucat_ghost));
519 }
520
521 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucat, &ur));
522 PetscCall(DMDAVecGetArrayRead(user->fda, target, &ut));
523 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
524 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
525 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
526 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2) continue; /* interior cells only */
527 err = PetscMax(err, PetscAbsReal(ur[k][j][i].x - ut[k][j][i].x));
528 err = PetscMax(err, PetscAbsReal(ur[k][j][i].y - ut[k][j][i].y));
529 err = PetscMax(err, PetscAbsReal(ur[k][j][i].z - ut[k][j][i].z));
530 }
531 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucat, &ur));
532 PetscCall(DMDAVecRestoreArrayRead(user->fda, target, &ut));
533 PetscCall(VecDestroy(&target));
534 PetscCall(UpdateLocalGhosts(user, "Ucat")); /* lUcat now consistent with base Ucont */
535
536 PetscCallMPI(MPI_Allreduce(&err, &err_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
537 PetscCall(ComputeMaxDiscreteDivergence(user, maxdiv));
538 *repeat_inf = err_global;
539 PetscFunctionReturn(0);
540}
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
Definition setup.c:2742
PetscErrorCode Cart2Contra(UserCtx *user)
Convert the ghosted Cartesian velocity field to contravariant face fluxes.
Definition setup.c:2877
static PetscErrorCode ComputeDeclaredSeamMismatch(CandState st, DMDALocalInfo info, PetscReal seam[3])
Computes analytic periodic seam mismatches for each coordinate direction.
static PetscErrorCode ComputeLocalOuterGhostMismatch(UserCtx *user, Vec local, PetscReal seam[3])
Computes outer periodic ghost mismatch for local Ucat.
static PetscErrorCode SetUcatField(UserCtx *user, CandState st)
static PetscErrorCode ComputeMaxDiscreteDivergence(UserCtx *user, PetscReal *maxdiv)
Computes max discrete divergence of the current local Ucont field.
static PetscErrorCode SetDirectUcontField(UserCtx *user, CandState st)
Sets the direct State B component-staggered Ucont field on owned entries.
static PetscErrorCode ComputeLocalDuplicateMismatch(UserCtx *user, Vec local, PetscReal seam[3])
Computes duplicate-plane mismatch in a local vector view.
Vec lUcat
Definition variables.h:902
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeMaxGradientContribution()

static PetscErrorCode ComputeMaxGradientContribution ( UserCtx user,
PetscReal *  gradmax 
)
static

Computes the global maximum Cartesian velocity-gradient row-sum used by Candidate D.

Definition at line 545 of file test_momentum_convective_candidates.c.

546{
547 DMDALocalInfo info = user->info;
548 Cmpnts ***ucat, ***csi, ***eta, ***zet;
549 PetscReal ***aj;
550 PetscReal loc = 0.0, glo;
551 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
552 PetscFunctionBeginUser;
553 PetscCall(UpdateLocalGhosts(user, "Ucat"));
554 PetscCall(DMDAVecGetArrayRead(user->fda, user->lUcat, &ucat));
555 PetscCall(DMDAVecGetArrayRead(user->fda, user->lCsi, &csi));
556 PetscCall(DMDAVecGetArrayRead(user->fda, user->lEta, &eta));
557 PetscCall(DMDAVecGetArrayRead(user->fda, user->lZet, &zet));
558 PetscCall(DMDAVecGetArrayRead(user->da, user->lAj, &aj));
559 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
560 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
561 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
562 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2) continue;
563 const Cmpnts duc = { 0.5*(ucat[k][j][i+1].x-ucat[k][j][i-1].x),
564 0.5*(ucat[k][j][i+1].y-ucat[k][j][i-1].y),
565 0.5*(ucat[k][j][i+1].z-ucat[k][j][i-1].z) };
566 const Cmpnts due = { 0.5*(ucat[k][j+1][i].x-ucat[k][j-1][i].x),
567 0.5*(ucat[k][j+1][i].y-ucat[k][j-1][i].y),
568 0.5*(ucat[k][j+1][i].z-ucat[k][j-1][i].z) };
569 const Cmpnts duz = { 0.5*(ucat[k+1][j][i].x-ucat[k-1][j][i].x),
570 0.5*(ucat[k+1][j][i].y-ucat[k-1][j][i].y),
571 0.5*(ucat[k+1][j][i].z-ucat[k-1][j][i].z) };
572 const Cmpnts C = csi[k][j][i], E = eta[k][j][i], Z = zet[k][j][i];
573 const PetscReal Ajc = aj[k][j][i];
574#define ROWSUM(cmp) ( \
575 PetscAbsReal(Ajc*(C.x*duc.cmp + E.x*due.cmp + Z.x*duz.cmp)) + \
576 PetscAbsReal(Ajc*(C.y*duc.cmp + E.y*due.cmp + Z.y*duz.cmp)) + \
577 PetscAbsReal(Ajc*(C.z*duc.cmp + E.z*due.cmp + Z.z*duz.cmp)) )
578 loc = PetscMax(loc, PetscMax(ROWSUM(x), PetscMax(ROWSUM(y), ROWSUM(z))));
579#undef ROWSUM
580 }
581 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lAj, &aj));
582 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet));
583 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta));
584 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi));
585 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lUcat, &ucat));
586 PetscCallMPI(MPI_Allreduce(&loc, &glo, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
587 *gradmax = glo;
588 PetscFunctionReturn(0);
589}
#define ROWSUM(cmp)
Vec lZet
Definition variables.h:925
Vec lCsi
Definition variables.h:925
Vec lAj
Definition variables.h:925
Vec lEta
Definition variables.h:925
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DenseSpectralRadius()

static PetscErrorCode DenseSpectralRadius ( const PetscReal *  A,
PetscInt  n,
PetscReal *  rho,
PetscReal *  maxRealPart 
)
static

Definition at line 595 of file test_momentum_convective_candidates.c.

597{
598 PetscBLASInt N, lda, lwork, info;
599 PetscReal *Acopy, *wr, *wi, *work, dummy = 0.0;
600 PetscFunctionBeginUser;
601 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N;
602 PetscCall(PetscMalloc4(n*n, &Acopy, n, &wr, n, &wi, (size_t)lwork, &work));
603 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
604 {
605 char nochar = 'N';
606 LAPACKgeev_(&nochar, &nochar, &N, Acopy, &lda, wr, wi, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
607 }
608 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "LAPACK dgeev failed: info=%d", (int)info);
609 *rho = 0.0; *maxRealPart = -PETSC_MAX_REAL;
610 for (PetscInt t = 0; t < n; t++) {
611 *rho = PetscMax(*rho, PetscSqrtReal(wr[t]*wr[t] + wi[t]*wi[t]));
612 *maxRealPart = PetscMax(*maxRealPart, wr[t]);
613 }
614 PetscCall(PetscFree4(Acopy, wr, wi, work));
615 PetscFunctionReturn(0);
616}
Here is the caller graph for this function:

◆ DenseRKPolynomialSpectralRadius()

static PetscErrorCode DenseRKPolynomialSpectralRadius ( const PetscReal *  J,
PetscInt  n,
PetscReal  dtau,
PetscReal *  rho 
)
static

Computes the spectral radius of the RK polynomial by applying it to eig(J).

Definition at line 621 of file test_momentum_convective_candidates.c.

623{
624 PetscBLASInt N, lda, lwork, info;
625 PetscReal *Jcopy, *wr, *wi, *work, dummy = 0.0;
626 PetscFunctionBeginUser;
627 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N;
628 PetscCall(PetscMalloc4(n*n, &Jcopy, n, &wr, n, &wi, (size_t)lwork, &work));
629 for (PetscInt t = 0; t < n*n; t++) Jcopy[t] = J[t];
630 {
631 char nochar = 'N';
632 LAPACKgeev_(&nochar, &nochar, &N, Jcopy, &lda, wr, wi, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
633 }
634 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "LAPACK dgeev failed: info=%d", (int)info);
635 *rho = 0.0;
636 for (PetscInt t = 0; t < n; t++) {
637 const PetscReal zr = dtau*wr[t], zi = dtau*wi[t];
638 const PetscReal z2r = zr*zr - zi*zi, z2i = 2.0*zr*zi;
639 const PetscReal z3r = z2r*zr - z2i*zi, z3i = z2r*zi + z2i*zr;
640 const PetscReal z4r = z3r*zr - z3i*zi, z4i = z3r*zi + z3i*zr;
641 const PetscReal pr = 1.0 + zr + 0.5*z2r + z3r/6.0 + z4r/24.0;
642 const PetscReal pi = zi + 0.5*z2i + z3i/6.0 + z4i/24.0;
643 *rho = PetscMax(*rho, PetscSqrtReal(pr*pr + pi*pi));
644 }
645 PetscCall(PetscFree4(Jcopy, wr, wi, work));
646 PetscFunctionReturn(0);
647}
Here is the caller graph for this function:

◆ DenseSigmaMax()

static PetscErrorCode DenseSigmaMax ( const PetscReal *  A,
PetscInt  n,
PetscReal *  smax,
PetscReal *  v1 
)
static

Definition at line 650 of file test_momentum_convective_candidates.c.

651{
652 PetscBLASInt N, lda, lwork, info;
653 PetscReal *Acopy, *S, *VT, *work, ufake = 0.0;
654 PetscFunctionBeginUser;
655 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N + 4*N;
656 PetscCall(PetscMalloc4(n*n, &Acopy, n, &S, n*n, &VT, (size_t)lwork, &work));
657 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
658 {
659 char jobu = 'N', jobvt = v1 ? 'S' : 'N';
660 LAPACKgesvd_(&jobu, &jobvt, &N, &N, Acopy, &lda, S, &ufake, &lda, VT, &lda, work, &lwork, &info);
661 }
662 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "LAPACK dgesvd failed: info=%d", (int)info);
663 *smax = S[0];
664 if (v1) { for (PetscInt r = 0; r < n; r++) v1[r] = VT[0 + r*n]; } /* first row of VT = v1^T */
665 PetscCall(PetscFree4(Acopy, S, VT, work));
666 PetscFunctionReturn(0);
667}
Here is the caller graph for this function:

◆ DenseNonNormality()

static PetscReal DenseNonNormality ( const PetscReal *  A,
PetscInt  n 
)
static

Definition at line 670 of file test_momentum_convective_candidates.c.

671{
672 PetscReal fro2 = 0.0, comm = 0.0;
673 for (PetscInt t = 0; t < n*n; t++) fro2 += A[t]*A[t];
674 for (PetscInt p = 0; p < n; p++)
675 for (PetscInt q = 0; q < n; q++) {
676 PetscReal ata = 0.0, aat = 0.0;
677 for (PetscInt r = 0; r < n; r++) { ata += A[p + r*n]*A[q + r*n]; aat += A[r + p*n]*A[r + q*n]; }
678 const PetscReal d = ata - aat; comm += d*d;
679 }
680 return PetscSqrtReal(comm) / PetscMax(fro2, PETSC_MACHINE_EPSILON);
681}
Here is the caller graph for this function:

◆ DenseSkewnessDefect()

static PetscReal DenseSkewnessDefect ( const PetscReal *  A,
PetscInt  n 
)
static

Computes the normalized Frobenius defect from skew symmetry.

Definition at line 686 of file test_momentum_convective_candidates.c.

687{
688 PetscReal fro2 = 0.0, sym2 = 0.0;
689 for (PetscInt i = 0; i < n*n; i++) fro2 += A[i]*A[i];
690 for (PetscInt c = 0; c < n; c++)
691 for (PetscInt r = 0; r < n; r++) {
692 const PetscReal s = A[r + c*n] + A[c + r*n];
693 sym2 += s*s;
694 }
695 return PetscSqrtReal(sym2) / PetscMax(PetscSqrtReal(fro2), PETSC_MACHINE_EPSILON);
696}
Here is the caller graph for this function:

◆ DenseShiftIdentity()

static PetscErrorCode DenseShiftIdentity ( const PetscReal *  A,
PetscInt  n,
PetscReal  shift,
PetscReal *  B 
)
static

Copies a dense matrix and adds a scalar shift to its diagonal.

Definition at line 701 of file test_momentum_convective_candidates.c.

702{
703 PetscFunctionBeginUser;
704 PetscCall(PetscArraycpy(B, A, (size_t)n*n));
705 for (PetscInt d = 0; d < n; d++) B[d + d*n] += shift;
706 PetscFunctionReturn(0);
707}
Here is the caller graph for this function:

◆ MatMul()

static void MatMul ( const PetscReal *  A,
const PetscReal *  B,
PetscReal *  out,
PetscInt  n 
)
static

Definition at line 710 of file test_momentum_convective_candidates.c.

711{
712 for (PetscInt c = 0; c < n; c++)
713 for (PetscInt r = 0; r < n; r++) {
714 PetscReal s = 0.0;
715 for (PetscInt t = 0; t < n; t++) s += A[r + t*n]*B[t + c*n];
716 out[r + c*n] = s;
717 }
718}
Here is the caller graph for this function:

◆ RKPolynomial()

static PetscErrorCode RKPolynomial ( const PetscReal *  J,
PetscReal  dtau,
PetscInt  n,
PetscReal *  P 
)
static

Definition at line 721 of file test_momentum_convective_candidates.c.

722{
723 PetscReal *M, *T, *T2;
724 PetscFunctionBeginUser;
725 PetscCall(PetscMalloc3(n*n, &M, n*n, &T, n*n, &T2));
726 for (PetscInt t = 0; t < n*n; t++) M[t] = dtau*J[t];
727 /* start S = I + M/4 */
728 for (PetscInt t = 0; t < n*n; t++) T[t] = M[t]/4.0;
729 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0;
730 const PetscReal coef[3] = {3.0, 2.0, 1.0}; /* divide by 3, then 2, then 1 */
731 for (int s = 0; s < 3; s++) {
732 MatMul(M, T, T2, n); /* T2 = M*S */
733 for (PetscInt t = 0; t < n*n; t++) T[t] = T2[t]/coef[s];
734 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0; /* S = I + M/coef * S */
735 }
736 for (PetscInt t = 0; t < n*n; t++) P[t] = T[t];
737 PetscCall(PetscFree3(M, T, T2));
738 PetscFunctionReturn(0);
739}
static void MatMul(const PetscReal *A, const PetscReal *B, PetscReal *out, PetscInt n)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AmplificationMetric()

static PetscErrorCode AmplificationMetric ( const PetscReal *  J,
PetscInt  n,
PetscReal  dtau,
PMetric  which,
PetscReal *  metric 
)
static

Evaluates either spectral-radius or 2-norm amplification for one pseudo-time step.

Definition at line 746 of file test_momentum_convective_candidates.c.

748{
749 PetscReal *Pm;
750 PetscFunctionBeginUser;
751 if (which == METRIC_RHO) {
752 PetscCall(DenseRKPolynomialSpectralRadius(J, n, dtau, metric));
753 PetscFunctionReturn(0);
754 }
755 PetscCall(PetscMalloc1(n*n, &Pm));
756 PetscCall(RKPolynomial(J, dtau, n, Pm));
757 PetscCall(DenseSigmaMax(Pm, n, metric, NULL));
758 PetscCall(PetscFree(Pm));
759 PetscFunctionReturn(0);
760}
static PetscErrorCode DenseSigmaMax(const PetscReal *A, PetscInt n, PetscReal *smax, PetscReal *v1)
static PetscErrorCode RKPolynomial(const PetscReal *J, PetscReal dtau, PetscInt n, PetscReal *P)
static PetscErrorCode DenseRKPolynomialSpectralRadius(const PetscReal *J, PetscInt n, PetscReal dtau, PetscReal *rho)
Computes the spectral radius of the RK polynomial by applying it to eig(J).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ StableCFL()

static PetscErrorCode StableCFL ( const PetscReal *  J,
PetscInt  n,
PetscReal  lam,
PMetric  which,
StableCFLResult result 
)
static

Definition at line 763 of file test_momentum_convective_candidates.c.

765{
766 const PetscReal tol = 1e-8, probe = 1e-8, scan_step = 0.01, hi = 4.0;
767 const PetscReal probe_tol = 1e-12, min_positive_cfl = 1e-6;
768 PetscReal met;
769 PetscFunctionBeginUser;
770 result->status = STABLE_CFL_NONE;
771 result->cfl = 0.0;
772 if (which == METRIC_RHO) {
773 PetscReal rhoJ, maxreJ;
774 PetscCall(DenseSpectralRadius(J, n, &rhoJ, &maxreJ));
775 if (maxreJ > 1e-8) PetscFunctionReturn(0);
776 }
777 PetscCall(AmplificationMetric(J, n, probe/lam, which, &met));
778 if (met > 1.0 + probe_tol) PetscFunctionReturn(0);
779
780 PetscReal stable = probe, cross_b = -1.0;
781 for (PetscReal cfl = scan_step; cfl <= hi + 1e-12; cfl += scan_step) {
782 PetscCall(AmplificationMetric(J, n, cfl/lam, which, &met));
783 if (met > 1.0 + tol) { cross_b = cfl; break; }
784 stable = cfl;
785 }
786 if (cross_b < 0.0) {
788 result->cfl = hi;
789 PetscFunctionReturn(0);
790 }
791 PetscReal cross_a = stable;
792 for (int it = 0; it < 40; it++) {
793 const PetscReal mid = 0.5*(cross_a + cross_b);
794 PetscCall(AmplificationMetric(J, n, mid/lam, which, &met));
795 if (met > 1.0 + tol) cross_b = mid; else cross_a = mid;
796 }
797 if (cross_a < min_positive_cfl) PetscFunctionReturn(0);
798 result->status = STABLE_CFL_FINITE;
799 result->cfl = cross_a;
800 PetscFunctionReturn(0);
801}
static PetscErrorCode AmplificationMetric(const PetscReal *J, PetscInt n, PetscReal dtau, PMetric which, PetscReal *metric)
Evaluates either spectral-radius or 2-norm amplification for one pseudo-time step.
static PetscErrorCode DenseSpectralRadius(const PetscReal *A, PetscInt n, PetscReal *rho, PetscReal *maxRealPart)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ StableCFLStatusText()

static const char * StableCFLStatusText ( StableCFLResult  r)
static

Returns human-readable text for a stable-CFL search result.

Definition at line 806 of file test_momentum_convective_candidates.c.

807{
808 if (r.status == STABLE_CFL_NONE) return "no positive stable interval connected to zero";
809 if (r.status == STABLE_CFL_EXCEEDS_SCAN) return "stable through CFL >= 4.0";
810 return "stable CFL";
811}
Here is the caller graph for this function:

◆ PrintStableCFLLine()

static PetscErrorCode PrintStableCFLLine ( const char *  candidate,
StableCFLResult  eig,
StableCFLResult  norm 
)
static

Prints one candidate's eigenvalue and norm stable-CFL statuses.

Definition at line 816 of file test_momentum_convective_candidates.c.

819{
820 PetscFunctionBeginUser;
821 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " cand %s: eig %s", candidate, StableCFLStatusText(eig)));
822 if (eig.status == STABLE_CFL_FINITE) PetscCall(PetscPrintf(PETSC_COMM_WORLD, " = %.4f", (double)eig.cfl));
823 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " | norm %s", StableCFLStatusText(norm)));
824 if (norm.status == STABLE_CFL_FINITE) PetscCall(PetscPrintf(PETSC_COMM_WORLD, " = %.4f", (double)norm.cfl));
825 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n"));
826 PetscFunctionReturn(0);
827}
static const char * StableCFLStatusText(StableCFLResult r)
Returns human-readable text for a stable-CFL search result.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ApplyP()

static void ApplyP ( const PetscReal *  P,
const PetscReal *  x,
PetscReal *  out,
PetscInt  n 
)
static

Definition at line 830 of file test_momentum_convective_candidates.c.

831{
832 for (PetscInt r = 0; r < n; r++) { PetscReal s = 0.0; for (PetscInt c = 0; c < n; c++) s += P[r + c*n]*x[c]; out[r] = s; }
833}
Here is the caller graph for this function:

◆ PrintFrozenAmplificationTable()

static PetscErrorCode PrintFrozenAmplificationTable ( const char *  title,
const PetscReal *  J,
PetscInt  n,
const PetscReal  lams[3],
const char *  cn[3] 
)
static

Prints frozen RK amplification tables for the supplied operator and candidates.

Definition at line 838 of file test_momentum_convective_candidates.c.

841{
842 const PetscReal cfls[5] = {0.25, 0.50, 1.00, 1.50, 2.00};
843 PetscReal *Pm;
844 PetscFunctionBeginUser;
845 PetscCall(PetscMalloc1(n*n, &Pm));
846 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
847 " --- %s ---\n"
848 " candidate CFL dtau rho(P) sigma_max(P)\n", title));
849 for (int c = 0; c < 3; c++) {
850 if (!(lams[c] > 0.0)) continue;
851 for (int q = 0; q < 5; q++) {
852 const PetscReal dtau = cfls[q]/lams[c];
853 PetscReal rhoP, smaxP;
854 PetscCall(RKPolynomial(J, dtau, n, Pm));
855 PetscCall(DenseRKPolynomialSpectralRadius(J, n, dtau, &rhoP));
856 PetscCall(DenseSigmaMax(Pm, n, &smaxP, NULL));
857 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
858 " %-9s %.2f %.6e %.6e %.6e\n",
859 cn[c], (double)cfls[q], (double)dtau, (double)rhoP, (double)smaxP));
860 }
861 }
862 PetscCall(PetscFree(Pm));
863 PetscFunctionReturn(0);
864}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ VecNorm2Array()

static PetscReal VecNorm2Array ( const PetscReal *  x,
PetscInt  n 
)
static

Computes the Euclidean norm of a dense vector.

Definition at line 869 of file test_momentum_convective_candidates.c.

870{
871 PetscReal s = 0.0;
872 for (PetscInt i = 0; i < n; i++) s += x[i]*x[i];
873 return PetscSqrtReal(s);
874}
Here is the caller graph for this function:

◆ VecNormInfArray()

static PetscReal VecNormInfArray ( const PetscReal *  x,
PetscInt  n 
)
static

Computes the infinity norm of a dense vector.

Definition at line 879 of file test_momentum_convective_candidates.c.

880{
881 PetscReal s = 0.0;
882 for (PetscInt i = 0; i < n; i++) s = PetscMax(s, PetscAbsReal(x[i]));
883 return s;
884}
Here is the caller graph for this function:

◆ DenseFrobenius()

static PetscReal DenseFrobenius ( const PetscReal *  A,
PetscInt  n 
)
static

Computes the Frobenius norm of a dense column-major matrix.

Definition at line 889 of file test_momentum_convective_candidates.c.

890{
891 PetscReal s = 0.0;
892 for (PetscInt i = 0; i < n*n; i++) s += A[i]*A[i];
893 return PetscSqrtReal(s);
894}
Here is the caller graph for this function:

◆ DenseRelativeDiff()

static PetscReal DenseRelativeDiff ( const PetscReal *  A,
const PetscReal *  B,
PetscInt  n,
PetscReal  denom_ref 
)
static

Computes a normalized Frobenius difference between two dense matrices.

Definition at line 899 of file test_momentum_convective_candidates.c.

900{
901 PetscReal s = 0.0;
902 for (PetscInt i = 0; i < n*n; i++) {
903 const PetscReal d = A[i] - B[i];
904 s += d*d;
905 }
906 return PetscSqrtReal(s) / PetscMax(1.0, denom_ref);
907}
Here is the caller graph for this function:

◆ AddActiveVector()

static PetscErrorCode AddActiveVector ( UserCtx user,
Vec  U,
const DofMap map,
const PetscReal *  x,
PetscReal  scale 
)
static

Adds a dense active-space vector into a global contravariant vector.

Definition at line 912 of file test_momentum_convective_candidates.c.

914{
915 Cmpnts ***a;
916 PetscFunctionBeginUser;
917 PetscCall(DMDAVecGetArray(user->fda, U, &a));
918 for (PetscInt m = 0; m < map->n; m++) {
919 PetscReal *p = (PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]];
920 p[map->comp[m]] += scale*x[m];
921 }
922 PetscCall(DMDAVecRestoreArray(user->fda, U, &a));
923 PetscFunctionReturn(0);
924}
Here is the caller graph for this function:

◆ ExtractActiveVector()

static PetscErrorCode ExtractActiveVector ( UserCtx user,
Vec  U,
const DofMap map,
PetscReal *  x 
)
static

Extracts active-space entries from a global contravariant vector.

Definition at line 929 of file test_momentum_convective_candidates.c.

930{
931 Cmpnts ***a;
932 PetscFunctionBeginUser;
933 PetscCall(DMDAVecGetArrayRead(user->fda, U, &a));
934 for (PetscInt m = 0; m < map->n; m++) {
935 const PetscReal *p = (const PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]];
936 x[m] = p[map->comp[m]];
937 }
938 PetscCall(DMDAVecRestoreArrayRead(user->fda, U, &a));
939 PetscFunctionReturn(0);
940}
Here is the caller graph for this function:

◆ DofWeight()

static PetscReal DofWeight ( const DofMap map,
PetscInt  m 
)
static

Returns a deterministic checksum weight for an active DOF.

Definition at line 945 of file test_momentum_convective_candidates.c.

946{
947 return 1.0 + 0.013*(PetscReal)(map->comp[m]+1)
948 + 0.017*(PetscReal)map->ci[m]
949 + 0.019*(PetscReal)map->cj[m]
950 + 0.023*(PetscReal)map->ck[m];
951}
Here is the caller graph for this function:

◆ ActiveStats()

static PetscErrorCode ActiveStats ( const DofMap map,
const PetscReal *  x,
GlobalVecStats stats 
)
static

Computes global active-vector norms and checksum.

Definition at line 956 of file test_momentum_convective_candidates.c.

957{
958 PetscReal loc2 = 0.0, locinf = 0.0, locsum = 0.0;
959 PetscReal glo2, gloinf, glosum;
960 PetscFunctionBeginUser;
961 for (PetscInt m = 0; m < map->n; m++) {
962 loc2 += x[m]*x[m];
963 locinf = PetscMax(locinf, PetscAbsReal(x[m]));
964 locsum += DofWeight(map, m)*x[m];
965 }
966 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
967 PetscCallMPI(MPI_Allreduce(&locinf, &gloinf, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
968 PetscCallMPI(MPI_Allreduce(&locsum, &glosum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
969 stats->n2 = PetscSqrtReal(glo2); stats->ninf = gloinf; stats->checksum = glosum;
970 PetscFunctionReturn(0);
971}
static PetscReal DofWeight(const DofMap *map, PetscInt m)
Returns a deterministic checksum weight for an active DOF.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillDeterministicDirection()

static PetscErrorCode FillDeterministicDirection ( UserCtx user,
Vec  V,
const DofMap map,
PetscReal *  x 
)
static

Fills a globally normalized deterministic active-space perturbation direction.

Definition at line 976 of file test_momentum_convective_candidates.c.

977{
978 PetscReal loc2 = 0.0, glo2;
979 PetscFunctionBeginUser;
980 PetscCall(VecSet(V, 0.0));
981 for (PetscInt m = 0; m < map->n; m++) {
982 x[m] = PetscSinReal(0.37*(PetscReal)(map->ci[m]+1)
983 + 0.51*(PetscReal)(map->cj[m]+1)
984 + 0.73*(PetscReal)(map->ck[m]+1)
985 + 0.29*(PetscReal)(map->comp[m]+1));
986 loc2 += x[m]*x[m];
987 }
988 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
989 const PetscReal invn = 1.0/PetscSqrtReal(glo2);
990 for (PetscInt m = 0; m < map->n; m++) x[m] *= invn;
991 PetscCall(AddActiveVector(user, V, map, x, 1.0));
992 PetscFunctionReturn(0);
993}
static PetscErrorCode AddActiveVector(UserCtx *user, Vec U, const DofMap *map, const PetscReal *x, PetscReal scale)
Adds a dense active-space vector into a global contravariant vector.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FourStage()

static PetscErrorCode FourStage ( UserCtx user,
Vec  U0full,
PetscReal  dtau,
Vec  Rhs,
const DofMap map,
PetscReal *  Rscratch,
Vec  Uwork,
Vec  Uout 
)
static

Definition at line 999 of file test_momentum_convective_candidates.c.

1001{
1002 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1003 PetscFunctionBeginUser;
1004 PetscCall(VecCopy(U0full, Uwork)); /* stage state */
1005 for (int s = 0; s < 4; s++) {
1006 PetscCall(EvalConvResidual(user, Uwork, Rhs, map, Rscratch)); /* R(U^{(s)}) into active rows */
1007 PetscCall(VecCopy(U0full, Uout)); /* U^{(s+1)} = U0 + alfa*dtau*R */
1008 Cmpnts ***a;
1009 PetscCall(DMDAVecGetArray(user->fda, Uout, &a));
1010 for (PetscInt m = 0; m < map->n; m++) {
1011 PetscReal *p = (PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]];
1012 p[map->comp[m]] += alfa[s]*dtau*Rscratch[m];
1013 }
1014 PetscCall(DMDAVecRestoreArray(user->fda, Uout, &a));
1015 PetscCall(VecCopy(Uout, Uwork));
1016 }
1017 PetscFunctionReturn(0);
1018}
static PetscErrorCode EvalConvResidual(UserCtx *user, Vec Ucont_in, Vec Rhs, const DofMap *map, PetscReal *Ract)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetAnchoredStage()

static PetscErrorCode SetAnchoredStage ( UserCtx user,
Vec  U0full,
PetscReal  scale,
const DofMap map,
const PetscReal *  Ract,
Vec  Ustage 
)
static

Forms one anchored RK stage state from the base state and active residual.

Definition at line 1023 of file test_momentum_convective_candidates.c.

1025{
1026 PetscFunctionBeginUser;
1027 PetscCall(VecCopy(U0full, Ustage));
1028 PetscCall(AddActiveVector(user, Ustage, map, Ract, scale));
1029 PetscFunctionReturn(0);
1030}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildStageStates()

static PetscErrorCode BuildStageStates ( UserCtx user,
Vec  U0full,
PetscReal  dtau,
Vec  Rhs,
const DofMap map,
PetscReal *  Rscratch,
Vec  Y1,
Vec  Y2,
Vec  Y3 
)
static

Builds the first three anchored RK stage states for a base vector.

Definition at line 1035 of file test_momentum_convective_candidates.c.

1038{
1039 const PetscReal alfa[3] = {0.25, 1.0/3.0, 0.5};
1040 PetscFunctionBeginUser;
1041 PetscCall(EvalConvResidual(user, U0full, Rhs, map, Rscratch));
1042 PetscCall(SetAnchoredStage(user, U0full, alfa[0]*dtau, map, Rscratch, Y1));
1043 PetscCall(EvalConvResidual(user, Y1, Rhs, map, Rscratch));
1044 PetscCall(SetAnchoredStage(user, U0full, alfa[1]*dtau, map, Rscratch, Y2));
1045 PetscCall(EvalConvResidual(user, Y2, Rhs, map, Rscratch));
1046 PetscCall(SetAnchoredStage(user, U0full, alfa[2]*dtau, map, Rscratch, Y3));
1047 PetscFunctionReturn(0);
1048}
static PetscErrorCode SetAnchoredStage(UserCtx *user, Vec U0full, PetscReal scale, const DofMap *map, const PetscReal *Ract, Vec Ustage)
Forms one anchored RK stage state from the base state and active residual.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildFDJacobian()

static PetscErrorCode BuildFDJacobian ( UserCtx user,
Vec  Ucenter,
PetscReal  epsrel,
Vec  Rhs,
const DofMap map,
PetscReal *  Rp,
PetscReal *  Rm,
Vec  Uwork,
PetscReal *  J 
)
static

Builds a centered finite-difference Jacobian of the production convective residual.

Definition at line 1053 of file test_momentum_convective_candidates.c.

1056{
1057 PetscFunctionBeginUser;
1058 for (PetscInt col = 0; col < map->n; col++) {
1059 PetscReal u0;
1060 PetscCall(GetDof(user, Ucenter, map, col, &u0));
1061 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1062 PetscCall(VecCopy(Ucenter, Uwork));
1063 PetscCall(PerturbDof(user, Uwork, map, col, +eps));
1064 PetscCall(EvalConvResidual(user, Uwork, Rhs, map, Rp));
1065 PetscCall(VecCopy(Ucenter, Uwork));
1066 PetscCall(PerturbDof(user, Uwork, map, col, -eps));
1067 PetscCall(EvalConvResidual(user, Uwork, Rhs, map, Rm));
1068 for (PetscInt row = 0; row < map->n; row++) J[row + col*map->n] = (Rp[row]-Rm[row])/(2.0*eps);
1069 }
1070 PetscFunctionReturn(0);
1071}
static PetscErrorCode GetDof(UserCtx *user, Vec Ucont, const DofMap *map, PetscInt m, PetscReal *val)
Reads one active contravariant component from a global vector.
static PetscErrorCode PerturbDof(UserCtx *user, Vec Ucont, const DofMap *map, PetscInt m, PetscReal delta)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildStageTangent()

static PetscErrorCode BuildStageTangent ( const PetscReal *  J0,
const PetscReal *  J1,
const PetscReal *  J2,
const PetscReal *  J3,
PetscReal  dtau,
PetscInt  n,
PetscReal *  T4 
)
static

Builds the exact four-stage tangent from stage-dependent Jacobians.

Definition at line 1076 of file test_momentum_convective_candidates.c.

1079{
1080 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1081 PetscReal *T1, *T2, *T3, *Tmp;
1082 PetscFunctionBeginUser;
1083 PetscCall(PetscMalloc4(n*n, &T1, n*n, &T2, n*n, &T3, n*n, &Tmp));
1084
1085 for (PetscInt i = 0; i < n*n; i++) T1[i] = alfa[0]*dtau*J0[i];
1086 for (PetscInt d = 0; d < n; d++) T1[d + d*n] += 1.0;
1087
1088 MatMul(J1, T1, Tmp, n);
1089 for (PetscInt i = 0; i < n*n; i++) T2[i] = alfa[1]*dtau*Tmp[i];
1090 for (PetscInt d = 0; d < n; d++) T2[d + d*n] += 1.0;
1091
1092 MatMul(J2, T2, Tmp, n);
1093 for (PetscInt i = 0; i < n*n; i++) T3[i] = alfa[2]*dtau*Tmp[i];
1094 for (PetscInt d = 0; d < n; d++) T3[d + d*n] += 1.0;
1095
1096 MatMul(J3, T3, Tmp, n);
1097 for (PetscInt i = 0; i < n*n; i++) T4[i] = alfa[3]*dtau*Tmp[i];
1098 for (PetscInt d = 0; d < n; d++) T4[d + d*n] += 1.0;
1099
1100 PetscCall(PetscFree4(T1, T2, T3, Tmp));
1101 PetscFunctionReturn(0);
1102}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildPhiJacobian()

static PetscErrorCode BuildPhiJacobian ( UserCtx user,
Vec  Ucenter,
PetscReal  dtau,
Vec  Rhs,
const DofMap map,
PetscReal *  Rscratch,
Vec  Upert,
Vec  Ustage,
Vec  PhiP,
Vec  PhiM,
PetscReal *  xp,
PetscReal *  xm,
PetscReal  epsrel,
PetscReal *  JPhi 
)
static

Builds a finite-difference Jacobian of the complete nonlinear four-stage map.

Definition at line 1107 of file test_momentum_convective_candidates.c.

1112{
1113 PetscFunctionBeginUser;
1114 for (PetscInt col = 0; col < map->n; col++) {
1115 PetscReal u0;
1116 PetscCall(GetDof(user, Ucenter, map, col, &u0));
1117 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1118 PetscCall(VecCopy(Ucenter, Upert));
1119 PetscCall(PerturbDof(user, Upert, map, col, +eps));
1120 PetscCall(FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiP));
1121 PetscCall(VecCopy(Ucenter, Upert));
1122 PetscCall(PerturbDof(user, Upert, map, col, -eps));
1123 PetscCall(FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiM));
1124 PetscCall(ExtractActiveVector(user, PhiP, map, xp));
1125 PetscCall(ExtractActiveVector(user, PhiM, map, xm));
1126 for (PetscInt row = 0; row < map->n; row++) JPhi[row + col*map->n] = (xp[row]-xm[row])/(2.0*eps);
1127 }
1128 PetscFunctionReturn(0);
1129}
static PetscErrorCode ExtractActiveVector(UserCtx *user, Vec U, const DofMap *map, PetscReal *x)
Extracts active-space entries from a global contravariant vector.
static PetscErrorCode FourStage(UserCtx *user, Vec U0full, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Uwork, Vec Uout)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RunRKTangentDiagnostics()

static PetscErrorCode RunRKTangentDiagnostics ( UserCtx user,
CandState  st,
Vec  Ubase,
Vec  Rhs,
const DofMap map,
PetscReal  epsrel,
const PetscReal  lams[3],
const char *  cn[3],
const PetscReal *  J0 
)
static

Runs stage-dependent RK tangent and direct nonlinear perturbation diagnostics.

Definition at line 1134 of file test_momentum_convective_candidates.c.

1138{
1139 const PetscReal cflsB[4] = {0.1, 0.25, 0.5, 1.0};
1140 const PetscReal cflsOther[1] = {0.5};
1141 const PetscReal *cfls = (st == STATE_B) ? cflsB : cflsOther;
1142 const PetscInt ncfl = (st == STATE_B) ? 4 : 1;
1143 const PetscReal amps[3] = {1e-4, 1e-5, 1e-6};
1144 Vec Y1, Y2, Y3, Upert, Ustage, PhiP, PhiM, Phi0;
1145 PetscReal *Rtmp, *J1, *J2, *J3, *T4, *Pm, *JPhi, *v1, *xrand;
1146 PetscReal *meas, *phi0, *phip, *xscaled, *predP, *predT;
1147 PetscFunctionBeginUser;
1148
1149 PetscCall(VecDuplicate(Ubase, &Y1));
1150 PetscCall(VecDuplicate(Ubase, &Y2));
1151 PetscCall(VecDuplicate(Ubase, &Y3));
1152 PetscCall(VecDuplicate(Ubase, &Upert));
1153 PetscCall(VecDuplicate(Ubase, &Ustage));
1154 PetscCall(VecDuplicate(Ubase, &PhiP));
1155 PetscCall(VecDuplicate(Ubase, &PhiM));
1156 PetscCall(VecDuplicate(Ubase, &Phi0));
1157 PetscCall(PetscMalloc5(map->n, &Rtmp, (size_t)map->n*map->n, &J1,
1158 (size_t)map->n*map->n, &J2, (size_t)map->n*map->n, &J3,
1159 (size_t)map->n*map->n, &T4));
1160 PetscCall(PetscMalloc5((size_t)map->n*map->n, &Pm, (size_t)map->n*map->n, &JPhi,
1161 map->n, &v1, map->n, &xrand, map->n, &meas));
1162 PetscCall(PetscMalloc5(map->n, &phi0, map->n, &phip, map->n, &xscaled,
1163 map->n, &predP, map->n, &predT));
1164
1165 PetscReal nrm = 0.0;
1166 for (PetscInt m = 0; m < map->n; m++) {
1167 xrand[m] = PetscSinReal((PetscReal)(m+1)*1.2345);
1168 nrm += xrand[m]*xrand[m];
1169 }
1170 nrm = PetscSqrtReal(nrm);
1171 for (PetscInt m = 0; m < map->n; m++) xrand[m] /= nrm;
1172
1173 for (int cand = 0; cand < 3; cand++) {
1174 if (!(lams[cand] > 0.0)) continue;
1175 for (PetscInt icfl = 0; icfl < ncfl; icfl++) {
1176 const PetscReal cfl = cfls[icfl], dtau = cfl/lams[cand];
1177 PetscCall(BuildStageStates(user, Ubase, dtau, Rhs, map, Rtmp, Y1, Y2, Y3));
1178 PetscCall(BuildFDJacobian(user, Y1, epsrel, Rhs, map, phi0, phip, Upert, J1));
1179 PetscCall(BuildFDJacobian(user, Y2, epsrel, Rhs, map, phi0, phip, Upert, J2));
1180 PetscCall(BuildFDJacobian(user, Y3, epsrel, Rhs, map, phi0, phip, Upert, J3));
1181 PetscCall(BuildStageTangent(J0, J1, J2, J3, dtau, map->n, T4));
1182 PetscCall(RKPolynomial(J0, dtau, map->n, Pm));
1183 PetscCall(BuildPhiJacobian(user, Ubase, dtau, Rhs, map, Rtmp,
1184 Upert, Ustage, PhiP, PhiM, phip, phi0, epsrel, JPhi));
1185
1186 const PetscReal froT = DenseFrobenius(T4, map->n);
1187 const PetscReal froPhi = DenseFrobenius(JPhi, map->n);
1188 const PetscReal relTP = DenseRelativeDiff(T4, Pm, map->n, froT);
1189 const PetscReal relPhiT = DenseRelativeDiff(JPhi, T4, map->n, froPhi);
1190 const PetscReal relPhiP = DenseRelativeDiff(JPhi, Pm, map->n, froPhi);
1191 PetscReal smaxT, rhoT, dummyT;
1192 PetscCall(DenseSpectralRadius(T4, map->n, &rhoT, &dummyT));
1193 PetscCall(DenseSigmaMax(T4, map->n, &smaxT, v1));
1194
1195 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1196 " --- convection-only stage-dependent RK tangent (cand %s, CFL=%.2f, dtau=%.6e) ---\n"
1197 " rho(T4)=%.6e sigma_max(T4)=%.6e\n"
1198 " ||T4-P(hJ0)||F/max(1,||T4||F) = %.3e\n"
1199 " ||J_Phi-T4||F/max(1,||J_Phi||F) = %.3e\n"
1200 " ||J_Phi-P(hJ0)||F/max(1,||J_Phi||F)= %.3e\n",
1201 cn[cand], (double)cfl, (double)dtau, (double)rhoT, (double)smaxT,
1202 (double)relTP, (double)relPhiT, (double)relPhiP));
1203
1204 PetscCall(FourStage(user, Ubase, dtau, Rhs, map, Rtmp, Ustage, Phi0));
1205 PetscCall(ExtractActiveVector(user, Phi0, map, phi0));
1206 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1207 " direction amp amp(meas) amp(frozen) amp(stage) err(frozen) err(stage)\n"));
1208 for (int dir = 0; dir < 2; dir++) {
1209 const PetscReal *xv = (dir == 0) ? xrand : v1;
1210 const char *dname = (dir == 0) ? "random" : "v1(T4)";
1211 for (int a = 0; a < 3; a++) {
1212 const PetscReal amp = amps[a];
1213 PetscCall(VecCopy(Ubase, Upert));
1214 PetscCall(AddActiveVector(user, Upert, map, xv, amp));
1215 PetscCall(FourStage(user, Upert, dtau, Rhs, map, Rtmp, Ustage, PhiP));
1216 PetscCall(ExtractActiveVector(user, PhiP, map, phip));
1217 for (PetscInt m = 0; m < map->n; m++) meas[m] = phip[m] - phi0[m];
1218 for (PetscInt m = 0; m < map->n; m++) xscaled[m] = amp*xv[m];
1219 ApplyP(Pm, xscaled, predP, map->n);
1220 ApplyP(T4, xscaled, predT, map->n);
1221
1222 PetscReal eP = 0.0, eT = 0.0;
1223 for (PetscInt m = 0; m < map->n; m++) {
1224 const PetscReal dP = meas[m] - predP[m];
1225 const PetscReal dT = meas[m] - predT[m];
1226 eP += dP*dP; eT += dT*dT;
1227 }
1228 const PetscReal nm = VecNorm2Array(meas, map->n);
1229 const PetscReal nP = VecNorm2Array(predP, map->n);
1230 const PetscReal nT = VecNorm2Array(predT, map->n);
1231 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1232 " %-8s %.0e %.6e %.6e %.6e %.3e %.3e\n",
1233 dname, (double)amp, (double)(nm/amp), (double)(nP/amp), (double)(nT/amp),
1234 (double)(PetscSqrtReal(eP)/PetscMax(PETSC_MACHINE_EPSILON, nP)),
1235 (double)(PetscSqrtReal(eT)/PetscMax(PETSC_MACHINE_EPSILON, nT))));
1236 }
1237 }
1238
1239 PetscCall(PicurvAssertBool((PetscBool)(relPhiT < 1e-6),
1240 "stage tangent matches direct finite-difference RK map"));
1241 if (st == STATE_B) {
1242 PetscCall(PicurvAssertBool((PetscBool)(relTP > 1e-5),
1243 "B: non-steady base makes frozen-Jacobian RK map measurably different"));
1244 PetscCall(PicurvAssertBool((PetscBool)(relPhiP > 1e-5),
1245 "B: direct RK map confirms frozen-Jacobian error"));
1246 } else {
1247 PetscCall(PicurvAssertBool((PetscBool)(relTP < 1e-8),
1248 "steady base reduces stage tangent to frozen RK polynomial"));
1249 }
1250 }
1251 }
1252
1253 PetscCall(PetscFree5(Rtmp, J1, J2, J3, T4));
1254 PetscCall(PetscFree5(Pm, JPhi, v1, xrand, meas));
1255 PetscCall(PetscFree5(phi0, phip, xscaled, predP, predT));
1256 PetscCall(VecDestroy(&Y1)); PetscCall(VecDestroy(&Y2)); PetscCall(VecDestroy(&Y3));
1257 PetscCall(VecDestroy(&Upert)); PetscCall(VecDestroy(&Ustage));
1258 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Phi0));
1259 PetscFunctionReturn(0);
1260}
static PetscReal VecNorm2Array(const PetscReal *x, PetscInt n)
Computes the Euclidean norm of a dense vector.
static PetscReal DenseRelativeDiff(const PetscReal *A, const PetscReal *B, PetscInt n, PetscReal denom_ref)
Computes a normalized Frobenius difference between two dense matrices.
static PetscReal DenseFrobenius(const PetscReal *A, PetscInt n)
Computes the Frobenius norm of a dense column-major matrix.
static PetscErrorCode BuildStageTangent(const PetscReal *J0, const PetscReal *J1, const PetscReal *J2, const PetscReal *J3, PetscReal dtau, PetscInt n, PetscReal *T4)
Builds the exact four-stage tangent from stage-dependent Jacobians.
static PetscErrorCode BuildFDJacobian(UserCtx *user, Vec Ucenter, PetscReal epsrel, Vec Rhs, const DofMap *map, PetscReal *Rp, PetscReal *Rm, Vec Uwork, PetscReal *J)
Builds a centered finite-difference Jacobian of the production convective residual.
static void ApplyP(const PetscReal *P, const PetscReal *x, PetscReal *out, PetscInt n)
static PetscErrorCode BuildStageStates(UserCtx *user, Vec U0full, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Y1, Vec Y2, Vec Y3)
Builds the first three anchored RK stage states for a base vector.
static PetscErrorCode BuildPhiJacobian(UserCtx *user, Vec Ucenter, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Upert, Vec Ustage, Vec PhiP, Vec PhiM, PetscReal *xp, PetscReal *xm, PetscReal epsrel, PetscReal *JPhi)
Builds a finite-difference Jacobian of the complete nonlinear four-stage map.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RunState()

static PetscErrorCode RunState ( CandState  st,
const char *  name 
)
static

Definition at line 1265 of file test_momentum_convective_candidates.c.

1266{
1267 SimCtx *simCtx = NULL; UserCtx *user = NULL; DofMap map;
1268 Vec Ubase, Rhs, Uwork, Uout;
1269 PetscReal *Rref, *Rrep, *Jbest;
1270 PetscReal repeat_err, maxdiv, det_err;
1271 SeamDiagnostics seam;
1273 const PetscInt N = (st == STATE_C) ? 5 : 4; /* C uses one extra point for canonical shear. */
1274 PetscFunctionBeginUser;
1275
1276 /* periodic Cartesian fixture, inviscid + centered + P=0, no LES/RANS/Clark/IB/body force. */
1277 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, N, N, N, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
1278 PetscCall(ConfigureCandidateFixture(simCtx, user));
1279
1280 PetscCall(DofMapBuild(user, &map));
1281 PetscCall(VecDuplicate(user->Ucont, &Ubase));
1282 PetscCall(VecDuplicate(user->Ucont, &Rhs));
1283 PetscCall(VecDuplicate(user->Ucont, &Uwork));
1284 PetscCall(VecDuplicate(user->Ucont, &Uout));
1285 PetscCall(PetscMalloc3(map.n, &Rref, map.n, &Rrep, (size_t)map.n*map.n, &Jbest));
1286
1287 PetscCall(BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
1288
1289 /* residual determinism: evaluate the base residual twice. */
1290 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, Rref));
1291 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, Rrep));
1292 det_err = 0.0; for (PetscInt m = 0; m < map.n; m++) det_err = PetscMax(det_err, PetscAbsReal(Rref[m]-Rrep[m]));
1293 const PetscReal R0_2 = VecNorm2Array(Rref, map.n);
1294 const PetscReal R0_inf = VecNormInfArray(Rref, map.n);
1295
1296 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1297 "\n================ STATE %s ================\n"
1298 " grid: DMDA %d^3 (periodic) | independent face DOFs: actual=%d expected=%d\n"
1299 " declared endpoint mismatch (x,y,z) = %.3e %.3e %.3e\n"
1300 " actual Ucat duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
1301 " local lUcat ghost mismatch (x,y,z) = %.3e %.3e %.3e\n"
1302 " actual Ucont duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
1303 " ||Ucat_repeat - Ucat_reference||inf = %.3e\n"
1304 " max|div_h Ucont| = %.3e\n"
1305 " ||R(U0)||2 = %.6e ||R(U0)||inf = %.6e\n"
1306 " residual determinism ||R_rep-R_ref||inf = %.3e\n",
1307 name, (int)(N+1), (int)map.n,
1308 (int)map.expected_n,
1309 (double)seam.declared[0], (double)seam.declared[1], (double)seam.declared[2],
1310 (double)seam.ucat_global[0], (double)seam.ucat_global[1], (double)seam.ucat_global[2],
1311 (double)seam.ucat_ghost[0], (double)seam.ucat_ghost[1], (double)seam.ucat_ghost[2],
1312 (double)seam.ucont_global[0], (double)seam.ucont_global[1], (double)seam.ucont_global[2],
1313 (double)repeat_err, (double)maxdiv,
1314 (double)R0_2, (double)R0_inf, (double)det_err));
1315
1316 /* ---- epsilon-convergence study: build J at several eps, compare to next-finer ---- */
1317 const PetscReal epsrel[5] = {1e-4, 1e-5, 1e-6, 1e-7, 1e-8};
1318 PetscReal *Jprev, *Jcur;
1319 PetscCall(PetscMalloc2((size_t)map.n*map.n, &Jprev, (size_t)map.n*map.n, &Jcur));
1320 PetscReal best_rel = PETSC_MAX_REAL; PetscInt best_e = 2;
1321 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " epsilon-convergence (||J_e - J_e/10||_F / ||J||_F):\n"));
1322 for (int e = 0; e < 5; e++) {
1323 /* build column-major J at epsrel[e] */
1324 for (PetscInt col = 0; col < map.n; col++) {
1325 PetscReal u0; PetscCall(GetDof(user, Ubase, &map, col, &u0));
1326 const PetscReal eps = epsrel[e]*PetscMax(1.0, PetscAbsReal(u0));
1327 PetscReal *Rp = Rref, *Rm = Rrep; /* reuse scratch */
1328 PetscCall(VecCopy(Ubase, Uwork));
1329 PetscCall(PerturbDof(user, Uwork, &map, col, +eps));
1330 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rp));
1331 PetscCall(VecCopy(Ubase, Uwork));
1332 PetscCall(PerturbDof(user, Uwork, &map, col, -eps));
1333 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rm));
1334 for (PetscInt row = 0; row < map.n; row++) Jcur[row + col*map.n] = (Rp[row]-Rm[row])/(2.0*eps);
1335 }
1336 if (e > 0) {
1337 PetscReal num = 0.0, den = 0.0;
1338 for (PetscInt t = 0; t < map.n*map.n; t++) { const PetscReal d = Jprev[t]-Jcur[t]; num += d*d; den += Jcur[t]*Jcur[t]; }
1339 const PetscReal rel = PetscSqrtReal(num)/PetscMax(1.0, PetscSqrtReal(den));
1340 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " eps=%.0e -> %.0e : rel=%.3e\n",
1341 (double)epsrel[e-1], (double)epsrel[e], (double)rel));
1342 if (rel < best_rel) { best_rel = rel; best_e = e; }
1343 }
1344 if (st == STATE_A) {
1345 PetscReal erho, emaxre, esmax;
1346 PetscCall(DenseSpectralRadius(Jcur, map.n, &erho, &emaxre));
1347 PetscCall(DenseSigmaMax(Jcur, map.n, &esmax, NULL));
1348 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1349 " eps=%.0e metrics: rho=%.6e sigma=%.6e max_real=%.6e fro=%.6e skew=%.3e\n",
1350 (double)epsrel[e], (double)erho, (double)esmax, (double)emaxre,
1351 (double)DenseFrobenius(Jcur, map.n), (double)DenseSkewnessDefect(Jcur, map.n)));
1352 }
1353 PetscCall(PetscArraycpy(Jprev, Jcur, (size_t)map.n*map.n)); /* prev <- current (no pointer swap) */
1354 }
1355 /* rebuild J at the plateau epsilon into Jbest */
1356 {
1357 const PetscReal er = epsrel[best_e];
1358 for (PetscInt col = 0; col < map.n; col++) {
1359 PetscReal u0; PetscCall(GetDof(user, Ubase, &map, col, &u0));
1360 const PetscReal eps = er*PetscMax(1.0, PetscAbsReal(u0));
1361 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(PerturbDof(user, Uwork, &map, col, +eps));
1362 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rref));
1363 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(PerturbDof(user, Uwork, &map, col, -eps));
1364 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rrep));
1365 for (PetscInt row = 0; row < map.n; row++) Jbest[row + col*map.n] = (Rref[row]-Rrep[row])/(2.0*eps);
1366 }
1367 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " selected plateau eps = %.0e\n", (double)er));
1368 }
1369 PetscCall(PetscFree2(Jprev, Jcur));
1370
1371 /* The FD probes leave the production vectors at the final perturbed evaluation;
1372 restore the base state before every downstream diagnostic. */
1373 PetscCall(VecCopy(Ubase, user->Ucont));
1374 {
1375 const char *fld[] = {"Ucont"};
1376 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fld));
1377 }
1378
1379 /* base state must be restored after the Jacobian build. */
1380 PetscBool eqbase; { Vec chk; PetscCall(VecDuplicate(Ubase,&chk)); PetscCall(VecCopy(user->Ucont,chk));
1381 PetscCall(VecAXPY(chk, -1.0, Ubase)); PetscReal nb; PetscCall(VecNorm(chk, NORM_INFINITY, &nb));
1382 eqbase = (PetscBool)(nb < 1e-12); PetscCall(VecDestroy(&chk));
1383 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " base Ucont restored after Jacobian: %s\n", eqbase?"yes":"NO")); }
1384
1385 /* The FD operator acts on Ucont; J is on the convective residual (sign per ComputeRHS). */
1386 PetscReal rho, maxre, smax;
1387 PetscCall(DenseSpectralRadius(Jbest, map.n, &rho, &maxre));
1388 PetscCall(DenseSigmaMax(Jbest, map.n, &smax, NULL));
1389 const PetscReal eta = DenseNonNormality(Jbest, map.n);
1390
1391 /* ---- candidate estimates (convection-only: lambda_cX = lambda_X - lambda_t) ---- */
1392 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, Rref)); /* restore lUcat consistent w/ base */
1393 PetscCall(UpdateLocalGhosts(user, "Ucont"));
1394 PetscCall(Contra2Cart(user)); PetscCall(UpdateLocalGhosts(user, "Ucat"));
1395 PetscCall(ComputeMomentumStabilityEstimate(user, 1, simCtx->dt, MOM_STAB_CAND_C, &rep));
1396 const PetscReal lcB = rep.lambda_B - rep.lambda_t;
1397 const PetscReal lcC = rep.lambda_C - rep.lambda_t;
1398 const PetscReal lcD = rep.lambda_D - rep.lambda_t;
1399 PetscReal gradmax = 0.0;
1400 PetscCall(ComputeMaxGradientContribution(user, &gradmax));
1401
1402 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1403 " --- convective Jacobian spectrum ---\n"
1404 " rho(J)=%.6e sigma_max(J)=%.6e nonnormality=%.3e max_real_eig=%.3e\n"
1405 " --- candidate convective estimates ---\n"
1406 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n"
1407 " max local |grad u| row-sum contribution = %.6e\n"
1408 " rB/rho=%.3f rC/rho=%.3f rD/rho=%.3f | rB/smax=%.3f rC/smax=%.3f rD/smax=%.3f\n",
1409 (double)rho, (double)smax, (double)eta, (double)maxre,
1410 (double)lcB, (double)lcC, (double)lcD,
1411 (double)gradmax,
1412 (double)(lcB/rho), (double)(lcC/rho), (double)(lcD/rho),
1413 (double)(lcB/smax), (double)(lcC/smax), (double)(lcD/smax)));
1414
1415 /* ---- RK pseudo-CFL stability per candidate (convective Jacobian) ---- */
1416 const PetscReal lams[3] = {lcB, lcC, lcD}; const char *cn[3] = {"B","C","D"};
1417 PetscReal *Jpseudo;
1418 PetscCall(PetscMalloc1((size_t)map.n*map.n, &Jpseudo));
1419 PetscCall(DenseShiftIdentity(Jbest, map.n, -rep.lambda_t, Jpseudo));
1420 const PetscReal lams_full[3] = {rep.lambda_B, rep.lambda_C, rep.lambda_D};
1421 PetscCall(PrintFrozenAmplificationTable("CONVECTION-ONLY FROZEN JACOBIAN", Jbest, map.n, lams, cn));
1422 PetscCall(PrintFrozenAmplificationTable("COMPLETE PSEUDO-TIME FROZEN OPERATOR", Jpseudo, map.n, lams_full, cn));
1423 PetscCall(PetscFree(Jpseudo));
1424
1425 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " --- RK stable pseudo-CFL (convective J) ---\n"));
1426 for (int c = 0; c < 3; c++) {
1427 if (!(lams[c] > 0.0)) continue;
1428 StableCFLResult cfl_rho, cfl_nrm;
1429 PetscCall(StableCFL(Jbest, map.n, lams[c], METRIC_RHO, &cfl_rho));
1430 PetscCall(StableCFL(Jbest, map.n, lams[c], METRIC_NORM, &cfl_nrm));
1431 PetscCall(PrintStableCFLLine(cn[c], cfl_rho, cfl_nrm));
1432 }
1433
1434 /* ---- exact stage-dependent tangent map and direct nonlinear RK cross-check ---- */
1435 if (lcC > 0.0) PetscCall(RunRKTangentDiagnostics(user, st, Ubase, Rhs, &map,
1436 epsrel[best_e], lams, cn, Jbest));
1437
1438 /* ---- robust automated assertions per state ---- */
1439 PetscCall(PicurvAssertBool(eqbase, "base Ucont restored after Jacobian build"));
1440 PetscCall(PicurvAssertBool((PetscBool)(det_err < 1e-10), "residual evaluation deterministic"));
1441 PetscCall(PicurvAssertBool((PetscBool)(rho > 0.0 && PetscIsNormalReal(rho)), "finite rho(J)"));
1442 PetscCall(PicurvAssertBool((PetscBool)(smax > 0.0 && PetscIsNormalReal(smax)), "finite sigma_max(J)"));
1443 if (st == STATE_A) {
1444 for (int d = 0; d < 3; d++) {
1445 PetscCall(PicurvAssertRealNear(seam.declared[d], 0.0, 1e-12, "A: declared periodic seam"));
1446 PetscCall(PicurvAssertRealNear(seam.ucat_global[d], 0.0, 1e-12, "A: Ucat duplicate seam"));
1447 PetscCall(PicurvAssertRealNear(seam.ucat_ghost[d], 0.0, 1e-12, "A: lUcat ghost seam"));
1448 PetscCall(PicurvAssertRealNear(seam.ucont_global[d], 0.0, 1e-12, "A: Ucont duplicate seam"));
1449 }
1450 PetscCall(PicurvAssertRealNear(repeat_err, 0.0, 1e-9, "A: recovered Ucat repeat near roundoff"));
1451 PetscCall(PicurvAssertRealNear(R0_2, 0.0, 1e-12, "A: base residual 2-norm near roundoff"));
1452 PetscCall(PicurvAssertRealNear(R0_inf, 0.0, 1e-12, "A: base residual inf-norm near roundoff"));
1453 PetscCall(PicurvAssertRealNear(lcB, lcC, 1e-9, "A: B == C (no divergence)"));
1454 PetscCall(PicurvAssertRealNear(lcC, lcD, 1e-9, "A: C == D (no shear)"));
1455 } else if (st == STATE_B) {
1456 for (int d = 0; d < 3; d++) {
1457 PetscCall(PicurvAssertRealNear(seam.declared[d], 0.0, 1e-12, "B: declared periodic seam"));
1458 PetscCall(PicurvAssertRealNear(seam.ucat_global[d], 0.0, 1e-12, "B: Ucat duplicate seam"));
1459 PetscCall(PicurvAssertRealNear(seam.ucat_ghost[d], 0.0, 1e-12, "B: lUcat ghost seam"));
1460 PetscCall(PicurvAssertRealNear(seam.ucont_global[d], 0.0, 1e-12, "B: Ucont duplicate seam"));
1461 }
1462 PetscCall(PicurvAssertRealNear(repeat_err, 0.0, 1e-9, "B: recovered Ucat repeat near roundoff"));
1463 PetscCall(PicurvAssertBool((PetscBool)(maxdiv > 1e-3), "B: nonzero discrete divergence"));
1464 PetscCall(PicurvAssertBool((PetscBool)(R0_2 > 1e-3), "B: materially nonzero base residual 2-norm"));
1465 PetscCall(PicurvAssertBool((PetscBool)(R0_inf > 1e-3), "B: materially nonzero base residual inf-norm"));
1466 PetscCall(PicurvAssertBool((PetscBool)(lcC > lcB + 1e-9), "B: C > B"));
1467 } else {
1468 for (int d = 0; d < 3; d++) {
1469 PetscCall(PicurvAssertRealNear(seam.declared[d], 0.0, 1e-12, "C: declared periodic seam"));
1470 PetscCall(PicurvAssertRealNear(seam.ucat_global[d], 0.0, 1e-12, "C: Ucat duplicate seam"));
1471 PetscCall(PicurvAssertRealNear(seam.ucat_ghost[d], 0.0, 1e-12, "C: lUcat ghost seam"));
1472 PetscCall(PicurvAssertRealNear(seam.ucont_global[d], 0.0, 1e-12, "C: Ucont duplicate seam"));
1473 }
1474 PetscCall(PicurvAssertRealNear(repeat_err, 0.0, 1e-9, "C: recovered Ucat repeat near roundoff"));
1475 PetscCall(PicurvAssertBool((PetscBool)(maxdiv < 1e-6), "C: divergence near zero"));
1476 PetscCall(PicurvAssertRealNear(R0_2, 0.0, 1e-12, "C: base residual 2-norm near roundoff"));
1477 PetscCall(PicurvAssertRealNear(R0_inf, 0.0, 1e-12, "C: base residual inf-norm near roundoff"));
1478 PetscCall(PicurvAssertBool((PetscBool)(PetscAbsReal(lcC-lcB) < 1e-6), "C: C ~= B"));
1479 PetscCall(PicurvAssertBool((PetscBool)(gradmax > 1e-6), "C: canonical shear has nonzero local gradient contribution"));
1480 }
1481
1482 PetscCall(PetscFree3(Rref, Rrep, Jbest));
1483 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs));
1484 PetscCall(VecDestroy(&Uwork)); PetscCall(VecDestroy(&Uout));
1485 PetscCall(DofMapDestroy(&map));
1486 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1487 PetscFunctionReturn(0);
1488}
@ MOM_STAB_CAND_C
PetscErrorCode ComputeMomentumStabilityEstimate(UserCtx *user, PetscInt block_number, PetscReal dt, MomStabCandidate candidate, MomStabilityReport *rep)
Compute the momentum pseudo-time stability estimate (shadow/diagnostic).
Diagnostic report produced by ComputeMomentumStabilityEstimate().
static PetscErrorCode ComputeMaxGradientContribution(UserCtx *user, PetscReal *gradmax)
Computes the global maximum Cartesian velocity-gradient row-sum used by Candidate D.
static PetscErrorCode RunRKTangentDiagnostics(UserCtx *user, CandState st, Vec Ubase, Vec Rhs, const DofMap *map, PetscReal epsrel, const PetscReal lams[3], const char *cn[3], const PetscReal *J0)
Runs stage-dependent RK tangent and direct nonlinear perturbation diagnostics.
static PetscErrorCode DofMapBuild(UserCtx *user, DofMap *map)
Builds the serial periodic independent face-DOF map used by dense Jacobians.
static PetscErrorCode StableCFL(const PetscReal *J, PetscInt n, PetscReal lam, PMetric which, StableCFLResult *result)
static PetscErrorCode DofMapDestroy(DofMap *map)
Releases storage owned by an active-DOF map.
static PetscErrorCode DenseShiftIdentity(const PetscReal *A, PetscInt n, PetscReal shift, PetscReal *B)
Copies a dense matrix and adds a scalar shift to its diagonal.
static PetscErrorCode PrintStableCFLLine(const char *candidate, StableCFLResult eig, StableCFLResult norm)
Prints one candidate's eigenvalue and norm stable-CFL statuses.
static PetscReal DenseNonNormality(const PetscReal *A, PetscInt n)
static PetscErrorCode BuildBaseState(UserCtx *user, CandState st, Vec Ubase, PetscReal *repeat_inf, PetscReal *maxdiv, SeamDiagnostics *seam)
static PetscErrorCode PrintFrozenAmplificationTable(const char *title, const PetscReal *J, PetscInt n, const PetscReal lams[3], const char *cn[3])
Prints frozen RK amplification tables for the supplied operator and candidates.
static PetscErrorCode ConfigureCandidateFixture(SimCtx *simCtx, UserCtx *user)
Configures the minimal context for centered inviscid periodic convection tests.
static PetscReal VecNormInfArray(const PetscReal *x, PetscInt n)
Computes the infinity norm of a dense vector.
static PetscReal DenseSkewnessDefect(const PetscReal *A, PetscInt n)
Computes the normalized Frobenius defect from skew symmetry.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvCreateMinimalContextsWithPeriodicity(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz, PetscBool x_periodic, PetscBool y_periodic, PetscBool z_periodic)
Builds minimal SimCtx and UserCtx fixtures for C unit tests with configurable periodicity.
The master context for the entire simulation.
Definition variables.h:683
User-defined context containing data specific to a single computational grid level.
Definition variables.h:874
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestStateA()

static PetscErrorCode TestStateA ( void  )
static

Runs the State A candidate harness.

Definition at line 1493 of file test_momentum_convective_candidates.c.

1493{ return RunState(STATE_A, "A (uniform div-free)"); }
static PetscErrorCode RunState(CandState st, const char *name)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestStateB()

static PetscErrorCode TestStateB ( void  )
static

Runs the State B candidate harness.

Definition at line 1498 of file test_momentum_convective_candidates.c.

1498{ return RunState(STATE_B, "B (nonzero divergence)"); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestStateC()

static PetscErrorCode TestStateC ( void  )
static

Runs the State C candidate harness.

Definition at line 1503 of file test_momentum_convective_candidates.c.

1503{ return RunState(STATE_C, "C (div-free shear)"); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RunStateAGridAuditOne()

static PetscErrorCode RunStateAGridAuditOne ( PetscInt  N)
static

Runs one State A grid-size audit case.

Definition at line 1508 of file test_momentum_convective_candidates.c.

1509{
1510 SimCtx *simCtx = NULL; UserCtx *user = NULL; DofMap map;
1511 Vec Ubase, Rhs, Uwork;
1512 PetscReal *Rp, *Rm, *J;
1513 PetscReal repeat_err, maxdiv;
1514 SeamDiagnostics seam;
1515 PetscFunctionBeginUser;
1516 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, N, N, N, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
1517 PetscCall(ConfigureCandidateFixture(simCtx, user));
1518 PetscCall(DofMapBuild(user, &map));
1519 PetscCall(VecDuplicate(user->Ucont, &Ubase));
1520 PetscCall(VecDuplicate(user->Ucont, &Rhs));
1521 PetscCall(VecDuplicate(user->Ucont, &Uwork));
1522 PetscCall(PetscMalloc3(map.n, &Rp, map.n, &Rm, (size_t)map.n*map.n, &J));
1523 PetscCall(BuildBaseState(user, STATE_A, Ubase, &repeat_err, &maxdiv, &seam));
1524 PetscCall(BuildFDJacobian(user, Ubase, 1e-5, Rhs, &map, Rp, Rm, Uwork, J));
1525 PetscReal rho, maxre, smax;
1526 PetscCall(DenseSpectralRadius(J, map.n, &rho, &maxre));
1527 PetscCall(DenseSigmaMax(J, map.n, &smax, NULL));
1528 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1529 " State A grid audit: DMDA %d^3 independent=%d expected=%d max_real=%.6e rho=%.6e sigma=%.6e skew=%.3e nonnormality=%.3e repeat=%.3e\n",
1530 (int)(N+1), (int)map.n, (int)map.expected_n, (double)maxre, (double)rho, (double)smax,
1531 (double)DenseSkewnessDefect(J, map.n), (double)DenseNonNormality(J, map.n), (double)repeat_err));
1532 PetscCall(PetscFree3(Rp, Rm, J));
1533 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
1534 PetscCall(DofMapDestroy(&map));
1535 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1536 PetscFunctionReturn(0);
1537}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestStateAGridAudit()

static PetscErrorCode TestStateAGridAudit ( void  )
static

Runs the State A grid-dependence and active-space audit.

Definition at line 1542 of file test_momentum_convective_candidates.c.

1543{
1544 PetscFunctionBeginUser;
1545 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1546 "\n================ STATE A GRID / ACTIVE-SPACE AUDIT ================\n"
1547 " residual sign convention: ComputeRHS returns the production convection residual used by pseudo-time updates.\n"
1548 " component-staggered periodic duplicate planes: 0<-m-2 and m-1<-1 in each direction.\n"
1549 " independent map: all three Ucont components use representatives i,j,k=1..m-2; count = 3*(m-2)^3.\n"));
1550 PetscCall(RunStateAGridAuditOne(4));
1551 PetscCall(RunStateAGridAuditOne(5));
1552 PetscFunctionReturn(0);
1553}
static PetscErrorCode RunStateAGridAuditOne(PetscInt N)
Runs one State A grid-size audit case.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteStateADecompReference()

static PetscErrorCode WriteStateADecompReference ( GlobalVecStats  r0,
GlobalVecStats  jv,
GlobalVecStats  phi,
const MomStabilityReport rep 
)
static

Writes the one-rank State A matrix-free decomposition reference.

Definition at line 1558 of file test_momentum_convective_candidates.c.

1560{
1561 PetscMPIInt rank;
1562 PetscFunctionBeginUser;
1563 if (!g_ref_path_set) PetscFunctionReturn(0);
1564 PetscCheck(g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
1565 "-candidate_ref_token is required when -candidate_ref_path is set");
1566 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1567 if (rank == 0) {
1568 FILE *fp = fopen(g_ref_path, "w");
1569 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "could not write State A MPI reference");
1570 fprintf(fp, "PICURV_CANDIDATE_STATEA_REF_V2 %s\n", g_ref_token);
1571 fprintf(fp, "%.17e %.17e %.17e\n", (double)r0.n2, (double)r0.ninf, (double)r0.checksum);
1572 fprintf(fp, "%.17e %.17e %.17e\n", (double)jv.n2, (double)jv.ninf, (double)jv.checksum);
1573 fprintf(fp, "%.17e %.17e %.17e\n", (double)phi.n2, (double)phi.ninf, (double)phi.checksum);
1574 fprintf(fp, "%.17e %.17e %.17e %d %d %d %d\n",
1575 (double)(rep->lambda_B - rep->lambda_t),
1576 (double)(rep->lambda_C - rep->lambda_t),
1577 (double)(rep->lambda_D - rep->lambda_t),
1578 (int)rep->active_cells, (int)rep->cblock, (int)rep->ci, (int)rep->cj);
1579 fclose(fp);
1580 }
1581 PetscFunctionReturn(0);
1582}
static PetscBool g_ref_path_set
static char g_ref_token[128]
static PetscBool g_ref_token_set
static char g_ref_path[PETSC_MAX_PATH_LEN]
Here is the caller graph for this function:

◆ ReadAndCompareStateADecompReference()

static PetscErrorCode ReadAndCompareStateADecompReference ( GlobalVecStats  r0,
GlobalVecStats  jv,
GlobalVecStats  phi,
const MomStabilityReport rep 
)
static

Compares a distributed State A matrix-free check against the one-rank reference.

Definition at line 1587 of file test_momentum_convective_candidates.c.

1589{
1590 PetscMPIInt rank;
1591 PetscReal vals[16] = {0.0};
1592 PetscFunctionBeginUser;
1593 PetscCheck(g_ref_path_set && g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
1594 "two-rank State A decomp check requires matching -candidate_ref_path and -candidate_ref_token from a preceding one-rank run");
1595 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1596 if (rank == 0) {
1597 char magic[64], token[128];
1598 FILE *fp = fopen(g_ref_path, "r");
1599 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
1600 "State A one-rank decomp reference missing; run the Makefile target so -n 1 precedes -n 2");
1601 PetscCheck(fscanf(fp, "%63s %127s", magic, token) == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference header");
1602 PetscCheck(strcmp(magic, "PICURV_CANDIDATE_STATEA_REF_V2") == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
1603 "bad reference magic");
1604 PetscCheck(strcmp(token, g_ref_token) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
1605 "State A one-rank decomp reference token mismatch");
1606 int active, cblock, ci, cj;
1607 PetscCheck(fscanf(fp, "%le %le %le", &vals[0], &vals[1], &vals[2]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference R0");
1608 PetscCheck(fscanf(fp, "%le %le %le", &vals[3], &vals[4], &vals[5]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference Jv");
1609 PetscCheck(fscanf(fp, "%le %le %le", &vals[6], &vals[7], &vals[8]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference Phi");
1610 PetscCheck(fscanf(fp, "%le %le %le %d %d %d %d", &vals[9], &vals[10], &vals[11],
1611 &active, &cblock, &ci, &cj) == 7, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference estimator");
1612 vals[12] = (PetscReal)active; vals[13] = (PetscReal)cblock; vals[14] = (PetscReal)ci; vals[15] = (PetscReal)cj;
1613 fclose(fp);
1614 PetscCheck(remove(g_ref_path) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
1615 "could not remove consumed State A MPI reference '%s'", g_ref_path);
1616 }
1617 PetscCallMPI(MPI_Bcast(vals, 16, MPIU_REAL, 0, PETSC_COMM_WORLD));
1618 PetscCall(PicurvAssertRealNear(r0.n2, vals[0], 1e-10, "MPI State A R0 L2"));
1619 PetscCall(PicurvAssertRealNear(r0.ninf, vals[1], 1e-10, "MPI State A R0 Linf"));
1620 PetscCall(PicurvAssertRealNear(r0.checksum, vals[2], 1e-10, "MPI State A R0 checksum"));
1621 PetscCall(PicurvAssertRealNear(jv.n2, vals[3], 1e-8, "MPI State A Jv L2"));
1622 PetscCall(PicurvAssertRealNear(jv.ninf, vals[4], 1e-8, "MPI State A Jv Linf"));
1623 PetscCall(PicurvAssertRealNear(jv.checksum, vals[5], 1e-8, "MPI State A Jv checksum"));
1624 PetscCall(PicurvAssertRealNear(phi.n2, vals[6], 1e-8, "MPI State A DPhi v L2"));
1625 PetscCall(PicurvAssertRealNear(phi.ninf, vals[7], 1e-8, "MPI State A DPhi v Linf"));
1626 PetscCall(PicurvAssertRealNear(phi.checksum, vals[8], 1e-8, "MPI State A DPhi v checksum"));
1627 PetscCall(PicurvAssertRealNear(rep->lambda_B - rep->lambda_t, vals[9], 1e-10, "MPI State A lambda_cB"));
1628 PetscCall(PicurvAssertRealNear(rep->lambda_C - rep->lambda_t, vals[10], 1e-10, "MPI State A lambda_cC"));
1629 PetscCall(PicurvAssertRealNear(rep->lambda_D - rep->lambda_t, vals[11], 1e-10, "MPI State A lambda_cD"));
1630 PetscCall(PicurvAssertBool((PetscBool)(rep->active_cells == (PetscInt)vals[12]), "MPI State A active cell count"));
1631 PetscCall(PicurvAssertBool((PetscBool)(rep->cblock == (PetscInt)vals[13]), "MPI State A controlling block"));
1632 PetscFunctionReturn(0);
1633}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ StateADecompDirectionalCheck()

static PetscErrorCode StateADecompDirectionalCheck ( UserCtx user,
Vec  Ubase,
Vec  Rhs,
PetscReal  lcC,
const MomStabilityReport rep 
)
static

Runs State A matrix-free residual, Jv, and four-stage MPI decomposition checks.

Definition at line 1638 of file test_momentum_convective_candidates.c.

1640{
1641 DofMap map;
1642 Vec V, Up, Um, PhiP, PhiM, Ustage;
1643 PetscReal *v, *R0, *Rp, *Rm, *ActP, *ActM, *Out;
1644 GlobalVecStats sR0, sJv, sPhi;
1645 const PetscReal eps = 1e-6, dtau = 0.5/lcC;
1646 PetscMPIInt size;
1647 PetscFunctionBeginUser;
1648 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
1649 PetscCall(DofMapBuildOwned(user, &map));
1650 PetscCall(VecDuplicate(Ubase, &V)); PetscCall(VecDuplicate(Ubase, &Up));
1651 PetscCall(VecDuplicate(Ubase, &Um)); PetscCall(VecDuplicate(Ubase, &PhiP));
1652 PetscCall(VecDuplicate(Ubase, &PhiM)); PetscCall(VecDuplicate(Ubase, &Ustage));
1653 PetscCall(PetscMalloc6(map.n, &v, map.n, &R0, map.n, &Rp, map.n, &Rm, map.n, &ActP, map.n, &ActM));
1654 PetscCall(PetscMalloc1(map.n, &Out));
1655 PetscCall(FillDeterministicDirection(user, V, &map, v));
1656
1657 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, R0));
1658 PetscCall(ActiveStats(&map, R0, &sR0));
1659 PetscCall(VecCopy(Ubase, Up)); PetscCall(VecAXPY(Up, eps, V));
1660 PetscCall(VecCopy(Ubase, Um)); PetscCall(VecAXPY(Um, -eps, V));
1661 PetscCall(EvalConvResidual(user, Up, Rhs, &map, Rp));
1662 PetscCall(EvalConvResidual(user, Um, Rhs, &map, Rm));
1663 for (PetscInt m = 0; m < map.n; m++) Out[m] = (Rp[m]-Rm[m])/(2.0*eps);
1664 PetscCall(ActiveStats(&map, Out, &sJv));
1665
1666 PetscCall(FourStage(user, Up, dtau, Rhs, &map, Rp, Ustage, PhiP));
1667 PetscCall(FourStage(user, Um, dtau, Rhs, &map, Rm, Ustage, PhiM));
1668 PetscCall(ExtractActiveVector(user, PhiP, &map, ActP));
1669 PetscCall(ExtractActiveVector(user, PhiM, &map, ActM));
1670 for (PetscInt m = 0; m < map.n; m++) Out[m] = (ActP[m]-ActM[m])/(2.0*eps);
1671 PetscCall(ActiveStats(&map, Out, &sPhi));
1672
1673 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1674 " State A matrix-free MPI check: R0 L2=%.6e Linf=%.6e checksum=%.6e\n"
1675 " Jv L2=%.6e Linf=%.6e checksum=%.6e\n"
1676 " DPhi v L2=%.6e Linf=%.6e checksum=%.6e\n",
1677 (double)sR0.n2, (double)sR0.ninf, (double)sR0.checksum,
1678 (double)sJv.n2, (double)sJv.ninf, (double)sJv.checksum,
1679 (double)sPhi.n2, (double)sPhi.ninf, (double)sPhi.checksum));
1680 if (size == 1) PetscCall(WriteStateADecompReference(sR0, sJv, sPhi, rep));
1681 else PetscCall(ReadAndCompareStateADecompReference(sR0, sJv, sPhi, rep));
1682
1683 PetscCall(PetscFree6(v, R0, Rp, Rm, ActP, ActM)); PetscCall(PetscFree(Out));
1684 PetscCall(VecDestroy(&V)); PetscCall(VecDestroy(&Up)); PetscCall(VecDestroy(&Um));
1685 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Ustage));
1686 PetscCall(DofMapDestroy(&map));
1687 PetscFunctionReturn(0);
1688}
static PetscErrorCode DofMapBuildOwned(UserCtx *user, DofMap *map)
Builds the rank-owned periodic independent face-DOF map for MPI checks.
static PetscErrorCode WriteStateADecompReference(GlobalVecStats r0, GlobalVecStats jv, GlobalVecStats phi, const MomStabilityReport *rep)
Writes the one-rank State A matrix-free decomposition reference.
static PetscErrorCode FillDeterministicDirection(UserCtx *user, Vec V, const DofMap *map, PetscReal *x)
Fills a globally normalized deterministic active-space perturbation direction.
static PetscErrorCode ReadAndCompareStateADecompReference(GlobalVecStats r0, GlobalVecStats jv, GlobalVecStats phi, const MomStabilityReport *rep)
Compares a distributed State A matrix-free check against the one-rank reference.
static PetscErrorCode ActiveStats(const DofMap *map, const PetscReal *x, GlobalVecStats *stats)
Computes global active-vector norms and checksum.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RunDecompBaseline()

static PetscErrorCode RunDecompBaseline ( CandState  st,
const char *  name,
PetscReal  expB,
PetscReal  expC,
PetscReal  expD 
)
static

Runs one decomp baseline and compares scalar estimates with regenerated references.

Definition at line 1693 of file test_momentum_convective_candidates.c.

1695{
1696 SimCtx *simCtx = NULL; UserCtx *user = NULL;
1697 Vec Ubase, Rhs;
1698 PetscReal repeat_err, maxdiv;
1699 SeamDiagnostics seam;
1701 const PetscInt N = 8;
1702 PetscFunctionBeginUser;
1703
1704 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, N, N, N, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
1705 PetscCall(ConfigureCandidateFixture(simCtx, user));
1706 PetscCall(VecDuplicate(user->Ucont, &Ubase));
1707 PetscCall(VecDuplicate(user->Ucont, &Rhs));
1708 PetscCall(BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
1709 PetscCall(ComputeMomentumStabilityEstimate(user, 1, simCtx->dt, MOM_STAB_CAND_C, &rep));
1710
1711 const PetscReal lcB = rep.lambda_B - rep.lambda_t;
1712 const PetscReal lcC = rep.lambda_C - rep.lambda_t;
1713 const PetscReal lcD = rep.lambda_D - rep.lambda_t;
1714 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1715 "\n================ DECOMP BASELINE %s ================\n"
1716 " active cells: %d | repeat=%.3e | max|div_h Ucont|=%.3e\n"
1717 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n",
1718 name, (int)rep.active_cells, (double)repeat_err, (double)maxdiv,
1719 (double)lcB, (double)lcC, (double)lcD));
1720
1721 PetscCall(PicurvAssertBool((PetscBool)(rep.active_cells == 343), "decomp: active-cell count invariant"));
1722 PetscCall(PicurvAssertRealNear(expB, lcB, 5e-7, "decomp: lambda_cB matches one-rank baseline"));
1723 PetscCall(PicurvAssertRealNear(expC, lcC, 5e-7, "decomp: lambda_cC matches one-rank baseline"));
1724 PetscCall(PicurvAssertRealNear(expD, lcD, 5e-7, "decomp: lambda_cD matches one-rank baseline"));
1725 if (st == STATE_A) {
1726 PetscCall(StateADecompDirectionalCheck(user, Ubase, Rhs, lcC, &rep));
1727 PetscCall(PicurvAssertRealNear(maxdiv, 0.0, 1e-12, "decomp A: divergence-free"));
1728 PetscCall(PicurvAssertRealNear(lcB, lcC, 1e-12, "decomp A: B == C"));
1729 PetscCall(PicurvAssertRealNear(lcC, lcD, 1e-12, "decomp A: C == D"));
1730 } else if (st == STATE_B) {
1731 PetscCall(PicurvAssertBool((PetscBool)(maxdiv > 1e-3), "decomp B: nonzero divergence"));
1732 PetscCall(PicurvAssertBool((PetscBool)(lcC > lcB), "decomp B: C > B"));
1733 } else {
1734 PetscCall(PicurvAssertRealNear(maxdiv, 0.0, 1e-12, "decomp C: divergence-free"));
1735 PetscCall(PicurvAssertRealNear(lcB, lcC, 1e-12, "decomp C: B == C"));
1736 }
1737
1738 PetscCall(VecDestroy(&Ubase));
1739 PetscCall(VecDestroy(&Rhs));
1740 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1741 PetscFunctionReturn(0);
1742}
static PetscErrorCode StateADecompDirectionalCheck(UserCtx *user, Vec Ubase, Vec Rhs, PetscReal lcC, const MomStabilityReport *rep)
Runs State A matrix-free residual, Jv, and four-stage MPI decomposition checks.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestDecompA()

static PetscErrorCode TestDecompA ( void  )
static

Runs the State A decomposition baseline.

Definition at line 1747 of file test_momentum_convective_candidates.c.

1747{ return RunDecompBaseline(STATE_A, "A (uniform div-free)", 1.1000000, 1.1000000, 1.1000000); }
static PetscErrorCode RunDecompBaseline(CandState st, const char *name, PetscReal expB, PetscReal expC, PetscReal expD)
Runs one decomp baseline and compares scalar estimates with regenerated references.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestDecompB()

static PetscErrorCode TestDecompB ( void  )
static

Runs the State B decomposition baseline.

Definition at line 1752 of file test_momentum_convective_candidates.c.

1752{ return RunDecompBaseline(STATE_B, "B (nonzero divergence)", 0.878379697325, 0.974927912182, 1.572173303885); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestDecompC()

static PetscErrorCode TestDecompC ( void  )
static

Runs the State C decomposition baseline.

Definition at line 1757 of file test_momentum_convective_candidates.c.

1757{ return RunDecompBaseline(STATE_C, "C (div-free shear)", 1.5000000, 1.5000000, 1.780330085890); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ConfigureMPIReferenceOptions()

static PetscErrorCode ConfigureMPIReferenceOptions ( void  )
static

Reads optional paired-run MPI reference path and token.

Definition at line 1762 of file test_momentum_convective_candidates.c.

1763{
1764 PetscFunctionBeginUser;
1765 PetscCall(PetscOptionsGetString(NULL, NULL, "-candidate_ref_path",
1767 PetscCall(PetscOptionsGetString(NULL, NULL, "-candidate_ref_token",
1770 PetscCheck(g_ref_path_set && g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
1771 "-candidate_ref_path and -candidate_ref_token must be supplied together");
1772 }
1773 PetscFunctionReturn(0);
1774}
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

PETSc entry point for the focused convective-candidate harness.

Definition at line 1779 of file test_momentum_convective_candidates.c.

1780{
1781 PetscErrorCode ierr;
1782 PetscMPIInt size;
1783 const PicurvTestCase cases[] = {
1784 {"candidate-state-A-uniform", TestStateA},
1785 {"candidate-state-B-divergence", TestStateB},
1786 {"candidate-state-C-shear", TestStateC},
1787 {"candidate-state-A-grid-audit", TestStateAGridAudit},
1788 };
1789 const PicurvTestCase decomp_cases[] = {
1790 {"candidate-decomp-A-uniform", TestDecompA},
1791 {"candidate-decomp-B-divergence", TestDecompB},
1792 {"candidate-decomp-C-shear", TestDecompC},
1793 };
1794 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv A4a convective-candidate study");
1795 if (ierr) return (int)ierr;
1796 ierr = ConfigureMPIReferenceOptions(); if (ierr) { PetscFinalize(); return (int)ierr; }
1797 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); if (ierr) { PetscFinalize(); return (int)ierr; }
1798 if (size == 1) {
1799 ierr = PicurvRunTests("unit-momentum-candidates", cases, sizeof(cases)/sizeof(cases[0]));
1800 if (!ierr) ierr = PicurvRunTests("unit-momentum-candidates-decomp", decomp_cases, sizeof(decomp_cases)/sizeof(decomp_cases[0]));
1801 } else {
1802 ierr = PicurvRunTests("unit-momentum-candidates-decomp", decomp_cases, sizeof(decomp_cases)/sizeof(decomp_cases[0]));
1803 }
1804 if (ierr) { PetscFinalize(); return (int)ierr; }
1805 return (int)PetscFinalize();
1806}
static PetscErrorCode TestDecompA(void)
Runs the State A decomposition baseline.
static PetscErrorCode TestDecompB(void)
Runs the State B decomposition baseline.
static PetscErrorCode TestStateC(void)
Runs the State C candidate harness.
static PetscErrorCode TestDecompC(void)
Runs the State C decomposition baseline.
static PetscErrorCode TestStateAGridAudit(void)
Runs the State A grid-dependence and active-space audit.
static PetscErrorCode ConfigureMPIReferenceOptions(void)
Reads optional paired-run MPI reference path and token.
static PetscErrorCode TestStateA(void)
Runs the State A candidate harness.
static PetscErrorCode TestStateB(void)
Runs the State B candidate harness.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
Named test case descriptor consumed by PicurvRunTests.
Here is the call graph for this function:

Variable Documentation

◆ g_ref_path

char g_ref_path[PETSC_MAX_PATH_LEN] = ""
static

Definition at line 36 of file test_momentum_convective_candidates.c.

◆ g_ref_token

char g_ref_token[128] = ""
static

Definition at line 37 of file test_momentum_convective_candidates.c.

◆ g_ref_path_set

PetscBool g_ref_path_set = PETSC_FALSE
static

Definition at line 38 of file test_momentum_convective_candidates.c.

◆ g_ref_token_set

PetscBool g_ref_token_set = PETSC_FALSE
static

Definition at line 39 of file test_momentum_convective_candidates.c.