From 74cddae5cfd15a101d25a8a6a7b3a2bc61d6dc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 9 Feb 2026 07:18:39 +0100 Subject: [PATCH 1/6] debug: API with SLURM support --- amorphouspy_api/src/amorphouspy_api/app.py | 68 ++++++++++----------- amorphouspy_api/src/amorphouspy_api/jobs.py | 7 +-- 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/amorphouspy_api/src/amorphouspy_api/app.py b/amorphouspy_api/src/amorphouspy_api/app.py index c48c9ed9..86bfbb50 100644 --- a/amorphouspy_api/src/amorphouspy_api/app.py +++ b/amorphouspy_api/src/amorphouspy_api/app.py @@ -107,41 +107,41 @@ def submit_to_executor(request_data: dict) -> dict: """ try: # Create fresh executor to properly detect cached results - exe = get_executor(cache_directory=MELTQUENCH_PROJECT_DIR) - - # Get LAMMPS-specific resource configuration - lammps_resource_dict = get_lammps_resource_dict() - - # Submit the workflow - this returns a future for the final result - future = run_meltquench_workflow( - executor=exe, - components=request_data["components"], - values=request_data["values"], - n_atoms=request_data["n_atoms"], - potential_type=request_data["potential_type"], - heating_rate=request_data["heating_rate"], - cooling_rate=request_data["cooling_rate"], - n_print=request_data["n_print"], - lammps_resource_dict=lammps_resource_dict, - ) + with get_executor(cache_directory=MELTQUENCH_PROJECT_DIR) as exe: + + # Get LAMMPS-specific resource configuration + lammps_resource_dict = get_lammps_resource_dict() + + # Submit the workflow - this returns a future for the final result + future = run_meltquench_workflow( + executor=exe, + components=request_data["components"], + values=request_data["values"], + n_atoms=request_data["n_atoms"], + potential_type=request_data["potential_type"], + heating_rate=request_data["heating_rate"], + cooling_rate=request_data["cooling_rate"], + n_print=request_data["n_print"], + lammps_resource_dict=lammps_resource_dict, + ) - # Wait briefly for cache check to complete (happens in background thread) - # With wait=False, executorlib checks cache asynchronously - for _ in range(10): # Up to 1 second - if future.done(): - break - time.sleep(0.1) - - # Check if result is already available (from cache or completed) - if future.done() and not future.cancelled(): - try: - result = future.result() - # Serialize using MeltquenchResult to handle ASE Atoms objects - serialized_result = MeltquenchResult(**result).model_dump() - return {"state": "complete", "result": serialized_result} - except Exception as e: - logger.exception("Job failed with exception") - return {"state": "error", "error": str(e)} + # Wait briefly for cache check to complete (happens in background thread) + # With wait=False, executorlib checks cache asynchronously + for _ in range(10): # Up to 1 second + if future.done(): + break + time.sleep(0.1) + + # Check if result is already available (from cache or completed) + if future.done() and not future.cancelled(): + try: + result = future.result() + # Serialize using MeltquenchResult to handle ASE Atoms objects + serialized_result = MeltquenchResult(**result).model_dump() + return {"state": "complete", "result": serialized_result} + except Exception as e: + logger.exception("Job failed with exception") + return {"state": "error", "error": str(e)} # Job is running in background return {"state": "running"} diff --git a/amorphouspy_api/src/amorphouspy_api/jobs.py b/amorphouspy_api/src/amorphouspy_api/jobs.py index 21c5dd76..f46b2c65 100644 --- a/amorphouspy_api/src/amorphouspy_api/jobs.py +++ b/amorphouspy_api/src/amorphouspy_api/jobs.py @@ -20,7 +20,7 @@ from typing import TYPE_CHECKING, Any if TYPE_CHECKING: - from executorlib.executor.single import TestClusterExecutor + from executorlib.api import TestClusterExecutor logger = logging.getLogger(__name__) @@ -40,7 +40,7 @@ def get_executor_class() -> type: else: # Use TestClusterExecutor for local - it supports wait=False # (SingleNodeExecutor does not support wait=False) - from executorlib.executor.single import TestClusterExecutor + from executorlib.api import TestClusterExecutor return TestClusterExecutor @@ -107,7 +107,4 @@ def get_executor(cache_directory: Path) -> "TestClusterExecutor": executor = executor_class(cache_directory=cache_directory, **executor_config) - # Enter context manager - executor.__enter__() - return executor From 9f132551157fab93a9607abb8d3b5bc2b7ca288d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 9 Feb 2026 07:21:20 +0100 Subject: [PATCH 2/6] fix ruff --- amorphouspy_api/src/amorphouspy_api/jobs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/amorphouspy_api/src/amorphouspy_api/jobs.py b/amorphouspy_api/src/amorphouspy_api/jobs.py index f46b2c65..38ff79ab 100644 --- a/amorphouspy_api/src/amorphouspy_api/jobs.py +++ b/amorphouspy_api/src/amorphouspy_api/jobs.py @@ -105,6 +105,4 @@ def get_executor(cache_directory: Path) -> "TestClusterExecutor": cache_directory, ) - executor = executor_class(cache_directory=cache_directory, **executor_config) - - return executor + return executor_class(cache_directory=cache_directory, **executor_config) From d7ce6384c855aca91928244a2df1ab1b9acbc2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 9 Feb 2026 07:34:43 +0100 Subject: [PATCH 3/6] remove empty line --- amorphouspy_api/src/amorphouspy_api/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/amorphouspy_api/src/amorphouspy_api/app.py b/amorphouspy_api/src/amorphouspy_api/app.py index 86bfbb50..4c7b08a4 100644 --- a/amorphouspy_api/src/amorphouspy_api/app.py +++ b/amorphouspy_api/src/amorphouspy_api/app.py @@ -108,7 +108,6 @@ def submit_to_executor(request_data: dict) -> dict: try: # Create fresh executor to properly detect cached results with get_executor(cache_directory=MELTQUENCH_PROJECT_DIR) as exe: - # Get LAMMPS-specific resource configuration lammps_resource_dict = get_lammps_resource_dict() From 0f923218a0d93f26c4f7496d74e79c9c0a2ceb7b Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Mon, 9 Feb 2026 09:37:44 +0100 Subject: [PATCH 4/6] add request data to dict --- amorphouspy_api/src/amorphouspy_api/database.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/amorphouspy_api/src/amorphouspy_api/database.py b/amorphouspy_api/src/amorphouspy_api/database.py index d5a1df13..fdd1c8af 100644 --- a/amorphouspy_api/src/amorphouspy_api/database.py +++ b/amorphouspy_api/src/amorphouspy_api/database.py @@ -252,6 +252,9 @@ def _task_to_dict(self, task: Task) -> dict[str, Any]: if task.error_message: task_dict["error"] = task.error_message + if task.request_data: + task_dict["request_data"] = task.request_data + return task_dict def _update_task_from_dict(self, task: Task, task_data: dict[str, Any]) -> None: From 54e88a23ca0c547b5337c4150e2c0241e02a10ef Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Mon, 9 Feb 2026 09:42:12 +0100 Subject: [PATCH 5/6] update test --- amorphouspy_api/src/tests/test_meltquench.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/amorphouspy_api/src/tests/test_meltquench.py b/amorphouspy_api/src/tests/test_meltquench.py index 8d767d00..452ed41d 100644 --- a/amorphouspy_api/src/tests/test_meltquench.py +++ b/amorphouspy_api/src/tests/test_meltquench.py @@ -154,7 +154,16 @@ def test_check_running_then_complete() -> None: task_id, { "state": "running", - "request_data": {"components": ["SiO2"], "values": [100.0], "unit": "wt"}, + "request_data": { + "components": ["SiO2"], + "values": [100.0], + "unit": "wt", + "n_atoms": 3, + "potential_type": "test", + "heating_rate": 1e12, + "cooling_rate": 1e12, + "n_print": 100, + }, "request_hash": "test-hash-running", }, ) From c9ed9ceb0c23e597336d1531aa30f7c109a813d1 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Mon, 9 Feb 2026 09:48:00 +0100 Subject: [PATCH 6/6] wait 5 sec for mock future --- amorphouspy_api/src/tests/test_meltquench.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/amorphouspy_api/src/tests/test_meltquench.py b/amorphouspy_api/src/tests/test_meltquench.py index 452ed41d..6171747e 100644 --- a/amorphouspy_api/src/tests/test_meltquench.py +++ b/amorphouspy_api/src/tests/test_meltquench.py @@ -21,10 +21,14 @@ class MockFuture: def __init__(self, result: dict[str, Any]) -> None: """Initialize mock future with result.""" self._result = result + self._time = time.time() def done(self) -> bool: """Return True to indicate job is complete.""" - return True + if time.time() - self._time > 5: + return True + else: + return False def cancelled(self) -> bool: """Return False to indicate job was not cancelled.""" @@ -155,8 +159,8 @@ def test_check_running_then_complete() -> None: { "state": "running", "request_data": { - "components": ["SiO2"], - "values": [100.0], + "components": ["SiO2"], + "values": [100.0], "unit": "wt", "n_atoms": 3, "potential_type": "test",