Fix surface load overlap: apply all loads even when they share elements - #420
Merged
Conversation
Three defects made a model with more than one load solve the wrong problem, none of them with a word in the log. A load group's force vector is its TOTAL, but rebuildSurfaceLoads emitted one surface load per picked SELECTION, each carrying that full vector. A 1000 N load picked as three faces reached the engine as three 1000 N loads and pulled 3000 N, while the panel still said 1000 N. It now emits one load per group over the union of its selections — de-duplicated, so overlapping picks contribute their shared element faces once — and the engine spreads the total over the whole loaded region, the same total-sharing rule rebuildLoads already applied to a group's nodal selections. apply_surface_loads gave each load its own boundary attribute and tagged its elements in load order. A boundary element carries exactly one attribute, so wherever two loads covered the same element the later one overwrote the earlier one's tag, and the overwritten load then integrated over nothing and vanished: a pressure and a bolt force on one flange face produced the effect of whichever came last. Elements are now grouped by the SET of loads covering them, each distinct set gets one attribute, and a load's marker selects every attribute whose set contains it. The coupled shell/solid path pinned a non-zero prescribed displacement to zero — shell_core's fixed_dofs are homogeneous and it has no inhomogeneous counterpart — turning a displacement-driven model into an unloaded one that returns an all-zero field looking like a converged answer. It now refuses loudly and names the node, as the explicit-shell path already did. A load selecting both faces and edges is refused the same way: one total force has no meaningful split between a loaded area and a loaded edge. The crane-hook-shell example stored its per-face vector as the group's force and so shipped at twice its intended load; its generator now stores the sum, and the example is regenerated. Tests: multiple-loads.test.mjs drives the engine (disjoint, coincident, partially overlapping and force+pressure loads, checked against superposition, plus three Dirichlet groups with no load at all); test_multi_load.mjs pins the store payload. Both fail on the previous build. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MZrBVJ5aP53sqx3UBoFReo
|
|
Overall Grade |
Security Reliability Complexity Hygiene Coverage |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| Code coverage | Aug 6, 2026 5:16a.m. | Review ↗ | |
| Rust | Aug 6, 2026 5:16a.m. | Review ↗ | |
| JavaScript | Aug 6, 2026 5:16a.m. | Review ↗ | |
| C & C++ | Aug 6, 2026 5:16a.m. | Review ↗ |
Code Coverage Summary
| Language | Line Coverage (New Code) | Line Coverage (Overall) |
|---|---|---|
| Aggregate | 86.7% |
87.8% |
| Javascript | 86.7% |
87.8% |
➟ Additional coverage metrics may have been reported. See full coverage report ↗
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
Two DeepSource antipattern findings on the KOF-216 diff, both in strings: a template literal with nothing interpolated in coupledFixedDofs' refusal message, and a `+` concatenation inside the test helper's template. The assembled strings are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MZrBVJ5aP53sqx3UBoFReo
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
Fixes KOF-216: surface loads that overlap (share boundary elements) were silently dropped. The engine's
apply_surface_loadsassigned each load a unique boundary attribute and tagged its elements in load order. Since a boundary element carries exactly one attribute, a later load's tag overwrote an earlier one's, causing the overwritten load to integrate over zero area and vanish without warning.Example: two equal forces on the same flange face produced the deflection of one, with no error message.
Key Changes
engine/cpp/solve_mfem.cpp
tag_load_faces→collect_load_elements: returns the sorted, de-duplicated list of boundary elements a load covers, without tagging them yet.loads_of_bemap tracks which loads cover each boundary element.attr_of_setmap assigns one attribute per distinct covering set.integrate_marked_area(renamed fromintegrate_tagged_area).web/src/store/boundarySlice.ts (
rebuildSurfaceLoads)web/src/workers/solver.worker.ts (
distributeShellSurfaceLoad)examples/validation/multiple-loads.test.mjs (new)
web/tests/test_multi_load.mjs (new)
rebuildSurfaceLoadsfunction.examples/web-examples/generate-crane-shell.mjs
rebuildSurfaceLoadsbehavior.Notable Implementation Details
collect_load_elementssorts and de-duplicates the boundary elements a load covers, so overlapping selections within a group do not double-count shared faces.https://claude.ai/code/session_01MZrBVJ5aP53sqx3UBoFReo