-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Add per-face thermal BC config to solver params #178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
ed5d256
d78ee8e
e6cbe69
869b016
a9dd20c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |||||||||||||||||
|
|
||||||||||||||||||
| #include "cfd/cfd_export.h" | ||||||||||||||||||
|
|
||||||||||||||||||
| #include "cfd/boundary/boundary_conditions.h" | ||||||||||||||||||
| #include "cfd/core/cfd_status.h" | ||||||||||||||||||
| #include "cfd/core/grid.h" | ||||||||||||||||||
| #include <stddef.h> | ||||||||||||||||||
|
|
@@ -90,6 +91,26 @@ typedef void (*ns_source_func_t)(double x, double y, double z, double t, | |||||||||||||||||
| typedef double (*ns_heat_source_func_t)(double x, double y, double z, double t, | ||||||||||||||||||
| void* context); | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Per-face thermal boundary condition configuration. | ||||||||||||||||||
| * | ||||||||||||||||||
| * Each face can independently be PERIODIC (default), NEUMANN (zero-gradient / | ||||||||||||||||||
| * adiabatic), or DIRICHLET (fixed temperature). When a face is DIRICHLET, its | ||||||||||||||||||
| * value is read from the corresponding field of `dirichlet_values`. | ||||||||||||||||||
| * | ||||||||||||||||||
| * Zero-initialization produces all-PERIODIC (BC_TYPE_PERIODIC == 0), | ||||||||||||||||||
| * preserving backward compatibility. | ||||||||||||||||||
|
Comment on lines
+101
to
+102
|
||||||||||||||||||
| * Zero-initialization produces all-PERIODIC (BC_TYPE_PERIODIC == 0), | |
| * preserving backward compatibility. | |
| * Zero-initialization produces an all-PERIODIC configuration | |
| * (BC_TYPE_PERIODIC == 0), matching the solver's default | |
| * `apply_boundary_conditions` behavior. This is not a "no change" mode: | |
| * periodic thermal boundaries will be actively enforced unless callers | |
| * explicitly set `thermal_bc` for non-periodic thermal walls (for example, | |
| * DIRICHLET or NEUMANN faces). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -194,3 +194,111 @@ void energy_compute_buoyancy(double T_local, const ns_solver_params_t* params, | |
| *source_v += -params->beta * dT * params->gravity[1]; | ||
| *source_w += -params->beta * dT * params->gravity[2]; | ||
| } | ||
|
|
||
| void energy_apply_thermal_bcs(flow_field* field, | ||
| const ns_solver_params_t* params) { | ||
| if (!field || !params || !field->T) return; | ||
| if (params->alpha <= 0.0) return; | ||
|
|
||
| const ns_thermal_bc_config_t* tbc = ¶ms->thermal_bc; | ||
|
|
||
| size_t nx = field->nx; | ||
| size_t ny = field->ny; | ||
| size_t nz = field->nz; | ||
| size_t plane = nx * ny; | ||
|
|
||
| /* Guard: Neumann needs >= 2 cells, Periodic needs >= 3 cells */ | ||
| if ((tbc->left == BC_TYPE_NEUMANN || tbc->right == BC_TYPE_NEUMANN) && nx < 2) return; | ||
| if ((tbc->bottom == BC_TYPE_NEUMANN || tbc->top == BC_TYPE_NEUMANN) && ny < 2) return; | ||
| if ((tbc->left == BC_TYPE_PERIODIC || tbc->right == BC_TYPE_PERIODIC) && nx < 3) return; | ||
| if ((tbc->bottom == BC_TYPE_PERIODIC || tbc->top == BC_TYPE_PERIODIC) && ny < 3) return; | ||
| if (nz > 1 && (tbc->back == BC_TYPE_NEUMANN || tbc->front == BC_TYPE_NEUMANN) && nz < 2) return; | ||
| if (nz > 1 && (tbc->back == BC_TYPE_PERIODIC || tbc->front == BC_TYPE_PERIODIC) && nz < 3) return; | ||
|
Comment on lines
+198
to
+216
|
||
|
|
||
| /* Left face (i=0) */ | ||
| for (size_t k = 0; k < nz; k++) { | ||
| size_t base = k * plane; | ||
| for (size_t j = 0; j < ny; j++) { | ||
| size_t idx = base + j * nx; | ||
| if (tbc->left == BC_TYPE_DIRICHLET) | ||
| field->T[idx] = tbc->dirichlet_values.left; | ||
| else if (tbc->left == BC_TYPE_NEUMANN) | ||
| field->T[idx] = field->T[idx + 1]; | ||
shaia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| else if (tbc->left == BC_TYPE_PERIODIC) | ||
| field->T[idx] = field->T[base + j * nx + (nx - 2)]; | ||
| } | ||
|
Comment on lines
+222
to
+229
|
||
| } | ||
|
|
||
| /* Right face (i=nx-1) */ | ||
| for (size_t k = 0; k < nz; k++) { | ||
| size_t base = k * plane; | ||
| for (size_t j = 0; j < ny; j++) { | ||
| size_t idx = base + j * nx + (nx - 1); | ||
| if (tbc->right == BC_TYPE_DIRICHLET) | ||
| field->T[idx] = tbc->dirichlet_values.right; | ||
| else if (tbc->right == BC_TYPE_NEUMANN) | ||
| field->T[idx] = field->T[idx - 1]; | ||
| else if (tbc->right == BC_TYPE_PERIODIC) | ||
| field->T[idx] = field->T[base + j * nx + 1]; | ||
| } | ||
| } | ||
|
|
||
| /* Bottom face (j=0) — runs after left/right, overwrites shared corners */ | ||
| for (size_t k = 0; k < nz; k++) { | ||
| size_t base = k * plane; | ||
| for (size_t i = 0; i < nx; i++) { | ||
| size_t idx = base + i; | ||
| if (tbc->bottom == BC_TYPE_DIRICHLET) | ||
| field->T[idx] = tbc->dirichlet_values.bottom; | ||
| else if (tbc->bottom == BC_TYPE_NEUMANN) | ||
| field->T[idx] = field->T[idx + nx]; | ||
shaia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| else if (tbc->bottom == BC_TYPE_PERIODIC) | ||
| field->T[idx] = field->T[base + (ny - 2) * nx + i]; | ||
| } | ||
| } | ||
|
|
||
| /* Top face (j=ny-1) */ | ||
| for (size_t k = 0; k < nz; k++) { | ||
| size_t base = k * plane; | ||
| for (size_t i = 0; i < nx; i++) { | ||
| size_t idx = base + (ny - 1) * nx + i; | ||
| if (tbc->top == BC_TYPE_DIRICHLET) | ||
| field->T[idx] = tbc->dirichlet_values.top; | ||
| else if (tbc->top == BC_TYPE_NEUMANN) | ||
| field->T[idx] = field->T[idx - nx]; | ||
| else if (tbc->top == BC_TYPE_PERIODIC) | ||
| field->T[idx] = field->T[base + nx + i]; | ||
| } | ||
| } | ||
|
|
||
| /* Back face (k=0) — only when nz > 1 */ | ||
| if (nz > 1) { | ||
| for (size_t j = 0; j < ny; j++) { | ||
| for (size_t i = 0; i < nx; i++) { | ||
| size_t idx = j * nx + i; | ||
shaia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (tbc->back == BC_TYPE_DIRICHLET) | ||
| field->T[idx] = tbc->dirichlet_values.back; | ||
| else if (tbc->back == BC_TYPE_NEUMANN) | ||
| field->T[idx] = field->T[plane + idx]; | ||
| else if (tbc->back == BC_TYPE_PERIODIC) | ||
| field->T[idx] = field->T[(nz - 2) * plane + idx]; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /* Front face (k=nz-1) — only when nz > 1 */ | ||
| if (nz > 1) { | ||
| size_t front_base = (nz - 1) * plane; | ||
| for (size_t j = 0; j < ny; j++) { | ||
| for (size_t i = 0; i < nx; i++) { | ||
| size_t off = j * nx + i; | ||
| if (tbc->front == BC_TYPE_DIRICHLET) | ||
| field->T[front_base + off] = tbc->dirichlet_values.front; | ||
| else if (tbc->front == BC_TYPE_NEUMANN) | ||
| field->T[front_base + off] = field->T[(nz - 2) * plane + off]; | ||
| else if (tbc->front == BC_TYPE_PERIODIC) | ||
| field->T[front_base + off] = field->T[plane + off]; | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header comment says PERIODIC “copies from the opposite interior cell”, but energy_apply_thermal_bcs applies faces sequentially and later faces overwrite edges/corners shared with earlier faces (and in 3D, back/front can overwrite entire planes). Consider documenting the precedence/order for edges/corners (or adjusting the implementation to make corner behavior independent of application order) so users don’t assume the periodic/Neumann rule holds universally at intersections.