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_A_X , STATE_A_Y , STATE_B ,
  STATE_C
}
 
enum  PMetric { METRIC_RHO , METRIC_NORM }
 
enum  ResidualStage { STAGE_UCAT = 0 , STAGE_CART_RESID = 1 , STAGE_RCT = 2 , STAGE_FINAL = 3 }
 

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 DenseMaxRealRightEigenpair (const PetscReal *A, PetscInt n, PetscReal *lamr, PetscReal *lami, PetscReal *vr_out, PetscReal *vi_out)
 Extracts the right eigenpair whose eigenvalue has largest real part.
 
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 PrintSpectrumSummary (const char *name, const PetscReal *J, PetscInt n)
 Prints eigenvalue and norm summary for one dense operator.
 
static void DenseMatVec (const PetscReal *J, const PetscReal *x, PetscReal *y, PetscInt n)
 Applies a dense column-major matrix to an active-space vector.
 
static void FillAuditDirection (const DofMap *map, PetscInt kind, PetscReal *x)
 Fills one deterministic active-space vector used by dense/matrix-free checks.
 
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 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 PetscBool DofTouchesPeriodicRepresentative (const DofMap *map, PetscInt m, DMDALocalInfo info)
 True if an active representative lies on a plane adjacent to periodic duplicates.
 
static PetscErrorCode PrintPeriodicSpaceAudit (UserCtx *user, const DofMap *map)
 Prints the component-wise periodic storage count actually used by the active map.
 
static PetscErrorCode PrintBlockAndSymmetricLocalization (UserCtx *user, const DofMap *map, const PetscReal *J)
 Prints 3x3 component block norms and localized symmetric rows.
 
static void FillStaggeredFourierBasis (const DofMap *map, PetscInt wx, PetscInt wy, PetscInt wz, PetscReal *Q)
 Fills the six real basis vectors for one staggered same-wavevector subspace.
 
static PetscErrorCode StaggeredFourierSymbol (const DofMap *map, const PetscReal *J, PetscInt wx, PetscInt wy, PetscInt wz, PetscReal A6[36], PetscReal *leak)
 Builds the 6x6 projected real symbol and leakage for one wavevector.
 
static PetscErrorCode SymbolEigenSummary (const PetscReal A6[36], PetscReal *maxre, PetscReal wr_out[6], PetscReal wi_out[6])
 Eigenvalue summary for a 6x6 real symbol.
 
static PetscErrorCode PrintFourierChecks (const DofMap *map, const PetscReal *J)
 Projects production J on full staggered six-dimensional Fourier subspaces.
 
static PetscErrorCode TraceStateAResidualStages (UserCtx *user, Vec Ubase, Vec Rhs, const DofMap *map, const PetscReal *J)
 Trace observable production residual stages for one deterministic perturbation.
 
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 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 CheckDenseJacobianAction (UserCtx *user, Vec Ubase, Vec Rhs, Vec Uwork, const DofMap *map, const PetscReal *J, PetscReal epsrel)
 Verifies that the assembled dense Jacobian has the same action as production FD Jv.
 
static PetscErrorCode MatrixFreeJv (UserCtx *user, Vec Ubase, Vec Rhs, const DofMap *map, const PetscReal *v, PetscReal eps, PetscReal *jv)
 Matrix-free production Jacobian-vector product on the active space.
 
static PetscReal DenseAdditivityError (const PetscReal *A, const PetscReal *B, const PetscReal *C, PetscInt n)
 Normalized Frobenius norm of A - (B+C).
 
static PetscReal DenseCommutatorNorm (const PetscReal *A, const PetscReal *B, PetscInt n)
 Computes C = A*B - B*A and returns its normalized Frobenius norm.
 
static PetscErrorCode RunStateADirectionalMechanismAudit (const PetscReal *Jxy, UserCtx *user_xy, Vec Ubase_xy, Vec Rhs_xy, const DofMap *map_xy, PetscReal epsrel)
 Builds Jx, Jy, Jxy and prints additivity/commutator/eigenpair diagnostics.
 
static PetscErrorCode ExtractLocalActiveVector (UserCtx *user, Vec local, const DofMap *map, PetscReal *x)
 Extract active-space entries from a local vector.
 
static PetscErrorCode MapCartesianResidualToRct (UserCtx *user, Vec Rc, Vec Rct)
 Mirrors ComputeRHS's Cartesian residual -> contravariant local Rct mapping.
 
static PetscErrorCode AverageRctToFinalActive (UserCtx *user, Vec Rct, const DofMap *map, PetscReal *out)
 Mirrors ComputeRHS's final Rct face averaging and active cleanup for P=0/no body force.
 
static PetscErrorCode EvalResidualStage (UserCtx *user, Vec Ucont_in, Vec Rhs, const DofMap *map, ResidualStage stage, PetscReal *out)
 Evaluates one observable/mirrored residual-path stage for a Ucont input.
 
static PetscErrorCode BuildStageJacobian (UserCtx *user, Vec Ucenter, PetscReal epsrel, Vec Rhs, const DofMap *map, ResidualStage stage, PetscReal *Rp, PetscReal *Rm, Vec Uwork, PetscReal *J)
 Builds a finite-difference Jacobian for one residual-path stage.
 
static PetscErrorCode RunStateAResidualPathIsolation (UserCtx *user, Vec Ubase, Vec Rhs, Vec Uwork, const DofMap *map, PetscReal epsrel)
 Prints the stage where positive-real spectrum first appears.
 
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 RunStateASplitOne (CandState st, const char *label)
 Runs one State A transport-direction split.
 
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 48 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 801 of file test_momentum_convective_candidates.c.

◆ ResidualStage

Enumerator
STAGE_UCAT 
STAGE_CART_RESID 
STAGE_RCT 
STAGE_FINAL 

Definition at line 1650 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 56 of file test_momentum_convective_candidates.c.

56{ 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 61 of file test_momentum_convective_candidates.c.

62{
63 return 3 * PeriodicRepCount(info.mx) * PeriodicRepCount(info.my) * PeriodicRepCount(info.mz);
64}
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 74 of file test_momentum_convective_candidates.c.

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

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

127{ 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 130 of file test_momentum_convective_candidates.c.

130{ 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 135 of file test_momentum_convective_candidates.c.

136{
137 Cmpnts ***r;
138 PetscFunctionBeginUser;
139 PetscCall(VecCopy(Ucont_in, user->Ucont));
140 {
141 const char *fld[] = {"Ucont"};
142 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fld)); /* global->local + periodic */
143 }
144 PetscCall(ComputeRHS(user, Rhs)); /* Contra2Cart + Convection + mapping */
145 PetscCall(DMDAVecGetArrayRead(user->fda, Rhs, &r));
146 for (PetscInt m = 0; m < map->n; m++)
147 Ract[m] = CmpGet(r[map->ck[m]][map->cj[m]][map->ci[m]], map->comp[m]);
148 PetscCall(DMDAVecRestoreArrayRead(user->fda, Rhs, &r));
149 PetscFunctionReturn(0);
150}
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:904
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 153 of file test_momentum_convective_candidates.c.

154{
155 Cmpnts ***a;
156 PetscFunctionBeginUser;
157 PetscCall(DMDAVecGetArray(user->fda, Ucont, &a));
158 { PetscReal *p = (PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]]; p[map->comp[m]] += delta; }
159 PetscCall(DMDAVecRestoreArray(user->fda, Ucont, &a));
160 PetscFunctionReturn(0);
161}
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 166 of file test_momentum_convective_candidates.c.

167{
168 Cmpnts ***a;
169 PetscFunctionBeginUser;
170 PetscCall(DMDAVecGetArray(user->fda, Ucont, &a));
171 { const PetscReal *p = (const PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]]; *val = p[map->comp[m]]; }
172 PetscCall(DMDAVecRestoreArray(user->fda, Ucont, &a));
173 PetscFunctionReturn(0);
174}
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 184 of file test_momentum_convective_candidates.c.

185{
186 const PetscInt nuniq = npts - 1;
187 const PetscInt ip = (idx == npts - 1) ? 0 : idx;
188 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
189}
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 194 of file test_momentum_convective_candidates.c.

195{
196 const PetscInt nuniq = PeriodicRepCount(npts);
197 PetscInt ip = idx - 1;
198 if (idx == 0) ip = nuniq - 1;
199 else if (idx == npts - 1) ip = 0;
200 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
201}
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 206 of file test_momentum_convective_candidates.c.

208{
209 Cmpnts v;
210 const PetscReal x = PeriodicCellAngle(i, mx);
211 const PetscReal y = PeriodicCellAngle(j, my);
212 (void)k; (void)mz;
213 if (st == STATE_A) {
214 v.x = 0.7; v.y = -0.4; v.z = 0.0;
215 } else if (st == STATE_A_X) {
216 v.x = 0.7; v.y = 0.0; v.z = 0.0;
217 } else if (st == STATE_A_Y) {
218 v.x = 0.0; v.y = -0.4; v.z = 0.0;
219 } else if (st == STATE_B) {
220 (void)x; v.x = 0.0; v.y = 0.0; v.z = 0.0;
221 } else {
222 v.x = 1.0 + 0.5*PetscSinReal(y); v.y = 0.0; v.z = 0.0;
223 }
224 return v;
225}
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 230 of file test_momentum_convective_candidates.c.

232{
233 Cmpnts v = {0.0, 0.0, 0.0};
234 (void)j; (void)k; (void)my; (void)mz;
235 if (st == STATE_B) v.x = PetscSinReal(PeriodicFaceAngle(i, mx));
236 return v;
237}
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 242 of file test_momentum_convective_candidates.c.

243{
244 return PetscMax(PetscAbsReal(a.x-b.x), PetscMax(PetscAbsReal(a.y-b.y), PetscAbsReal(a.z-b.z)));
245}
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 250 of file test_momentum_convective_candidates.c.

251{
252 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
253 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
254 PetscFunctionBeginUser;
255 if (st == STATE_B) {
256 for (PetscInt k = 1; k < mz-1; k++)
257 for (PetscInt j = 1; j < my-1; j++) {
258 loc[0] = PetscMax(loc[0], CmpDiffInf(DirectUcontVelocity(st, 0, j, k, mx, my, mz),
259 DirectUcontVelocity(st, mx-2, j, k, mx, my, mz)));
260 loc[0] = PetscMax(loc[0], CmpDiffInf(DirectUcontVelocity(st, mx-1, j, k, mx, my, mz),
261 DirectUcontVelocity(st, 1, j, k, mx, my, mz)));
262 }
263 for (PetscInt k = 1; k < mz-1; k++)
264 for (PetscInt i = 1; i < mx-1; i++) {
265 loc[1] = PetscMax(loc[1], CmpDiffInf(DirectUcontVelocity(st, i, 0, k, mx, my, mz),
266 DirectUcontVelocity(st, i, my-2, k, mx, my, mz)));
267 loc[1] = PetscMax(loc[1], CmpDiffInf(DirectUcontVelocity(st, i, my-1, k, mx, my, mz),
268 DirectUcontVelocity(st, i, 1, k, mx, my, mz)));
269 }
270 for (PetscInt j = 1; j < my-1; j++)
271 for (PetscInt i = 1; i < mx-1; i++) {
272 loc[2] = PetscMax(loc[2], CmpDiffInf(DirectUcontVelocity(st, i, j, 0, mx, my, mz),
273 DirectUcontVelocity(st, i, j, mz-2, mx, my, mz)));
274 loc[2] = PetscMax(loc[2], CmpDiffInf(DirectUcontVelocity(st, i, j, mz-1, mx, my, mz),
275 DirectUcontVelocity(st, i, j, 1, mx, my, mz)));
276 }
277 } else {
278 for (PetscInt k = 0; k < mz; k++)
279 for (PetscInt j = 0; j < my; j++)
280 loc[0] = PetscMax(loc[0], CmpDiffInf(AnalyticVelocity(st, 0, j, k, mx, my, mz),
281 AnalyticVelocity(st, mx-1, j, k, mx, my, mz)));
282 for (PetscInt k = 0; k < mz; k++)
283 for (PetscInt i = 0; i < mx; i++)
284 loc[1] = PetscMax(loc[1], CmpDiffInf(AnalyticVelocity(st, i, 0, k, mx, my, mz),
285 AnalyticVelocity(st, i, my-1, k, mx, my, mz)));
286 for (PetscInt j = 0; j < my; j++)
287 for (PetscInt i = 0; i < mx; i++)
288 loc[2] = PetscMax(loc[2], CmpDiffInf(AnalyticVelocity(st, i, j, 0, mx, my, mz),
289 AnalyticVelocity(st, i, j, mz-1, mx, my, mz)));
290 }
291 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
292 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
293 PetscFunctionReturn(0);
294}
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 299 of file test_momentum_convective_candidates.c.

300{ 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 305 of file test_momentum_convective_candidates.c.

306{
307 DMDALocalInfo info = user->info;
308 Cmpnts ***a;
309 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
310 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
311 PetscFunctionBeginUser;
312 PetscCall(DMDAVecGetArrayRead(user->fda, local, &a));
313#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
314#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
315#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
316 if (HAVE_I(0) && HAVE_I(mx-2))
317 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
318 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
319 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][0], a[k][j][mx-2]));
320 if (HAVE_I(mx-1) && HAVE_I(1))
321 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
322 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
323 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][mx-1], a[k][j][1]));
324 if (HAVE_J(0) && HAVE_J(my-2))
325 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
326 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
327 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][0][i], a[k][my-2][i]));
328 if (HAVE_J(my-1) && HAVE_J(1))
329 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
330 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
331 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][my-1][i], a[k][1][i]));
332 if (HAVE_K(0) && HAVE_K(mz-2))
333 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
334 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
335 loc[2] = PetscMax(loc[2], CmpDiffInf(a[0][j][i], a[mz-2][j][i]));
336 if (HAVE_K(mz-1) && HAVE_K(1))
337 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
338 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
339 loc[2] = PetscMax(loc[2], CmpDiffInf(a[mz-1][j][i], a[1][j][i]));
340#undef HAVE_I
341#undef HAVE_J
342#undef HAVE_K
343 PetscCall(DMDAVecRestoreArrayRead(user->fda, local, &a));
344 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
345 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
346 PetscFunctionReturn(0);
347}
#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 352 of file test_momentum_convective_candidates.c.

353{
354 DMDALocalInfo info = user->info;
355 Cmpnts ***a;
356 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
357 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
358 PetscFunctionBeginUser;
359 PetscCall(DMDAVecGetArrayRead(user->fda, local, &a));
360#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
361#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
362#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
363 if (HAVE_I(-1) && HAVE_I(1))
364 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
365 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
366 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][-1], a[k][j][1]));
367 if (HAVE_I(mx) && HAVE_I(mx-2))
368 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
369 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
370 loc[0] = PetscMax(loc[0], CmpDiffInf(a[k][j][mx], a[k][j][mx-2]));
371 if (HAVE_J(-1) && HAVE_J(1))
372 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
373 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
374 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][-1][i], a[k][1][i]));
375 if (HAVE_J(my) && HAVE_J(my-2))
376 for (PetscInt k = 1; k < mz-1; k++) if (HAVE_K(k))
377 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
378 loc[1] = PetscMax(loc[1], CmpDiffInf(a[k][my][i], a[k][my-2][i]));
379 if (HAVE_K(-1) && HAVE_K(1))
380 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
381 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
382 loc[2] = PetscMax(loc[2], CmpDiffInf(a[-1][j][i], a[1][j][i]));
383 if (HAVE_K(mz) && HAVE_K(mz-2))
384 for (PetscInt j = 1; j < my-1; j++) if (HAVE_J(j))
385 for (PetscInt i = 1; i < mx-1; i++) if (HAVE_I(i))
386 loc[2] = PetscMax(loc[2], CmpDiffInf(a[mz][j][i], a[mz-2][j][i]));
387#undef HAVE_I
388#undef HAVE_J
389#undef HAVE_K
390 PetscCall(DMDAVecRestoreArrayRead(user->fda, local, &a));
391 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
392 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
393 PetscFunctionReturn(0);
394}
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 399 of file test_momentum_convective_candidates.c.

400{
401 PetscFunctionBeginUser;
402 for (int f = 0; f < 6; f++) user->boundary_faces[f].mathematical_type = PERIODIC;
403 simCtx->dt = 0.1; simCtx->step = 5; simCtx->StartStep = 0; /* BDF2 -> a0=1.5 */
404 simCtx->ren = 1.0e6; simCtx->invicid = 1; simCtx->les = 0; simCtx->rans = 0;
405 simCtx->central = 1; simCtx->clark = 0; simCtx->TwoD = 0; simCtx->block_number = 1;
406 simCtx->bulkVelocityCorrection = 0.0; simCtx->moveframe = 0; simCtx->rotateframe = 0;
407 if (!user->lNu_t) PetscCall(DMCreateLocalVector(user->da, &user->lNu_t));
408 PetscCall(VecSet(user->P, 0.0)); PetscCall(UpdateLocalGhosts(user, "P"));
409 PetscCall(VecSet(user->lNvert, 0.0)); PetscCall(VecSet(user->Nvert, 0.0));
410 PetscFunctionReturn(0);
411}
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1752
PetscInt clark
Definition variables.h:790
@ PERIODIC
Definition variables.h:290
PetscInt moveframe
Definition variables.h:715
PetscInt TwoD
Definition variables.h:715
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:896
PetscInt block_number
Definition variables.h:768
Vec lNvert
Definition variables.h:904
PetscInt rans
Definition variables.h:789
PetscReal ren
Definition variables.h:732
PetscReal dt
Definition variables.h:699
PetscReal bulkVelocityCorrection
Definition variables.h:781
PetscInt StartStep
Definition variables.h:694
PetscInt invicid
Definition variables.h:715
Vec lNu_t
Definition variables.h:935
PetscInt central
Definition variables.h:730
PetscInt step
Definition variables.h:692
PetscInt les
Definition variables.h:789
Vec Nvert
Definition variables.h:904
BCType mathematical_type
Definition variables.h:366
PetscInt rotateframe
Definition variables.h:715
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 414 of file test_momentum_convective_candidates.c.

