loadpath 0.1.1__py3-none-any.whl

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.
Files changed (220) hide show
  1. loadpath/README.md +294 -0
  2. loadpath/SKILL.md +584 -0
  3. loadpath/__init__.py +17 -0
  4. loadpath/__main__.py +1202 -0
  5. loadpath/am.py +316 -0
  6. loadpath/amgfast.py +326 -0
  7. loadpath/assembly.py +985 -0
  8. loadpath/benchmarks/__init__.py +0 -0
  9. loadpath/benchmarks/beams.py +266 -0
  10. loadpath/benchmarks/cases/ge-bracket.json +380 -0
  11. loadpath/benchmarks/evaluate.py +172 -0
  12. loadpath/benchmarks/mechanisms.py +416 -0
  13. loadpath/benchmarks/problems.py +140 -0
  14. loadpath/benchmarks/reference/bridge-3d.top3d.npz +0 -0
  15. loadpath/benchmarks/reference/cantilever-3d.top3d.npz +0 -0
  16. loadpath/benchmarks/reference/lbracket-2d.top88-ft2.npz +0 -0
  17. loadpath/benchmarks/reference/mbb-2d.top88-ft1.npz +0 -0
  18. loadpath/benchmarks/reference/mbb-2d.top88-ft2.npz +0 -0
  19. loadpath/benchmarks/reference.py +138 -0
  20. loadpath/benchmarks/run.py +301 -0
  21. loadpath/brep.py +1470 -0
  22. loadpath/bucklingopt.py +300 -0
  23. loadpath/buildsim.py +1490 -0
  24. loadpath/cadimport.py +904 -0
  25. loadpath/calibration.py +885 -0
  26. loadpath/cavities.py +211 -0
  27. loadpath/checks/__init__.py +0 -0
  28. loadpath/checks/dfm.py +354 -0
  29. loadpath/checks/exchanger.py +7 -0
  30. loadpath/checks/fea.py +212 -0
  31. loadpath/checks/fit.py +475 -0
  32. loadpath/checks/networks.py +260 -0
  33. loadpath/checks/opening.py +67 -0
  34. loadpath/checks/sdf_kit.py +7 -0
  35. loadpath/conjugate.py +267 -0
  36. loadpath/constrained.py +329 -0
  37. loadpath/contact.py +691 -0
  38. loadpath/coopt.py +342 -0
  39. loadpath/cores.py +163 -0
  40. loadpath/crease.py +1138 -0
  41. loadpath/critic.py +212 -0
  42. loadpath/crosscheck.py +1107 -0
  43. loadpath/cutcell.py +510 -0
  44. loadpath/data/lattice_buckling.json +439 -0
  45. loadpath/data/lattice_tensors.json +27449 -0
  46. loadpath/data/published_experiments.json +71 -0
  47. loadpath/decimate.py +177 -0
  48. loadpath/delivery.py +190 -0
  49. loadpath/directions.py +262 -0
  50. loadpath/domain.py +630 -0
  51. loadpath/drains.py +615 -0
  52. loadpath/durability.py +413 -0
  53. loadpath/editor.html +3135 -0
  54. loadpath/editor.py +610 -0
  55. loadpath/escape.py +354 -0
  56. loadpath/evals/__init__.py +0 -0
  57. loadpath/evals/baselines/coarse.json +1543 -0
  58. loadpath/evals/baselines/full.json +1497 -0
  59. loadpath/evals/brief_kinds/__init__.py +1 -0
  60. loadpath/evals/brief_kinds/heatx.py +387 -0
  61. loadpath/evals/brief_kinds/lattice.py +571 -0
  62. loadpath/evals/brief_kinds/multimat.py +593 -0
  63. loadpath/evals/briefs/assets/bracket.step +1201 -0
  64. loadpath/evals/briefs/assets/desk_arm.urdf +22 -0
  65. loadpath/evals/briefs/assets/elbow-gearbox.stl +0 -0
  66. loadpath/evals/briefs/assets/motor-body.stl +0 -0
  67. loadpath/evals/briefs/assets/sketch.png +0 -0
  68. loadpath/evals/briefs/base-adapter-fdm.json +492 -0
  69. loadpath/evals/briefs/bell-crank-lpbf.json +180 -0
  70. loadpath/evals/briefs/belt-tensioner-fdm.json +151 -0
  71. loadpath/evals/briefs/camera-boom-mjf.json +339 -0
  72. loadpath/evals/briefs/camera-mount-pla.json +203 -0
  73. loadpath/evals/briefs/coolant-isolator-petg.json +100 -0
  74. loadpath/evals/briefs/elbow-bearing-bracket-sls.json +300 -0
  75. loadpath/evals/briefs/elbow-gearbox-forearm-mjf.json +558 -0
  76. loadpath/evals/briefs/elbow-link-fatigue-fdm.json +251 -0
  77. loadpath/evals/briefs/elbow-stop-pad-tpu.json +39 -0
  78. loadpath/evals/briefs/forearm-fdm.json +146 -0
  79. loadpath/evals/briefs/forearm-servo-link-fdm.json +327 -0
  80. loadpath/evals/briefs/grip-pad-finger-mm.json +354 -0
  81. loadpath/evals/briefs/gripper-bracket-creep-fdm.json +340 -0
  82. loadpath/evals/briefs/gripper-finger-fdm.json +155 -0
  83. loadpath/evals/briefs/gripper-jaw-fatigue-mjf.json +328 -0
  84. loadpath/evals/briefs/gripper-palm-fdm.json +715 -0
  85. loadpath/evals/briefs/hot-stepper-mount-asa-fdm.json +471 -0
  86. loadpath/evals/briefs/hpu-oil-cooler-lpbf.json +121 -0
  87. loadpath/evals/briefs/isolated-camera-mount-mm.json +675 -0
  88. loadpath/evals/briefs/kart-charge-cooler-lpbf.json +93 -0
  89. loadpath/evals/briefs/lighten-step-bracket.json +220 -0
  90. loadpath/evals/briefs/nema17-mount-stl.json +429 -0
  91. loadpath/evals/briefs/pillow-block-sls.json +220 -0
  92. loadpath/evals/briefs/polyjet-fingertip-mm.json +305 -0
  93. loadpath/evals/briefs/rod-hook-pla.json +154 -0
  94. loadpath/evals/briefs/sensor-arm-resin.json +150 -0
  95. loadpath/evals/briefs/shelf-bracket-pla.json +158 -0
  96. loadpath/evals/briefs/shoulder-riser-mjf.json +487 -0
  97. loadpath/evals/briefs/sketch-clevis.json +229 -0
  98. loadpath/evals/briefs/spring-bracket-pacf.json +294 -0
  99. loadpath/evals/briefs/tool-flange-ti64.json +280 -0
  100. loadpath/evals/briefs/tray-arm-lattice-fdm.json +260 -0
  101. loadpath/evals/briefs/turret-fdm.json +281 -0
  102. loadpath/evals/briefs/upper-arm-sls.json +179 -0
  103. loadpath/evals/briefs/urdf-forearm.json +233 -0
  104. loadpath/evals/briefs/wrist-link-mjf.json +278 -0
  105. loadpath/evals/briefs/wrist-yoke-mjf.json +245 -0
  106. loadpath/evals/briefs.py +393 -0
  107. loadpath/evals/cases/arm-link-cast.json +157 -0
  108. loadpath/evals/cases/arm-link-driven.json +171 -0
  109. loadpath/evals/cases/arm-link-sandwich.json +315 -0
  110. loadpath/evals/cases/arm-link.json +111 -0
  111. loadpath/evals/cases/bell-crank.json +116 -0
  112. loadpath/evals/cases/grip-turret.json +479 -0
  113. loadpath/evals/cases/grip-upper-arm.json +253 -0
  114. loadpath/evals/cases/grip-wrist-link-mjf.json +929 -0
  115. loadpath/evals/cases/grip-wrist-yoke.json +831 -0
  116. loadpath/evals/cases/lpbf-intercooler-core.json +59 -0
  117. loadpath/evals/cases/mbb-beam.json +61 -0
  118. loadpath/evals/cases/motor-body.stl +0 -0
  119. loadpath/evals/cases/motor-mount.json +265 -0
  120. loadpath/evals/cases/printed-hook.json +77 -0
  121. loadpath/evals/cases/wall-bracket-fasteners.json +125 -0
  122. loadpath/evals/cases/wall-bracket.json +126 -0
  123. loadpath/evals/corpus.py +179 -0
  124. loadpath/evals/pareto.py +90 -0
  125. loadpath/evals/run.py +860 -0
  126. loadpath/examples/arm-link.json +25 -0
  127. loadpath/examples/bumpered-bracket-compression.json +225 -0
  128. loadpath/examples/bumpered-bracket-lattice.json +204 -0
  129. loadpath/examples/bumpered-bracket.json +34 -0
  130. loadpath/examples/gripper-finger-mm.json +185 -0
  131. loadpath/examples/heat-exchanger-counterflow.json +21 -0
  132. loadpath/examples/heat-exchanger-crossflow-tuned.json +48 -0
  133. loadpath/examples/heat-exchanger-crossflow.json +20 -0
  134. loadpath/examples/pedal-lattice.json +23 -0
  135. loadpath/examples/pressure-plenum.json +12 -0
  136. loadpath/examples/shelf-bracket.json +27 -0
  137. loadpath/exchanger.py +831 -0
  138. loadpath/fasteners.py +199 -0
  139. loadpath/fem.py +668 -0
  140. loadpath/femops.py +70 -0
  141. loadpath/fieldjit.py +981 -0
  142. loadpath/fieldops.py +119 -0
  143. loadpath/fields.py +3697 -0
  144. loadpath/fieldtorch.py +464 -0
  145. loadpath/flow.py +984 -0
  146. loadpath/flowtopo.py +300 -0
  147. loadpath/gpu.py +521 -0
  148. loadpath/heatx.py +1067 -0
  149. loadpath/heatx_thermal.py +432 -0
  150. loadpath/homogenized.py +886 -0
  151. loadpath/ibrep.py +552 -0
  152. loadpath/impact.py +693 -0
  153. loadpath/infill.py +376 -0
  154. loadpath/interface_library.py +340 -0
  155. loadpath/interlock.py +186 -0
  156. loadpath/isolator.py +149 -0
  157. loadpath/knn.py +204 -0
  158. loadpath/lattice.py +1065 -0
  159. loadpath/lattice3mf.py +760 -0
  160. loadpath/lattice_buckling.py +245 -0
  161. loadpath/lattice_grade.py +325 -0
  162. loadpath/lattice_orient.py +595 -0
  163. loadpath/lattice_print.py +159 -0
  164. loadpath/lattice_tensors.py +558 -0
  165. loadpath/latticestep.py +1210 -0
  166. loadpath/manufacture.py +446 -0
  167. loadpath/material_library.py +489 -0
  168. loadpath/materials.py +144 -0
  169. loadpath/mcp_server.py +786 -0
  170. loadpath/mechanism.py +218 -0
  171. loadpath/mechanism_nl.py +811 -0
  172. loadpath/meshops.py +452 -0
  173. loadpath/mg.py +853 -0
  174. loadpath/mma.py +214 -0
  175. loadpath/modal.py +210 -0
  176. loadpath/multimat.py +1788 -0
  177. loadpath/narrowband.py +418 -0
  178. loadpath/nlkernel.py +241 -0
  179. loadpath/nonlinear.py +1095 -0
  180. loadpath/orient.py +334 -0
  181. loadpath/porous.py +994 -0
  182. loadpath/pressure.py +171 -0
  183. loadpath/preview.py +335 -0
  184. loadpath/printcheck.py +263 -0
  185. loadpath/printsetup.py +207 -0
  186. loadpath/processcheck.py +376 -0
  187. loadpath/quick.py +113 -0
  188. loadpath/recall.py +406 -0
  189. loadpath/reconstruct.py +797 -0
  190. loadpath/render.py +436 -0
  191. loadpath/resolved.py +189 -0
  192. loadpath/schema.py +1701 -0
  193. loadpath/sdf_kit.py +843 -0
  194. loadpath/selfx.py +292 -0
  195. loadpath/shapes.py +584 -0
  196. loadpath/sharp.py +717 -0
  197. loadpath/simp.py +1170 -0
  198. loadpath/sizing.py +312 -0
  199. loadpath/slicer.py +321 -0
  200. loadpath/spec.py +1072 -0
  201. loadpath/step.py +806 -0
  202. loadpath/struts.py +639 -0
  203. loadpath/study.py +1937 -0
  204. loadpath/tasks.py +822 -0
  205. loadpath/thermal.py +1691 -0
  206. loadpath/threemf.py +487 -0
  207. loadpath/tune.py +437 -0
  208. loadpath/validation.py +145 -0
  209. loadpath/verify.py +1215 -0
  210. loadpath/viewer.html +694 -0
  211. loadpath/viewer.py +446 -0
  212. loadpath/viscoelastic.py +106 -0
  213. loadpath/voxelprint.py +582 -0
  214. loadpath/voxels.py +402 -0
  215. loadpath-0.1.1.dist-info/METADATA +319 -0
  216. loadpath-0.1.1.dist-info/RECORD +220 -0
  217. loadpath-0.1.1.dist-info/WHEEL +5 -0
  218. loadpath-0.1.1.dist-info/entry_points.txt +2 -0
  219. loadpath-0.1.1.dist-info/licenses/LICENSE +21 -0
  220. loadpath-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,159 @@
