metafold 0.13.1.dev0__tar.gz → 0.13.2__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.13.1.dev0 → metafold-0.13.2}/PKG-INFO +1 -1
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/simulation/compression_simulation.py +45 -24
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/simulation/run_experiment.py +11 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold.egg-info/PKG-INFO +1 -1
- {metafold-0.13.1.dev0 → metafold-0.13.2}/pyproject.toml +1 -1
- {metafold-0.13.1.dev0 → metafold-0.13.2}/LICENSE +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/README.md +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/__init__.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/api.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/assets.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/auth.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/client.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/exceptions.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/jobs.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/materials.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/projects.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/simulation/__init__.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/simulation/compression_experiment.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/utils.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold/workflows.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold.egg-info/SOURCES.txt +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold.egg-info/dependency_links.txt +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold.egg-info/requires.txt +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/metafold.egg-info/top_level.txt +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/setup.cfg +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_assets.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_compession_experiment.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_compression_simulation.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_jobs.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_materials.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_projects.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_run_experiment.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_shear_simulation.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_utils.py +0 -0
- {metafold-0.13.1.dev0 → metafold-0.13.2}/tests/test_workflows.py +0 -0
|
@@ -299,6 +299,39 @@ class ExperimentSupportParallelepiped(ExperimentParallelepiped, ExperimentSuppor
|
|
|
299
299
|
material: Material = field(default_factory=lambda: DEFAULT_SUPPORT_MATERIAL)
|
|
300
300
|
|
|
301
301
|
|
|
302
|
+
def validate_simulation_parts(parts: list) -> None:
|
|
303
|
+
"""Raise ValueError if the parts can't produce a compression simulation.
|
|
304
|
+
|
|
305
|
+
Callers that dispatch work asynchronously should call this up front so
|
|
306
|
+
invalid input fails before any project or job is created.
|
|
307
|
+
"""
|
|
308
|
+
if not parts:
|
|
309
|
+
return
|
|
310
|
+
|
|
311
|
+
has_piston = False
|
|
312
|
+
has_support = False
|
|
313
|
+
piston_moves = False
|
|
314
|
+
for p in parts:
|
|
315
|
+
if isinstance(p, ExperimentPistonBase):
|
|
316
|
+
has_piston = True
|
|
317
|
+
piston_moves = piston_moves or _has_motion(p.velocity)
|
|
318
|
+
elif isinstance(p, ExperimentSupportBase):
|
|
319
|
+
has_support = True
|
|
320
|
+
|
|
321
|
+
if not has_piston and not has_support:
|
|
322
|
+
raise ValueError(
|
|
323
|
+
"No piston part: a compression simulation needs "
|
|
324
|
+
"a rigid part to apply load. Add a part of type piston_mesh, "
|
|
325
|
+
"piston_cylinder, or piston_box."
|
|
326
|
+
)
|
|
327
|
+
# Supports are stationary by design, so only pistons must move.
|
|
328
|
+
if has_piston and not piston_moves:
|
|
329
|
+
raise ValueError(
|
|
330
|
+
"Piston velocity is zero. Set a velocity "
|
|
331
|
+
"profile of [time, vx, vy, vz] rows with a non-zero component."
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
302
335
|
@dataclass
|
|
303
336
|
class ReferenceData:
|
|
304
337
|
csv_path: Path = Path("")
|
|
@@ -491,28 +524,7 @@ class CompressionSimulation:
|
|
|
491
524
|
self.part_infos.append(inner_part)
|
|
492
525
|
|
|
493
526
|
# A rigid part drives the compression.
|
|
494
|
-
|
|
495
|
-
has_piston = False
|
|
496
|
-
has_support = False
|
|
497
|
-
piston_moves = False
|
|
498
|
-
for p in parts:
|
|
499
|
-
if isinstance(p, ExperimentPistonBase):
|
|
500
|
-
has_piston = True
|
|
501
|
-
piston_moves = piston_moves or _has_motion(p.velocity)
|
|
502
|
-
elif isinstance(p, ExperimentSupportBase):
|
|
503
|
-
has_support = True
|
|
504
|
-
if not has_piston and not has_support:
|
|
505
|
-
raise ValueError(
|
|
506
|
-
"No piston part: a compression simulation needs "
|
|
507
|
-
"a rigid part to apply load. Add a part of type piston_mesh, "
|
|
508
|
-
"piston_cylinder, or piston_box."
|
|
509
|
-
)
|
|
510
|
-
# Supports are stationary by design, so only pistons must move.
|
|
511
|
-
if has_piston and not piston_moves:
|
|
512
|
-
raise ValueError(
|
|
513
|
-
"Piston velocity is zero. Set a velocity "
|
|
514
|
-
"profile of [time, vx, vy, vz] rows with a non-zero component."
|
|
515
|
-
)
|
|
527
|
+
validate_simulation_parts(parts)
|
|
516
528
|
|
|
517
529
|
self.setup_ply_files(stl_folder_path)
|
|
518
530
|
self.setup_results(output_path)
|
|
@@ -644,6 +656,7 @@ class CompressionSimulation:
|
|
|
644
656
|
base_url: str = "https://api.metafold3d.com/",
|
|
645
657
|
cancel_existing_workflows: bool = True,
|
|
646
658
|
project_access: Access = Access.PRIVATE,
|
|
659
|
+
user: Optional[str] = None,
|
|
647
660
|
) -> str:
|
|
648
661
|
"""Find an existing project by name or create a new one.
|
|
649
662
|
|
|
@@ -651,6 +664,10 @@ class CompressionSimulation:
|
|
|
651
664
|
client_id + client_secret (local/programmable use, reads from env via
|
|
652
665
|
setup_client). base_url must match the audience the token was issued for.
|
|
653
666
|
|
|
667
|
+
When user is given, only the caller's own projects are reused; a
|
|
668
|
+
same-named project owned by someone else (visible under org access) is
|
|
669
|
+
ignored so it can't be overwritten.
|
|
670
|
+
|
|
654
671
|
When cancel_existing_workflows is True and an existing project is
|
|
655
672
|
reused, its running workflows are cancelled first.
|
|
656
673
|
|
|
@@ -663,10 +680,14 @@ class CompressionSimulation:
|
|
|
663
680
|
auth_domain=auth_domain,
|
|
664
681
|
base_url=base_url,
|
|
665
682
|
)
|
|
666
|
-
# Quote the
|
|
683
|
+
# Quote the values so multi-word names stay a single search term.
|
|
684
|
+
q = f'name:"{project_name}"'
|
|
685
|
+
if user is not None:
|
|
686
|
+
q = f'{q} AND user:"{user}"'
|
|
667
687
|
existing = [
|
|
668
|
-
p for p in client.projects.list(q=
|
|
688
|
+
p for p in client.projects.list(q=q)
|
|
669
689
|
if p.name == project_name # ensure full match
|
|
690
|
+
and (user is None or p.user == user)
|
|
670
691
|
]
|
|
671
692
|
if existing:
|
|
672
693
|
project_id = existing[0].id
|
|
@@ -160,6 +160,7 @@ from metafold.simulation.compression_simulation import (
|
|
|
160
160
|
ExperimentPistonMesh,
|
|
161
161
|
SimulationParameters,
|
|
162
162
|
WorkflowStep,
|
|
163
|
+
validate_simulation_parts,
|
|
163
164
|
)
|
|
164
165
|
|
|
165
166
|
# Build preset lookup from all Material constants in the materials module.
|
|
@@ -243,6 +244,16 @@ def _build_parts(parts_config: list[dict]) -> list[ExperimentPart]:
|
|
|
243
244
|
return parts
|
|
244
245
|
|
|
245
246
|
|
|
247
|
+
def validate_experiment_config(config: dict) -> None:
|
|
248
|
+
"""Raise ValueError if a manifest can't produce a runnable experiment.
|
|
249
|
+
Mirrors the checks run_experiment performs so an API can reject bad
|
|
250
|
+
input before creating a project.
|
|
251
|
+
"""
|
|
252
|
+
if not config.get("project_name", ""):
|
|
253
|
+
raise ValueError("project_name is required")
|
|
254
|
+
validate_simulation_parts(_build_parts(config.get("parts", [])))
|
|
255
|
+
|
|
256
|
+
|
|
246
257
|
def _build_varying(varying_config: list[dict]) -> list[ExperimentVarying]:
|
|
247
258
|
varying: list[ExperimentVarying] = []
|
|
248
259
|
for entry in varying_config:
|
|
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
|
|
File without changes
|