415{
416 Cmpnts ***u;
417 DMDALocalInfo info = user->info;
418 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
419 PetscFunctionBeginUser;
420 PetscCall(DMDAVecGetArray(user->fda, user->Ucat, &u));
421 /* only owned region for a GLOBAL vec */
422 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
423 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
424 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
425 u[k][j][i] = AnalyticVelocity(st, i, j, k, mx, my, mz);
426 }
427 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucat, &u));
428 PetscFunctionReturn(0);
429}
Vec Ucat
Definition variables.h:904
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 434 of file test_momentum_convective_candidates.c.

435{
436 Cmpnts ***u;
437 DMDALocalInfo info = user->info;
438 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
439 PetscFunctionBeginUser;
440 PetscCall(VecSet(user->Ucont, 0.0));
441 PetscCall(DMDAVecGetArray(user->fda, user->Ucont, &u));
442 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
443 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
444 for (PetscInt i = info.xs; i < info.xs+info.xm; i++)
445 u[k][j][i] = DirectUcontVelocity(st, i, j, k, mx, my, mz);
446 PetscCall(DMDAVecRestoreArray(user->fda, user->Ucont, &u));
447 PetscFunctionReturn(0);
448}
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 453 of file test_momentum_convective_candidates.c.

454{
455 DMDALocalInfo info = user->info;
456 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
457 Cmpnts ***uc;
458 PetscReal dv = 0.0, dv_global;
459 PetscFunctionBeginUser;
460 PetscCall(UpdateLocalGhosts(user, "Ucont"));
461 PetscCall(DMDAVecGetArrayRead(user->fda, user->lUcont, &uc));
462 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
463 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
464 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
465 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2) continue;
466 const PetscReal d = (uc[k][j][i].x - uc[k][j][i-1].x)
467 + (uc[k][j][i].y - uc[k][j-1][i].y)
468 + (uc[k][j][i].z - uc[k-1][j][i].z);
469 dv = PetscMax(dv, PetscAbsReal(d));
470 }
471 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lUcont, &uc));
472 PetscCallMPI(MPI_Allreduce(&dv, &dv_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
473 *maxdiv = dv_global;
474 PetscFunctionReturn(0);
475}
Vec lUcont
Definition variables.h:904
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 479 of file test_momentum_convective_candidates.c.

482{
483 DMDALocalInfo info = user->info;
484 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
485 PetscReal err = 0.0, err_global;
486 Vec target;
487 Cmpnts ***ur, ***ut;
488 PetscFunctionBeginUser;
489
490 PetscCall(VecDuplicate(user->Ucat, &target));
491
492 if (seam) PetscCall(ComputeDeclaredSeamMismatch(st, info, seam->declared));
493
494 if (st == STATE_B) {
495 const char *ufld[] = {"Ucont"};
496 const char *cfld[] = {"Ucat"};
497 PetscCall(SetDirectUcontField(user, st));
498 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, ufld));
499 PetscCall(VecCopy(user->Ucont, Ubase));
500 if (seam) PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcont, seam->ucont_global));
501 PetscCall(Contra2Cart(user));
502 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
503 PetscCall(VecCopy(user->Ucat, target)); /* saved recovered Cartesian state */
504 PetscCall(Contra2Cart(user));
505 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
506 } else {
507 const char *cfld[] = {"Ucat"};
508 const char *ufld[] = {"Ucont"};
509 PetscCall(SetUcatField(user, st));
510 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
511 PetscCall(VecCopy(user->Ucat, target)); /* saved declared Cartesian state */
512 PetscCall(Cart2Contra(user)); /* global Ucont from lUcat + metrics */
513 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, ufld));
514 PetscCall(VecCopy(user->Ucont, Ubase));
515 if (seam) PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcont, seam->ucont_global));
516 PetscCall(Contra2Cart(user)); /* recovered Cartesian from Ucont */
517 PetscCall(SynchronizePeriodicCellFields(user, 1, cfld));
518 }
519
520 if (seam) {
521 PetscCall(UpdateLocalGhosts(user, "Ucat"));
522 PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcat, seam->ucat_global));
523 PetscCall(ComputeLocalOuterGhostMismatch(user, user->lUcat, seam->ucat_ghost));
524 }
525
526 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucat, &ur));
527 PetscCall(DMDAVecGetArrayRead(user->fda, target, &ut));
528 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
529 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
530 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
531 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2) continue; /* interior cells only */
532 err = PetscMax(err, PetscAbsReal(ur[k][j][i].x - ut[k][j][i].x));
533 err = PetscMax(err, PetscAbsReal(ur[k][j][i].y - ut[k][j][i].y));
534 err = PetscMax(err, PetscAbsReal(ur[k][j][i].z - ut[k][j][i].z));
535 }
536 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucat, &ur));
537 PetscCall(DMDAVecRestoreArrayRead(user->fda, target, &ut));
538 PetscCall(VecDestroy(&target));
539 PetscCall(UpdateLocalGhosts(user, "Ucat")); /* lUcat now consistent with base Ucont */
540
541 PetscCallMPI(MPI_Allreduce(&err, &err_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
542 PetscCall(ComputeMaxDiscreteDivergence(user, maxdiv));
543 *repeat_inf = err_global;
544 PetscFunctionReturn(0);
545}
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:2743
PetscErrorCode Cart2Contra(UserCtx *user)
Convert the ghosted Cartesian velocity field to contravariant face fluxes.
Definition setup.c:2878
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:904
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 550 of file test_momentum_convective_candidates.c.

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

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

◆ DenseMaxRealRightEigenpair()

static PetscErrorCode DenseMaxRealRightEigenpair ( const PetscReal *  A,
PetscInt  n,
PetscReal *  lamr,
PetscReal *  lami,
PetscReal *  vr_out,
PetscReal *  vi_out 
)
static

Extracts the right eigenpair whose eigenvalue has largest real part.

For a complex pair, LAPACK stores real and imaginary parts in adjacent columns of VR.

Definition at line 628 of file test_momentum_convective_candidates.c.

631{
632 PetscBLASInt N, lda, lwork, info;
633 PetscReal *Acopy, *wr, *wi, *vr, *work, dummy = 0.0;
634 PetscFunctionBeginUser;
635 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 16*N;
636 PetscCall(PetscMalloc5(n*n, &Acopy, n, &wr, n, &wi, n*n, &vr, (size_t)lwork, &work));
637 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
638 {
639 char jobvl = 'N', jobvr = 'V';
640 LAPACKgeev_(&jobvl, &jobvr, &N, Acopy, &lda, wr, wi, &dummy, &lda, vr, &lda, work, &lwork, &info);
641 }
642 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "LAPACK dgeev failed: info=%d", (int)info);
643 PetscInt best = 0;
644 for (PetscInt t = 1; t < n; t++) if (wr[t] > wr[best]) best = t;
645 *lamr = wr[best]; *lami = wi[best];
646 if (PetscAbsReal(wi[best]) < 1e-14) {
647 for (PetscInt r = 0; r < n; r++) { vr_out[r] = vr[r + best*n]; vi_out[r] = 0.0; }
648 } else if (wi[best] > 0.0) {
649 for (PetscInt r = 0; r < n; r++) { vr_out[r] = vr[r + best*n]; vi_out[r] = vr[r + (best+1)*n]; }
650 } else {
651 for (PetscInt r = 0; r < n; r++) { vr_out[r] = vr[r + (best-1)*n]; vi_out[r] = -vr[r + best*n]; }
652 }
653 PetscCall(PetscFree5(Acopy, wr, wi, vr, work));
654 PetscFunctionReturn(0);
655}
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 660 of file test_momentum_convective_candidates.c.

662{
663 PetscBLASInt N, lda, lwork, info;
664 PetscReal *Jcopy, *wr, *wi, *work, dummy = 0.0;
665 PetscFunctionBeginUser;
666 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N;
667 PetscCall(PetscMalloc4(n*n, &Jcopy, n, &wr, n, &wi, (size_t)lwork, &work));
668 for (PetscInt t = 0; t < n*n; t++) Jcopy[t] = J[t];
669 {
670 char nochar = 'N';
671 LAPACKgeev_(&nochar, &nochar, &N, Jcopy, &lda, wr, wi, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
672 }
673 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "LAPACK dgeev failed: info=%d", (int)info);
674 *rho = 0.0;
675 for (PetscInt t = 0; t < n; t++) {
676 const PetscReal zr = dtau*wr[t], zi = dtau*wi[t];
677 const PetscReal z2r = zr*zr - zi*zi, z2i = 2.0*zr*zi;
678 const PetscReal z3r = z2r*zr - z2i*zi, z3i = z2r*zi + z2i*zr;
679 const PetscReal z4r = z3r*zr - z3i*zi, z4i = z3r*zi + z3i*zr;
680 const PetscReal pr = 1.0 + zr + 0.5*z2r + z3r/6.0 + z4r/24.0;
681 const PetscReal pi = zi + 0.5*z2i + z3i/6.0 + z4i/24.0;
682 *rho = PetscMax(*rho, PetscSqrtReal(pr*pr + pi*pi));
683 }
684 PetscCall(PetscFree4(Jcopy, wr, wi, work));
685 PetscFunctionReturn(0);
686}
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 689 of file test_momentum_convective_candidates.c.

690{
691 PetscBLASInt N, lda, lwork, info;
692 PetscReal *Acopy, *S, *VT, *work, ufake = 0.0;
693 PetscFunctionBeginUser;
694 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N + 4*N;
695 PetscCall(PetscMalloc4(n*n, &Acopy, n, &S, n*n, &VT, (size_t)lwork, &work));
696 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
697 {
698 char jobu = 'N', jobvt = v1 ? 'S' : 'N';
699 LAPACKgesvd_(&jobu, &jobvt, &N, &N, Acopy, &lda, S, &ufake, &lda, VT, &lda, work, &lwork, &info);
700 }
701 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "LAPACK dgesvd failed: info=%d", (int)info);
702 *smax = S[0];
703 if (v1) { for (PetscInt r = 0; r < n; r++) v1[r] = VT[0 + r*n]; } /* first row of VT = v1^T */
704 PetscCall(PetscFree4(Acopy, S, VT, work));
705 PetscFunctionReturn(0);
706}
Here is the caller graph for this function:

◆ DenseNonNormality()

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

Definition at line 709 of file test_momentum_convective_candidates.c.

710{
711 PetscReal fro2 = 0.0, comm = 0.0;
712 for (PetscInt t = 0; t < n*n; t++) fro2 += A[t]*A[t];
713 for (PetscInt p = 0; p < n; p++)
714 for (PetscInt q = 0; q < n; q++) {
715 PetscReal ata = 0.0, aat = 0.0;
716 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]; }
717 const PetscReal d = ata - aat; comm += d*d;
718 }
719 return PetscSqrtReal(comm) / PetscMax(fro2, PETSC_MACHINE_EPSILON);
720}
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 725 of file test_momentum_convective_candidates.c.

726{
727 PetscReal fro2 = 0.0, sym2 = 0.0;
728 for (PetscInt i = 0; i < n*n; i++) fro2 += A[i]*A[i];
729 for (PetscInt c = 0; c < n; c++)
730 for (PetscInt r = 0; r < n; r++) {
731 const PetscReal s = A[r + c*n] + A[c + r*n];
732 sym2 += s*s;
733 }
734 return PetscSqrtReal(sym2) / PetscMax(PetscSqrtReal(fro2), PETSC_MACHINE_EPSILON);
735}
Here is the caller graph for this function:

◆ PrintSpectrumSummary()

static PetscErrorCode PrintSpectrumSummary ( const char *  name,
const PetscReal *  J,
PetscInt  n 
)
static

Prints eigenvalue and norm summary for one dense operator.

Definition at line 740 of file test_momentum_convective_candidates.c.

741{
742 PetscReal rho, maxre, smax;
743 PetscFunctionBeginUser;
744 PetscCall(DenseSpectralRadius(J, n, &rho, &maxre));
745 PetscCall(DenseSigmaMax(J, n, &smax, NULL));
746 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
747 " %-7s rho=%.6e sigma=%.6e max_real=%.6e skew=%.3e nonnormality=%.3e\n",
748 name, (double)rho, (double)smax, (double)maxre,
749 (double)DenseSkewnessDefect(J, n), (double)DenseNonNormality(J, n)));
750 PetscFunctionReturn(0);
751}
static PetscErrorCode DenseSigmaMax(const PetscReal *A, PetscInt n, PetscReal *smax, PetscReal *v1)
static PetscErrorCode DenseSpectralRadius(const PetscReal *A, PetscInt n, PetscReal *rho, PetscReal *maxRealPart)
static PetscReal DenseNonNormality(const PetscReal *A, PetscInt n)
static PetscReal DenseSkewnessDefect(const PetscReal *A, PetscInt n)
Computes the normalized Frobenius defect from skew symmetry.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DenseMatVec()

static void DenseMatVec ( const PetscReal *  J,
const PetscReal *  x,
PetscReal *  y,
PetscInt  n 
)
static

Applies a dense column-major matrix to an active-space vector.

Definition at line 1440 of file test_momentum_convective_candidates.c.

1441{
1442 for (PetscInt r = 0; r < n; r++) {
1443 PetscReal s = 0.0;
1444 for (PetscInt c = 0; c < n; c++) s += J[r + c*n]*x[c];
1445 y[r] = s;
1446 }
1447}
Here is the caller graph for this function:

◆ FillAuditDirection()

static void FillAuditDirection ( const DofMap map,
PetscInt  kind,
PetscReal *  x 
)
static

Fills one deterministic active-space vector used by dense/matrix-free checks.

Definition at line 1452 of file test_momentum_convective_candidates.c.

1453{
1454 PetscReal n2 = 0.0;
1455 for (PetscInt m = 0; m < map->n; m++) {
1456 const PetscReal a = 0.31*(PetscReal)(map->ci[m]+1)
1457 + 0.47*(PetscReal)(map->cj[m]+1)
1458 + 0.59*(PetscReal)(map->ck[m]+1)
1459 + 0.23*(PetscReal)(map->comp[m]+1);
1460 if (kind == 0) x[m] = PetscSinReal(a);
1461 else if (kind == 1) x[m] = PetscCosReal(1.7*a) + 0.25*PetscSinReal(0.9*(PetscReal)(m+1));
1462 else x[m] = (map->comp[m] == kind-2) ? PetscSinReal(a) : 0.0;
1463 n2 += x[m]*x[m];
1464 }
1465 n2 = PetscSqrtReal(n2);
1466 if (n2 > 0.0) for (PetscInt m = 0; m < map->n; m++) x[m] /= n2;
1467}
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 1276 of file test_momentum_convective_candidates.c.

1278{
1279 Cmpnts ***a;
1280 PetscFunctionBeginUser;
1281 PetscCall(DMDAVecGetArray(user->fda, U, &a));
1282 for (PetscInt m = 0; m < map->n; m++) {
1283 PetscReal *p = (PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]];
1284 p[map->comp[m]] += scale*x[m];
1285 }
1286 PetscCall(DMDAVecRestoreArray(user->fda, U, &a));
1287 PetscFunctionReturn(0);
1288}
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 761 of file test_momentum_convective_candidates.c.

762{
763 PetscFunctionBeginUser;
764 PetscCall(PetscArraycpy(B, A, (size_t)n*n));
765 for (PetscInt d = 0; d < n; d++) B[d + d*n] += shift;
766 PetscFunctionReturn(0);
767}
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 770 of file test_momentum_convective_candidates.c.

771{
772 for (PetscInt c = 0; c < n; c++)
773 for (PetscInt r = 0; r < n; r++) {
774 PetscReal s = 0.0;
775 for (PetscInt t = 0; t < n; t++) s += A[r + t*n]*B[t + c*n];
776 out[r + c*n] = s;
777 }
778}
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 781 of file test_momentum_convective_candidates.c.

782{
783 PetscReal *M, *T, *T2;
784 PetscFunctionBeginUser;
785 PetscCall(PetscMalloc3(n*n, &M, n*n, &T, n*n, &T2));
786 for (PetscInt t = 0; t < n*n; t++) M[t] = dtau*J[t];
787 /* start S = I + M/4 */
788 for (PetscInt t = 0; t < n*n; t++) T[t] = M[t]/4.0;
789 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0;
790 const PetscReal coef[3] = {3.0, 2.0, 1.0}; /* divide by 3, then 2, then 1 */
791 for (int s = 0; s < 3; s++) {
792 MatMul(M, T, T2, n); /* T2 = M*S */
793 for (PetscInt t = 0; t < n*n; t++) T[t] = T2[t]/coef[s];
794 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0; /* S = I + M/coef * S */
795 }
796 for (PetscInt t = 0; t < n*n; t++) P[t] = T[t];
797 PetscCall(PetscFree3(M, T, T2));
798 PetscFunctionReturn(0);
799}
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 806 of file test_momentum_convective_candidates.c.

808{
809 PetscReal *Pm;
810 PetscFunctionBeginUser;
811 if (which == METRIC_RHO) {
812 PetscCall(DenseRKPolynomialSpectralRadius(J, n, dtau, metric));
813 PetscFunctionReturn(0);
814 }
815 PetscCall(PetscMalloc1(n*n, &Pm));
816 PetscCall(RKPolynomial(J, dtau, n, Pm));
817 PetscCall(DenseSigmaMax(Pm, n, metric, NULL));
818 PetscCall(PetscFree(Pm));
819 PetscFunctionReturn(0);
820}
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 823 of file test_momentum_convective_candidates.c.

