PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
momentum_newton_krylov.c File Reference
#include "momentumsolvers.h"
Include dependency graph for momentum_newton_krylov.c:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MomentumNewtonJacobian
 
struct  MomentumPreconditionerDescription
 
struct  MomentumPreconditionerModelOps
 
struct  MomentumPreconditionerEngine
 
struct  MomentumNewtonKrylovContext
 

Macros

#define __FUNCT__   "MomentumNewtonKrylov_Validate"
 
#define __FUNCT__   "MomentumNewtonKrylov_ReadLinearizationConfig"
 
#define __FUNCT__   "FrozenMomentumJacobian_DescribePointBlock"
 
#define __FUNCT__   "FrozenMomentumJacobian_AssemblePointBlocks"
 
#define __FUNCT__   "MomentumPreconditionerEngine_ApplyConstraintRows"
 
#define __FUNCT__   "MomentumNewtonJacobian_Create"
 
#define __FUNCT__   "MomentumPreconditionerEngine_Create"
 
#define __FUNCT__   "MomentumPreconditionerEngine_Assemble"
 
#define __FUNCT__   "MomentumNewtonKrylov_FormJacobian"
 
#define __FUNCT__   "MomentumPreconditionerEngine_CreateExactPointBlockMatrix"
 
#define __FUNCT__   "MomentumNewtonKrylov_ApplyConstraints"
 
#define __FUNCT__   "MomentumNewtonKrylov_FormResidual"
 
#define __FUNCT__   "MomentumSolver_NewtonKrylov"
 

Enumerations

enum  MomentumNewtonJacobianType { MOM_NK_JACOBIAN_FINITE_DIFFERENCE }
 
enum  MomentumNewtonFiniteDifferenceMode { MOM_NK_FD_MODE_MATRIX_FREE }
 
enum  MomentumPreconditionerModel { MOM_NK_PC_MODEL_NONE , MOM_NK_PC_MODEL_FROZEN_MOMENTUM_JACOBIAN }
 
enum  MomentumPreconditionerStructure { MOM_NK_PC_STRUCTURE_NONE , MOM_NK_PC_STRUCTURE_POINT_BLOCK }
 

Functions

static PetscErrorCode MomentumNewtonKrylov_Validate (UserCtx *user)
 Rejects configurations outside the audited version-one feature set.
 
static PetscErrorCode MomentumNewtonKrylov_FormResidual (SNES snes, Vec X, Vec F, void *vctx)
 Adapts a PETSc trial vector to the existing momentum residual path.
 
static PetscErrorCode MomentumNewtonKrylov_Monitor (SNES snes, PetscInt iteration, PetscReal norm, void *vctx)
 Captures SNES iteration norms and optionally writes PICurv history rows.
 
static PetscErrorCode MomentumNewtonKrylov_LinearMonitor (KSP ksp, PetscInt iteration, PetscReal norm, void *vctx)
 Writes the effective KSP tolerance and PETSc-reported norm for each inner iteration.
 
static void MomentumNewtonKrylov_OpenHistory (MomentumNewtonKrylovContext *ctx)
 Opens the optional rank-zero Newton iteration-history file.
 
static void MomentumNewtonKrylov_WriteSummary (const MomentumNewtonKrylovContext *ctx, SNESConvergedReason reason, PetscInt nonlinear_its, PetscInt function_evals, PetscInt linear_its, PetscReal final_norm, PetscBool committed)
 Appends one rank-zero structured Newton result for a physical step.
 
static PetscErrorCode MomentumNewtonKrylov_ApplyConstraints (MomentumNewtonKrylovContext *ctx, Vec X, Vec F)
 Replaces every non-independent residual row with an explicit equation.
 
static PetscErrorCode MomentumNewtonKrylov_ReadLinearizationConfig (MomentumNewtonJacobian *jacobian, MomentumPreconditionerDescription *description)
 Reads application-owned Jacobian and preconditioner mathematics.
 
static PetscErrorCode MomentumNewtonKrylov_FormJacobian (SNES snes, Vec current_solution, Mat jacobian_operator, Mat preconditioning_matrix, void *vctx)
 Updates the Jacobian and then assembles any separate preconditioning matrix.
 
static PetscErrorCode FrozenMomentumJacobian_AssemblePointBlocks (UserCtx *user, Vec current_solution, Mat preconditioning_matrix)
 Inserts only the audited interior frozen-momentum point blocks.
 
static PetscErrorCode MomentumPreconditionerEngine_CreateExactPointBlockMatrix (UserCtx *user, Mat *preconditioning_matrix)
 Creates the frozen point-block P matrix with its exact scalar pattern.
 
static MomentumRowType MomentumNewtonKrylov_ClassifyRow (UserCtx *user, const PetscReal ***nvert, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
 Row classification with solid-cell masking folded in.
 
static PetscReal FrozenMomentumJacobian_MetricNormSquared (Cmpnts metric)
 Returns the squared Euclidean norm of one metric vector.
 
static PetscReal FrozenMomentumJacobian_FaceEddyViscosity (const UserCtx *user, const PetscReal ***nu_t, PetscInt axis, PetscInt i, PetscInt j, PetscInt k)
 Returns the face-averaged eddy viscosity the residual uses on one face.
 
static void FrozenMomentumJacobian_PointBlock (const UserCtx *user, const Cmpnts ***ucont, const Cmpnts ***csi, const Cmpnts ***eta, const Cmpnts ***zet, const PetscReal ***aj, const PetscReal ***nu_t, PetscInt i, PetscInt j, PetscInt k, PetscScalar block[9])
 Returns the frozen-momentum point block for the current residual convention.
 
static PetscErrorCode FrozenMomentumJacobian_DescribePointBlock (UserCtx *user, MomentumPreconditionerDescription *description)
 Describes the audited frozen-coefficient point-block model.
 
static PetscErrorCode MomentumPreconditionerEngine_ApplyConstraintRows (UserCtx *user, Mat preconditioning_matrix)
 Inserts all common fixed, homogeneous, and periodic-duplicate rows.
 
static PetscErrorCode MomentumNewtonJacobian_Create (SNES snes, MomentumNewtonJacobian *jacobian)
 Creates the selected Jacobian operator; currently PETSc MFFD only.
 
static PetscErrorCode MomentumNewtonJacobian_Update (SNES snes, Vec current_solution, MomentumNewtonJacobian *jacobian)
 Updates the matrix-free finite-difference operator base.
 
static PetscErrorCode MomentumNewtonJacobian_Register (SNES snes, MomentumNewtonJacobian *jacobian, MomentumPreconditionerEngine *engine, MomentumNewtonKrylovContext *ctx)
 Registers the application orchestration callback and both SNES matrices.
 
static PetscErrorCode MomentumNewtonJacobian_Destroy (MomentumNewtonJacobian *jacobian)
 Destroys a partially or fully created Jacobian operator.
 
static PetscErrorCode MomentumPreconditionerEngine_Create (UserCtx *user, Mat jacobian_operator, const MomentumPreconditionerDescription *requested, MomentumPreconditionerEngine *engine)
 Validates a model/structure and creates or aliases its matrix.
 
static PetscErrorCode MomentumPreconditionerEngine_Assemble (MomentumPreconditionerEngine *engine, UserCtx *user, Vec current_solution)
 Runs model insertion, common row handling, and final assembly.
 
static PetscErrorCode MomentumPreconditionerEngine_ConfigurePetscPC (MomentumPreconditionerEngine *engine, PC pc)
 Applies the validated model/structure-to-PETSc-PC mapping.
 
static PetscErrorCode MomentumPreconditionerEngine_ValidatePetscPC (MomentumPreconditionerEngine *engine, PC pc)
 Rejects raw options that select an unvalidated PETSc PC backend.
 
static PetscErrorCode MomentumPreconditionerEngine_Destroy (MomentumPreconditionerEngine *engine)
 Destroys only a separately owned preconditioning matrix.
 
PetscErrorCode MomentumSolver_NewtonKrylov (UserCtx *user, IBMNodes *ibm, FSInfo *fsi)
 Solves one physical momentum step with matrix-free Newton–Krylov.
 

Variables

static const MomentumPreconditionerModelOps frozen_momentum_point_block_ops
 

Data Structure Documentation

◆ MomentumNewtonJacobian

struct MomentumNewtonJacobian

Definition at line 11 of file momentum_newton_krylov.c.

Data Fields
MomentumNewtonJacobianType type
MomentumNewtonFiniteDifferenceMode finite_difference_mode
Mat jacobian_operator

◆ MomentumPreconditionerDescription

struct MomentumPreconditionerDescription

Definition at line 27 of file momentum_newton_krylov.c.

Data Fields
MomentumPreconditionerModel model
MomentumPreconditionerStructure structure
PetscInt block_size
PetscInt stencil_width

◆ MomentumPreconditionerEngine

struct MomentumPreconditionerEngine

Definition at line 39 of file momentum_newton_krylov.c.

Collaboration diagram for MomentumPreconditionerEngine:
[legend]
Data Fields
MomentumPreconditionerDescription description
const MomentumPreconditionerModelOps * model_ops
Mat preconditioning_matrix
PetscBool aliases_jacobian_operator
PetscBool owns_preconditioning_matrix
const char * petsc_pc_type

◆ MomentumNewtonKrylovContext

struct MomentumNewtonKrylovContext

Definition at line 48 of file momentum_newton_krylov.c.

Collaboration diagram for MomentumNewtonKrylovContext:
[legend]
Data Fields
UserCtx * user
SNES snes
FILE * history_file
FILE * linear_history_file
PetscBool have_initial_norm
PetscReal initial_norm
MomentumNewtonJacobian jacobian
MomentumPreconditionerEngine preconditioning_engine

Macro Definition Documentation

◆ __FUNCT__ [1/13]

#define __FUNCT__   "MomentumNewtonKrylov_Validate"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [2/13]

#define __FUNCT__   "MomentumNewtonKrylov_ReadLinearizationConfig"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [3/13]

#define __FUNCT__   "FrozenMomentumJacobian_DescribePointBlock"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [4/13]

#define __FUNCT__   "FrozenMomentumJacobian_AssemblePointBlocks"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [5/13]

#define __FUNCT__   "MomentumPreconditionerEngine_ApplyConstraintRows"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [6/13]

#define __FUNCT__   "MomentumNewtonJacobian_Create"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [7/13]

#define __FUNCT__   "MomentumPreconditionerEngine_Create"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [8/13]

#define __FUNCT__   "MomentumPreconditionerEngine_Assemble"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [9/13]

#define __FUNCT__   "MomentumNewtonKrylov_FormJacobian"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [10/13]

#define __FUNCT__   "MomentumPreconditionerEngine_CreateExactPointBlockMatrix"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [11/13]

#define __FUNCT__   "MomentumNewtonKrylov_ApplyConstraints"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [12/13]

#define __FUNCT__   "MomentumNewtonKrylov_FormResidual"

Definition at line 240 of file momentum_newton_krylov.c.

◆ __FUNCT__ [13/13]

#define __FUNCT__   "MomentumSolver_NewtonKrylov"

Definition at line 240 of file momentum_newton_krylov.c.

Enumeration Type Documentation

◆ MomentumNewtonJacobianType

Enumerator
MOM_NK_JACOBIAN_FINITE_DIFFERENCE 

Definition at line 3 of file momentum_newton_krylov.c.

◆ MomentumNewtonFiniteDifferenceMode

Enumerator
MOM_NK_FD_MODE_MATRIX_FREE 

Definition at line 7 of file momentum_newton_krylov.c.

◆ MomentumPreconditionerModel

Enumerator
MOM_NK_PC_MODEL_NONE 
MOM_NK_PC_MODEL_FROZEN_MOMENTUM_JACOBIAN 

Definition at line 17 of file momentum_newton_krylov.c.

◆ MomentumPreconditionerStructure

Enumerator
MOM_NK_PC_STRUCTURE_NONE 
MOM_NK_PC_STRUCTURE_POINT_BLOCK 

Definition at line 22 of file momentum_newton_krylov.c.

Function Documentation

◆ MomentumNewtonKrylov_Validate()

static PetscErrorCode MomentumNewtonKrylov_Validate ( UserCtx *  user)
static

Rejects configurations outside the audited version-one feature set.

Parameters
userSingle-block momentum context to validate.
Returns
PetscErrorCode 0 when the configuration is supported.

Definition at line 246 of file momentum_newton_krylov.c.

247{
248 SimCtx *simCtx;
249 PetscReal mask_max = 0.0;
250 PetscInt velocity_dof = 0;
251
252 PetscFunctionBeginUser;
253 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
254 "Newton Krylov requires a non-NULL UserCtx.");
255 simCtx = user->simCtx;
256 PetscCheck(simCtx != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
257 "Newton Krylov requires UserCtx::simCtx.");
258 PetscCall(DMDAGetInfo(user->fda, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
259 &velocity_dof, NULL, NULL, NULL, NULL, NULL));
260 PetscCheck(velocity_dof == 3, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
261 "Newton Krylov requires a three-component velocity DMDA (got dof=%d).",
262 velocity_dof);
263 PetscCheck(simCtx->block_number == 1, PETSC_COMM_WORLD, PETSC_ERR_SUP,
264 "Newton Krylov version one supports exactly one block (got %d).",
265 simCtx->block_number);
266 PetscCheck(!simCtx->immersed, PETSC_COMM_WORLD, PETSC_ERR_SUP,
267 "Newton Krylov version one does not support immersed boundaries.");
268 PetscCheck(!simCtx->movefsi && !simCtx->rotatefsi, PETSC_COMM_WORLD, PETSC_ERR_SUP,
269 "Newton Krylov version one does not support moving or rotating bodies/FSI.");
270 PetscCheck(!simCtx->moveframe && !simCtx->rotateframe, PETSC_COMM_WORLD, PETSC_ERR_SUP,
271 "Newton Krylov version one does not support moving or rotating reference frames.");
272 PetscCheck(!simCtx->TwoD, PETSC_COMM_WORLD, PETSC_ERR_SUP,
273 "Newton Krylov version one does not support TwoD component masking.");
274 for (PetscInt face = 0; face < 6; ++face) {
275 const BoundaryFaceConfig *cfg = &user->boundary_faces[face];
276 PetscBool supported = PETSC_FALSE;
277
278 switch (cfg->handler_type) {
280 supported = (PetscBool)(cfg->mathematical_type == WALL);
281 break;
285 supported = (PetscBool)(cfg->mathematical_type == INLET);
286 break;
288 supported = (PetscBool)(cfg->mathematical_type == OUTLET);
289 break;
291 /* Both driven handlers freeze their correction once per timestep in
292 * PreStep, which the Newton solve never re-enters, so the momentum
293 * source stays constant across every residual evaluation. The paired
294 * face checks below still apply. */
297 supported = (PetscBool)(cfg->mathematical_type == PERIODIC);
298 break;
299 default:
300 supported = PETSC_FALSE;
301 break;
302 }
303 PetscCheck(supported, PETSC_COMM_WORLD, PETSC_ERR_SUP,
304 "Newton Krylov version one does not support boundary face %d with mathematical type %d and handler %d.",
305 face, (PetscInt)cfg->mathematical_type, (PetscInt)cfg->handler_type);
306 }
307
310 PETSC_COMM_WORLD, PETSC_ERR_SUP, "Newton Krylov requires paired x-periodic faces.");
313 PETSC_COMM_WORLD, PETSC_ERR_SUP, "Newton Krylov requires paired y-periodic faces.");
316 PETSC_COMM_WORLD, PETSC_ERR_SUP, "Newton Krylov requires paired z-periodic faces.");
317
318 PetscCheck(user->Nvert != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
319 "Newton Krylov requires the cell-mask vector Nvert.");
320 /* Solid cells no longer disqualify the solver: MomentumRowIsSolidMasked() gives
321 their rows the same constrained treatment as any other row carrying no unknown.
322 The immersed-boundary method itself remains unsupported above, because its
323 velocity reconstruction does not run inside this solver's residual. */
324 PetscCall(VecMax(user->Nvert, NULL, &mask_max));
325 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Newton Krylov solid-cell mask maximum Nvert=%g.\n",
326 (double)mask_max);
327 PetscFunctionReturn(PETSC_SUCCESS);
328}
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
PetscInt movefsi
Definition variables.h:895
@ INLET
Definition variables.h:320
@ OUTLET
Definition variables.h:319
@ PERIODIC
Definition variables.h:322
@ WALL
Definition variables.h:316
PetscInt moveframe
Definition variables.h:896
PetscInt TwoD
Definition variables.h:896
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:1093
PetscInt block_number
Definition variables.h:957
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:1071
@ BC_HANDLER_PERIODIC_GEOMETRIC
Definition variables.h:346
@ BC_HANDLER_INLET_PARABOLIC
Definition variables.h:339
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
Definition variables.h:338
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:349
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:348
@ BC_HANDLER_INLET_PROFILE_FROM_FILE
Definition variables.h:340
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:335
@ BC_HANDLER_OUTLET_CONSERVATION
Definition variables.h:344
BCHandlerType handler_type
Definition variables.h:399
PetscInt rotatefsi
Refused at setup: immersed boundaries and moving bodies are not implemented.
Definition variables.h:895
Vec Nvert
Definition variables.h:1108
BCType mathematical_type
Definition variables.h:398
PetscInt rotateframe
moveframe/rotateframe are refused at setup.
Definition variables.h:896
PetscInt immersed
Definition variables.h:895
@ BC_FACE_NEG_X
Definition variables.h:292
@ BC_FACE_POS_Z
Definition variables.h:294
@ BC_FACE_POS_Y
Definition variables.h:293
@ BC_FACE_NEG_Z
Definition variables.h:294
@ BC_FACE_POS_X
Definition variables.h:292
@ BC_FACE_NEG_Y
Definition variables.h:293
Holds the complete configuration for one of the six boundary faces.
Definition variables.h:396
The master context for the entire simulation.
Definition variables.h:863
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_FormResidual()

static PetscErrorCode MomentumNewtonKrylov_FormResidual ( SNES  snes,
Vec  X,
Vec  F,
void *  vctx 
)
static

Adapts a PETSc trial vector to the existing momentum residual path.

A matrix-free SNES residual must be a deterministic function of the trial vector X alone: F(X) may not depend on any state left by a previous residual or MFFD evaluation, or finite-difference Jacobian actions become inconsistent. To honor that contract this callback fully derives the Cartesian velocity state (Ucat/lUcat) from X before the first boundary sweep – see the inline comment below for why ApplyBoundaryConditions()'s own internal reconstruction is not sufficient for the first outlet pass.

State invariants:

  • On entry, X is the only input that determines the result; user->Ucont, user->Ucat and their local ghosts are treated as scratch and are fully overwritten from X.
  • Supported handlers may overwrite flux totals and other diagnostics on every call, but those values must not affect a later call at the same X; the deterministic seed guarantees this.
  • No histories, pressure, viscosity, or controller state advance here.

Side effects: overwrites user->Ucont/lUcont, user->Ucat/lUcat, user->Rhs, the boundary Ubcs targets, and boundary flux/area diagnostics; writes F.

Parameters
snesCalling nonlinear solver.
XTrial solution (read-only).
FResidual output.
vctxPointer to MomentumNewtonKrylovContext.
Returns
PetscErrorCode 0 on success.

Definition at line 1130 of file momentum_newton_krylov.c.

1131{
1133 UserCtx *user = ctx->user;
1134 const FieldId staggered_fields[] = {FIELD_ID_UCONT};
1135 const FieldId cell_fields[] = {FIELD_ID_UCAT};
1136
1137 PetscFunctionBeginUser;
1138 (void)snes;
1139 PetscCall(VecCopy(X, user->Ucont));
1140 PetscCall(SynchronizePeriodicStaggeredFields(user, 1, staggered_fields));
1141
1142 /* Deterministic pre-boundary Cartesian seed. Establish the full Ucat/lUcat
1143 * state from the current X before any boundary handler runs:
1144 *
1145 * X -> Ucont/lUcont -> Ucat -> periodic Ucat -> lUcat -> boundaries
1146 *
1147 * Why this is required, and why it is NOT redundant with the reconstruction
1148 * already performed inside ApplyBoundaryConditions():
1149 *
1150 * 1. A matrix-free SNES residual must be a deterministic function of X. If
1151 * the Cartesian state is left over from a previous residual/MFFD call,
1152 * F(X) becomes history dependent and the finite-difference Jacobian
1153 * action Jv = (F(X+hv)-F(X))/h is invalidated.
1154 * 2. The conservation-outlet handler reads lUcat during the FIRST boundary
1155 * sweep (it measures the uncorrected outflow and builds the outlet
1156 * profile from the Cartesian field). Without this seed it would read the
1157 * stale lUcat from the preceding evaluation.
1158 * 3. ApplyBoundaryConditions() does reconstruct Ucat/lUcat, but only AFTER
1159 * each handler sweep (Contra2Cart runs after BoundarySystem_ExecuteStep
1160 * within every pass). Those internal updates therefore prepare passes 2
1161 * and 3 -- they cannot prepare the very first outlet read of pass 1.
1162 * 4. Contra2Cart() rebuilds the global Ucat interior from the current
1163 * lUcont, but it does not by itself refresh lUcat (nor lUcont; that was
1164 * done by the SynchronizePeriodicStaggeredFields call above).
1165 * 5. SynchronizePeriodicCellFields(FIELD_ID_UCAT) must run before the ghost
1166 * scatter so periodic duplicate planes are finalized consistently (it is
1167 * a no-op when no direction is periodic, as on the straight duct).
1168 * 6. UpdateLocalGhosts(FIELD_ID_UCAT) is required because the outlet handler reads
1169 * lUcat -- the local ghosted vector -- not merely the global Ucat.
1170 *
1171 * Do NOT "simplify" this to a bare Contra2Cart(user), and do NOT delete it
1172 * as apparently redundant with ApplyBoundaryConditions(): the three internal
1173 * boundary passes remain necessary (they refresh the Cartesian state after
1174 * each boundary correction), but only this sequence makes pass 1's input a
1175 * deterministic function of X. */
1176 PetscCall(Contra2Cart(user));
1177 PetscCall(SynchronizePeriodicCellFields(user, 1, cell_fields));
1178 PetscCall(UpdateLocalGhosts(user, FIELD_ID_UCAT));
1179
1180 PetscCall(ApplyBoundaryConditions(user));
1181 PetscCall(ComputeTotalResidual(user));
1182 PetscCall(VecCopy(user->Rhs, F));
1183 PetscCall(VecScale(F, -1.0));
1184 PetscCall(MomentumNewtonKrylov_ApplyConstraints(ctx, X, F));
1185 PetscFunctionReturn(PETSC_SUCCESS);
1186}
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode ApplyBoundaryConditions(UserCtx *user)
Main boundary-condition orchestrator executed during solver timestepping.
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_UCAT
@ FIELD_ID_UCONT
static PetscErrorCode MomentumNewtonKrylov_ApplyConstraints(MomentumNewtonKrylovContext *ctx, Vec X, Vec F)
Replaces every non-independent residual row with an explicit equation.
PetscErrorCode ComputeTotalResidual(UserCtx *user)
Computes the shared spatial-plus-BDF momentum residual in user->Rhs.
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
Definition setup.c:3305
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:2494
Vec Ucont
Definition variables.h:1108
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1068
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_Monitor()

