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
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
0050 eval_stage = StageDefinition(
0051 name="evaluate",
0052 jobs=[eval_job],
0053 )
0054
0055
0056 main_branch = BranchDefinition(
0057 name="main",
0058 stages=[eval_stage],
0059 )
0060
0061
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
0079 executor = DAGExecutor(
0080 workflow=workflow,
0081 base_output_dir="/tmp/aid2e_examples",
0082 log_level="INFO",
0083 )
0084
0085
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
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
0110 eval_stage = StageDefinition(
0111 name="parallel_evaluate",
0112 jobs=[eval_job],
0113 job_factory=JobFactory(
0114 type="range",
0115 params={"n": 4},
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
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
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
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
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
0215 container_job = JobDefinition(
0216 name="docker_simulation",
0217 command="python /app/simulate.py",
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
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
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
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)