825{
826 const PetscReal tol = 1e-8, probe = 1e-8, scan_step = 0.01, hi = 4.0;
827 const PetscReal probe_tol = 1e-12, min_positive_cfl = 1e-6;
828 PetscReal met;
829 PetscFunctionBeginUser;
830 result->status = STABLE_CFL_NONE;
831 result->cfl = 0.0;
832 if (which == METRIC_RHO) {
833 PetscReal rhoJ, maxreJ;
834 PetscCall(DenseSpectralRadius(J, n, &rhoJ, &maxreJ));
835 if (maxreJ > 1e-8) PetscFunctionReturn(0);
836 }
837 PetscCall(AmplificationMetric(J, n, probe/lam, which, &met));
838 if (met > 1.0 + probe_tol) PetscFunctionReturn(0);
839
840 PetscReal stable = probe, cross_b = -1.0;
841 for (PetscReal cfl = scan_step; cfl <= hi + 1e-12; cfl += scan_step) {
842 PetscCall(AmplificationMetric(J, n, cfl/lam, which, &met));
843 if (met > 1.0 + tol) { cross_b = cfl; break; }
844 stable = cfl;
845 }
846 if (cross_b < 0.0) {
848 result->cfl = hi;
849 PetscFunctionReturn(0);
850 }
851 PetscReal cross_a = stable;
852 for (int it = 0; it < 40; it++) {
853 const PetscReal mid = 0.5*(cross_a + cross_b);
854 PetscCall(AmplificationMetric(J, n, mid/lam, which, &met));
855 if (met > 1.0 + tol) cross_b = mid; else cross_a = mid;
856 }
857 if (cross_a < min_positive_cfl) PetscFunctionReturn(0);
858 result->status = STABLE_CFL_FINITE;
859 result->cfl = cross_a;
860 PetscFunctionReturn(0);
861}
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.
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 866 of file test_momentum_convective_candidates.c.

867{
868 if (r.status == STABLE_CFL_NONE) return "no positive stable interval connected to zero";
869 if (r.status == STABLE_CFL_EXCEEDS_SCAN) return "stable through CFL >= 4.0";
870 return "stable CFL";
871}
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 876 of file test_momentum_convective_candidates.c.

879{
880 PetscFunctionBeginUser;
881 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " cand %s: eig %s", candidate, StableCFLStatusText(eig)));
882 if (eig.status == STABLE_CFL_FINITE) PetscCall(PetscPrintf(PETSC_COMM_WORLD, " = %.4f", (double)eig.cfl));
883 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " | norm %s", StableCFLStatusText(norm)));
884 if (norm.status == STABLE_CFL_FINITE) PetscCall(PetscPrintf(PETSC_COMM_WORLD, " = %.4f", (double)norm.cfl));
885 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n"));
886 PetscFunctionReturn(0);
887}
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 890 of file test_momentum_convective_candidates.c.

891{
892 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; }
893}
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 898 of file test_momentum_convective_candidates.c.

901{
902 const PetscReal cfls[5] = {0.25, 0.50, 1.00, 1.50, 2.00};
903 PetscReal *Pm;
904 PetscFunctionBeginUser;
905 PetscCall(PetscMalloc1(n*n, &Pm));
906 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
907 " --- %s ---\n"
908 " candidate CFL dtau rho(P) sigma_max(P)\n", title));
909 for (int c = 0; c < 3; c++) {
910 if (!(lams[c] > 0.0)) continue;
911 for (int q = 0; q < 5; q++) {
912 const PetscReal dtau = cfls[q]/lams[c];
913 PetscReal rhoP, smaxP;
914 PetscCall(RKPolynomial(J, dtau, n, Pm));
915 PetscCall(DenseRKPolynomialSpectralRadius(J, n, dtau, &rhoP));
916 PetscCall(DenseSigmaMax(Pm, n, &smaxP, NULL));
917 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
918 " %-9s %.2f %.6e %.6e %.6e\n",
919 cn[c], (double)cfls[q], (double)dtau, (double)rhoP, (double)smaxP));
920 }
921 }
922 PetscCall(PetscFree(Pm));
923 PetscFunctionReturn(0);
924}
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 929 of file test_momentum_convective_candidates.c.

930{
931 PetscReal s = 0.0;
932 for (PetscInt i = 0; i < n; i++) s += x[i]*x[i];
933 return PetscSqrtReal(s);
934}
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 939 of file test_momentum_convective_candidates.c.

940{
941 PetscReal s = 0.0;
942 for (PetscInt i = 0; i < n; i++) s = PetscMax(s, PetscAbsReal(x[i]));
943 return s;
944}
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 949 of file test_momentum_convective_candidates.c.

950{
951 PetscReal s = 0.0;
952 for (PetscInt i = 0; i < n*n; i++) s += A[i]*A[i];
953 return PetscSqrtReal(s);
954}
Here is the caller graph for this function:

◆ DofTouchesPeriodicRepresentative()

static PetscBool DofTouchesPeriodicRepresentative ( const DofMap map,
PetscInt  m,
DMDALocalInfo  info 
)
static

True if an active representative lies on a plane adjacent to periodic duplicates.

Definition at line 959 of file test_momentum_convective_candidates.c.

960{
961 return (PetscBool)(map->ci[m] == 1 || map->ci[m] == info.mx-2 ||
962 map->cj[m] == 1 || map->cj[m] == info.my-2 ||
963 map->ck[m] == 1 || map->ck[m] == info.mz-2);
964}
Here is the caller graph for this function:

◆ PrintPeriodicSpaceAudit()

static PetscErrorCode PrintPeriodicSpaceAudit ( UserCtx user,
const DofMap map 
)
static

Prints the component-wise periodic storage count actually used by the active map.

Definition at line 969 of file test_momentum_convective_candidates.c.

970{
971 PetscInt count[3] = {0,0,0};
972 PetscInt min_i[3] = {PETSC_MAX_INT,PETSC_MAX_INT,PETSC_MAX_INT};
973 PetscInt min_j[3] = {PETSC_MAX_INT,PETSC_MAX_INT,PETSC_MAX_INT};
974 PetscInt min_k[3] = {PETSC_MAX_INT,PETSC_MAX_INT,PETSC_MAX_INT};
975 PetscInt max_i[3] = {-PETSC_MAX_INT,-PETSC_MAX_INT,-PETSC_MAX_INT};
976 PetscInt max_j[3] = {-PETSC_MAX_INT,-PETSC_MAX_INT,-PETSC_MAX_INT};
977 PetscInt max_k[3] = {-PETSC_MAX_INT,-PETSC_MAX_INT,-PETSC_MAX_INT};
978 PetscFunctionBeginUser;
979 for (PetscInt m = 0; m < map->n; m++) {
980 const PetscInt c = map->comp[m];
981 count[c]++;
982 min_i[c] = PetscMin(min_i[c], map->ci[m]); max_i[c] = PetscMax(max_i[c], map->ci[m]);
983 min_j[c] = PetscMin(min_j[c], map->cj[m]); max_j[c] = PetscMax(max_j[c], map->cj[m]);
984 min_k[c] = PetscMin(min_k[c], map->ck[m]); max_k[c] = PetscMax(max_k[c], map->ck[m]);
985 }
986 const PetscInt per_comp = PeriodicRepCount(user->info.mx) *
987 PeriodicRepCount(user->info.my) *
988 PeriodicRepCount(user->info.mz);
989 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
990 " --- periodic independent-space audit ---\n"
991 " synchronization convention: duplicate planes 0<-m-2 and m-1<-1 in x/y/z for Ucont.\n"
992 " active rows and columns both use the same representatives i,j,k=1..m-2.\n"
993 " comp expected actual i-range j-range k-range\n"));
994 for (PetscInt c = 0; c < 3; c++) {
995 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
996 " %d %7d %6d [%d,%d] [%d,%d] [%d,%d]\n",
997 (int)c, (int)per_comp, (int)count[c],
998 (int)min_i[c], (int)max_i[c], (int)min_j[c], (int)max_j[c], (int)min_k[c], (int)max_k[c]));
999 }
1000 PetscFunctionReturn(0);
1001}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PrintBlockAndSymmetricLocalization()

static PetscErrorCode PrintBlockAndSymmetricLocalization ( UserCtx user,
const DofMap map,
const PetscReal *  J 
)
static

Prints 3x3 component block norms and localized symmetric rows.

Definition at line 1006 of file test_momentum_convective_candidates.c.

1008{
1009 PetscReal block2[3][3] = {{0.0}}, sym2[3][3] = {{0.0}};
1010 PetscReal *row2;
1011 PetscInt top[8];
1012 PetscFunctionBeginUser;
1013 PetscCall(PetscMalloc1(map->n, &row2));
1014 for (PetscInt r = 0; r < map->n; r++) row2[r] = 0.0;
1015 for (PetscInt c = 0; c < map->n; c++) {
1016 for (PetscInt r = 0; r < map->n; r++) {
1017 const PetscInt rb = map->comp[r], cb = map->comp[c];
1018 const PetscReal a = J[r + c*map->n];
1019 const PetscReal s = 0.5*(J[r + c*map->n] + J[c + r*map->n]);
1020 block2[rb][cb] += a*a;
1021 sym2[rb][cb] += s*s;
1022 row2[r] += s*s;
1023 }
1024 }
1025 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1026 " --- component block norms J_ab = dR_a/dU_b ---\n"
1027 " row-comp col-comp ||J_ab||F ||0.5(J+J^T)_ab||F\n"));
1028 for (PetscInt rb = 0; rb < 3; rb++)
1029 for (PetscInt cb = 0; cb < 3; cb++)
1030 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1031 " %d %d %.6e %.6e\n",
1032 (int)rb, (int)cb, (double)PetscSqrtReal(block2[rb][cb]),
1033 (double)PetscSqrtReal(sym2[rb][cb])));
1034
1035 for (PetscInt q = 0; q < 8; q++) {
1036 top[q] = -1;
1037 for (PetscInt r = 0; r < map->n; r++) {
1038 PetscBool used = PETSC_FALSE;
1039 for (PetscInt p = 0; p < q; p++) if (top[p] == r) used = PETSC_TRUE;
1040 if (!used && (top[q] < 0 || row2[r] > row2[top[q]])) top[q] = r;
1041 }
1042 }
1043 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1044 " --- largest rows of S=0.5*(J+J^T) ---\n"
1045 " row comp (i,j,k) seam-adj ||S_row||2 largest symmetric columns\n"));
1046 for (PetscInt q = 0; q < 8; q++) {
1047 const PetscInt r = top[q];
1048 PetscInt best[3] = {-1,-1,-1};
1049 for (PetscInt pass = 0; pass < 3; pass++) {
1050 for (PetscInt c = 0; c < map->n; c++) {
1051 PetscBool used = PETSC_FALSE;
1052 for (PetscInt p = 0; p < pass; p++) if (best[p] == c) used = PETSC_TRUE;
1053 const PetscReal mag = PetscAbsReal(0.5*(J[r + c*map->n] + J[c + r*map->n]));
1054 if (!used && (best[pass] < 0 ||
1055 mag > PetscAbsReal(0.5*(J[r + best[pass]*map->n] + J[best[pass] + r*map->n])))) best[pass] = c;
1056 }
1057 }
1058 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1059 " %3d %d (%d,%d,%d) %s %.6e",
1060 (int)r, (int)map->comp[r], (int)map->ci[r], (int)map->cj[r], (int)map->ck[r],
1061 DofTouchesPeriodicRepresentative(map, r, user->info) ? "yes" : "no ",
1062 (double)PetscSqrtReal(row2[r])));
1063 for (PetscInt p = 0; p < 3; p++) {
1064 const PetscInt c = best[p];
1065 const PetscReal s = 0.5*(J[r + c*map->n] + J[c + r*map->n]);
1066 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " | c%d:%d(%d,%d,%d)=%.3e",
1067 (int)p, (int)map->comp[c], (int)map->ci[c], (int)map->cj[c],
1068 (int)map->ck[c], (double)s));
1069 }
1070 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n"));
1071 }
1072 PetscCall(PetscFree(row2));
1073 PetscFunctionReturn(0);
1074}
static PetscBool DofTouchesPeriodicRepresentative(const DofMap *map, PetscInt m, DMDALocalInfo info)
True if an active representative lies on a plane adjacent to periodic duplicates.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillStaggeredFourierBasis()

static void FillStaggeredFourierBasis ( const DofMap map,
PetscInt  wx,
PetscInt  wy,
PetscInt  wz,
PetscReal *  Q 
)
static

Fills the six real basis vectors for one staggered same-wavevector subspace.

Definition at line 1079 of file test_momentum_convective_candidates.c.

1081{
1082 PetscInt nrep = 0;
1083 for (PetscInt m = 0; m < map->n; m++) nrep = PetscMax(nrep, map->ci[m]);
1084 for (PetscInt q = 0; q < 6*map->n; q++) Q[q] = 0.0;
1085 for (PetscInt m = 0; m < map->n; m++) {
1086 const PetscInt comp = map->comp[m];
1087 const PetscReal x = (PetscReal)(map->ci[m]-1) - (comp == 0 ? 0.5 : 0.0);
1088 const PetscReal y = (PetscReal)(map->cj[m]-1) - (comp == 1 ? 0.5 : 0.0);
1089 const PetscReal z = (PetscReal)(map->ck[m]-1) - (comp == 2 ? 0.5 : 0.0);
1090 const PetscReal phase = 2.0*PETSC_PI*((PetscReal)wx*x + (PetscReal)wy*y + (PetscReal)wz*z)/(PetscReal)nrep;
1091 Q[m + (2*comp+0)*map->n] = PetscCosReal(phase);
1092 Q[m + (2*comp+1)*map->n] = PetscSinReal(phase);
1093 }
1094 for (PetscInt q = 0; q < 6; q++) {
1095 PetscReal n2 = 0.0;
1096 for (PetscInt m = 0; m < map->n; m++) n2 += Q[m + q*map->n]*Q[m + q*map->n];
1097 n2 = PetscSqrtReal(n2);
1098 if (n2 > 0.0) for (PetscInt m = 0; m < map->n; m++) Q[m + q*map->n] /= n2;
1099 }
1100}
Here is the caller graph for this function:

◆ StaggeredFourierSymbol()

static PetscErrorCode StaggeredFourierSymbol ( const DofMap map,
const PetscReal *  J,
PetscInt  wx,
PetscInt  wy,
PetscInt  wz,
PetscReal  A6[36],
PetscReal *  leak 
)
static

Builds the 6x6 projected real symbol and leakage for one wavevector.

Definition at line 1105 of file test_momentum_convective_candidates.c.

1108{
1109 PetscReal *Q, *JQ;
1110 PetscReal all2 = 0.0, leak2 = 0.0;
1111 PetscFunctionBeginUser;
1112 PetscCall(PetscMalloc2((size_t)6*map->n, &Q, (size_t)6*map->n, &JQ));
1113 FillStaggeredFourierBasis(map, wx, wy, wz, Q);
1114 for (PetscInt q = 0; q < 6; q++) DenseMatVec(J, &Q[q*map->n], &JQ[q*map->n], map->n);
1115 for (PetscInt c = 0; c < 6; c++)
1116 for (PetscInt r = 0; r < 6; r++) {
1117 PetscReal s = 0.0;
1118 for (PetscInt m = 0; m < map->n; m++) s += Q[m + r*map->n] * JQ[m + c*map->n];
1119 A6[r + c*6] = s;
1120 }
1121 for (PetscInt c = 0; c < 6; c++) {
1122 for (PetscInt m = 0; m < map->n; m++) {
1123 PetscReal proj = 0.0;
1124 for (PetscInt r = 0; r < 6; r++) proj += Q[m + r*map->n] * A6[r + c*6];
1125 const PetscReal d = JQ[m + c*map->n] - proj;
1126 leak2 += d*d;
1127 all2 += JQ[m + c*map->n]*JQ[m + c*map->n];
1128 }
1129 }
1130 *leak = PetscSqrtReal(leak2) / PetscMax(PETSC_MACHINE_EPSILON, PetscSqrtReal(all2));
1131 PetscCall(PetscFree2(Q, JQ));
1132 PetscFunctionReturn(0);
1133}
static void DenseMatVec(const PetscReal *J, const PetscReal *x, PetscReal *y, PetscInt n)
Applies a dense column-major matrix to an active-space vector.
static void FillStaggeredFourierBasis(const DofMap *map, PetscInt wx, PetscInt wy, PetscInt wz, PetscReal *Q)
Fills the six real basis vectors for one staggered same-wavevector subspace.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SymbolEigenSummary()

static PetscErrorCode SymbolEigenSummary ( const PetscReal  A6[36],
PetscReal *  maxre,
PetscReal  wr_out[6],
PetscReal  wi_out[6] 
)
static

Eigenvalue summary for a 6x6 real symbol.

Definition at line 1138 of file test_momentum_convective_candidates.c.

1140{
1141 PetscBLASInt N = 6, lda = 6, lwork = 128, info;
1142 PetscReal Acopy[36], work[128], dummy = 0.0;
1143 PetscFunctionBeginUser;
1144 for (PetscInt t = 0; t < 36; t++) Acopy[t] = A6[t];
1145 {
1146 char nochar = 'N';
1147 LAPACKgeev_(&nochar, &nochar, &N, Acopy, &lda, wr_out, wi_out, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
1148 }
1149 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "LAPACK dgeev failed for 6x6 symbol: info=%d", (int)info);
1150 *maxre = -PETSC_MAX_REAL;
1151 for (PetscInt q = 0; q < 6; q++) *maxre = PetscMax(*maxre, wr_out[q]);
1152 PetscFunctionReturn(0);
1153}
Here is the caller graph for this function:

◆ PrintFourierChecks()

static PetscErrorCode PrintFourierChecks ( const DofMap map,
const PetscReal *  J 
)
static

Projects production J on full staggered six-dimensional Fourier subspaces.

Definition at line 1158 of file test_momentum_convective_candidates.c.

