PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
BodyForces.c
Go to the documentation of this file.
1#include "BodyForces.h"
2#include "io.h"
3
4
5//////////////////////////////////////////////
6// DRIVEN CHANNEL FLOW FORCE(EQUIVALENT) TERM
7/////////////////////////////////////////////
8
9/**
10 * @brief The axis a driven periodic handler drives, or ' ' when none is configured.
11 * @param[in] user Block whose boundary faces are inspected.
12 * @return 'X', 'Y', 'Z', or ' '.
13 */
14static char DrivenFlowDirection(const UserCtx *user)
15{
16 for (int i = 0; i < 6; i++) {
17 const BCHandlerType handler_type = user->boundary_faces[i].handler_type;
18 if (handler_type == BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX ||
20 switch (user->boundary_faces[i].face_id) {
21 case BC_FACE_NEG_X: case BC_FACE_POS_X: return 'X';
22 case BC_FACE_NEG_Y: case BC_FACE_POS_Y: return 'Y';
23 case BC_FACE_NEG_Z: case BC_FACE_POS_Z: return 'Z';
24 }
25 return ' ';
26 }
27 }
28 return ' ';
29}
30
31#undef __FUNCT__
32#define __FUNCT__ "ComputeDrivenChannelFlowSource"
33/**
34 * @brief Internal helper implementation: `ComputeDrivenChannelFlowSource()`.
35 * @details Local to this translation unit.
36 */
37PetscErrorCode ComputeDrivenChannelFlowSource(UserCtx *user, Vec Rct)
38{
39 PetscErrorCode ierr;
40 SimCtx *simCtx = user->simCtx;
41 PetscFunctionBeginUser;
42
43 // --- Step 1: Discover if and where a driven flow is active ---
44 const char drivenDirection = DrivenFlowDirection(user); // ' ' when none is configured
45
46 // --- Step 2: Early exit if no driven flow is configured ---
47 if (drivenDirection == ' ') {
48 PetscFunctionReturn(0);
49 }
50
51 // --- Step 3: Get the control signal and exit if no correction is needed ---
52 PetscReal bulkVelocityCorrection = simCtx->bulkVelocityCorrection;
53 if (PetscAbsReal(bulkVelocityCorrection) < 1.0e-12) {
54 PetscFunctionReturn(0);
55 }
56
57 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d, Block %d: Applying driven flow momentum source in '%c' direction.\n",
58 simCtx->rank, user->_this, drivenDirection);
59 LOG_ALLOW(LOCAL, LOG_DEBUG, " - Received Bulk Velocity Correction: %le\n", bulkVelocityCorrection);
60
61 // --- Step 4: Setup for calculation ---
62 DMDALocalInfo info = user->info;
63 PetscInt i, j, k;
64 PetscInt lxs = (info.xs == 0) ? 1 : info.xs;
65 PetscInt lys = (info.ys == 0) ? 1 : info.ys;
66 PetscInt lzs = (info.zs == 0) ? 1 : info.zs;
67 PetscInt lxe = (info.xs + info.xm == info.mx) ? info.mx - 1 : info.xs + info.xm;
68 PetscInt lye = (info.ys + info.ym == info.my) ? info.my - 1 : info.ys + info.ym;
69 PetscInt lze = (info.zs + info.zm == info.mz) ? info.mz - 1 : info.zs + info.zm;
70
71 Cmpnts ***rct, ***csi, ***eta, ***zet;
72 PetscReal ***nvert;
73 ierr = DMDAVecGetArray(user->fda, Rct, &rct); CHKERRQ(ierr);
74 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
75 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
76 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
77 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
78
79 // Calculate the driving force magnitude for the current timestep, smoothed
80 // with the value from the previous step for stability.
81 //
82 // ONCE PER PHYSICAL STEP, NOT ONCE PER CALL. This function runs from
83 // ComputeRHS, which executes once per Jameson RK stage under the Picard
84 // solver and once per residual evaluation under Newton-Krylov. The smoothing
85 // below carries state in simCtx across calls, so advancing it every call
86 // would walk the applied force toward its target within a single timestep
87 // (0.5, then 0.75, then 0.875 ... of the way there). The force would then
88 // depend on how many residual evaluations preceded it - history dependence
89 // that MomentumNewtonKrylov_FormResidual() explicitly forbids, and that
90 // breaks the constant-forcing assumption behind the Picard shadow-Jacobian
91 // estimate. Resolve it once for the step and reuse it thereafter.
92 const PetscReal forceScalingFactor = simCtx->forceScalingFactor;
93 PetscReal drivingForceMagnitude;
94
95 if (simCtx->drivingForceStep != simCtx->step) {
96 const PetscReal targetForce = (bulkVelocityCorrection / simCtx->dt / 1.0 * COEF_TIME_ACCURACY); // replaced simCtx->st with 1.0.
97 drivingForceMagnitude = (simCtx->drivingForceMagnitude * 0.5) + (targetForce * 0.5);
98 simCtx->drivingForceMagnitude = drivingForceMagnitude;
99 simCtx->drivingForceStep = simCtx->step;
100 } else {
101 drivingForceMagnitude = simCtx->drivingForceMagnitude;
102 }
103
104 LOG_ALLOW(GLOBAL, LOG_DEBUG, " - Previous driving force: %le\n", simCtx->drivingForceMagnitude);
105 LOG_ALLOW(GLOBAL, LOG_DEBUG, " - New smoothed driving force: %le\n", drivingForceMagnitude);
106 LOG_ALLOW(GLOBAL, LOG_DEBUG, " - Force scaling factor: %f\n", simCtx->forceScalingFactor);
107
108 PetscBool hasLoggedApplication = PETSC_FALSE; // Flag to log details only once per rank.
109 // --- Step 5: Apply the momentum source to the correct RHS component ---
110 for (k = lzs; k < lze; k++) {
111 for (j = lys; j < lye; j++) {
112 for (i = lxs; i < lxe; i++) {
113 if (nvert[k][j][i] < 0.1) { // Apply only to fluid cells
114 PetscReal faceArea = 0.0;
115 PetscReal momentumSource = 0.0;
116
117 switch (drivenDirection) {
118 case 'X':
119 faceArea = sqrt(csi[k][j][i].x * csi[k][j][i].x + csi[k][j][i].y * csi[k][j][i].y + csi[k][j][i].z * csi[k][j][i].z);
120 momentumSource = drivingForceMagnitude * forceScalingFactor * faceArea;
121 rct[k][j][i].x += momentumSource;
122
123 // Log details for the very first point where force is applied on this rank.
124 if (!hasLoggedApplication) {
125 LOG_ALLOW(LOCAL, LOG_DEBUG,"Body Force %le added at (%d,%d,%d)\n",momentumSource, k, j, i);
126 hasLoggedApplication = PETSC_TRUE;
127 }
128 break;
129 case 'Y':
130 faceArea = sqrt(eta[k][j][i].x * eta[k][j][i].x + eta[k][j][i].y * eta[k][j][i].y + eta[k][j][i].z * eta[k][j][i].z);
131 momentumSource = drivingForceMagnitude * forceScalingFactor * faceArea;
132 rct[k][j][i].y += momentumSource;
133
134 // Log details for the very first point where force is applied on this rank.
135 if (!hasLoggedApplication) {
136 LOG_ALLOW(LOCAL, LOG_DEBUG,"Body Force %le added at (%d,%d,%d)\n",momentumSource, k, j, i);
137 hasLoggedApplication = PETSC_TRUE;
138 }
139 break;
140 case 'Z':
141 faceArea = sqrt(zet[k][j][i].x * zet[k][j][i].x + zet[k][j][i].y * zet[k][j][i].y + zet[k][j][i].z * zet[k][j][i].z);
142 momentumSource = drivingForceMagnitude * forceScalingFactor * faceArea;
143 rct[k][j][i].z += momentumSource;
144
145 // Log details for the very first point where force is applied on this rank.
146 if (!hasLoggedApplication) {
147 LOG_ALLOW(LOCAL, LOG_DEBUG,"Body Force %le added at (%d,%d,%d)\n",momentumSource, k, j, i);
148 hasLoggedApplication = PETSC_TRUE;
149 }
150 break;
151 }
152 }
153 }
154 }
155 }
156
157 // --- Step 6: Restore arrays ---
158 ierr = DMDAVecRestoreArray(user->fda, Rct, &rct); CHKERRQ(ierr);
159 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
160 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
161 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
162 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
163
164 PetscFunctionReturn(0);
165}
166
167#undef __FUNCT__
168#define __FUNCT__ "LogDrivenFlowDiagnostics"
169/**
170 * @brief Implementation of \ref LogDrivenFlowDiagnostics().
171 * @details Full API contract is documented with the header declaration in
172 * `include/BodyForces.h`.
173 */
175{
176 SimCtx *simCtx = user->simCtx;
177 const char direction = DrivenFlowDirection(user);
178 FILE *file = NULL;
179
180 PetscFunctionBeginUser;
181
182 /* The controller state is global: every rank holds the same values, set from the
183 controller's collective reductions, so rank 0 reports it once per step. */
184 if (direction == ' ' || user->_this != 0 || simCtx->rank != 0) PetscFunctionReturn(0);
185
186 /* What the momentum equation actually received this step. The source is resolved
187 once per step and skipped entirely when the correction is negligible, in which
188 case the smoothed magnitude is stale and nothing was applied. */
189 const PetscBool applied = (PetscBool)(simCtx->drivingForceStep == simCtx->step &&
190 PetscAbsReal(simCtx->bulkVelocityCorrection) >= 1.0e-12);
191 const PetscReal acceleration = applied ? simCtx->drivingForceMagnitude * simCtx->forceScalingFactor : 0.0;
192 const PetscReal area = simCtx->drivenFluxArea;
193 const PetscReal bulk_velocity = (area > 0.0) ? simCtx->drivenFluxMeasured / area : 0.0;
194 PetscReal physical_time = 0.0;
195
196 PetscCall(PicurvPhysicalTime(simCtx, simCtx->ti, &physical_time));
197 PetscCall(PicurvOpenDiagnosticsCsv(simCtx, "driven_flow.csv",
198 "step,time,direction,target_flux,measured_flux,cross_section_area,"
199 "bulk_velocity,bulk_velocity_correction,driving_acceleration,physical_time",
200 &file));
201 fprintf(file, "%d,%.6e,%c,%.10e,%.10e,%.10e,%.10e,%.6e,%.10e,%.6e\n",
202 (int)simCtx->step, (double)simCtx->ti, direction,
203 (double)simCtx->targetVolumetricFlux, (double)simCtx->drivenFluxMeasured, (double)area,
204 (double)bulk_velocity, (double)simCtx->bulkVelocityCorrection, (double)acceleration,
205 (double)physical_time);
206 PetscCheck(fclose(file) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
207 "Unable to close the driven-flow diagnostics file.");
208 PetscFunctionReturn(0);
209}
PetscErrorCode LogDrivenFlowDiagnostics(UserCtx *user)
Implementation of LogDrivenFlowDiagnostics().
Definition BodyForces.c:174
PetscErrorCode ComputeDrivenChannelFlowSource(UserCtx *user, Vec Rct)
Internal helper implementation: ComputeDrivenChannelFlowSource().
Definition BodyForces.c:37
static char DrivenFlowDirection(const UserCtx *user)
The axis a driven periodic handler drives, or ' ' when none is configured.
Definition BodyForces.c:14
Momentum source terms added to the contravariant RHS.
Public interface for data input/output routines.
PetscErrorCode PicurvPhysicalTime(const SimCtx *simCtx, PetscReal solver_time, PetscReal *physical)
Convert a solver time to physical seconds, t * L_ref / U_ref.
Definition io.c:3177
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
PetscErrorCode PicurvOpenDiagnosticsCsv(const SimCtx *simCtx, const char *filename, const char *header, FILE **file)
Opens a per-run diagnostics CSV in the run's analysis directory for appending.
Definition logging.c:3503
PetscMPIInt rank
Definition variables.h:862
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:1099
PetscReal targetVolumetricFlux
Definition variables.h:967
Vec lNvert
Definition variables.h:1113
PetscReal forceScalingFactor
Definition variables.h:961
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:1077
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:329
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:343
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:342
BCHandlerType handler_type
Definition variables.h:393
PetscInt _this
Definition variables.h:1092
PetscReal dt
Definition variables.h:874
PetscReal bulkVelocityCorrection
Definition variables.h:973
PetscScalar x
Definition variables.h:122
PetscScalar z
Definition variables.h:122
PetscInt drivingForceStep
Definition variables.h:966
PetscReal drivenFluxMeasured
Definition variables.h:978
PetscInt step
Definition variables.h:867
PetscReal drivenFluxArea
Definition variables.h:978
DMDALocalInfo info
Definition variables.h:1086
PetscScalar y
Definition variables.h:122
PetscReal ti
Definition variables.h:868
#define COEF_TIME_ACCURACY
Coefficient controlling the temporal accuracy scheme (e.g., 1.5 for 2nd Order Backward Difference).
Definition variables.h:75
PetscReal drivingForceMagnitude
Definition variables.h:961
@ BC_FACE_NEG_X
Definition variables.h:288
@ BC_FACE_POS_Z
Definition variables.h:290
@ BC_FACE_POS_Y
Definition variables.h:289
@ BC_FACE_NEG_Z
Definition variables.h:290
@ BC_FACE_POS_X
Definition variables.h:288
@ BC_FACE_NEG_Y
Definition variables.h:289
A 3D point or vector with PetscScalar components.
Definition variables.h:121
The master context for the entire simulation.
Definition variables.h:859
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1074