Skip to content

Analytic SolCx: expose exact stress tensor (SolCx_stress)#226

Open
lmoresi wants to merge 1 commit into
developmentfrom
bugfix/analytic-solcx-stress
Open

Analytic SolCx: expose exact stress tensor (SolCx_stress)#226
lmoresi wants to merge 1 commit into
developmentfrom
bugfix/analytic-solcx-stress

Conversation

@lmoresi

@lmoresi lmoresi commented Jun 9, 2026

Copy link
Copy Markdown
Member

What

Expose the exact total (Cauchy) stress tensor from the Velic solCx analytic Stokes solution as SolCx_stress (a tensor2 of sigma_xx, sigma_zz, sigma_xz), with AnalyticSolCx_stress_{xx,yy,xy} sympy wrappers — mirroring the existing SolCx_pressure / SolCx_velocity adapters. The Velic kernel _Velic_solCx already fills total_stress; this just surfaces it.

The SolCx helper class gains fn_stress_{xx,yy,xy}, evaluate_stress(), and topography_top() (= -sigma_yy on the top boundary).

Why

The exact dynamic topography on a free-slip boundary is -n.sigma.n. Without this wrapper the only pure-Python route was a finite difference of v_y near the boundary — unreliable precisely there (v_y ≈ 0). SolCx_stress gives the exact normal stress directly. This is part of completing the analytic-solution suite (follows #223).

Validation

Extends tests/test_1015_analytic_solcx.py:

  • test_solcx_stress_binding — the kernel binding returns finite, non-trivial values.
  • test_solcx_stress_pressure_consistency — convention-independent check that the mean normal stress (sigma_xx+sigma_yy)/2 equals -p (since sigma = -p I + tau with tau traceless) to machine precision, validating the stress wrapper against the kernel's own pressure without assuming any UW3 sign convention.

All 4 tests in test_1015 pass. No setup.py change (sources already listed).

Underworld development team with AI support from Claude Code

The Velic solCx kernel already fills total_stress (sigma_xx, sigma_zz,
sigma_xz); expose it as a tensor2 SolCx_stress adapter (mirroring
SolCx_pressure/SolCx_velocity) with AnalyticSolCx_stress_{xx,yy,xy}
sympy wrappers. The SolCx helper gains fn_stress_{xx,yy,xy},
evaluate_stress(), and topography_top() (= -sigma_yy on the top
boundary) so the exact dynamic topography is available directly rather
than by an unreliable finite difference of v_y near a boundary where
v_y is approximately zero.

Regression tests (test_1015): stress binding is finite and non-trivial,
and a convention-independent consistency check that the mean normal
stress (sigma_xx+sigma_yy)/2 equals -p (sigma = -p I + tau, tau
traceless) at sample points - validating the stress wrapper against the
kernel's own pressure without assuming any UW3 sign convention.

Underworld development team with AI support from Claude Code
Copilot AI review requested due to automatic review settings June 9, 2026 02:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 exposes the Velic solCx analytic solution’s exact total (Cauchy) stress as a first-class wrapper (SolCx_stress + SymPy component adapters) and wires it into the Python-side SolCx helper so users can query stress (and dynamic topography on the top boundary) directly.

Changes:

  • Added a C adapter SolCx_stress() that returns the kernel’s total_stress as a tensor2 (xx, zz/yy, xz/xy).
  • Added Cython/SymPy wrappers AnalyticSolCx_stress_{xx,yy,xy} and extended SolCx with fn_stress_{xx,yy,xy}, evaluate_stress(), and topography_top().
  • Extended tests/test_1015_analytic_solcx.py with binding/consistency tests for the new stress wrapper.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
tests/test_1015_analytic_solcx.py Adds stress binding and pressure–stress consistency tests to validate the new wrapper.
src/underworld3/function/AnalyticSolCx.h Exposes the new SolCx_stress() API returning tensor2.
src/underworld3/function/AnalyticSolCx.c Implements SolCx_stress() by calling _Velic_solCx(... total_stress ...) and packing results into tensor2.
src/underworld3/function/analytic.pyx Adds Cython/SymPy stress component wrappers and new SolCx convenience members/methods.

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

Comment on lines +233 to +240
p = (self.eta_A, self.eta_B, self.x_c, self.n)
out = _np.empty((len(coords), 3))
for i in range(len(coords)):
xi = float(coords[i, 0]); yi = float(coords[i, 1])
out[i, 0] = float(AnalyticSolCx_stress_xx(*p, xi, yi).evalf())
out[i, 1] = float(AnalyticSolCx_stress_yy(*p, xi, yi).evalf())
out[i, 2] = float(AnalyticSolCx_stress_xy(*p, xi, yi).evalf())
return out
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