metafold 0.15.dev1__tar.gz → 0.15.dev2__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.
Files changed (35) hide show
  1. {metafold-0.15.dev1 → metafold-0.15.dev2}/PKG-INFO +1 -1
  2. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/materials.py +18 -4
  3. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold.egg-info/PKG-INFO +1 -1
  4. {metafold-0.15.dev1 → metafold-0.15.dev2}/pyproject.toml +1 -1
  5. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_materials.py +48 -3
  6. {metafold-0.15.dev1 → metafold-0.15.dev2}/LICENSE +0 -0
  7. {metafold-0.15.dev1 → metafold-0.15.dev2}/README.md +0 -0
  8. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/__init__.py +0 -0
  9. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/api.py +0 -0
  10. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/assets.py +0 -0
  11. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/auth.py +0 -0
  12. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/client.py +0 -0
  13. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/exceptions.py +0 -0
  14. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/jobs.py +0 -0
  15. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/projects.py +0 -0
  16. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/simulation/__init__.py +0 -0
  17. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/simulation/compression_experiment.py +0 -0
  18. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/simulation/compression_simulation.py +0 -0
  19. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/simulation/run_experiment.py +0 -0
  20. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/utils.py +0 -0
  21. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold/workflows.py +0 -0
  22. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold.egg-info/SOURCES.txt +0 -0
  23. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold.egg-info/dependency_links.txt +0 -0
  24. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold.egg-info/requires.txt +0 -0
  25. {metafold-0.15.dev1 → metafold-0.15.dev2}/metafold.egg-info/top_level.txt +0 -0
  26. {metafold-0.15.dev1 → metafold-0.15.dev2}/setup.cfg +0 -0
  27. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_assets.py +0 -0
  28. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_compession_experiment.py +0 -0
  29. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_compression_simulation.py +0 -0
  30. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_jobs.py +0 -0
  31. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_projects.py +0 -0
  32. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_run_experiment.py +0 -0
  33. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_shear_simulation.py +0 -0
  34. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_utils.py +0 -0
  35. {metafold-0.15.dev1 → metafold-0.15.dev2}/tests/test_workflows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metafold
3
- Version: 0.15.dev1
3
+ Version: 0.15.dev2
4
4
  Summary: Metafold SDK for Python
5
5
  Author-email: Metafold 3D <info@metafold3d.com>
6
6
  License: Copyright 2024 Metafold 3D
@@ -232,11 +232,14 @@ class HyperfoamTerm:
232
232
  class HyperfoamParams(ParamsBase):
233
233
  """Ogden hyperfoam (mpmgpu only; no Uintah equivalent).
234
234
 
235
+ The Ogden hyperfoam model is defined entirely by its terms (bulk_modulus is
236
+ not used, so it is not part of this material; a legacy "bulk_modulus"/"K" is
237
+ ignored if present on from_dict).
238
+
235
239
  An optional viscoelastic overlay (Prony series) may be supplied via
236
240
  terminal_shear_modulus + viscoelastic_series, matching the MaxwellWeichert
237
241
  mode structure. Omit both for a purely elastic hyperfoam.
238
242
  """
239
- bulk_modulus: float
240
243
  terms: List[HyperfoamTerm]
241
244
  terminal_shear_modulus: Optional[float] = None
242
245
  viscoelastic_series: Optional[List[ViscoelasticMode]] = None
@@ -247,7 +250,6 @@ class HyperfoamParams(ParamsBase):
247
250
 
248
251
  def to_dict(self):
249
252
  d = {
250
- "bulk_modulus": float(self.bulk_modulus),
251
253
  "terms": [t.to_dict() for t in self.terms],
252
254
  }
253
255
  if self.terminal_shear_modulus is not None:
@@ -258,9 +260,9 @@ class HyperfoamParams(ParamsBase):
258
260
 
259
261
  @classmethod
260
262
  def from_dict(cls, d: dict) -> "HyperfoamParams":
263
+ # A legacy bulk_modulus/K is ignored (older scripts may still send it).
261
264
  series = d.get("viscoelastic_series")
