PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Data Structures | Macros | Functions
BC_Handlers.c File Reference
#include "BC_Handlers.h"
Include dependency graph for BC_Handlers.c:

Go to the source code of this file.

Data Structures

struct  InletConstantData
 Private data structure for the Constant Velocity Inlet handler. More...
 
struct  InletParabolicData
 Private data structure for the Parabolic Velocity Inlet handler. More...
 
struct  DrivenConstantData
 Private data structure for the handler. More...
 

Macros

#define __FUNCT__   "Validate_DrivenFlowConfiguration"
 
#define __FUNCT__   "Create_WallNoSlip"
 
#define __FUNCT__   "Apply_WallNoSlip"
 
#define __FUNCT__   "Create_InletConstantVelocity"
 
#define __FUNCT__   "Initialize_InletConstantVelocity"
 
#define __FUNCT__   "PreStep_InletConstantVelocity"
 
#define __FUNCT__   "Apply_InletConstantVelocity"
 
#define __FUNCT__   "PostStep_InletConstantVelocity"
 
#define __FUNCT__   "Destroy_InletConstantVelocity"
 
#define __FUNCT__   "Create_InletParabolicProfile"
 
#define __FUNCT__   "Initialize_InletParabolicProfile"
 
#define __FUNCT__   "PreStep_InletParabolicProfile"
 
#define __FUNCT__   "Apply_InletParabolicProfile"
 
#define __FUNCT__   "PostStep_InletParabolicProfile"
 
#define __FUNCT__   "Destroy_InletParabolicProfile"
 
#define __FUNCT__   "Create_OutletConservation"
 
#define __FUNCT__   "PreStep_OutletConservation"
 
#define __FUNCT__   "Apply_OutletConservation"
 
#define __FUNCT__   "PostStep_OutletConservation"
 
#define __FUNCT__   "Create_PeriodicDrivenConstant"
 
#define __FUNCT__   "Initialize_PeriodicDrivenConstant"
 
#define __FUNCT__   "PreStep_PeriodicDrivenConstant"
 
#define __FUNCT__   "Apply_PeriodicDrivenConstant"
 
#define __FUNCT__   "Destroy_PeriodicDrivenConstant"
 

Functions

PetscErrorCode Validate_DrivenFlowConfiguration (UserCtx *user)
 Internal helper implementation: Validate_DrivenFlowConfiguration().
 
static PetscErrorCode Apply_WallNoSlip (BoundaryCondition *self, BCContext *ctx)
 Internal helper implementation: Apply_WallNoSlip().
 
PetscErrorCode Create_WallNoSlip (BoundaryCondition *bc)
 Implementation of Create_WallNoSlip().
 
static PetscErrorCode Initialize_InletConstantVelocity (BoundaryCondition *self, BCContext *ctx)
 Internal helper implementation: Initialize_InletConstantVelocity().
 