static PetscErrorCode MomentumNewtonKrylov_Monitor ( SNES  snes,
PetscInt  iteration,
PetscReal  norm,
void *  vctx 
)
static

Captures SNES iteration norms and optionally writes PICurv history rows.

SNES supplies the already-computed norm, so this monitor never causes an additional nonlinear residual evaluation. PETSc monitors selected through -mom_nk_snes_monitor remain independent and may run alongside this callback.

Definition at line 92 of file momentum_newton_krylov.c.

94{
96 SimCtx *simCtx = ctx->user->simCtx;
97
98 (void)snes;
99 PetscFunctionBeginUser;
100 if (iteration == 0 && !ctx->have_initial_norm) {
101 ctx->initial_norm = norm;
102 ctx->have_initial_norm = PETSC_TRUE;
103 }
104 if (ctx->history_file) {
105 (void)fprintf(ctx->history_file,
106 "step: %d | block: %d | newton: %d | nonlinear_norm: %.16e\n",
107 (int)simCtx->step, (int)ctx->user->_this, (int)iteration,
108 (double)norm);
109 (void)fflush(ctx->history_file);
110 }
111 PetscFunctionReturn(PETSC_SUCCESS);
112}
PetscInt _this
Definition variables.h:1086
PetscInt step
Definition variables.h:871
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_LinearMonitor()

static PetscErrorCode MomentumNewtonKrylov_LinearMonitor ( KSP  ksp,
PetscInt  iteration,
PetscReal  norm,
void *  vctx 
)
static

Writes the effective KSP tolerance and PETSc-reported norm for each inner iteration.

The tolerance is queried after SNES has applied any inexact-Newton forcing update, so the log distinguishes changing Eisenstat–Walker requests from changing linear convergence behavior.

Definition at line 120 of file momentum_newton_krylov.c.

122{
124 PetscInt newton_iteration = -1;
125 PetscReal relative_tolerance = 0.0;
126
127 PetscFunctionBeginUser;
128 if (!ctx->linear_history_file) PetscFunctionReturn(PETSC_SUCCESS);
129 PetscCall(SNESGetIterationNumber(ctx->snes, &newton_iteration));
130 PetscCall(KSPGetTolerances(ksp, &relative_tolerance, NULL, NULL, NULL));
131 (void)fprintf(ctx->linear_history_file,
132 "step: %d | block: %d | newton: %d | krylov: %d | "
133 "requested_rtol: %.16e | reported_residual_norm: %.16e\n",
134 (int)ctx->user->simCtx->step, (int)ctx->user->_this,
135 (int)newton_iteration, (int)iteration,
136 (double)relative_tolerance, (double)norm);
137 (void)fflush(ctx->linear_history_file);
138 PetscFunctionReturn(PETSC_SUCCESS);
139}
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_OpenHistory()

static void MomentumNewtonKrylov_OpenHistory ( MomentumNewtonKrylovContext *  ctx)
static

Opens the optional rank-zero Newton iteration-history file.

Definition at line 142 of file momentum_newton_krylov.c.

143{
144 SimCtx *simCtx = ctx->user->simCtx;
145 char path[PETSC_MAX_PATH_LEN + 128];
146 const char *mode;
147
148 if (!simCtx->mom_nk_monitor_history || simCtx->rank != 0) return;
149 if (PetscSNPrintf(path, sizeof(path),
150 "%s/Momentum_Solver_Newton_Krylov_History_Block_%d.log",
151 simCtx->log_dir, (int)ctx->user->_this)) return;
152 mode = (simCtx->step == simCtx->StartStep + 1 && !simCtx->continueMode) ? "w" : "a";
153 ctx->history_file = fopen(path, mode);
154 if (!ctx->history_file) {
155 LOG(GLOBAL, LOG_WARNING, "Could not open Newton iteration-history log '%s'.\n", path);
156 return;
157 }
158 if (mode[0] == 'w') {
159 (void)fprintf(ctx->history_file,
160 "# step | block | Newton iteration | nonlinear residual norm\n");
161 } else if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
162 (void)fprintf(ctx->history_file, "# Continuation from step %d\n", (int)simCtx->StartStep);
163 }
164 if (PetscSNPrintf(path, sizeof(path),
165 "%s/Momentum_Solver_Newton_Krylov_Linear_History_Block_%d.log",
166 simCtx->log_dir, (int)ctx->user->_this)) return;
167 ctx->linear_history_file = fopen(path, mode);
168 if (!ctx->linear_history_file) {
169 LOG(GLOBAL, LOG_WARNING, "Could not open Newton Krylov linear-history log '%s'.\n", path);
170 return;
171 }
172 if (mode[0] == 'w') {
173 (void)fprintf(ctx->linear_history_file,
174 "# step | block | Newton iteration | Krylov iteration | "
175 "requested relative tolerance | PETSc-reported residual norm\n");
176 } else if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
177 (void)fprintf(ctx->linear_history_file, "# Continuation from step %d\n",
178 (int)simCtx->StartStep);
179 }
180}
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:84
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
PetscBool mom_nk_monitor_history
Definition variables.h:918
PetscBool continueMode
Definition variables.h:880
PetscMPIInt rank
Definition variables.h:866
PetscInt StartStep
Definition variables.h:873
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:886
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_WriteSummary()

static void MomentumNewtonKrylov_WriteSummary ( const MomentumNewtonKrylovContext *  ctx,
SNESConvergedReason  reason,
PetscInt  nonlinear_its,
PetscInt  function_evals,
PetscInt  linear_its,
PetscReal  final_norm,
PetscBool  committed 
)
static

Appends one rank-zero structured Newton result for a physical step.

File failures are deliberately diagnostic-only: rollback and PETSc cleanup must retain their original error behavior.

Definition at line 187 of file momentum_newton_krylov.c.

194{
195 SimCtx *simCtx = ctx->user->simCtx;
196 char path[PETSC_MAX_PATH_LEN + 128];
197 const char *mode;
198 const char *reason_name;
199 FILE *file;
200
201 if (simCtx->rank != 0) return;
202 if (PetscSNPrintf(path, sizeof(path),
203 "%s/Momentum_Solver_Newton_Krylov_Summary_Block_%d.log",
204 simCtx->log_dir, (int)ctx->user->_this)) return;
205 mode = (simCtx->step == simCtx->StartStep + 1 && !simCtx->continueMode) ? "w" : "a";
206 file = fopen(path, mode);
207 if (!file) {
208 LOG(GLOBAL, LOG_WARNING, "Could not open Newton summary log '%s'.\n", path);
209 return;
210 }
211 if (mode[0] == 'w') {
212 (void)fprintf(file,
213 "# step | block | solver | Jacobian | preconditioner | SNES reason | "
214 "reason code | Newton iterations | "
215 "residual evaluations | Krylov iterations | initial nonlinear norm | "
216 "final nonlinear norm | state\n");
217 } else if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
218 (void)fprintf(file, "# Continuation from step %d\n", (int)simCtx->StartStep);
219 }
220 reason_name = reason == SNES_CONVERGED_ITERATING
221 ? "SNES_CONVERGED_ITERATING" : SNESConvergedReasons[reason];
222 (void)fprintf(file,
223 "step: %d | block: %d | solver: Newton Krylov | "
224 "Jacobian: finite_difference / matrix_free | Preconditioner: %s | "
225 "reason: %s | reason_code: %d | "
226 "newton: %d | evals: %d | krylov: %d | initial: ",
227 (int)simCtx->step, (int)ctx->user->_this,
229 "none" : "frozen_momentum_jacobian / point_block",
230 reason_name, (int)reason,
231 (int)nonlinear_its, (int)function_evals, (int)linear_its);
232 if (ctx->have_initial_norm) (void)fprintf(file, "%.16e", (double)ctx->initial_norm);
233 else (void)fprintf(file, "unavailable");
234 (void)fprintf(file, " | final: %.16e | state: %s\n", (double)final_norm,
235 committed ? "committed" : "rolled_back");
236 (void)fclose(file);
237}
MomentumPreconditionerDescription description
MomentumPreconditionerEngine preconditioning_engine
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_ApplyConstraints()

static PetscErrorCode MomentumNewtonKrylov_ApplyConstraints ( MomentumNewtonKrylovContext *  ctx,
Vec  X,
Vec  F 
)
static

Replaces every non-independent residual row with an explicit equation.

Which rows are non-independent is decided by ClassifyMomentumRow(), shared with the residual path; only the action taken differs. Conditioned face-normal rows use F=X-Uconditioned, unconditioned legacy dummy/tangential rows use F=X, and periodic duplicates use Fdup=Xdup-Xrep. These equations prevent the zero Jacobian rows that EnforceRHSBoundaryConditions()'s zeroing would produce in a matrix-free Newton operator. Immersed, masked, TwoD, and interface rows are rejected before this callback is installed.

Parameters
ctxActive solve context.
XUnconditioned PETSc trial state.
FResidual vector to update in place.
Returns
PetscErrorCode 0 on success.

Definition at line 1050 of file momentum_newton_krylov.c.

