Repository navigation
Add sparse meshless models (Faure et al. 2011); release 0.1.9 - #12
Merged
Merged
Conversation
… 2011) Implements "Sparse Meshless Models of Complex Deformable Solids" on triangle meshes with a per-element Young's modulus. A compliance-distance metric (Dijkstra over mesh edges weighted by length / E) drives farthest-point node placement with Lloyd relaxation, Voronoi labelling, and clamped-linear material-aware skinning weights W. sparse_lbs_jacobian assembles W into a sparse LBS subspace whose affine DOF ordering matches simkit.lbs_jacobian exactly; lbs_affine_coordinates gives the reduced coordinates of a global affine map for patch tests. Exports the public functions from simkit, adds tests (dense/sparse basis equivalence, partition of unity, interpolation at nodes, affine patch test, material adaptivity of node placement) and a changelog entry. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX
Follows SimKit's flat layout: each public function lives in a same-named
module and is re-exported from the package root, with helpers that nothing
else uses kept private in the module that owns them.
compliance_graph (+ _element_compliance)
compliance_distances
compliance_node_sampling (+ _farthest_point_in_compliance_metric,
_lloyd_relaxation)
voronoi_labels
voronoi_shape_functions
sparse_lbs_jacobian (+ _point_frame_jacobian, _affine_frame_jacobian)
lbs_affine_coordinates
sparse_meshless_methods_basis
sample_nodes is renamed compliance_node_sampling so it is descriptive in the
flat simkit namespace; element_compliance becomes a private helper. Every
public function has a NumPy-style docstring so the autoapi reference picks
it up. Tests are split one file per module with shared mesh fixtures in a
new tests/conftest.py. Bumps the version to 0.1.9 and finalises the
changelog entry.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX
Replaces the separate sparse_lbs_jacobian module with an optional sparse=False flag on lbs_jacobian. The dense path is unchanged; sparse=True assembles only the non-zeros of W into a csr_matrix with the identical DOF ordering. Point frames in sparse_meshless_methods_basis become the one-line kron(W, I). Tests for the sparse path move into test_lbs_jacobian.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX
The per-node tent radius (distance to the nearest other node) leaves vertices uncovered in soft regions thicker than the node spacing; the old rigid nearest-node fallback made the weights jump across the Voronoi frontier there, which locked the joints of a thick model. The radius is now max(r_node, d1 + d2) per vertex, so the paper's linear tents are kept wherever they cover and widened continuously elsewhere; the nearest node always carries at least half the weight, no vertex is uncovered, and the weights still interpolate the nodes exactly at support_scale = 1, which is now the default (1.25 cut the forced interpolation against wider tents and created the same kind of jump at node vertices). Tests cover linearity between two nodes, coverage of far vertices, continuity across a frontier with unequal node spacing, and the single node case. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX
mu was already forwarded to dirichlet_laplacian, which accepts one value per element; the signature and docstring only advertised a scalar. State the array form so heterogeneous (material-aware) eigenmodes are discoverable. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX
The coordinates that give every frame the same affine map are np.tile(np.c_[A, t].T.ravel(), k). Inline that in the tests and document it on lbs_jacobian instead of exporting a function for it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX
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
Implements Sparse Meshless Models of Complex Deformable Solids (Faure, Gilles, Bousquet, Pai, SIGGRAPH 2011) on triangle meshes with a per-element Young's modulus, following SimKit's flat one-function-per-module layout, and bumps the version to 0.1.9.
A compliance-distance metric (Dijkstra over mesh edges weighted by
length / E) drives control-node placement, a Voronoi partition and material-aware skinning weights, which are then assembled into a sparse linear-blend-skinning subspace via a newsparse=Trueflag on the existinglbs_jacobian.New public functions (each in its own module, exported from
simkit)compliance_graphlength / E(mean/min/maxedge aggregation)compliance_distancescompliance_node_samplingvoronoi_labelsvoronoi_shape_functionsW(Sec. 4.3)sparse_meshless_methods_basisThe coordinates that give every frame the same affine map
[A | t](the rest state, or a patch test) are the one-linernp.tile(np.c_[A, t].T.ravel(), k), documented onlbs_jacobian; no function is exported for it.Changed
lbs_jacobian(V, W, sparse=False)gains an optionalsparseflag. Withsparse=Trueit assembles only the non-zeros ofWand returns ascipy.sparse.csr_matrixwith the identical DOF ordering as the dense result. The default dense path is unchanged, and both paths accept dense or sparseW.skinning_eigenmodes(X, T, k, mu=...)now documents and tests its per-elementmu(it was already forwarded todirichlet_laplacian, but the signature and docstring said scalar). With the Lamémuof a heterogeneous model the eigenmodes are material-aware: nearly constant on stiff parts, varying in soft ones. On the tutorial's tentacle they reach 96% of the full gravity sag with 9 bones, so they are the natural accuracy baseline for the sparse model, which trades accuracy per DOF for locality (compact support, sparseB, interpolating nodes).Shape-function kernel (differs from the uploaded draft)
voronoi_shape_functionskeeps the paper's clamped-linear tents in compliance distance (radius = distance to the nearest other node, so two frames blend linearly across a joint), but the radius is widened per vertex tod1 + d2(the vertex's two nearest node distances) wherever the per-node radius would leave the vertex uncovered. The draft assigned such vertices rigidly to their nearest node, which made the weights jump across the Voronoi frontier in soft regions thicker than the node spacing and locked the joints of a thick model. The defaultsupport_scaleis now1.0: at1.25the forced exact interpolation at node vertices cut against the wider tents and produced the same kind of jump. On a 1.2-thick tentacle with 0.6-wide joints this raises the subspace's share of the full gravity sag from 44% to 62% at 9 frames and from 67% to 81% at 18.Helpers nothing else uses are private to the module that owns them (
_element_compliance,_farthest_point_in_compliance_metric,_lloyd_relaxation,_dense_lbs_jacobian,_sparse_lbs_jacobian), so they do not appear in the API reference.Tests
One test file per module plus a new
tests/conftest.pywith shared stiff-bar strip fixtures. Coverage includes:lbs_jacobian(sparse=True)equals the dense result to machine precision in 2D and 3D, for dense and sparseW, and its sparsity followsW[A | t]coordinates reproduceA x + ton the whole mesh through the full pipelineskinning_eigenmodeswith a per-elementmugives modes that are flat on the stiff half of a strip and vary on the soft halfFull suite: 635 passed, 5 skipped (optional deps).
python -m build+twine checkpass, andsphinx-buildgenerates an API page for each new module.Tutorial
Tutorial 026 in simkit-tutorials (on
main) walks through the pipeline on the tentacle and compares full FEM, uniform and material skinning eigenmodes and the sparse frames.Release
pyproject.tomlis bumped to 0.1.9 andCHANGELOG.mdgains the 0.1.9 section. Once this is merged, pushing thev0.1.9tag onmaintriggersrelease.ymland publishes to PyPI.🤖 Generated with Claude Code
https://claude.ai/code/session_01UGZcwqzGYGz9YtjzzdLtBX