wobbl 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wobbl-0.1.0/.gitattributes +13 -0
- wobbl-0.1.0/.gitignore +38 -0
- wobbl-0.1.0/CHANGELOG.md +64 -0
- wobbl-0.1.0/LICENSE +21 -0
- wobbl-0.1.0/PKG-INFO +343 -0
- wobbl-0.1.0/README.md +311 -0
- wobbl-0.1.0/docs/agents.md +11 -0
- wobbl-0.1.0/docs/architecture.md +11 -0
- wobbl-0.1.0/docs/bakeoff.md +10 -0
- wobbl-0.1.0/docs/circuits.md +9 -0
- wobbl-0.1.0/docs/cli.md +10 -0
- wobbl-0.1.0/docs/fix.md +10 -0
- wobbl-0.1.0/docs/getting-started.md +15 -0
- wobbl-0.1.0/docs/heat.md +10 -0
- wobbl-0.1.0/docs/limits.md +10 -0
- wobbl-0.1.0/docs/publishing.md +47 -0
- wobbl-0.1.0/docs/strength.md +14 -0
- wobbl-0.1.0/docs/validation-results.json +337 -0
- wobbl-0.1.0/docs/validation.md +12 -0
- wobbl-0.1.0/docs/verification.md +12 -0
- wobbl-0.1.0/examples/battery-pack/README.md +24 -0
- wobbl-0.1.0/examples/battery-pack/output/outcome.json +143 -0
- wobbl-0.1.0/examples/battery-pack/output/summary.txt +27 -0
- wobbl-0.1.0/examples/battery-pack/pack.py +11 -0
- wobbl-0.1.0/examples/battery-pack/run.sh +7 -0
- wobbl-0.1.0/examples/cast-motor-mount/README.md +35 -0
- wobbl-0.1.0/examples/cast-motor-mount/output/geometry.json +22 -0
- wobbl-0.1.0/examples/cast-motor-mount/output/outcome.json +3055 -0
- wobbl-0.1.0/examples/cast-motor-mount/output/study.json +44 -0
- wobbl-0.1.0/examples/cast-motor-mount/output/summary.txt +31 -0
- wobbl-0.1.0/examples/cast-motor-mount/run.sh +10 -0
- wobbl-0.1.0/examples/circuits/README.md +19 -0
- wobbl-0.1.0/examples/circuits/buck/netlist.cir +12 -0
- wobbl-0.1.0/examples/circuits/buck/outcome.json +87 -0
- wobbl-0.1.0/examples/circuits/buck/summary.txt +20 -0
- wobbl-0.1.0/examples/circuits/led/netlist.cir +7 -0
- wobbl-0.1.0/examples/circuits/led/outcome.json +90 -0
- wobbl-0.1.0/examples/circuits/led/summary.txt +21 -0
- wobbl-0.1.0/examples/circuits/mosfet/netlist.cir +8 -0
- wobbl-0.1.0/examples/circuits/mosfet/outcome.json +76 -0
- wobbl-0.1.0/examples/circuits/mosfet/summary.txt +17 -0
- wobbl-0.1.0/examples/circuits/run.sh +10 -0
- wobbl-0.1.0/examples/drone-arm/README.md +34 -0
- wobbl-0.1.0/examples/drone-arm/arm.py +41 -0
- wobbl-0.1.0/examples/drone-arm/output/geometry.json +24 -0
- wobbl-0.1.0/examples/drone-arm/output/outcome.json +2057 -0
- wobbl-0.1.0/examples/drone-arm/output/study.json +62 -0
- wobbl-0.1.0/examples/drone-arm/output/summary.txt +32 -0
- wobbl-0.1.0/examples/drone-arm/run.sh +8 -0
- wobbl-0.1.0/examples/enclosure/README.md +26 -0
- wobbl-0.1.0/examples/enclosure/enclosure.py +45 -0
- wobbl-0.1.0/examples/enclosure/output/geometry.json +24 -0
- wobbl-0.1.0/examples/enclosure/output/outcome.json +3063 -0
- wobbl-0.1.0/examples/enclosure/output/study.json +40 -0
- wobbl-0.1.0/examples/enclosure/output/summary.txt +28 -0
- wobbl-0.1.0/examples/enclosure/run.sh +6 -0
- wobbl-0.1.0/examples/heat-sink/README.md +23 -0
- wobbl-0.1.0/examples/heat-sink/heatsink.py +21 -0
- wobbl-0.1.0/examples/heat-sink/output/outcome.json +152 -0
- wobbl-0.1.0/examples/heat-sink/output/summary.txt +24 -0
- wobbl-0.1.0/examples/heat-sink/run.sh +7 -0
- wobbl-0.1.0/examples/motor-mount/README.md +34 -0
- wobbl-0.1.0/examples/motor-mount/mount.py +40 -0
- wobbl-0.1.0/examples/motor-mount/output/geometry.json +24 -0
- wobbl-0.1.0/examples/motor-mount/output/outcome.json +1984 -0
- wobbl-0.1.0/examples/motor-mount/output/study.json +44 -0
- wobbl-0.1.0/examples/motor-mount/output/summary.txt +27 -0
- wobbl-0.1.0/examples/motor-mount/output-noribs/geometry.json +24 -0
- wobbl-0.1.0/examples/motor-mount/output-noribs/outcome.json +1752 -0
- wobbl-0.1.0/examples/motor-mount/output-noribs/study.json +46 -0
- wobbl-0.1.0/examples/motor-mount/output-noribs/summary.txt +33 -0
- wobbl-0.1.0/examples/motor-mount/run.sh +9 -0
- wobbl-0.1.0/examples/run_all.sh +8 -0
- wobbl-0.1.0/examples/shelf-bracket/README.md +32 -0
- wobbl-0.1.0/examples/shelf-bracket/bracket.py +31 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-fillet/geometry.json +24 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-fillet/outcome.json +980 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-fillet/study.json +48 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-fillet/summary.txt +27 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-gusset/geometry/gusset_t6.step +1258 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-gusset/geometry.json +24 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-gusset/outcome.json +1292 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-gusset/study.json +46 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-gusset/summary.txt +27 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-thicken/geometry.json +24 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-thicken/outcome.json +983 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-thicken/study.json +48 -0
- wobbl-0.1.0/examples/shelf-bracket/output/fix-thicken/summary.txt +27 -0
- wobbl-0.1.0/examples/shelf-bracket/output/geometry.json +24 -0
- wobbl-0.1.0/examples/shelf-bracket/output/outcome.json +1075 -0
- wobbl-0.1.0/examples/shelf-bracket/output/study.json +46 -0
- wobbl-0.1.0/examples/shelf-bracket/output/summary.txt +33 -0
- wobbl-0.1.0/examples/shelf-bracket/run.sh +9 -0
- wobbl-0.1.0/pyproject.toml +57 -0
- wobbl-0.1.0/src/wobbl/__init__.py +16 -0
- wobbl-0.1.0/src/wobbl/__main__.py +4 -0
- wobbl-0.1.0/src/wobbl/ask.py +177 -0
- wobbl-0.1.0/src/wobbl/circuits/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/circuits/run.py +270 -0
- wobbl-0.1.0/src/wobbl/circuits/templates.py +184 -0
- wobbl-0.1.0/src/wobbl/circuits/tools.py +93 -0
- wobbl-0.1.0/src/wobbl/cli/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/cli/admin.py +177 -0
- wobbl-0.1.0/src/wobbl/cli/circuits.py +73 -0
- wobbl-0.1.0/src/wobbl/cli/main.py +438 -0
- wobbl-0.1.0/src/wobbl/cli/thermal.py +90 -0
- wobbl-0.1.0/src/wobbl/cli/ui.py +93 -0
- wobbl-0.1.0/src/wobbl/fe.py +141 -0
- wobbl-0.1.0/src/wobbl/fix/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/fix/apply.py +245 -0
- wobbl-0.1.0/src/wobbl/fix/cad_edit.py +115 -0
- wobbl-0.1.0/src/wobbl/fix/suggest.py +178 -0
- wobbl-0.1.0/src/wobbl/geometry/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/geometry/cad.py +350 -0
- wobbl-0.1.0/src/wobbl/geometry/faces.py +426 -0
- wobbl-0.1.0/src/wobbl/geometry/parametric.py +92 -0
- wobbl-0.1.0/src/wobbl/geometry/remap.py +67 -0
- wobbl-0.1.0/src/wobbl/geometry/select.py +270 -0
- wobbl-0.1.0/src/wobbl/materials.py +251 -0
- wobbl-0.1.0/src/wobbl/mcp/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/mcp/server.py +136 -0
- wobbl-0.1.0/src/wobbl/mcp/tools.py +284 -0
- wobbl-0.1.0/src/wobbl/mesh/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/mesh/isolate.py +90 -0
- wobbl-0.1.0/src/wobbl/mesh/mesher.py +696 -0
- wobbl-0.1.0/src/wobbl/outcome_generic.py +94 -0
- wobbl-0.1.0/src/wobbl/report/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/report/html.py +129 -0
- wobbl-0.1.0/src/wobbl/report/render.py +348 -0
- wobbl-0.1.0/src/wobbl/setup/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/setup/agents.py +240 -0
- wobbl-0.1.0/src/wobbl/setup/installer.py +247 -0
- wobbl-0.1.0/src/wobbl/skill/SKILL.md +64 -0
- wobbl-0.1.0/src/wobbl/solvers/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/solvers/base.py +115 -0
- wobbl-0.1.0/src/wobbl/solvers/calculix.py +334 -0
- wobbl-0.1.0/src/wobbl/solvers/locate.py +73 -0
- wobbl-0.1.0/src/wobbl/solvers/ngspice.py +74 -0
- wobbl-0.1.0/src/wobbl/structural/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/structural/budget.py +56 -0
- wobbl-0.1.0/src/wobbl/structural/build.py +286 -0
- wobbl-0.1.0/src/wobbl/structural/hotspots.py +183 -0
- wobbl-0.1.0/src/wobbl/structural/outcome.py +493 -0
- wobbl-0.1.0/src/wobbl/structural/pipeline.py +58 -0
- wobbl-0.1.0/src/wobbl/structural/report.py +101 -0
- wobbl-0.1.0/src/wobbl/structural/run.py +719 -0
- wobbl-0.1.0/src/wobbl/structural/spec.py +248 -0
- wobbl-0.1.0/src/wobbl/thermal/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/thermal/study.py +502 -0
- wobbl-0.1.0/src/wobbl/thermal/tools.py +85 -0
- wobbl-0.1.0/src/wobbl/units.py +212 -0
- wobbl-0.1.0/src/wobbl/validation/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/validation/cases.py +342 -0
- wobbl-0.1.0/src/wobbl/validation/geometry.py +93 -0
- wobbl-0.1.0/src/wobbl/validation/parts/README.md +16 -0
- wobbl-0.1.0/src/wobbl/validation/parts/cast_motor_mount.step +7204 -0
- wobbl-0.1.0/src/wobbl/validation/parts/drone_arm_truss.step +7849 -0
- wobbl-0.1.0/src/wobbl/validation/parts/enclosure_shell.step +5548 -0
- wobbl-0.1.0/src/wobbl/validation/parts/shelf_bracket_fillet.step +812 -0
- wobbl-0.1.0/src/wobbl/validation/parts/shelf_bracket_sharp.step +812 -0
- wobbl-0.1.0/src/wobbl/verify/__init__.py +1 -0
- wobbl-0.1.0/src/wobbl/verify/beam.py +118 -0
- wobbl-0.1.0/src/wobbl/verify/checks.py +184 -0
- wobbl-0.1.0/tests/conftest.py +68 -0
- wobbl-0.1.0/tests/test_cli_mcp.py +115 -0
- wobbl-0.1.0/tests/test_e2e.py +240 -0
- wobbl-0.1.0/tests/test_geometry.py +123 -0
- wobbl-0.1.0/tests/test_heat_balance.py +58 -0
- wobbl-0.1.0/tests/test_parametric_fix.py +106 -0
- wobbl-0.1.0/tests/test_render_report.py +32 -0
- wobbl-0.1.0/tests/test_result_vtu.py +28 -0
- wobbl-0.1.0/tests/test_setup_agents.py +80 -0
- wobbl-0.1.0/tests/test_skill_commands.py +118 -0
- wobbl-0.1.0/tests/test_spec_ask.py +138 -0
- wobbl-0.1.0/tests/test_units_materials.py +92 -0
- wobbl-0.1.0/tests/test_verify.py +135 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Generated geometry and reports are data, not code
|
|
2
|
+
*.step binary
|
|
3
|
+
*.stp binary
|
|
4
|
+
*.stl binary
|
|
5
|
+
*.png binary
|
|
6
|
+
examples/**/report.html binary
|
|
7
|
+
docs/img/** binary
|
|
8
|
+
examples/**/outcome.json linguist-generated -diff
|
|
9
|
+
examples/**/study.json linguist-generated -diff
|
|
10
|
+
examples/**/geometry.json linguist-generated -diff
|
|
11
|
+
examples/**/summary.txt linguist-generated
|
|
12
|
+
examples/**/*.html linguist-generated -diff
|
|
13
|
+
examples/**/*.vtu binary
|
wobbl-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.coverage
|
|
9
|
+
htmlcov/
|
|
10
|
+
.DS_Store
|
|
11
|
+
|
|
12
|
+
# solver scratch output
|
|
13
|
+
wobbl-out/
|
|
14
|
+
*.frd
|
|
15
|
+
*.dat
|
|
16
|
+
*.sta
|
|
17
|
+
*.cvg
|
|
18
|
+
*.12d
|
|
19
|
+
spooles.out
|
|
20
|
+
*.vtu
|
|
21
|
+
|
|
22
|
+
# example runs keep their reports, summaries and images, not solver scratch
|
|
23
|
+
examples/**/work/
|
|
24
|
+
examples/**/*.npz
|
|
25
|
+
examples/**/*.brep
|
|
26
|
+
examples/**/geometry/*.json
|
|
27
|
+
examples/**/fix-*/report.html
|
|
28
|
+
|
|
29
|
+
# browser automation scratch
|
|
30
|
+
.playwright-cli/
|
|
31
|
+
|
|
32
|
+
# website build output (scripts/build_site.py)
|
|
33
|
+
_site/
|
|
34
|
+
|
|
35
|
+
# the website (Astro) builds into site/dist
|
|
36
|
+
site/node_modules/
|
|
37
|
+
site/dist/
|
|
38
|
+
site/.astro/
|
wobbl-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-10-13)
|
|
4
|
+
|
|
5
|
+
First release.
|
|
6
|
+
|
|
7
|
+
**Strength**
|
|
8
|
+
- STEP, IGES, BREP, STL and parametric `.py` parts, read through OpenCASCADE with
|
|
9
|
+
healing only when a solid is broken, touching bodies bonded, tiny faces removed.
|
|
10
|
+
- Second order tetrahedral meshes (gmsh) with feature sizing, hotspot refinement,
|
|
11
|
+
automatic fallbacks (another algorithm, straight sided elements, a finer size),
|
|
12
|
+
and every mesh attempt isolated in a child process with a timeout.
|
|
13
|
+
- Loads can be forces, pressures, bolt bearing, gravity, or remote forces and
|
|
14
|
+
moments through distributing (RBE3 style) or rigid couplings. Supports can be
|
|
15
|
+
fixed (in all or some directions), bolted holes with washer rings, rollers,
|
|
16
|
+
or wall contact solved by an active set loop with a coarse pre solve and warm
|
|
17
|
+
starts.
|
|
18
|
+
- A face selector language picks sides, planes, normals, holes and fillets by
|
|
19
|
+
size, nearest faces, spherical and box patches, and ids.
|
|
20
|
+
- 23 sourced materials, including sand cast A356-T6, plus custom properties.
|
|
21
|
+
Each material says how it is made (printed, molded, cast or wrought), so its
|
|
22
|
+
assumptions fit, and printed parts can be checked across layers.
|
|
23
|
+
- A `bearing` keyword for a bolt or pin pressing on one side of a hole, as in
|
|
24
|
+
`--load "300 N -x bearing @ hole d=6.6"`. Without it the force spreads evenly
|
|
25
|
+
over the hole faces.
|
|
26
|
+
|
|
27
|
+
**Verification on every answer**
|
|
28
|
+
- Mesh convergence over at least three meshes, force and moment balance, a beam
|
|
29
|
+
theory hand calculation through the critical section, singularity detection
|
|
30
|
+
from exact CAD geometry, bolt bearing, units and deflection sanity, a large
|
|
31
|
+
deflection re-solve when a part bends a good fraction of its wall, and the
|
|
32
|
+
spread between rigid and distributed load attachment.
|
|
33
|
+
- Confidence (high, medium, low) with reasons, and never high after a failed
|
|
34
|
+
check.
|
|
35
|
+
- The same input gives the same numbers on every run, because meshing runs on
|
|
36
|
+
one thread with a fixed seed and every size comes from the CAD. When the
|
|
37
|
+
rigid and distributed load attachments disagree, the other one is converged
|
|
38
|
+
at its own peak before it is quoted.
|
|
39
|
+
- Bounded runtime, so the last finished level is returned when time or a
|
|
40
|
+
solver runs out.
|
|
41
|
+
|
|
42
|
+
**Seeing and fixing**
|
|
43
|
+
- Heatmaps with the failure point marked (VTK off screen, matplotlib fallback),
|
|
44
|
+
convergence plots, plain text summaries and a self contained HTML report.
|
|
45
|
+
- Fix suggestions with numbers. Fillets and gussets are applied to any STEP
|
|
46
|
+
through OpenCASCADE, along with thickness and fillet parameters of parametric
|
|
47
|
+
parts and material swaps, and each one is simulated again for a before and
|
|
48
|
+
after table.
|
|
49
|
+
|
|
50
|
+
**Heat and circuits**
|
|
51
|
+
- Steady and transient conduction with convection, radiation, heat sources and
|
|
52
|
+
held temperatures, with an energy balance on steady and transient runs and
|
|
53
|
+
lumped hand calculations.
|
|
54
|
+
- ngspice checks for LEDs, RC networks, buck converter ripple and MOSFET junction
|
|
55
|
+
temperature, plus arbitrary netlists, with textbook and time step checks.
|
|
56
|
+
|
|
57
|
+
**Agents**
|
|
58
|
+
- `wobbl setup` installs CalculiX and ngspice into `~/.wobbl` with a pinned
|
|
59
|
+
micromamba and registers an MCP server and skill for Claude Code, Codex, Cursor
|
|
60
|
+
and Gemini CLI, with backups and `wobbl uninstall`. A test parses every
|
|
61
|
+
command in the skill against the real CLI.
|
|
62
|
+
- A validation suite of 18 cases, with textbook solutions, NAFEMS LE1 and LE10,
|
|
63
|
+
and five real parts against converged reference models. It runs in about
|
|
64
|
+
30 minutes on a 2018 six core laptop.
|
wobbl-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sohan Bhat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wobbl-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: wobbl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Simulate anything before you build it. Verified engineering simulation for AI coding agents and humans.
|
|
5
|
+
Project-URL: Homepage, https://github.com/sohan-bhat/wobbl
|
|
6
|
+
Project-URL: Issues, https://github.com/sohan-bhat/wobbl/issues
|
|
7
|
+
Author: Sohan Bhat
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: cad,calculix,engineering,fea,gmsh,mcp,ngspice,simulation
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Manufacturing
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: click>=8.1
|
|
20
|
+
Requires-Dist: gmsh>=4.11
|
|
21
|
+
Requires-Dist: matplotlib>=3.7
|
|
22
|
+
Requires-Dist: mcp>=1.2
|
|
23
|
+
Requires-Dist: numpy>=1.24
|
|
24
|
+
Requires-Dist: pyvista>=0.43
|
|
25
|
+
Requires-Dist: rich>=13
|
|
26
|
+
Requires-Dist: scipy>=1.10
|
|
27
|
+
Requires-Dist: tomli>=2; python_version < '3.11'
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest-timeout>=2; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
<a href="https://sohan-bhat.github.io/wobbl/">
|
|
35
|
+
<picture>
|
|
36
|
+
<source media="(prefers-color-scheme: dark)" srcset="site/assets/logo-dark.svg">
|
|
37
|
+
<img alt="Wobbl" src="site/assets/logo-light.svg" width="280">
|
|
38
|
+
</picture>
|
|
39
|
+
</a>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<strong>Simulate anything before you build it.</strong><br>
|
|
44
|
+
Verified strength, heat and circuit simulation for coding agents and the people who design physical things.
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<a href="https://github.com/sohan-bhat/wobbl/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/sohan-bhat/wobbl/actions/workflows/ci.yml/badge.svg"></a>
|
|
49
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/github/license/sohan-bhat/wobbl"></a>
|
|
50
|
+
<a href="pyproject.toml"><img alt="Python 3.10 or newer" src="https://img.shields.io/badge/python-3.10%2B-3776ab"></a>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<a href="https://sohan-bhat.github.io/wobbl/">Website</a> |
|
|
55
|
+
<a href="https://sohan-bhat.github.io/wobbl/get-started/">Getting started</a> |
|
|
56
|
+
<a href="https://sohan-bhat.github.io/wobbl/guides/">Guides</a> |
|
|
57
|
+
<a href="https://sohan-bhat.github.io/wobbl/guides/cli/">CLI reference</a> |
|
|
58
|
+
<a href="https://sohan-bhat.github.io/wobbl/examples/">Examples</a>
|
|
59
|
+
</p>
|
|
60
|
+
|
|
61
|
+