1052{
1053 UserCtx *user = ctx->user;
1054 DMDALocalInfo info = user->info;
1055 Vec local_x = NULL;
1056 Cmpnts ***x = NULL, ***conditioned = NULL, ***f = NULL, ***lx = NULL;
1057 const PetscInt xs = info.xs, xe = info.xs + info.xm;
1058 const PetscInt ys = info.ys, ye = info.ys + info.ym;
1059 const PetscInt zs = info.zs, ze = info.zs + info.zm;
1060
1061 PetscFunctionBeginUser;
1062 PetscCall(DMGetLocalVector(user->fda, &local_x));
1063 PetscCall(DMGlobalToLocalBegin(user->fda, X, INSERT_VALUES, local_x));
1064 PetscCall(DMGlobalToLocalEnd(user->fda, X, INSERT_VALUES, local_x));
1065 PetscCall(DMDAVecGetArrayRead(user->fda, X, &x));
1066 PetscCall(DMDAVecGetArrayRead(user->fda, user->Ucont, &conditioned));
1067 PetscCall(DMDAVecGetArray(user->fda, F, &f));
1068 PetscCall(DMDAVecGetArrayRead(user->fda, local_x, &lx));
1069
1070 for (PetscInt k = zs; k < ze; ++k) {
1071 for (PetscInt j = ys; j < ye; ++j) {
1072 for (PetscInt i = xs; i < xe; ++i) {
1073 PetscScalar *fv = &f[k][j][i].x;
1074 const PetscScalar *xv = &x[k][j][i].x;
1075 const PetscScalar *cv = &conditioned[k][j][i].x;
1076
1077 for (PetscInt component = 0; component < 3; ++component) {
1078 PetscInt ri, rj, rk;
1080 user, i, j, k, component, &ri, &rj, &rk);
1081 const PetscScalar *rv = &lx[rk][rj][ri].x;
1082
1083 if (row == MOM_ROW_FIXED_CONDITIONED) fv[component] = xv[component] - cv[component];
1084 else if (row == MOM_ROW_FIXED_HOMOGENEOUS) fv[component] = xv[component];
1085 else if (row == MOM_ROW_PERIODIC_DUPLICATE) fv[component] = xv[component] - rv[component];
1086 }
1087 }
1088 }
1089 }
1090
1091 PetscCall(DMDAVecRestoreArrayRead(user->fda, local_x, &lx));
1092 PetscCall(DMDAVecRestoreArray(user->fda, F, &f));
1093 PetscCall(DMDAVecRestoreArrayRead(user->fda, user->Ucont, &conditioned));
1094 PetscCall(DMDAVecRestoreArrayRead(user->fda, X, &x));
1095 PetscCall(DMRestoreLocalVector(user->fda, &local_x));
1096 PetscFunctionReturn(PETSC_SUCCESS);
1097}
MomentumRowType
Classification of one staggered momentum row (location + component).
Definition Boundaries.h:252
@ MOM_ROW_FIXED_HOMOGENEOUS
Dummy/tangential row carrying no unknown at all.
Definition Boundaries.h:255
@ MOM_ROW_PERIODIC_DUPLICATE
Duplicate of a wrapped representative row (see ri, rj, rk).
Definition Boundaries.h:256
@ MOM_ROW_FIXED_CONDITIONED
Strong Dirichlet row; the value comes from ApplyBoundaryConditions().
Definition Boundaries.h:254
MomentumRowType ClassifyMomentumRow(UserCtx *user, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
Single source of truth for "which staggered momentum rows are unknowns".
Definition Boundaries.c:597
PetscScalar x
Definition variables.h:121
DMDALocalInfo info
Definition variables.h:1080
A 3D point or vector with PetscScalar components.
Definition variables.h:120
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_ReadLinearizationConfig()

static PetscErrorCode MomentumNewtonKrylov_ReadLinearizationConfig ( MomentumNewtonJacobian *  jacobian,
MomentumPreconditionerDescription *  description 
)
static

Reads application-owned Jacobian and preconditioner mathematics.

Definition at line 335 of file momentum_newton_krylov.c.

337{
338 char type[48] = "finite_difference";
339 char finite_difference_mode[32] = "matrix_free";
340 char model[48] = "none";
341 char structure[32] = "none";
342 PetscBool set = PETSC_FALSE, match = PETSC_FALSE;
343
344 PetscFunctionBeginUser;
345 PetscCheck(jacobian != NULL && description != NULL, PETSC_COMM_SELF,
346 PETSC_ERR_ARG_NULL, "Newton Krylov linearization configuration is NULL.");
347 PetscCall(PetscOptionsGetString(NULL, NULL, "-mom_nk_jacobian_type",
348 type, sizeof(type), &set));
349 PetscCall(PetscStrcasecmp(type, "finite_difference", &match));
350 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
351 "-mom_nk_jacobian_type must be 'finite_difference' (got '%s').", type);
353 PetscCall(PetscOptionsGetString(NULL, NULL, "-mom_nk_jacobian_fd_mode",
354 finite_difference_mode,
355 sizeof(finite_difference_mode), &set));
356 PetscCall(PetscStrcasecmp(finite_difference_mode, "matrix_free", &match));
357 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
358 "-mom_nk_jacobian_fd_mode must be 'matrix_free' (got '%s').",
359 finite_difference_mode);
361
362 PetscCall(PetscOptionsGetString(NULL, NULL, "-mom_nk_preconditioner_model",
363 model, sizeof(model), &set));
364 PetscCall(PetscStrcasecmp(model, "none", &match));
365 if (match) description->model = MOM_NK_PC_MODEL_NONE;
366 if (!match) {
367 PetscCall(PetscStrcasecmp(model, "frozen_momentum_jacobian", &match));
368 if (match) description->model = MOM_NK_PC_MODEL_FROZEN_MOMENTUM_JACOBIAN;
369 }
370 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
371 "-mom_nk_preconditioner_model must be 'none' or "
372 "'frozen_momentum_jacobian' (got '%s').", model);
373 PetscCall(PetscOptionsGetString(NULL, NULL, "-mom_nk_preconditioner_structure",
374 structure, sizeof(structure), &set));
375 PetscCall(PetscStrcasecmp(structure, "none", &match));
376 if (match) description->structure = MOM_NK_PC_STRUCTURE_NONE;
377 if (!match) {
378 PetscCall(PetscStrcasecmp(structure, "point_block", &match));
379 if (match) description->structure = MOM_NK_PC_STRUCTURE_POINT_BLOCK;
380 }
381 PetscCheck(match, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG,
382 "-mom_nk_preconditioner_structure must be 'none' or 'point_block' "
383 "(got '%s').", structure);
384 PetscCheck((description->model == MOM_NK_PC_MODEL_NONE &&
385 description->structure == MOM_NK_PC_STRUCTURE_NONE) ||
388 PETSC_COMM_WORLD, PETSC_ERR_SUP,
389 "Unsupported Newton Krylov preconditioner model/structure combination: "
390 "model='%s', structure='%s'.", model, structure);
391 PetscFunctionReturn(PETSC_SUCCESS);
392}
MomentumNewtonFiniteDifferenceMode finite_difference_mode
MomentumNewtonJacobianType type
MomentumPreconditionerStructure structure
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_FormJacobian()

static PetscErrorCode MomentumNewtonKrylov_FormJacobian ( SNES  snes,
Vec  current_solution,
Mat  jacobian_operator,
Mat  preconditioning_matrix,
void *  vctx 
)
static

Updates the Jacobian and then assembles any separate preconditioning matrix.

Definition at line 863 of file momentum_newton_krylov.c.

865{
867 PetscFunctionBeginUser;
868 (void)jacobian_operator;
869 (void)preconditioning_matrix;
870 PetscCall(MomentumNewtonJacobian_Update(snes, current_solution, &ctx->jacobian));
872 &ctx->preconditioning_engine, ctx->user, current_solution));
873 PetscFunctionReturn(PETSC_SUCCESS);
874}
static PetscErrorCode MomentumPreconditionerEngine_Assemble(MomentumPreconditionerEngine *engine, UserCtx *user, Vec current_solution)
Runs model insertion, common row handling, and final assembly.
static PetscErrorCode MomentumNewtonJacobian_Update(SNES snes, Vec current_solution, MomentumNewtonJacobian *jacobian)
Updates the matrix-free finite-difference operator base.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FrozenMomentumJacobian_AssemblePointBlocks()

static PetscErrorCode FrozenMomentumJacobian_AssemblePointBlocks ( UserCtx *  user,
Vec  current_solution,
Mat  preconditioning_matrix 
)
static

Inserts only the audited interior frozen-momentum point blocks.

Definition at line 600 of file momentum_newton_krylov.c.

