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.
- {metafold-0.12.dev9 → metafold-0.12.dev11}/PKG-INFO +1 -1
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/compression_simulation.py +30 -37
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/run_experiment.py +6 -3
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/PKG-INFO +1 -1
- {metafold-0.12.dev9 → metafold-0.12.dev11}/pyproject.toml +1 -1
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_compression_simulation.py +68 -33
- {metafold-0.12.dev9 → metafold-0.12.dev11}/LICENSE +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/README.md +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/__init__.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/api.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/assets.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/auth.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/client.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/exceptions.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/jobs.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/materials.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/projects.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/__init__.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/simulation/compression_experiment.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/utils.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold/workflows.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/SOURCES.txt +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/dependency_links.txt +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/requires.txt +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/metafold.egg-info/top_level.txt +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/setup.cfg +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_assets.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_compession_experiment.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_jobs.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_materials.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_projects.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_run_experiment.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_shear_simulation.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_utils.py +0 -0
- {metafold-0.12.dev9 → metafold-0.12.dev11}/tests/test_workflows.py +0 -0
|
@@ -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
|
-
|
|
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
|
-
|
|
2677
|
-
|
|
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"]["
|
|
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",
|
|
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:
|
|
@@ -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
|
|
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"]["
|
|
853
|
-
assert
|
|
854
|
-
|
|
855
|
-
|
|
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"]["
|
|
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"]["
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|