Skip to content

experimental/adrh: boundary kinds (prescribed inflow flux, weak Dirichlet IIPG/NIPG/SIPG) against Proteus - #96

Merged
cekees merged 2 commits into
mainfrom
adrh-boundary-kinds
Oct 24, 2026
Merged

cekees merged 2 commits into
mainfrom
adrh-boundary-kinds

Conversation

@cekees

@cekees cekees commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #91 (base adrh-engine); the design note's section 14 listed these as the next boundary kinds. Nothing outside experimental/adrh/ changes.

  • boundary.h: one exterior-face kernel, exteriorFaceKernel, with a BC functor returning a kind per component and boundary quadrature point: Strong (nothing on the face), Flux (prescribed diffusive flux; advective flux prescribed where given, else the interior f(u).n on outflow and zero on inflow, which is what StrongDirichlet's 'outFlow' does), WeakDirichlet (upwinded advective flux against f(g), -a grad phi.n + (C/h^p)(u - g) with h the face's longest edge, adjoint -sigma (u - g)(a^T n).grad w). WeakDirichletParams = C, p, sigma: 2/1/0 IIPG, 10/1/-1 NIPG, 100/1/+1 SIPG, Proteus's class defaults. The header comment maps each term to the Proteus routine it follows (calculateExteriorNumericalAdvectiveFlux, calculateExteriorNumericalDiffusiveFlux, updateExteriorElementBoundaryDiffusionAdjoint, computeGeometricInfo_tetrahedron for h) and names two deliberate differences: Proteus's adjoint contracts the tensor by its column sums (equal to (a^T n).grad w only for diagonal a), and its adjoint Jacobian ignores da/du. Neither shows with an isotropic constant a.
  • ad_regression.py: AD_BC=strong|mixed|inflow|iipg|nipg|sipg selects the treatment on both sides (ad_sine_p.py/ad_sine_n.py: StrongDirichletFactory with flux boundary conditions, or Advection_DiagonalUpwind_Diffusion_{IIPG,NIPG,SIPG}_exterior). Boundary faces are picked plane by plane, since a face with nodes on different planes is interior.

Engine vs Proteus nodal solutions on the same mesh, nn = 5 / 9 / 17 (max abs difference), and L2 rates:

mode max difference L2 rate (9, 17)
strong 5.6e-16 / 2.9e-15 / 4.1e-15 1.85, 1.97
mixed 1.3e-15 / 2.6e-15 / 3.4e-15 1.84, 1.96
inflow 1.8e-15 / 2.9e-15 / 3.7e-15 1.85, 1.97
iipg 8.9e-16 / 2.7e-15 / 4.4e-15 1.75, 1.90
nipg 2.0e-15 / 2.7e-15 / 6.0e-15 1.84, 1.96
sipg 2.2e-15 / 2.7e-15 / 7.1e-15 1.89, 1.97

compare_with_python.py and compare_masks.py are unchanged and still pass (7e-16 / 6e-16; chain nc=5 masked 6.8 us vs 172 us per element). Design note: ADRH_ENGINE_DESIGN.md section 15 (beside the campaign notes, not in this repo).


Second commit (400144d): 2D segments and Robin fluxes. exteriorFaceKernel is generic in Coefficients::nSpace (2 or 3): segments of triangles with the edge's perpendicular as normal and the edge length as the penalty's h, triangles of tetrahedra as before. The Flux kind's diffusive flux may be affine in the trace (gdiff + dgdiff u), which is what RobinFactory's alpha u + beta q.n = g amounts to, so Robin needed no new kind. ad_regression.py takes AD_ND=2|3 and a seventh mode AD_BC=robin (against RobinFactory(base=StrongDirichletFactory({0: 'outFlow'})), alpha, beta = 1, 2).

Engine vs Proteus, max nodal difference, all seven modes: 3D (nn 5/9/17) <= 7.1e-15; 2D (nn 9/17/33/65) <= 4.6e-14, growing with system size as the direct solves' round-off does. L2 rates 2.00 in 2D, 1.90-1.97 in 3D. Design note section 16.

🤖 Generated with Claude Code

…t IIPG/NIPG/SIPG) against Proteus

boundary.h has one exterior-face kernel, exteriorFaceKernel, and a BC functor that returns a
kind per component and quadrature point: Strong (nothing on the face), Flux (prescribed
diffusive flux; advective flux prescribed where given, else the interior f(u).n on outflow and
zero on inflow, as StrongDirichlet's 'outFlow' does) and WeakDirichlet (upwinded advective
flux against f(g), -a grad phi.n + (C/h^p)(u - g) with h the face's longest edge, and the
adjoint -sigma (u - g)(a^T n).grad w), each the engine's version of a Proteus exterior
numerical-flux treatment. WeakDirichletParams carries C, p, sigma (2/1/0 IIPG, 10/1/-1 NIPG,
100/1/+1 SIPG, Proteus's class defaults). The header's comment maps every term to the
Proteus routine it follows and names the two deliberate differences (the adjoint's tensor
contraction, da/du in the Jacobian), neither visible with an isotropic constant a.

ad_regression.py gets AD_BC=strong|mixed|inflow|iipg|nipg|sipg, with the Proteus side in
ad_sine_p.py/ad_sine_n.py (StrongDirichletFactory with flux boundary conditions, or
Advection_DiagonalUpwind_Diffusion_{IIPG,NIPG,SIPG}_exterior). Engine and Proteus nodal
solutions agree to 7e-15 or better in every mode at nn = 5, 9, 17; L2 rates 1.85-1.97.
Boundary faces are picked plane by plane: a face whose nodes lie on different planes is
interior.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Base automatically changed from adrh-engine to main October 23, 2026 14:40
…sion in 2D and 3D

exteriorFaceKernel is now generic in Coefficients::nSpace (2 or 3): a face is the nS nodes
other than the opposite one, the normal is the edge's perpendicular in 2D and the cross
product in 3D, the penalty's h is the longest face edge (the edge itself in 2D), and the
reference quadrature has nS - 1 coordinates. The Flux kind takes a diffusive flux affine in
the trace, gdiff + dgdiff u, which is what RobinFactory's alpha u + beta q.n = g amounts to
(q.n = g/beta - (alpha/beta) u, Jacobian -alpha/beta). AdvectionDiffusionSine and SineBC are
templates on the dimension; the module's advection_diffusion_sine and
advection_diffusion_sine_faces take nd first.

ad_regression.py: AD_ND=2|3, and a seventh mode AD_BC=robin (face x = 1 carries
alpha u + beta q.n = g with alpha, beta = 1, 2, against RobinFactory over
StrongDirichletFactory({0: 'outFlow'})). Engine and Proteus nodal solutions agree in all
seven modes: 3D (nn 5/9/17) to 7.1e-15, 2D (nn 9/17/33/65) to 4.6e-14; L2 rates 2.00 in 2D,
1.90-1.97 in 3D. Boundary faces are picked plane by plane with the plane count following nd.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cekees
cekees merged commit 96f7bf5 into main Oct 24, 2026
10 checks passed
@cekees
cekees deleted the adrh-boundary-kinds branch October 24, 2026 04:01
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.

1 participant