1
+ """
2
+ As-printed lattice stiffness: how much softer a printed lattice is than its
3
+ designed geometry, by process, cell family and density, fitted to published
4
+ compression tests.
5
+
6
+ Checked against 33 printed lattices (validation.py,
7
+ data/published_experiments.json), loadpath's homogenized check reads the
8
+ designed geometry 1.0-4.1x stiffer than the prints measured (median 1.68x
9
+ either way), and its resolved voxel solve agrees with the homogenized one, so
10
+ the gap is the print, not the model: walls and struts thinner and rougher
11
+ than drawn, porous, stair-stepped, weakly bonded, and (in the tests) modulus
12
+ read from crosshead travel. The factor here is
13
+
14
+ k = 1 / exp(a_process + b_strut [strut cell] + c ln(rho / 0.2))
15
+
16
+ with rho the lattice's relative density (clipped to the tested 0.1-0.4 for
17
+ the density term) and k capped at 1: the check never reads a lattice stiffer
18
+ than designed. The density term says the prints stiffen more slowly with
19
+ density than the design does (the papers' denser lattices are the
20
+ over-predicted ones); the strut term that strut cells lose more than sheets.
21
+
22
+ Fitted coefficients (bench/lattice_print_fit.py, least squares on log
23
+ modulus ratio over all 33 specimens, results in
24
+ bench/results/lattice-print-fit.json):
25
+
26
+ process group exp(a) from
27
+ fdm 1.54 Shevchenko 2023 (PLA sheets), Guerra Silva 2021 (ABS, PC struts)
28
+ sls 1.08 Shevchenko 2023 (PA12 sheets), Abou-Ali 2022 (PA11 sheets and struts)
29
+ resin 1.33 Shevchenko 2023 (LCD resin sheets)
30
+ strut cells x1.58
31
+ density x1.34 per e-fold of rho / 0.2
32
+
33
+ Held out (each specimen predicted from a fit to the other 32), the median
34
+ error in modulus falls from 1.68x to 1.23x (worst 4.12x to 2.04x); leaving
35
+ out a whole paper, its specimens read a median 0.92-1.17x of the measurement. Per-cell-type terms (Schwarz P,
36
+ Kelvin, octet) did not improve the held-out error and are not used.
37
+
38
+ Process groups: mjf is read as sls (no MJF lattice tests found), sla and dlp
39
+ as the LCD resin. volumetric, jetting and lpbf have no printed-lattice data
40
+ here: their factor is None and the check reads the designed geometry, with
41
+ a note.
42
+
43
+ Strength: a sheet print fails at about the strain its design predicts for
44
+ first yield, not the stress (the PLA Schwarz P lattice that broke at 0.84x
45
+ its predicted first-yield stress is 2.4x softer than the same geometry in
46
+ SLS PA12 and failed at the same strain), so for sheets the homogenized
47
+ check reads wall stress from the strain the softer lattice takes. Strut
48
+ lattices read from the macro stress they carry: their first yield was safe
49
+ that way on every strut specimen, and the strain reading made FDM strut
50
+ lattices 2.5x more conservative than they need (STRAIN_SHARE). Held out,
51
+ first yield is under the measured strength on all 33 specimens.
52
+
53
+ A calibrated card (calibration.py, gyroid coupon L-GY) that measured its own
54
+ lattice stiffness factor replaces this fit; so does a study's
55
+ process.latticeStiffness (a number, or "designed").
56
+ """
57
+ from __future__ import annotations
58
+
59
+ import numpy as np
60
+
61
+ __all__ = ["STRAIN_SHARE", "strain_share", "PRINT_FIT", "PROCESS_GROUP", "print_factor", "process_group", "features", "fit", "fit_rows"]
62
+
63
+ # bench/lattice_print_fit.py writes these (tests/test_lattice_print.py checks
64
+ # they match a refit of bench/results/published-experiments.json)
65
+ PRINT_FIT = {
66
+ "intercept": {"fdm": 0.43111, "sls": 0.07451, "resin": 0.2811},
67
+ "strut": 0.45728,
68
+ "densitySlope": 0.29423,
69
+ "rhoRef": 0.2,
70
+ "rhoRange": [0.1, 0.4],
71
+ }
72
+
73
+ # How the check reads wall stress in a softer printed lattice: 1 = from the
74
+ # strain it takes (stress k^-1 higher than the carried macro stress says),
75
+ # 0 = from the stress it carries. Chosen per family as the least value that
76
+ # keeps every published specimen's first-yield reading under its measured
77
+ # strength, then held out a paper at a time (bench/lattice_print_fit.py):
78
+ # - sheets 1: the FDM PLA Schwarz P lattice needs it (1.19x at 0, 0.82x at
79
+ # 1). With Shevchenko 2023 held out the rest of the data asks for 0, and
80
+ # that paper's PLA P then reads 1.19x, so the sheet value rests on one
81
+ # paper and the physical reading (the PLA print failed at the strain its
82
+ # design yields at, 2.4x softer than the same geometry in SLS);
83
+ # - struts 0: safe on all 20 strut specimens (0.18-0.91x), and with either
84
+ # strut paper held out the other still asks for 0 and reads safe on it
85
+ # (Abou-Ali 0.65-0.91x, Guerra Silva 0.18-0.78x). At 1 the FDM strut
86
+ # lattices read 0.07-0.41x of their plateau.
87
+ STRAIN_SHARE = {"sheet": 1.0, "strut": 0.0}
88
+
89
+ PROCESS_GROUP = {"fdm": "fdm", "sls": "sls", "mjf": "sls", "sla": "resin", "dlp": "resin"}
90
+
91
+ SOURCES = {
92
+ "fdm": ["shevchenko2023", "guerrasilva2021"],
93
+ "sls": ["shevchenko2023", "abouali2022"],
94
+ "resin": ["shevchenko2023"],
95
+ }
96
+
97
+ FEATURES = ("fdm", "sls", "resin", "strut", "lrho")
98
+
99
+
100
+ def strain_share(lattice_kind: str) -> float:
101
+ from .struts import is_strut
102
+
103
+ return STRAIN_SHARE["strut" if is_strut(lattice_kind) else "sheet"]
104
+
105
+
106
+ def process_group(kind: str | None) -> str | None:
107
+ return PROCESS_GROUP.get(str(kind).lower()) if kind else None
108
+
109
+
110
+ def features(group: str, strut: bool, rho, rho_ref: float = 0.2, rho_range=(0.1, 0.4)) -> np.ndarray:
111
+ """Design rows (n, 5) for the fit: one-hot process group, strut flag,
112
+ log density over the reference (clipped to the tested range)."""
113
+ rho = np.atleast_1d(np.asarray(rho, float))
114
+ x = np.zeros((len(rho), len(FEATURES)))
115
+ x[:, FEATURES.index(group)] = 1.0
116
+ x[:, 3] = float(bool(strut))
117
+ x[:, 4] = np.log(np.clip(rho, *rho_range) / rho_ref)
118
+ return x
119
+
120
+
121
+ def print_factor(process_kind: str | None, lattice_kind: str, rho, fit_: dict | None = None):
122
+ """As-printed stiffness over designed (<= 1) at relative densities rho,
123
+ or None where the process has no printed-lattice data."""
124
+ from .struts import is_strut
125
+
126
+ group = process_group(process_kind)
127
+ if group is None:
128
+ return None
129
+ f = fit_ or PRINT_FIT
130
+ b = np.array([f["intercept"]["fdm"], f["intercept"]["sls"], f["intercept"]["resin"], f["strut"],
131
+ f["densitySlope"]])
132
+ x = features(group, is_strut(lattice_kind), rho, f["rhoRef"], tuple(f["rhoRange"]))
133
+ return np.minimum(np.exp(-(x @ b)), 1.0)
134
+
135
+
136
+ def fit_rows(results: dict) -> list[dict]:
137
+ """Rows for the fit from bench/results/published-experiments.json: group,
138
+ strut flag, rho, the homogenized and measured modulus and strength."""
139
+ from .struts import is_strut
140
+ from .validation import process_kind
141
+
142
+ rows = []
143
+ for sid, r in results.items():
144
+ rows.append({"id": sid, "source": r["source"], "group": process_group(process_kind(r["process"])),
145
+ "strut": bool(is_strut(r["lattice"]["type"])), "type": r["lattice"]["type"],
146
+ "rho": float(r["table"]["rho"]), "E": float(r["homogenized"]["E"]),
147
+ "Emeas": float(r["measured"]["E"]), "firstYield": float(r["homogenized"]["firstYield"]),
148
+ "strength": float(r["measured"]["strength"])})
149
+ return rows
150
+
151
+
152
+ def fit(rows: list[dict], ridge: float = 1e-3) -> dict:
153
+ """Least squares of log(designed / measured modulus) on the features
154
+ (a light ridge keeps a group missing from `rows` at zero)."""
155
+ x = np.vstack([features(r["group"], r["strut"], r["rho"]) for r in rows])
156
+ y = np.log([r["E"] / r["Emeas"] for r in rows])
157
+ b = np.linalg.solve(x.T @ x + ridge * np.eye(x.shape[1]), x.T @ y)
158
+ return {"intercept": {"fdm": float(b[0]), "sls": float(b[1]), "resin": float(b[2])}, "strut": float(b[3]),
159
+ "densitySlope": float(b[4]), "rhoRef": 0.2, "rhoRange": [0.1, 0.4]}