262
265
  return cls(
263
- bulk_modulus=d["bulk_modulus"],
264
266
  terms=[
265
267
  HyperfoamTerm(
266
268
  mu=t["mu"], alpha=t["alpha"], poisson_ratio=t["poisson_ratio"])
@@ -459,7 +461,19 @@ class Material:
459
461
  ]
460
462
  PARAMS_CLASSES = {c.get_type(): c for c in params_classes}
461
463
  cm = d["constitutive_model"]
462
- params = PARAMS_CLASSES[cm["type"]].from_dict(cm["params"])
464
+ model_type = cm.get("type")
465
+ if model_type not in PARAMS_CLASSES:
466
+ # ValueError so API callers reject with a 400, not a 500. An
467
+ # unknown type usually means a client newer than the server.
468
+ raise ValueError(
469
+ f"Unknown constitutive model type {model_type!r}. "
470
+ f"Known types: {', '.join(sorted(PARAMS_CLASSES))}.")
471
+ try:
472
+ params = PARAMS_CLASSES[model_type].from_dict(cm["params"])
473
+ except KeyError as e:
474
+ # Missing param -> ValueError (400) rather than an uncaught 500.
475
+ raise ValueError(
476
+ f"{model_type} material is missing required param {e}.")
463
477
  return cls(
464
478
  density=d["density"],
465
479
  thermal_conductivity=d["thermal_conductivity"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metafold
3
- Version: 0.15.dev1
3
+ Version: 0.15.dev2
4
4
  Summary: Metafold SDK for Python
5
5
  Author-email: Metafold 3D <info@metafold3d.com>
6
6
  License: Copyright 2024 Metafold 3D
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "metafold"
7
- version = "0.15.dev1"
7
+ version = "0.15.dev2"
8
8
  authors = [
9
9
  {name = "Metafold 3D", email = "info@metafold3d.com"},
10
10
  ]
@@ -292,7 +292,6 @@ class TestHyperfoamParams:
292
292
  specific_heat=1.36,
293
293
  constitutive_model=ConstitutiveModel(
294
294
  params=HyperfoamParams(
295
- bulk_modulus=1.0e6,
296
295
  terms=[
297
296
  HyperfoamTerm(mu=0.16e6, alpha=8.9, poisson_ratio=0.0),
298
297
  HyperfoamTerm(mu=0.01e6, alpha=-2.0, poisson_ratio=0.0),
@@ -307,10 +306,30 @@ class TestHyperfoamParams:
307
306
 
308
307
  def test_type_key(self):
309
308
  d = ConstitutiveModel(
310
- params=HyperfoamParams(bulk_modulus=1.0, terms=[])
309
+ params=HyperfoamParams(terms=[])
311
310
  ).to_dict()
312
311
  assert d["type"] == "hyperfoam"
313
312
 
313
+ def test_bulk_modulus_not_emitted(self):
314
+ # bulk_modulus is not part of the Ogden hyperfoam model.
315
+ d = self._material().constitutive_model.params.to_dict()
316
+ assert "bulk_modulus" not in d
317
+ assert "K" not in d
318
+
319
+ def test_legacy_bulk_modulus_ignored_on_from_dict(self):
320
+ # Older scripts / GH plugins may still send bulk_modulus or K — ignore it.
321
+ d = {
322
+ "type": "hyperfoam",
323
+ "params": {
324
+ "bulk_modulus": 1.0e6,
325
+ "K": 2.0e6,
326
+ "terms": [{"mu": 0.16e6, "alpha": 8.9, "poisson_ratio": 0.0}],
327
+ },
328
+ }
329
+ params = HyperfoamParams.from_dict(d["params"])
330
+ assert len(params.terms) == 1
331
+ assert "bulk_modulus" not in params.to_dict()
332
+
314
333
  def test_terms_preserved(self):
315
334
  d = self._material().constitutive_model.params.to_dict()
316
335
  assert len(d["terms"]) == 2
@@ -331,7 +350,6 @@ class TestHyperfoamParams:
331
350
  specific_heat=1.36,
332
351
  constitutive_model=ConstitutiveModel(
333
352
  params=HyperfoamParams(
334
- bulk_modulus=1.0e6,
335
353
  terms=[HyperfoamTerm(mu=0.16e6, alpha=8.9, poisson_ratio=0.0)],
336
354
  terminal_shear_modulus=5.0e4,
337
355
  viscoelastic_series=[
@@ -389,3 +407,30 @@ class TestOrthotropicParams:
389
407
  d = m.to_dict()
390
408
  d["constitutive_model"]["params"]["direction_a"] = "1 0 0"
391
409
  assert OrthotropicParams.from_dict(d["constitutive_model"]["params"]).direction_a == [1.0, 0.0, 0.0]
410
+
411
+
412
+ class TestMaterialFromDictErrors:
413
+ # from_dict must raise ValueError (not KeyError) so API callers return 400,
414
+ # not 500. See lightcycle experiments blueprint.
415
+ def _material_dict(self, mtype, params):
416
+ return {
417
+ "density": 1000.0, "thermal_conductivity": 1.0, "specific_heat": 1500,
418
+ "constitutive_model": {"type": mtype, "params": params},
419
+ }
420
+
421
+ def test_unknown_type_raises_value_error(self):
422
+ # A client newer than the server sends a type we don't know.
423
+ d = self._material_dict("some_future_type", {})
424
+ with pytest.raises(ValueError, match="Unknown constitutive model type"):
425
+ Material.from_dict(d)
426
+
427
+ def test_missing_param_raises_value_error(self):
428
+ params = {
429
+ "E1": 1e9, "E2": 1e9, "E3": 1e9,
430
+ "nu12": 0.3, "nu13": 0.3, "nu23": 0.3,
431
+ "G12": 5e8, "G13": 5e8, "G23": 5e8,
432
+ "direction_a": [1.0, 0.0, 0.0], "direction_b": [0.0, 1.0, 0.0],
433
+ }
434
+ del params["E1"]
435
+ with pytest.raises(ValueError, match="missing required param"):
436
+ Material.from_dict(self._material_dict("orthotropic", params))
File without changes
File without changes
File without changes