1159{
1160 typedef struct { const char *name; PetscInt wx, wy, wz; } Mode;
1161 const Mode modes[4] = {{"x",1,0,0}, {"y",0,1,0}, {"xy",1,1,0}, {"x-y",1,2,0}};
1162 PetscReal best_re = -PETSC_MAX_REAL, best_leak = 0.0;
1163 PetscInt best_wx = 0, best_wy = 0, best_wz = 0, nrep = 0;
1164 PetscFunctionBeginUser;
1165 for (PetscInt m = 0; m < map->n; m++) nrep = PetscMax(nrep, map->ci[m]);
1166 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1167 " --- staggered 6x6 Fourier-symbol check ---\n"
1168 " mode max_real leakage eigenvalues (real,imag)\n"));
1169 for (PetscInt im = 0; im < 4; im++) {
1170 PetscReal A6[36], wr[6], wi[6], maxre, leak;
1171 PetscCall(StaggeredFourierSymbol(map, J, modes[im].wx, modes[im].wy, modes[im].wz, A6, &leak));
1172 PetscCall(SymbolEigenSummary(A6, &maxre, wr, wi));
1173 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1174 " %-5s(%d,%d,%d) %.6e %.3e",
1175 modes[im].name, (int)modes[im].wx, (int)modes[im].wy, (int)modes[im].wz,
1176 (double)maxre, (double)leak));
1177 for (PetscInt q = 0; q < 6; q++) PetscCall(PetscPrintf(PETSC_COMM_WORLD, " %.3e%+.3ei", (double)wr[q], (double)wi[q]));
1178 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n"));
1179 }
1180 for (PetscInt wz = 0; wz < nrep; wz++)
1181 for (PetscInt wy = 0; wy < nrep; wy++)
1182 for (PetscInt wx = 0; wx < nrep; wx++) {
1183 if (wx == 0 && wy == 0 && wz == 0) continue;
1184 PetscReal A6[36], wr[6], wi[6], maxre, leak;
1185 PetscCall(StaggeredFourierSymbol(map, J, wx, wy, wz, A6, &leak));
1186 PetscCall(SymbolEigenSummary(A6, &maxre, wr, wi));
1187 if (maxre > best_re) {
1188 best_re = maxre; best_leak = leak; best_wx = wx; best_wy = wy; best_wz = wz;
1189 }
1190 }
1191 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1192 " best scanned wavevector (%d,%d,%d): max_real=%.6e leakage=%.3e\n",
1193 (int)best_wx, (int)best_wy, (int)best_wz, (double)best_re, (double)best_leak));
1194 PetscFunctionReturn(0);
1195}
static PetscErrorCode SymbolEigenSummary(const PetscReal A6[36], PetscReal *maxre, PetscReal wr_out[6], PetscReal wi_out[6])
Eigenvalue summary for a 6x6 real symbol.
static PetscErrorCode StaggeredFourierSymbol(const DofMap *map, const PetscReal *J, PetscInt wx, PetscInt wy, PetscInt wz, PetscReal A6[36], PetscReal *leak)
Builds the 6x6 projected real symbol and leakage for one wavevector.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TraceStateAResidualStages()

static PetscErrorCode TraceStateAResidualStages ( UserCtx user,
Vec  Ubase,
Vec  Rhs,
const DofMap map,
const PetscReal *  J 
)
static

Trace observable production residual stages for one deterministic perturbation.

Definition at line 1200 of file test_momentum_convective_candidates.c.

1202{
1203 Vec Upert, Conv;
1204 PetscReal *v, *ract;
1205 PetscReal seam_ucont[3], seam_ucat[3], conv2, convinf, rhs2, rhsinf;
1206 PetscInt active_rows[4] = {0,0,0,0};
1207 PetscFunctionBeginUser;
1208 PetscCall(VecDuplicate(Ubase, &Upert));
1209 PetscCall(VecDuplicate(user->lUcont, &Conv));
1210 PetscCall(PetscMalloc2(map->n, &v, map->n, &ract));
1211 FillAuditDirection(map, 0, v);
1212 PetscCall(VecCopy(Ubase, Upert));
1213 PetscCall(AddActiveVector(user, Upert, map, v, 1e-6));
1214 PetscCall(VecCopy(Upert, user->Ucont));
1215 {
1216 const char *fld[] = {"Ucont"};
1217 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fld));
1218 }
1219 PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcont, seam_ucont));
1220 PetscCall(Contra2Cart(user));
1221 PetscCall(UpdateLocalGhosts(user, "Ucat"));
1222 PetscCall(ComputeLocalDuplicateMismatch(user, user->lUcat, seam_ucat));
1223 PetscCall(Convection(user, user->lUcont, user->lUcat, Conv));
1224 PetscCall(VecNorm(Conv, NORM_2, &conv2));
1225 PetscCall(VecNorm(Conv, NORM_INFINITY, &convinf));
1226 PetscCall(EvalConvResidual(user, Upert, Rhs, map, ract));
1227 rhs2 = VecNorm2Array(ract, map->n);
1228 rhsinf = VecNormInfArray(ract, map->n);
1229 {
1230 PetscReal ***nvert;
1231 PetscCall(DMDAVecGetArrayRead(user->da, user->lNvert, &nvert));
1232 for (PetscInt m = 0; m < map->n; m++) {
1233 const PetscInt rows = MomCellActiveRows(nvert, map->ck[m], map->cj[m], map->ci[m],
1234 user->info.mx, user->info.my, user->info.mz,
1235 PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, 0);
1236 if (rows & (1 << map->comp[m])) active_rows[map->comp[m]]++;
1237 else active_rows[3]++;
1238 }
1239 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lNvert, &nvert));
1240 }
1241 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1242 " --- observable State A residual trace (mixed perturbation, amp=1e-6) ---\n"
1243 " after Ucont periodic sync duplicate mismatch (x,y,z)=%.3e %.3e %.3e\n"
1244 " after Contra2Cart Ucat duplicate mismatch (x,y,z)=%.3e %.3e %.3e\n"
1245 " direct Convection() Cartesian norm: ||Conv||2=%.6e ||Conv||inf=%.6e\n"
1246 " final active ComputeRHS() norm: ||R||2=%.6e ||R||inf=%.6e\n"
1247 " active-row mask counts by component: u=%d v=%d w=%d discarded=%d\n"
1248 " final active-space skewness defect already reported from J: %.3e\n",
1249 (double)seam_ucont[0], (double)seam_ucont[1], (double)seam_ucont[2],
1250 (double)seam_ucat[0], (double)seam_ucat[1], (double)seam_ucat[2],
1251 (double)conv2, (double)convinf, (double)rhs2, (double)rhsinf,
1252 (int)active_rows[0], (int)active_rows[1], (int)active_rows[2], (int)active_rows[3],
1253 (double)DenseSkewnessDefect(J, map->n)));
1254 PetscCall(PetscFree2(v, ract));
1255 PetscCall(VecDestroy(&Upert));
1256 PetscCall(VecDestroy(&Conv));
1257 PetscFunctionReturn(0);
1258}
PetscInt MomCellActiveRows(PetscReal ***nvert, PetscInt k, PetscInt j, PetscInt i, PetscInt mx, PetscInt my, PetscInt mz, PetscBool np_x1, PetscBool np_y1, PetscBool np_z1, PetscInt twoD)
Active staggered-momentum row mask for a cell (exposed for unit testing).
PetscErrorCode Convection(UserCtx *user, Vec Ucont, Vec Ucat, Vec Conv)
Computes the convective contribution to the contravariant momentum RHS.
Definition rhs.c:13
static PetscErrorCode EvalConvResidual(UserCtx *user, Vec Ucont_in, Vec Rhs, const DofMap *map, PetscReal *Ract)
static PetscReal VecNorm2Array(const PetscReal *x, PetscInt n)
Computes the Euclidean norm of a dense vector.
static void FillAuditDirection(const DofMap *map, PetscInt kind, PetscReal *x)
Fills one deterministic active-space vector used by dense/matrix-free checks.
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 PetscReal VecNormInfArray(const PetscReal *x, PetscInt n)
Computes the infinity norm of a dense vector.
Here is the call graph for this function:
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 1263 of file test_momentum_convective_candidates.c.

1264{
1265 PetscReal s = 0.0;
1266 for (PetscInt i = 0; i < n*n; i++) {
1267 const PetscReal d = A[i] - B[i];
1268 s += d*d;
1269 }
1270 return PetscSqrtReal(s) / PetscMax(1.0, denom_ref);
1271}
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 1293 of file test_momentum_convective_candidates.c.

1294{
1295 Cmpnts ***a;
1296 PetscFunctionBeginUser;
1297 PetscCall(DMDAVecGetArrayRead(user->fda, U, &a));
1298 for (PetscInt m = 0; m < map->n; m++) {
1299 const PetscReal *p = (const PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]];
1300 x[m] = p[map->comp[m]];
1301 }
1302 PetscCall(DMDAVecRestoreArrayRead(user->fda, U, &a));
1303 PetscFunctionReturn(0);
1304}
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 1309 of file test_momentum_convective_candidates.c.

1310{
1311 return 1.0 + 0.013*(PetscReal)(map->comp[m]+1)
1312 + 0.017*(PetscReal)map->ci[m]
1313 + 0.019*(PetscReal)map->cj[m]
1314 + 0.023*(PetscReal)map->ck[m];
1315}
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 1320 of file test_momentum_convective_candidates.c.

1321{
1322 PetscReal loc2 = 0.0, locinf = 0.0, locsum = 0.0;
1323 PetscReal glo2, gloinf, glosum;
1324 PetscFunctionBeginUser;
1325 for (PetscInt m = 0; m < map->n; m++) {
1326 loc2 += x[m]*x[m];
1327 locinf = PetscMax(locinf, PetscAbsReal(x[m]));
1328 locsum += DofWeight(map, m)*x[m];
1329 }
1330 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
1331 PetscCallMPI(MPI_Allreduce(&locinf, &gloinf, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
1332 PetscCallMPI(MPI_Allreduce(&locsum, &glosum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
1333 stats->n2 = PetscSqrtReal(glo2); stats->ninf = gloinf; stats->checksum = glosum;
1334 PetscFunctionReturn(0);
1335}
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 1340 of file test_momentum_convective_candidates.c.

1341{
1342 PetscReal loc2 = 0.0, glo2;
1343 PetscFunctionBeginUser;
1344 PetscCall(VecSet(V, 0.0));
1345 for (PetscInt m = 0; m < map->n; m++) {
1346 x[m] = PetscSinReal(0.37*(PetscReal)(map->ci[m]+1)
1347 + 0.51*(PetscReal)(map->cj[m]+1)
1348 + 0.73*(PetscReal)(map->ck[m]+1)
1349 + 0.29*(PetscReal)(map->comp[m]+1));
1350 loc2 += x[m]*x[m];
1351 }
1352 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
1353 const PetscReal invn = 1.0/PetscSqrtReal(glo2);
1354 for (PetscInt m = 0; m < map->n; m++) x[m] *= invn;
1355 PetscCall(AddActiveVector(user, V, map, x, 1.0));
1356 PetscFunctionReturn(0);
1357}
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 1363 of file test_momentum_convective_candidates.c.

1365{
1366 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1367 PetscFunctionBeginUser;
1368 PetscCall(VecCopy(U0full, Uwork)); /* stage state */
1369 for (int s = 0; s < 4; s++) {
1370 PetscCall(EvalConvResidual(user, Uwork, Rhs, map, Rscratch)); /* R(U^{(s)}) into active rows */
1371 PetscCall(VecCopy(U0full, Uout)); /* U^{(s+1)} = U0 + alfa*dtau*R */
1372 Cmpnts ***a;
1373 PetscCall(DMDAVecGetArray(user->fda, Uout, &a));
1374 for (PetscInt m = 0; m < map->n; m++) {
1375 PetscReal *p = (PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]];
1376 p[map->comp[m]] += alfa[s]*dtau*Rscratch[m];
1377 }
1378 PetscCall(DMDAVecRestoreArray(user->fda, Uout, &a));
1379 PetscCall(VecCopy(Uout, Uwork));
1380 }
1381 PetscFunctionReturn(0);
1382}
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 1387 of file test_momentum_convective_candidates.c.

1389{
1390 PetscFunctionBeginUser;
1391 PetscCall(VecCopy(U0full, Ustage));
1392 PetscCall(AddActiveVector(user, Ustage, map, Ract, scale));
1393 PetscFunctionReturn(0);
1394}
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 1399 of file test_momentum_convective_candidates.c.

1402{
1403 const PetscReal alfa[3] = {0.25, 1.0/3.0, 0.5};
1404 PetscFunctionBeginUser;
1405 PetscCall(EvalConvResidual(user, U0full, Rhs, map, Rscratch));
1406 PetscCall(SetAnchoredStage(user, U0full, alfa[0]*dtau, map, Rscratch, Y1));
1407 PetscCall(EvalConvResidual(user, Y1, Rhs, map, Rscratch));
1408 PetscCall(SetAnchoredStage(user, U0full, alfa[1]*dtau, map, Rscratch, Y2));
1409 PetscCall(EvalConvResidual(user, Y2, Rhs, map, Rscratch));
1410 PetscCall(SetAnchoredStage(user, U0full, alfa[2]*dtau, map, Rscratch, Y3));
1411 PetscFunctionReturn(0);
1412}
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 1417 of file test_momentum_convective_candidates.c.

1420{
1421 PetscFunctionBeginUser;
1422 for (PetscInt col = 0; col < map->n; col++) {
1423 PetscReal u0;
1424 PetscCall(GetDof(user, Ucenter, map, col, &u0));
1425 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1426 PetscCall(VecCopy(Ucenter, Uwork));
1427 PetscCall(PerturbDof(user, Uwork, map, col, +eps));
1428 PetscCall(EvalConvResidual(user, Uwork, Rhs, map, Rp));
1429 PetscCall(VecCopy(Ucenter, Uwork));
1430 PetscCall(PerturbDof(user, Uwork, map, col, -eps));
1431 PetscCall(EvalConvResidual(user, Uwork, Rhs, map, Rm));
1432 for (PetscInt row = 0; row < map->n; row++) J[row + col*map->n] = (Rp[row]-Rm[row])/(2.0*eps);
1433 }
1434 PetscFunctionReturn(0);
1435}
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:

◆ CheckDenseJacobianAction()

static PetscErrorCode CheckDenseJacobianAction ( UserCtx user,
Vec  Ubase,
Vec  Rhs,
Vec  Uwork,
const DofMap map,
const PetscReal *  J,
PetscReal  epsrel 
)
static

Verifies that the assembled dense Jacobian has the same action as production FD Jv.

Definition at line 1472 of file test_momentum_convective_candidates.c.

1475{
1476 Vec Up, Um;
1477 PetscReal *v, *jd, *Rp, *Rm, *jmf;
1478 PetscFunctionBeginUser;
1479 PetscCall(VecDuplicate(Ubase, &Up));
1480 PetscCall(VecDuplicate(Ubase, &Um));
1481 PetscCall(PetscMalloc5(map->n, &v, map->n, &jd, map->n, &Rp, map->n, &Rm, map->n, &jmf));
1482 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1483 " --- dense Jacobian action check against matrix-free production Jv ---\n"
1484 " direction rel_L2 rel_Linf ||Jv||2 ||Jv||inf\n"));
1485 const char *names[5] = {"mixed-sin", "mixed-cos", "u-only", "v-only", "w-only"};
1486 for (PetscInt kind = 0; kind < 5; kind++) {
1487 FillAuditDirection(map, kind, v);
1488 DenseMatVec(J, v, jd, map->n);
1489 PetscCall(VecCopy(Ubase, Up));
1490 PetscCall(VecCopy(Ubase, Um));
1491 PetscCall(AddActiveVector(user, Up, map, v, +epsrel));
1492 PetscCall(AddActiveVector(user, Um, map, v, -epsrel));
1493 PetscCall(EvalConvResidual(user, Up, Rhs, map, Rp));
1494 PetscCall(EvalConvResidual(user, Um, Rhs, map, Rm));
1495 for (PetscInt m = 0; m < map->n; m++) jmf[m] = (Rp[m]-Rm[m])/(2.0*epsrel);
1496 PetscReal e2 = 0.0, einf = 0.0;
1497 for (PetscInt m = 0; m < map->n; m++) {
1498 const PetscReal d = jd[m] - jmf[m];
1499 e2 += d*d; einf = PetscMax(einf, PetscAbsReal(d));
1500 }
1501 const PetscReal n2 = VecNorm2Array(jmf, map->n);
1502 const PetscReal ni = VecNormInfArray(jmf, map->n);
1503 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1504 " %-13s %.3e %.3e %.6e %.6e\n",
1505 names[kind], (double)(PetscSqrtReal(e2)/PetscMax(PETSC_MACHINE_EPSILON,n2)),
1506 (double)(einf/PetscMax(PETSC_MACHINE_EPSILON,ni)), (double)n2, (double)ni));
1507 }
1508 (void)Uwork;
1509 PetscCall(PetscFree5(v, jd, Rp, Rm, jmf));
1510 PetscCall(VecDestroy(&Up));
1511 PetscCall(VecDestroy(&Um));
1512 PetscFunctionReturn(0);
1513}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MatrixFreeJv()

static PetscErrorCode MatrixFreeJv ( UserCtx user,
Vec  Ubase,
Vec  Rhs,
const DofMap map,
const PetscReal *  v,
PetscReal  eps,
PetscReal *  jv 
)
static

Matrix-free production Jacobian-vector product on the active space.

Definition at line 1518 of file test_momentum_convective_candidates.c.

1520{
1521 Vec Up, Um;
1522 PetscReal *Rp, *Rm;
1523 PetscFunctionBeginUser;
1524 PetscCall(VecDuplicate(Ubase, &Up));
1525 PetscCall(VecDuplicate(Ubase, &Um));
1526 PetscCall(PetscMalloc2(map->n, &Rp, map->n, &Rm));
1527 PetscCall(VecCopy(Ubase, Up));
1528 PetscCall(VecCopy(Ubase, Um));
1529 PetscCall(AddActiveVector(user, Up, map, v, +eps));
1530 PetscCall(AddActiveVector(user, Um, map, v, -eps));
1531 PetscCall(EvalConvResidual(user, Up, Rhs, map, Rp));
1532 PetscCall(EvalConvResidual(user, Um, Rhs, map, Rm));
1533 for (PetscInt m = 0; m < map->n; m++) jv[m] = (Rp[m]-Rm[m])/(2.0*eps);
1534 PetscCall(PetscFree2(Rp, Rm));
1535 PetscCall(VecDestroy(&Up));
1536 PetscCall(VecDestroy(&Um));
1537 PetscFunctionReturn(0);
1538}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DenseAdditivityError()

static PetscReal DenseAdditivityError ( const PetscReal *  A,
const PetscReal *  B,
const PetscReal *  C,
PetscInt  n 
)
static

Normalized Frobenius norm of A - (B+C).

Definition at line 1543 of file test_momentum_convective_candidates.c.

1545{
1546 PetscReal num = 0.0, den = 0.0;
1547 for (PetscInt t = 0; t < n*n; t++) {
1548 const PetscReal d = A[t] - B[t] - C[t];
1549 num += d*d; den += A[t]*A[t];
1550 }
1551 return PetscSqrtReal(num) / PetscMax(1.0, PetscSqrtReal(den));
1552}
Here is the caller graph for this function:

◆ DenseCommutatorNorm()

