schema_v2.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. """Simulation Plan Schema V2 (P3-M1).
  2. Extends V1 with multi-fidelity strategy, search strategy,
  3. calibration policy, and acceptance criteria per third-party review.
  4. Backward compatible: V1 plans without these fields use defaults.
  5. """
  6. from enum import Enum
  7. from typing import Optional, List, Dict, Any
  8. from pydantic import BaseModel, Field
  9. # ============================================================
  10. # Enums
  11. # ============================================================
  12. class StrategyMode(str, Enum):
  13. """Simulation strategy mode."""
  14. FAST_FEASIBLE = "fast_feasible" # Default: constrained Bayesian / active learning
  15. PARETO_EXPLORATION = "pareto_exploration" # Morris + LHS + Kriging + NSGA-II
  16. HIGH_FIDELITY_VALIDATION = "high_fidelity_validation" # L2 + L3 verification
  17. ROBUSTNESS_CHECK = "robustness_check" # Tolerance / disturbance analysis
  18. class FidelityLevel(str, Enum):
  19. """Multi-fidelity levels L0-L4."""
  20. L0_ANALYTIC = "L0_analytic" # Analytic formulas + rule engine
  21. L1_MOTORCAD_EMAG = "L1_motorcad_emag" # Motor-CAD fast EM model
  22. L2_MOTORCAD_LAB_THERM = "L2_motorcad_lab_therm" # Motor-CAD Lab/Therm/Mech
  23. L3_MAXWELL_3D = "L3_maxwell_3d" # Maxwell 3D / JMAG high-fidelity
  24. L4_ROBUSTNESS = "L4_robustness" # Tolerance / prototype data
  25. class SearchMethod(str, Enum):
  26. """Search/optimization method."""
  27. CONSTRAINED_BAYESIAN = "constrained_bayesian" # Default: feasibility-first
  28. ACTIVE_LEARNING = "active_learning" # Uncertainty-based sampling
  29. LHS_KRIGING_NSGA2 = "lhs_kriging_nsga2" # Global Pareto exploration
  30. GRID_SCAN = "grid_scan" # Fixed full factorial
  31. TRUST_REGION = "trust_region" # Local trust region search
  32. class ConfidenceGrade(str, Enum):
  33. """Result confidence grade A/B/C/D."""
  34. A = "A" # Full multi-physics + high-fidelity + robustness, design freeze ready
  35. B = "B" # Motor-CAD + at least one high-fidelity check, candidate ready
  36. C = "C" # Motor-CAD only, internal discussion only, no external commitment
  37. D = "D" # Analytic / surrogate only, reference only
  38. class ConvergenceStatus(str, Enum):
  39. """Six types of convergence status (per review)."""
  40. # Solver convergence
  41. SOLVER_PASS = "SOLVER_PASS"
  42. SOLVER_FAIL = "SOLVER_FAIL"
  43. # Hard constraint convergence
  44. FEASIBLE = "FEASIBLE"
  45. INFEASIBLE = "INFEASIBLE"
  46. # Optimization convergence
  47. CONVERGED = "CONVERGED"
  48. STALLED = "STALLED"
  49. # Surrogate model trust
  50. MODEL_TRUSTED = "MODEL_TRUSTED"
  51. MODEL_UNCERTAIN = "MODEL_UNCERTAIN"
  52. # Cross-tool consistency
  53. HF_PASS = "HF_PASS"
  54. HF_FAIL = "HF_FAIL"
  55. # Robustness
  56. ROBUST = "ROBUST"
  57. FRAGILE = "FRAGILE"
  58. # ============================================================
  59. # Strategy Sub-models
  60. # ============================================================
  61. class FidelityStrategy(BaseModel):
  62. """Multi-fidelity execution strategy."""
  63. levels: List[FidelityLevel] = Field(
  64. default_factory=lambda: [
  65. FidelityLevel.L0_ANALYTIC,
  66. FidelityLevel.L1_MOTORCAD_EMAG,
  67. ],
  68. description="Enabled fidelity levels in execution order"
  69. )
  70. upgrade_rule: str = Field(
  71. default="top_candidates_only",
  72. description="Rule for upgrading to higher fidelity: top_candidates_only / threshold_based / all"
  73. )
  74. max_candidates_for_l3: int = Field(
  75. default=3, ge=1, le=10,
  76. description="Max candidates to send to L3 (Maxwell/JMAG)"
  77. )
  78. max_solver_cost_per_level: Optional[Dict[str, int]] = Field(
  79. default=None,
  80. description="Max solver calls per fidelity level, e.g. {'L1': 80, 'L2': 10}"
  81. )
  82. class SearchStrategy(BaseModel):
  83. """Adaptive search strategy."""
  84. method: SearchMethod = Field(
  85. default=SearchMethod.CONSTRAINED_BAYESIAN,
  86. description="Search/optimization method"
  87. )
  88. initial_samples: int = Field(
  89. default=16, ge=4, le=100,
  90. description="Number of initial samples (LHS or from experience)"
  91. )
  92. batch_size: int = Field(
  93. default=4, ge=1, le=16,
  94. description="Number of points per adaptive batch"
  95. )
  96. max_solver_calls: int = Field(
  97. default=80, ge=10, le=500,
  98. description="Maximum total solver calls"
  99. )
  100. local_trust_region: bool = Field(
  101. default=True,
  102. description="Enable local trust region refinement after feasible region found"
  103. )
  104. trust_region_radius: Optional[float] = Field(
  105. default=None,
  106. description="Initial trust region radius as fraction of parameter range"
  107. )
  108. use_experience_seeds: bool = Field(
  109. default=True,
  110. description="Use similar experience cases as initial seeds"
  111. )
  112. class CalibrationPolicy(BaseModel):
  113. """Cross-tool calibration policy (Motor-CAD vs Maxwell/JMAG)."""
  114. enabled: bool = Field(default=False, description="Enable cross-tool calibration")
  115. cross_tool_metrics: List[str] = Field(
  116. default_factory=lambda: ["torque_nm", "efficiency_pct", "axial_force_n"],
  117. description="Metrics to compare across tools"
  118. )
  119. tolerance: Dict[str, float] = Field(
  120. default_factory=lambda: {"torque_pct": 5.0, "efficiency_point": 1.0, "axial_force_pct": 10.0},
  121. description="Acceptable tolerance for cross-tool deviation"
  122. )
  123. correction_method: str = Field(
  124. default="additive",
  125. description="Correction method: additive / multiplicative / co-kriging"
  126. )
  127. feedback_to_surrogate: bool = Field(
  128. default=True,
  129. description="Feed calibration coefficients back to surrogate model and objective"
  130. )
  131. class AcceptanceCriteria(BaseModel):
  132. """Acceptance criteria for convergence and validation."""
  133. hard_constraints: List[str] = Field(
  134. default_factory=list,
  135. description="Hard constraint expressions, e.g. ['torque_nm >= 10', 'temperature_c <= 120']"
  136. )
  137. soft_objectives: Optional[List[str]] = Field(
  138. default=None,
  139. description="Soft objective expressions for optimization"
  140. )
  141. cross_tool_tolerance: Optional[Dict[str, float]] = Field(
  142. default=None,
  143. description="Override cross-tool tolerance"
  144. )
  145. surrogate_max_uncertainty: float = Field(
  146. default=0.05, ge=0.01, le=0.5,
  147. description="Max surrogate model uncertainty for MODEL_TRUSTED status"
  148. )
  149. robustness_required: bool = Field(
  150. default=False,
  151. description="Require robustness check before final acceptance"
  152. )
  153. min_confidence_grade: ConfidenceGrade = Field(
  154. default=ConfidenceGrade.C,
  155. description="Minimum confidence grade for plan acceptance"
  156. )
  157. class ParallelExecution(BaseModel):
  158. """Parallel execution configuration."""
  159. max_instances: int = Field(
  160. default=1, ge=1, le=8,
  161. description="Max parallel Motor-CAD instances"
  162. )
  163. model_copy_strategy: str = Field(
  164. default="per_instance",
  165. description="Model file copy strategy: per_instance / shared_readonly"
  166. )
  167. license_fail_policy: str = Field(
  168. default="queue_retry",
  169. description="Policy on license failure: queue_retry / fail_fast / reduce_instances"
  170. )
  171. # ============================================================
  172. # Schema V2 Main Model
  173. # ============================================================
  174. class SimulationPlanSchemaV2(BaseModel):
  175. """Extended simulation plan schema (V2) per third-party review.
  176. All new fields are optional for backward compatibility with V1 plans.
  177. """
  178. schema_version: str = Field(default="2.0", description="Schema version")
  179. strategy_mode: StrategyMode = Field(
  180. default=StrategyMode.FAST_FEASIBLE,
  181. description="Simulation strategy mode"
  182. )
  183. fidelity_strategy: Optional[FidelityStrategy] = Field(
  184. default=None,
  185. description="Multi-fidelity execution strategy"
  186. )
  187. search_strategy: Optional[SearchStrategy] = Field(
  188. default=None,
  189. description="Adaptive search strategy"
  190. )
  191. calibration_policy: Optional[CalibrationPolicy] = Field(
  192. default=None,
  193. description="Cross-tool calibration policy"
  194. )
  195. acceptance_criteria: Optional[AcceptanceCriteria] = Field(
  196. default=None,
  197. description="Acceptance criteria"
  198. )
  199. parallel_execution: Optional[ParallelExecution] = Field(
  200. default=None,
  201. description="Parallel execution configuration"
  202. )
  203. # V1 fields (preserved)
  204. model_path: Optional[str] = None
  205. topology: Optional[str] = None
  206. variables: List[Dict[str, Any]] = Field(default_factory=list)
  207. cases: List[Dict[str, Any]] = Field(default_factory=list)
  208. boundary_conditions: Optional[Dict[str, Any]] = None
  209. def get_effective_fidelity(self) -> FidelityStrategy:
  210. """Get fidelity strategy with defaults applied."""
  211. return self.fidelity_strategy or FidelityStrategy()
  212. def get_effective_search(self) -> SearchStrategy:
  213. """Get search strategy with defaults applied."""
  214. return self.search_strategy or SearchStrategy()
  215. def get_effective_acceptance(self) -> AcceptanceCriteria:
  216. """Get acceptance criteria with defaults applied."""
  217. return self.acceptance_criteria or AcceptanceCriteria()