metafold 0.12.dev9__tar.gz → 0.12.dev11__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.12.dev9 → metafold-0.12.dev11}/PKG-INFO +1 -1
  2. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/compression_simulation.py +30 -37
  3. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/run_experiment.py +6 -3
  4. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/PKG-INFO +1 -1
  5. {metafold-0.12.dev9 → metafold-0.12.dev11}/pyproject.toml +1 -1
  6. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_compression_simulation.py +68 -33
  7. {metafold-0.12.dev9 → metafold-0.12.dev11}/LICENSE +0 -0
  8. {metafold-0.12.dev9 → metafold-0.12.dev11}/README.md +0 -0
  9. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/__init__.py +0 -0
  10. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/api.py +0 -0
  11. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/assets.py +0 -0
  12. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/auth.py +0 -0
  13. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/client.py +0 -0
  14. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/exceptions.py +0 -0
  15. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/jobs.py +0 -0
  16. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/materials.py +0 -0
  17. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/projects.py +0 -0
  18. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/__init__.py +0 -0
  19. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/compression_experiment.py +0 -0
  20. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/utils.py +0 -0
  21. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/workflows.py +0 -0
  22. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/SOURCES.txt +0 -0
  23. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/dependency_links.txt +0 -0
  24. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/requires.txt +0 -0
  25. {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/top_level.txt +0 -0
  26. {metafold-0.12.dev9 → metafold-0.12.dev11}/setup.cfg +0 -0
  27. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_assets.py +0 -0
  28. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_compession_experiment.py +0 -0
  29. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_jobs.py +0 -0
  30. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_materials.py +0 -0
  31. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_projects.py +0 -0
  32. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_run_experiment.py +0 -0
  33. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_shear_simulation.py +0 -0
  34. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_utils.py +0 -0
  35. {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_workflows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metafold
3
- Version: 0.12.dev9
3
+ Version: 0.12.dev11
4
4
  Summary: Metafold SDK for Python
5
5
  Author-email: Metafold 3D <info@metafold3d.com>
6
6
  License: Copyright 2024 Metafold 3D
@@ -437,7 +437,7 @@ class CompressionSimulation:
437
437
  WorkflowStep(WorkflowStepType.VON_MISES_STRESS),
438
438
  WorkflowStep(WorkflowStepType.EFFECTIVE_STRAIN),
439
439
  WorkflowStep(WorkflowStepType.FORCE_DISPLACEMENT),
440
- WorkflowStep(WorkflowStepType.STRESS_STRAIN),
440
+ # stress_strain is opt-in (not default): callers add it via workflow_steps.
441
441
  WorkflowStep(WorkflowStepType.PARTICLE_DISPLACEMENT),
442
442
  WorkflowStep(WorkflowStepType.ENERGY_METRICS),
443
443
  ],
@@ -535,20 +535,6 @@ class CompressionSimulation:
535
535
  def download_results(self):
536
536
  self.write_results()
537
537
 
538
- def _get_primary_deformable_info(self):
539
- """The specimen part for stress/strain and the featured histogram: the
540
- first part that isn't a rigid piston/support (pistons are inserted at
541
- index 0, so this is the first deformable body in the stack)."""
542
- return next(
543
- (
544
- p for p in self.part_infos
545
- if not isinstance(
546
- p.part, (ExperimentPistonBase, ExperimentSupportBase)
547
- )
548
- ),
549
- None,
550
- )
551
-
552
538
  def setup_results(self, output_path):
553
539
  self.out_dir = Path(output_path)
554
540
  self.out_dir.mkdir(parents=True, exist_ok=True)
@@ -2673,24 +2659,8 @@ class CompressionSimulation:
2673
2659
  },
2674
2660
  ]
2675
2661
 
2676
- self.manifest["cardsConfig"]["B"] = []
2677
- specimen = self._get_primary_deformable_info()
2678
- if self._contains_step(WorkflowStepType.VON_MISES_STRESS) and specimen is not None:
2679
- rep_idx = specimen.material_index
2680
- self.manifest["cardsConfig"]["B"].append(
2681
- {
2682
- "id": "vonMisesStress",
2683
- "title": "von Mises Stress",
2684
- "component": "SingleExperimentHistogram",
2685
- "props": {
2686
- "dataSource": f"vonMisesStressHistogram{rep_idx}",
2687
- "xAxisLabel": "von Mises Stress",
2688
- "yAxisLabel": "Frequency",
2689
- },
2690
- }
2691
- )
2692
-
2693
- # One stress-strain card per deformable part (keyed stressStrain{i}).
2662
+ # One stress-strain card per deformable part (keyed stressStrain{i}),
2663
+ # under force-displacement: same data, per-part normalizations.
2694
2664
  if self._contains_step(WorkflowStepType.STRESS_STRAIN):