static PetscReal DenseCommutatorNorm ( const PetscReal *  A,
const PetscReal *  B,
PetscInt  n 
)
static

Computes C = A*B - B*A and returns its normalized Frobenius norm.

Definition at line 1557 of file test_momentum_convective_candidates.c.

1558{
1559 PetscReal num = 0.0;
1560 for (PetscInt c = 0; c < n; c++) {
1561 for (PetscInt r = 0; r < n; r++) {
1562 PetscReal ab = 0.0, ba = 0.0;
1563 for (PetscInt q = 0; q < n; q++) {
1564 ab += A[r + q*n] * B[q + c*n];
1565 ba += B[r + q*n] * A[q + c*n];
1566 }
1567 const PetscReal d = ab - ba;
1568 num += d*d;
1569 }
1570 }
1571 const PetscReal den = PetscMax(DenseFrobenius(A, n)*DenseFrobenius(B, n), PETSC_MACHINE_EPSILON);
1572 return PetscSqrtReal(num) / den;
1573}
static PetscReal DenseFrobenius(const PetscReal *A, PetscInt n)
Computes the Frobenius norm of a dense column-major matrix.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RunStateADirectionalMechanismAudit()

static PetscErrorCode RunStateADirectionalMechanismAudit ( const PetscReal *  Jxy,
UserCtx user_xy,
Vec  Ubase_xy,
Vec  Rhs_xy,
const DofMap map_xy,
PetscReal  epsrel 
)
static

Builds Jx, Jy, Jxy and prints additivity/commutator/eigenpair diagnostics.

Definition at line 1578 of file test_momentum_convective_candidates.c.

1581{
1582 SimCtx *simCtx = NULL; UserCtx *user = NULL; DofMap map;
1583 Vec Ux, Uy, Rhs, Uwork;
1584 PetscReal *Rp, *Rm, *Jx, *Jy, *Jsum, *vr, *vi, *jdr, *jdi, *jmfr, *jmfi;
1585 PetscReal repeat_err, maxdiv, lamr, lami;
1586 SeamDiagnostics seam;
1587 PetscFunctionBeginUser;
1588 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
1589 PetscCall(ConfigureCandidateFixture(simCtx, user));
1590 PetscCall(DofMapBuild(user, &map));
1591 PetscCheck(map.n == map_xy->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "directional audit map size mismatch");
1592 PetscCall(VecDuplicate(user->Ucont, &Ux));
1593 PetscCall(VecDuplicate(user->Ucont, &Uy));
1594 PetscCall(VecDuplicate(user->Ucont, &Rhs));
1595 PetscCall(VecDuplicate(user->Ucont, &Uwork));
1596 PetscCall(PetscMalloc5(map.n, &Rp, map.n, &Rm, (size_t)map.n*map.n, &Jx,
1597 (size_t)map.n*map.n, &Jy, (size_t)map.n*map.n, &Jsum));
1598 PetscCall(BuildBaseState(user, STATE_A_X, Ux, &repeat_err, &maxdiv, &seam));
1599 PetscCall(BuildFDJacobian(user, Ux, epsrel, Rhs, &map, Rp, Rm, Uwork, Jx));
1600 PetscCall(BuildBaseState(user, STATE_A_Y, Uy, &repeat_err, &maxdiv, &seam));
1601 PetscCall(BuildFDJacobian(user, Uy, epsrel, Rhs, &map, Rp, Rm, Uwork, Jy));
1602 for (PetscInt t = 0; t < map.n*map.n; t++) Jsum[t] = Jx[t] + Jy[t];
1603
1604 const PetscReal add_err = DenseAdditivityError(Jxy, Jx, Jy, map.n);
1605 const PetscReal comm = DenseCommutatorNorm(Jx, Jy, map.n);
1606 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1607 " --- State A directional additivity / noncommutation audit ---\n"
1608 " ||Jxy-(Jx+Jy)||F/max(1,||Jxy||F) = %.3e\n"
1609 " ||Jx Jy - Jy Jx||F/(||Jx||F||Jy||F) = %.3e\n"
1610 " spectra:\n", (double)add_err, (double)comm));
1611 PetscCall(PrintSpectrumSummary("Jx", Jx, map.n));
1612 PetscCall(PrintSpectrumSummary("Jy", Jy, map.n));
1613 PetscCall(PrintSpectrumSummary("Jx+Jy", Jsum, map.n));
1614 PetscCall(PrintSpectrumSummary("Jxy", Jxy, map.n));
1615
1616 PetscCall(PetscMalloc6(map.n, &vr, map.n, &vi, map.n, &jdr, map.n, &jdi, map.n, &jmfr, map.n, &jmfi));
1617 PetscCall(DenseMaxRealRightEigenpair(Jxy, map.n, &lamr, &lami, vr, vi));
1618 DenseMatVec(Jxy, vr, jdr, map.n);
1619 DenseMatVec(Jxy, vi, jdi, map.n);
1620 PetscReal ed2 = 0.0, em2 = 0.0, v2 = 0.0;
1621 for (PetscInt m = 0; m < map.n; m++) {
1622 const PetscReal rr = jdr[m] - (lamr*vr[m] - lami*vi[m]);
1623 const PetscReal ri = jdi[m] - (lami*vr[m] + lamr*vi[m]);
1624 ed2 += rr*rr + ri*ri;
1625 v2 += vr[m]*vr[m] + vi[m]*vi[m];
1626 }
1627 PetscCall(MatrixFreeJv(user_xy, Ubase_xy, Rhs_xy, map_xy, vr, epsrel, jmfr));
1628 PetscCall(MatrixFreeJv(user_xy, Ubase_xy, Rhs_xy, map_xy, vi, epsrel, jmfi));
1629 for (PetscInt m = 0; m < map.n; m++) {
1630 const PetscReal rr = jmfr[m] - (lamr*vr[m] - lami*vi[m]);
1631 const PetscReal ri = jmfi[m] - (lami*vr[m] + lamr*vi[m]);
1632 em2 += rr*rr + ri*ri;
1633 }
1634 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1635 " --- State A unstable eigenpair verification ---\n"
1636 " lambda_max_real = %.12e%+.12ei\n"
1637 " ||Jdense v-lambda v||2/||v||2 = %.3e\n"
1638 " ||Jmf v-lambda v||2/||v||2 = %.3e\n",
1639 (double)lamr, (double)lami, (double)(PetscSqrtReal(ed2)/PetscSqrtReal(v2)),
1640 (double)(PetscSqrtReal(em2)/PetscSqrtReal(v2))));
1641
1642 PetscCall(PetscFree6(vr, vi, jdr, jdi, jmfr, jmfi));
1643 PetscCall(PetscFree5(Rp, Rm, Jx, Jy, Jsum));
1644 PetscCall(VecDestroy(&Ux)); PetscCall(VecDestroy(&Uy)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
1645 PetscCall(DofMapDestroy(&map));
1646 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
1647 PetscFunctionReturn(0);
1648}
static PetscErrorCode DofMapBuild(UserCtx *user, DofMap *map)
Builds the serial periodic independent face-DOF map used by dense Jacobians.
static PetscErrorCode DofMapDestroy(DofMap *map)
Releases storage owned by an active-DOF map.
static PetscReal DenseCommutatorNorm(const PetscReal *A, const PetscReal *B, PetscInt n)
Computes C = A*B - B*A and returns its normalized Frobenius norm.
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 DenseMaxRealRightEigenpair(const PetscReal *A, PetscInt n, PetscReal *lamr, PetscReal *lami, PetscReal *vr_out, PetscReal *vi_out)
Extracts the right eigenpair whose eigenvalue has largest real part.
static PetscReal DenseAdditivityError(const PetscReal *A, const PetscReal *B, const PetscReal *C, PetscInt n)
Normalized Frobenius norm of A - (B+C).
static PetscErrorCode MatrixFreeJv(UserCtx *user, Vec Ubase, Vec Rhs, const DofMap *map, const PetscReal *v, PetscReal eps, PetscReal *jv)
Matrix-free production Jacobian-vector product on the active space.
static PetscErrorCode BuildBaseState(UserCtx *user, CandState st, Vec Ubase, PetscReal *repeat_inf, PetscReal *maxdiv, SeamDiagnostics *seam)
static PetscErrorCode ConfigureCandidateFixture(SimCtx *simCtx, UserCtx *user)
Configures the minimal context for centered inviscid periodic convection tests.
static PetscErrorCode PrintSpectrumSummary(const char *name, const PetscReal *J, PetscInt n)
Prints eigenvalue and norm summary for one dense operator.
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:684
User-defined context containing data specific to a single computational grid level.
Definition variables.h:876
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ExtractLocalActiveVector()

static PetscErrorCode ExtractLocalActiveVector ( UserCtx user,
Vec  local,
const DofMap map,
PetscReal *  x 
)
static

Extract active-space entries from a local vector.

Definition at line 1660 of file test_momentum_convective_candidates.c.

1661{
1662 Cmpnts ***a;
1663 PetscFunctionBeginUser;
1664 PetscCall(DMDAVecGetArrayRead(user->fda, local, &a));
1665 for (PetscInt m = 0; m < map->n; m++) {
1666 const PetscReal *p = (const PetscReal*)&a[map->ck[m]][map->cj[m]][map->ci[m]];
1667 x[m] = p[map->comp[m]];
1668 }
1669 PetscCall(DMDAVecRestoreArrayRead(user->fda, local, &a));
1670 PetscFunctionReturn(0);
1671}
Here is the caller graph for this function:

◆ MapCartesianResidualToRct()

static PetscErrorCode MapCartesianResidualToRct ( UserCtx user,
Vec  Rc,
Vec  Rct 
)
static

Mirrors ComputeRHS's Cartesian residual -> contravariant local Rct mapping.

Definition at line 1676 of file test_momentum_convective_candidates.c.

1677{
1678 DMDALocalInfo info = user->info;
1679 const PetscInt xs = info.xs, xe = xs + info.xm, mx = info.mx;
1680 const PetscInt ys = info.ys, ye = ys + info.ym, my = info.my;
1681 const PetscInt zs = info.zs, ze = zs + info.zm, mz = info.mz;
1682 const PetscInt lxs = (xs==0) ? xs+1 : xs, lxe = (xe==mx) ? xe-1 : xe;
1683 const PetscInt lys = (ys==0) ? ys+1 : ys, lye = (ye==my) ? ye-1 : ye;
1684 const PetscInt lzs = (zs==0) ? zs+1 : zs, lze = (ze==mz) ? ze-1 : ze;
1685 Cmpnts ***csi, ***eta, ***zet, ***rc, ***rct;
1686 PetscReal ***aj;
1687 PetscFunctionBeginUser;
1688 PetscCall(VecSet(Rct, 0.0));
1689 PetscCall(DMDAVecGetArrayRead(user->fda, user->lCsi, &csi));
1690 PetscCall(DMDAVecGetArrayRead(user->fda, user->lEta, &eta));
1691 PetscCall(DMDAVecGetArrayRead(user->fda, user->lZet, &zet));
1692 PetscCall(DMDAVecGetArrayRead(user->da, user->lAj, &aj));
1693 PetscCall(DMDAVecGetArrayRead(user->fda, Rc, &rc));
1694 PetscCall(DMDAVecGetArray(user->fda, Rct, &rct));
1695 for (PetscInt k = lzs; k < lze; k++)
1696 for (PetscInt j = lys; j < lye; j++)
1697 for (PetscInt i = lxs; i < lxe; i++) {
1698 rct[k][j][i].x = aj[k][j][i] *
1699 (0.5 * (csi[k][j][i].x + csi[k][j][i-1].x) * rc[k][j][i].x +
1700 0.5 * (csi[k][j][i].y + csi[k][j][i-1].y) * rc[k][j][i].y +
1701 0.5 * (csi[k][j][i].z + csi[k][j][i-1].z) * rc[k][j][i].z);
1702 rct[k][j][i].y = aj[k][j][i] *
1703 (0.5 * (eta[k][j][i].x + eta[k][j-1][i].x) * rc[k][j][i].x +
1704 0.5 * (eta[k][j][i].y + eta[k][j-1][i].y) * rc[k][j][i].y +
1705 0.5 * (eta[k][j][i].z + eta[k][j-1][i].z) * rc[k][j][i].z);
1706 rct[k][j][i].z = aj[k][j][i] *
1707 (0.5 * (zet[k][j][i].x + zet[k-1][j][i].x) * rc[k][j][i].x +
1708 0.5 * (zet[k][j][i].y + zet[k-1][j][i].y) * rc[k][j][i].y +
1709 0.5 * (zet[k][j][i].z + zet[k-1][j][i].z) * rc[k][j][i].z);
1710 }
1711 PetscCall(DMDAVecRestoreArray(user->fda, Rct, &rct));
1712 PetscCall(DMDAVecRestoreArrayRead(user->fda, Rc, &rc));
1713 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lAj, &aj));
1714 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet));
1715 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta));
1716 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi));
1717 PetscCall(SynchronizePeriodicLocalStaggeredField(user, Rct));
1718 PetscFunctionReturn(0);
1719}
PetscErrorCode SynchronizePeriodicLocalStaggeredField(UserCtx *user, Vec local_field)
Synchronizes one local-only component-staggered periodic work field.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AverageRctToFinalActive()

static PetscErrorCode AverageRctToFinalActive ( UserCtx user,
Vec  Rct,
const DofMap map,
PetscReal *  out 
)
static

Mirrors ComputeRHS's final Rct face averaging and active cleanup for P=0/no body force.

Definition at line 1724 of file test_momentum_convective_candidates.c.

1725{
1726 Cmpnts ***rct;
1727 PetscFunctionBeginUser;
1728 PetscCall(DMDAVecGetArrayRead(user->fda, Rct, &rct));
1729 for (PetscInt m = 0; m < map->n; m++) {
1730 const PetscInt i = map->ci[m], j = map->cj[m], k = map->ck[m], c = map->comp[m];
1731 if (c == 0) out[m] = 0.5*(rct[k][j][i].x + rct[k][j][i+1].x);
1732 else if (c == 1) out[m] = 0.5*(rct[k][j][i].y + rct[k][j+1][i].y);
1733 else out[m] = 0.5*(rct[k][j][i].z + rct[k+1][j][i].z);
1734 }
1735 PetscCall(DMDAVecRestoreArrayRead(user->fda, Rct, &rct));
1736 PetscFunctionReturn(0);
1737}
Here is the caller graph for this function:

◆ EvalResidualStage()

static PetscErrorCode EvalResidualStage ( UserCtx user,
Vec  Ucont_in,
Vec  Rhs,
const DofMap map,
ResidualStage  stage,
PetscReal *  out 
)
static

Evaluates one observable/mirrored residual-path stage for a Ucont input.

Definition at line 1742 of file test_momentum_convective_candidates.c.

1744{
1745 Vec Conv, Rc, Rct;
1746 PetscFunctionBeginUser;
1747 if (stage == STAGE_FINAL) {
1748 PetscCall(EvalConvResidual(user, Ucont_in, Rhs, map, out));
1749 PetscFunctionReturn(0);
1750 }
1751 PetscCall(VecCopy(Ucont_in, user->Ucont));
1752 {
1753 const char *fld[] = {"Ucont"};
1754 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fld));
1755 }
1756 PetscCall(Contra2Cart(user));
1757 PetscCall(UpdateLocalGhosts(user, "Ucat"));
1758 if (stage == STAGE_UCAT) {
1759 PetscCall(ExtractActiveVector(user, user->Ucat, map, out));
1760 PetscFunctionReturn(0);
1761 }
1762 PetscCall(VecDuplicate(user->lUcont, &Conv));
1763 PetscCall(VecDuplicate(user->lUcont, &Rc));
1764 PetscCall(VecDuplicate(user->lUcont, &Rct));
1765 PetscCall(Convection(user, user->lUcont, user->lUcat, Conv));
1766 PetscCall(VecSet(Rc, 0.0));
1767 PetscCall(VecAXPY(Rc, -1.0, Conv));
1768 if (stage == STAGE_CART_RESID) PetscCall(ExtractLocalActiveVector(user, Rc, map, out));
1769 else {
1770 PetscCall(MapCartesianResidualToRct(user, Rc, Rct));
1771 if (stage == STAGE_RCT) PetscCall(ExtractLocalActiveVector(user, Rct, map, out));
1772 else PetscCall(AverageRctToFinalActive(user, Rct, map, out));
1773 }
1774 PetscCall(VecDestroy(&Conv));
1775 PetscCall(VecDestroy(&Rc));
1776 PetscCall(VecDestroy(&Rct));
1777 PetscFunctionReturn(0);
1778}
static PetscErrorCode AverageRctToFinalActive(UserCtx *user, Vec Rct, const DofMap *map, PetscReal *out)
Mirrors ComputeRHS's final Rct face averaging and active cleanup for P=0/no body force.
static PetscErrorCode MapCartesianResidualToRct(UserCtx *user, Vec Rc, Vec Rct)
Mirrors ComputeRHS's Cartesian residual -> contravariant local Rct mapping.
static PetscErrorCode ExtractActiveVector(UserCtx *user, Vec U, const DofMap *map, PetscReal *x)
Extracts active-space entries from a global contravariant vector.
static PetscErrorCode ExtractLocalActiveVector(UserCtx *user, Vec local, const DofMap *map, PetscReal *x)
Extract active-space entries from a local vector.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildStageJacobian()

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

Builds a finite-difference Jacobian for one residual-path stage.

Definition at line 1783 of file test_momentum_convective_candidates.c.

1786{
1787 PetscFunctionBeginUser;
1788 for (PetscInt col = 0; col < map->n; col++) {
1789 PetscReal u0;
1790 PetscCall(GetDof(user, Ucenter, map, col, &u0));
1791 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1792 PetscCall(VecCopy(Ucenter, Uwork));
1793 PetscCall(PerturbDof(user, Uwork, map, col, +eps));
1794 PetscCall(EvalResidualStage(user, Uwork, Rhs, map, stage, Rp));
1795 PetscCall(VecCopy(Ucenter, Uwork));
1796 PetscCall(PerturbDof(user, Uwork, map, col, -eps));
1797 PetscCall(EvalResidualStage(user, Uwork, Rhs, map, stage, Rm));
1798 for (PetscInt row = 0; row < map->n; row++) J[row + col*map->n] = (Rp[row]-Rm[row])/(2.0*eps);
1799 }
1800 PetscFunctionReturn(0);
1801}
static PetscErrorCode EvalResidualStage(UserCtx *user, Vec Ucont_in, Vec Rhs, const DofMap *map, ResidualStage stage, PetscReal *out)
Evaluates one observable/mirrored residual-path stage for a Ucont input.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RunStateAResidualPathIsolation()