static PetscErrorCode PreStep_InletConstantVelocity (BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
 Internal helper implementation: PreStep_InletConstantVelocity().
 
static PetscErrorCode Apply_InletConstantVelocity (BoundaryCondition *self, BCContext *ctx)
 Internal helper implementation: Apply_InletConstantVelocity().
 
static PetscErrorCode PostStep_InletConstantVelocity (BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
 Internal helper implementation: PostStep_InletConstantVelocity().
 
static PetscErrorCode Destroy_InletConstantVelocity (BoundaryCondition *self)
 Internal helper implementation: Destroy_InletConstantVelocity().
 
PetscErrorCode Create_InletConstantVelocity (BoundaryCondition *bc)
 Implementation of Create_InletConstantVelocity().
 
static PetscErrorCode Initialize_InletParabolicProfile (BoundaryCondition *self, BCContext *ctx)
 Internal helper implementation: Initialize_InletParabolicProfile().
 
static PetscErrorCode PreStep_InletParabolicProfile (BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
 Internal helper implementation: PreStep_InletParabolicProfile().
 
static PetscErrorCode Apply_InletParabolicProfile (BoundaryCondition *self, BCContext *ctx)
 Internal helper implementation: Apply_InletParabolicProfile().
 
static PetscErrorCode PostStep_InletParabolicProfile (BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
 Internal helper implementation: PostStep_InletParabolicProfile().
 
static PetscErrorCode Destroy_InletParabolicProfile (BoundaryCondition *self)
 Internal helper implementation: Destroy_InletParabolicProfile().
 
PetscErrorCode Create_InletParabolicProfile (BoundaryCondition *bc)
 Implementation of Create_InletParabolicProfile().
 
static PetscErrorCode PreStep_OutletConservation (BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
 Internal helper implementation: PreStep_OutletConservation().
 
static PetscErrorCode Apply_OutletConservation (BoundaryCondition *self, BCContext *ctx)
 (Handler Action) Applies mass conservation correction to the outlet face.
 
static PetscErrorCode PostStep_OutletConservation (BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
 Internal helper implementation: PostStep_OutletConservation().
 
PetscErrorCode Create_OutletConservation (BoundaryCondition *bc)
 Implementation of Create_OutletConservation().
 
PetscErrorCode Create_PeriodicGeometric (BoundaryCondition *bc)
 Implementation of Create_PeriodicGeometric().
 
static PetscErrorCode Initialize_PeriodicDrivenConstant (BoundaryCondition *self, BCContext *ctx)
 Internal helper implementation: Initialize_PeriodicDrivenConstant().
 
static PetscErrorCode PreStep_PeriodicDrivenConstant (BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
 Internal helper implementation: PreStep_PeriodicDrivenConstant().
 
static PetscErrorCode Apply_PeriodicDrivenConstant (BoundaryCondition *self, BCContext *ctx)
 Internal helper implementation: Apply_PeriodicDrivenConstant().
 
static PetscErrorCode Destroy_PeriodicDrivenConstant (BoundaryCondition *self)
 Internal helper implementation: Destroy_PeriodicDrivenConstant().
 
PetscErrorCode Create_PeriodicDrivenConstant (BoundaryCondition *bc)
 Internal helper implementation: Create_PeriodicDrivenConstant().
 

Data Structure Documentation

◆ InletConstantData

struct InletConstantData

Private data structure for the Constant Velocity Inlet handler.

Definition at line 311 of file BC_Handlers.c.

Data Fields
PetscReal normal_velocity

◆ InletParabolicData

struct InletParabolicData

Private data structure for the Parabolic Velocity Inlet handler.

Stores the peak velocity and pre-computed cross-stream geometry needed to evaluate the parabolic profile at each boundary node.

Definition at line 705 of file BC_Handlers.c.

Data Fields
PetscReal v_max Peak centerline velocity (from user params).
PetscReal cs1_center Center index in cross-stream direction 1.
PetscReal cs2_center Center index in cross-stream direction 2.
PetscReal cs1_half Half-width (in index space) in cross-stream direction 1.
PetscReal cs2_half Half-width (in index space) in cross-stream direction 2.

◆ DrivenConstantData

struct DrivenConstantData

Private data structure for the handler.

Definition at line 1682 of file BC_Handlers.c.

Data Fields
char direction
PetscReal targetVolumetricFlux
PetscReal boundaryVelocityCorrection
PetscBool isMasterController
PetscBool applyBoundaryTrim

Macro Definition Documentation

◆ __FUNCT__ [1/24]

#define __FUNCT__   "Validate_DrivenFlowConfiguration"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [2/24]

#define __FUNCT__   "Create_WallNoSlip"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [3/24]

#define __FUNCT__   "Apply_WallNoSlip"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [4/24]

#define __FUNCT__   "Create_InletConstantVelocity"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [5/24]

#define __FUNCT__   "Initialize_InletConstantVelocity"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [6/24]

#define __FUNCT__   "PreStep_InletConstantVelocity"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [7/24]

#define __FUNCT__   "Apply_InletConstantVelocity"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [8/24]

#define __FUNCT__   "PostStep_InletConstantVelocity"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [9/24]

#define __FUNCT__   "Destroy_InletConstantVelocity"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [10/24]

#define __FUNCT__   "Create_InletParabolicProfile"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [11/24]

#define __FUNCT__   "Initialize_InletParabolicProfile"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [12/24]

#define __FUNCT__   "PreStep_InletParabolicProfile"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [13/24]

#define __FUNCT__   "Apply_InletParabolicProfile"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [14/24]

#define __FUNCT__   "PostStep_InletParabolicProfile"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [15/24]

#define __FUNCT__   "Destroy_InletParabolicProfile"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [16/24]

#define __FUNCT__   "Create_OutletConservation"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [17/24]

#define __FUNCT__   "PreStep_OutletConservation"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [18/24]

#define __FUNCT__   "Apply_OutletConservation"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [19/24]

#define __FUNCT__   "PostStep_OutletConservation"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [20/24]

#define __FUNCT__   "Create_PeriodicDrivenConstant"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [21/24]

#define __FUNCT__   "Initialize_PeriodicDrivenConstant"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [22/24]

#define __FUNCT__   "PreStep_PeriodicDrivenConstant"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [23/24]

#define __FUNCT__   "Apply_PeriodicDrivenConstant"

Definition at line 10 of file BC_Handlers.c.

◆ __FUNCT__ [24/24]

#define __FUNCT__   "Destroy_PeriodicDrivenConstant"

Definition at line 10 of file BC_Handlers.c.

Function Documentation

◆ Validate_DrivenFlowConfiguration()

PetscErrorCode Validate_DrivenFlowConfiguration ( UserCtx user)

Internal helper implementation: Validate_DrivenFlowConfiguration().

(Private) Validates all consistency rules for a driven flow (channel/pipe) setup.

Local to this translation unit.

Definition at line 15 of file BC_Handlers.c.

16{
17 PetscFunctionBeginUser;
18
19 // --- CHECK 1: Detect if a driven flow is active. ---
20 PetscBool is_driven_flow_active = PETSC_FALSE;
21 char driven_direction = ' ';
22 const char* first_driven_face_name = "";
23
24 for (int i = 0; i < 6; i++) {
25 BCHandlerType handler_type = user->boundary_faces[i].handler_type;
26 if (handler_type == BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX ||
28 {
29 is_driven_flow_active = PETSC_TRUE;
30 first_driven_face_name = BCFaceToString((BCFace)i);
31
32 if (i <= 1) driven_direction = 'X';
33 else if (i <= 3) driven_direction = 'Y';
34 else driven_direction = 'Z';
35
36 break; // Exit loop once we've confirmed it's active and found the direction.
37 }
38 }
39
40 // If no driven flow handler is found, validation for this rule set is complete.
41 if (!is_driven_flow_active) {
42 PetscFunctionReturn(0);
43 }
44
45 LOG_ALLOW(GLOBAL, LOG_DEBUG, " - Driven Flow Handler detected on face %s. Applying driven flow validation rules...\n", first_driven_face_name);
46
47 // --- CHECK 2: Ensure no conflicting BCs (Inlet/Outlet/Far-field) are present. ---
48 LOG_ALLOW(GLOBAL, LOG_DEBUG, " - Checking for incompatible Inlet/Outlet/Far-field BCs...\n");
49 for (int i = 0; i < 6; i++) {
50 BCType math_type = user->boundary_faces[i].mathematical_type;
51 if (math_type == INLET || math_type == OUTLET || math_type == FARFIELD) {
52 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
53 "Configuration Error: A DRIVEN flow handler is active, which is incompatible with the %s boundary condition found on face %s.",
54 BCTypeToString(math_type), BCFaceToString((BCFace)i));
55 }
56 }
57 LOG_ALLOW(GLOBAL, LOG_DEBUG, " ... No conflicting BC types found. OK.\n");
58
59 // --- CHECK 3: Ensure both ends of the driven direction have identical, valid setups. ---
60 LOG_ALLOW(GLOBAL, LOG_DEBUG, " - Validating symmetry and mathematical types for the '%c' direction...\n", driven_direction);
61
62 PetscInt neg_face_idx = 0, pos_face_idx = 0;
63 if (driven_direction == 'X') {
64 neg_face_idx = BC_FACE_NEG_X; pos_face_idx = BC_FACE_POS_X;
65 } else if (driven_direction == 'Y') {
66 neg_face_idx = BC_FACE_NEG_Y; pos_face_idx = BC_FACE_POS_Y;
67 } else { // 'Z'
68 neg_face_idx = BC_FACE_NEG_Z; pos_face_idx = BC_FACE_POS_Z;
69 }
70
71 BoundaryFaceConfig *neg_face_cfg = &user->boundary_faces[neg_face_idx];
72 BoundaryFaceConfig *pos_face_cfg = &user->boundary_faces[pos_face_idx];
73
74 // Rule 3a: Both faces must be PERIODIC.
75 if (neg_face_cfg->mathematical_type != PERIODIC || pos_face_cfg->mathematical_type != PERIODIC) {
76 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
77 "Configuration Error: For a driven flow in the '%c' direction, both the %s and %s faces must be of mathematical_type PERIODIC.",
78 driven_direction, BCFaceToString((BCFace)neg_face_idx), BCFaceToString((BCFace)pos_face_idx));
79 }
80
81 // Rule 3b: Both faces must use the exact same handler type.
82 if (neg_face_cfg->handler_type != pos_face_cfg->handler_type) {
83 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
84 "Configuration Error: The DRIVEN handlers on the %s and %s faces of the '%c' direction do not match. Both must be the same type (e.g., both CONSTANT_FLUX).",
85 BCFaceToString((BCFace)neg_face_idx), BCFaceToString((BCFace)pos_face_idx), driven_direction);
86 }
87
88 LOG_ALLOW(GLOBAL, LOG_DEBUG, " ... Symmetry and mathematical types are valid. OK.\n");
89
90 PetscFunctionReturn(0);
91}
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45
const char * BCFaceToString(BCFace face)
Helper function to convert BCFace enum to a string representation.
Definition logging.c:669
#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:199
const char * BCTypeToString(BCType type)
Helper function to convert BCType enum to a string representation.
Definition logging.c:751
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:31
BCType
Defines the general mathematical/physical Category of a boundary.
Definition variables.h:251
@ INLET
Definition variables.h:258
@ FARFIELD
Definition variables.h:259
@ OUTLET
Definition variables.h:257
@ PERIODIC
Definition variables.h:260
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:829
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:271
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:287
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:286
BCHandlerType handler_type
Definition variables.h:337
BCType mathematical_type
Definition variables.h:336
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:244
@ BC_FACE_NEG_X
Definition variables.h:245
@ BC_FACE_POS_Z
Definition variables.h:247
@ BC_FACE_POS_Y
Definition variables.h:246
@ BC_FACE_NEG_Z
Definition variables.h:247
@ BC_FACE_POS_X
Definition variables.h:245
@ BC_FACE_NEG_Y
Definition variables.h:246
Holds the complete configuration for one of the six boundary faces.
Definition variables.h:334
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Apply_WallNoSlip()

static PetscErrorCode Apply_WallNoSlip ( BoundaryCondition self,
BCContext ctx 
)
static

Internal helper implementation: Apply_WallNoSlip().

Local to this translation unit.

Definition at line 144 of file BC_Handlers.c.

145{
146 PetscErrorCode ierr;
147 UserCtx* user = ctx->user;
148 BCFace face_id = ctx->face_id;
149 PetscBool can_service;
150
151 (void)self; // Unused for simple handlers
152
153 PetscFunctionBeginUser;
154 DMDALocalInfo *info = &user->info;
155 Cmpnts ***ubcs, ***ucont;
156 PetscInt IM_nodes_global, JM_nodes_global,KM_nodes_global;
157
158 IM_nodes_global = user->IM;
159 JM_nodes_global = user->JM;
160 KM_nodes_global = user->KM;
161
162 ierr = CanRankServiceFace(info,IM_nodes_global,JM_nodes_global,KM_nodes_global,face_id,&can_service); CHKERRQ(ierr);
163 // Check if this rank owns part of this boundary face
164 if (!can_service) PetscFunctionReturn(0);
165
166 LOG_ALLOW(LOCAL, LOG_DEBUG, "Apply_WallNoSlip: Applying to Face %d (%s).\n",
167 face_id, BCFaceToString(face_id));
168
169 // Get arrays
170
171 ierr = DMDAVecGetArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
172 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
173
174 PetscInt xs = info->xs, xe = info->xs + info->xm;
175 PetscInt ys = info->ys, ye = info->ys + info->ym;
176 PetscInt zs = info->zs, ze = info->zs + info->zm;
177 PetscInt mx = info->mx, my = info->my, mz = info->mz;
178
179 // ✅ Use shrunken loop bounds (avoids edges/corners like inlet handler)
180 PetscInt lxs = xs, lxe = xe, lys = ys, lye = ye, lzs = zs, lze = ze;
181 if (xs == 0) lxs = xs + 1;
182 if (xe == mx) lxe = xe - 1;
183 if (ys == 0) lys = ys + 1;
184 if (ye == my) lye = ye - 1;
185 if (zs == 0) lzs = zs + 1;
186 if (ze == mz) lze = ze - 1;
187
188 switch (face_id) {
189 case BC_FACE_NEG_X: {
190 if (xs == 0){
191 PetscInt i = xs;
192 for (PetscInt k = lzs; k < lze; k++) {
193 for (PetscInt j = lys; j < lye; j++) {
194 // ✅ Set contravariant flux to zero (no penetration)
195 ucont[k][j][i].x = 0.0;
196
197 // ✅ Set boundary velocity to zero (no slip)
198 ubcs[k][j][i].x = 0.0;
199 ubcs[k][j][i].y = 0.0;
200 ubcs[k][j][i].z = 0.0;
201 }
202 }
203 }
204 break;
205 }
206
207 case BC_FACE_POS_X: {
208 if (xe == mx){
209 PetscInt i = xe - 1;
210 for (PetscInt k = lzs; k < lze; k++) {
211 for (PetscInt j = lys; j < lye; j++) {
212 ucont[k][j][i-1].x = 0.0;
213
214 ubcs[k][j][i].x = 0.0;
215 ubcs[k][j][i].y = 0.0;
216 ubcs[k][j][i].z = 0.0;
217 }
218 }
219 }
220 break;
221 }
222 case BC_FACE_NEG_Y: {
223 if (ys == 0){
224 PetscInt j = ys;
225 for (PetscInt k = lzs; k < lze; k++) {
226 for (PetscInt i = lxs; i < lxe; i++) {
227 ucont[k][j][i].y = 0.0;
228
229 ubcs[k][j][i].x = 0.0;
230 ubcs[k][j][i].y = 0.0;
231 ubcs[k][j][i].z = 0.0;
232 }
233 }
234 }
235 } break;
236
237 case BC_FACE_POS_Y: {
238 if (ye == my){
239 PetscInt j = ye - 1;
240 for (PetscInt k = lzs; k < lze; k++) {
241 for (PetscInt i = lxs; i < lxe; i++) {
242 ucont[k][j-1][i].y = 0.0;
243
244 ubcs[k][j][i].x = 0.0;
245 ubcs[k][j][i].y = 0.0;
246 ubcs[k][j][i].z = 0.0;
247 }
248 }
249 }
250 } break;
251
252 case BC_FACE_NEG_Z: {
253 if (zs == 0){
254 PetscInt k = zs;
255 for (PetscInt j = lys; j < lye; j++) {
256 for (PetscInt i = lxs; i < lxe; i++) {
257 ucont[k][j][i].z = 0.0;
258
259 ubcs[k][j][i].x = 0.0;
260 ubcs[k][j][i].y = 0.0;
261 ubcs[k][j][i].z = 0.0;
262 }
263 }
264 }
265 } break;
266
267 case BC_FACE_POS_Z: {
268 if (ze == mz) {
269 PetscInt k = ze - 1;
270 for (PetscInt j = lys; j < lye; j++) {
271 for (PetscInt i = lxs; i < lxe; i++) {
272 ucont[k-1][j][i].z = 0.0;
273
274 ubcs[k][j][i].x = 0.0;
275 ubcs[k][j][i].y = 0.0;
276 ubcs[k][j][i].z = 0.0;
277 }
278 }
279 }
280 } break;
281 }
282
283 // Restore arrays
284 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
285 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
286
287 PetscFunctionReturn(0);
288}
PetscErrorCode CanRankServiceFace(const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, BCFace face_id, PetscBool *can_service_out)
Determines if the current MPI rank owns any part of a specified global face.
Definition Boundaries.c:126
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
PetscInt KM
Definition variables.h:820
BCFace face_id
Definition variables.h:313
Vec Ucont
Definition variables.h:837
Vec Ubcs
Physical Cartesian velocity at boundary faces. Full 3D array but only boundary-face entries are meani...
Definition variables.h:121
PetscScalar x
Definition variables.h:101
BCS Bcs
Definition variables.h:832
UserCtx * user
Definition variables.h:312
PetscScalar z
Definition variables.h:101
PetscInt JM
Definition variables.h:820
DMDALocalInfo info
Definition variables.h:818
PetscScalar y
Definition variables.h:101
PetscInt IM
Definition variables.h:820
A 3D point or vector with PetscScalar components.
Definition variables.h:100
User-defined context containing data specific to a single computational grid level.
Definition variables.h:811
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Create_WallNoSlip()

PetscErrorCode Create_WallNoSlip ( BoundaryCondition bc)

Implementation of Create_WallNoSlip().

Configures a BoundaryCondition object to behave as a no-slip, stationary wall.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/BC_Handlers.h.

See also
Create_WallNoSlip()

Definition at line 114 of file BC_Handlers.c.

115{
116 PetscFunctionBeginUser;
117
118 if (!bc) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
119 "Input BoundaryCondition object is NULL in Create_WallNoSlip");
120
121 // ✅ Set priority
123
124 // Assign function pointers
125 bc->Initialize = NULL;
126 bc->PreStep = NULL;
128 bc->PostStep = NULL;
129 bc->UpdateUbcs = NULL;
130 bc->Destroy = NULL;
131
132 // No private data needed for this simple handler
133 bc->data = NULL;
134
135 PetscFunctionReturn(0);
136}
static PetscErrorCode Apply_WallNoSlip(BoundaryCondition *self, BCContext *ctx)
Internal helper implementation: Apply_WallNoSlip().
PetscErrorCode(* PostStep)(BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow, PetscReal *local_outflow)
Definition variables.h:328
PetscErrorCode(* PreStep)(BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow, PetscReal *local_outflow)
Definition variables.h:326
PetscErrorCode(* Destroy)(BoundaryCondition *self)
Definition variables.h:330
PetscErrorCode(* Initialize)(BoundaryCondition *self, BCContext *ctx)
Definition variables.h:325
PetscErrorCode(* UpdateUbcs)(BoundaryCondition *self, BCContext *ctx)
Definition variables.h:329
PetscErrorCode(* Apply)(BoundaryCondition *self, BCContext *ctx)
Definition variables.h:327
BCPriorityType priority
Definition variables.h:323
@ BC_PRIORITY_WALL
Definition variables.h:295
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Initialize_InletConstantVelocity()

static PetscErrorCode Initialize_InletConstantVelocity ( BoundaryCondition self,
BCContext ctx 
)
static

Internal helper implementation: Initialize_InletConstantVelocity().

Local to this translation unit.

Definition at line 352 of file BC_Handlers.c.

353{
354 PetscErrorCode ierr;
355 UserCtx* user = ctx->user;
356 BCFace face_id = ctx->face_id;
358 PetscBool found;
359
360 PetscFunctionBeginUser;
361 LOG_ALLOW(LOCAL, LOG_DEBUG, "Initialize_InletConstantVelocity: Initializing handler for Face %d. \n", face_id);
362 data->normal_velocity = 0.0;
363
364 switch (face_id) {
365 case BC_FACE_NEG_X:
366 case BC_FACE_POS_X:
367 // For X-faces, read "vx" as normal velocity
368 ierr = GetBCParamReal(user->boundary_faces[face_id].params, "vx",
369 &data->normal_velocity, &found); CHKERRQ(ierr);
370 break;
371
372 case BC_FACE_NEG_Y:
373 case BC_FACE_POS_Y:
374 // For Y-faces, read "vy" as normal velocity
375 ierr = GetBCParamReal(user->boundary_faces[face_id].params, "vy",
376 &data->normal_velocity, &found); CHKERRQ(ierr);
377 break;
378
379 case BC_FACE_NEG_Z:
380 case BC_FACE_POS_Z:
381 // For Z-faces, read "vz" as normal velocity
382 ierr = GetBCParamReal(user->boundary_faces[face_id].params, "vz",
383 &data->normal_velocity, &found); CHKERRQ(ierr);
384 break;
385 }
386
387 LOG_ALLOW(LOCAL, LOG_INFO, " Inlet Face %d: normal velocity = %.4f\n",
388 face_id, data->normal_velocity);
389
390 // Set initial boundary state
391 ierr = Apply_InletConstantVelocity(self, ctx); CHKERRQ(ierr);
392
393 PetscFunctionReturn(0);
394}
static PetscErrorCode Apply_InletConstantVelocity(BoundaryCondition *self, BCContext *ctx)
Internal helper implementation: Apply_InletConstantVelocity().
Private data structure for the Constant Velocity Inlet handler.
PetscErrorCode GetBCParamReal(BC_Param *params, const char *key, PetscReal *value_out, PetscBool *found)
Searches a BC_Param linked list for a key and returns its value as a double.
Definition io.c:387
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PreStep_InletConstantVelocity()

static PetscErrorCode PreStep_InletConstantVelocity ( BoundaryCondition self,
BCContext ctx,
PetscReal *  local_inflow_contribution,
PetscReal *  local_outflow_contribution 
)
static

Internal helper implementation: PreStep_InletConstantVelocity().

Local to this translation unit.

Definition at line 402 of file BC_Handlers.c.

405{
406 // No preparation needed for constant velocity inlet.
407 // The velocity is already stored in self->data from Initialize.
408 // Apply will set ucont, and PostStep will measure the actual flux.
409
410 (void)self;
411 (void)ctx;
412 (void)local_inflow_contribution;
413 (void)local_outflow_contribution;
414
415 PetscFunctionBeginUser;
416 PetscFunctionReturn(0);
417}
Here is the caller graph for this function:

◆ Apply_InletConstantVelocity()

static PetscErrorCode Apply_InletConstantVelocity ( BoundaryCondition self,
BCContext ctx 
)
static

Internal helper implementation: Apply_InletConstantVelocity().

Local to this translation unit.

Definition at line 425 of file BC_Handlers.c.

426{
427 PetscErrorCode ierr;
428 UserCtx* user = ctx->user;
429 BCFace face_id = ctx->face_id;
431 PetscBool can_service;
432
433 PetscFunctionBeginUser;
434
435 DMDALocalInfo *info = &user->info;
436 Cmpnts ***ubcs, ***ucont, ***csi, ***eta, ***zet;
437 PetscReal ***nvert;
438 PetscInt IM_nodes_global, JM_nodes_global,KM_nodes_global;
439
440 IM_nodes_global = user->IM;
441 JM_nodes_global = user->JM;
442 KM_nodes_global = user->KM;
443
444 ierr = CanRankServiceFace(info,IM_nodes_global,JM_nodes_global,KM_nodes_global,face_id,&can_service); CHKERRQ(ierr);
445
446 if (!can_service) PetscFunctionReturn(0);
447
448 // Get arrays
449
450 ierr = DMDAVecGetArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
451 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
452 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
453 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
454 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
455 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
456
457 // Get SCALAR velocity (not vector!)
458 PetscReal uin_this_point = data->normal_velocity;
459
460 PetscInt xs = info->xs, xe = info->xs + info->xm;
461 PetscInt ys = info->ys, ye = info->ys + info->ym;
462 PetscInt zs = info->zs, ze = info->zs + info->zm;
463 PetscInt mx = info->mx, my = info->my, mz = info->mz;
464
465 PetscInt lxs = xs, lxe = xe, lys = ys, lye = ye, lzs = zs, lze = ze;
466 if (xs == 0) lxs = xs + 1;
467 if (xe == mx) lxe = xe - 1;
468 if (ys == 0) lys = ys + 1;
469 if (ye == my) lye = ye - 1;
470 if (zs == 0) lzs = zs + 1;
471 if (ze == mz) lze = ze - 1;
472
473 switch (face_id) {
474 case BC_FACE_NEG_X:
475 case BC_FACE_POS_X: {
476 PetscReal sign = (face_id == BC_FACE_NEG_X) ? 1.0 : -1.0;
477 PetscInt i = (face_id == BC_FACE_NEG_X) ? xs : mx - 2;
478
479 for (PetscInt k = lzs; k < lze; k++) {
480 for (PetscInt j = lys; j < lye; j++) {
481 if ((sign > 0 && nvert[k][j][i+1] > 0.1) ||
482 (sign < 0 && nvert[k][j][i] > 0.1)) continue;
483
484 PetscReal CellArea = sqrt(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
488 ucont[k][j][i].x = sign * uin_this_point * CellArea;
489
490 ubcs[k][j][i + (sign < 0)].x = sign * uin_this_point * csi[k][j][i].x / CellArea;
491 ubcs[k][j][i + (sign < 0)].y = sign * uin_this_point * csi[k][j][i].y / CellArea;
492 ubcs[k][j][i + (sign < 0)].z = sign * uin_this_point * csi[k][j][i].z / CellArea;
493 }
494 }
495 } break;
496
497 case BC_FACE_NEG_Y:
498 case BC_FACE_POS_Y: {
499 PetscReal sign = (face_id == BC_FACE_NEG_Y) ? 1.0 : -1.0;
500 PetscInt j = (face_id == BC_FACE_NEG_Y) ? ys : my - 2;
501
502 for (PetscInt k = lzs; k < lze; k++) {
503 for (PetscInt i = lxs; i < lxe; i++) {
504 if ((sign > 0 && nvert[k][j+1][i] > 0.1) ||
505 (sign < 0 && nvert[k][j][i] > 0.1)) continue;
506
507 PetscReal CellArea = sqrt(eta[k][j][i].x * eta[k][j][i].x +
508 eta[k][j][i].y * eta[k][j][i].y +
509 eta[k][j][i].z * eta[k][j][i].z);
510
511 ucont[k][j][i].y = sign * uin_this_point * CellArea;
512
513 ubcs[k][j + (sign < 0)][i].x = sign * uin_this_point * eta[k][j][i].x / CellArea;
514 ubcs[k][j + (sign < 0)][i].y = sign * uin_this_point * eta[k][j][i].y / CellArea;
515 ubcs[k][j + (sign < 0)][i].z = sign * uin_this_point * eta[k][j][i].z / CellArea;
516 }
517 }
518 } break;
519
520 case BC_FACE_NEG_Z:
521 case BC_FACE_POS_Z: {
522 PetscReal sign = (face_id == BC_FACE_NEG_Z) ? 1.0 : -1.0;
523 PetscInt k = (face_id == BC_FACE_NEG_Z) ? zs : mz - 2;
524
525 for (PetscInt j = lys; j < lye; j++) {
526 for (PetscInt i = lxs; i < lxe; i++) {
527 if ((sign > 0 && nvert[k+1][j][i] > 0.1) ||
528 (sign < 0 && nvert[k][j][i] > 0.1)) continue;
529
530 PetscReal CellArea = sqrt(zet[k][j][i].x * zet[k][j][i].x +
531 zet[k][j][i].y * zet[k][j][i].y +
532 zet[k][j][i].z * zet[k][j][i].z);
533
534 ucont[k][j][i].z = sign * uin_this_point * CellArea;
535
536 ubcs[k + (sign < 0)][j][i].x = sign * uin_this_point * zet[k][j][i].x / CellArea;
537 ubcs[k + (sign < 0)][j][i].y = sign * uin_this_point * zet[k][j][i].y / CellArea;
538 ubcs[k + (sign < 0)][j][i].z = sign * uin_this_point * zet[k][j][i].z / CellArea;
539 }
540 }
541 } break;
542 }
543
544 // Restore arrays
545 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
546 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
547 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
548 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
549 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
550 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
551
552 PetscFunctionReturn(0);
553}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PostStep_InletConstantVelocity()

static PetscErrorCode PostStep_InletConstantVelocity ( BoundaryCondition self,
BCContext ctx,
PetscReal *  local_inflow_contribution,
PetscReal *  local_outflow_contribution 
)
static

Internal helper implementation: PostStep_InletConstantVelocity().

Local to this translation unit.

Definition at line 561 of file BC_Handlers.c.

564{
565 PetscErrorCode ierr;
566 UserCtx* user = ctx->user;
567 BCFace face_id = ctx->face_id;
568 PetscBool can_service;
569
570 (void)self;
571 (void)local_outflow_contribution;
572
573 PetscFunctionBeginUser;
574
575 DMDALocalInfo *info = &user->info;
576 Cmpnts ***ucont;
577
578 PetscInt IM_nodes_global, JM_nodes_global,KM_nodes_global;
579
580 IM_nodes_global = user->IM;
581 JM_nodes_global = user->JM;
582 KM_nodes_global = user->KM;
583
584 ierr = CanRankServiceFace(info,IM_nodes_global,JM_nodes_global,KM_nodes_global,face_id,&can_service); CHKERRQ(ierr);
585
586
587 if (!can_service) PetscFunctionReturn(0);
588
589 ierr = DMDAVecGetArrayRead(user->fda, user->Ucont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
590
591 PetscReal local_flux = 0.0;
592
593 PetscInt xs = info->xs, xe = info->xs + info->xm;
594 PetscInt ys = info->ys, ye = info->ys + info->ym;
595 PetscInt zs = info->zs, ze = info->zs + info->zm;
596 PetscInt mx = info->mx, my = info->my, mz = info->mz;
597
598 PetscInt lxs = xs, lxe = xe, lys = ys, lye = ye, lzs = zs, lze = ze;
599 if (xs == 0) lxs = xs + 1;
600 if (xe == mx) lxe = xe - 1;
601 if (ys == 0) lys = ys + 1;
602 if (ye == my) lye = ye - 1;
603 if (zs == 0) lzs = zs + 1;
604 if (ze == mz) lze = ze - 1;
605
606 // Sum ucont components
607 switch (face_id) {
608 case BC_FACE_NEG_X:
609 case BC_FACE_POS_X: {
610 PetscInt i = (face_id == BC_FACE_NEG_X) ? xs : mx - 2;
611 for (PetscInt k = lzs; k < lze; k++) {
612 for (PetscInt j = lys; j < lye; j++) {
613 local_flux += ucont[k][j][i].x;
614 }
615 }
616 } break;
617
618 case BC_FACE_NEG_Y:
619 case BC_FACE_POS_Y: {
620 PetscInt j = (face_id == BC_FACE_NEG_Y) ? ys : my - 2;
621 for (PetscInt k = lzs; k < lze; k++) {
622 for (PetscInt i = lxs; i < lxe; i++) {
623 local_flux += ucont[k][j][i].y;
624 }
625 }
626 } break;
627
628 case BC_FACE_NEG_Z:
629 case BC_FACE_POS_Z: {
630 PetscInt k = (face_id == BC_FACE_NEG_Z) ? zs : mz - 2;
631 for (PetscInt j = lys; j < lye; j++) {
632 for (PetscInt i = lxs; i < lxe; i++) {
633 local_flux += ucont[k][j][i].z;
634 }
635 }
636 } break;
637 }
638
639 ierr = DMDAVecRestoreArrayRead(user->fda, user->Ucont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
640
641 *local_inflow_contribution += local_flux;
642
643 LOG_ALLOW(LOCAL, LOG_DEBUG, "PostStep_InletConstantVelocity: Face %d, flux = %.6e\n",
644 face_id, local_flux);
645
646 PetscFunctionReturn(0);
647}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Destroy_InletConstantVelocity()

static PetscErrorCode Destroy_InletConstantVelocity ( BoundaryCondition self)
static

Internal helper implementation: Destroy_InletConstantVelocity().

Local to this translation unit.

Definition at line 656 of file BC_Handlers.c.

657{
658 PetscFunctionBeginUser;
659 if (self && self->data) {
660 PetscFree(self->data);
661 self->data = NULL;
662 }
663 PetscFunctionReturn(0);
664}
Here is the caller graph for this function:

◆ Create_InletConstantVelocity()

PetscErrorCode Create_InletConstantVelocity ( BoundaryCondition bc)

Implementation of Create_InletConstantVelocity().

Configures a BoundaryCondition object to behave as a constant velocity inlet.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/BC_Handlers.h.

See also
Create_InletConstantVelocity()

Definition at line 323 of file BC_Handlers.c.

324{
325 PetscErrorCode ierr;
326 PetscFunctionBeginUser;
327
328 if (!bc) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "BoundaryCondition is NULL");
329
330 InletConstantData *data = NULL;
331 ierr = PetscMalloc1(1, &data); CHKERRQ(ierr);
332 bc->data = (void*)data;
333
339 bc->UpdateUbcs = NULL;
341
342 PetscFunctionReturn(0);
343}
static PetscErrorCode PreStep_InletConstantVelocity(BoundaryCondition *self, BCContext *ctx, PetscReal *in, PetscReal *out)
Internal helper implementation: PreStep_InletConstantVelocity().
static PetscErrorCode Destroy_InletConstantVelocity(BoundaryCondition *self)
Internal helper implementation: Destroy_InletConstantVelocity().
static PetscErrorCode Initialize_InletConstantVelocity(BoundaryCondition *self, BCContext *ctx)
Internal helper implementation: Initialize_InletConstantVelocity().
static PetscErrorCode PostStep_InletConstantVelocity(BoundaryCondition *self, BCContext *ctx, PetscReal *in, PetscReal *out)
Internal helper implementation: PostStep_InletConstantVelocity().
@ BC_PRIORITY_INLET
Definition variables.h:293
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Initialize_InletParabolicProfile()

static PetscErrorCode Initialize_InletParabolicProfile ( BoundaryCondition self,
BCContext ctx 
)
static

Internal helper implementation: Initialize_InletParabolicProfile().

Local to this translation unit.

Definition at line 750 of file BC_Handlers.c.

751{
752 PetscErrorCode ierr;
753 UserCtx* user = ctx->user;
754 BCFace face_id = ctx->face_id;
756 PetscBool found;
757
758 PetscFunctionBeginUser;
759 LOG_ALLOW(LOCAL, LOG_DEBUG, "Initialize_InletParabolicProfile: Initializing handler for Face %d.\n", face_id);
760
761 // --- Parse v_max from boundary condition parameters ---
762 data->v_max = 0.0;
763 ierr = GetBCParamReal(user->boundary_faces[face_id].params, "v_max",
764 &data->v_max, &found); CHKERRQ(ierr);
765 if (!found) {
766 LOG_ALLOW(GLOBAL, LOG_WARNING, "Initialize_InletParabolicProfile: 'v_max' not found in params for face %d. Defaulting to 0.0.\n", face_id);
767 }
768
769 // --- Determine cross-stream dimensions based on face orientation ---
770 PetscReal cs1_dim, cs2_dim;
771 switch (face_id) {
772 case BC_FACE_NEG_X:
773 case BC_FACE_POS_X:
774 cs1_dim = (PetscReal)user->JM; // j-direction
775 cs2_dim = (PetscReal)user->KM; // k-direction
776 break;
777 case BC_FACE_NEG_Y:
778 case BC_FACE_POS_Y:
779 cs1_dim = (PetscReal)user->IM; // i-direction
780 cs2_dim = (PetscReal)user->KM; // k-direction
781 break;
782 case BC_FACE_NEG_Z:
783 case BC_FACE_POS_Z:
784 default:
785 cs1_dim = (PetscReal)user->IM; // i-direction
786 cs2_dim = (PetscReal)user->JM; // j-direction
787 break;
788 }
789
790 // Interior width = dim - 2 (nodes 1 through dim-2 are interior)
791 PetscReal cs1_width = cs1_dim - 2.0;
792 PetscReal cs2_width = cs2_dim - 2.0;
793
794 data->cs1_center = 1.0 + cs1_width / 2.0;
795 data->cs2_center = 1.0 + cs2_width / 2.0;
796 data->cs1_half = cs1_width / 2.0;
797 data->cs2_half = cs2_width / 2.0;
798
799 LOG_ALLOW(LOCAL, LOG_INFO, " Inlet Face %d (Parabolic): v_max = %.4f\n", face_id, data->v_max);
800 LOG_ALLOW(LOCAL, LOG_DEBUG, " Cross-stream 1: center=%.1f, half=%.1f\n", data->cs1_center, data->cs1_half);
801 LOG_ALLOW(LOCAL, LOG_DEBUG, " Cross-stream 2: center=%.1f, half=%.1f\n", data->cs2_center, data->cs2_half);
802
803 // Set initial boundary state
804 ierr = Apply_InletParabolicProfile(self, ctx); CHKERRQ(ierr);
805
806 PetscFunctionReturn(0);
807}
static PetscErrorCode Apply_InletParabolicProfile(BoundaryCondition *self, BCContext *ctx)
Internal helper implementation: Apply_InletParabolicProfile().
Private data structure for the Parabolic Velocity Inlet handler.
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PreStep_InletParabolicProfile()

static PetscErrorCode PreStep_InletParabolicProfile ( BoundaryCondition self,
BCContext ctx,
PetscReal *  local_inflow_contribution,
PetscReal *  local_outflow_contribution 
)
static

Internal helper implementation: PreStep_InletParabolicProfile().

Local to this translation unit.

Definition at line 816 of file BC_Handlers.c.

819{
820 (void)self;
821 (void)ctx;
822 (void)local_inflow_contribution;
823 (void)local_outflow_contribution;
824
825 PetscFunctionBeginUser;
826 PetscFunctionReturn(0);
827}
Here is the caller graph for this function:

◆ Apply_InletParabolicProfile()

static PetscErrorCode Apply_InletParabolicProfile ( BoundaryCondition self,
BCContext ctx 
)
static

Internal helper implementation: Apply_InletParabolicProfile().

Local to this translation unit.

Definition at line 836 of file BC_Handlers.c.

837{
838 PetscErrorCode ierr;
839 UserCtx* user = ctx->user;
840 BCFace face_id = ctx->face_id;
842 PetscBool can_service;
843
844 PetscFunctionBeginUser;
845
846 DMDALocalInfo *info = &user->info;
847 Cmpnts ***ubcs, ***ucont, ***csi, ***eta, ***zet;
848 PetscReal ***nvert;
849 PetscInt IM_nodes_global, JM_nodes_global, KM_nodes_global;
850
851 IM_nodes_global = user->IM;
852 JM_nodes_global = user->JM;
853 KM_nodes_global = user->KM;
854
855 ierr = CanRankServiceFace(info, IM_nodes_global, JM_nodes_global, KM_nodes_global,
856 face_id, &can_service); CHKERRQ(ierr);
857
858 if (!can_service) PetscFunctionReturn(0);
859
860 // Get arrays
861 ierr = DMDAVecGetArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
862 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
863 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
864 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
865 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
866 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
867
868 PetscInt xs = info->xs, xe = info->xs + info->xm;
869 PetscInt ys = info->ys, ye = info->ys + info->ym;
870 PetscInt zs = info->zs, ze = info->zs + info->zm;
871 PetscInt mx = info->mx, my = info->my, mz = info->mz;
872
873 PetscInt lxs = xs, lxe = xe, lys = ys, lye = ye, lzs = zs, lze = ze;
874 if (xs == 0) lxs = xs + 1;
875 if (xe == mx) lxe = xe - 1;
876 if (ys == 0) lys = ys + 1;
877 if (ye == my) lye = ye - 1;
878 if (zs == 0) lzs = zs + 1;
879 if (ze == mz) lze = ze - 1;
880
881 switch (face_id) {
882 case BC_FACE_NEG_X:
883 case BC_FACE_POS_X: {
884 // X-faces: normal = i, cross-stream = (j, k)
885 PetscReal sign = (face_id == BC_FACE_NEG_X) ? 1.0 : -1.0;
886 PetscInt i = (face_id == BC_FACE_NEG_X) ? xs : mx - 2;
887
888 for (PetscInt k = lzs; k < lze; k++) {
889 for (PetscInt j = lys; j < lye; j++) {
890 if ((sign > 0 && nvert[k][j][i+1] > 0.1) ||
891 (sign < 0 && nvert[k][j][i] > 0.1)) continue;
892
893 // Evaluate parabolic profile: cs1 = j, cs2 = k
894 PetscReal cs1_norm = ((PetscReal)j - data->cs1_center) / data->cs1_half;
895 PetscReal cs2_norm = ((PetscReal)k - data->cs2_center) / data->cs2_half;
896 PetscReal profile = PetscMax(0.0, 1.0 - cs1_norm * cs1_norm)
897 * PetscMax(0.0, 1.0 - cs2_norm * cs2_norm);
898 PetscReal uin_local = data->v_max * profile;
899
900 PetscReal CellArea = sqrt(csi[k][j][i].x * csi[k][j][i].x +
901 csi[k][j][i].y * csi[k][j][i].y +
902 csi[k][j][i].z * csi[k][j][i].z);
903
904 ucont[k][j][i].x = sign * uin_local * CellArea;
905
906 ubcs[k][j][i + (sign < 0)].x = sign * uin_local * csi[k][j][i].x / CellArea;
907 ubcs[k][j][i + (sign < 0)].y = sign * uin_local * csi[k][j][i].y / CellArea;
908 ubcs[k][j][i + (sign < 0)].z = sign * uin_local * csi[k][j][i].z / CellArea;
909 }
910 }
911 } break;
912
913 case BC_FACE_NEG_Y:
914 case BC_FACE_POS_Y: {
915 // Y-faces: normal = j, cross-stream = (i, k)
916 PetscReal sign = (face_id == BC_FACE_NEG_Y) ? 1.0 : -1.0;
917 PetscInt j = (face_id == BC_FACE_NEG_Y) ? ys : my - 2;
918
919 for (PetscInt k = lzs; k < lze; k++) {
920 for (PetscInt i = lxs; i < lxe; i++) {
921 if ((sign > 0 && nvert[k][j+1][i] > 0.1) ||
922 (sign < 0 && nvert[k][j][i] > 0.1)) continue;
923
924 // Evaluate parabolic profile: cs1 = i, cs2 = k
925 PetscReal cs1_norm = ((PetscReal)i - data->cs1_center) / data->cs1_half;
926 PetscReal cs2_norm = ((PetscReal)k - data->cs2_center) / data->cs2_half;
927 PetscReal profile = PetscMax(0.0, 1.0 - cs1_norm * cs1_norm)
928 * PetscMax(0.0, 1.0 - cs2_norm * cs2_norm);
929 PetscReal uin_local = data->v_max * profile;
930
931 PetscReal CellArea = sqrt(eta[k][j][i].x * eta[k][j][i].x +
932 eta[k][j][i].y * eta[k][j][i].y +
933 eta[k][j][i].z * eta[k][j][i].z);
934
935 ucont[k][j][i].y = sign * uin_local * CellArea;
936
937 ubcs[k][j + (sign < 0)][i].x = sign * uin_local * eta[k][j][i].x / CellArea;
938 ubcs[k][j + (sign < 0)][i].y = sign * uin_local * eta[k][j][i].y / CellArea;
939 ubcs[k][j + (sign < 0)][i].z = sign * uin_local * eta[k][j][i].z / CellArea;
940 }
941 }
942 } break;
943
944 case BC_FACE_NEG_Z:
945 case BC_FACE_POS_Z: {
946 // Z-faces: normal = k, cross-stream = (i, j)
947 PetscReal sign = (face_id == BC_FACE_NEG_Z) ? 1.0 : -1.0;
948 PetscInt k = (face_id == BC_FACE_NEG_Z) ? zs : mz - 2;
949
950 for (PetscInt j = lys; j < lye; j++) {
951 for (PetscInt i = lxs; i < lxe; i++) {
952 if ((sign > 0 && nvert[k+1][j][i] > 0.1) ||
953 (sign < 0 && nvert[k][j][i] > 0.1)) continue;
954
955 // Evaluate parabolic profile: cs1 = i, cs2 = j
956 PetscReal cs1_norm = ((PetscReal)i - data->cs1_center) / data->cs1_half;
957 PetscReal cs2_norm = ((PetscReal)j - data->cs2_center) / data->cs2_half;
958 PetscReal profile = PetscMax(0.0, 1.0 - cs1_norm * cs1_norm)
959 * PetscMax(0.0, 1.0 - cs2_norm * cs2_norm);
960 PetscReal uin_local = data->v_max * profile;
961
962 PetscReal CellArea = sqrt(zet[k][j][i].x * zet[k][j][i].x +
963 zet[k][j][i].y * zet[k][j][i].y +
964 zet[k][j][i].z * zet[k][j][i].z);
965
966 ucont[k][j][i].z = sign * uin_local * CellArea;
967
968 ubcs[k + (sign < 0)][j][i].x = sign * uin_local * zet[k][j][i].x / CellArea;
969 ubcs[k + (sign < 0)][j][i].y = sign * uin_local * zet[k][j][i].y / CellArea;
970 ubcs[k + (sign < 0)][j][i].z = sign * uin_local * zet[k][j][i].z / CellArea;
971 }
972 }
973 } break;
974 }
975
976 // Restore arrays
977 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
978 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
979 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
980 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
981 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
982 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
983
984 PetscFunctionReturn(0);
985}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PostStep_InletParabolicProfile()

static PetscErrorCode PostStep_InletParabolicProfile ( BoundaryCondition self,
BCContext ctx,
PetscReal *  local_inflow_contribution,
PetscReal *  local_outflow_contribution 
)
static

Internal helper implementation: PostStep_InletParabolicProfile().

Local to this translation unit.

Definition at line 994 of file BC_Handlers.c.

997{
998 PetscErrorCode ierr;
999 UserCtx* user = ctx->user;
1000 BCFace face_id = ctx->face_id;
1001 PetscBool can_service;
1002
1003 (void)self;
1004 (void)local_outflow_contribution;
1005
1006 PetscFunctionBeginUser;
1007
1008 DMDALocalInfo *info = &user->info;
1009 Cmpnts ***ucont;
1010
1011 PetscInt IM_nodes_global, JM_nodes_global, KM_nodes_global;
1012
1013 IM_nodes_global = user->IM;
1014 JM_nodes_global = user->JM;
1015 KM_nodes_global = user->KM;
1016
1017 ierr = CanRankServiceFace(info, IM_nodes_global, JM_nodes_global, KM_nodes_global,
1018 face_id, &can_service); CHKERRQ(ierr);
1019
1020 if (!can_service) PetscFunctionReturn(0);
1021
1022 ierr = DMDAVecGetArrayRead(user->fda, user->Ucont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
1023
1024 PetscReal local_flux = 0.0;
1025
1026 PetscInt xs = info->xs, xe = info->xs + info->xm;
1027 PetscInt ys = info->ys, ye = info->ys + info->ym;
1028 PetscInt zs = info->zs, ze = info->zs + info->zm;
1029 PetscInt mx = info->mx, my = info->my, mz = info->mz;
1030
1031 PetscInt lxs = xs, lxe = xe, lys = ys, lye = ye, lzs = zs, lze = ze;
1032 if (xs == 0) lxs = xs + 1;
1033 if (xe == mx) lxe = xe - 1;
1034 if (ys == 0) lys = ys + 1;
1035 if (ye == my) lye = ye - 1;
1036 if (zs == 0) lzs = zs + 1;
1037 if (ze == mz) lze = ze - 1;
1038
1039 switch (face_id) {
1040 case BC_FACE_NEG_X:
1041 case BC_FACE_POS_X: {
1042 PetscInt i = (face_id == BC_FACE_NEG_X) ? xs : mx - 2;
1043 for (PetscInt k = lzs; k < lze; k++) {
1044 for (PetscInt j = lys; j < lye; j++) {
1045 local_flux += ucont[k][j][i].x;
1046 }
1047 }
1048 } break;
1049
1050 case BC_FACE_NEG_Y:
1051 case BC_FACE_POS_Y: {
1052 PetscInt j = (face_id == BC_FACE_NEG_Y) ? ys : my - 2;
1053 for (PetscInt k = lzs; k < lze; k++) {
1054 for (PetscInt i = lxs; i < lxe; i++) {
1055 local_flux += ucont[k][j][i].y;
1056 }
1057 }
1058 } break;
1059
1060 case BC_FACE_NEG_Z:
1061 case BC_FACE_POS_Z: {
1062 PetscInt k = (face_id == BC_FACE_NEG_Z) ? zs : mz - 2;
1063 for (PetscInt j = lys; j < lye; j++) {
1064 for (PetscInt i = lxs; i < lxe; i++) {
1065 local_flux += ucont[k][j][i].z;
1066 }
1067 }
1068 } break;
1069 }
1070
1071 ierr = DMDAVecRestoreArrayRead(user->fda, user->Ucont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
1072
1073 *local_inflow_contribution += local_flux;
1074
1075 LOG_ALLOW(LOCAL, LOG_DEBUG, "PostStep_InletParabolicProfile: Face %d, flux = %.6e\n",
1076 face_id, local_flux);
1077
1078 PetscFunctionReturn(0);
1079}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Destroy_InletParabolicProfile()

static PetscErrorCode Destroy_InletParabolicProfile ( BoundaryCondition self)
static

Internal helper implementation: Destroy_InletParabolicProfile().

Local to this translation unit.

Definition at line 1088 of file BC_Handlers.c.

1089{
1090 PetscFunctionBeginUser;
1091 if (self && self->data) {
1092 PetscFree(self->data);
1093 self->data = NULL;
1094 }
1095 PetscFunctionReturn(0);
1096}
Here is the caller graph for this function:

◆ Create_InletParabolicProfile()

PetscErrorCode Create_InletParabolicProfile ( BoundaryCondition bc)

Implementation of Create_InletParabolicProfile().

Configures a BoundaryCondition object for a parabolic inlet profile.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/BC_Handlers.h.

See also
Create_InletParabolicProfile()

Definition at line 721 of file BC_Handlers.c.

722{
723 PetscErrorCode ierr;
724 PetscFunctionBeginUser;
725
726 if (!bc) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "BoundaryCondition is NULL");
727
728 InletParabolicData *data = NULL;
729 ierr = PetscMalloc1(1, &data); CHKERRQ(ierr);
730 bc->data = (void*)data;
731
737 bc->UpdateUbcs = NULL;
739
740 PetscFunctionReturn(0);
741}
static PetscErrorCode Initialize_InletParabolicProfile(BoundaryCondition *self, BCContext *ctx)
Internal helper implementation: Initialize_InletParabolicProfile().
static PetscErrorCode PostStep_InletParabolicProfile(BoundaryCondition *self, BCContext *ctx, PetscReal *in, PetscReal *out)
Internal helper implementation: PostStep_InletParabolicProfile().
static PetscErrorCode PreStep_InletParabolicProfile(BoundaryCondition *self, BCContext *ctx, PetscReal *in, PetscReal *out)
Internal helper implementation: PreStep_InletParabolicProfile().
static PetscErrorCode Destroy_InletParabolicProfile(BoundaryCondition *self)
Internal helper implementation: Destroy_InletParabolicProfile().
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PreStep_OutletConservation()

static PetscErrorCode PreStep_OutletConservation ( BoundaryCondition self,
BCContext ctx,
PetscReal *  local_inflow_contribution,
PetscReal *  local_outflow_contribution 
)
static

Internal helper implementation: PreStep_OutletConservation().

Local to this translation unit.

Definition at line 1158 of file BC_Handlers.c.

1160{
1161 PetscErrorCode ierr;
1162 UserCtx* user = ctx->user;
1163 BCFace face_id = ctx->face_id;
1164 DMDALocalInfo* info = &user->info;
1165 PetscBool can_service;
1166
1167 // Suppress unused parameter warnings for clarity.
1168 (void)self;
1169 (void)local_inflow_contribution;
1170
1171 PetscFunctionBeginUser;
1172
1173 // Step 1: Use the robust utility function to determine if this MPI rank owns a computable
1174 // portion of the specified boundary face. If not, there is no work to do, so we exit immediately.
1175 const PetscInt IM_nodes_global = user->IM;
1176 const PetscInt JM_nodes_global = user->JM;
1177 const PetscInt KM_nodes_global = user->KM;
1178 ierr = CanRankServiceFace(info, IM_nodes_global, JM_nodes_global, KM_nodes_global, face_id, &can_service); CHKERRQ(ierr);
1179
1180 if (!can_service) {
1181 PetscFunctionReturn(0);
1182 }
1183
1184 // Step 2: Get read-only access to the necessary PETSc arrays.
1185 // We use the local versions (`lUcat`, `lNvert`) which include ghost cell data,
1186 // ensuring we have the correct interior values adjacent to the boundary.
1187 Cmpnts ***ucat, ***csi, ***eta, ***zet;
1188 PetscReal ***nvert;
1189 ierr = DMDAVecGetArrayRead(user->fda, user->lUcat, (const Cmpnts***)&ucat); CHKERRQ(ierr);
1190 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
1191 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
1192 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
1193 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
1194
1195 PetscReal local_flux_out = 0.0;
1196 const PetscInt xs=info->xs, xe=info->xs+info->xm;
1197 const PetscInt ys=info->ys, ye=info->ys+info->ym;
1198 const PetscInt zs=info->zs, ze=info->zs+info->zm;
1199 const PetscInt mx=info->mx, my=info->my, mz=info->mz;
1200
1201 // Step 3: Replicate the legacy shrunk loop bounds to exclude corners and edges.
1202 PetscInt lxs = xs; if (xs == 0) lxs = xs + 1;
1203 PetscInt lxe = xe; if (xe == mx) lxe = xe - 1;
1204 PetscInt lys = ys; if (ys == 0) lys = ys + 1;
1205 PetscInt lye = ye; if (ye == my) lye = ye - 1;
1206 PetscInt lzs = zs; if (zs == 0) lzs = zs + 1;
1207 PetscInt lze = ze; if (ze == mz) lze = ze - 1;
1208
1209 // Step 4: Loop over the specified face using the corrected bounds and indexing to calculate flux.
1210 switch (face_id) {
1211 case BC_FACE_NEG_X: {
1212 const PetscInt i_cell = xs + 1; // Index for first interior cell-centered data
1213 const PetscInt i_face = xs; // Index for the -X face of that cell
1214 for (int k=lzs; k<lze; k++) for (int j=lys; j<lye; j++) {
1215 if (nvert[k][j][i_cell] < 0.1) {
1216 local_flux_out += (ucat[k][j][i_cell].x * csi[k][j][i_face].x + ucat[k][j][i_cell].y * csi[k][j][i_face].y + ucat[k][j][i_cell].z * csi[k][j][i_face].z);
1217 }
1218 }
1219 break;
1220 }
1221 case BC_FACE_POS_X: {
1222 const PetscInt i_cell = xe - 2; // Index for last interior cell-centered data
1223 const PetscInt i_face = xe - 2; // Index for the +X face of that cell
1224 for (int k=lzs; k<lze; k++) for (int j=lys; j<lye; j++) {
1225 if (nvert[k][j][i_cell] < 0.1) {
1226 local_flux_out += (ucat[k][j][i_cell].x * csi[k][j][i_face].x + ucat[k][j][i_cell].y * csi[k][j][i_face].y + ucat[k][j][i_cell].z * csi[k][j][i_face].z);
1227 }
1228 }
1229 break;
1230 }
1231 case BC_FACE_NEG_Y: {
1232 const PetscInt j_cell = ys + 1;
1233 const PetscInt j_face = ys;
1234 for (int k=lzs; k<lze; k++) for (int i=lxs; i<lxe; i++) {
1235 if (nvert[k][j_cell][i] < 0.1) {
1236 local_flux_out += (ucat[k][j_cell][i].x * eta[k][j_face][i].x + ucat[k][j_cell][i].y * eta[k][j_face][i].y + ucat[k][j_cell][i].z * eta[k][j_face][i].z);
1237 }
1238 }
1239 break;
1240 }
1241 case BC_FACE_POS_Y: {
1242 const PetscInt j_cell = ye - 2;
1243 const PetscInt j_face = ye - 2;
1244 for (int k=lzs; k<lze; k++) for (int i=lxs; i<lxe; i++) {
1245 if (nvert[k][j_cell][i] < 0.1) {
1246 local_flux_out += (ucat[k][j_cell][i].x * eta[k][j_face][i].x + ucat[k][j_cell][i].y * eta[k][j_face][i].y + ucat[k][j_cell][i].z * eta[k][j_face][i].z);
1247 }
1248 }
1249 break;
1250 }
1251 case BC_FACE_NEG_Z: {
1252 const PetscInt k_cell = zs + 1;
1253 const PetscInt k_face = zs;
1254 for (int j=lys; j<lye; j++) for (int i=lxs; i<lxe; i++) {
1255 if (nvert[k_cell][j][i] < 0.1) {
1256 local_flux_out += (ucat[k_cell][j][i].x * zet[k_face][j][i].x + ucat[k_cell][j][i].y * zet[k_face][j][i].y + ucat[k_cell][j][i].z * zet[k_face][j][i].z);
1257 }
1258 }
1259 break;
1260 }
1261 case BC_FACE_POS_Z: {
1262 const PetscInt k_cell = ze - 2;
1263 const PetscInt k_face = ze - 2;
1264 for (int j=lys; j<lye; j++) for (int i=lxs; i<lxe; i++) {
1265 if (nvert[k_cell][j][i] < 0.1) {
1266 local_flux_out += (ucat[k_cell][j][i].x * zet[k_face][j][i].x + ucat[k_cell][j][i].y * zet[k_face][j][i].y + ucat[k_cell][j][i].z * zet[k_face][j][i].z);
1267 }
1268 }
1269 break;
1270 }
1271 }
1272
1273 // Step 5: Restore the PETSc arrays.
1274 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcat, (const Cmpnts***)&ucat); CHKERRQ(ierr);
1275 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
1276 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
1277 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
1278 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
1279
1280 // Step 6: Add this face's calculated flux to the accumulator for this rank.
1281 *local_outflow_contribution += local_flux_out;
1282
1283 PetscFunctionReturn(0);
1284}
Vec lNvert
Definition variables.h:837
Vec lZet
Definition variables.h:858
Vec lCsi
Definition variables.h:858
Vec lUcat
Definition variables.h:837
Vec lEta
Definition variables.h:858
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Apply_OutletConservation()

static PetscErrorCode Apply_OutletConservation ( BoundaryCondition self,
BCContext ctx 
)
static

(Handler Action) Applies mass conservation correction to the outlet face.

This function calculates a global correction factor based on the total inflow and outflow fluxes and applies it to the contravariant velocity (ucont) on the outlet face to ensure mass conservation.

Definition at line 1294 of file BC_Handlers.c.

1295{
1296 PetscErrorCode ierr;
1297 (void)self;
1298 UserCtx* user = ctx->user;
1299 BCFace face_id = ctx->face_id;
1300 DMDALocalInfo* info = &user->info;
1301 PetscBool can_service;
1302
1303 PetscFunctionBeginUser;
1305
1306 const PetscInt IM_nodes_global = user->IM;
1307 const PetscInt JM_nodes_global = user->JM;
1308 const PetscInt KM_nodes_global = user->KM;
1309 ierr = CanRankServiceFace(info, IM_nodes_global, JM_nodes_global, KM_nodes_global, face_id, &can_service); CHKERRQ(ierr);
1310
1311 if (!can_service) {
1313 PetscFunctionReturn(0);
1314 }
1315
1316 // --- STEP 1: Calculate the correction factor using pre-calculated area ---
1317 PetscReal total_inflow = *ctx->global_inflow_sum + *ctx->global_farfield_inflow_sum;
1318 PetscReal flux_imbalance = total_inflow - *ctx->global_outflow_sum;
1319
1320 // Directly use the pre-calculated area from the simulation context.
1321 PetscReal velocity_correction = (PetscAbsReal(user->simCtx->AreaOutSum) > 1e-12)
1322 ? flux_imbalance / user->simCtx->AreaOutSum
1323 : 0.0;
1324
1325 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Outlet Correction on Face %d: Imbalance=%.4e, Pre-calc Area=%.4e, V_corr=%.4e\n",
1326 face_id, flux_imbalance, user->simCtx->AreaOutSum, velocity_correction);
1327
1328 // --- STEP 2: Apply the correction to ucont on the outlet face ---
1329
1330 // Get read/write access to necessary arrays
1331
1332 Cmpnts ***ubcs, ***ucont, ***csi, ***eta, ***zet, ***ucat;
1333 PetscReal ***nvert;
1334 ierr = DMDAVecGetArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
1335 ierr = DMDAVecGetArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
1336 ierr = DMDAVecGetArrayRead(user->fda,user->lUcat, (const Cmpnts***)&ucat); CHKERRQ(ierr);
1337 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
1338 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
1339 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
1340 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
1341
1342 // Get local grid bounds to exclude corners/edges
1343 PetscInt xs = info->xs, xe = info->xs + info->xm;
1344 PetscInt ys = info->ys, ye = info->ys + info->ym;
1345 PetscInt zs = info->zs, ze = info->zs + info->zm;
1346 PetscInt mx = info->mx, my = info->my, mz = info->mz;
1347 PetscInt lxs = xs, lxe = xe, lys = ys, lye = ye, lzs = zs, lze = ze;
1348
1349 if (xs == 0) lxs = xs + 1;
1350 if (xe == mx) lxe = xe - 1;
1351 if (ys == 0) lys = ys + 1;
1352 if (ye == my) lye = ye - 1;
1353 if (zs == 0) lzs = zs + 1;
1354 if (ze == mz) lze = ze - 1;
1355
1356 // Loop over faces and apply correction
1357 switch(face_id){
1358 case BC_FACE_NEG_X:{
1359 const PetscInt i_cell = xs + 1;
1360 const PetscInt i_face = xs;
1361 const PetscInt i_dummy = xs;
1362 for (PetscInt k = lzs; k < lze; k++) {
1363 for (PetscInt j = lys; j < lye; j++) {
1364 if (nvert[k][j][i_cell] < 0.1) {
1365 // Set ubcs
1366 ubcs[k][j][i_dummy] = ucat[k][j][i_cell];
1367
1368 // Calculate Local uncorrected original flux
1369 PetscReal Uncorrected_local_flux = (ubcs[k][j][i_dummy].x * csi[k][j][i_face].x) + (ubcs[k][j][i_dummy].y * csi[k][j][i_face].y) + (ubcs[k][j][i_dummy].z * csi[k][j][i_face].z);
1370
1371 PetscReal Cell_Area = sqrt((csi[k][j][i_face].x*csi[k][j][i_face].x) + (csi[k][j][i_face].y*csi[k][j][i_face].y) + (csi[k][j][i_face].z*csi[k][j][i_face].z));
1372
1373 PetscReal Correction_flux = velocity_correction*Cell_Area;
1374
1375 ucont[k][j][i_face].x = Uncorrected_local_flux + Correction_flux;
1376 }
1377 }
1378 }
1379 break;
1380 }
1381 case BC_FACE_POS_X:{
1382 const PetscInt i_cell = xe - 2;
1383 const PetscInt i_face = xe - 2;
1384 const PetscInt i_dummy = xe - 1;
1385 for(PetscInt k = lzs; k < lze; k++) for (PetscInt j = lys; j < lye; j++){
1386 if(nvert[k][j][i_cell]<0.1){
1387 // Set ubcs
1388 ubcs[k][j][i_dummy] = ucat[k][j][i_cell];
1389
1390 // Calculate Local uncorrected original flux
1391 PetscReal Uncorrected_local_flux = (ubcs[k][j][i_dummy].x * csi[k][j][i_face].x) + (ubcs[k][j][i_dummy].y * csi[k][j][i_face].y) + (ubcs[k][j][i_dummy].z * csi[k][j][i_face].z);
1392
1393 PetscReal Cell_Area = sqrt((csi[k][j][i_face].x*csi[k][j][i_face].x) + (csi[k][j][i_face].y*csi[k][j][i_face].y) + (csi[k][j][i_face].z*csi[k][j][i_face].z));
1394
1395 PetscReal Correction_flux = velocity_correction*Cell_Area;
1396
1397 ucont[k][j][i_face].x = Uncorrected_local_flux + Correction_flux;
1398 }
1399 }
1400 break;
1401 }
1402 case BC_FACE_NEG_Y:{
1403 const PetscInt j_cell = ys + 1;
1404 const PetscInt j_face = ys;
1405 const PetscInt j_dummy = ys;
1406 for(PetscInt k = lzs; k < lze; k++) for (PetscInt i = lxs; i < lxe; i++){
1407 if(nvert[k][j_cell][i]<0.1){
1408 // Set ubcs
1409 ubcs[k][j_dummy][i] = ucat[k][j_cell][i];
1410
1411 // Calculate Local uncorrected original flux
1412 PetscReal Uncorrected_local_flux = (ubcs[k][j_dummy][i].x*eta[k][j_face][i].x) + (ubcs[k][j_dummy][i].y*eta[k][j_face][i].y) + (ubcs[k][j_dummy][i].z*eta[k][j_face][i].z);
1413
1414 PetscReal Cell_Area = sqrt((eta[k][j_face][i].x*eta[k][j_face][i].x)+(eta[k][j_face][i].y*eta[k][j_face][i].y)+(eta[k][j_face][i].z*eta[k][j_face][i].z));
1415
1416 PetscReal Correction_flux = velocity_correction*Cell_Area;
1417
1418 ucont[k][j_face][i].y = Uncorrected_local_flux + Correction_flux;
1419 }
1420 }
1421 break;
1422 }
1423 case BC_FACE_POS_Y:{
1424 const PetscInt j_cell = ye - 2;
1425 const PetscInt j_face = ye - 2;
1426 const PetscInt j_dummy = ye - 1;
1427 for(PetscInt k = lzs; k < lze; k++) for (PetscInt i = lxs; i < lxe; i++){
1428 if(nvert[k][j_cell][i]<0.1){
1429 // Set ubcs
1430 ubcs[k][j_dummy][i] = ucat[k][j_cell][i];
1431
1432 // Calculate Local uncorrected original flux
1433 PetscReal Uncorrected_local_flux = (ubcs[k][j_dummy][i].x*eta[k][j_face][i].x) + (ubcs[k][j_dummy][i].y*eta[k][j_face][i].y) + (ubcs[k][j_dummy][i].z*eta[k][j_face][i].z);
1434
1435 PetscReal Cell_Area = sqrt((eta[k][j_face][i].x*eta[k][j_face][i].x)+(eta[k][j_face][i].y*eta[k][j_face][i].y)+(eta[k][j_face][i].z*eta[k][j_face][i].z));
1436
1437 PetscReal Correction_flux = velocity_correction*Cell_Area;
1438
1439 ucont[k][j_face][i].y = Uncorrected_local_flux + Correction_flux;
1440 }
1441 }
1442 break;
1443 }
1444 case BC_FACE_NEG_Z:{
1445 const PetscInt k_cell = zs + 1;
1446 const PetscInt k_face = zs;
1447 const PetscInt k_dummy = zs;
1448 for(PetscInt j = lys; j < lye; j++) for (PetscInt i = lxs; i < lxe; i++){
1449 if(nvert[k_cell][j][i]<0.1){
1450 // Set ubcs
1451 ubcs[k_dummy][j][i] = ucat[k_cell][j][i];
1452
1453 // Calculate Local uncorrected original flux
1454 PetscReal Uncorrected_local_flux = ((ubcs[k_dummy][j][i].x*zet[k_face][j][i].x) + (ubcs[k_dummy][j][i].y*zet[k_face][j][i].y) + (ubcs[k_dummy][j][i].z*zet[k_face][j][i].z));
1455
1456 PetscReal Cell_Area = sqrt((zet[k_face][j][i].x*zet[k_face][j][i].x)+(zet[k_face][j][i].y*zet[k_face][j][i].y)+(zet[k_face][j][i].z*zet[k_face][j][i].z));
1457
1458 PetscReal Correction_flux = velocity_correction*Cell_Area;
1459
1460 ucont[k_face][j][i].z = Uncorrected_local_flux + Correction_flux;
1461 }
1462 }
1463 break;
1464 }
1465 case BC_FACE_POS_Z:{
1466 const PetscInt k_cell = ze - 2;
1467 const PetscInt k_face = ze - 2;
1468 const PetscInt k_dummy = ze - 1;
1469 for(PetscInt j = lys; j < lye; j++) for (PetscInt i = lxs; i < lxe; i++){
1470 if(nvert[k_cell][j][i]<0.1){
1471 // Set ubcs
1472 ubcs[k_dummy][j][i] = ucat[k_cell][j][i];
1473
1474 // Calculate Local uncorrected original flux
1475 PetscReal Uncorrected_local_flux = ((ubcs[k_dummy][j][i].x*zet[k_face][j][i].x) + (ubcs[k_dummy][j][i].y*zet[k_face][j][i].y) + (ubcs[k_dummy][j][i].z*zet[k_face][j][i].z));
1476
1477 PetscReal Cell_Area = sqrt((zet[k_face][j][i].x*zet[k_face][j][i].x)+(zet[k_face][j][i].y*zet[k_face][j][i].y)+(zet[k_face][j][i].z*zet[k_face][j][i].z));
1478
1479 PetscReal Correction_flux = velocity_correction*Cell_Area;
1480
1481 ucont[k_face][j][i].z = Uncorrected_local_flux + Correction_flux;
1482 }
1483 }
1484 break;
1485 }
1486 }
1487
1488 // Restore all arrays
1489 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
1490 ierr = DMDAVecRestoreArray(user->fda, user->Ucont, &ucont); CHKERRQ(ierr);
1491 ierr = DMDAVecRestoreArrayRead(user->fda,user->lUcat, (const Cmpnts***)&ucat); CHKERRQ(ierr);
1492 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
1493 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
1494 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
1495 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
1496
1498 PetscFunctionReturn(0);
1499}
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:779
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:770
const PetscReal * global_outflow_sum
Definition variables.h:317
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:814
const PetscReal * global_inflow_sum
Definition variables.h:314
const PetscReal * global_farfield_inflow_sum
Definition variables.h:315
PetscReal AreaOutSum
Definition variables.h:726
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PostStep_OutletConservation()

static PetscErrorCode PostStep_OutletConservation ( BoundaryCondition self,
BCContext ctx,
PetscReal *  local_inflow_contribution,
PetscReal *  local_outflow_contribution 
)
static

Internal helper implementation: PostStep_OutletConservation().

Local to this translation unit.

Definition at line 1507 of file BC_Handlers.c.

1510{
1511 PetscErrorCode ierr;
1512 UserCtx* user = ctx->user;
1513 BCFace face_id = ctx->face_id;
1514 DMDALocalInfo* info = &user->info;
1515 PetscBool can_service;
1516
1517 (void)self;
1518 (void)local_inflow_contribution;
1519
1520 PetscFunctionBeginUser;
1521 const PetscInt IM_nodes_global = user->IM;
1522 const PetscInt JM_nodes_global = user->JM;
1523 const PetscInt KM_nodes_global = user->KM;
1524 ierr = CanRankServiceFace(info, IM_nodes_global, JM_nodes_global, KM_nodes_global, face_id, &can_service); CHKERRQ(ierr);
1525
1526 if (!can_service) PetscFunctionReturn(0);
1527
1528 // Get arrays (need both ucont and nvert)
1529 Cmpnts ***ucont;
1530 PetscReal ***nvert; // ✅ ADD nvert
1531
1532 ierr = DMDAVecGetArrayRead(user->fda, user->Ucont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
1533 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr); // ✅ ADD
1534
1535 PetscReal local_flux = 0.0;
1536
1537 PetscInt xs = info->xs, xe = info->xs + info->xm;
1538 PetscInt ys = info->ys, ye = info->ys + info->ym;
1539 PetscInt zs = info->zs, ze = info->zs + info->zm;
1540 PetscInt mx = info->mx, my = info->my, mz = info->mz;
1541
1542 PetscInt lxs = xs, lxe = xe, lys = ys, lye = ye, lzs = zs, lze = ze;
1543 if (xs == 0) lxs = xs + 1;
1544 if (xe == mx) lxe = xe - 1;
1545 if (ys == 0) lys = ys + 1;
1546 if (ye == my) lye = ye - 1;
1547 if (zs == 0) lzs = zs + 1;
1548 if (ze == mz) lze = ze - 1;
1549
1550 // Sum ucont components, skipping solid cells (same indices as PreStep)
1551 switch (face_id) {
1552 case BC_FACE_NEG_X: {
1553 const PetscInt i_cell = xs + 1; // ✅ Match PreStep
1554 const PetscInt i_face = xs;
1555 for (PetscInt k = lzs; k < lze; k++) {
1556 for (PetscInt j = lys; j < lye; j++) {
1557 if (nvert[k][j][i_cell] < 0.1) { // ✅ Skip solid cells
1558 local_flux += ucont[k][j][i_face].x;
1559 }
1560 }
1561 }
1562 } break;
1563
1564 case BC_FACE_POS_X: {
1565 const PetscInt i_cell = xe - 2; // ✅ Match PreStep
1566 const PetscInt i_face = xe - 2;
1567 for (PetscInt k = lzs; k < lze; k++) {
1568 for (PetscInt j = lys; j < lye; j++) {
1569 if (nvert[k][j][i_cell] < 0.1) { // ✅ Skip solid cells
1570 local_flux += ucont[k][j][i_face].x;
1571 }
1572 }
1573 }
1574 } break;
1575
1576 case BC_FACE_NEG_Y: {
1577 const PetscInt j_cell = ys + 1; // ✅ Match PreStep
1578 const PetscInt j_face = ys;
1579 for (PetscInt k = lzs; k < lze; k++) {
1580 for (PetscInt i = lxs; i < lxe; i++) {
1581 if (nvert[k][j_cell][i] < 0.1) { // ✅ Skip solid cells
1582 local_flux += ucont[k][j_face][i].y;
1583 }
1584 }
1585 }
1586 } break;
1587
1588 case BC_FACE_POS_Y: {
1589 const PetscInt j_cell = ye - 2; // ✅ Match PreStep
1590 const PetscInt j_face = ye - 2;
1591 for (PetscInt k = lzs; k < lze; k++) {
1592 for (PetscInt i = lxs; i < lxe; i++) {
1593 if (nvert[k][j_cell][i] < 0.1) { // ✅ Skip solid cells
1594 local_flux += ucont[k][j_face][i].y;
1595 }
1596 }
1597 }
1598 } break;
1599
1600 case BC_FACE_NEG_Z: {
1601 const PetscInt k_cell = zs + 1; // ✅ Match PreStep
1602 const PetscInt k_face = zs;
1603 for (PetscInt j = lys; j < lye; j++) {
1604 for (PetscInt i = lxs; i < lxe; i++) {
1605 if (nvert[k_cell][j][i] < 0.1) { // ✅ Skip solid cells
1606 local_flux += ucont[k_face][j][i].z;
1607 }
1608 }
1609 }
1610 } break;
1611
1612 case BC_FACE_POS_Z: {
1613 const PetscInt k_cell = ze - 2; // ✅ Match PreStep
1614 const PetscInt k_face = ze - 2;
1615 for (PetscInt j = lys; j < lye; j++) {
1616 for (PetscInt i = lxs; i < lxe; i++) {
1617 if (nvert[k_cell][j][i] < 0.1) { // ✅ Skip solid cells
1618 local_flux += ucont[k_face][j][i].z;
1619 }
1620 }
1621 }
1622 } break;
1623 }
1624
1625 // Restore arrays
1626 ierr = DMDAVecRestoreArrayRead(user->fda, user->Ucont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
1627 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr); // ✅ ADD
1628
1629 // Add to accumulator
1630 *local_outflow_contribution += local_flux;
1631
1632 LOG_ALLOW(LOCAL, LOG_DEBUG, "PostStep_OutletConservation: Face %d, corrected flux = %.6e\n",
1633 face_id, local_flux);
1634
1635 PetscFunctionReturn(0);
1636}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Create_OutletConservation()

PetscErrorCode Create_OutletConservation ( BoundaryCondition bc)

Implementation of Create_OutletConservation().

Configures a BoundaryCondition object for conservative outlet treatment.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/BC_Handlers.h.

See also
Create_OutletConservation()

Definition at line 1129 of file BC_Handlers.c.

1130{
1131 PetscFunctionBeginUser;
1132
1133 if (!bc) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input BoundaryCondition is NULL");
1134
1135 // This handler has the highest priority to ensure it runs after
1136 // all inflow fluxes have been calculated.
1138
1139 // Assign function pointers
1140 bc->Initialize = NULL; // No initialization needed
1144 bc->UpdateUbcs = NULL;
1145 bc->Destroy = NULL; // No private data to destroy
1146
1147 bc->data = NULL;
1148
1149 PetscFunctionReturn(0);
1150}
static PetscErrorCode Apply_OutletConservation(BoundaryCondition *self, BCContext *ctx)
(Handler Action) Applies mass conservation correction to the outlet face.
static PetscErrorCode PostStep_OutletConservation(BoundaryCondition *self, BCContext *ctx, PetscReal *in, PetscReal *out)
Internal helper implementation: PostStep_OutletConservation().
static PetscErrorCode PreStep_OutletConservation(BoundaryCondition *self, BCContext *ctx, PetscReal *local_inflow_contribution, PetscReal *local_outflow_contribution)
Internal helper implementation: PreStep_OutletConservation().
@ BC_PRIORITY_OUTLET
Definition variables.h:296
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Create_PeriodicGeometric()

PetscErrorCode Create_PeriodicGeometric ( BoundaryCondition bc)

Implementation of Create_PeriodicGeometric().

Configures a BoundaryCondition object for geometric periodic coupling.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/BC_Handlers.h.

See also
Create_PeriodicGeometric()

Definition at line 1646 of file BC_Handlers.c.

1646 {
1647 PetscFunctionBeginUser;
1648
1649 if (!bc) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input BoundaryCondition is NULL");
1651
1652 // Assign function pointers
1653 bc->Initialize = NULL; // No initialization needed
1654 bc->PreStep = NULL;
1655 bc->Apply = NULL;
1656 bc->PostStep = NULL;
1657 bc->UpdateUbcs = NULL;
1658 bc->Destroy = NULL; // No private data to destroy
1659
1660 bc->data = NULL;
1661
1662 PetscFunctionReturn(0);
1663}
Here is the caller graph for this function:

◆ Initialize_PeriodicDrivenConstant()

static PetscErrorCode Initialize_PeriodicDrivenConstant ( BoundaryCondition self,
BCContext ctx 
)
static

Internal helper implementation: Initialize_PeriodicDrivenConstant().

Local to this translation unit.

Definition at line 1743 of file BC_Handlers.c.

1744{
1745 PetscErrorCode ierr;
1747 BCFace face_id = ctx->face_id;
1748 UserCtx* user = ctx->user;
1749
1750 PetscFunctionBeginUser;
1751
1752 LOG_ALLOW(LOCAL, LOG_DEBUG, "Initializing PERIODIC_DRIVEN_CONSTANT_FLUX handler on Face %s...\n", BCFaceToString(face_id));
1753
1754 // --- 1. Validation: Ensure the mathematical type is PERIODIC ---
1755 if (user->boundary_faces[face_id].mathematical_type != PERIODIC) {
1756 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
1757 "Configuration Error: Handler PERIODIC_DRIVEN_CONSTANT_FLUX on Face %s must be applied to a face with mathematical_type PERIODIC.",
1758 BCFaceToString(face_id));
1759 }
1760
1761 // --- 2. Role Assignment: Determine direction and master status ---
1762 data->isMasterController = PETSC_FALSE;
1763 switch (face_id) {
1764 case BC_FACE_NEG_X: data->direction = 'X'; data->isMasterController = PETSC_TRUE; break;
1765 case BC_FACE_POS_X: data->direction = 'X'; break;
1766 case BC_FACE_NEG_Y: data->direction = 'Y'; data->isMasterController = PETSC_TRUE; break;
1767 case BC_FACE_POS_Y: data->direction = 'Y'; break;
1768 case BC_FACE_NEG_Z: data->direction = 'Z'; data->isMasterController = PETSC_TRUE; break;
1769 case BC_FACE_POS_Z: data->direction = 'Z'; break;
1770 }
1771
1772 // --- 3. Parameter Parsing (Master Controller only) ---
1773 if (data->isMasterController) {
1774 PetscBool found;
1775
1776 // Attempt to read the 'target_flux' parameter from the bcs.run file.
1777 ierr = GetBCParamReal(user->boundary_faces[face_id].params, "target_flux",
1778 &data->targetVolumetricFlux, &found); CHKERRQ(ierr);
1779
1780 // If the required parameter is not found, halt with an informative error.
1781 if (!found) {
1782 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT,
1783 "Configuration Error: Handler PERIODIC_DRIVEN_CONSTANT_FLUX on Face %s requires a 'target_flux' parameter in the bcs file (e.g., target_flux=10.0).",
1784 BCFaceToString(face_id));
1785 }
1786
1787 LOG_ALLOW(GLOBAL, LOG_INFO, "Driven Flow (Dir %c): Constant target volumetric flux set to %le.\n",
1788 data->direction, data->targetVolumetricFlux);
1789
1790 // Store the target flux in the UserCtx. This makes it globally accessible
1791 // to other parts of the solver, such as the `CorrectChannelFluxProfile` enforcer function.
1792 user->simCtx->targetVolumetricFlux = data->targetVolumetricFlux;
1793 }
1794
1795 PetscBool trimfound;
1796 // Attempt to read Trim flag.
1797 ierr = GetBCParamBool(user->boundary_faces[face_id].params, "apply_trim",
1798 &data->applyBoundaryTrim, &trimfound); CHKERRQ(ierr);
1799
1800 if(!trimfound) LOG_ALLOW(GLOBAL,LOG_DEBUG,"Trim Application not found,defaults to %s.\n",data->applyBoundaryTrim? "True":"False");
1801
1802 PetscFunctionReturn(0);
1803}
Private data structure for the handler.
PetscErrorCode GetBCParamBool(BC_Param *params, const char *key, PetscBool *value_out, PetscBool *found)
Searches a BC_Param linked list for a key and returns its value as a bool.
Definition io.c:408
PetscReal targetVolumetricFlux
Definition variables.h:724
BC_Param * params
Definition variables.h:338
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PreStep_PeriodicDrivenConstant()

static PetscErrorCode PreStep_PeriodicDrivenConstant ( BoundaryCondition self,
BCContext ctx,
PetscReal *  local_inflow_contribution,
PetscReal *  local_outflow_contribution 
)
static

Internal helper implementation: PreStep_PeriodicDrivenConstant().

Local to this translation unit.

Definition at line 1811 of file BC_Handlers.c.

1814{
1815 PetscErrorCode ierr;
1817 UserCtx* user = ctx->user;
1818 SimCtx* simCtx = user->simCtx;
1819
1820 PetscFunctionBeginUser;
1821
1822 // --- Master Check: Only the handler on the negative face performs calculations ---
1823 if (!data->isMasterController) {
1824 PetscFunctionReturn(0);
1825 }
1826
1827 // This function is the generalized implementation of the old InitializeChannelFlowController.
1828 char direction = data->direction;
1829 DMDALocalInfo info = user->info;
1830 PetscInt i, j, k;
1831
1832 // --- Get read-only access to necessary field data ---
1833 Cmpnts ***ucont;
1834 PetscReal ***nvert;
1835 ierr = DMDAVecGetArrayRead(user->fda, user->lUcont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
1836 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
1837
1838 // --- Define local loop bounds ---
1839 PetscInt lxs = (info.xs == 0) ? 1 : info.xs;
1840 PetscInt lys = (info.ys == 0) ? 1 : info.ys;
1841 PetscInt lzs = (info.zs == 0) ? 1 : info.zs;
1842 PetscInt lxe = (info.xs + info.xm == info.mx) ? info.mx - 1 : info.xs + info.xm;
1843 PetscInt lye = (info.ys + info.ym == info.my) ? info.my - 1 : info.ys + info.ym;
1844 PetscInt lze = (info.zs + info.zm == info.mz) ? info.mz - 1 : info.zs + info.zm;
1845
1846 // ===================================================================================
1847 // CONTROLLER SENSORS: DUAL-FLUX MEASUREMENT STRATEGY
1848 //
1849 // To create a control system that is both stable and responsive, we measure the
1850 // volumetric flux in two distinct ways. One provides a fast, local signal for
1851 // immediate corrections, while the other provides a slow, stable signal for
1852 // strategic, domain-wide adjustments.
1853 //
1854 // -----------------------------------------------------------------------------------
1855 // ** 1. Fast/Local Sensor: `globalCurrentBoundaryFlux` **
1856 // -----------------------------------------------------------------------------------
1857 //
1858 // - WHAT IT IS: The total volumetric flux (m³/s) passing through the single,
1859 // representative periodic boundary plane at k=0.
1860 //
1861 // - PHYSICAL MEANING: An instantaneous "snapshot" of the flow rate at the
1862 // critical "seam" where the domain wraps around.
1863 //
1864 // - CHARACTERISTICS:
1865 // - Fast & Responsive: It immediately reflects any local flow changes or
1866 // errors occurring at the periodic interface.
1867 // - Noisy: It is susceptible to local fluctuations from turbulence or
1868 // numerical artifacts, causing its value to jitter from step to step.
1869 //
1870 // - CONTROLLER'S USE: This measurement is used to compute the
1871 // `boundaryVelocityCorrection`. This is a TACTICAL, fast-acting "trim" that is
1872 // applied immediately and directly to the boundary velocities to ensure perfect
1873 // continuity at the seam.
1874 //
1875 // -----------------------------------------------------------------------------------
1876 // ** 2. Stable/Global Sensor: `globalAveragePlanarVolumetricFlux` **
1877 // -----------------------------------------------------------------------------------
1878 //
1879 // - WHAT IT IS: The average of the volumetric fluxes across ALL cross-sectional
1880 // k-planes in the domain.
1881 // (i.e., [Flux(k=0) + Flux(k=1) + ... + Flux(k=N)] / N)
1882 //
1883 // - PHYSICAL MEANING: It represents the overall, bulk momentum of the fluid,
1884 // effectively filtering out local, transient fluctuations.
1885 //
1886 // - CHARACTERISTICS:
1887 // - Stable & Robust: Local noise at one plane is averaged out by all other
1888 // planes, providing a very smooth signal.
1889 // - Inertial: It changes more slowly, reflecting the inertia of the entire
1890 // fluid volume.
1891 //
1892 // - CONTROLLER'S USE: This measurement is used to compute the
1893 // `bulkVelocityCorrection`. This is a STRATEGIC, long-term adjustment used to
1894 // scale the main momentum source (body force). Using this stable signal prevents
1895 // the main driving force from oscillating wildly, ensuring simulation stability.
1896 //
1897 // ===================================================================================
1898
1899 // --- Initialize local accumulators ---
1900 PetscReal localCurrentBoundaryFlux = 0.0;
1901 PetscReal localAveragePlanarVolumetricFluxTerm = 0.0;
1902
1903 // --- Measure local contributions to the two flux types, generalized by direction ---
1904 switch (direction) {
1905 case 'X':
1906 if (info.xs == 0) { // Only the rank on the negative face contributes to boundary flux
1907 i = 0;
1908 for (k = lzs; k < lze; k++) for (j = lys; j < lye; j++) {
1909 if (nvert[k][j][i + 1] < 0.1) localCurrentBoundaryFlux += ucont[k][j][i].x;
1910 }
1911 }
1912 for (i = info.xs; i < lxe; i++) {
1913 for (k = lzs; k < lze; k++) for (j = lys; j < lye; j++) {
1914 if (nvert[k][j][i + 1] < 0.1) localAveragePlanarVolumetricFluxTerm += ucont[k][j][i].x / (PetscReal)(info.mx - 1);
1915 }
1916 }
1917 break;
1918 case 'Y':
1919 if (info.ys == 0) {
1920 j = 0;
1921 for (k = lzs; k < lze; k++) for (i = lxs; i < lxe; i++) {
1922 if (nvert[k][j + 1][i] < 0.1) localCurrentBoundaryFlux += ucont[k][j][i].y;
1923 }
1924 }
1925 for (j = info.ys; j < lye; j++) {
1926 for (k = lzs; k < lze; k++) for (i = lxs; i < lxe; i++) {
1927 if (nvert[k][j + 1][i] < 0.1) localAveragePlanarVolumetricFluxTerm += ucont[k][j][i].y / (PetscReal)(info.my - 1);
1928 }
1929 }
1930 break;
1931 case 'Z':
1932 if (info.zs == 0) {
1933 k = 0;
1934 for (j = lys; j < lye; j++) for (i = lxs; i < lxe; i++) {
1935 if (nvert[k + 1][j][i] < 0.1) localCurrentBoundaryFlux += ucont[k][j][i].z;
1936 }
1937 }
1938 for (k = info.zs; k < lze; k++) {
1939 for (j = lys; j < lye; j++) for (i = lxs; i < lxe; i++) {
1940 if (nvert[k + 1][j][i] < 0.1) localAveragePlanarVolumetricFluxTerm += ucont[k][j][i].z / (PetscReal)(info.mz - 1);
1941 }
1942 }
1943 break;
1944 }
1945
1946 // --- Release array access as soon as possible ---
1947 ierr = DMDAVecRestoreArrayRead(user->fda, user->lUcont, (const Cmpnts***)&ucont); CHKERRQ(ierr);
1948 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
1949
1950 // --- Get cross-sectional area using the dedicated geometry function ---
1951 Cmpnts ignored_center;
1952 PetscReal globalBoundaryArea;
1953 BCFace neg_face_id = (direction == 'X') ? BC_FACE_NEG_X : (direction == 'Y') ? BC_FACE_NEG_Y : BC_FACE_NEG_Z;
1954 ierr = CalculateFaceCenterAndArea(user, neg_face_id, &ignored_center, &globalBoundaryArea); CHKERRQ(ierr);
1955
1956 // --- Perform global reductions to get the final flux values ---
1957 PetscReal globalCurrentBoundaryFlux, globalAveragePlanarVolumetricFlux;
1958 ierr = MPI_Allreduce(&localCurrentBoundaryFlux, &globalCurrentBoundaryFlux, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
1959 ierr = MPI_Allreduce(&localAveragePlanarVolumetricFluxTerm, &globalAveragePlanarVolumetricFlux, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
1960
1961 // --- Calculate the two correction terms ---
1962 if (globalBoundaryArea > 1.0e-12) {
1963 // The main correction for the body force is based on the STABLE domain-averaged flux.
1964 simCtx->bulkVelocityCorrection = (data->targetVolumetricFlux - globalAveragePlanarVolumetricFlux) / globalBoundaryArea;
1965
1966 // The immediate correction for the boundary trim is based on the FAST boundary-specific flux.
1967 data->boundaryVelocityCorrection = (data->targetVolumetricFlux - globalCurrentBoundaryFlux) / globalBoundaryArea;
1968 } else {
1969 simCtx->bulkVelocityCorrection = 0.0;
1970 data->boundaryVelocityCorrection = 0.0;
1971 }
1972
1973 LOG_ALLOW(GLOBAL, LOG_INFO, "Driven Flow Controller Update (Dir %c):\n", data->direction);
1974 LOG_ALLOW(GLOBAL, LOG_INFO, " - Target Volumetric Flux: %.6e\n", data->targetVolumetricFlux);
1975 LOG_ALLOW(GLOBAL, LOG_INFO, " - Avg Planar Volumetric Flux (Stable): %.6e\n", globalAveragePlanarVolumetricFlux);
1976 LOG_ALLOW(GLOBAL, LOG_INFO, " - Boundary Flux (Fast): %.6e\n", globalCurrentBoundaryFlux);
1977 LOG_ALLOW(GLOBAL, LOG_INFO, " - Bulk Velocity Correction: %.6e (For Momentum Source)\n", simCtx->bulkVelocityCorrection);
1978 LOG_ALLOW(GLOBAL, LOG_INFO, " - Boundary Velocity Correction: %.6e (For Boundary Trim)\n", data->boundaryVelocityCorrection);
1979
1980 // Suppress unused parameter warnings for this handler
1981 (void)local_inflow_contribution;
1982 (void)local_outflow_contribution;
1983
1984 PetscFunctionReturn(0);
1985}
PetscErrorCode CalculateFaceCenterAndArea(UserCtx *user, BCFace face_id, Cmpnts *face_center, PetscReal *face_area)
Calculates the geometric center and total area of a specified boundary face.
Definition grid.c:1029
PetscReal bulkVelocityCorrection
Definition variables.h:725
Vec lUcont
Definition variables.h:837
The master context for the entire simulation.
Definition variables.h:643
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Apply_PeriodicDrivenConstant()

static PetscErrorCode Apply_PeriodicDrivenConstant ( BoundaryCondition self,
BCContext ctx 
)
static

Internal helper implementation: Apply_PeriodicDrivenConstant().

Local to this translation unit.

Definition at line 1993 of file BC_Handlers.c.

1994{
1995 PetscErrorCode ierr;
1997 UserCtx* user = ctx->user;
1998 BCFace face_id = ctx->face_id;
1999 PetscBool can_service;
2000
2001 PetscFunctionBeginUser;
2002
2003 // Check if this rank owns part of this boundary face
2004 ierr = CanRankServiceFace(&user->info, user->IM, user->JM, user->KM, face_id, &can_service); CHKERRQ(ierr);
2005 if (!can_service) {
2006 PetscFunctionReturn(0);
2007 }
2008
2009 // If the correction is negligible, no work is needed.
2010 if (PetscAbsReal(data->boundaryVelocityCorrection) < 1e-12) {
2011 PetscFunctionReturn(0);
2012 }
2013
2014 LOG_ALLOW(LOCAL, LOG_TRACE, "Apply_PeriodicDrivenConstant: Applying boundary trim on Face %s...\n", BCFaceToString(face_id));
2015
2016 // --- Get read/write access to necessary arrays ---
2017 DMDALocalInfo info = user->info;
2018 Cmpnts ***ucont, ***uch, ***csi, ***eta, ***zet;
2019 PetscReal ***nvert;
2020
2021 ierr = DMDAVecGetArray(user->fda, user->lUcont, &ucont); CHKERRQ(ierr);
2022 ierr = DMDAVecGetArray(user->fda, user->Bcs.Uch, &uch); CHKERRQ(ierr);
2023 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
2024 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
2025 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
2026 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
2027
2028 PetscInt lxs = (info.xs == 0) ? 1 : info.xs;
2029 PetscInt lys = (info.ys == 0) ? 1 : info.ys;
2030 PetscInt lzs = (info.zs == 0) ? 1 : info.zs;
2031 PetscInt lxe = (info.xs + info.xm == info.mx) ? info.mx - 1 : info.xs + info.xm;
2032 PetscInt lye = (info.ys + info.ym == info.my) ? info.my - 1 : info.ys + info.ym;
2033 PetscInt lze = (info.zs + info.zm == info.mz) ? info.mz - 1 : info.zs + info.zm;
2034
2035 // --- Apply correction to the appropriate face and velocity component ---
2036 switch (face_id) {
2037 case BC_FACE_NEG_X: case BC_FACE_POS_X: {
2038 PetscInt i_face = (face_id == BC_FACE_NEG_X) ? info.xs : info.mx - 2;
2039 PetscInt i_nvert = (face_id == BC_FACE_NEG_X) ? info.xs + 1 : info.mx - 2;
2040
2041 for (PetscInt k = lzs; k < lze; k++) for (PetscInt j = lys; j < lye; j++) {
2042 if (nvert[k][j][i_nvert] < 0.1) {
2043 PetscReal faceArea = sqrt(csi[k][j][i_face].x*csi[k][j][i_nvert].x + csi[k][j][i_nvert].y*csi[k][j][i_nvert].y + csi[k][j][i_face].z*csi[k][j][i_face].z);
2044 PetscReal fluxTrim = data->boundaryVelocityCorrection * faceArea;
2045 if(data->applyBoundaryTrim) ucont[k][j][i_face].x += fluxTrim;
2046 uch[k][j][i_face].x = fluxTrim; // Store correction for diagnostics
2047 }
2048 }
2049 } break;
2050
2051 case BC_FACE_NEG_Y: case BC_FACE_POS_Y: {
2052 PetscInt j_face = (face_id == BC_FACE_NEG_Y) ? info.ys : info.my - 2;
2053 PetscInt j_nvert = (face_id == BC_FACE_NEG_Y) ? info.ys + 1 : info.my - 2;
2054
2055 for (PetscInt k = lzs; k < lze; k++) for (PetscInt i = lxs; i < lxe; i++) {
2056 if (nvert[k][j_nvert][i] < 0.1) {
2057 PetscReal faceArea = sqrt(eta[k][j_face][i].x*eta[k][j_face][i].x + eta[k][j_face][i].y*eta[k][j_face][i].y + eta[k][j_face][i].z*eta[k][j_face][i].z);
2058 PetscReal fluxTrim = data->boundaryVelocityCorrection * faceArea;
2059 if(data->applyBoundaryTrim) ucont[k][j_face][i].y += fluxTrim;
2060 uch[k][j_face][i].y = fluxTrim;
2061 }
2062 }
2063 } break;
2064
2065 case BC_FACE_NEG_Z: case BC_FACE_POS_Z: {
2066 PetscInt k_face = (face_id == BC_FACE_NEG_Z) ? info.zs : info.mz - 2;
2067 PetscInt k_nvert = (face_id == BC_FACE_NEG_Z) ? info.zs + 1 : info.mz - 2;
2068
2069 for (PetscInt j = lys; j < lye; j++) for (PetscInt i = lxs; i < lxe; i++) {
2070 if (nvert[k_nvert][j][i] < 0.1) {
2071 PetscReal faceArea = sqrt(zet[k_nvert][j][i].x*zet[k_nvert][j][i].x + zet[k_nvert][j][i].y*zet[k_nvert][j][i].y + zet[k_nvert][j][i].z*zet[k_nvert][j][i].z);
2072 PetscReal fluxTrim = data->boundaryVelocityCorrection * faceArea;
2073 if(data->applyBoundaryTrim) ucont[k_face][j][i].z += fluxTrim;
2074 uch[k_face][j][i].z = fluxTrim;
2075 }
2076 }
2077 } break;
2078 }
2079
2080 // --- Restore arrays ---
2081 ierr = DMDAVecRestoreArray(user->fda, user->lUcont, &ucont); CHKERRQ(ierr);
2082 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Uch, &uch); CHKERRQ(ierr);
2083 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
2084 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
2085 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
2086 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
2087
2088 PetscFunctionReturn(0);
2089}
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:32
Vec Uch
Characteristic velocity for boundary conditions.
Definition variables.h:122
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Destroy_PeriodicDrivenConstant()

static PetscErrorCode Destroy_PeriodicDrivenConstant ( BoundaryCondition self)
static

Internal helper implementation: Destroy_PeriodicDrivenConstant().

Local to this translation unit.

Definition at line 2097 of file BC_Handlers.c.

2098{
2099 PetscFunctionBeginUser;
2100
2101 // Check that the handler object and its private data pointer are valid before trying to free.
2102 if (self && self->data) {
2103 // The private data was allocated with PetscNew(), so it must be freed with PetscFree().
2104 PetscFree(self->data);
2105
2106 // It is good practice to nullify the pointer after freeing to prevent
2107 // any accidental use of the dangling pointer (use-after-free).
2108 self->data = NULL;
2109
2110 LOG_ALLOW(LOCAL, LOG_TRACE, "Destroy_PeriodicDrivenConstant: Private data freed successfully.\n");
2111 }
2112
2113 PetscFunctionReturn(0);
2114}
Here is the caller graph for this function:

◆ Create_PeriodicDrivenConstant()

PetscErrorCode Create_PeriodicDrivenConstant ( BoundaryCondition bc)

Internal helper implementation: Create_PeriodicDrivenConstant().

Configures a BoundaryCondition object for periodic driven-flow forcing.

Local to this translation unit.

Definition at line 1699 of file BC_Handlers.c.

1700{
1701 PetscErrorCode ierr;
1702 PetscFunctionBeginUser;
1703
1704 if (!bc) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Input BoundaryCondition object is NULL in Create_PeriodicDrivenConstantFlux");
1705
1706 // --- Allocate the private data structure ---
1707 DrivenConstantData *data = NULL;
1708 ierr = PetscNew(&data); CHKERRQ(ierr);
1709 // Initialize fields to safe default values
1710 data->direction = ' ';
1711 data->targetVolumetricFlux = 0.0;
1712 data->boundaryVelocityCorrection = 0.0;
1713 data->isMasterController = PETSC_FALSE;
1714 data->applyBoundaryTrim = PETSC_FALSE;
1715
1716 // Attach the private data to the generic handler object
1717 bc->data = (void*)data;
1718
1719 // --- Configure the handler's properties and methods ---
1720
1721 // Set priority: Using BC_PRIORITY_INLET ensures this handler's PreStep runs
1722 // before other handlers (like outlets) that might depend on its calculations.
1723 // It is the caller's responsibility that there are no Inlets called along with driven periodic to avoid clash.
1725
1726 // Assign the function pointers to the implementations in this file.
1730 bc->PostStep = NULL; // This handler has no action after the main solver step.
1731 bc->UpdateUbcs = NULL; // The boundary value is not flow-dependent (it's periodic).
1733
1734 PetscFunctionReturn(0);
1735}
PetscBool applyBoundaryTrim
PetscReal targetVolumetricFlux
PetscBool isMasterController
static PetscErrorCode Apply_PeriodicDrivenConstant(BoundaryCondition *self, BCContext *ctx)
Internal helper implementation: Apply_PeriodicDrivenConstant().
static PetscErrorCode Initialize_PeriodicDrivenConstant(BoundaryCondition *self, BCContext *ctx)
Internal helper implementation: Initialize_PeriodicDrivenConstant().
static PetscErrorCode Destroy_PeriodicDrivenConstant(BoundaryCondition *self)
Internal helper implementation: Destroy_PeriodicDrivenConstant().
static PetscErrorCode PreStep_PeriodicDrivenConstant(BoundaryCondition *self, BCContext *ctx, PetscReal *in, PetscReal *out)
Internal helper implementation: PreStep_PeriodicDrivenConstant().
PetscReal boundaryVelocityCorrection
Here is the call graph for this function:
Here is the caller graph for this function: