Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-09 09:29:52

0001 #!/usr/bin/env python
0002 """Submit ten Slurm jobs together, monitor them, and collect per-job outputs."""
0003 
0004 from __future__ import annotations
0005 
0006 import json
0007 import sys
0008 import time
0009 from collections import Counter
0010 from datetime import UTC, datetime
0011 from pathlib import Path
0012 from typing import Any, Dict, List
0013 
0014 
0015 REPO_ROOT = Path(__file__).resolve().parents[3]
0016 SRC_ROOT = REPO_ROOT / "src"
0017 for candidate in (str(REPO_ROOT), str(SRC_ROOT)):
0018     if candidate not in sys.path:
0019         sys.path.insert(0, candidate)
0020 
0021 from aid2e.optimizers.base import Trial
0022 from aid2e.schedulers.Slurm import SlurmRunnerConfig, SlurmScheduler
0023 
0024 
0025 DEFAULT_SETUP_COMMANDS = [
0026     "module load miniforge3/24.9.2-0",
0027     "conda activate env_AID2E",
0028 ]
0029 
0030 
0031 def build_dtlz2_point(index: int) -> Dict[str, float]:
0032     return {
0033         "DTLZ2_variables.x1": 0.10 + 0.05 * index,
0034         "DTLZ2_variables.x2": 0.65 - 0.02 * index,
0035         "DTLZ2_variables.x3": 0.35 + 0.01 * index,
0036         "DTLZ2_variables.x4": 0.58 - 0.01 * index,
0037         "DTLZ2_variables.x5": 0.42 + 0.01 * index,
0038         **{f"DTLZ2_variables.x{i}": 0.5 for i in range(6, 11)},
0039     }
0040 
0041 
0042 def make_scheduler(run_dir: Path) -> SlurmScheduler:
0043     return SlurmScheduler(
0044         config=SlurmRunnerConfig(
0045             job_name_prefix="aid2e_multi10",
0046             setup_commands=list(DEFAULT_SETUP_COMMANDS),
0047             submit_working_dir=str(run_dir),
0048             runtime_working_dir=str(REPO_ROOT),
0049             poll_interval=2,
0050         )
0051     )
0052 
0053 
0054 def main() -> int:
0055     run_dir = REPO_ROOT / "experimental_tests" / "output" / (
0056         f"slurm_ten_simultaneous_jobs_{datetime.now(UTC).strftime('%Y%m%d_%H%M%S')}"
0057     )
0058     run_dir.mkdir(parents=True, exist_ok=True)
0059 
0060     scheduler = make_scheduler(run_dir)
0061     job_definitions: List[Dict[str, Any]] = []
0062     expected_outputs: Dict[str, Path] = {}
0063 
0064     for index in range(10):
0065         design_point = build_dtlz2_point(index)
0066         job_name = f"dtlz2_design_{index}"
0067         design_path = run_dir / "designs" / f"{job_name}.json"
0068         output_path = run_dir / "results" / f"{job_name}.json"
0069         Trial(index=index, parameters=design_point, status="pending").save_to_json(design_path)
0070 
0071         job_definitions.append(
0072             {
0073                 "name": job_name,
0074                 "command": (
0075                     "python examples/dtlz2/dtlz2_evaluator.py "
0076                     f"--design {design_path} "
0077                     f"--output {output_path} "
0078                     f"--label {job_name} "
0079                     "--sleep-sec 0.6 "
0080                     "--repeat 3"
0081                 ),
0082                 "payload": {"execution_dir": str(run_dir / "runtime" / job_name)},
0083                 "outputs": [{"path": str(output_path), "format": "json"}],
0084                 "resources": {"time": "00:05:00"},
0085             }
0086         )
0087         expected_outputs[job_name] = output_path
0088 
0089     stage_id = scheduler.submit_stage(
0090         "ten_dtlz2_designs",
0091         job_definitions,
0092         parallelism_policy={"poll_interval": 1},
0093         working_dir=str(run_dir / "scheduler"),
0094     )
0095 
0096     history: List[Dict[str, Any]] = []
0097     while True:
0098         stage_status = scheduler.check_stage_status(stage_id)
0099         counts = Counter(job.status for job in stage_status.job_statuses or [])
0100         snapshot = {
0101             "timestamp_utc": datetime.now(UTC).isoformat(),
0102             "stage_status": stage_status.status,
0103             "completed_jobs": stage_status.completed_jobs,
0104             "total_jobs": stage_status.total_jobs,
0105             "status_counts": dict(counts),
0106         }
0107         history.append(snapshot)
0108         print(f"[ten-jobs] {snapshot}")
0109         if stage_status.status in {"completed", "failed", "cancelled"}:
0110             break
0111         time.sleep(1)
0112 
0113     result = scheduler.get_stage_results(stage_id)
0114     if not result.success:
0115         raise RuntimeError(f"Expected all 10 jobs to succeed, got: {result.error_message}")
0116     if len(result.job_statuses) != 10:
0117         raise RuntimeError(f"Expected 10 job statuses, got {len(result.job_statuses)}")
0118     if any(job.status != "completed" for job in result.job_statuses):
0119         raise RuntimeError("Expected all ten jobs to complete successfully")
0120 
0121     per_job_outputs = {}
0122     for job_status in result.job_statuses:
0123         if not job_status.outputs or "f1" not in job_status.outputs or "f2" not in job_status.outputs:
0124             raise RuntimeError(f"Missing objective outputs for job {job_status.job_id}: {job_status.outputs}")
0125         per_job_outputs[job_status.job_id] = job_status.outputs
0126 
0127     for job_name, output_path in expected_outputs.items():
0128         if not output_path.exists():
0129             raise RuntimeError(f"Expected output file missing for {job_name}: {output_path}")
0130 
0131     summary = {
0132         "stage_id": stage_id,
0133         "history": history,
0134         "jobs": [
0135             {
0136                 "job_id": job_status.job_id,
0137                 "status": job_status.status,
0138                 "return_code": job_status.return_code,
0139                 "slurm_job_id": (job_status.metrics or {}).get("slurm_job_id"),
0140                 "outputs": job_status.outputs,
0141             }
0142             for job_status in result.job_statuses
0143         ],
0144         "design_files": sorted(str(path) for path in (run_dir / "designs").glob("*.json")),
0145         "result_files": sorted(str(path) for path in (run_dir / "results").glob("*.json")),
0146     }
0147     summary_path = run_dir / "run_slurm_ten_simultaneous_jobs.summary.json"
0148     summary_path.write_text(json.dumps(summary, indent=2), encoding="utf-8")
0149     print(json.dumps(summary, indent=2))
0150     return 0
0151 
0152 
0153 if __name__ == "__main__":
0154     raise SystemExit(main())