static PetscErrorCode RunStateAResidualPathIsolation ( UserCtx user,
Vec  Ubase,
Vec  Rhs,
Vec  Uwork,
const DofMap map,
PetscReal  epsrel 
)
static

Prints the stage where positive-real spectrum first appears.

Definition at line 1806 of file test_momentum_convective_candidates.c.

1808{
1809 const char *names[4] = {"Contra2Cart Ucat", "Cartesian Rc=-Conv", "mapped local Rct", "final active RHS"};
1810 PetscReal *Rp, *Rm, *J;
1811 PetscFunctionBeginUser;
1812 PetscCall(PetscMalloc3(map->n, &Rp, map->n, &Rm, (size_t)map->n*map->n, &J));
1813 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1814 " --- State A residual-path stage Jacobians ---\n"
1815 " stage rho sigma max_real skew nonnormal\n"));
1816 for (PetscInt s = 0; s < 4; s++) {
1817 PetscReal rho, maxre, smax;
1818 PetscCall(BuildStageJacobian(user, Ubase, epsrel, Rhs, map, (ResidualStage)s, Rp, Rm, Uwork, J));
1819 PetscCall(DenseSpectralRadius(J, map->n, &rho, &maxre));
1820 PetscCall(DenseSigmaMax(J, map->n, &smax, NULL));
1821 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1822 " %-20s %.6e %.6e %.6e %.3e %.3e\n",
1823 names[s], (double)rho, (double)smax, (double)maxre,
1824 (double)DenseSkewnessDefect(J, map->n), (double)DenseNonNormality(J, map->n)));
1825 }
1826 PetscCall(PetscFree3(Rp, Rm, J));
1827 PetscFunctionReturn(0);
1828}
static PetscErrorCode BuildStageJacobian(UserCtx *user, Vec Ucenter, PetscReal epsrel, Vec Rhs, const DofMap *map, ResidualStage stage, PetscReal *Rp, PetscReal *Rm, Vec Uwork, PetscReal *J)
Builds a finite-difference Jacobian for one residual-path stage.
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 1833 of file test_momentum_convective_candidates.c.

1836{
1837 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1838 PetscReal *T1, *T2, *T3, *Tmp;
1839 PetscFunctionBeginUser;
1840 PetscCall(PetscMalloc4(n*n, &T1, n*n, &T2, n*n, &T3, n*n, &Tmp));
1841
1842 for (PetscInt i = 0; i < n*n; i++) T1[i] = alfa[0]*dtau*J0[i];
1843 for (PetscInt d = 0; d < n; d++) T1[d + d*n] += 1.0;
1844
1845 MatMul(J1, T1, Tmp, n);
1846 for (PetscInt i = 0; i < n*n; i++) T2[i] = alfa[1]*dtau*Tmp[i];
1847 for (PetscInt d = 0; d < n; d++) T2[d + d*n] += 1.0;
1848
1849 MatMul(J2, T2, Tmp, n);
1850 for (PetscInt i = 0; i < n*n; i++) T3[i] = alfa[2]*dtau*Tmp[i];
1851 for (PetscInt d = 0; d < n; d++) T3[d + d*n] += 1.0;
1852
1853 MatMul(J3, T3, Tmp, n);
1854 for (PetscInt i = 0; i < n*n; i++) T4[i] = alfa[3]*dtau*Tmp[i];
1855 for (PetscInt d = 0; d < n; d++) T4[d + d*n] += 1.0;
1856
1857 PetscCall(PetscFree4(T1, T2, T3, Tmp));
1858 PetscFunctionReturn(0);
1859}
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 1864 of file test_momentum_convective_candidates.c.

1869{
1870 PetscFunctionBeginUser;
1871 for (PetscInt col = 0; col < map->n; col++) {
1872 PetscReal u0;
1873 PetscCall(GetDof(user, Ucenter, map, col, &u0));
1874 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1875 PetscCall(VecCopy(Ucenter, Upert));
1876 PetscCall(PerturbDof(user, Upert, map, col, +eps));
1877 PetscCall(FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiP));
1878 PetscCall(VecCopy(Ucenter, Upert));
1879 PetscCall(PerturbDof(user, Upert, map, col, -eps));
1880 PetscCall(FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiM));
1881 PetscCall(ExtractActiveVector(user, PhiP, map, xp));
1882 PetscCall(ExtractActiveVector(user, PhiM, map, xm));
1883 for (PetscInt row = 0; row < map->n; row++) JPhi[row + col*map->n] = (xp[row]-xm[row])/(2.0*eps);
1884 }
1885 PetscFunctionReturn(0);
1886}
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 1891 of file test_momentum_convective_candidates.c.

1895{
1896 const PetscReal cflsB[4] = {0.1, 0.25, 0.5, 1.0};
1897 const PetscReal cflsOther[1] = {0.5};
1898 const PetscReal *cfls = (st == STATE_B) ? cflsB : cflsOther;
1899 const PetscInt ncfl = (st == STATE_B) ? 4 : 1;
1900 const PetscReal amps[3] = {1e-4, 1e-5, 1e-6};
1901 Vec Y1, Y2, Y3, Upert, Ustage, PhiP, PhiM, Phi0;
1902 PetscReal *Rtmp, *J1, *J2, *J3, *T4, *Pm, *JPhi, *v1, *xrand;
1903 PetscReal *meas, *phi0, *phip, *xscaled, *predP, *predT;
1904 PetscFunctionBeginUser;
1905
1906 PetscCall(VecDuplicate(Ubase, &Y1));
1907 PetscCall(VecDuplicate(Ubase, &Y2));
1908 PetscCall(VecDuplicate(Ubase, &Y3));
1909 PetscCall(VecDuplicate(Ubase, &Upert));
1910 PetscCall(VecDuplicate(Ubase, &Ustage));
1911 PetscCall(VecDuplicate(Ubase, &PhiP));
1912 PetscCall(VecDuplicate(Ubase, &PhiM));
1913 PetscCall(VecDuplicate(Ubase, &Phi0));
1914 PetscCall(PetscMalloc5(map->n, &Rtmp, (size_t)map->n*map->n, &J1,
1915 (size_t)map->n*map->n, &J2, (size_t)map->n*map->n, &J3,
1916 (size_t)map->n*map->n, &T4));
1917 PetscCall(PetscMalloc5((size_t)map->n*map->n, &Pm, (size_t)map->n*map->n, &JPhi,
1918 map->n, &v1, map->n, &xrand, map->n, &meas));
1919 PetscCall(PetscMalloc5(map->n, &phi0, map->n, &phip, map->n, &xscaled,
1920 map->n, &predP, map->n, &predT));
1921
1922 PetscReal nrm = 0.0;
1923 for (PetscInt m = 0; m < map->n; m++) {
1924 xrand[m] = PetscSinReal((PetscReal)(m+1)*1.2345);
1925 nrm += xrand[m]*xrand[m];
1926 }
1927 nrm = PetscSqrtReal(nrm);
1928 for (PetscInt m = 0; m < map->n; m++) xrand[m] /= nrm;
1929
1930 for (int cand = 0; cand < 3; cand++) {
1931 if (!(lams[cand] > 0.0)) continue;
1932 for (PetscInt icfl = 0; icfl < ncfl; icfl++) {
1933 const PetscReal cfl = cfls[icfl], dtau = cfl/lams[cand];
1934 PetscCall(BuildStageStates(user, Ubase, dtau, Rhs, map, Rtmp, Y1, Y2, Y3));
1935 PetscCall(BuildFDJacobian(user, Y1, epsrel, Rhs, map, phi0, phip, Upert, J1));
1936 PetscCall(BuildFDJacobian(user, Y2, epsrel, Rhs, map, phi0, phip, Upert, J2));
1937 PetscCall(BuildFDJacobian(user, Y3, epsrel, Rhs, map, phi0, phip, Upert, J3));
1938 PetscCall(BuildStageTangent(J0, J1, J2, J3, dtau, map->n, T4));
1939 PetscCall(RKPolynomial(J0, dtau, map->n, Pm));
1940 PetscCall(BuildPhiJacobian(user, Ubase, dtau, Rhs, map, Rtmp,
1941 Upert, Ustage, PhiP, PhiM, phip, phi0, epsrel, JPhi));
1942
1943 const PetscReal froT = DenseFrobenius(T4, map->n);
1944 const PetscReal froPhi = DenseFrobenius(JPhi, map->n);
1945 const PetscReal relTP = DenseRelativeDiff(T4, Pm, map->n, froT);
1946 const PetscReal relPhiT = DenseRelativeDiff(JPhi, T4, map->n, froPhi);
1947 const PetscReal relPhiP = DenseRelativeDiff(JPhi, Pm, map->n, froPhi);
1948 PetscReal smaxT, rhoT, dummyT;
1949 PetscCall(DenseSpectralRadius(T4, map->n, &rhoT, &dummyT));
1950 PetscCall(DenseSigmaMax(T4, map->n, &smaxT, v1));
1951
1952 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1953 " --- convection-only stage-dependent RK tangent (cand %s, CFL=%.2f, dtau=%.6e) ---\n"
1954 " rho(T4)=%.6e sigma_max(T4)=%.6e\n"
1955 " ||T4-P(hJ0)||F/max(1,||T4||F) = %.3e\n"
1956 " ||J_Phi-T4||F/max(1,||J_Phi||F) = %.3e\n"
1957 " ||J_Phi-P(hJ0)||F/max(1,||J_Phi||F)= %.3e\n",
1958 cn[cand], (double)cfl, (double)dtau, (double)rhoT, (double)smaxT,
1959 (double)relTP, (double)relPhiT, (double)relPhiP));
1960
1961 PetscCall(FourStage(user, Ubase, dtau, Rhs, map, Rtmp, Ustage, Phi0));
1962 PetscCall(ExtractActiveVector(user, Phi0, map, phi0));
1963 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1964 " direction amp amp(meas) amp(frozen) amp(stage) err(frozen) err(stage)\n"));
1965 for (int dir = 0; dir < 2; dir++) {
1966 const PetscReal *xv = (dir == 0) ? xrand : v1;
1967 const char *dname = (dir == 0) ? "random" : "v1(T4)";
1968 for (int a = 0; a < 3; a++) {
1969 const PetscReal amp = amps[a];
1970 PetscCall(VecCopy(Ubase, Upert));
1971 PetscCall(AddActiveVector(user, Upert, map, xv, amp));
1972 PetscCall(FourStage(user, Upert, dtau, Rhs, map, Rtmp, Ustage, PhiP));
1973 PetscCall(ExtractActiveVector(user, PhiP, map, phip));
1974 for (PetscInt m = 0; m < map->n; m++) meas[m] = phip[m] - phi0[m];
1975 for (PetscInt m = 0; m < map->n; m++) xscaled[m] = amp*xv[m];
1976 ApplyP(Pm, xscaled, predP, map->n);
1977 ApplyP(T4, xscaled, predT, map->n);
1978
1979 PetscReal eP = 0.0, eT = 0.0;
1980 for (PetscInt m = 0; m < map->n; m++) {
1981 const PetscReal dP = meas[m] - predP[m];
1982 const PetscReal dT = meas[m] - predT[m];
1983 eP += dP*dP; eT += dT*dT;
1984 }
1985 const PetscReal nm = VecNorm2Array(meas, map->n);
1986 const PetscReal nP = VecNorm2Array(predP, map->n);
1987 const PetscReal nT = VecNorm2Array(predT, map->n);
1988 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1989 " %-8s %.0e %.6e %.6e %.6e %.3e %.3e\n",
1990 dname, (double)amp, (double)(nm/amp), (double)(nP/amp), (double)(nT/amp),
1991 (double)(PetscSqrtReal(eP)/PetscMax(PETSC_MACHINE_EPSILON, nP)),
1992 (double)(PetscSqrtReal(eT)/PetscMax(PETSC_MACHINE_EPSILON, nT))));
1993 }
1994 }
1995
1996 PetscCall(PicurvAssertBool((PetscBool)(relPhiT < 1e-6),
1997 "stage tangent matches direct finite-difference RK map"));
1998 if (st == STATE_B) {
1999 PetscCall(PicurvAssertBool((PetscBool)(relTP > 1e-5),
2000 "B: non-steady base makes frozen-Jacobian RK map measurably different"));
2001 PetscCall(PicurvAssertBool((PetscBool)(relPhiP > 1e-5),
2002 "B: direct RK map confirms frozen-Jacobian error"));
2003 } else {
2004 PetscCall(PicurvAssertBool((PetscBool)(relTP < 1e-8),
2005 "steady base reduces stage tangent to frozen RK polynomial"));
2006 }
2007 }
2008 }
2009
2010 PetscCall(PetscFree5(Rtmp, J1, J2, J3, T4));
2011 PetscCall(PetscFree5(Pm, JPhi, v1, xrand, meas));
2012 PetscCall(PetscFree5(phi0, phip, xscaled, predP, predT));
2013 PetscCall(VecDestroy(&Y1)); PetscCall(VecDestroy(&Y2)); PetscCall(VecDestroy(&Y3));
2014 PetscCall(VecDestroy(&Upert)); PetscCall(VecDestroy(&Ustage));
2015 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Phi0));
2016 PetscFunctionReturn(0);
2017}
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 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 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 2022 of file test_momentum_convective_candidates.c.

