geoid._project_spherical_harmonic_samples (postprocessing/geoid.py:240) computes the
harmonic coefficient by gathering every boundary coordinate and value to rank zero,
discarding the mesh connectivity, and re-deriving a triangulation of the point cloud
with scipy.spatial.ConvexHull(unit_coords, qhull_options="QJ"). It then integrates with
analytic spherical triangle areas and one-point centroid values.
The boundary facets already exist — it is the FE trace, and _desmear walks exactly
those facets a few modules away. uw.maths.BdIntegral already integrates over them
properly, through DMPlexComputeBdIntegral, with the real quadrature and no gather.
The coefficient is then just the projection onto the harmonic written in the FE inner
product the assembler already uses:
numerator = uw.maths.BdIntegral(mesh=mesh, fn=h.sym[0] * legendre, boundary=b).evaluate()
denominator = uw.maths.BdIntegral(mesh=mesh, fn=legendre**2, boundary=b).evaluate()
coefficient = sign * numerator / denominator
What is wrong with the current path
Measured
Zhong l=2 shell, same solves, coefficient three ways, relative error against the analytic
0.41920 (surface) / 0.77060 (CMB):
| cellSize |
0.25 |
0.20 |
0.16 |
0.13 |
| surface, ConvexHull |
0.0028 |
0.0001 |
0.0014 |
0.0013 |
| surface, BdIntegral |
0.0003 |
0.0014 |
0.0005 |
0.0008 |
| CMB, ConvexHull |
0.0041 |
0.0081 |
0.0059 |
0.0027 |
| CMB, BdIntegral |
0.0091 |
0.0098 |
0.0084 |
0.0037 |
| CMB, pointwise fit |
0.0313 |
0.0236 |
0.0188 |
0.0097 |
On accuracy the two integral arms are a wash — ConvexHull is slightly better at the
CMB, BdIntegral slightly better at the surface, neither converging cleanly. This is not
an accuracy argument and should not be sold as one. It is a correctness-of-construction
and portability argument: same answer, on the mesh we actually have, on any boundary
shape, without a gather or a joggle.
The third row is worth noting separately: both integral forms beat the pointwise harmonic
fit by 3-10x at coarse resolution, which is independent support for #414's advice to
steer consumers to integral/fitted quantities rather than sampled vertices.
Relation to #646
#646 adds boundary_normal_traction_integral, which contracts the assembled reaction
with the test function directly and needs no pointwise recovery at all. For a coefficient
that is better than either arm above, because it never forms a pointwise field. This
issue is about the path that remains when projection="centroid" — currently the
default. Between the two, _project_spherical_harmonic_samples looks retirable rather
than repairable.
Script: ~/+Simulations/topography_penalty_633/replace_convexhull.py
geoid._project_spherical_harmonic_samples(postprocessing/geoid.py:240) computes theharmonic coefficient by gathering every boundary coordinate and value to rank zero,
discarding the mesh connectivity, and re-deriving a triangulation of the point cloud
with
scipy.spatial.ConvexHull(unit_coords, qhull_options="QJ"). It then integrates withanalytic spherical triangle areas and one-point centroid values.
The boundary facets already exist — it is the FE trace, and
_desmearwalks exactlythose facets a few modules away.
uw.maths.BdIntegralalready integrates over themproperly, through
DMPlexComputeBdIntegral, with the real quadrature and no gather.The coefficient is then just the projection onto the harmonic written in the FE inner
product the assembler already uses:
What is wrong with the current path
only the boundary for a convex surface. An annulus arc, an internal boundary, or a
deformed free surface will silently get the wrong triangulation.
QJjoggles the input — it perturbs coordinates to break degeneracies. That is apoor foundation for a reproducible diagnostic.
reaction; the two disagree at O(h²), which is the chord-versus-arc family of Curved-boundary P2 VERTEX flux/traction values converge only slowly — document and steer consumers to midpoint/fitted quantities #414/CBF sigma_nn recovery on deformed/faceted boundaries: ~2.4% amplitude deficit (chord-vs-arc boundary mass suspected) #431.
scaling objection as boundary_flux 3D assembly gathers the full global boundary onto every rank (memory scaling) #408.
Measured
Zhong l=2 shell, same solves, coefficient three ways, relative error against the analytic
0.41920 (surface) / 0.77060 (CMB):
On accuracy the two integral arms are a wash — ConvexHull is slightly better at the
CMB, BdIntegral slightly better at the surface, neither converging cleanly. This is not
an accuracy argument and should not be sold as one. It is a correctness-of-construction
and portability argument: same answer, on the mesh we actually have, on any boundary
shape, without a gather or a joggle.
The third row is worth noting separately: both integral forms beat the pointwise harmonic
fit by 3-10x at coarse resolution, which is independent support for #414's advice to
steer consumers to integral/fitted quantities rather than sampled vertices.
Relation to #646
#646 adds
boundary_normal_traction_integral, which contracts the assembled reactionwith the test function directly and needs no pointwise recovery at all. For a coefficient
that is better than either arm above, because it never forms a pointwise field. This
issue is about the path that remains when
projection="centroid"— currently thedefault. Between the two,
_project_spherical_harmonic_sampleslooks retirable ratherthan repairable.
Script:
~/+Simulations/topography_penalty_633/replace_convexhull.py