602{
603 DMDALocalInfo info = user->info;
604 Cmpnts ***ucont = NULL, ***csi = NULL, ***eta = NULL, ***zet = NULL;
605 PetscReal ***aj = NULL, ***nvert = NULL, ***nu_t = NULL;
606 SimCtx *simCtx = user->simCtx;
607 /* The eddy viscosity enters the preconditioner only when a turbulence model is
608 actually producing one; without it the field may not even be allocated. */
609 const PetscBool has_eddy_viscosity =
610 (PetscBool)(simCtx->les && user->lNu_t != NULL);
611 PetscErrorCode ierr = PETSC_SUCCESS, cleanup_ierr;
612
613 PetscFunctionBeginUser;
614 /*
615 * current_solution is the current SNES trial Ucont Vec: it is layout-compatible
616 * with user->fda/user->Ucont, but is not necessarily the canonical user->Ucont
617 * selected by UpdateLocalGhosts(FIELD_ID_UCONT). Scatter that trial Vec directly with
618 * user->fda so PETSc applies its MPI ownership, periodic topology, component
619 * ordering, and ghost mapping without canonical-field synchronization or mutation
620 * of current_solution. UpdateLocalGhosts additionally repairs the component-normal
621 * staggered buffers Uxi(i=-1,mx), Ueta(j=-1,my), and Uzeta(k=-1,mz); the audited
622 * point-block velocity stencil reads none of those planes, so the repair cannot
623 * change a coefficient. Revisit this choice and extend the periodic-localization
624 * tests if the model stencil is expanded to read any repaired normal buffer.
625 */
626 ierr = DMGlobalToLocalBegin(user->fda, current_solution, INSERT_VALUES, user->lUcont);
627 if (ierr) goto cleanup;
628 ierr = DMGlobalToLocalEnd(user->fda, current_solution, INSERT_VALUES, user->lUcont);
629 if (ierr) goto cleanup;
630 ierr = DMDAVecGetArrayRead(user->fda, user->lUcont, &ucont); if (ierr) goto cleanup;
631 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi); if (ierr) goto cleanup;
632 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta); if (ierr) goto cleanup;
633 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet); if (ierr) goto cleanup;
634 ierr = DMDAVecGetArrayRead(user->da, user->lAj, &aj); if (ierr) goto cleanup;
635 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, &nvert); if (ierr) goto cleanup;
636 if (has_eddy_viscosity) {
637 ierr = DMDAVecGetArrayRead(user->da, user->lNu_t, &nu_t); if (ierr) goto cleanup;
638 }
639 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k) {
640 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j) {
641 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
642 for (PetscInt component = 0; component < 3; ++component) {
643 MatStencil row = {.i = i, .j = j, .k = k, .c = component};
644 PetscInt ri, rj, rk;
646 user, (const PetscReal ***)nvert, i, j, k, component, &ri, &rj, &rk);
647 if (type == MOM_ROW_PHYSICAL) {
648 PetscScalar block[9];
649 MatStencil cols[3] = {
650 {.i = i, .j = j, .k = k, .c = 0},
651 {.i = i, .j = j, .k = k, .c = 1},
652 {.i = i, .j = j, .k = k, .c = 2}
653 };
654 FrozenMomentumJacobian_PointBlock(user, (const Cmpnts ***)ucont,
655 (const Cmpnts ***)csi, (const Cmpnts ***)eta, (const Cmpnts ***)zet,
656 (const PetscReal ***)aj, (const PetscReal ***)nu_t, i, j, k, block);
657 ierr = MatSetValuesStencil(preconditioning_matrix, 1, &row, 3, cols,
658 &block[3 * component], INSERT_VALUES);
659 if (ierr) goto cleanup;
660 }
661 }
662 }
663 }
664 }
665cleanup:
666 if (nu_t) { cleanup_ierr = DMDAVecRestoreArrayRead(user->da, user->lNu_t, &nu_t); if (!ierr) ierr = cleanup_ierr; }
667 if (nvert) { cleanup_ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, &nvert); if (!ierr) ierr = cleanup_ierr; }
668 if (aj) { cleanup_ierr = DMDAVecRestoreArrayRead(user->da, user->lAj, &aj); if (!ierr) ierr = cleanup_ierr; }
669 if (zet) { cleanup_ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet); if (!ierr) ierr = cleanup_ierr; }
670 if (eta) { cleanup_ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta); if (!ierr) ierr = cleanup_ierr; }
671 if (csi) { cleanup_ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi); if (!ierr) ierr = cleanup_ierr; }
672 if (ucont) { cleanup_ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcont, &ucont); if (!ierr) ierr = cleanup_ierr; }
673 PetscFunctionReturn(ierr);
674}
@ MOM_ROW_PHYSICAL
Independent unknown governed by the momentum equation.
Definition Boundaries.h:253
static void FrozenMomentumJacobian_PointBlock(const UserCtx *user, const Cmpnts ***ucont, const Cmpnts ***csi, const Cmpnts ***eta, const Cmpnts ***zet, const PetscReal ***aj, const PetscReal ***nu_t, PetscInt i, PetscInt j, PetscInt k, PetscScalar block[9])
Returns the frozen-momentum point block for the current residual convention.
static MomentumRowType MomentumNewtonKrylov_ClassifyRow(UserCtx *user, const PetscReal ***nvert, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
Row classification with solid-cell masking folded in.
Vec lNvert
Definition variables.h:1108
Vec lNu_t
Definition variables.h:1151
Vec lUcont
Definition variables.h:1108
PetscInt les
Active LES closure; an LESModelType value.
Definition variables.h:985
double nu_t(double yplus)
Computes turbulent eddy viscosity ratio (ν_t / ν)
Here is the call graph for this function:

◆ MomentumPreconditionerEngine_CreateExactPointBlockMatrix()

static PetscErrorCode MomentumPreconditionerEngine_CreateExactPointBlockMatrix ( UserCtx *  user,
Mat *  preconditioning_matrix 
)
static

Creates the frozen point-block P matrix with its exact scalar pattern.

Row and column ownership follows the velocity DMDA global vector. Physical rows reserve the three same-point components, fixed rows reserve only their diagonal, and periodic duplicate rows additionally reserve their wrapped representative. DMDA AO, local mapping, and stencil metadata are retained so the existing insertion paths keep their exact ordering.

Definition at line 886 of file momentum_newton_krylov.c.

888{
889 DMDALocalInfo info;
890 ISLocalToGlobalMapping local_to_global = NULL;
891 Mat matrix = NULL;
892 MPI_Comm comm;
893 PetscInt local_size, global_size, ownership_start, ownership_end;
894 PetscInt *diagonal_nnz = NULL, *offdiagonal_nnz = NULL;
895 PetscInt ghost_starts[4] = {0, 0, 0, 0}, ghost_sizes[3] = {0, 0, 0};
896 const PetscReal ***nvert = NULL;
897 PetscErrorCode ierr = PETSC_SUCCESS, cleanup_ierr;
898
899 PetscFunctionBeginUser;
900 PetscCheck(preconditioning_matrix != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
901 "Point-block matrix output is NULL.");
902 *preconditioning_matrix = NULL;
903 comm = PetscObjectComm((PetscObject)user->fda);
904 PetscCall(DMDAGetLocalInfo(user->fda, &info));
905 PetscCall(VecGetLocalSize(user->Ucont, &local_size));
906 PetscCall(VecGetSize(user->Ucont, &global_size));
907 PetscCall(VecGetOwnershipRange(user->Ucont, &ownership_start, &ownership_end));
908 PetscCheck(local_size == ownership_end - ownership_start, comm, PETSC_ERR_PLIB,
909 "Velocity ownership range does not match its local size.");
910 ierr = PetscCalloc2(local_size, &diagonal_nnz,
911 local_size, &offdiagonal_nnz); if (ierr) goto cleanup;
912 ierr = DMGetLocalToGlobalMapping(user->fda, &local_to_global); if (ierr) goto cleanup;
913 ierr = DMDAGetGhostCorners(user->fda,
914 &ghost_starts[0], &ghost_starts[1], &ghost_starts[2],
915 &ghost_sizes[0], &ghost_sizes[1], &ghost_sizes[2]);
916 if (ierr) goto cleanup;
917 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, &nvert); if (ierr) goto cleanup;
918
919 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k) {
920 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j) {
921 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
922 for (PetscInt component = 0; component < 3; ++component) {
923 PetscInt ri, rj, rk, column_count;
924 MatStencil row_stencil = {.i = i, .j = j, .k = k, .c = component};
925 MatStencil column_stencils[3];
926 PetscInt row_local, row, column_locals[3], columns[3];
928 user, nvert, i, j, k, component, &ri, &rj, &rk);
929
930 if (type == MOM_ROW_PHYSICAL) {
931 column_count = 3;
932 for (PetscInt column_component = 0; column_component < 3;
933 ++column_component) {
934 column_stencils[column_component] = (MatStencil){
935 .i = i, .j = j, .k = k, .c = column_component
936 };
937 }
938 } else {
939 column_count = 1;
940 column_stencils[0] = row_stencil;
941 if (type == MOM_ROW_PERIODIC_DUPLICATE) {
942 column_stencils[column_count++] = (MatStencil){
943 .i = ri, .j = rj, .k = rk, .c = component
944 };
945 }
946 }
947 row_local = component + 3 * (
948 (i - ghost_starts[0]) + ghost_sizes[0] * (
949 (j - ghost_starts[1]) + ghost_sizes[1] *
950 (k - ghost_starts[2])));
951 for (PetscInt column_index = 0; column_index < column_count;
952 ++column_index) {
953 const MatStencil column = column_stencils[column_index];
954 if (!(column.i >= ghost_starts[0] &&
955 column.i < ghost_starts[0] + ghost_sizes[0] &&
956 column.j >= ghost_starts[1] &&
957 column.j < ghost_starts[1] + ghost_sizes[1] &&
958 column.k >= ghost_starts[2] &&
959 column.k < ghost_starts[2] + ghost_sizes[2])) {
960 ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__,
961 PETSC_ERR_ARG_OUTOFRANGE,
962 PETSC_ERROR_INITIAL,
963 "Point-block column lies outside the DMDA ghost stencil.");
964 goto cleanup;
965 }
966 column_locals[column_index] = column.c + 3 * (
967 (column.i - ghost_starts[0]) + ghost_sizes[0] * (
968 (column.j - ghost_starts[1]) + ghost_sizes[1] *
969 (column.k - ghost_starts[2])));
970 }
971 ierr = ISLocalToGlobalMappingApply(local_to_global, 1,
972 &row_local, &row);
973 if (ierr) goto cleanup;
974 ierr = ISLocalToGlobalMappingApply(local_to_global, column_count,
975 column_locals, columns);
976 if (ierr) goto cleanup;
977 if (!(row >= ownership_start && row < ownership_end)) {
978 ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__,
979 PETSC_ERR_PLIB, PETSC_ERROR_INITIAL,
980 "DMDA-mapped point-block row is not locally owned.");
981 goto cleanup;
982 }
983 for (PetscInt column_index = 0; column_index < column_count;
984 ++column_index) {
985 PetscBool duplicate = PETSC_FALSE;
986 for (PetscInt previous = 0; previous < column_index; ++previous)
987 if (columns[previous] == columns[column_index]) duplicate = PETSC_TRUE;
988 if (columns[column_index] < 0) {
989 ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__,
990 PETSC_ERR_PLIB, PETSC_ERROR_INITIAL,
991 "DMDA-mapped point-block column is invalid.");
992 goto cleanup;
993 }
994 if (duplicate) continue;
995 if (columns[column_index] >= ownership_start &&
996 columns[column_index] < ownership_end)
997 ++diagonal_nnz[row - ownership_start];
998 else
999 ++offdiagonal_nnz[row - ownership_start];
1000 }
1001 }
1002 }
1003 }
1004 }
1005
1006 ierr = MatCreateAIJ(comm, local_size, local_size, global_size, global_size,
1007 0, diagonal_nnz, 0, offdiagonal_nnz, &matrix);
1008 if (ierr) goto cleanup;
1009 ierr = MatSetBlockSize(matrix, 3); if (ierr) goto cleanup;
1010 ierr = MatSetLocalToGlobalMapping(matrix, local_to_global, local_to_global);
1011 if (ierr) goto cleanup;
1012 ierr = MatSetStencil(matrix, 3, ghost_sizes, ghost_starts, 3);
1013 if (ierr) goto cleanup;
1014 ierr = MatSetDM(matrix, user->fda); if (ierr) goto cleanup;
1015 ierr = MatSetOption(matrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
1016 if (ierr) goto cleanup;
1017 ierr = PetscFree2(diagonal_nnz, offdiagonal_nnz); if (ierr) goto cleanup;
1018
1019 *preconditioning_matrix = matrix;
1020 matrix = NULL;
1021
1022cleanup:
1023 if (nvert) {
1024 cleanup_ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, &nvert);
1025 if (!ierr) ierr = cleanup_ierr;
1026 }
1027 cleanup_ierr = MatDestroy(&matrix); if (!ierr) ierr = cleanup_ierr;
1028 cleanup_ierr = PetscFree2(diagonal_nnz, offdiagonal_nnz);
1029 if (!ierr) ierr = cleanup_ierr;
1030 PetscFunctionReturn(ierr);
1031}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MomentumNewtonKrylov_ClassifyRow()

static MomentumRowType MomentumNewtonKrylov_ClassifyRow ( UserCtx *  user,
const PetscReal ***  nvert,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscInt  component,
PetscInt *  ri,
PetscInt *  rj,
PetscInt *  rk 
)
static

Row classification with solid-cell masking folded in.

A masked row's residual is identically zero for every X, so it has a zero Jacobian row and a zero column and its unknown is undetermined. It therefore needs the same identity treatment as any other row carrying no unknown. Checked after the boundary classification so a periodic duplicate keeps its representative column.

Definition at line 402 of file momentum_newton_krylov.c.

405{
406 const MomentumRowType type = ClassifyMomentumRow(user, i, j, k, component, ri, rj, rk);
407
408 if (type == MOM_ROW_PHYSICAL && MomentumRowIsSolidMasked(nvert, i, j, k, component))
410 return type;
411}
PetscBool MomentumRowIsSolidMasked(const PetscReal ***nvert, PetscInt i, PetscInt j, PetscInt k, PetscInt component)
Reports whether a momentum row is masked out by the solid-cell field.
Definition Boundaries.c:655
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FrozenMomentumJacobian_MetricNormSquared()

static PetscReal FrozenMomentumJacobian_MetricNormSquared ( Cmpnts  metric)
static

Returns the squared Euclidean norm of one metric vector.

Definition at line 414 of file momentum_newton_krylov.c.

415{
416 return metric.x * metric.x + metric.y * metric.y + metric.z * metric.z;
417}
PetscScalar z
Definition variables.h:121
PetscScalar y
Definition variables.h:121
Here is the caller graph for this function:

◆ FrozenMomentumJacobian_FaceEddyViscosity()

static PetscReal FrozenMomentumJacobian_FaceEddyViscosity ( const UserCtx *  user,
const PetscReal ***  nu_t,
PetscInt  axis,
PetscInt  i,
PetscInt  j,
PetscInt  k 
)
static

Returns the face-averaged eddy viscosity the residual uses on one face.

The preconditioner has to reproduce the operator it preconditions, so the interior face average here tracks Viscous().

The WALL branch below does not, and is retained only because it cannot currently change an assembled entry. It is unreachable by construction, not by configuration: FrozenMomentumJacobian_PointBlock() puts the eddy viscosity only on the three diagonal entries, and the row-at-a-time insertion in FrozenMomentumJacobian_AssemblePointBlocks() means row c carries only axis == c. The two coordinates that trigger the branch are exactly those ClassifyMomentumRow() reports as non-MOM_ROW_PHYSICAL, and only physical rows assemble a block; the WALL-on-a-periodic-axis loophole is closed by the pairing check in BoundarySystem_Validate(). Both rules state the same boundary fact: the wall-normal flux at a no-slip wall is not an unknown.

Viscous() substitutes the wall-model eddy viscosity lnu_wall on a wall face and falls back to zero only when simCtx->wallfunction is unset, so this branch is already wrong for a wall-modelled run – it simply has no way to express that yet. Widening the stencil makes it reachable and therefore wrong in effect: an interior row would need the eddy viscosity on the wall face for its off-diagonal. Fix this to read lNu_Wall before adding any preconditioner with stencil_width >= 1, or any row classification that makes wall-normal DOFs solvable. Tracked as issue #8.

Definition at line 444 of file momentum_newton_krylov.c.

447{
448 const BCFace neg_face[3] = {BC_FACE_NEG_X, BC_FACE_NEG_Y, BC_FACE_NEG_Z};
449 const BCFace pos_face[3] = {BC_FACE_POS_X, BC_FACE_POS_Y, BC_FACE_POS_Z};
450 const PetscInt coord[3] = {i, j, k};
451 const PetscInt size[3] = {user->info.mx, user->info.my, user->info.mz};
452 PetscReal neighbour;
453
454 if (nu_t == NULL) return 0.0;
455 if ((user->boundary_faces[neg_face[axis]].mathematical_type == WALL && coord[axis] == 0) ||
456 (user->boundary_faces[pos_face[axis]].mathematical_type == WALL && coord[axis] == size[axis] - 2))
457 return 0.0;
458
459 neighbour = (axis == 0) ? nu_t[k][j][i + 1]
460 : (axis == 1) ? nu_t[k][j + 1][i]
461 : nu_t[k + 1][j][i];
462 return 0.5 * (nu_t[k][j][i] + neighbour);
463}
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:291
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FrozenMomentumJacobian_PointBlock()