2023{
2024 SimCtx *simCtx = NULL; UserCtx *user = NULL; DofMap map;
2025 Vec Ubase, Rhs, Uwork, Uout;
2026 PetscReal *Rref, *Rrep, *Jbest;
2027 PetscReal repeat_err, maxdiv, det_err;
2028 SeamDiagnostics seam;
2030 const PetscInt N = (st == STATE_C) ? 5 : 4; /* C uses one extra point for canonical shear. */
2031 PetscFunctionBeginUser;
2032
2033 /* periodic Cartesian fixture, inviscid + centered + P=0, no LES/RANS/Clark/IB/body force. */
2034 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, N, N, N, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
2035 PetscCall(ConfigureCandidateFixture(simCtx, user));
2036
2037 PetscCall(DofMapBuild(user, &map));
2038 PetscCall(VecDuplicate(user->Ucont, &Ubase));
2039 PetscCall(VecDuplicate(user->Ucont, &Rhs));
2040 PetscCall(VecDuplicate(user->Ucont, &Uwork));
2041 PetscCall(VecDuplicate(user->Ucont, &Uout));
2042 PetscCall(PetscMalloc3(map.n, &Rref, map.n, &Rrep, (size_t)map.n*map.n, &Jbest));
2043
2044 PetscCall(BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
2045
2046 /* residual determinism: evaluate the base residual twice. */
2047 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, Rref));
2048 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, Rrep));
2049 det_err = 0.0; for (PetscInt m = 0; m < map.n; m++) det_err = PetscMax(det_err, PetscAbsReal(Rref[m]-Rrep[m]));
2050 const PetscReal R0_2 = VecNorm2Array(Rref, map.n);
2051 const PetscReal R0_inf = VecNormInfArray(Rref, map.n);
2052
2053 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2054 "\n================ STATE %s ================\n"
2055 " grid: DMDA %d^3 (periodic) | independent face DOFs: actual=%d expected=%d\n"
2056 " declared endpoint mismatch (x,y,z) = %.3e %.3e %.3e\n"
2057 " actual Ucat duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
2058 " local lUcat ghost mismatch (x,y,z) = %.3e %.3e %.3e\n"
2059 " actual Ucont duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
2060 " ||Ucat_repeat - Ucat_reference||inf = %.3e\n"
2061 " max|div_h Ucont| = %.3e\n"
2062 " ||R(U0)||2 = %.6e ||R(U0)||inf = %.6e\n"
2063 " residual determinism ||R_rep-R_ref||inf = %.3e\n",
2064 name, (int)(N+1), (int)map.n,
2065 (int)map.expected_n,
2066 (double)seam.declared[0], (double)seam.declared[1], (double)seam.declared[2],
2067 (double)seam.ucat_global[0], (double)seam.ucat_global[1], (double)seam.ucat_global[2],
2068 (double)seam.ucat_ghost[0], (double)seam.ucat_ghost[1], (double)seam.ucat_ghost[2],
2069 (double)seam.ucont_global[0], (double)seam.ucont_global[1], (double)seam.ucont_global[2],
2070 (double)repeat_err, (double)maxdiv,
2071 (double)R0_2, (double)R0_inf, (double)det_err));
2072 if (st == STATE_A) PetscCall(PrintPeriodicSpaceAudit(user, &map));
2073
2074 /* ---- epsilon-convergence study: build J at several eps, compare to next-finer ---- */
2075 const PetscReal epsrel[5] = {1e-4, 1e-5, 1e-6, 1e-7, 1e-8};
2076 PetscReal *Jprev, *Jcur;
2077 PetscCall(PetscMalloc2((size_t)map.n*map.n, &Jprev, (size_t)map.n*map.n, &Jcur));
2078 PetscReal best_rel = PETSC_MAX_REAL; PetscInt best_e = 2;
2079 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " epsilon-convergence (||J_e - J_e/10||_F / ||J||_F):\n"));
2080 for (int e = 0; e < 5; e++) {
2081 /* build column-major J at epsrel[e] */
2082 for (PetscInt col = 0; col < map.n; col++) {
2083 PetscReal u0; PetscCall(GetDof(user, Ubase, &map, col, &u0));
2084 const PetscReal eps = epsrel[e]*PetscMax(1.0, PetscAbsReal(u0));
2085 PetscReal *Rp = Rref, *Rm = Rrep; /* reuse scratch */
2086 PetscCall(VecCopy(Ubase, Uwork));
2087 PetscCall(PerturbDof(user, Uwork, &map, col, +eps));
2088 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rp));
2089 PetscCall(VecCopy(Ubase, Uwork));
2090 PetscCall(PerturbDof(user, Uwork, &map, col, -eps));
2091 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rm));
2092 for (PetscInt row = 0; row < map.n; row++) Jcur[row + col*map.n] = (Rp[row]-Rm[row])/(2.0*eps);
2093 }
2094 if (e > 0) {
2095 PetscReal num = 0.0, den = 0.0;
2096 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]; }
2097 const PetscReal rel = PetscSqrtReal(num)/PetscMax(1.0, PetscSqrtReal(den));
2098 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " eps=%.0e -> %.0e : rel=%.3e\n",
2099 (double)epsrel[e-1], (double)epsrel[e], (double)rel));
2100 if (rel < best_rel) { best_rel = rel; best_e = e; }
2101 }
2102 if (st == STATE_A) {
2103 PetscReal erho, emaxre, esmax;
2104 PetscCall(DenseSpectralRadius(Jcur, map.n, &erho, &emaxre));
2105 PetscCall(DenseSigmaMax(Jcur, map.n, &esmax, NULL));
2106 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2107 " eps=%.0e metrics: rho=%.6e sigma=%.6e max_real=%.6e fro=%.6e skew=%.3e\n",
2108 (double)epsrel[e], (double)erho, (double)esmax, (double)emaxre,
2109 (double)DenseFrobenius(Jcur, map.n), (double)DenseSkewnessDefect(Jcur, map.n)));
2110 }
2111 PetscCall(PetscArraycpy(Jprev, Jcur, (size_t)map.n*map.n)); /* prev <- current (no pointer swap) */
2112 }
2113 /* rebuild J at the plateau epsilon into Jbest */
2114 {
2115 const PetscReal er = epsrel[best_e];
2116 for (PetscInt col = 0; col < map.n; col++) {
2117 PetscReal u0; PetscCall(GetDof(user, Ubase, &map, col, &u0));
2118 const PetscReal eps = er*PetscMax(1.0, PetscAbsReal(u0));
2119 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(PerturbDof(user, Uwork, &map, col, +eps));
2120 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rref));
2121 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(PerturbDof(user, Uwork, &map, col, -eps));
2122 PetscCall(EvalConvResidual(user, Uwork, Rhs, &map, Rrep));
2123 for (PetscInt row = 0; row < map.n; row++) Jbest[row + col*map.n] = (Rref[row]-Rrep[row])/(2.0*eps);
2124 }
2125 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " selected plateau eps = %.0e\n", (double)er));
2126 }
2127 PetscCall(PetscFree2(Jprev, Jcur));
2128
2129 /* The FD probes leave the production vectors at the final perturbed evaluation;
2130 restore the base state before every downstream diagnostic. */
2131 PetscCall(VecCopy(Ubase, user->Ucont));
2132 {
2133 const char *fld[] = {"Ucont"};
2134 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, fld));
2135 }
2136
2137 /* base state must be restored after the Jacobian build. */
2138 PetscBool eqbase; { Vec chk; PetscCall(VecDuplicate(Ubase,&chk)); PetscCall(VecCopy(user->Ucont,chk));
2139 PetscCall(VecAXPY(chk, -1.0, Ubase)); PetscReal nb; PetscCall(VecNorm(chk, NORM_INFINITY, &nb));
2140 eqbase = (PetscBool)(nb < 1e-12); PetscCall(VecDestroy(&chk));
2141 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " base Ucont restored after Jacobian: %s\n", eqbase?"yes":"NO")); }
2142
2143 /* The FD operator acts on Ucont; J is on the convective residual (sign per ComputeRHS). */
2144 PetscReal rho, maxre, smax;
2145 PetscCall(DenseSpectralRadius(Jbest, map.n, &rho, &maxre));
2146 PetscCall(DenseSigmaMax(Jbest, map.n, &smax, NULL));
2147 const PetscReal eta = DenseNonNormality(Jbest, map.n);
2148
2149 /* ---- candidate estimates (convection-only: lambda_cX = lambda_X - lambda_t) ---- */
2150 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, Rref)); /* restore lUcat consistent w/ base */
2151 PetscCall(UpdateLocalGhosts(user, "Ucont"));
2152 PetscCall(Contra2Cart(user)); PetscCall(UpdateLocalGhosts(user, "Ucat"));
2153 PetscCall(ComputeMomentumStabilityEstimate(user, 1, simCtx->dt, MOM_STAB_CAND_C, &rep));
2154 const PetscReal lcB = rep.lambda_B - rep.lambda_t;
2155 const PetscReal lcC = rep.lambda_C - rep.lambda_t;
2156 const PetscReal lcD = rep.lambda_D - rep.lambda_t;
2157 PetscReal gradmax = 0.0;
2158 PetscCall(ComputeMaxGradientContribution(user, &gradmax));
2159
2160 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2161 " --- convective Jacobian spectrum ---\n"
2162 " rho(J)=%.6e sigma_max(J)=%.6e nonnormality=%.3e max_real_eig=%.3e\n"
2163 " --- candidate convective estimates ---\n"
2164 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n"
2165 " max local |grad u| row-sum contribution = %.6e\n"
2166 " rB/rho=%.3f rC/rho=%.3f rD/rho=%.3f | rB/smax=%.3f rC/smax=%.3f rD/smax=%.3f\n",
2167 (double)rho, (double)smax, (double)eta, (double)maxre,
2168 (double)lcB, (double)lcC, (double)lcD,
2169 (double)gradmax,
2170 (double)(lcB/rho), (double)(lcC/rho), (double)(lcD/rho),
2171 (double)(lcB/smax), (double)(lcC/smax), (double)(lcD/smax)));
2172 if (st == STATE_A) {
2173 PetscCall(CheckDenseJacobianAction(user, Ubase, Rhs, Uwork, &map, Jbest, epsrel[best_e]));
2174 PetscCall(RunStateADirectionalMechanismAudit(Jbest, user, Ubase, Rhs, &map, epsrel[best_e]));
2175 PetscCall(PrintBlockAndSymmetricLocalization(user, &map, Jbest));
2176 PetscCall(PrintFourierChecks(&map, Jbest));
2177 PetscCall(TraceStateAResidualStages(user, Ubase, Rhs, &map, Jbest));
2178 PetscCall(RunStateAResidualPathIsolation(user, Ubase, Rhs, Uwork, &map, epsrel[best_e]));
2179 }
2180
2181 /* ---- RK pseudo-CFL stability per candidate (convective Jacobian) ---- */
2182 const PetscReal lams[3] = {lcB, lcC, lcD}; const char *cn[3] = {"B","C","D"};
2183 PetscReal *Jpseudo;
2184 PetscCall(PetscMalloc1((size_t)map.n*map.n, &Jpseudo));
2185 PetscCall(DenseShiftIdentity(Jbest, map.n, -rep.lambda_t, Jpseudo));
2186 const PetscReal lams_full[3] = {rep.lambda_B, rep.lambda_C, rep.lambda_D};
2187 PetscCall(PrintFrozenAmplificationTable("CONVECTION-ONLY FROZEN JACOBIAN", Jbest, map.n, lams, cn));
2188 PetscCall(PrintFrozenAmplificationTable("COMPLETE PSEUDO-TIME FROZEN OPERATOR", Jpseudo, map.n, lams_full, cn));
2189 PetscCall(PetscFree(Jpseudo));
2190
2191 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " --- RK stable pseudo-CFL (convective J) ---\n"));
2192 for (int c = 0; c < 3; c++) {
2193 if (!(lams[c] > 0.0)) continue;
2194 StableCFLResult cfl_rho, cfl_nrm;
2195 PetscCall(StableCFL(Jbest, map.n, lams[c], METRIC_RHO, &cfl_rho));
2196 PetscCall(StableCFL(Jbest, map.n, lams[c], METRIC_NORM, &cfl_nrm));
2197 PetscCall(PrintStableCFLLine(cn[c], cfl_rho, cfl_nrm));
2198 }
2199
2200 /* ---- exact stage-dependent tangent map and direct nonlinear RK cross-check ---- */
2201 if (lcC > 0.0) PetscCall(RunRKTangentDiagnostics(user, st, Ubase, Rhs, &map,
2202 epsrel[best_e], lams, cn, Jbest));
2203
2204 /* ---- robust automated assertions per state ---- */
2205 PetscCall(PicurvAssertBool(eqbase, "base Ucont restored after Jacobian build"));
2206 PetscCall(PicurvAssertBool((PetscBool)(det_err < 1e-10), "residual evaluation deterministic"));
2207 PetscCall(PicurvAssertBool((PetscBool)(rho > 0.0 && PetscIsNormalReal(rho)), "finite rho(J)"));
2208 PetscCall(PicurvAssertBool((PetscBool)(smax > 0.0 && PetscIsNormalReal(smax)), "finite sigma_max(J)"));
2209 if (st == STATE_A) {
2210 for (int d = 0; d < 3; d++) {
2211 PetscCall(PicurvAssertRealNear(seam.declared[d], 0.0, 1e-12, "A: declared periodic seam"));
2212 PetscCall(PicurvAssertRealNear(seam.ucat_global[d], 0.0, 1e-12, "A: Ucat duplicate seam"));
2213 PetscCall(PicurvAssertRealNear(seam.ucat_ghost[d], 0.0, 1e-12, "A: lUcat ghost seam"));
2214 PetscCall(PicurvAssertRealNear(seam.ucont_global[d], 0.0, 1e-12, "A: Ucont duplicate seam"));
2215 }
2216 PetscCall(PicurvAssertRealNear(repeat_err, 0.0, 1e-9, "A: recovered Ucat repeat near roundoff"));
2217 PetscCall(PicurvAssertRealNear(R0_2, 0.0, 1e-12, "A: base residual 2-norm near roundoff"));
2218 PetscCall(PicurvAssertRealNear(R0_inf, 0.0, 1e-12, "A: base residual inf-norm near roundoff"));
2219 PetscCall(PicurvAssertRealNear(lcB, lcC, 1e-9, "A: B == C (no divergence)"));
2220 PetscCall(PicurvAssertRealNear(lcC, lcD, 1e-9, "A: C == D (no shear)"));
2221 } else if (st == STATE_B) {
2222 for (int d = 0; d < 3; d++) {
2223 PetscCall(PicurvAssertRealNear(seam.declared[d], 0.0, 1e-12, "B: declared periodic seam"));
2224 PetscCall(PicurvAssertRealNear(seam.ucat_global[d], 0.0, 1e-12, "B: Ucat duplicate seam"));
2225 PetscCall(PicurvAssertRealNear(seam.ucat_ghost[d], 0.0, 1e-12, "B: lUcat ghost seam"));
2226 PetscCall(PicurvAssertRealNear(seam.ucont_global[d], 0.0, 1e-12, "B: Ucont duplicate seam"));
2227 }
2228 PetscCall(PicurvAssertRealNear(repeat_err, 0.0, 1e-9, "B: recovered Ucat repeat near roundoff"));
2229 PetscCall(PicurvAssertBool((PetscBool)(maxdiv > 1e-3), "B: nonzero discrete divergence"));
2230 PetscCall(PicurvAssertBool((PetscBool)(R0_2 > 1e-3), "B: materially nonzero base residual 2-norm"));
2231 PetscCall(PicurvAssertBool((PetscBool)(R0_inf > 1e-3), "B: materially nonzero base residual inf-norm"));
2232 PetscCall(PicurvAssertBool((PetscBool)(lcC > lcB + 1e-9), "B: C > B"));
2233 } else {
2234 for (int d = 0; d < 3; d++) {
2235 PetscCall(PicurvAssertRealNear(seam.declared[d], 0.0, 1e-12, "C: declared periodic seam"));
2236 PetscCall(PicurvAssertRealNear(seam.ucat_global[d], 0.0, 1e-12, "C: Ucat duplicate seam"));
2237 PetscCall(PicurvAssertRealNear(seam.ucat_ghost[d], 0.0, 1e-12, "C: lUcat ghost seam"));
2238 PetscCall(PicurvAssertRealNear(seam.ucont_global[d], 0.0, 1e-12, "C: Ucont duplicate seam"));
2239 }
2240 PetscCall(PicurvAssertRealNear(repeat_err, 0.0, 1e-9, "C: recovered Ucat repeat near roundoff"));
2241 PetscCall(PicurvAssertBool((PetscBool)(maxdiv < 1e-6), "C: divergence near zero"));
2242 PetscCall(PicurvAssertRealNear(R0_2, 0.0, 1e-12, "C: base residual 2-norm near roundoff"));
2243 PetscCall(PicurvAssertRealNear(R0_inf, 0.0, 1e-12, "C: base residual inf-norm near roundoff"));
2244 PetscCall(PicurvAssertBool((PetscBool)(PetscAbsReal(lcC-lcB) < 1e-6), "C: C ~= B"));
2245 PetscCall(PicurvAssertBool((PetscBool)(gradmax > 1e-6), "C: canonical shear has nonzero local gradient contribution"));
2246 }
2247
2248 PetscCall(PetscFree3(Rref, Rrep, Jbest));
2249 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs));
2250 PetscCall(VecDestroy(&Uwork)); PetscCall(VecDestroy(&Uout));
2251 PetscCall(DofMapDestroy(&map));
2252 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
2253 PetscFunctionReturn(0);
2254}
@ 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 StableCFL(const PetscReal *J, PetscInt n, PetscReal lam, PMetric which, StableCFLResult *result)
static PetscErrorCode RunStateADirectionalMechanismAudit(const PetscReal *Jxy, UserCtx *user_xy, Vec Ubase_xy, Vec Rhs_xy, const DofMap *map_xy, PetscReal epsrel)
Builds Jx, Jy, Jxy and prints additivity/commutator/eigenpair diagnostics.
static PetscErrorCode PrintBlockAndSymmetricLocalization(UserCtx *user, const DofMap *map, const PetscReal *J)
Prints 3x3 component block norms and localized symmetric rows.
static PetscErrorCode CheckDenseJacobianAction(UserCtx *user, Vec Ubase, Vec Rhs, Vec Uwork, const DofMap *map, const PetscReal *J, PetscReal epsrel)
Verifies that the assembled dense Jacobian has the same action as production FD Jv.
static PetscErrorCode PrintFourierChecks(const DofMap *map, const PetscReal *J)
Projects production J on full staggered six-dimensional Fourier subspaces.
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 PetscErrorCode TraceStateAResidualStages(UserCtx *user, Vec Ubase, Vec Rhs, const DofMap *map, const PetscReal *J)
Trace observable production residual stages for one deterministic perturbation.
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 PrintPeriodicSpaceAudit(UserCtx *user, const DofMap *map)
Prints the component-wise periodic storage count actually used by the active map.
static PetscErrorCode RunStateAResidualPathIsolation(UserCtx *user, Vec Ubase, Vec Rhs, Vec Uwork, const DofMap *map, PetscReal epsrel)
Prints the stage where positive-real spectrum first appears.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
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 2259 of file test_momentum_convective_candidates.c.

2259{ 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 2264 of file test_momentum_convective_candidates.c.

2264{ 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 2269 of file test_momentum_convective_candidates.c.

2269{ 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 2274 of file test_momentum_convective_candidates.c.

2275{
2276 SimCtx *simCtx = NULL; UserCtx *user = NULL; DofMap map;
2277 Vec Ubase, Rhs, Uwork;
2278 PetscReal *Rp, *Rm, *J;
2279 PetscReal repeat_err, maxdiv;
2280 SeamDiagnostics seam;
2281 PetscFunctionBeginUser;
2282 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, N, N, N, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
2283 PetscCall(ConfigureCandidateFixture(simCtx, user));
2284 PetscCall(DofMapBuild(user, &map));
2285 PetscCall(VecDuplicate(user->Ucont, &Ubase));
2286 PetscCall(VecDuplicate(user->Ucont, &Rhs));
2287 PetscCall(VecDuplicate(user->Ucont, &Uwork));
2288 PetscCall(PetscMalloc3(map.n, &Rp, map.n, &Rm, (size_t)map.n*map.n, &J));
2289 PetscCall(BuildBaseState(user, STATE_A, Ubase, &repeat_err, &maxdiv, &seam));
2290 PetscCall(BuildFDJacobian(user, Ubase, 1e-5, Rhs, &map, Rp, Rm, Uwork, J));
2291 PetscReal rho, maxre, smax;
2292 PetscCall(DenseSpectralRadius(J, map.n, &rho, &maxre));
2293 PetscCall(DenseSigmaMax(J, map.n, &smax, NULL));
2294 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2295 " 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",
2296 (int)(N+1), (int)map.n, (int)map.expected_n, (double)maxre, (double)rho, (double)smax,
2297 (double)DenseSkewnessDefect(J, map.n), (double)DenseNonNormality(J, map.n), (double)repeat_err));
2298 if (N >= 5) {
2299 PetscReal *vr, *vi;
2300 PetscReal lamr, lami, v2 = 0.0, seam2 = 0.0, maxabs = 0.0;
2301 PetscCall(PetscMalloc2(map.n, &vr, map.n, &vi));
2302 PetscCall(DenseMaxRealRightEigenpair(J, map.n, &lamr, &lami, vr, vi));
2303 for (PetscInt m = 0; m < map.n; m++) {
2304 const PetscReal a2 = vr[m]*vr[m] + vi[m]*vi[m];
2305 v2 += a2;
2306 if (DofTouchesPeriodicRepresentative(&map, m, user->info)) seam2 += a2;
2307 maxabs = PetscMax(maxabs, PetscSqrtReal(a2));
2308 }
2309 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2310 " larger-grid eigenvector: lambda=%.6e%+.6ei seam_energy=%.3f max_entry/||v||=%.3e\n",
2311 (double)lamr, (double)lami, (double)(seam2/PetscMax(v2, PETSC_MACHINE_EPSILON)),
2312 (double)(maxabs/PetscSqrtReal(PetscMax(v2, PETSC_MACHINE_EPSILON)))));
2313 PetscCall(PrintBlockAndSymmetricLocalization(user, &map, J));
2314 PetscCall(PetscFree2(vr, vi));
2315 }
2316 PetscCall(PetscFree3(Rp, Rm, J));
2317 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
2318 PetscCall(DofMapDestroy(&map));
2319 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
2320 PetscFunctionReturn(0);
2321}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RunStateASplitOne()

static PetscErrorCode RunStateASplitOne ( CandState  st,
const char *  label 
)
static

Runs one State A transport-direction split.

