Port SolCx analytic Stokes solution (uw.function.analytic.SolCx)#223
Open
lmoresi wants to merge 1 commit into
Open
Port SolCx analytic Stokes solution (uw.function.analytic.SolCx)#223lmoresi wants to merge 1 commit into
lmoresi wants to merge 1 commit into
Conversation
Adds the classic Velic "SolCx" exact solution (free-slip, discontinuous viscosity step eta_A|eta_B at x_c, density forcing (0, cos(pi x) sin(n pi z))) as an analytic validation reference. Mirrors the existing AnalyticSolNL port: - solCx.c / solCx.h: verbatim Velic kernel (_Velic_solCx), pure self-contained C - AnalyticSolCx.c / .h: thin vec2-shape adapters around the kernel - analytic.pyx: AnalyticSolCx_velocity_x/y, _pressure, _viscosity wrappers (JIT-printable + evalf), plus a uw.function.analytic.SolCx(mesh, eta_A, eta_B, x_c, n) convenience exposing fn_velocity/pressure/viscosity/bodyforce and velocity_error(). Body-force sign matches UW3's momentum convention. - setup.py: build the new C sources into the analytic extension - tests/test_1015_analytic_solcx.py: binding + convergence-to-analytic (~4th order, rel 5.5e-7 at res 64) This establishes the reusable pattern for porting the remaining Velic solutions (SolKx, SolKz, SolDB, SolA/B/H, ...). It already caught a real trap: a direct ksponly+lu solve silently mis-solves the singular saddle on free-slip / pressure-nullspace problems; only the exact solution exposes it. Underworld development team with AI support from Claude Code
Contributor
There was a problem hiding this comment.
Pull request overview
Ports the classic Velic SolCx discontinuous-viscosity Stokes benchmark into underworld3.function.analytic by adding the upstream C kernel, thin UW3 adapters, Cython/SymPy wrappers, and a regression test that solves Stokes and checks convergence against the analytic solution.
Changes:
- Adds the verbatim Velic SolCx kernel (
solCx.c/.h) and UW3 adapter layer (AnalyticSolCx.c/.h). - Extends
underworld3.function.analytic(Cython) with SolCx wrappers and a Python convenience class (SolCx) exposing fields and an error metric. - Introduces a new test validating binding non-triviality and solver convergence (
tests/test_1015_analytic_solcx.py).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_1015_analytic_solcx.py | New regression test for SolCx binding + Stokes convergence vs analytic |
| src/underworld3/function/solCx.h | Declares Velic SolCx kernel entry points |
| src/underworld3/function/solCx.c | Adds the (verbatim) Velic SolCx analytic kernel implementation |
| src/underworld3/function/AnalyticSolCx.h | Declares UW3 adapter API for SolCx in vec2/scalar form |
| src/underworld3/function/AnalyticSolCx.c | Implements thin adapters around _Velic_solCx plus viscosity step helper |
| src/underworld3/function/analytic.pyx | Adds SolCx Cython bindings and Python convenience wrapper (SolCx) |
| setup.py | Includes new SolCx C sources in the analytic extension build |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self.fn_velocity = _sp.Matrix([AnalyticSolCx_velocity_x(*p, x, y), | ||
| AnalyticSolCx_velocity_y(*p, x, y)]) | ||
| self.fn_pressure = AnalyticSolCx_pressure(*p, x, y) | ||
| self.fn_viscosity = _sp.Piecewise((self.eta_B, x > self.x_c), (self.eta_A, True)) |
|
|
||
| # ---------------------------------------------------------------------------- | ||
| # SolCx: viscosity step in x (eta_A | eta_B at x_c), trigonometric density | ||
| # forcing f = (0, -cos(pi x) sin(n pi z)) on a unit box with free-slip walls. |
Comment on lines
+11
to
+13
| isoviscous step in x (eta_A for x<x_c, eta_B for x>x_c), trigonometric | ||
| density forcing f = (0, -cos(pi x) sin(n pi z)) on a unit box with | ||
| free-slip walls. The heavy lifting is the verbatim Velic kernel in solCx.c |
| const double pos[], | ||
| double _eta_A, double _eta_B, | ||
| double _x_c, int _n, | ||
| double vel[], double* presssure, |
| const double pos[], | ||
| double _eta_A, double _eta_B, /* Input parameters: density, viscosity A, viscosity B */ | ||
| double _x_c, int _n, /* Input parameters: viscosity jump location, wavenumber in x */ | ||
| double vel[], double* presssure, |
| const double pos[], | ||
| double _eta_A, double _eta_B, /* Input parameters: density, viscosity A, viscosity B */ | ||
| double _x_c, int _n, /* Input parameters: viscosity jump location, wavenumber in x */ | ||
| double vel[], double* presssure, |
| self.eta_A = float(eta_A) | ||
| self.eta_B = float(eta_B) | ||
| self.x_c = float(x_c) | ||
| self.n = int(n) |
| self.eta_B = float(eta_B) | ||
| self.x_c = float(x_c) | ||
| self.n = int(n) | ||
| x, y = mesh.X |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ports the classic Velic SolCx exact Stokes solution into
uw.function.analytic, giving UW3 an exact-solution reference for the canonical free-slip, discontinuous-viscosity benchmark (viscosity stepeta_A|eta_Batx_c, density forcing(0, cos(pi x) sin(n pi z)), free-slip walls).Mirrors the existing
AnalyticSolNLport and establishes the reusable pattern for the rest of the Velic suite.What's included
solCx.c/solCx.h— verbatim Velic kernel (_Velic_solCx), self-contained CAnalyticSolCx.c/.h— thinvec2-shape adaptersanalytic.pyx— raw wrappers (AnalyticSolCx_velocity_x/y,_pressure,_viscosity) plus auw.function.analytic.SolCx(mesh, eta_A, eta_B, x_c, n)convenience exposingfn_velocity/pressure/viscosity/bodyforceandvelocity_error()setup.py— builds the new C sources into the analytic extensiontests/test_1015_analytic_solcx.py— binding + convergence-to-analytic (~4th order, rel5.5e-7at res 64)Notes
fn_velocity/fn_pressurewrap the compiled kernel and are evaluated point-wise viaevalf(notlambdify-able) — usevelocity_error();fn_bodyforce/fn_viscosityare elementary and compile through the normal JIT path.Follow-up
Finalise the full analytic suite (SolKx, SolKz, SolDB2d/3d, SolA/B/H, ...) by the same mechanical pattern, each with a convergence test. Tracked in planning.
Underworld development team with AI support from Claude Code