static void FrozenMomentumJacobian_PointBlock ( const UserCtx *  user,
const Cmpnts ***  ucont,
const Cmpnts ***  csi,
const Cmpnts ***  eta,
const Cmpnts ***  zet,
const PetscReal ***  aj,
const PetscReal ***  nu_t,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscScalar  block[9] 
)
static

Returns the frozen-momentum point block for the current residual convention.

Definition at line 466 of file momentum_newton_krylov.c.

470{
471 const SimCtx *simCtx = user->simCtx;
472 const PetscReal dtc = MomentumBDFCoefficient((SimCtx *)simCtx) / simCtx->dt;
473 const PetscReal molecular = simCtx->ren > 0.0 ? 1.0 / simCtx->ren : 0.0;
474 /* The residual diffuses with nu + nu_t, so the block must too; nu_t alone is the
475 eddy contribution. Omitting it left the preconditioner modelling a viscous
476 diagonal smaller than the operator's by the eddy-to-molecular ratio, which on a
477 developed LES is order one or more. */
478 const PetscReal nu_eff_i = molecular + FrozenMomentumJacobian_FaceEddyViscosity(user, nu_t, 0, i, j, k);
479 const PetscReal nu_eff_j = molecular + FrozenMomentumJacobian_FaceEddyViscosity(user, nu_t, 1, i, j, k);
480 const PetscReal nu_eff_k = molecular + FrozenMomentumJacobian_FaceEddyViscosity(user, nu_t, 2, i, j, k);
481 const PetscReal AJip = 0.5 * (aj[k][j][i] + aj[k][j][i + 1]);
482 const PetscReal AJjp = 0.5 * (aj[k][j][i] + aj[k][j + 1][i]);
483 const PetscReal AJkp = 0.5 * (aj[k][j][i] + aj[k + 1][j][i]);
484 const PetscReal g11ip = csi[k][j][i].x * csi[k][j][i].x +
485 csi[k][j][i].y * csi[k][j][i].y +
486 csi[k][j][i].z * csi[k][j][i].z;
487 const PetscReal g22ip = 0.25 * (
491 FrozenMomentumJacobian_MetricNormSquared(eta[k][j - 1][i + 1]));
492 const PetscReal g33ip = 0.25 * (
496 FrozenMomentumJacobian_MetricNormSquared(zet[k - 1][j][i + 1]));
497 const PetscReal g11jp = 0.25 * (
501 FrozenMomentumJacobian_MetricNormSquared(csi[k][j + 1][i - 1]));
502 const PetscReal g22jp = eta[k][j][i].x * eta[k][j][i].x +
503 eta[k][j][i].y * eta[k][j][i].y +
504 eta[k][j][i].z * eta[k][j][i].z;
505 const PetscReal g33jp = 0.25 * (
509 FrozenMomentumJacobian_MetricNormSquared(zet[k - 1][j + 1][i]));
510 const PetscReal g11kp = 0.25 * (
514 FrozenMomentumJacobian_MetricNormSquared(csi[k + 1][j][i - 1]));
515 const PetscReal g22kp = 0.25 * (
519 FrozenMomentumJacobian_MetricNormSquared(eta[k + 1][j - 1][i]));
520 const PetscReal g33kp = zet[k][j][i].x * zet[k][j][i].x +
521 zet[k][j][i].y * zet[k][j][i].y +
522 zet[k][j][i].z * zet[k][j][i].z;
523 const PetscReal U0jp = 0.25 * (ucont[k][j][i].x + ucont[k][j][i - 1].x +
524 ucont[k][j + 1][i].x + ucont[k][j + 1][i - 1].x);
525 const PetscReal U0kp = 0.25 * (ucont[k][j][i].x + ucont[k][j][i - 1].x +
526 ucont[k + 1][j][i].x + ucont[k + 1][j][i - 1].x);
527 const PetscReal U1ip = 0.25 * (ucont[k][j][i].y + ucont[k][j - 1][i].y +
528 ucont[k][j][i + 1].y + ucont[k][j - 1][i + 1].y);
529 const PetscReal U1kp = 0.25 * (ucont[k][j][i].y + ucont[k][j - 1][i].y +
530 ucont[k + 1][j][i].y + ucont[k + 1][j - 1][i].y);
531 const PetscReal U2ip = 0.25 * (ucont[k][j][i].z + ucont[k - 1][j][i].z +
532 ucont[k][j][i + 1].z + ucont[k - 1][j][i + 1].z);
533 const PetscReal U2jp = 0.25 * (ucont[k][j][i].z + ucont[k - 1][j][i].z +
534 ucont[k][j + 1][i].z + ucont[k - 1][j + 1][i].z);
535 PetscReal A[6][4] = {{0.0}};
536 PetscReal Su, Sv, Sw, nui, nuj, nuk;
537
538 A[0][0] = 0.125 * aj[k][j][i] * ucont[k][j][i].y;
539 A[0][1] = -0.125 * aj[k][j - 1][i] * ucont[k][j - 1][i].y;
540 A[0][2] = 0.125 * aj[k][j][i + 1] * ucont[k][j][i + 1].y;
541 A[0][3] = -0.125 * aj[k][j - 1][i + 1] * ucont[k][j - 1][i + 1].y;
542 A[1][0] = 0.125 * aj[k][j][i] * ucont[k][j][i].z;
543 A[1][1] = -0.125 * aj[k - 1][j][i] * ucont[k - 1][j][i].z;
544 A[1][2] = 0.125 * aj[k][j][i + 1] * ucont[k][j][i + 1].z;
545 A[1][3] = -0.125 * aj[k - 1][j][i + 1] * ucont[k - 1][j][i + 1].z;
546 A[2][0] = -0.125 * aj[k][j + 1][i - 1] * ucont[k][j + 1][i - 1].x;
547 A[2][1] = -0.125 * aj[k][j][i - 1] * ucont[k][j][i - 1].x;
548 A[2][2] = 0.125 * aj[k][j + 1][i] * ucont[k][j + 1][i].x;
549 A[2][3] = 0.125 * aj[k][j][i] * ucont[k][j][i].x;
550 A[3][0] = 0.125 * aj[k][j][i] * ucont[k][j][i].z;
551 A[3][1] = -0.125 * aj[k - 1][j][i] * ucont[k - 1][j][i].z;
552 A[3][2] = 0.125 * aj[k][j + 1][i] * ucont[k][j + 1][i].z;
553 A[3][3] = -0.125 * aj[k - 1][j + 1][i] * ucont[k - 1][j + 1][i].z;
554 A[4][0] = -0.125 * aj[k + 1][j][i - 1] * ucont[k + 1][j][i - 1].x;
555 A[4][1] = -0.125 * aj[k][j][i - 1] * ucont[k][j][i - 1].x;
556 A[4][2] = 0.125 * aj[k + 1][j][i] * ucont[k + 1][j][i].x;
557 A[4][3] = 0.125 * aj[k][j][i] * ucont[k][j][i].x;
558 A[5][0] = -0.125 * aj[k + 1][j - 1][i] * ucont[k + 1][j - 1][i].y;
559 A[5][1] = -0.125 * aj[k][j - 1][i] * ucont[k][j - 1][i].y;
560 A[5][2] = 0.125 * aj[k + 1][j][i] * ucont[k + 1][j][i].y;
561 A[5][3] = 0.125 * aj[k][j][i] * ucont[k][j][i].y;
562 Su = A[0][0] + A[0][1] + A[0][2] + A[0][3] +
563 A[1][0] + A[1][1] + A[1][2] + A[1][3];
564 Sv = A[2][0] + A[2][1] + A[2][2] + A[2][3] +
565 A[3][0] + A[3][1] + A[3][2] + A[3][3];
566 Sw = A[4][0] + A[4][1] + A[4][2] + A[4][3] +
567 A[5][0] + A[5][1] + A[5][2] + A[5][3];
568 nui = AJip * AJip * (g11ip + g22ip + g33ip) * nu_eff_i;
569 nuj = AJjp * AJjp * (g11jp + g22jp + g33jp) * nu_eff_j;
570 nuk = AJkp * AJkp * (g11kp + g22kp + g33kp) * nu_eff_k;
571
572 /* MomentumNewtonKrylov_FormResidual forms F = -R, fixing this block's sign. */
573 /* `block` is row-major: each row is one residual component and each column
574 is one same-cell Ucont component. */
575 block[0] = dtc + nui + Su; block[1] = 0.5 * AJjp * U0jp; block[2] = 0.5 * AJkp * U0kp;
576 block[3] = 0.5 * AJip * U1ip; block[4] = dtc + nuj + Sv; block[5] = 0.5 * AJkp * U1kp;
577 block[6] = 0.5 * AJip * U2ip; block[7] = 0.5 * AJjp * U2jp; block[8] = dtc + nuk + Sw;
578}
static PetscReal FrozenMomentumJacobian_FaceEddyViscosity(const UserCtx *user, const PetscReal ***nu_t, PetscInt axis, PetscInt i, PetscInt j, PetscInt k)
Returns the face-averaged eddy viscosity the residual uses on one face.
static PetscReal FrozenMomentumJacobian_MetricNormSquared(Cmpnts metric)
Returns the squared Euclidean norm of one metric vector.
PetscReal MomentumBDFCoefficient(SimCtx *simCtx)
Returns the BDF physical-time coefficient a0 for the current step.
PetscReal ren
Definition variables.h:910
PetscReal dt
Definition variables.h:878
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FrozenMomentumJacobian_DescribePointBlock()

static PetscErrorCode FrozenMomentumJacobian_DescribePointBlock ( UserCtx *  user,
MomentumPreconditionerDescription *  description 
)
static

Describes the audited frozen-coefficient point-block model.

Definition at line 583 of file momentum_newton_krylov.c.

585{
586 PetscFunctionBeginUser;
587 (void)user;
588 PetscCheck(description != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
589 "Preconditioner description is NULL.");
592 description->block_size = 3;
593 description->stencil_width = 0;
594 PetscFunctionReturn(PETSC_SUCCESS);
595}

◆ MomentumPreconditionerEngine_ApplyConstraintRows()

static PetscErrorCode MomentumPreconditionerEngine_ApplyConstraintRows ( UserCtx *  user,
Mat  preconditioning_matrix 
)
static

Inserts all common fixed, homogeneous, and periodic-duplicate rows.

Definition at line 679 of file momentum_newton_krylov.c.

681{
682 DMDALocalInfo info = user->info;
683 const PetscReal ***nvert = NULL;
684
685 PetscFunctionBeginUser;
686 PetscCall(DMDAVecGetArrayRead(user->da, user->lNvert, &nvert));
687 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k) {
688 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j) {
689 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
690 for (PetscInt component = 0; component < 3; ++component) {
691 PetscInt ri, rj, rk;
693 user, nvert, i, j, k, component, &ri, &rj, &rk);
694 if (type != MOM_ROW_PHYSICAL) {
695 MatStencil row = {.i = i, .j = j, .k = k, .c = component};
696 MatStencil columns[2] = {row, row};
697 PetscScalar values[2] = {1.0, -1.0};
698 PetscInt column_count = 1;
699 if (type == MOM_ROW_PERIODIC_DUPLICATE) {
700 columns[column_count++] = (MatStencil){
701 .i = ri, .j = rj, .k = rk, .c = component
702 };
703 }
704 PetscCall(MatSetValuesStencil(preconditioning_matrix, 1, &row,
705 column_count, columns, values,
706 INSERT_VALUES));
707 }
708 }
709 }
710 }
711 }
712 PetscCall(DMDAVecRestoreArrayRead(user->da, user->lNvert, &nvert));
713 PetscFunctionReturn(PETSC_SUCCESS);
714}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MomentumNewtonJacobian_Create()