Definition at line 2326 of file test_momentum_convective_candidates.c.

2327{
2328 SimCtx *simCtx = NULL; UserCtx *user = NULL; DofMap map;
2329 Vec Ubase, Rhs, Uwork;
2330 PetscReal *Rp, *Rm, *J;
2331 PetscReal repeat_err, maxdiv;
2332 SeamDiagnostics seam;
2333 PetscFunctionBeginUser;
2334 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, 4, 4, 4, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
2335 PetscCall(ConfigureCandidateFixture(simCtx, user));
2336 PetscCall(DofMapBuild(user, &map));
2337 PetscCall(VecDuplicate(user->Ucont, &Ubase));
2338 PetscCall(VecDuplicate(user->Ucont, &Rhs));
2339 PetscCall(VecDuplicate(user->Ucont, &Uwork));
2340 PetscCall(PetscMalloc3(map.n, &Rp, map.n, &Rm, (size_t)map.n*map.n, &J));
2341 PetscCall(BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
2342 PetscCall(BuildFDJacobian(user, Ubase, 1e-5, Rhs, &map, Rp, Rm, Uwork, J));
2343 PetscReal rho, maxre, smax;
2344 PetscCall(DenseSpectralRadius(J, map.n, &rho, &maxre));
2345 PetscCall(DenseSigmaMax(J, map.n, &smax, NULL));
2346 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2347 " %-4s rho=%.6e sigma=%.6e max_real=%.6e skew=%.3e nonnormality=%.3e div=%.3e repeat=%.3e\n",
2348 label, (double)rho, (double)smax, (double)maxre,
2349 (double)DenseSkewnessDefect(J, map.n), (double)DenseNonNormality(J, map.n),
2350 (double)maxdiv, (double)repeat_err));
2351 PetscCall(PetscFree3(Rp, Rm, J));
2352 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
2353 PetscCall(DofMapDestroy(&map));
2354 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
2355 PetscFunctionReturn(0);
2356}
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 2361 of file test_momentum_convective_candidates.c.

2362{
2363 PetscFunctionBeginUser;
2364 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2365 "\n================ STATE A GRID / ACTIVE-SPACE AUDIT ================\n"
2366 " residual sign convention: ComputeRHS returns the production convection residual used by pseudo-time updates.\n"
2367 " component-staggered periodic duplicate planes: 0<-m-2 and m-1<-1 in each direction.\n"
2368 " independent map: all three Ucont components use representatives i,j,k=1..m-2; count = 3*(m-2)^3.\n"));
2369 PetscCall(RunStateAGridAuditOne(4));
2370 PetscCall(RunStateAGridAuditOne(5));
2371 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2372 " State A transport-direction split on DMDA 5^3:\n"));
2373 PetscCall(RunStateASplitOne(STATE_A_X, "A-x"));
2374 PetscCall(RunStateASplitOne(STATE_A_Y, "A-y"));
2375 PetscCall(RunStateASplitOne(STATE_A, "A-xy"));
2376 PetscFunctionReturn(0);
2377}
static PetscErrorCode RunStateAGridAuditOne(PetscInt N)
Runs one State A grid-size audit case.
static PetscErrorCode RunStateASplitOne(CandState st, const char *label)
Runs one State A transport-direction split.
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 2382 of file test_momentum_convective_candidates.c.

2384{
2385 PetscMPIInt rank;
2386 PetscFunctionBeginUser;
2387 if (!g_ref_path_set) PetscFunctionReturn(0);
2388 PetscCheck(g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
2389 "-candidate_ref_token is required when -candidate_ref_path is set");
2390 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2391 if (rank == 0) {
2392 FILE *fp = fopen(g_ref_path, "w");
2393 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "could not write State A MPI reference");
2394 fprintf(fp, "PICURV_CANDIDATE_STATEA_REF_V2 %s\n", g_ref_token);
2395 fprintf(fp, "%.17e %.17e %.17e\n", (double)r0.n2, (double)r0.ninf, (double)r0.checksum);
2396 fprintf(fp, "%.17e %.17e %.17e\n", (double)jv.n2, (double)jv.ninf, (double)jv.checksum);
2397 fprintf(fp, "%.17e %.17e %.17e\n", (double)phi.n2, (double)phi.ninf, (double)phi.checksum);
2398 fprintf(fp, "%.17e %.17e %.17e %d %d %d %d\n",
2399 (double)(rep->lambda_B - rep->lambda_t),
2400 (double)(rep->lambda_C - rep->lambda_t),
2401 (double)(rep->lambda_D - rep->lambda_t),
2402 (int)rep->active_cells, (int)rep->cblock, (int)rep->ci, (int)rep->cj);
2403 fclose(fp);
2404 }
2405 PetscFunctionReturn(0);
2406}
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 2411 of file test_momentum_convective_candidates.c.

2413{
2414 PetscMPIInt rank;
2415 PetscReal vals[16] = {0.0};
2416 PetscFunctionBeginUser;
2417 PetscCheck(g_ref_path_set && g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
2418 "two-rank State A decomp check requires matching -candidate_ref_path and -candidate_ref_token from a preceding one-rank run");
2419 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2420 if (rank == 0) {
2421 char magic[64], token[128];
2422 FILE *fp = fopen(g_ref_path, "r");
2423 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
2424 "State A one-rank decomp reference missing; run the Makefile target so -n 1 precedes -n 2");
2425 PetscCheck(fscanf(fp, "%63s %127s", magic, token) == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference header");
2426 PetscCheck(strcmp(magic, "PICURV_CANDIDATE_STATEA_REF_V2") == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
2427 "bad reference magic");
2428 PetscCheck(strcmp(token, g_ref_token) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
2429 "State A one-rank decomp reference token mismatch");
2430 int active, cblock, ci, cj;
2431 PetscCheck(fscanf(fp, "%le %le %le", &vals[0], &vals[1], &vals[2]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference R0");
2432 PetscCheck(fscanf(fp, "%le %le %le", &vals[3], &vals[4], &vals[5]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference Jv");
2433 PetscCheck(fscanf(fp, "%le %le %le", &vals[6], &vals[7], &vals[8]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference Phi");
2434 PetscCheck(fscanf(fp, "%le %le %le %d %d %d %d", &vals[9], &vals[10], &vals[11],
2435 &active, &cblock, &ci, &cj) == 7, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "bad reference estimator");
2436 vals[12] = (PetscReal)active; vals[13] = (PetscReal)cblock; vals[14] = (PetscReal)ci; vals[15] = (PetscReal)cj;
2437 fclose(fp);
2438 PetscCheck(remove(g_ref_path) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
2439 "could not remove consumed State A MPI reference '%s'", g_ref_path);
2440 }
2441 PetscCallMPI(MPI_Bcast(vals, 16, MPIU_REAL, 0, PETSC_COMM_WORLD));
2442 PetscCall(PicurvAssertRealNear(r0.n2, vals[0], 1e-10, "MPI State A R0 L2"));
2443 PetscCall(PicurvAssertRealNear(r0.ninf, vals[1], 1e-10, "MPI State A R0 Linf"));
2444 PetscCall(PicurvAssertRealNear(r0.checksum, vals[2], 1e-10, "MPI State A R0 checksum"));
2445 PetscCall(PicurvAssertRealNear(jv.n2, vals[3], 1e-8, "MPI State A Jv L2"));
2446 PetscCall(PicurvAssertRealNear(jv.ninf, vals[4], 1e-8, "MPI State A Jv Linf"));
2447 PetscCall(PicurvAssertRealNear(jv.checksum, vals[5], 1e-8, "MPI State A Jv checksum"));
2448 PetscCall(PicurvAssertRealNear(phi.n2, vals[6], 1e-8, "MPI State A DPhi v L2"));
2449 PetscCall(PicurvAssertRealNear(phi.ninf, vals[7], 1e-8, "MPI State A DPhi v Linf"));
2450 PetscCall(PicurvAssertRealNear(phi.checksum, vals[8], 1e-8, "MPI State A DPhi v checksum"));
2451 PetscCall(PicurvAssertRealNear(rep->lambda_B - rep->lambda_t, vals[9], 1e-10, "MPI State A lambda_cB"));
2452 PetscCall(PicurvAssertRealNear(rep->lambda_C - rep->lambda_t, vals[10], 1e-10, "MPI State A lambda_cC"));
2453 PetscCall(PicurvAssertRealNear(rep->lambda_D - rep->lambda_t, vals[11], 1e-10, "MPI State A lambda_cD"));
2454 PetscCall(PicurvAssertBool((PetscBool)(rep->active_cells == (PetscInt)vals[12]), "MPI State A active cell count"));
2455 PetscCall(PicurvAssertBool((PetscBool)(rep->cblock == (PetscInt)vals[13]), "MPI State A controlling block"));
2456 PetscFunctionReturn(0);
2457}
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 2462 of file test_momentum_convective_candidates.c.

2464{
2465 DofMap map;
2466 Vec V, Up, Um, PhiP, PhiM, Ustage;
2467 PetscReal *v, *R0, *Rp, *Rm, *ActP, *ActM, *Out;
2468 GlobalVecStats sR0, sJv, sPhi;
2469 const PetscReal eps = 1e-6, dtau = 0.5/lcC;
2470 PetscMPIInt size;
2471 PetscFunctionBeginUser;
2472 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
2473 PetscCall(DofMapBuildOwned(user, &map));
2474 PetscCall(VecDuplicate(Ubase, &V)); PetscCall(VecDuplicate(Ubase, &Up));
2475 PetscCall(VecDuplicate(Ubase, &Um)); PetscCall(VecDuplicate(Ubase, &PhiP));
2476 PetscCall(VecDuplicate(Ubase, &PhiM)); PetscCall(VecDuplicate(Ubase, &Ustage));
2477 PetscCall(PetscMalloc6(map.n, &v, map.n, &R0, map.n, &Rp, map.n, &Rm, map.n, &ActP, map.n, &ActM));
2478 PetscCall(PetscMalloc1(map.n, &Out));
2479 PetscCall(FillDeterministicDirection(user, V, &map, v));
2480
2481 PetscCall(EvalConvResidual(user, Ubase, Rhs, &map, R0));
2482 PetscCall(ActiveStats(&map, R0, &sR0));
2483 PetscCall(VecCopy(Ubase, Up)); PetscCall(VecAXPY(Up, eps, V));
2484 PetscCall(VecCopy(Ubase, Um)); PetscCall(VecAXPY(Um, -eps, V));
2485 PetscCall(EvalConvResidual(user, Up, Rhs, &map, Rp));
2486 PetscCall(EvalConvResidual(user, Um, Rhs, &map, Rm));
2487 for (PetscInt m = 0; m < map.n; m++) Out[m] = (Rp[m]-Rm[m])/(2.0*eps);
2488 PetscCall(ActiveStats(&map, Out, &sJv));
2489
2490 PetscCall(FourStage(user, Up, dtau, Rhs, &map, Rp, Ustage, PhiP));
2491 PetscCall(FourStage(user, Um, dtau, Rhs, &map, Rm, Ustage, PhiM));
2492 PetscCall(ExtractActiveVector(user, PhiP, &map, ActP));
2493 PetscCall(ExtractActiveVector(user, PhiM, &map, ActM));
2494 for (PetscInt m = 0; m < map.n; m++) Out[m] = (ActP[m]-ActM[m])/(2.0*eps);
2495 PetscCall(ActiveStats(&map, Out, &sPhi));
2496
2497 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2498 " State A matrix-free MPI check: R0 L2=%.6e Linf=%.6e checksum=%.6e\n"
2499 " Jv L2=%.6e Linf=%.6e checksum=%.6e\n"
2500 " DPhi v L2=%.6e Linf=%.6e checksum=%.6e\n",
2501 (double)sR0.n2, (double)sR0.ninf, (double)sR0.checksum,
2502 (double)sJv.n2, (double)sJv.ninf, (double)sJv.checksum,
2503 (double)sPhi.n2, (double)sPhi.ninf, (double)sPhi.checksum));
2504 if (size == 1) PetscCall(WriteStateADecompReference(sR0, sJv, sPhi, rep));
2505 else PetscCall(ReadAndCompareStateADecompReference(sR0, sJv, sPhi, rep));
2506
2507 PetscCall(PetscFree6(v, R0, Rp, Rm, ActP, ActM)); PetscCall(PetscFree(Out));
2508 PetscCall(VecDestroy(&V)); PetscCall(VecDestroy(&Up)); PetscCall(VecDestroy(&Um));
2509 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Ustage));
2510 PetscCall(DofMapDestroy(&map));
2511 PetscFunctionReturn(0);
2512}
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 2517 of file test_momentum_convective_candidates.c.

2519{
2520 SimCtx *simCtx = NULL; UserCtx *user = NULL;
2521 Vec Ubase, Rhs;
2522 PetscReal repeat_err, maxdiv;
2523 SeamDiagnostics seam;
2525 const PetscInt N = 8;
2526 PetscFunctionBeginUser;
2527
2528 PetscCall(PicurvCreateMinimalContextsWithPeriodicity(&simCtx, &user, N, N, N, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
2529 PetscCall(ConfigureCandidateFixture(simCtx, user));
2530 PetscCall(VecDuplicate(user->Ucont, &Ubase));
2531 PetscCall(VecDuplicate(user->Ucont, &Rhs));
2532 PetscCall(BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
2533 PetscCall(ComputeMomentumStabilityEstimate(user, 1, simCtx->dt, MOM_STAB_CAND_C, &rep));
2534
2535 const PetscReal lcB = rep.lambda_B - rep.lambda_t;
2536 const PetscReal lcC = rep.lambda_C - rep.lambda_t;
2537 const PetscReal lcD = rep.lambda_D - rep.lambda_t;
2538 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2539 "\n================ DECOMP BASELINE %s ================\n"
2540 " active cells: %d | repeat=%.3e | max|div_h Ucont|=%.3e\n"
2541 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n",
2542 name, (int)rep.active_cells, (double)repeat_err, (double)maxdiv,
2543 (double)lcB, (double)lcC, (double)lcD));
2544
2545 PetscCall(PicurvAssertBool((PetscBool)(rep.active_cells == 343), "decomp: active-cell count invariant"));
2546 PetscCall(PicurvAssertRealNear(expB, lcB, 5e-7, "decomp: lambda_cB matches one-rank baseline"));
2547 PetscCall(PicurvAssertRealNear(expC, lcC, 5e-7, "decomp: lambda_cC matches one-rank baseline"));
2548 PetscCall(PicurvAssertRealNear(expD, lcD, 5e-7, "decomp: lambda_cD matches one-rank baseline"));
2549 if (st == STATE_A) {
2550 PetscCall(StateADecompDirectionalCheck(user, Ubase, Rhs, lcC, &rep));
2551 PetscCall(PicurvAssertRealNear(maxdiv, 0.0, 1e-12, "decomp A: divergence-free"));
2552 PetscCall(PicurvAssertRealNear(lcB, lcC, 1e-12, "decomp A: B == C"));
2553 PetscCall(PicurvAssertRealNear(lcC, lcD, 1e-12, "decomp A: C == D"));
2554 } else if (st == STATE_B) {
2555 PetscCall(PicurvAssertBool((PetscBool)(maxdiv > 1e-3), "decomp B: nonzero divergence"));
2556 PetscCall(PicurvAssertBool((PetscBool)(lcC > lcB), "decomp B: C > B"));
2557 } else {
2558 PetscCall(PicurvAssertRealNear(maxdiv, 0.0, 1e-12, "decomp C: divergence-free"));
2559 PetscCall(PicurvAssertRealNear(lcB, lcC, 1e-12, "decomp C: B == C"));
2560 }
2561
2562 PetscCall(VecDestroy(&Ubase));
2563 PetscCall(VecDestroy(&Rhs));
2564 PetscCall(PicurvDestroyMinimalContexts(&simCtx, &user));
2565 PetscFunctionReturn(0);
2566}
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 2571 of file test_momentum_convective_candidates.c.

2571{ 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 2576 of file test_momentum_convective_candidates.c.

2576{ 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 2581 of file test_momentum_convective_candidates.c.

2581{ 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 2586 of file test_momentum_convective_candidates.c.

2587{
2588 PetscFunctionBeginUser;
2589 PetscCall(PetscOptionsGetString(NULL, NULL, "-candidate_ref_path",
2591 PetscCall(PetscOptionsGetString(NULL, NULL, "-candidate_ref_token",
2594 PetscCheck(g_ref_path_set && g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
2595 "-candidate_ref_path and -candidate_ref_token must be supplied together");
2596 }
2597 PetscFunctionReturn(0);
2598}
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 2603 of file test_momentum_convective_candidates.c.

2604{
2605 PetscErrorCode ierr;
2606 PetscMPIInt size;
2607 const PicurvTestCase cases[] = {
2608 {"candidate-state-A-uniform", TestStateA},
2609 {"candidate-state-B-divergence", TestStateB},
2610 {"candidate-state-C-shear", TestStateC},
2611 {"candidate-state-A-grid-audit", TestStateAGridAudit},
2612 };
2613 const PicurvTestCase decomp_cases[] = {
2614 {"candidate-decomp-A-uniform", TestDecompA},
2615 {"candidate-decomp-B-divergence", TestDecompB},
2616 {"candidate-decomp-C-shear", TestDecompC},
2617 };
2618 ierr = PetscInitialize(&argc, &argv, NULL, "PICurv A4a convective-candidate study");
2619 if (ierr) return (int)ierr;
2620 ierr = ConfigureMPIReferenceOptions(); if (ierr) { PetscFinalize(); return (int)ierr; }
2621 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); if (ierr) { PetscFinalize(); return (int)ierr; }
2622 if (size == 1) {
2623 ierr = PicurvRunTests("unit-momentum-candidates", cases, sizeof(cases)/sizeof(cases[0]));
2624 if (!ierr) ierr = PicurvRunTests("unit-momentum-candidates-decomp", decomp_cases, sizeof(decomp_cases)/sizeof(decomp_cases[0]));
2625 } else {
2626 ierr = PicurvRunTests("unit-momentum-candidates-decomp", decomp_cases, sizeof(decomp_cases)/sizeof(decomp_cases[0]));
2627 }
2628 if (ierr) { PetscFinalize(); return (int)ierr; }
2629 return (int)PetscFinalize();
2630}
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.