2695
2665
  for part_info in self.part_infos:
2696
2666
  if not self._is_analysis_target(part_info.part):
@@ -2698,7 +2668,7 @@ class CompressionSimulation:
2698
2668
  if part_info.disabled:
2699
2669
  continue
2700
2670
  i = part_info.material_index
2701
- self.manifest["cardsConfig"]["B"].append(
2671
+ self.manifest["cardsConfig"]["A"].append(
2702
2672
  {
2703
2673
  "id": f"stressStrain{i}",
2704
2674
  "title": f"{part_info.part_unique_name} Stress-Strain",
@@ -2714,6 +2684,29 @@ class CompressionSimulation:
2714
2684
  }
2715
2685
  )
2716
2686
 
2687
+ # One von Mises histogram card per deformable part (keyed
2688
+ # vonMisesStressHistogram{i}).
2689
+ self.manifest["cardsConfig"]["B"] = []
2690
+ if self._contains_step(WorkflowStepType.VON_MISES_STRESS):
2691
+ for part_info in self.part_infos:
2692
+ if not self._is_analysis_target(part_info.part):
2693
+ continue
2694
+ if part_info.disabled:
2695
+ continue
2696
+ i = part_info.material_index
2697
+ self.manifest["cardsConfig"]["B"].append(
2698
+ {
2699
+ "id": f"vonMisesStress{i}",
2700
+ "title": f"{part_info.part_unique_name} von Mises Stress",
2701
+ "component": "SingleExperimentHistogram",
2702
+ "props": {
2703
+ "dataSource": f"vonMisesStressHistogram{i}",
2704
+ "xAxisLabel": "von Mises Stress",
2705
+ "yAxisLabel": "Frequency",
2706
+ },
2707
+ }
2708
+ )
2709
+
2717
2710
  if self._results_have_energy_metrics(results):
2718
2711
  self.manifest["resultsListConfig"].append(
2719
2712
  {"key": "volume", "heading": "Volume (mm³)", "filtering": False},
@@ -2739,7 +2732,7 @@ class CompressionSimulation:
2739
2732
  "filtering": False,
2740
2733
  }
2741
2734
  )
2742
- self.manifest["cardsConfig"]["C"] = [
2735
+ self.manifest["cardsConfig"]["C"].append(
2743
2736
  {
2744
2737
  "id": "energyVolume",
2745
2738
  "title": "Energy Absorbed-Interior Volume",
@@ -2751,7 +2744,7 @@ class CompressionSimulation:
2751
2744
  "yAxisLabel": "Energy Absorbed (J)",
2752
2745
  "colorScaleMeasurement": "energyAbsorbed",
2753
2746
  },
2754
- },
2755
- ]
2747
+ }
2748
+ )
2756
2749
 
2757
2750
 
@@ -98,12 +98,15 @@ Available material presets
98
98
  "material_pla", "material_stainless_steel",
99
99
  "material_ti64", "material_tpu"
100
100
 
101
- Available workflow steps (default: all)
102
- ----------------------------------------
101
+ Available workflow steps (default: all except stress_strain)
102
+ ------------------------------------------------------------
103
103
  "compute_bvh", "metrics", "compress", "von_mises_stress",
104
- "effective_strain", "force_displacement", "stress_strain",
104
+ "effective_strain", "force_displacement",
105
105
  "particle_displacement", "energy_metrics"
106
106
 
107
+ Opt-in (not run by default; add explicitly to workflow_steps):
108
+ "stress_strain"
109
+
107
110
  Zip format (for run_experiment_from_zip)
108
111
  -----------------------------------------
109
112
  A zip containing:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metafold
3
- Version: 0.12.dev9
3
+ Version: 0.12.dev11
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.12.dev9"
7
+ version = "0.12.dev11"
8
8
  authors = [
9
9
  {name = "Metafold 3D", email = "info@metafold3d.com"},
10
10
  ]
@@ -565,24 +565,6 @@ jobs:
565
565
  - compress
566
566
  assets:
567
567
  data: compress
568
- stress-strain-upper_foam:
569
- type: sim/postprocess/stress-strain
570
- needs:
571
- - force-displacement
572
- assets:
573
- data: force-displacement
574
- stress-strain-midsole:
575
- type: sim/postprocess/stress-strain
576
- needs:
577
- - force-displacement
578
- assets:
579
- data: force-displacement
580
- stress-strain-outsole:
581
- type: sim/postprocess/stress-strain
582
- needs:
583
- - force-displacement
584
- assets:
585
- data: force-displacement
586
568
  particle-displacement:
587
569
  type: sim/postprocess/particle-displacement
588
570
  needs:
@@ -638,12 +620,6 @@ jobs:
638
620
  "metrics-upper_foam.volume_resolution": "[32, 32, 16]",
639
621
  "metrics-upper_foam.volume_size": "[0.1, 0.1, 0.05]",
640
622
  "particle-displacement.keys": "[\"/material0/position\", \"/material1/position\", \"/material2/position\", \"/material3/position\"]",
641
- "stress-strain-midsole.initial_length": "0.05",
642
- "stress-strain-midsole.keys": "[\"/force_displacement\"]",
643
- "stress-strain-outsole.initial_length": "0.05",
644
- "stress-strain-outsole.keys": "[\"/force_displacement\"]",
645
- "stress-strain-upper_foam.initial_length": "0.05",
646
- "stress-strain-upper_foam.keys": "[\"/force_displacement\"]",
647
623
  "von-mises-stress.keys": "[\"/material0/cauchy_stress\", \"/material1/cauchy_stress\", \"/material2/cauchy_stress\", \"/material3/cauchy_stress\"]"
648
624
  }
649
625
  """)
@@ -653,7 +629,8 @@ jobs:
653
629
 
654
630
 
655
631
  class TestStressStrainPerPart:
656
- """stress-strain runs once per deformable part (not one representative)."""
632
+ """stress-strain runs once per deformable part (not one representative).
633
+ It is opt-in: callers must add the step to workflow_steps."""
657
634
 
658
635
  def _built_sim(self, ply_folder, basic_parts, tmp_path):
659
636
  sim = CompressionSimulation(
@@ -662,6 +639,12 @@ class TestStressStrainPerPart:
662
639
  stl_folder_path=str(ply_folder),
663
640
  output_path=str(tmp_path / "out"),
664
641
  client=MagicMock(),
642
+ # stress_strain is not default; opt in (needs compress + force-displacement).
643
+ workflow_steps=[
644
+ WorkflowStep(WorkflowStepType.COMPRESS),
645
+ WorkflowStep(WorkflowStepType.FORCE_DISPLACEMENT),
646
+ WorkflowStep(WorkflowStepType.STRESS_STRAIN),
647
+ ],
665
648
  )
666
649
  # Distinct X/Y so compression_area = X*Y is unambiguous.
667
650
  fake_patch = {"size": [0.1, 0.2, 0.05], "offset": [0.0, 0.0, 0.0], "resolution": [32, 32, 16]}
@@ -673,6 +656,16 @@ class TestStressStrainPerPart:
673
656
  sim.build_workflow()
674
657
  return sim
675
658
 
659
+ def test_not_run_by_default(self, ply_folder, basic_parts, tmp_path):
660
+ sim = CompressionSimulation(
661
+ parts=basic_parts,
662
+ simulation_name="t",
663
+ stl_folder_path=str(ply_folder),
664
+ output_path=str(tmp_path / "out"),
665
+ client=MagicMock(),
666
+ )
667
+ assert not sim._contains_step(WorkflowStepType.STRESS_STRAIN)
668
+
676
669
  def test_one_job_per_deformable_part(self, ply_folder, basic_parts, tmp_path):
677
670
  sim = self._built_sim(ply_folder, basic_parts, tmp_path)
678
671
  for name in ("upper_foam", "midsole", "outsole"):
@@ -721,6 +714,18 @@ class TestMakeManifestV2:
721
714
  stl_folder_path=str(ply_folder),
722
715
  output_path=str(tmp_path / "out"),
723
716
  client=MagicMock(),
717
+ # Every step, including opt-in stress_strain, so all cards render.
718
+ workflow_steps=[
719
+ WorkflowStep(WorkflowStepType.COMPUTE_BVH),
720
+ WorkflowStep(WorkflowStepType.METRICS),
721
+ WorkflowStep(WorkflowStepType.COMPRESS),
722
+ WorkflowStep(WorkflowStepType.VON_MISES_STRESS),
723
+ WorkflowStep(WorkflowStepType.EFFECTIVE_STRAIN),
724
+ WorkflowStep(WorkflowStepType.FORCE_DISPLACEMENT),
725
+ WorkflowStep(WorkflowStepType.STRESS_STRAIN),
726
+ WorkflowStep(WorkflowStepType.PARTICLE_DISPLACEMENT),
727
+ WorkflowStep(WorkflowStepType.ENERGY_METRICS),
728
+ ],
724
729
  )
725
730
  # In the real flow create_sim_config() assigns material indices before
726
731
  # make_manifest_v2() runs; mirror that so per-part cards key correctly.
@@ -754,7 +759,6 @@ class TestMakeManifestV2:
754
759
  def test_card_c_present_when_energy_metrics_step_present(self, sim_with_full_steps):
755
760
  sim_with_full_steps.make_manifest_v2(results=[])
756
761
  card_c = sim_with_full_steps.manifest["cardsConfig"]["C"]
757
- assert len(card_c) == 1
758
762
  assert card_c[0]["id"] == "energyVolume"
759
763
 
760
764
  def test_card_c_absent_when_no_energy_metrics(self, ply_folder, basic_parts, tmp_path):
@@ -847,12 +851,38 @@ class TestMakeManifestV2:
847
851
  sim.make_manifest_v2()
848
852
  assert sim.manifest["cardsConfig"]["A"] == []
849
853
 
850
- def test_stress_strain_cards_one_per_deformable_part(self, sim_with_full_steps):
854
+ def test_von_mises_cards_one_per_deformable_part(self, sim_with_full_steps):
855
+ sim_with_full_steps.make_manifest_v2()
856
+ cards = sim_with_full_steps.manifest["cardsConfig"]["B"]
857
+ ids = [c["id"] for c in cards]
858
+ assert ids == ["vonMisesStress1", "vonMisesStress2", "vonMisesStress3"]
859
+ for card in cards:
860
+ assert card["component"] == "SingleExperimentHistogram"
861
+ assert card["props"]["dataSource"] == card["id"].replace(
862
+ "vonMisesStress", "vonMisesStressHistogram"
863
+ )
864
+
865
+ def test_von_mises_cards_absent_when_step_missing(self, ply_folder, basic_parts, tmp_path):
866
+ sim = CompressionSimulation(
867
+ parts=basic_parts,
868
+ simulation_name="t",
869
+ stl_folder_path=str(ply_folder),
870
+ output_path=str(tmp_path / "out"),
871
+ client=MagicMock(),
872
+ workflow_steps=[WorkflowStep(WorkflowStepType.COMPRESS)],
873
+ )
874
+ sim.make_manifest_v2()
875
+ assert sim.manifest["cardsConfig"]["B"] == []
876
+
877
+ def test_stress_strain_cards_in_pane_a_after_force_displacement(self, sim_with_full_steps):
851
878
  sim_with_full_steps.make_manifest_v2()
852
- ids = [c["id"] for c in sim_with_full_steps.manifest["cardsConfig"]["B"]]
853
- assert "stressStrain1" in ids
854
- assert "stressStrain2" in ids
855
- assert "stressStrain3" in ids
879
+ ids = [c["id"] for c in sim_with_full_steps.manifest["cardsConfig"]["A"]]
880
+ assert ids == [
881
+ "forceDisplacement",
882
+ "stressStrain1",
883
+ "stressStrain2",
884
+ "stressStrain3",
885
+ ]
856
886
  # Piston (material_index 0) gets no stress-strain card.
857
887
  assert "stressStrain0" not in ids
858
888
 
@@ -860,7 +890,7 @@ class TestMakeManifestV2:
860
890
  sim_with_full_steps.make_manifest_v2()
861
891
  cards = [
862
892
  c
863
- for c in sim_with_full_steps.manifest["cardsConfig"]["B"]
893
+ for c in sim_with_full_steps.manifest["cardsConfig"]["A"]
864
894
  if c["id"].startswith("stressStrain")
865
895
  ]
866
896
  assert cards
@@ -880,9 +910,14 @@ class TestMakeManifestV2:
880
910
  workflow_steps=[WorkflowStep(WorkflowStepType.COMPRESS)],
881
911
  )
882
912
  sim.make_manifest_v2()
883
- ids = [c["id"] for c in sim.manifest["cardsConfig"]["B"]]
913
+ ids = [c["id"] for c in sim.manifest["cardsConfig"]["A"]]
884
914
  assert not any(i.startswith("stressStrain") for i in ids)
885
915
 
916
+ def test_pane_c_is_energy_volume_only(self, sim_with_full_steps):
917
+ sim_with_full_steps.make_manifest_v2(results=[])
918
+ ids = [c["id"] for c in sim_with_full_steps.manifest["cardsConfig"]["C"]]
919
+ assert ids == ["energyVolume"]
920
+
886
921
 
887
922
  class TestResultsHaveEnergyMetrics:
888
923
  def test_returns_true_when_energy_metrics_step_present(self, ply_folder, basic_parts, tmp_path):
File without changes
File without changes
File without changes