static PetscErrorCode MomentumNewtonJacobian_Create ( SNES  snes,
MomentumNewtonJacobian *  jacobian 
)
static

Creates the selected Jacobian operator; currently PETSc MFFD only.

Definition at line 724 of file momentum_newton_krylov.c.

726{
727 PetscFunctionBeginUser;
728 PetscCheck(jacobian->type == MOM_NK_JACOBIAN_FINITE_DIFFERENCE &&
730 PETSC_COMM_WORLD, PETSC_ERR_SUP,
731 "Unsupported Newton Krylov Jacobian type/finite-difference-mode combination.");
732 PetscCall(MatCreateSNESMF(snes, &jacobian->jacobian_operator));
733 PetscCall(MatSetOptionsPrefix(jacobian->jacobian_operator, "mom_nk_"));
734 PetscCall(PetscObjectSetName((PetscObject)jacobian->jacobian_operator,
735 "momentum_jacobian_finite_difference_matrix_free"));
736 PetscFunctionReturn(PETSC_SUCCESS);
737}
Here is the caller graph for this function:

◆ MomentumNewtonJacobian_Update()

static PetscErrorCode MomentumNewtonJacobian_Update ( SNES  snes,
Vec  current_solution,
MomentumNewtonJacobian *  jacobian 
)
static

Updates the matrix-free finite-difference operator base.

Definition at line 740 of file momentum_newton_krylov.c.

742{
743 PetscFunctionBeginUser;
744 PetscCall(MatMFFDComputeJacobian(snes, current_solution, jacobian->jacobian_operator,
745 jacobian->jacobian_operator, NULL));
746 PetscFunctionReturn(PETSC_SUCCESS);
747}
Here is the caller graph for this function:

◆ MomentumNewtonJacobian_Register()

static PetscErrorCode MomentumNewtonJacobian_Register ( SNES  snes,
MomentumNewtonJacobian *  jacobian,
MomentumPreconditionerEngine *  engine,
MomentumNewtonKrylovContext *  ctx 
)
static

Registers the application orchestration callback and both SNES matrices.

Definition at line 750 of file momentum_newton_krylov.c.

753{
754 PetscFunctionBeginUser;
755 PetscCall(SNESSetJacobian(snes, jacobian->jacobian_operator,
758 PetscFunctionReturn(PETSC_SUCCESS);
759}
static PetscErrorCode MomentumNewtonKrylov_FormJacobian(SNES snes, Vec current_solution, Mat jacobian_operator, Mat preconditioning_matrix, void *vctx)
Updates the Jacobian and then assembles any separate preconditioning matrix.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MomentumNewtonJacobian_Destroy()

static PetscErrorCode MomentumNewtonJacobian_Destroy ( MomentumNewtonJacobian *  jacobian)
static

Destroys a partially or fully created Jacobian operator.

Definition at line 762 of file momentum_newton_krylov.c.

763{
764 PetscFunctionBeginUser;
765 PetscCall(MatDestroy(&jacobian->jacobian_operator));
766 PetscFunctionReturn(PETSC_SUCCESS);
767}
Here is the caller graph for this function:

◆ MomentumPreconditionerEngine_Create()

static PetscErrorCode MomentumPreconditionerEngine_Create ( UserCtx *  user,
Mat  jacobian_operator,
const MomentumPreconditionerDescription *  requested,
MomentumPreconditionerEngine *  engine 
)
static

Validates a model/structure and creates or aliases its matrix.

Definition at line 772 of file momentum_newton_krylov.c.

775{
776 PetscFunctionBeginUser;
777 engine->description = *requested;
778 if (requested->model == MOM_NK_PC_MODEL_NONE &&
779 requested->structure == MOM_NK_PC_STRUCTURE_NONE) {
780 engine->description.block_size = 0;
781 engine->description.stencil_width = 0;
782 engine->preconditioning_matrix = jacobian_operator;
783 engine->aliases_jacobian_operator = PETSC_TRUE;
784 engine->owns_preconditioning_matrix = PETSC_FALSE;
785 engine->petsc_pc_type = PCNONE;
786 } else if (requested->model == MOM_NK_PC_MODEL_FROZEN_MOMENTUM_JACOBIAN &&
789 PetscCall(engine->model_ops->Describe(user, &engine->description));
791 user, &engine->preconditioning_matrix));
792 engine->owns_preconditioning_matrix = PETSC_TRUE;
793 PetscCall(PetscObjectSetName((PetscObject)engine->preconditioning_matrix,
794 "momentum_preconditioner_frozen_point_block"));
795 engine->aliases_jacobian_operator = PETSC_FALSE;
796 engine->petsc_pc_type = PCPBJACOBI;
797 } else {
798 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP,
799 "Unsupported Newton Krylov preconditioner model/structure combination.");
800 }
801 PetscFunctionReturn(PETSC_SUCCESS);
802}
static const MomentumPreconditionerModelOps frozen_momentum_point_block_ops
const MomentumPreconditionerModelOps * model_ops
static PetscErrorCode MomentumPreconditionerEngine_CreateExactPointBlockMatrix(UserCtx *user, Mat *preconditioning_matrix)
Creates the frozen point-block P matrix with its exact scalar pattern.
PetscErrorCode(* Describe)(UserCtx *, MomentumPreconditionerDescription *)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MomentumPreconditionerEngine_Assemble()

static PetscErrorCode MomentumPreconditionerEngine_Assemble ( MomentumPreconditionerEngine *  engine,
UserCtx *  user,
Vec  current_solution 
)
static

Runs model insertion, common row handling, and final assembly.

Definition at line 807 of file momentum_newton_krylov.c.

809{
810 PetscFunctionBeginUser;
811 if (engine->aliases_jacobian_operator) PetscFunctionReturn(PETSC_SUCCESS);
812 PetscCall(MatZeroEntries(engine->preconditioning_matrix));
813 PetscCall(engine->model_ops->AssembleInterior(user, current_solution,
814 engine->preconditioning_matrix));
816 user, engine->preconditioning_matrix));
817 PetscCall(MatAssemblyBegin(engine->preconditioning_matrix, MAT_FINAL_ASSEMBLY));
818 PetscCall(MatAssemblyEnd(engine->preconditioning_matrix, MAT_FINAL_ASSEMBLY));
819 PetscFunctionReturn(PETSC_SUCCESS);
820}
static PetscErrorCode MomentumPreconditionerEngine_ApplyConstraintRows(UserCtx *user, Mat preconditioning_matrix)
Inserts all common fixed, homogeneous, and periodic-duplicate rows.
PetscErrorCode(* AssembleInterior)(UserCtx *, Vec, Mat)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MomentumPreconditionerEngine_ConfigurePetscPC()

static PetscErrorCode MomentumPreconditionerEngine_ConfigurePetscPC ( MomentumPreconditionerEngine *  engine,
PC  pc 
)
static

Applies the validated model/structure-to-PETSc-PC mapping.

Definition at line 823 of file momentum_newton_krylov.c.

825{
826 PetscFunctionBeginUser;
827 PetscCall(PCSetType(pc, engine->petsc_pc_type));
828 PetscFunctionReturn(PETSC_SUCCESS);
829}
Here is the caller graph for this function:

◆ MomentumPreconditionerEngine_ValidatePetscPC()

static PetscErrorCode MomentumPreconditionerEngine_ValidatePetscPC ( MomentumPreconditionerEngine *  engine,
PC  pc 
)
static

Rejects raw options that select an unvalidated PETSc PC backend.

Definition at line 832 of file momentum_newton_krylov.c.

834{
835 const char *actual_type = NULL;
836 PetscBool matches = PETSC_FALSE;
837
838 PetscFunctionBeginUser;
839 PetscCall(PCGetType(pc, &actual_type));
840 PetscCall(PetscStrcmp(actual_type, engine->petsc_pc_type, &matches));
841 PetscCheck(matches, PETSC_COMM_WORLD, PETSC_ERR_SUP,
842 "Newton Krylov preconditioner model/structure requires internal PETSc PC "
843 "type '%s', but raw option processing selected '%s'.",
844 engine->petsc_pc_type, actual_type ? actual_type : "(unset)");
845 PetscFunctionReturn(PETSC_SUCCESS);
846}
Here is the caller graph for this function:

◆ MomentumPreconditionerEngine_Destroy()

static PetscErrorCode MomentumPreconditionerEngine_Destroy ( MomentumPreconditionerEngine *  engine)
static

Destroys only a separately owned preconditioning matrix.

Definition at line 849 of file momentum_newton_krylov.c.

851{
852 PetscFunctionBeginUser;
853 if (!engine->owns_preconditioning_matrix) engine->preconditioning_matrix = NULL;
854 PetscCall(MatDestroy(&engine->preconditioning_matrix));
855 engine->aliases_jacobian_operator = PETSC_FALSE;
856 engine->owns_preconditioning_matrix = PETSC_FALSE;
857 PetscFunctionReturn(PETSC_SUCCESS);
858}
Here is the caller graph for this function:

◆ MomentumSolver_NewtonKrylov()

PetscErrorCode MomentumSolver_NewtonKrylov ( UserCtx *  user,
IBMNodes *  ibm,
FSInfo *  fsi 
)

Solves one physical momentum step with matrix-free Newton–Krylov.

The Jacobian operator is the finite-difference, matrix-free operator of the complete deterministic residual. With no mathematical preconditioner its matrix is also passed to PETSc's preconditioning slot and PCNONE is derived. The optional provisional frozen-momentum, point-block model approximates same-cell frozen coupling, owns a separate matrix, and derives a block-Jacobi PETSc backend. It does not relax the version-one physics or boundary-condition restrictions. All PETSc solver objects are local to this call. Rows removed by legacy boundary residual enforcement are made explicit: conditioned normal rows use X-Uconditioned, untouched dummy/tangential rows use X, and periodic duplicates use Xdup-Xrepresentative. Unsupported masked, interface, and component-disabled rows are rejected before setup.

Parameters
userSingle-block momentum context.
ibmMust be NULL; immersed boundaries are not supported in version one.
fsiMust be NULL; moving-body coupling is not supported in version one.
Returns
0 on convergence, PETSC_ERR_CONV_FAILED after rollback on nonconvergence.

Definition at line 1195 of file momentum_newton_krylov.c.

