Skip to content

feat: Add per-face thermal BC config to solver params#178

Open
shaia wants to merge 5 commits intomasterfrom
feat/thermal-bc-integration
Open

feat: Add per-face thermal BC config to solver params#178
shaia wants to merge 5 commits intomasterfrom
feat/thermal-bc-integration

Conversation

@shaia
Copy link
Copy Markdown
Owner

@shaia shaia commented Apr 4, 2026

Thermal boundary conditions (Dirichlet/Neumann) are now configured via ns_solver_params_t.thermal_bc instead of being applied manually by the caller. The solver applies them automatically after each energy step.

  • Add ns_thermal_bc_config_t with per-face bc_type_t + Dirichlet values
  • Add energy_apply_thermal_bcs() for 3D-aware thermal BC application
  • Remove save/restore T memcpy hack from explicit Euler, projection, RK2
  • Update natural convection test to use config-driven thermal BCs
  • Add unit tests for mixed Dirichlet/Neumann and all-periodic no-op

Thermal boundary conditions (Dirichlet/Neumann) are now configured via
ns_solver_params_t.thermal_bc instead of being applied manually by the
caller. The solver applies them automatically after each energy step.

- Add ns_thermal_bc_config_t with per-face bc_type_t + Dirichlet values
- Add energy_apply_thermal_bcs() for 3D-aware thermal BC application
- Remove save/restore T memcpy hack from explicit Euler, projection, RK2
- Update natural convection test to use config-driven thermal BCs
- Add unit tests for mixed Dirichlet/Neumann and all-periodic no-op
@shaia shaia requested a review from Copilot April 4, 2026 21:45
@shaia shaia self-assigned this Apr 4, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR moves thermal boundary condition (BC) handling into solver parameters (ns_solver_params_t.thermal_bc) and applies configured thermal BCs automatically within solver steps, eliminating the need for callers to manually set temperature boundaries each iteration.

Changes:

  • Introduces ns_thermal_bc_config_t (per-face Dirichlet/Neumann/Periodic) in ns_solver_params_t.
  • Adds energy_apply_thermal_bcs() and calls it from CPU solvers after the energy update.
  • Updates validation and unit tests to use config-driven thermal BCs (and adds new thermal BC unit tests).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
lib/include/cfd/solvers/navier_stokes_solver.h Adds ns_thermal_bc_config_t and embeds it into ns_solver_params_t.
lib/include/cfd/solvers/energy_solver.h Declares public energy_apply_thermal_bcs() API.
lib/src/solvers/energy/cpu/energy_solver.c Implements per-face thermal BC application (including 3D faces).
lib/src/solvers/navier_stokes/cpu/solver_explicit_euler.c Removes T save/restore hack; applies configured thermal BCs after periodic BC application.
lib/src/solvers/navier_stokes/cpu/solver_rk2.c Removes T save/restore hack; applies configured thermal BCs after periodic BC application.
lib/src/solvers/navier_stokes/cpu/solver_projection.c Applies configured thermal BCs after the energy step.
tests/validation/test_natural_convection.c Switches from manual temperature BC enforcement to params.thermal_bc; keeps velocity no-slip applied by the test.
tests/solvers/energy/test_energy_solver.c Adds unit tests for mixed Dirichlet/Neumann and all-periodic no-op behavior.
ROADMAP.md Updates backend coverage wording and documents current GPU backend limitations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

shaia added 4 commits April 7, 2026 20:34
Neumann BCs read from adjacent interior cells, which is out-of-bounds
when nx<2 or ny<2. Add early-return guards for undersized grids.

Periodic temperature BCs were previously a no-op, relying on the caller
to have already called apply_boundary_conditions(). This left periodic
temperature boundaries unenforced in the projection solver. Handle all
three BC types (Dirichlet, Neumann, Periodic) directly so the function
is self-contained across all solvers.
Exercises nz>1 code paths: Dirichlet on back face, Neumann on front
face, Periodic on left/right, and Dirichlet on bottom/top. Verifies
corner overwrite ordering and periodic copy from opposite interior.
Update all-periodic test to verify periodic copy behavior instead of
no-op (periodic now actively copies from opposite interior cells).

Fix 3D test: back/front faces run after bottom/top, so z-face BCs
overwrite corner intersections at k=0 and k=nz-1.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +198 to +216
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 = &params->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;
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

energy_apply_thermal_bcs() is exported but silently returns on invalid inputs (NULLs, alpha<=0, or too-small dimensions for the requested BC types). This makes misconfiguration hard to detect and is inconsistent with other energy APIs (e.g., energy_step_explicit_with_workspace) that return cfd_status_t and set an error. Consider returning cfd_status_t here (or at least calling cfd_set_error on invalid configs) so callers/solvers can surface actionable failures instead of quietly skipping BC application.

Copilot uses AI. Check for mistakes.
Comment on lines +222 to +229
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];
else if (tbc->left == BC_TYPE_PERIODIC)
field->T[idx] = field->T[base + j * nx + (nx - 2)];
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ns_thermal_bc_config_t uses bc_type_t, but energy_apply_thermal_bcs() only handles PERIODIC/NEUMANN/DIRICHLET; any other bc_type_t value will currently fall through and leave that face unchanged without warning. This can produce silently-wrong BCs if a caller accidentally sets BC_TYPE_NOSLIP/INLET/OUTLET/SYMMETRY. Consider validating that each face is one of the supported thermal types and treating any other value as CFD_ERROR_INVALID (or explicitly mapping unsupported values to PERIODIC).

Copilot uses AI. Check for mistakes.
Comment on lines +101 to +102
* Zero-initialization produces all-PERIODIC (BC_TYPE_PERIODIC == 0),
* preserving backward compatibility.
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs state that zero-initialization yields “all-PERIODIC … no change”, but with the new design the solver will actively enforce periodic temperature boundaries (and overwrite any caller-set boundary temperatures) unless thermal_bc is configured. Consider rewording this to clarify that {0} means “all PERIODIC (matches apply_boundary_conditions default)” rather than “no change”, and explicitly note that callers must set thermal_bc when they want non-periodic thermal walls.

Suggested change
* 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).

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +77
/**
* Apply thermal boundary conditions to the temperature field.
*
* For each face configured as DIRICHLET, sets T to the specified value.
* For each face configured as NEUMANN, copies from adjacent interior cell.
* For PERIODIC faces (default), copies from the opposite interior cell.
*
* Only active when params->alpha > 0. Returns immediately otherwise.
*
* @param field Flow field (T is updated in-place)
* @param params Solver parameters containing thermal_bc config
*/
CFD_LIBRARY_EXPORT void energy_apply_thermal_bcs(flow_field* field,
const ns_solver_params_t* params);
Copy link

Copilot AI Apr 7, 2026

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants