Back to home page

EIC code displayed by LXR

 
 

    


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

0001 """Complete DAG Executor usage examples.
0002 
0003 Demonstrates how to use the DAG Executor to orchestrate workflows with:
0004 1. Simple sequential workflow
0005 2. Parallel job execution with job_factory
0006 3. Multi-stage workflow with dependencies
0007 4. Container-based evaluators
0008 5. Complete optimizer integration example
0009 
0010 Project: AID2E v0.0.0 - AI assisted Detector Design for EIC
0011 """
0012 
0013 import sys
0014 from pathlib import Path
0015 
0016 REPO_ROOT = Path(__file__).resolve().parents[3]
0017 if str(REPO_ROOT) not in sys.path:
0018     sys.path.insert(0, str(REPO_ROOT))
0019 
0020 from aid2e.utilities.workflows import (
0021     DAGExecutor,
0022     WorkflowDefinition,
0023     BranchDefinition,
0024     StageDefinition,
0025     JobDefinition,
0026     JobFactory,
0027     ParallelismPolicy,
0028     ArtifactSpec,
0029 )
0030 from aid2e.utilities.configurations.objectives import (
0031     ObjectiveDefinition,
0032     ObjectiveDirection,
0033 )
0034 
0035 
0036 def example_1_simple_workflow():
0037     """Example 1: Simple workflow with one stage and one job."""
0038     print("\n" + "="*80)
0039     print("Example 1: Simple Sequential Workflow")
0040     print("="*80)
0041     
0042     # Define a simple job that evaluates DTLZ2
0043     eval_job = JobDefinition(
0044         name="dtlz2_eval",
0045         command="python -c \"import json; obj={'f1': 0.234, 'f2': 0.876}; print(json.dumps(obj))\"",
0046         payload={"evaluator_type": "bash"},
0047     )
0048     
0049     # Define a stage containing the job
0050     eval_stage = StageDefinition(
0051         name="evaluate",
0052         jobs=[eval_job],
0053     )
0054     
0055     # Define a branch containing the stage
0056     main_branch = BranchDefinition(
0057         name="main",
0058         stages=[eval_stage],
0059     )
0060     
0061     # Define the workflow
0062     workflow = WorkflowDefinition(
0063         name="dtlz2_simple",
0064         description="Simple DTLZ2 evaluation workflow",
0065         branches=[main_branch],
0066         objectives=[
0067             ObjectiveDefinition(
0068                 name="f1",
0069                 direction=ObjectiveDirection.MINIMIZE,
0070             ),
0071             ObjectiveDefinition(
0072                 name="f2",
0073                 direction=ObjectiveDirection.MINIMIZE,
0074             ),
0075         ],
0076     )
0077     
0078     # Create executor
0079     executor = DAGExecutor(
0080         workflow=workflow,
0081         base_output_dir="/tmp/aid2e_examples",
0082         log_level="INFO",
0083     )
0084     
0085     # Execute for a design point
0086     design_point = {"x1": 0.5, "x2": 0.7, "x3": 0.3}
0087     print(f"\nExecuting workflow for design point: {design_point}")
0088     
0089     objectives = executor.execute(design_point)
0090     
0091     print(f"\n✅ Workflow completed!")
0092     print(f"Objectives: {objectives}")
0093     print(f"Output directory: {executor.output_dir}")
0094 
0095 
0096 def example_2_parallel_jobs():
0097     """Example 2: Workflow with parallel job execution."""
0098     print("\n" + "="*80)
0099     print("Example 2: Parallel Job Execution with JobFactory")
0100     print("="*80)
0101     
0102     # Job template that will be expanded to N parallel jobs
0103     eval_job = JobDefinition(
0104         name="parallel_eval",
0105         command="echo 'Evaluating design point with job_index={{job_index}}'",
0106         payload={"evaluator_type": "bash"},
0107     )
0108     
0109     # Stage with job_factory to expand to 4 parallel jobs
0110     eval_stage = StageDefinition(
0111         name="parallel_evaluate",
0112         jobs=[eval_job],
0113         job_factory=JobFactory(
0114             type="range",
0115             params={"n": 4},  # Create 4 parallel jobs
0116         ),
0117         parallelism=ParallelismPolicy(
0118             max_concurrent=4,
0119             retry_max=2,
0120             timeout_sec=300,
0121         ),
0122     )
0123     
0124     branch = BranchDefinition(name="main", stages=[eval_stage])
0125     
0126     workflow = WorkflowDefinition(
0127         name="parallel_workflow",
0128         description="Workflow with 4 parallel evaluations",
0129         branches=[branch],
0130         objectives=[],
0131     )
0132     
0133     executor = DAGExecutor(workflow, base_output_dir="/tmp/aid2e_examples")
0134     design_point = {"x1": 0.5, "x2": 0.7}
0135     
0136     print(f"\nExecuting workflow with 4 parallel jobs...")
0137     objectives = executor.execute(design_point)
0138     
0139     print(f"\n✅ Workflow completed with 4 parallel jobs!")
0140     print(f"Total jobs executed: {len(executor.global_xcom)}")
0141 
0142 
0143 def example_3_multi_stage_workflow():
0144     """Example 3: Multi-stage workflow with sequential dependencies."""
0145     print("\n" + "="*80)
0146     print("Example 3: Multi-Stage Workflow with Dependencies")
0147     print("="*80)
0148     
0149     # Stage 1: Generate input data
0150     generate_job = JobDefinition(
0151         name="generate_data",
0152         command="echo 'Generating simulation input data'",
0153         payload={"evaluator_type": "bash"},
0154     )
0155     
0156     generate_stage = StageDefinition(
0157         name="generate",
0158         jobs=[generate_job],
0159     )
0160     
0161     # Stage 2: Run simulation (depends on generate)
0162     simulate_job = JobDefinition(
0163         name="run_simulation",
0164         command="echo 'Running physics simulation'",
0165         payload={"evaluator_type": "bash"},
0166     )
0167     
0168     simulate_stage = StageDefinition(
0169         name="simulate",
0170         jobs=[simulate_job],
0171     )
0172     
0173     # Stage 3: Compute objectives (depends on simulate)
0174     compute_job = JobDefinition(
0175         name="compute_objectives",
0176         command="python -c \"import json; print(json.dumps({'f1': 0.5, 'f2': 0.8}))\"",
0177         payload={"evaluator_type": "bash"},
0178     )
0179     
0180     compute_stage = StageDefinition(
0181         name="compute",
0182         jobs=[compute_job],
0183     )
0184     
0185     # Stages are executed sequentially: generate → simulate → compute
0186     branch = BranchDefinition(
0187         name="main",
0188         stages=[generate_stage, simulate_stage, compute_stage],
0189     )
0190     
0191     workflow = WorkflowDefinition(
0192         name="multi_stage_workflow",
0193         description="Sequential pipeline: generate → simulate → compute",
0194         branches=[branch],
0195         objectives=[],
0196     )
0197     
0198     executor = DAGExecutor(workflow, base_output_dir="/tmp/aid2e_examples")
0199     design_point = {"energy": 100, "angle": 45}
0200     
0201     print(f"\nExecuting 3-stage sequential workflow...")
0202     objectives = executor.execute(design_point)
0203     
0204     print(f"\n✅ Multi-stage workflow completed!")
0205     print(f"Stages executed: generate → simulate → compute")
0206 
0207 
0208 def example_4_container_evaluators():
0209     """Example 4: Using ContainerEvaluator for Docker-based jobs."""
0210     print("\n" + "="*80)
0211     print("Example 4: Container-Based Workflow (ContainerEvaluator)")
0212     print("="*80)
0213     
0214     # Job using ContainerEvaluator
0215     container_job = JobDefinition(
0216         name="docker_simulation",
0217         command="python /app/simulate.py",  # Command inside container
0218         payload={
0219             "evaluator_type": "container",
0220             "image": "python:3.9-slim",
0221             "container_command": [
0222                 "/bin/bash", "-c",
0223                 "python -c \"import json; print(json.dumps({'f1': 0.3, 'f2': 0.9}))\""
0224             ],
0225             "environment": {
0226                 "SIMULATION_MODE": "fast",
0227                 "NUM_EVENTS": "1000",
0228             },
0229             "volumes": {
0230                 "/tmp/input": "/app/input",
0231                 "/tmp/output": "/app/output",
0232             },
0233         },
0234         resources={
0235             "cpu": "2",
0236             "memory": "4GB",
0237         },
0238     )
0239     
0240     stage = StageDefinition(
0241         name="containerized_eval",
0242         jobs=[container_job],
0243     )
0244     
0245     branch = BranchDefinition(name="main", stages=[stage])
0246     
0247     workflow = WorkflowDefinition(
0248         name="container_workflow",
0249         description="Workflow using Docker containers",
0250         branches=[branch],
0251         objectives=[],
0252     )
0253     
0254     executor = DAGExecutor(workflow, base_output_dir="/tmp/aid2e_examples")
0255     design_point = {"detector_thickness": 5.0}
0256     
0257     print(f"\nExecuting containerized workflow...")
0258     print(f"Container image: python:3.9-slim")
0259     print(f"Environment: SIMULATION_MODE=fast, NUM_EVENTS=1000")
0260     
0261     try:
0262         objectives = executor.execute(design_point)
0263         print(f"\n✅ Container workflow completed!")
0264     except Exception as e:
0265         print(f"\n⚠️  Container workflow failed (Docker may not be available): {e}")
0266         print("This is expected if Docker is not installed.")
0267 
0268 
0269 def example_5_optimizer_integration():
0270     """Example 5: Complete optimizer integration example."""
0271     print("\n" + "="*80)
0272     print("Example 5: Complete Optimizer Integration")
0273     print("="*80)
0274     
0275     # Define workflow for optimizer
0276     eval_job = JobDefinition(
0277         name="evaluate_design",
0278         command=(
0279             "python -c \""
0280             "import json, sys; "
0281             "import numpy as np; "
0282             "# DTLZ2 objectives; "
0283             "x = [0.5, 0.7, 0.3]; "
0284             "f1 = x[0]; "
0285             "f2 = (1 + sum([(xi - 0.5)**2 for xi in x[1:]])) * (1 - np.sqrt(x[0]/(1 + sum([(xi - 0.5)**2 for xi in x[1:]]))));  "
0286             "print(json.dumps({'f1': float(f1), 'f2': float(f2)})); "
0287             "\""
0288         ),
0289         payload={"evaluator_type": "bash"},
0290     )
0291     
0292     eval_stage = StageDefinition(
0293         name="evaluate",
0294         jobs=[eval_job],
0295     )
0296     
0297     branch = BranchDefinition(name="main", stages=[eval_stage])
0298     
0299     workflow = WorkflowDefinition(
0300         name="optimizer_workflow",
0301         description="Workflow for optimizer integration",
0302         branches=[branch],
0303         objectives=[
0304             ObjectiveDefinition(name="f1", direction=ObjectiveDirection.MINIMIZE),
0305             ObjectiveDefinition(name="f2", direction=ObjectiveDirection.MINIMIZE),
0306         ],
0307     )
0308     
0309     executor = DAGExecutor(workflow, base_output_dir="/tmp/aid2e_examples")
0310     
0311     print("\nSimulating optimizer loop with 3 design points...")
0312     
0313     # Simulate optimizer providing design points
0314     design_points = [
0315         {"x1": 0.2, "x2": 0.5, "x3": 0.8},
0316         {"x1": 0.5, "x2": 0.7, "x3": 0.3},
0317         {"x1": 0.8, "x2": 0.3, "x3": 0.6},
0318     ]
0319     
0320     results = []
0321     for i, design_point in enumerate(design_points):
0322         print(f"\n  Iteration {i+1}: Evaluating {design_point}")
0323         objectives = executor.execute(design_point)
0324         results.append({
0325             "design_point": design_point,
0326             "objectives": objectives,
0327         })
0328         print(f"  → Objectives: {objectives}")
0329     
0330     print(f"\n✅ Optimizer integration complete!")
0331     print(f"\nResults summary:")
0332     for i, result in enumerate(results):
0333         print(f"  {i+1}. {result['design_point']} → {result['objectives']}")
0334 
0335 
0336 def example_6_workflow_from_config():
0337     """Example 6: Load workflow from YAML config file."""
0338     print("\n" + "="*80)
0339     print("Example 6: Loading Workflow from Config File")
0340     print("="*80)
0341     
0342     from aid2e.utilities.configurations import load_config
0343     from aid2e.utilities.runtime_builders import build_workflow_executor_from_config
0344 
0345     config_path = REPO_ROOT / "examples/dtlz2/configurations/dtlz2_ax_joblib.yml"
0346     loaded_config = load_config(str(config_path))
0347     executor = build_workflow_executor_from_config(
0348         loaded_config.workflows,
0349         problem_cfg=loaded_config.problem,
0350         scheduler_cfg=loaded_config.scheduler,
0351         config_dir=str(config_path.parent),
0352         base_output_dir="/tmp/aid2e_examples",
0353     )
0354 
0355     design_point = {
0356         name: parameter.value
0357         for name, parameter in loaded_config.problem.design_config.get_flat_parameters().items()
0358     }
0359     objectives = executor.execute(design_point)
0360     print(f"Config: {config_path}")
0361     print(f"Workflow name: {executor.workflow.name}")
0362     print(f"Objectives: {objectives}")
0363 
0364 
0365 if __name__ == "__main__":
0366     print("\n" + "="*80)
0367     print("DAG Executor Complete Examples")
0368     print("="*80)
0369     print("\nThese examples demonstrate the full capabilities of the DAG Executor")
0370     print("for orchestrating multi-stage, multi-objective workflows.\n")
0371     
0372     # Run all examples
0373     example_1_simple_workflow()
0374     example_2_parallel_jobs()
0375     example_3_multi_stage_workflow()
0376     example_4_container_evaluators()
0377     example_5_optimizer_integration()
0378     example_6_workflow_from_config()
0379     
0380     print("\n" + "="*80)
0381     print("All examples completed!")
0382     print("="*80)