1196{
1197 PetscErrorCode ierr = PETSC_SUCCESS, cleanup_ierr;
1198 SimCtx *simCtx;
1199 SNES snes = NULL;
1200 Vec solution = NULL, entry_backup = NULL;
1201 KSP ksp = NULL;
1202 PC pc = NULL;
1203 MomentumPreconditionerDescription preconditioner_description = {0};
1204 PetscBool restore_entry = PETSC_FALSE;
1205 PetscBool rhs_created = PETSC_FALSE;
1206 PetscBool solve_started = PETSC_FALSE;
1207 PetscBool committed = PETSC_FALSE;
1208 SNESConvergedReason reason = SNES_CONVERGED_ITERATING;
1209 PetscInt nonlinear_its = 0, function_evals = 0, linear_its = 0;
1210 PetscReal final_norm = PETSC_MAX_REAL;
1212 const FieldId staggered_fields[] = {FIELD_ID_UCONT};
1213
1214 PetscFunctionBeginUser;
1215 PetscCall(MomentumNewtonKrylov_Validate(user));
1216 PetscCheck(ibm == NULL && fsi == NULL, PETSC_COMM_WORLD, PETSC_ERR_SUP,
1217 "Newton Krylov version one does not accept IBM or FSI objects.");
1218 PetscCheck(user->Rhs == NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
1219 "Newton Krylov requires UserCtx::Rhs to be unallocated on entry.");
1220 simCtx = user->simCtx;
1221
1222 ierr = VecDuplicate(user->Ucont, &solution); if (ierr) goto cleanup;
1223 ierr = VecDuplicate(user->Ucont, &entry_backup); if (ierr) goto cleanup;
1224 ierr = VecDuplicate(user->Ucont, &user->Rhs); if (ierr) goto cleanup;
1225 rhs_created = PETSC_TRUE;
1226 ierr = SNESCreate(PetscObjectComm((PetscObject)user->Ucont), &snes); if (ierr) goto cleanup;
1227
1228 ierr = SynchronizePeriodicStaggeredFields(user, 1, staggered_fields); if (ierr) goto cleanup;
1229 ierr = ApplyBoundaryConditions(user); if (ierr) goto cleanup;
1230 ierr = VecCopy(user->Ucont, entry_backup); if (ierr) goto cleanup;
1231 restore_entry = PETSC_TRUE;
1232 ierr = VecCopy(user->Ucont, solution); if (ierr) goto cleanup;
1233
1234 ctx.user = user;
1235 ctx.snes = snes;
1237 &ctx.jacobian, &preconditioner_description); if (ierr) goto cleanup;
1238 ierr = SNESSetOptionsPrefix(snes, "mom_nk_"); if (ierr) goto cleanup;
1239 ierr = SNESSetType(snes, SNESNEWTONLS); if (ierr) goto cleanup;
1240 ierr = SNESSetDM(snes, user->fda); if (ierr) goto cleanup;
1241 ierr = SNESSetFunction(snes, NULL, MomentumNewtonKrylov_FormResidual, &ctx); if (ierr) goto cleanup;
1242 ierr = MomentumNewtonJacobian_Create(snes, &ctx.jacobian); if (ierr) goto cleanup;
1244 &preconditioner_description,
1245 &ctx.preconditioning_engine); if (ierr) goto cleanup;
1246 ierr = MomentumNewtonJacobian_Register(snes, &ctx.jacobian,
1247 &ctx.preconditioning_engine, &ctx); if (ierr) goto cleanup;
1248 ierr = SNESGetKSP(snes, &ksp); if (ierr) goto cleanup;
1249 ierr = KSPSetType(ksp, KSPGMRES); if (ierr) goto cleanup;
1250 ierr = KSPGetPC(ksp, &pc); if (ierr) goto cleanup;
1251 ierr = MomentumPreconditionerEngine_ConfigurePetscPC(&ctx.preconditioning_engine, pc); if (ierr) goto cleanup;
1252 ierr = SNESSetFromOptions(snes); if (ierr) goto cleanup;
1253 ierr = SNESMonitorSet(snes, MomentumNewtonKrylov_Monitor, &ctx, NULL); if (ierr) goto cleanup;
1254 ierr = KSPMonitorSet(ksp, MomentumNewtonKrylov_LinearMonitor, &ctx, NULL); if (ierr) goto cleanup;
1255 ierr = MomentumPreconditionerEngine_ValidatePetscPC(&ctx.preconditioning_engine, pc); if (ierr) goto cleanup;
1256
1258 "Newton Krylov Jacobian: finite_difference / matrix_free; "
1259 "Preconditioner: %s; PETSc Jacobian matrix type: MATMFFD; "
1260 "PETSc PC type: %s.\n",
1262 "none" : "frozen_momentum_jacobian / point_block",
1263 ctx.preconditioning_engine.petsc_pc_type);
1264
1266 solve_started = PETSC_TRUE;
1267 ierr = SNESSolve(snes, NULL, solution);
1268 if (ierr) goto cleanup;
1269 ierr = SNESGetConvergedReason(snes, &reason); if (ierr) goto cleanup;
1270 ierr = SNESGetIterationNumber(snes, &nonlinear_its); if (ierr) goto cleanup;
1271 ierr = SNESGetNumberFunctionEvals(snes, &function_evals); if (ierr) goto cleanup;
1272 ierr = SNESGetLinearSolveIterations(snes, &linear_its); if (ierr) goto cleanup;
1273 ierr = SNESGetFunctionNorm(snes, &final_norm); if (ierr) goto cleanup;
1274
1275 if (reason > 0) {
1276 ierr = VecCopy(solution, user->Ucont); if (ierr) goto cleanup;
1277 simCtx->mom_last_converged = PETSC_TRUE;
1278 } else {
1279 ierr = VecCopy(entry_backup, user->Ucont); if (ierr) goto cleanup;
1280 simCtx->mom_last_converged = PETSC_FALSE;
1281 }
1282 ierr = SynchronizePeriodicStaggeredFields(user, 1, staggered_fields); if (ierr) goto cleanup;
1283 ierr = ApplyBoundaryConditions(user); if (ierr) goto cleanup;
1284 restore_entry = PETSC_FALSE;
1285 committed = (PetscBool)(reason > 0);
1286
1288 "Newton Krylov momentum solve: reason=%s (%d), Newton iterations=%d, residual evaluations=%d, Krylov iterations=%d, final norm=%.6e, state=%s.\n",
1289 SNESConvergedReasons[reason], (PetscInt)reason, nonlinear_its, function_evals,
1290 linear_its, (double)final_norm, reason > 0 ? "committed" : "rolled back");
1291 if (reason <= 0) ierr = PETSC_ERR_CONV_FAILED;
1292
1293cleanup:
1294 /* A PETSc solve error can bypass the normal statistics path. Query whatever
1295 SNES retained without replacing the primary error so a failed attempt is
1296 still represented in the structured log. */
1297 if (solve_started && snes) {
1298 (void)SNESGetConvergedReason(snes, &reason);
1299 (void)SNESGetIterationNumber(snes, &nonlinear_its);
1300 (void)SNESGetNumberFunctionEvals(snes, &function_evals);
1301 (void)SNESGetLinearSolveIterations(snes, &linear_its);
1302 (void)SNESGetFunctionNorm(snes, &final_norm);
1303 }
1304 if (restore_entry && entry_backup) {
1305 cleanup_ierr = VecCopy(entry_backup, user->Ucont);
1306 if (!ierr) ierr = cleanup_ierr;
1307 cleanup_ierr = SynchronizePeriodicStaggeredFields(user, 1, staggered_fields);
1308 if (!ierr) ierr = cleanup_ierr;
1309 cleanup_ierr = ApplyBoundaryConditions(user);
1310 if (!ierr) ierr = cleanup_ierr;
1311 simCtx->mom_last_converged = PETSC_FALSE;
1312 committed = PETSC_FALSE;
1313 }
1314 if (ctx.history_file) {
1315 (void)fclose(ctx.history_file);
1316 ctx.history_file = NULL;
1317 }
1318 if (ctx.linear_history_file) {
1319 (void)fclose(ctx.linear_history_file);
1320 ctx.linear_history_file = NULL;
1321 }
1322 if (solve_started) {
1323 MomentumNewtonKrylov_WriteSummary(&ctx, reason, nonlinear_its, function_evals,
1324 linear_its, final_norm, committed);
1325 }
1326 if (rhs_created) {
1327 cleanup_ierr = VecDestroy(&user->Rhs);
1328 if (!ierr) ierr = cleanup_ierr;
1329 }
1330 cleanup_ierr = VecDestroy(&entry_backup); if (!ierr) ierr = cleanup_ierr;
1331 cleanup_ierr = VecDestroy(&solution); if (!ierr) ierr = cleanup_ierr;
1332 cleanup_ierr = MomentumPreconditionerEngine_Destroy(&ctx.preconditioning_engine); if (!ierr) ierr = cleanup_ierr;
1333 cleanup_ierr = MomentumNewtonJacobian_Destroy(&ctx.jacobian); if (!ierr) ierr = cleanup_ierr;
1334 cleanup_ierr = SNESDestroy(&snes); if (!ierr) ierr = cleanup_ierr;
1335 PetscFunctionReturn(ierr);
1336}
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
static PetscErrorCode MomentumNewtonJacobian_Register(SNES snes, MomentumNewtonJacobian *jacobian, MomentumPreconditionerEngine *engine, MomentumNewtonKrylovContext *ctx)
Registers the application orchestration callback and both SNES matrices.
static PetscErrorCode MomentumPreconditionerEngine_ConfigurePetscPC(MomentumPreconditionerEngine *engine, PC pc)
Applies the validated model/structure-to-PETSc-PC mapping.
static PetscErrorCode MomentumPreconditionerEngine_ValidatePetscPC(MomentumPreconditionerEngine *engine, PC pc)
Rejects raw options that select an unvalidated PETSc PC backend.
static PetscErrorCode MomentumPreconditionerEngine_Create(UserCtx *user, Mat jacobian_operator, const MomentumPreconditionerDescription *requested, MomentumPreconditionerEngine *engine)
Validates a model/structure and creates or aliases its matrix.
static void MomentumNewtonKrylov_WriteSummary(const MomentumNewtonKrylovContext *ctx, SNESConvergedReason reason, PetscInt nonlinear_its, PetscInt function_evals, PetscInt linear_its, PetscReal final_norm, PetscBool committed)
Appends one rank-zero structured Newton result for a physical step.
static PetscErrorCode MomentumNewtonKrylov_ReadLinearizationConfig(MomentumNewtonJacobian *jacobian, MomentumPreconditionerDescription *description)
Reads application-owned Jacobian and preconditioner mathematics.
static PetscErrorCode MomentumNewtonJacobian_Destroy(MomentumNewtonJacobian *jacobian)
Destroys a partially or fully created Jacobian operator.
static void MomentumNewtonKrylov_OpenHistory(MomentumNewtonKrylovContext *ctx)
Opens the optional rank-zero Newton iteration-history file.
static PetscErrorCode MomentumNewtonKrylov_LinearMonitor(KSP ksp, PetscInt iteration, PetscReal norm, void *ctx)
Writes the effective KSP tolerance and PETSc-reported norm for each inner iteration.
static PetscErrorCode MomentumNewtonJacobian_Create(SNES snes, MomentumNewtonJacobian *jacobian)
Creates the selected Jacobian operator; currently PETSc MFFD only.
static PetscErrorCode MomentumNewtonKrylov_Validate(UserCtx *user)
Rejects configurations outside the audited version-one feature set.
static PetscErrorCode MomentumPreconditionerEngine_Destroy(MomentumPreconditionerEngine *engine)
Destroys only a separately owned preconditioning matrix.
static PetscErrorCode MomentumNewtonKrylov_FormResidual(SNES snes, Vec X, Vec F, void *ctx)
Adapts a PETSc trial vector to the existing momentum residual path.
static PetscErrorCode MomentumNewtonKrylov_Monitor(SNES snes, PetscInt iteration, PetscReal norm, void *ctx)
Captures SNES iteration norms and optionally writes PICurv history rows.
PetscBool mom_last_converged
Definition variables.h:916
Here is the call graph for this function:

Variable Documentation

◆ frozen_momentum_point_block_ops

const MomentumPreconditionerModelOps frozen_momentum_point_block_ops
static
Initial value:
= {
}
static PetscErrorCode FrozenMomentumJacobian_DescribePointBlock(UserCtx *user, MomentumPreconditionerDescription *description)
Describes the audited frozen-coefficient point-block model.
static PetscErrorCode FrozenMomentumJacobian_AssemblePointBlocks(UserCtx *user, Vec current_solution, Mat preconditioning_matrix)
Inserts only the audited interior frozen-momentum point blocks.

Definition at line 716 of file momentum_newton_krylov.c.