|
|
62
|
+
|
|
63
|
+
<p align="center"><sub>A real Wobbl output, a sand cast motor mount under a 2 kN belt pull, with the peak of 124 MPa at the rib tip and a safety factor of 1.33 against a target of 2.</sub></p>
|
|
64
|
+
|
|
65
|
+
## What it is
|
|
66
|
+
|
|
67
|
+
Wobbl is a command line tool, an MCP server and an agent skill that run real
|
|
68
|
+
engineering solvers and check every answer before anyone acts on it. Point it at
|
|
69
|
+
a STEP, IGES, STL or parametric Python part, ask a question in plain words or
|
|
70
|
+
with explicit loads and supports, and you get back the number, where it happens,
|
|
71
|
+
a confidence level with its reasons, the assumptions, a heatmap with the failure
|
|
72
|
+
point marked and fixes with numbers.
|
|
73
|
+
|
|
74
|
+
- Strength with [CalculiX](http://www.calculix.de), on second order tetrahedral
|
|
75
|
+
meshes from [gmsh](https://gmsh.info) and OpenCASCADE that are refined around the
|
|
76
|
+
peaks until the stress settles.
|
|
77
|
+
- Heat, steady and transient, also with CalculiX.
|
|
78
|
+
- Circuits with [ngspice](https://ngspice.sourceforge.io), for LEDs, RC networks,
|
|
79
|
+
buck converters, MOSFETs or any netlist.
|
|
80
|
+
|
|
81
|
+
`wobbl fix --apply` edits the part, adding fillets and gussets to any STEP file,
|
|
82
|
+
and runs the whole study again. The same tools work from your terminal and from
|
|
83
|
+
Claude Code, Codex, Cursor and Gemini CLI.
|
|
84
|
+
|
|
85
|
+
## Quick start
|
|
86
|
+
|
|
87
|
+
Wobbl needs Python 3.10 or newer, and until it is on PyPI you install it from GitHub.
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
pipx install "git+https://github.com/sohan-bhat/wobbl"
|
|
91
|
+
# or: uv tool install "git+https://github.com/sohan-bhat/wobbl"
|
|
92
|
+
|
|
93
|
+
wobbl setup # solvers into ~/.wobbl, MCP server and skill for your agents
|
|
94
|
+
wobbl doctor # check every piece
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`wobbl setup` downloads a pinned micromamba and installs the solvers from
|
|
98
|
+
conda-forge into `~/.wobbl` (about 340 MB, no admin rights). Use
|
|
99
|
+
`wobbl setup --no-agents` for solvers only, or `--agents claude,cursor` to pick.
|
|
100
|
+
|
|
101
|
+
This first answer needs no files.
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
wobbl "will a blue LED on 5V with a 47 ohm resistor fry?"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Then try your own part.
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
# holes, fillets, sharp corners and face ids
|
|
111
|
+
wobbl inspect part.step
|
|
112
|
+
|
|
113
|
+
# ask in plain words, or give the material, supports and loads yourself
|
|
114
|
+
wobbl part.step "will this 6061 bracket yield under 50 lbf at the tip?"
|
|
115
|
+
wobbl run part.step -m petg --fix "bolt holes d=5.5" \
|
|
116
|
+
--load "250 N down at 0,-15,31 @ holes d=3.4 rigid"
|
|
117
|
+
|
|
118
|
+
# build the fixes (fillets, gussets, thicker walls) and run each again
|
|
119
|
+
wobbl fix wobbl-out/part --apply
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Or run a bundled example, which takes a few minutes.
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
git clone https://github.com/sohan-bhat/wobbl
|
|
126
|
+
cd wobbl/examples/shelf-bracket && ./run.sh
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
| Platform | CalculiX | ngspice |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| macOS Apple Silicon | native | Intel build under Rosetta 2 |
|
|
132
|
+
| macOS Intel | native | native |
|
|
133
|
+
| Linux x86_64 | native | native |
|
|
134
|
+
| Linux arm64 | native | not packaged, so install it with your package manager and Wobbl finds it |
|
|
135
|
+
| Windows x64 | native | native |
|
|
136
|
+
|
|
137
|
+
## Example output
|
|
138
|
+
|
|
139
|
+
This is a printed PLA shelf bracket, screwed to a wall and carrying its share of
|
|
140
|
+
an 8 kg shelf. Every run writes `summary.txt`, which is what an agent reads, along
|
|
141
|
+
with `report.html`, `outcome.json`, heatmaps and `result.vtu` for ParaView.
|
|
142
|
+
|
|
143
|
+
```console
|
|
144
|
+
$ cd examples/shelf-bracket
|
|
145
|
+
$ wobbl run bracket.py -m pla --fix "bolt holes d=4.5" --fix "wall x=min" \
|
|
146
|
+
--load "40 N down @ top and within 12 of 65,12.5,6" -o output
|
|
147
|
+
$ cat output/summary.txt
|
|
148
|
+
FAILS. Peak 52.3 MPa on the 0.5 mm inside fillet (face 3) at (6.19, 12.6, 6.11). The part cracks at about 0.96x this load.
|
|
149
|
+
|
|
150
|
+
Confidence: high. passed mesh convergence, force balance, hand calculation, singularities, bolt bearing, units and sanity
|
|
151
|
+
Max deflection 3.47 mm at (90, 0, 6).
|
|
152
|
+
|
|
153
|
+
Checks:
|
|
154
|
+
[pass] mesh convergence: max principal stress settled: 43 -> 50.9 -> 53 -> 52.3 MPa over 4 meshes, last change 1.4%
|
|
155
|
+
[pass] force balance: reactions balance the loads to 0.00014% (forces) and 8.4e-06% (moments)
|
|
156
|
+
[pass] hand calculation: beam theory through the critical section gives 15.2 MPa nominal; FEA peak is 3.45x that, a stress concentration of about 3.4 from the local shape
|
|
157
|
+
[pass] singularities: no sharp corner or support artifact is above the reported stress
|
|
158
|
+
[pass] bolt bearing: worst hole of fix1 (d 4.5 mm) carries 2.7 N sideways and 45.7 N along its axis; bearing stress 0.1 MPa, safety factor 499.33 on bearing
|
|
159
|
+
[pass] units and sanity: part 123 mm across, peak strain 0.015, max deflection 3.47 mm (2.8% of size): all plausible
|
|
160
|
+
|
|
161
|
+
Suggested fixes:
|
|
162
|
+
- Stress piles up in the 0.5 mm fillet. A fillet of 3 mm (about half the 6 mm wall) spreads it out. ...
|
|
163
|
+
- The peak sits where two walls meet and bend. A gusset as thick as the wall ...
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`wobbl fix output --apply` then builds each fix and solves it again.
|
|
167
|
+
|
|
168
|
+
| Version | Peak stress | Safety factor (PLA, 50 MPa) | Verdict |
|
|
169
|
+
|---|---|---|---|
|
|
170
|
+
| As drawn, 0.5 mm corner | 52.3 MPa | 0.96 | fails |
|
|
171
|
+
| 3 mm fillet | 24.1 MPa | 2.08 | marginal (target 2.5) |
|
|
172
|
+
| Legs thickened to 10 mm | 21.0 MPa | 2.38 | marginal |
|
|
173
|
+
| Gusset across the corner | 9.82 MPa | 5.09 | holds |
|
|
174
|
+
|
|
175
|
+
<p>
|
|
176
|
+
<img alt="The bracket as drawn, with a thin line of high stress along the 0.5 mm inside corner peaking at 52.3 MPa" src="examples/shelf-bracket/output/images/stress.png" width="49%">
|
|
177
|
+
<img alt="The bracket with a gusset, where the peak drops to 9.82 MPa near the gusset toe" src="examples/shelf-bracket/output/fix-gusset/images/stress.png" width="49%">
|
|
178
|
+
</p>
|
|
179
|
+
|
|
180
|
+
## An agent on its own versus Wobbl
|
|
181
|
+
|
|
182
|
+
Given a CAD file, a strength question and 15 minutes, a capable coding agent
|
|
183
|
+
working alone answered in 1 of 10 trials across six
|
|
184
|
+
parts. Its hand calculations on beam like parts were good, within 1 to 5%. On the
|
|
185
|
+
ribbed cast motor mount and the thin walled enclosure, the two parts that
|
|
186
|
+
actually fail, it delivered nothing in six trials, because it kept writing its own
|
|
187
|
+
finite element code and hitting the same traps, such as meshers folding thin curved
|
|
188
|
+
walls, singular peaks at bonded bolts and load idealizations that flip the verdict.
|
|
189
|
+
|
|
190
|
+
Wobbl answers the same parts in minutes and handles each of those traps by default.
|
|
191
|
+
|
|
192
|
+
| Part | Converged reference | Wobbl | Confidence |
|
|
193
|
+
|---|---|---|---|
|
|
194
|
+
| Cast motor mount, belt pull through four bolts | 124.3 MPa at the rib tip | 123.7 MPa, same spot | medium, because the verdict flips if the servo is treated as rigid (55.0 versus 124 MPa), and Wobbl says so |
|
|
195
|
+
| ABS enclosure shell pressed near a corner | 93 MPa, 1.93 mm deflection | 93.0 MPa, 1.92 mm | medium, because large deflection theory lowers the peak 11%, and Wobbl says so |
|
|
196
|
+
| PA12 truss drone arm, thrust and torque | 11.5 MPa, 4.09 mm rise | 11.49 MPa, 4.08 mm | high |
|
|
197
|
+
| PLA bracket, sharp inside corner | about 78 MPa | 80.5 MPa | high |
|
|
198
|
+
|
|
199
|
+
The full comparison, with times and every trap, is [on the website](https://sohan-bhat.github.io/wobbl/validation/bakeoff/).
|
|
200
|
+
|
|
201
|
+
## Using it from agents
|
|
202
|
+
|
|
203
|
+
`wobbl setup` registers an MCP server and installs a skill for every coding
|
|
204
|
+
agent it finds, backing up each file it touches. `wobbl uninstall` removes
|
|
205
|
+
exactly what it added.
|
|
206
|
+
|
|
207
|
+
| Agent | MCP server | Skill or context |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| Claude Code | `claude mcp add --scope user wobbl` | `~/.claude/skills/wobbl/SKILL.md` |
|
|
210
|
+
| Codex | `[mcp_servers.wobbl]` in `~/.codex/config.toml` | `~/.codex/skills/wobbl/SKILL.md` |
|
|
211
|
+
| Cursor | `mcpServers.wobbl` in `~/.cursor/mcp.json` | `~/.cursor/skills/wobbl/SKILL.md` |
|
|
212
|
+
| Gemini CLI | extension at `~/.gemini/extensions/wobbl/` | `WOBBL.md` in the same extension |
|
|
213
|
+
|
|
214
|
+
The agent gets 13 tools, `inspect_geometry`, `mesh`, `new_study`,
|
|
215
|
+
`set_material`, `apply_load`, `add_fixture`, `solve_structural`, `verify`,
|
|
216
|
+
`render`, `suggest_fix`, `solve_thermal`, `solve_circuit` and `list_materials`.
|
|
217
|
+
Results are compact JSON with image and report paths. The skill teaches the
|
|
218
|
+
workflow and what never to skip, which means reading the checks before the number,
|
|
219
|
+
never quoting an excluded peak and making the supports match the real build.
|
|
220
|
+
|
|
221
|
+
```text
|
|
222
|
+
> Will this printed PLA shelf bracket hold its share of an 8 kg shelf?
|
|
223
|
+
|
|
224
|
+
agent: solve_structural(path="bracket.py", material="pla",
|
|
225
|
+
fixtures=["bolt holes d=4.5", "wall x=min"],
|
|
226
|
+
loads=["40 N down @ top and within 12 of 65,12.5,6"])
|
|
227
|
+
verdict fails, 52.3 MPa on the 0.5 mm inside fillet, safety factor 0.96, confidence high
|
|
228
|
+
agent: suggest_fix(result_dir, apply=true)
|
|
229
|
+
3 mm fillet 24.1 MPa (2.08), legs at 10 mm 21 MPa (2.38), gusset 9.82 MPa (5.09)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Strength studies take one to seven minutes on a 2018 laptop. Each agent's setup, the
|
|
233
|
+
timeouts and every tool are [on the website](https://sohan-bhat.github.io/wobbl/guides/agents/).
|
|
234
|
+
|
|
235
|
+
## What it checks
|
|
236
|
+
|
|
237
|
+
Every strength answer runs these checks and turns them into a confidence level,
|
|
238
|
+
high, medium or low, always with the reasons. A result that failed a check is
|
|
239
|
+
never reported as high confidence.
|
|
240
|
+
|
|
241
|
+
- Mesh convergence over at least three meshes, refined around the peaks that matter.
|
|
242
|
+
- Force and moment balance, with the reactions cancelling the loads to 0.5%.
|
|
243
|
+
- A hand calculation with beam theory through the critical section, and a check that the stress concentration is physical.
|
|
244
|
+
- Singularities, with sharp inside corners found from exact CAD normals and the peaks there and at idealized supports excluded, named and tracked.
|
|
245
|
+
- Load introduction, where off part loads are solved both rigid and distributed, each converged at its own peak, and the spread is reported.
|
|
246
|
+
- Bolt bearing at bolted holes, in place of the idealized peak.
|
|
247
|
+
- Units and sanity for the part size, peak strain and deflection.
|
|
248
|
+
- Large deflection, a nonlinear re-solve when the part bends a good fraction of its wall.
|
|
249
|
+
|
|
250
|
+
Heat answers check energy balance and a lumped hand calculation, and circuit
|
|
251
|
+
answers are compared with the textbook and run again at half the time step. Every
|
|
252
|
+
study has a time budget, and when it runs out the last finished mesh level comes
|
|
253
|
+
back with its checks. The same input gives the same answer on every run, because
|
|
254
|
+
meshing, wall thickness sampling and the budget are all deterministic. The website
|
|
255
|
+
explains every [check](https://sohan-bhat.github.io/wobbl/guides/results/checks/) and how the
|
|
256
|
+
[confidence](https://sohan-bhat.github.io/wobbl/guides/results/confidence/) is set.
|
|
257
|
+
|
|
258
|
+
## Validation
|
|
259
|
+
|
|
260
|
+
Eighteen cases with known answers run through the same pipeline you get. Every
|
|
261
|
+
case passes its tolerance, and every case whose reference is exact for the
|
|
262
|
+
modeled setup lands within 2%.
|
|
263
|
+
|
|
264
|
+
| Group | Cases | Largest error |
|
|
265
|
+
|---|---|---|
|
|
266
|
+
| Textbook and benchmark strength (Timoshenko, Kirsch, Lame, NAFEMS LE1 and LE10, torsion, self weight) | 8 | 1.54%, plate with a hole |
|
|
267
|
+
| Real parts against converged reference models | 5 | 4.26%, PLA bracket with a 6 mm fillet |
|
|
268
|
+
| Heat (slab conduction, lumped cooling) | 2 | 0.44% |
|
|
269
|
+
| Circuits (LED, RC, buck ripple) | 3 | 7.70%, buck ripple against an ideal formula that ignores switch and diode drops |
|
|
270
|
+
|
|
271
|
+
The full table is [on the website](https://sohan-bhat.github.io/wobbl/validation/). Run it yourself with
|
|
272
|
+
`wobbl validate`, which takes about 30 minutes.
|
|
273
|
+
|
|
274
|
+
## Examples
|
|
275
|
+
|
|
276
|
+
Each folder in [`examples/`](examples) is a real product with its real outputs, the
|
|
277
|
+
reports, heatmaps and summaries, and each has a page [on the website](https://sohan-bhat.github.io/wobbl/examples/).
|
|
278
|
+
|
|
279
|
+
| Example | Question | Domain |
|
|
280
|
+
|---|---|---|
|
|
281
|
+
| [cast-motor-mount](examples/cast-motor-mount) | Does a cast motor mount meet a safety factor of 2 under a 2 kN belt pull? | strength, remote loads |
|
|
282
|
+
| [shelf-bracket](examples/shelf-bracket) | Does a printed PLA bracket hold an 8 kg shelf, and what fixes it? | strength, fixes |
|
|
283
|
+
| [motor-mount](examples/motor-mount) | Do the ribs on a printed NEMA 17 mount earn their keep? | strength |
|
|
284
|
+
| [enclosure](examples/enclosure) | Does a PC enclosure survive a thumb press, and how far does it dent? | strength, thin walls |
|
|
285
|
+
| [drone-arm](examples/drone-arm) | Is a PA12 drone arm strong enough at full throttle? | strength, rigid loads |
|
|
286
|
+
| [heat-sink](examples/heat-sink) | Does a 15 W chip stay under 85 C without a fan? | heat |
|
|
287
|
+
| [battery-pack](examples/battery-pack) | When does a pack in a sealed box pass 60 C? | transient heat |
|
|
288
|
+
| [circuits](examples/circuits) | Will this LED fry? What is the ripple? How hot is the MOSFET? | circuits |
|
|
289
|
+
|
|
290
|
+
Each folder has a `run.sh` that regenerates its outputs.
|
|
291
|
+
|
|
292
|
+
## Documentation
|
|
293
|
+
|
|
294
|
+
- [Getting started](https://sohan-bhat.github.io/wobbl/get-started/), to install, set up and run a first study
|
|
295
|
+
- [Guides](https://sohan-bhat.github.io/wobbl/guides/) for strength, heat and circuits, the inputs, the results and fixing parts
|
|
296
|
+
- [CLI reference](https://sohan-bhat.github.io/wobbl/guides/cli/) with every command and option
|
|
297
|
+
- [Agents and MCP](https://sohan-bhat.github.io/wobbl/guides/agents/) with what `wobbl setup` registers, the 13 tools and the skill
|
|
298
|
+
- [How it checks itself](https://sohan-bhat.github.io/wobbl/guides/results/checks/), every check and what sets the confidence
|
|
299
|
+
- [Validation](https://sohan-bhat.github.io/wobbl/validation/), the 18 cases and their setups
|
|
300
|
+
- [Bake-off](https://sohan-bhat.github.io/wobbl/validation/bakeoff/), a coding agent on its own versus Wobbl
|
|
301
|
+
- [Contributing](https://sohan-bhat.github.io/wobbl/get-started/contributing/), with the architecture and how a new solver plugs in
|
|
302
|
+
- [Publishing](docs/publishing.md), the release steps for PyPI
|
|
303
|
+
- [Changelog](CHANGELOG.md)
|
|
304
|
+
|
|
305
|
+
## Limits
|
|
306
|
+
|
|
307
|
+
- Materials are linear elastic, so Wobbl reports whether yield is reached but not
|
|
308
|
+
what happens after, and large deflection is checked with a nonlinear re-solve.
|
|
309
|
+
- Loads are static, and fatigue, impact and vibration are not modeled yet.
|
|
310
|
+
- Contact is limited to rigid walls the part can push on but not pull, and bolted
|
|
311
|
+
joints are modeled as clamped holes without preload.
|
|
312
|
+
- Each study uses one material, and assemblies of touching bodies are bonded.
|
|
313
|
+
- Thin walls are slow, since 2 to 3 mm shells on 100 mm parts need large
|
|
314
|
+
tetrahedral meshes and take several minutes, and shell elements are on the roadmap.
|
|
315
|
+
- Printed plastics are treated as isotropic at 100 percent infill, with a layer
|
|
316
|
+
strength knockdown when you give the print direction.
|
|
317
|
+
|
|
318
|
+
Shell elements, fatigue estimates and bolt preload come next in 0.2, then CFD with
|
|
319
|
+
OpenFOAM in 0.3 and motion with MuJoCo in 0.4.
|
|
320
|
+
|
|
321
|
+
## Contributing
|
|
322
|
+
|
|
323
|
+
Issues and pull requests are welcome, and this is how to work on Wobbl itself.
|
|
324
|
+
|
|
325
|
+
```sh
|
|
326
|
+
git clone https://github.com/sohan-bhat/wobbl && cd wobbl
|
|
327
|
+
python -m pip install -e ".[dev]"
|
|
328
|
+
python -m pytest -m "not solver" # fast unit tests
|
|
329
|
+
wobbl setup --no-agents # CalculiX and ngspice
|
|
330
|
+
python -m pytest -m solver # end to end tests with the solvers
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
A new solver plugs in as one adapter class, as
|
|
334
|
+
[contributing](https://sohan-bhat.github.io/wobbl/get-started/contributing/) explains. If you change the physics, add or update a
|
|
335
|
+
case in `src/wobbl/validation/cases.py` so `wobbl validate` covers it.
|
|
336
|
+
|
|
337
|
+
## License
|
|
338
|
+
|
|
339
|
+
[MIT](LICENSE), copyright Sohan Bhat.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
<p align="center"><a href="https://sohan-bhat.github.io/wobbl/">sohan-bhat.github.io/wobbl</a></p>
|