|
STAR
Cal STAR — firmware, DAQ server, and engine design
|
Classes | |
| class | _LocalSerialExecutor |
| class | ElitePool |
Functions | |
| float | _layer1_total_wall_thickness_m (Any config) |
| Optional[float] | _throat_area_m2_from_config (PintleEngineConfig config) |
| float | _requirement_float (Dict[str, Any] requirements, str key, float default) |
| float | _layer1_thrust_deadband (Any req) |
| Optional[Dict[str, Any]] | _layer1_igniter_keepouts (Any config_obj, Dict[str, Any] requirements) |
| Dict[str, Any] | _layer1_plate (Any config_obj) |
| Dict[str, Any] | _layer1_injector_plate_constants (Any config_obj, Dict[str, Any] requirements) |
| float | _layer1_centre_clear_m (Any config_obj, Dict[str, Any] requirements) |
| bool | _requirement_bool (Dict[str, Any] requirements, str key, bool default) |
| float | _layer1_infeasibility_gate_eps (Dict[str, Any] requirements) |
| float | _layer1_inf_residual (float infeasibility_score, Dict[str, Any] requirements) |
| bool | _layer1_feasible_for_primary_objective (float infeasibility_score, Dict[str, Any] requirements, *, bool length_violation=False) |
| float | _layer1_inf_residual_from_objective (float obj) |
| bool | _layer1_feasible_scalar_objective (float obj) |
| int | _layer1_valley_escape_tier (int evals, float best_f, int stagnation) |
| np.ndarray | _x_solved_or (Dict[str, Any] res, np.ndarray fallback) |
| None | _store_last_good_eval_bundle_from_worker_res (Dict[str, Any] res, Optional[Dict[str, Any]] state) |
| bool | _lox_ring_inboard (Any spacing_O_m, Any spacing_F_m, *, bool fallback=True) |
| float | _impinging_resultant_tilt_deg (float mdot_O, float mdot_F, float rho_O, float rho_F, float n_elements, float d_jet_O_m, float d_jet_F_m, float angle_O_deg, float angle_F_deg, bool lox_inboard=True, *, float spacing_O_m=float("nan"), float spacing_F_m=float("nan")) |
| float | _resultant_tilt_breakeven_deg (*, float n_elements, float spacing_O_m, float spacing_F_m, float angle_O_deg, float angle_F_deg, float D_chamber_inner_m, float L_chamber_m) |
| float | _resolve_tilt_allowance_deg (*, bool from_reach, float constant_deg, float breakeven_deg, float margin) |
| float | _impinging_resultant_tilt_preference (Any tilt_deg, *, float scale_deg=2.0, float outward_multiplier=25.0) |
| float | _impinging_resultant_wall_violation (Any tilt_deg, *, float max_outward_deg=0.0, float scale_deg=2.0) |
| float | _impinging_momentum_wall_violation (Any R, *, float band_width=0.025, bool safe_side_is_below_one=True, float scale=0.005) |
| float | _impinging_momentum_asymmetric_squared (Any R, *, float wall_side_multiplier=1.0, float low_side_multiplier=1.0, float band_width=0.05, bool safe_side_is_below_one=True, float scale=0.10, Optional[float] band_lo=None, Optional[float] band_hi=None) |
| float | _impinging_momentum_hinge_squared (Any R, *, Optional[float] r_band_lo=None, Optional[float] r_band_hi=None) |
| float | _impinging_momentum_log_target_squared (Any R, *, float rel_deadband=_LAYER1_DEFAULT_MOMENTUM_LOG_DEADBAND_REL) |
| float | _impinging_momentum_band_violation_squared (Any R, *, Optional[float] r_band_lo=None, Optional[float] r_band_hi=None) |
| float | _impinging_angle_hinge_squared (Any impingement_angle_deg, *, Optional[float] angle_band_lo_deg=None, Optional[float] angle_band_hi_deg=None) |
| float | _layer1_lstar_target_from_smd (float smd_um, *, float smd_ref_um=99.0, float Lstar_ref_m=1.10, float exponent=2.0, float Lstar_min_m=0.0, float Lstar_max_m=float("inf")) |
| float | _layer1_lstar_band_term (float Lstar_m, float target_m, float deadband_m) |
| _req_lookup (requirements, key) | |
| float | _layer1_contraction_theta (requirements) |
| float | _layer1_geometry_infeasibility (requirements, *, L_cylindrical, D_chamber_inner, A_chamber, n_elements) |
| float | _layer1_lstar_term (float Lstar_m, float target_m) |
| float | _layer1_chamber_mass_kg (float A_chamber_inner_m2, float L_chamber_m, float total_wall_thickness_m, float wall_density_kg_m3, float Pc_pa=0.0, float closure_yield_pa=205e6, str plate_support="clamped", float r_plate_m=0.0, float poisson=0.3) |
| float | _closure_plate_stress_coeff (str support, float poisson=0.3) |
| float | _layer1_chamber_mass_term (float chamber_mass_kg, float mass_ref_kg) |
| float | _layer1_chamber_od_floor_m (float max_od_m, float wall_total_m, float A_throat_lo_m2, float dt_ratio_min) |
| Dict[str, float] | _layer1_chamber_lengths (float A_throat, float Lstar, float D_chamber_inner, float theta) |
| float | _layer1_site_ambient_pa (Any config_obj) |
| float | _layer1_bell_length_m (float A_throat, float eps) |
| bool | _layer1_cea_ok (Any cea_cache) |
| float | _layer1_ideal_isp_s (Any cea_cache, float MR, float Pc_pa, float Pa, float eps) |
| float | _layer1_isp_merit_s (Any result, dict constants, Any cea_cache=None) |
| float | _layer1_isp_term (float isp_merit_s, float isp_ref_s) |
| Tuple[float, float] | _layer1_isp_reference (Any cea_cache, float MR, float Pc_pa, float Pa, float eps_lo, float eps_hi) |
| Dict[str, float] | _layer1_merit_weights (dict requirements, Any cea_cache, float optimal_of, float Pc_ref_pa, float Pa, Tuple[float, float] eps_range, float target_thrust, float burn_time_s, float W_MASS_config, float mass_ref_kg) |
| Optional[float] | _layer1_eps_for_exit_pressure_cea (Any cea_cache, float MR, float Pc_pa, float Pa, Optional[float] eps_guess=None) |
| float | _layer1_exit_pressure_sq_term (float P_exit_actual, float target_P_exit, *, float deadband_rel=0.05, float inside_rel_quad_scale=0.0) |
| Dict[str, float] | _layer1_primary_relative_metrics (Dict[str, Any] final_performance, *, float target_thrust, float optimal_of, float target_P_exit) |
| float | _impinging_jet_pair_asymmetry_squared (Any theta_o_deg, Any theta_f_deg, *, float max_delta_deg) |
| float | _relative_hinge_band_squared (Any v, Optional[float] lo, Optional[float] hi) |
| float | _layer1_discharge_cd_inf_ratio_from_config (Any config_obj, str injector_type) |
| float | _expected_geom_ao_af_for_unit_momentum_ratio (float optimal_of, float rho_o, float rho_f) |
| Tuple[float, float] | _rescale_impinging_jet_diameters_for_mr_target (float d_jet_O, float d_jet_F, *, int n_elements_O, int n_elements_F, float optimal_of, float rho_o, float rho_f, float min_d=1e-5, float rel_tol=0.02) |
| None | _write_impinging_jet_diameters_to_config (Any config_obj, float d_jet_O, float d_jet_F) |
| Tuple[float, float] | _layer1_rescale_impinging_seed_jets_for_mr (Any config_obj, *, float d_jet_O, float d_jet_F, int n_doublets, float optimal_of, Sequence[Tuple[float, float]] bounds, logging.Logger logger, Optional[Any] also_config=None) |
| Tuple[float, float, float] | _geom_ao_af_momentum_hint_squared (float A_geom_o, float A_geom_f, float optimal_of, float rho_o, float rho_f) |
| float | _effective_smd_um (Any diagnostics, Any mr_mass=None) |
| Tuple[float, float] | _layer1_resolve_lstar_target (float smd_um, Any constants_or_req, getter, float fallback_target_m) |
| Tuple[float, float, float] | _impinging_smd_penalty_with_angle (Dict[str, Any] diagnostics, *, float target_smd_microns, float smd_rel_tol=0.20, Optional[float] mr_mass=None) |
| float | _tank_pressure_equal_squared (float P_O_tank_psi, float P_F_tank_psi, float scale_psi=100.0, float tol_psi=0.0, float inband_frac=0.0) |
| Tuple[float, float] | _face_halves (*, float r_in, float d_in, float th_in, float r_out, float d_out, float th_out, bool face_contoured, float exit_land) |
| float | _impinging_ring_geometry_squared (*, float n_elements, float spacing_O_m, float spacing_F_m, float d_jet_O_m, float d_jet_F_m, float D_chamber_inner_m, float angle_O_deg=float("nan"), float angle_F_deg=float("nan"), float Ld_min=0.0, float Ld_max=0.0, bool ring_order_fuel_outboard=True, float center_clear_dia_m=0.0, float min_web_m=0.0, float wall_clearance_m=0.0, float spray_radius_frac=0.0, float spray_radius_tol=0.08, bool face_contoured=False, float exit_land=EXIT_LAND_DEFAULT) |
| float | _impinging_geometry_fit_squared (Dict[str, Any] diagnostics, *, float D_chamber_inner_m, float L_chamber_m) |
| float | _impinging_free_jet_ld (*, float n_elements, float spacing_O_m, float spacing_F_m, float d_jet_O_m, float d_jet_F_m, float angle_O_deg, float angle_F_deg) |
| float | _impinging_free_jet_violation (**kw) |
| Tuple[bool, List[str]] | _layer1_stability_gate (str state, float score, float chug, float acoustic, float feed, Any stability_results, dict requirements, float min_stability) |
| Tuple[bool, Tuple[Optional[float], Optional[float]]] | _layer1_momentum_gate (float R, Optional[float] R_min, Optional[float] R_max, float slack=1.0) |
| Dict[str, Tuple[bool, str]] | _layer1_declared_limit_gates (Any config, dict requirements, dict constants, Optional[Dict[str, Any]] performance=None) |
| float | _impinging_face_infeasibility_terms (*, float n_elements, float spacing_O_m, float spacing_F_m, float d_jet_O_m, float d_jet_F_m, float D_chamber_inner_m, float angle_O_deg, float angle_F_deg, float center_clear_dia_m=0.0, float min_web_m=0.0, float wall_clearance_m=0.0, float spray_radius_frac=0.0, float spray_radius_tol=0.08, float min_face_incidence_deg=0.0, bool face_contoured=False, float exit_land=EXIT_LAND_DEFAULT) |
| Optional[Tuple[Dict[str, Any], Dict[str, Any], bool]] | _impinging_channel_pair (*, float n_elements, float spacing_O_m, float spacing_F_m, float d_jet_O_m, float d_jet_F_m, float angle_O_deg, float angle_F_deg, float plate_thickness_m, bool face_contoured, float exit_land, float passage_ld_O, float passage_ld_F, float channel_width_m, str channel_floor) |
| Dict[str, Dict[str, float]] | _impinging_manifold_q (*, float n_elements, float spacing_O_m, float spacing_F_m, float d_jet_O_m, float d_jet_F_m, float angle_O_deg, float angle_F_deg, float plate_thickness_m, bool face_contoured, float exit_land, float passage_ld_O, float passage_ld_F, float channel_width_m, str channel_floor, int channel_inlets, Any mdot_O, Any mdot_F, Any dp_O, Any dp_F, Any rho_O, Any rho_F) |
| float | _impinging_manifold_violation (Dict[str, Dict[str, float]] q) |
| float | _impinging_channel_terms (*, float n_elements, float spacing_O_m, float spacing_F_m, float d_jet_O_m, float d_jet_F_m, float D_chamber_inner_m, float angle_O_deg, float angle_F_deg, float plate_thickness_m, bool face_contoured, float exit_land, float passage_ld_O, float passage_ld_F, float channel_width_m, str channel_floor, float r_plate_m, float r_port_m, float min_land_m=0.0, float back_keepout_dia_m=0.0, float back_keepout_wall_m=0.0) |
| float | _impinging_back_face_terms (*, float n_elements, float spacing_O_m, float spacing_F_m, float d_jet_O_m, float d_jet_F_m, float D_chamber_inner_m, float angle_O_deg, float angle_F_deg, float plate_thickness_m=0.0, float counterbore_dia_m=0.0, float land_ld_O=4.0, float land_ld_F=4.0, float min_back_web_m=0.0, float back_keepout_dia_m=0.0, float back_keepout_wall_m=0.0, bool face_contoured=False, float exit_land=EXIT_LAND_DEFAULT, bool back_channels=False, float passage_ld_O=4.0, float passage_ld_F=4.0, float channel_width_m=0.0, str channel_floor="flat", float r_plate_m=0.0, float r_port_m=0.0, float liner_thickness_m=0.0) |
| bool | _impinging_hard_geometry_blocks_eval (*, float d_jet_O, float d_jet_F, float sp_O, float sp_F, float D_chamber_inner, float D_throat_check, float A_chamber_check, float A_throat_check, float n_elements=float("nan"), float angle_O_deg=float("nan"), float angle_F_deg=float("nan"), float center_clear_dia_m=0.0, float min_web_m=0.0, float wall_clearance_m=0.0, float min_face_incidence_deg=0.0, float spray_radius_frac=0.0, float spray_radius_tol=0.08, float plate_thickness_m=0.0, float counterbore_dia_m=0.0, float land_ld_O=4.0, float land_ld_F=4.0, float min_back_web_m=0.0, float back_keepout_dia_m=0.0, float back_keepout_wall_m=0.0, bool face_contoured=False, float exit_land=EXIT_LAND_DEFAULT, bool back_channels=False, float passage_ld_O=4.0, float passage_ld_F=4.0, float channel_width_m=0.0, str channel_floor="flat", float r_plate_m=0.0, float r_port_m=0.0, float liner_thickness_m=0.0) |
| float | _impinging_infeasibility_layout_terms (*, float d_jet_O, float d_jet_F, float sp_O, float sp_F, int n_el_O, int n_el_F, float D_chamber_inner) |
| float | _impinging_infeasibility_flow_capacity_terms (*, float A_lox_flow, float A_fuel_flow, float A_throat_check, float flow_cap=0.95) |
| None | _merge_runner_eval_into_performance (Dict[str, Any] initial_performance, Dict[str, Any] eval_results) |
| Dict[str, float] | _layer1_final_primary_objective_terms (Dict[str, Any] final_performance, *, float thrust_deadband_rel=0.02, float target_thrust, float optimal_of, float target_P_exit, float layer1_exit_pressure_inside_quad_scale=0.0, float layer1_w_dp, float layer1_w_dp_o, float layer1_w_dp_f, Tuple[float, float] injector_dp_o_band, Tuple[float, float] injector_dp_f_band, Optional[float] injector_dp_o_soft_floor=None, float layer1_w_dp_o_floor=0.0, float layer1_w_dp_center=0.0, float layer1_w_thrust=1.0e4, float layer1_w_of=1.0e4, float layer1_w_of_low_mr_scale=1.0, float layer1_w_of_high_mr_scale=1.0) |
| float | _layer1_apply_chamber_geometry_to_config (PintleEngineConfig config, *, float A_throat, float Lstar, float expansion_ratio, float D_chamber_outer, float max_nozzle_exit, float wall_thickness_m, requirements=None) |
| None | _layer1_stamp_design_point (config, performance, logger=None) |
| None | _layer1_warn_stale_pressure_curves (config, logger=None, float tol_psi=1.0) |
| _layer1_eps_for_exit_pressure (float Pc_Pa, float gamma, float Pe_Pa) | |
| Optional[float] | _layer1_matched_eps (Any result, float Pa, Any cea_cache=None, Optional[float] eps_guess=None) |
| None | _layer1_derive_matched_tank_pressure (np.ndarray x, dict constants) |
| None | _layer1_derive_fuel_spacing (np.ndarray x, dict constants) |
| Optional[Tuple[PintleEngineConfig, np.ndarray, dict]] | _layer1_rebuild_final_config (np.ndarray x_best, PintleEngineConfig config_base, dict constants, logger=None, Optional[dict] diag=None) |
| None | _layer1_finalize_derived_geometry (PintleEngineConfig config, float P_O_pa, float P_F_pa, dict constants, logger=None) |
| Optional[dict] | _layer1_solve_derived_geometry (np.ndarray x, PintleEngineConfig config, dict constants, Callable[[], Optional[dict]] evaluate, Optional[dict] result, Any cea_cache=None) |
| Callable | create_layer1_apply_x_to_config (list bounds, float max_chamber_od, float max_nozzle_exit, str injector_type="pintle", float chamber_od_increment_in=0.0, str chamber_od_snap_target="outer", Optional[dict] derive_constants=None, Tuple[float, float] derive_spacing_F_range=(0.0, float("inf"))) |
| dict | _config_to_dict (PintleEngineConfig config) |
| PintleEngineConfig | _dict_to_config (dict config_dict) |
| float | _quantize_chamber_od_m (float D_outer_m, float increment_in, float wall_m=0.0, str snap_target="outer") |
| list | _l1_shrink_derived_stds (np.ndarray cma_stds, Dict[int, float] derived) |
| Tuple[list, list] | _layer1_cma_discrete_options (int n_dims, Optional[Sequence[int]] integer_dims, int od_index=-1, float od_step_m=0.0, Optional[Sequence[Sequence[float]]] bounds=None) |
| np.ndarray | _snap_integer_dims (np.ndarray x, list integer_indices) |
| int | _get_num_workers (config_obj) |
| _init_worker (dict config_dict, np.ndarray bounds_array, dict requirements_dict, dict constants_dict, bool debug_strict=False) | |
| _apply_x_to_worker_config_inplace (np.ndarray x, PintleEngineConfig config, dict constants) | |
| None | _infeas_trace (Optional[Dict[str, float]] entry, str label, float value) |
| Any | _compute_objective_value (Any result, np.ndarray x, dict requirements, dict constants, Any cea_cache=None, *, Optional[str] eval_error=None, bool return_terms=False) |
| Dict[str, Any] | _layer1_objective_terms (Any result, np.ndarray x, dict requirements, dict constants, *, Any cea_cache=None, Optional[str] eval_error=None) |
| bool | _native_fast_eval_enabled () |
| _eval_candidate (x_raw) | |
| Tuple[np.ndarray, float] | _layer1_cma_warmstart_candidates (np.ndarray x0, *, np.ndarray lower_bounds, np.ndarray upper_bounds, np.ndarray span, List[int] integer_dims, np.random.Generator rng, Any executor, int n_trials, float sigma_frac, Dict[Any, Any] eval_cache, Callable[[np.ndarray], Any] make_cache_key_fn, Dict[str, Any] opt_state, logging.Logger logger) |
| None | _layer1_sync_best_from_worker_eval (Dict[str, Any] opt_state, np.ndarray x_vec, float obj_val, *, Optional[Callable[[np.ndarray], float]] parent_objective=None) |
| None | _layer1_emit_objective_plot_point (Optional[Callable[[int, float, float], None]] objective_callback, Dict[str, Any] opt_state, int iteration, float current_obj, float best_obj) |
| Optional[str] | _layer1_infeasibility_reason (runner, x, dict requirements, dict constants) |
| np.ndarray | run_layer1_global_search (Callable[[np.ndarray], float] objective, list bounds, np.ndarray x0, int max_evals=150, int random_seed=42) |
| None | _layer1_check_of_target_in_cea_range (Any config_obj, Any optimal_of) |
| Tuple[float, Optional[str]] | _layer1_resolve_of_target (Any config_obj, Any optimal_of, Any cea_cache=None, float Pc_pa=3.0e6, float Pa=101325.0) |
| Tuple[PintleEngineConfig, Dict[str, Any]] | run_layer1_optimization (PintleEngineConfig config_obj, PintleEngineRunner runner, Dict[str, Any] requirements, float target_burn_time, Dict[str, float] tolerances, Dict[str, Any] pressure_config, Optional[Callable[[str, float, str], None]] update_progress=None, Optional[Callable[[str, str], None]] log_status=None, Optional[Callable[[int, float, float], None]] objective_callback=None, Optional[Any] stop_event=None, Optional[int] layer1_max_iterations=None, Optional[int] layer1_cma_restarts=None, bool layer1_smoke=False) |
| Tuple[np.ndarray, float, int] | run_cma_core (Callable[[np.ndarray], float] objective_fn, np.ndarray x0, float sigma0, list bounds, int budget, int popsize, np.ndarray cma_stds=None, int seed=None, Optional[ElitePool] elite_pool=None, Optional[Callable[[np.ndarray], float]] true_objective_fn=None, Optional[Dict[str, Any]] valley_escape_tracker=None, logger=None, Optional[ProcessPoolExecutor] executor=None, Optional[list] integer_dims=None, int od_index=-1, float od_step_m=0.0, Optional[Dict[int, float]] fixed_variables=None, Optional[dict] eval_cache=None, Optional[Callable[[np.ndarray], Tuple[int,...]]] make_cache_key_fn=None, Optional[Any] stop_event=None, Optional[np.ndarray] embed_base=None, Optional[List[int]] embed_idx=None, Optional[Callable[[np.ndarray], float]] full_objective_fn=None) |
| Tuple[np.ndarray, float, int] | _layer1_iso_area_count_scan (np.ndarray x, float f, list bounds, Any executor, list integer_dims, Tuple[int, Tuple[int,...], Tuple[int,...]] iso_area, logger=None, Optional[dict] eval_cache=None, Optional[Callable[[np.ndarray], Any]] make_cache_key_fn=None) |
| list[list[int]] | compute_blocks_from_elites (ElitePool elite_pool, int num_blocks, int dim, str method="random", float overlap_fraction=0.0, np.random.Generator rng=None) |
| Tuple[np.ndarray, float, int] | run_hybrid_optimization (Callable[[np.ndarray], float] objective, list bounds, np.ndarray x0, HybridOptimizerConfig hybrid_config, int total_budget=3000, logger=None, log_status_fn=None, update_progress_fn=None, Optional[Dict[str, Any]] valley_escape_tracker=None, Optional[ProcessPoolExecutor] executor=None, Optional[list] integer_dims=None, int od_index=-1, float od_step_m=0.0, Optional[Dict[int, float]] fixed_variables=None, Optional[dict] eval_cache=None, Optional[Callable[[np.ndarray], Tuple[int,...]]] make_cache_key_fn=None, Optional[Any] stop_event=None, Optional[int] seed=None, int popsize=16, Optional[Tuple[int, Tuple[int,...], Tuple[int,...]]] iso_area=None) |
Layer 1: Static Optimization This layer implements the main optimization loop that optimizes ONLY static (time‑independent) quantities: - Engine geometry (throat, L*, expansion ratio, pintle or impinging jet geometry) - Initial tank pressures for LOX and fuel (single value per tank) All **time‑varying** pressure behavior (segments/curves over the burn) is handled **exclusively** in Layer 2 (`layer2_pressure.py`). Layer 1 must NOT create or manipulate pressure segments or time arrays.
|
protected |
Apply x to config IN-PLACE (mutates config, no copy). Assumes x is already bounded and snapped (CMA-ES + parent handle this).
Definition at line 4295 of file layer1_static_optimization.py.
References _layer1_apply_chamber_geometry_to_config(), _layer1_derive_fuel_spacing(), _layer1_derive_matched_tank_pressure(), _quantize_chamber_od_m(), and max.
Referenced by _eval_candidate(), and _layer1_rebuild_final_config().
|
protected |
k in sigma_max = k p a^2 / t^2 for a solid circular plate under uniform pressure p. Roark's Formulas for Stress and Strain (7th ed.), Table 11.2, uniform load over the plate (Timoshenko & Woinowsky-Krieger, Theory of Plates and Shells, 2nd ed., sections 15-16, give the same): * case 10a, edge SIMPLY SUPPORTED: max stress at the centre, k = 3 (3 + nu) / 8 (1.2375 at nu = 0.3); * case 10b, edge FIXED (clamped): max stress at the edge, k = 3 / 4. A plug retained by a rim/shoulder and a snap ring rotates at its edge, so it is closer to simply supported than to clamped -- the clamped figure sizes it ~22 % thin.
Definition at line 1134 of file layer1_static_optimization.py.
Referenced by _layer1_chamber_mass_kg(), and _layer1_injector_plate_constants().
|
protected |
The Layer-1 objective; with ``return_terms`` every weighted term and the values behind it. The ONE scoring function. The worker pool (``_eval_candidate``) and the inline ``objective()`` closure both call it on the SOLVED vector, so CMA, the block stage, L-BFGS-B and the reported breakdown rank the same surface. It used to exist twice and the two drifted by ~300 points on the same design (chamber length, ΔP centre term, L* keys). Structure: infeasibility (BASE_INFEAS + W_INFEAS x residual) dominates; below it the requirement terms (thrust, Pc, O/F with deadbands), the preference bands, and the figure of merit -- delivered Isp (``isp_penalty``) against chamber mass (``chamber_mass_penalty``). Returns the scalar, or with ``return_terms`` a dict: ``objective``, ``terms`` (weighted; sums to ``objective`` on a feasible design) and the context values.
Definition at line 4400 of file layer1_static_optimization.py.
References _effective_smd_um(), _geom_ao_af_momentum_hint_squared(), _impinging_angle_hinge_squared(), _impinging_back_face_terms(), _impinging_face_infeasibility_terms(), _impinging_free_jet_violation(), _impinging_geometry_fit_squared(), _impinging_infeasibility_flow_capacity_terms(), _impinging_infeasibility_layout_terms(), _impinging_jet_pair_asymmetry_squared(), _impinging_manifold_q(), _impinging_manifold_violation(), _impinging_momentum_asymmetric_squared(), _impinging_resultant_tilt_deg(), _impinging_resultant_tilt_preference(), _impinging_resultant_wall_violation(), _impinging_ring_geometry_squared(), _impinging_smd_penalty_with_angle(), _infeas_trace(), _layer1_bell_length_m(), _layer1_chamber_lengths(), _layer1_chamber_mass_kg(), _layer1_chamber_mass_term(), _layer1_contraction_theta(), _layer1_derive_fuel_spacing(), _layer1_derive_matched_tank_pressure(), _layer1_exit_pressure_sq_term(), _layer1_geometry_infeasibility(), _layer1_inf_residual(), _layer1_isp_merit_s(), _layer1_isp_term(), _layer1_lstar_band_term(), _layer1_resolve_lstar_target(), _layer1_thrust_deadband(), _quantize_chamber_od_m(), _relative_hinge_band_squared(), _resolve_tilt_allowance_deg(), _resultant_tilt_breakeven_deg(), _tank_pressure_equal_squared(), max, and min.
Referenced by _layer1_infeasibility_reason(), and _layer1_objective_terms().
|
protected |
Convert config to lightweight dict for pickling. Uses pydantic's dict() method if available, otherwise falls back to __dict__.
Definition at line 4072 of file layer1_static_optimization.py.
|
protected |
Reconstruct config from dict.
Definition at line 4080 of file layer1_static_optimization.py.
Referenced by _init_worker().
|
protected |
Mass-flux-weighted effective spray SMD [um] from injector diagnostics. The blend the SMD penalty has always used, hoisted out so the L*-target correlation can read the SAME number rather than recomputing it from a second correlation (which is what previously let the two disagree about how fine the spray was).
Definition at line 1711 of file layer1_static_optimization.py.
Referenced by _compute_objective_value().
|
protected |
Pure evaluation function for parallel execution.
Reuses worker's PintleEngineRunner by mutating its config in-place.
Assumes x_raw is already snapped (integers) and within bounds (CMA-ES handles this).
Returns lightweight scalar diagnostics only.
Args:
x_raw: Candidate vector (already snapped and bounded)
Returns:
dict with 'value', 'success', and optional diagnostics
Definition at line 5044 of file layer1_static_optimization.py.
References _apply_x_to_worker_config_inplace(), _layer1_inf_residual_from_objective(), _layer1_objective_terms(), _layer1_solve_derived_geometry(), _native_fast_eval_enabled(), and min.
|
protected |
Geometric A_O/A_F consistent with MR ≈ optimal_of when R ≈ 1 (bulk u, fixed ρ).
Definition at line 1590 of file layer1_static_optimization.py.
Referenced by _geom_ao_af_momentum_hint_squared(), _layer1_rescale_impinging_seed_jets_for_mr(), and _rescale_impinging_jet_diameters_for_mr_target().
|
protected |
How far the ring pair reaches in from the inner pitch circle and out from the outer one on the face datum: the elliptical exit traces on a flat face, the groove edges on a contoured one (engine.core.injectors.layout.ring_face_reach -- the drawing's own rule).
Definition at line 1893 of file layer1_static_optimization.py.
Referenced by _impinging_face_infeasibility_terms(), _impinging_hard_geometry_blocks_eval(), and _impinging_ring_geometry_squared().
|
protected |
Returns (relative_error_squared, A_O/A_F, expected_A_O/A_F for R≈1).
Definition at line 1695 of file layer1_static_optimization.py.
References _expected_geom_ao_af_for_unit_momentum_ratio().
Referenced by _compute_objective_value().
|
protected |
Get number of workers from config or default to cpu_count - 1. ``ED_L1_WORKERS`` overrides both (``1`` runs every candidate in-process, which is what a debugger or an infeasibility trace needs).
Definition at line 4233 of file layer1_static_optimization.py.
References max.
|
protected |
Penalty for effective impingement angle outside a preferred degree band. Returns 0.0 when bounds are unset/invalid, or when angle is missing/non-finite.
Definition at line 843 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Back-face (manifold side) misses as a graded infeasibility. Always on, when a plate thickness is known: passages that overlap at the back face, cross the axis, or open into the centre port -- none of those can be built. The declared limits (``min_back_web_m``, the igniter's back keep-out) add to that. Each passage walks ``t tan(theta)`` radially through the plate, the two rings walking APART, so a face that fits can leave entries that crowd each other (inner ring) or leave no room for the wall between the two manifolds. The geometry is ``engine.core.injectors.layout.passage_back_entry`` -- the same call the drawing makes. Relative to the bore and squared, like the face terms, so CMA has a gradient home.
Definition at line 2608 of file layer1_static_optimization.py.
References _impinging_channel_terms(), and max.
Referenced by _compute_objective_value(), _impinging_hard_geometry_blocks_eval(), and _layer1_declared_limit_gates().
|
protected |
(LOX channel, fuel channel, LOX inboard) from ``layout.channel_for_ring`` -- the drawing's own geometry -- or None when the ring pair is degenerate.
Definition at line 2461 of file layer1_static_optimization.py.
Referenced by _impinging_channel_terms(), and _impinging_manifold_q().
|
protected |
Channel-back misses as a graded infeasibility. Active whenever the back is channels. The same geometry the drawing uses (``engine.core.injectors.layout.channel_for_ring``): each passage runs its L/d from the exit to its channel floor. Infeasible when a passage would run out through the back face before its length, when the two channels overlap (or leave less than ``min_land_m`` between them), when the inner channel reaches the centre port or the igniter's thick centre, or when the outer channel runs off the plug.
Definition at line 2559 of file layer1_static_optimization.py.
References _impinging_channel_pair(), and max.
Referenced by _impinging_back_face_terms().
|
protected |
Face real-estate misses as a GRADED infeasibility, for the parallel worker path. These limits need three properties at once and only this shape has all three: * **Hard.** Routed into ``infeasibility_score``, so any violation ranks below every feasible design instead of being priced against Isp. As a plain objective term at W_IMP_GEOM = 1500 a 0.022 spray-radius miss cost 1.5 points against an objective of ~2690 and every seed simply bought it -- the same way a 2.7 %-over ring once bought orifices outside the bore for 1.1 points. * **Graded.** A binary ``+= 1.0`` was tried and is worse than useless: it puts the whole violating region on one flat 1e6 plateau with no gradient, and 2 of 3 seeds then never found the feasible set at all (converged O/F 2.09 and 25.6). Same failure the per-jet angle box produced once; see the note at the angle bounds. * **In both paths.** The serial loop's ``_impinging_hard_geometry_blocks_eval`` never ran in the parallel CMA workers, where essentially every candidate is scored. All terms are relative, one-sided, and exactly zero for a comfortable design, so a config that declares none of these keys contributes nothing -- except the bore itself: an orifice whose elliptical trace crosses the chamber wall is drilled into the liner whether or not a wall land was declared, so that check runs at a clearance of 0 too. The soft term and the serial hard block apply the same rule.
Definition at line 2367 of file layer1_static_optimization.py.
References _face_halves(), and max.
Referenced by _compute_objective_value(), and _layer1_declared_limit_gates().
|
protected |
Longest free jet to the impingement point, in that stream's own orifice diameters. SP-8089 criterion 3.1.1.1.4 measures the impingement distance ALONG each jet: L_k / d_k = L_imp,axial / (d_k cos theta_k). Layer 1's standoff target is axial over the mean diameter, so the same target means a longer free jet at steep angles and for the smaller hole. NaN when the geometry is degenerate.
Definition at line 2135 of file layer1_static_optimization.py.
References max.
Referenced by _impinging_free_jet_violation(), and _layer1_declared_limit_gates().
|
protected |
Squared relative excess of the longest free jet over SP-8089's 7 d (0 inside).
Definition at line 2160 of file layer1_static_optimization.py.
References _impinging_free_jet_ld(), and max.
Referenced by _compute_objective_value().
|
protected |
Squared penalty keeping the impinging element geometry physically self-consistent. Two soft constraints, read from the physics ``diagnostics``: * **Ring fit** — the hole pitch-circle ``D_pitch = n·spacing/π`` must stay inside the chamber bore. * **No overlap** — adjacent orifices must not collide (``element_gap = spacing − d_jet`` ≥ 0). It no longer co-locates the rings (that drove the impingement standoff to zero) nor charges a vaporization-length budget (a second, cruder evaporation model double-counting eta_vap); see the comments below. :func:`_impinging_ring_geometry_squared` carries the ring pair. All terms are relative (scale-free) and one-sided (only violations are penalized), so a comfortably sized element contributes exactly zero.
Definition at line 2077 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
True when doublet layout is physically impossible — skip ``evaluate()``. The face-real-estate checks (centre clearance, web, wall land) are HARD for the same reason ring fit is: as soft terms they get bought for a rounding error against an objective of ~2700. They stay inert unless the corresponding requirement is set, so a config that declares none of them behaves exactly as before.
Definition at line 2692 of file layer1_static_optimization.py.
References _face_halves(), _impinging_back_face_terms(), max, and min.
|
protected |
Effective injector area vs throat — impinging uses Cd×A from diagnostics when available.
Definition at line 2864 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Layout infeasibility for unlike doublets: overlap + pitch-circle vs bore. Uses the same pitch definition as the impinging injector model (``n·spacing/π``), not the legacy pintle-era ``(n_O+n_F)·spacing²/face`` proxy.
Definition at line 2836 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Soft penalty when paired oxidizer/fuel jet inclinations diverge excessively. ``max_delta_deg`` is an allowable |Δθ| band for nominally coherent doublet impingement; excess is normalized by ``max(max_delta_deg, 5 degrees)`` so the term is order one before weights.
Definition at line 1516 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Channels back: each channel's velocity head at its feed port against the injector drop.
``layout.channel_velocity_head`` on the channel ``layout.channel_for_ring`` draws, with
``channel_inlets`` ports each splitting two ways: q = rho/2 (mdot / (2 n rho A))^2. The limit
is ``layout.MANIFOLD_Q_FRAC`` of the drop (Rohde, Richards & Metger, NASA TN D-5467: holes
fed across a channel recover none of its velocity head). {side: velocity-head dict}; a side
is missing when its channel pierces the back (no channel) or its flow is not known -- the
same skips as ``layout._check_manifold``.
Definition at line 2501 of file layer1_static_optimization.py.
References _impinging_channel_pair().
Referenced by _compute_objective_value(), and _layer1_declared_limit_gates().
|
protected |
Graded infeasibility from :func:`_impinging_manifold_q`: the channel AREA shortfall, ``(A_needed / A - 1)^2`` summed over the sides, 0 at or under ``MANIFOLD_Q_FRAC``.
Definition at line 2548 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Mild symmetric cost on the momentum ratio: free in the band, quadratic outside.
``band_lo``/``band_hi`` (the configured impinging_momentum_R_min/max, or their aim band)
set the free band when given; otherwise it is [1/(1+band_width), 1+band_width].
A doublet's resultant is the vector sum of its two streams. With LOX inboard its jet
travels radially outward to the collision and the fuel jet travels inward, so R > 1 means
the LOX side wins and the fan is thrown OUTWARD onto the ablative; R < 1 sends it into
the core, which only costs mixing::
[1 - band_width, 1] free -- slightly fuel-dominant, fan leans safely in
R < 1 - band_width discouraged -- 10x, a mixing loss and negotiable
R > 1 not priced here -- it is a hard constraint; see
_impinging_momentum_wall_violation
``wall_side_multiplier`` is retained only so an existing config can still express "price
the wall side instead of banning it"; at its default the wall side returns 0 from this
function because the infeasibility path owns it.
Definition at line 652 of file layer1_static_optimization.py.
References min.
Referenced by _compute_objective_value().
|
protected |
Normalized squared violation outside a configured momentum band. Returns 0.0 when no valid band is configured or R is missing/non-finite.
Definition at line 809 of file layer1_static_optimization.py.
References max.
|
protected |
Penalty for momentum_ratio_R outside a preferred band. If both ``r_band_lo`` and ``r_band_hi`` are finite and ``r_band_hi > r_band_lo``, uses a **ratio-space** deadband: zero when ``r_band_lo <= R <= r_band_hi``, else squared distance to the nearest band edge. Otherwise (defaults / legacy): **log-space** deadband zero for R in [1/1.1, 1.1], ``max(0, |log R| - log(1.1))**2`` outside. Returns 0.0 if R is missing, non-finite, or <= 0.
Definition at line 723 of file layer1_static_optimization.py.
References max.
|
protected |
Soft penalty pulling ``momentum_ratio_R`` toward 1.0 in log space. Unlike the wide ratio-band hinge (zero throughout [R_min, R_max]), this stays active near R≈1 so CMA/L-BFGS can co-optimize momentum with thrust and O/F without lexicographic blocking. Final validation still uses ``impinging_momentum_R_min/max``.
Definition at line 768 of file layer1_static_optimization.py.
References max.
|
protected |
SUPERSEDED by _impinging_resultant_wall_violation; retained for tests/back-compat. R is a momentum-FLUX ratio: it carries no areas and no angles, so R = 1 is not a balanced doublet (p_O/p_F = R^2 * A_O/A_F). Banning R > 1 to protect the liner selected the most outward-tilted design available and cost 8.2 s of ideal Isp. The live guard is the resultant tilt. Squared normalized excess of the momentum ratio past the WALL side of the band. Zero when safe. This is a CONSTRAINT, not a preference, so it is added to the infeasibility score rather than priced as a quality term. Pricing it instead -- a 999999x multiplier on a W_MOM of 1.2e5 -- put a quality term at 1e7..1e11 against a BASE_INFEAS of 1e6, which inverted the lexicographic order (every wall-side design scored worse than every genuinely infeasible one), flattened the landscape CMA adapts to, and stopped the run dead in about a second. Routed through infeasibility it keeps the intended meaning -- no feasible design ever sits on the wall side -- while staying on the same numeric scale as every other hard constraint, so the infeasibility gradient can still walk a candidate back into the band.
Definition at line 604 of file layer1_static_optimization.py.
|
protected |
Tilt of the doublet's resultant from the chamber axis [deg]; + = toward the WALL.
Which ring is inboard comes from the pitch circles when the spacings are given
(:func:`_lox_ring_inboard`, the rule :func:`_resultant_tilt_breakeven_deg` uses), and
only falls back to ``lox_inboard`` without them. It used to come from the
``layer1_ring_order_fuel_outboard`` REQUEST, so a design whose LOX ring sat outboard had
its tilt reported with the wrong sign against a break-even computed the right way.
This is the quantity the "protect the ablative" rule was always meant to guard. A
doublet's spray fan follows the VECTOR SUM of its two streams. With LOX inboard, the LOX
jet travels radially outward to the collision and the fuel jet inward, so with outward
positive::
p = mdot * v (stream momentum; v = mdot / (rho * n * A_jet))
P_r = p_O*sin(th_O) - p_F*sin(th_F)
P_z = p_O*cos(th_O) + p_F*cos(th_F)
alpha = atan2(P_r, P_z)
The momentum-FLUX ratio ``R = sqrt(rho_O v_O^2 / (rho_F v_F^2))`` that Layer 1 used as
the proxy carries no areas and no angles, and::
p_O/p_F = R^2 * (A_O n_O)/(A_F n_F)
so R = 1 is NOT balance -- balance is p_O = p_F. Measured on this design: at R = 1.0002
the stream ratio is 1.805 and the fan tilts +16.0 deg OUTWARD, reaching the liner 99 mm
down a 190 mm chamber while the spray is still liquid (x* = 167 mm). Banning R > 1 was
therefore selecting the WORST case for the liner, and costing 8.2 s of ideal Isp by
forcing O/F to 2.19 (CEA peak is at 1.65).
Angles are the lever: sin(th_O)/sin(th_F) = p_F/p_O gives alpha = 0 exactly.
Definition at line 407 of file layer1_static_optimization.py.
References _lox_ring_inboard(), and max.
Referenced by _compute_objective_value().
|
protected |
Preference for a spray fan aimed straight down the chamber: ``(tilt/scale)^2``. ``tilt_deg`` is the resultant tilt, positive OUTWARD (toward the liner). Inward lean costs the plain quadratic, outward lean ``outward_multiplier`` times it. This is a preference priced in the objective; the wall guard (:func:`_impinging_resultant_wall_violation`) stays the hard limit.
Definition at line 553 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Squared normalized excess of the resultant tilt past ``max_outward_deg``. A CONSTRAINT, not a preference: a fan aimed at the liner is a burn-through, so this goes to the infeasibility score (same treatment the R proxy had) rather than being priced against Isp. Tilting INWARD costs nothing here -- it is a mixing loss, handled by the ordinary quality terms.
Definition at line 576 of file layer1_static_optimization.py.
Referenced by _compute_objective_value().
|
protected |
Doublet ring geometry, computed straight from the DESIGN VARIABLES.
HOW AN UNLIKE DOUBLET ACTUALLY WORKS. The oxidizer and fuel orifices sit on two DIFFERENT
pitch circles and are canted toward each other; the jets close the radial gap between the
rings and collide partway between them:
radial offset dr = |D_pitch_O - D_pitch_F| / 2
impingement dist L_imp = dr / (tan(theta_O) + tan(theta_F))
So the rings MUST be separated -- that separation is the whole mechanism. An earlier version
of this function penalised |D_pitch_O - D_pitch_F| toward zero, i.e. drove both streams onto
the SAME circle, which gives dr = 0 and L_imp = 0: the jets "impinge" at the face plate.
That is a face-eroding non-injector, and it was wrong.
The real constraint is on the impingement DISTANCE, not on the ring separation itself.
Published practice for unlike impinging elements puts L_imp at roughly 3-7 orifice diameters
(5-7 as SP-8089 is usually quoted), with ~60 deg included angle. The band itself comes
from ``engine.core.injectors.layout.impingement_ld_band``; the defaults here (0, 0) leave
the standoff term off for a caller that passes no band. Too short and the jets collide on
the face; too long and the free jets wander before they meet, so the pair stops mixing.
This exists because ``_impinging_geometry_fit_squared`` reads its inputs out of the physics
``diagnostics`` dict, and the numba accelerator -- which is what the Layer-1 inner loop runs
on -- emits none of the keys it needs (``D_pitch_O``, ``element_gap_O``,
``vaporization_length_total``, ``L_imp``, ``s_pair``: zero occurrences in engine/accel/).
They come back None, every lookup fails, and the whole W_IMP_GEOM constraint has been
returning 0.0 for every candidate since the C->numba port. The A/B parity suite compares
physics outputs (thrust, Pc, MR), not diagnostic keys, so it passed while a constraint was
silently switched off.
Consequences seen live: a seed whose fuel ring was 119.4 mm across a 114.8 mm bore (orifices
outside the chamber wall), and converged designs with the oxidizer and fuel rings 20-51 mm
apart radially -- i.e. "doublets" whose two jets are on different circles and cannot meet.
Pitch circle, orifice pitch and overlap are pure geometry -- n, spacing and d_jet are design
variables -- so deriving them here makes the constraint independent of which physics path ran.
Terms (all relative, one-sided, zero when comfortable):
* ring fit -- each D_pitch = n*spacing/pi must stay inside the bore
* no overlap -- adjacent orifices must not collide (spacing >= d_jet + min web)
* standoff -- L_imp/d_avg inside [Ld_min, Ld_max]
* ring order -- fuel outboard, so wall spillover is fuel-rich
* centre clear -- keep a circle free at the axis (igniter boss / centre port)
* wall clearance -- keep a land between the outer ring and the bore
* spray radius -- put the impingement circle where the propellant is wanted
WHERE THE RING PAIR SITS was an exactly flat direction until the last three terms existed.
``_layer1_derive_fuel_spacing`` solves s_F so the standoff hits its target, and it does that
by fixing the GAP ``|s_F - s_O|``; dr is therefore independent of s_O, the pair slides
radially at zero cost, and s_O fell onto its own lower bound (0.003 m). The result on
ethalox_8kN_FINAL: D_pitch_O = 26.90 mm, all 28 doublets impinging on a 41.79 mm circle
inside a 127.00 mm bore -- 10.8 % of the chamber area, narrower than the 49.57 mm throat,
a 1.44 mm LOX web, and no room at the axis for the 3/8 NPT igniter.
WHERE THE PROPELLANT LANDS. Every doublet on one ring collides on the SAME circle,
``r_imp = r_inner + L_imp*tan(theta_inner)``, and nothing used to constrain it. Bounding the
pair only from BELOW (the centre-clear term) is not enough -- the direction is still flat
above that bound, and the search parks on it: measured r_imp/r_wall = 0.33 before any of
these terms, then 0.44 once only the lower bound existed. The target is the EQUAL-AREA
radius, ``r_wall/sqrt(2)``, which splits the chamber cross-section in half.
RADIAL EXTENT IS ELLIPTICAL. A hole of diameter d inclined ``theta`` from the chamber axis
cuts the (axis-normal) face as an ellipse: minor axis d circumferentially, MAJOR axis
``d/cos(theta)`` radially. At theta = 69 deg that is 2.79x the drill diameter, so the
centre- and wall-clearance terms use the ellipse while the web term -- a circumferential
distance -- correctly uses d.
Definition at line 1904 of file layer1_static_optimization.py.
References _face_halves(), max, and min.
Referenced by _compute_objective_value().
|
protected |
Return (range_penalty, effective_smd_um, impingement_angle_deg). Single source of truth: the effective spray SMD is the mass-flux-weighted blend of the injector-physics Sauter means ``D32_O`` / ``D32_F`` (metres) reported by the impinging solve. Those values come from the Ingebo correlation, which already embeds the aerodynamic Weber number (gas-shear breakup), the liquid Reynolds number (viscous resistance — important for cryogens), and the impingement angle (through the law-of-cosines collision velocity ``u_rel``). We do NOT recompute SMD from a separate parametric correlation here — that previously gave the optimizer a different answer than the reported physics. Penalty is a **two-sided** deadband: zero inside ``[target·(1−tol), target·(1+tol)]`` and the squared, target-normalized distance to the nearest edge outside it (so both too-coarse and too-fine atomization are penalized — "SMD within a range").
Definition at line 1789 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Definition at line 4395 of file layer1_static_optimization.py.
Referenced by _compute_objective_value().
|
protected |
Initialize worker process with lightweight data.
Builds PintleEngineRunner ONCE per worker for major speedup.
Runner is reused by mutating its config in-place (runner.evaluate is stateless).
Args:
config_dict: Serialized config (primitives only)
bounds_array: Bounds array [n_dims x 2]
requirements_dict: Requirements dict
constants_dict: Constants needed for geometry calculations
debug_strict: If True, re-raise exceptions; if False, return penalties
Definition at line 4253 of file layer1_static_optimization.py.
References _dict_to_config().
|
protected |
CMA_stds with derived dimensions damped to effectively zero. Derived DOFs keep their FULL bounds -- collapsing them to a point made every one of the ~50 ``np.clip(x, bounds...)`` sites in this module silently revert the solved value to the seed. Full bounds make each clip a no-op; this keeps CMA from wasting variance on a coordinate whose value is overwritten at evaluation anyway.
Definition at line 4129 of file layer1_static_optimization.py.
References max.
|
protected |
Update chamber / nozzle fields from the first four Layer-1 DOFs.
Returns:
Final expansion ratio after optional exit clipping [–]
Definition at line 2988 of file layer1_static_optimization.py.
References _layer1_chamber_lengths(), _layer1_contraction_theta(), and max.
Referenced by _apply_x_to_worker_config_inplace(), _layer1_finalize_derived_geometry(), _layer1_rebuild_final_config(), _layer1_solve_derived_geometry(), and create_layer1_apply_x_to_config().
|
protected |
Rao 80 % bell length from the throat [m]: 0.8 (sqrt(eps) - 1) R_t / tan 15 deg. Huzel & Huang ch. 4; the same L_noz nozzle_solver.rao draws.
Definition at line 1243 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value(), and _layer1_declared_limit_gates().
|
protected |
Definition at line 1255 of file layer1_static_optimization.py.
Referenced by _layer1_eps_for_exit_pressure_cea(), _layer1_ideal_isp_s(), _layer1_isp_reference(), and _layer1_resolve_of_target().
|
protected |
Centre keep-out diameter: the explicit reservation if set, else the igniter's, else 0.
Definition at line 262 of file layer1_static_optimization.py.
References _layer1_igniter_keepouts(), and _requirement_float().
|
protected |
Axial lengths of the chamber Layer 1 builds [m].
One source for the objective, the config writer and validation, so all three score the
chamber that is drawn. The cone runs to the tangency of the 1.5 R_t entrance arc,
r_tan = R_t (1 + 1.5 (1 - cos theta)); the arc then covers 1.5 R_t sin(theta) to the
throat plane (nozzle_solver.rao)::
length = L_cyl + L_cone (cg.length: mass proxy, L/D band)
face_to_throat = length + 1.5 R_t sin(theta) (injector face to throat plane)
Definition at line 1186 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value(), _layer1_apply_chamber_geometry_to_config(), and _layer1_declared_limit_gates().
|
protected |
Cylindrical-shell dry-mass proxy for the chamber barrel [kg]. Why this exists: chamber volume carried no cost. More residence time only helps delivered c*, so with nothing opposing it L* either pinned to its maximum or, once the objective hit zero, wandered with the seed. This is the counterweight to the Isp term. Deliberately a barrel-only shell, not a full stack mass: it is a monotone proxy whose whole job is to make L* trade against something. ``wall_density_kg_m3`` is an EFFECTIVE density for the liner stack (metal + ablative + graphite), configured rather than derived.
Definition at line 1082 of file layer1_static_optimization.py.
References _closure_plate_stress_coeff().
Referenced by _compute_objective_value().
|
protected |
Normalised, dimensionless mass cost: (m / m_ref)^2. 0 when mass is unavailable.
Definition at line 1157 of file layer1_static_optimization.py.
Referenced by _compute_objective_value().
|
protected |
Smallest chamber OD worth searching [m]: wall + (D/Dt)_min x Dt at the smallest throat. Any bore below that sits under the chamber-shape band for every reachable throat.
Definition at line 1175 of file layer1_static_optimization.py.
References max.
|
protected |
Refuse a target O/F the propellant's CEA table cannot evaluate. A propellant switch keeps the previous design target, so an ethalox target of 1.4 left behind on a methalox config used to run a full optimization against a table that stops at 2.4 -- the mixture ratio pinned at the table edge and the run returned a huge objective with nothing to say why. Fail before any work is done, with the fix in the message.
Definition at line 5525 of file layer1_static_optimization.py.
|
protected |
CMA options that make discrete DOFs behave like discrete DOFs.
Snapping a variable at dispatch (``_snap_integer_dims``) guarantees the design that
gets EVALUATED is manufacturable, but it leaves CMA-ES searching a continuous
coordinate over a staircase objective: many distinct proposals collapse onto the same
evaluated value, so most of the variation CMA generates in that coordinate returns a
bit-identical objective and teaches its covariance adaptation nothing. Worse, as sigma
decays during convergence it can fall below half a cell, at which point essentially
every proposal rounds to the same value and the coordinate freezes on whatever cell it
happened to occupy -- measured on a real run: 1116 distinct proposals for the chamber
diameter produced 8 distinct evaluated sizes, and four seeds of one problem landed on
5.5/6.5/5.5/6.5 in while every other output matched to 4 significant figures.
Two fixes, both from ``cma`` itself:
* ``integer_variables`` -- integer centering plus a minimum std, for coordinates whose
granularity really is 1 (element counts, whole-degree jet angles).
* ``minstd`` -- a hard floor on the per-coordinate std, in the coordinate's OWN units.
This is how the chamber diameter is handled: its granularity is one stock increment
in metres, not 1, so it must NOT be declared an integer variable (that would centre
it on integer *metres*) -- it just needs a std floor of a fraction of one increment.
Returns:
``(integer_variables, minstd)`` ready to drop into the CMA options dict.
Definition at line 4145 of file layer1_static_optimization.py.
Referenced by run_cma_core().
|
protected |
Local cloud around ``x0`` using the **same** ``_eval_candidate`` path as CMA-ES. Picks the clipped/snapped vector with lowest scalar objective. This only replaces the CMA initial mean when ``n_trials > 0``; it does not alter ``_compute_objective_value``, validation gates, or final ``evaluate()`` physics.
Definition at line 5226 of file layer1_static_optimization.py.
References _snap_integer_dims(), _store_last_good_eval_bundle_from_worker_res(), max, and min.
|
protected |
Convergent half-angle [rad], from config. Was hardcoded np.pi/4 in three places (here, the worker objective, and chamber_geometry.theta_default). 45 deg is the LENGTH-optimal angle but not the MASS-optimal one: a shallower cone is longer yet moves volume out of the full-diameter barrel -- which carries the whole ablative + structural wall stack -- into the tapering cone shell. Measured on the 8 kN ethalox point, 30 deg is the lighter chamber at equal L*. Leaving this pinned hid that trade entirely.
Definition at line 982 of file layer1_static_optimization.py.
References _req_lookup().
Referenced by _compute_objective_value(), _layer1_apply_chamber_geometry_to_config(), and _layer1_declared_limit_gates().
|
protected |
Every declared geometric limit, checked on the emitted design at face value.
{gate: (passed, reason)}. Only limits the configuration declares are checked (plus the
SP-8089 free-jet length and the bore, which always apply to a doublet). ``performance``
(the emitted design's solve: ``mdot_O/F`` and ``diagnostics.delta_p_injector_O/F``) adds
the manifold velocity-head gate when the plate declares channels.
Definition at line 2213 of file layer1_static_optimization.py.
References _impinging_back_face_terms(), _impinging_face_infeasibility_terms(), _impinging_free_jet_ld(), _impinging_manifold_q(), _layer1_bell_length_m(), _layer1_chamber_lengths(), _layer1_contraction_theta(), _layer1_injector_plate_constants(), and _req_lookup().
|
protected |
Solve the fuel-ring hole pitch so the jets meet at exactly the requested standoff.
The user states ONE number -- how many jet diameters off the face the doublet should
collide (``layer1_impingement_Ld_target``) -- and that closes the geometry algebraically.
There is nothing to search and nothing to negotiate::
L_imp = dr / (tan(theta_O) + tan(theta_F)) want L_imp = k * d_avg
dr = n * |s_F - s_O| / (2*pi) (dr = half the pitch-circle gap)
=> |s_F - s_O| = 2*pi * k * d_avg * (tan(theta_O) + tan(theta_F)) / n
One equation, one unknown. ``s_O`` (the LOX / inner ring) stays the free variable because
it is the packing-constrained one -- the inner ring has the least circumference and LOX
carries the higher volumetric flow -- and ``s_F`` follows from it. That removes a whole
CMA dimension AND makes L/d exact by construction instead of a penalty the search haggles
with.
Mutates ``x[10]`` in place so every downstream reader sees the solved value.
If the solved fuel ring will not fit the bore the value clamps to its bound; L/d then
misses and the ordinary ring-geometry penalty reports it, rather than the derivation
quietly producing an unbuildable ring.
Definition at line 3298 of file layer1_static_optimization.py.
References max.
Referenced by _apply_x_to_worker_config_inplace(), _compute_objective_value(), _layer1_solve_derived_geometry(), and create_layer1_apply_x_to_config().
|
protected |
Slave the fuel tank pressure to the LOX tank pressure when they must match. "Match propellant tank pressures" is a statement that the two are ONE quantity, not two that ought to end up nearby. Searching them separately and then penalising the gap makes the optimizer pay, forever, for a degree of freedom it was told not to use: at W_TANK_EQUAL = 300 it simply accepted a 13 psi gap because closing it cost more Isp than the penalty; at 30000 it got to 10 psi and carried a large residual for the remainder. Collapsing them removes the gap by construction -- the penalty goes to zero, the residual stops reporting a violation that is not a design flaw, and CMA gets one dimension back. Applies to both injector families (the pressure indices come from ``constants``). Mutates ``x`` in place so every downstream reader sees the same pair.
Definition at line 3266 of file layer1_static_optimization.py.
Referenced by _apply_x_to_worker_config_inplace(), _compute_objective_value(), and create_layer1_apply_x_to_config().
|
protected |
Cd_inf,O / Cd_inf,F at seed jet/orifice diameters (≈1 for matched impinging holes).
Definition at line 1572 of file layer1_static_optimization.py.
|
protected |
SSE / UI objective curve (parallel CMA does not call ``objective()``). ``iteration`` arrives from two different counters -- the parent candidate index in ``_eval_candidate`` and ``function_evaluations`` in the parallel CMA generation loop -- and both are reset between phases. Plotted raw, the x-axis folded back on itself (observed: 1, 17, 65, 113, 161, 209, then 2, 3, 4 ...), which made the curve unreadable. Clamp to a non-decreasing sequence here, at the single point every emission passes through, rather than trying to keep every call site's counter in sync.
Definition at line 5332 of file layer1_static_optimization.py.
|
protected |
Expansion ratio that puts the exit plane exactly at ``Pe_Pa``. Standard isentropic area-ratio relation -- solve the exit Mach number from the pressure ratio, then evaluate A/A*. Returns ``None`` when the inputs cannot describe a supersonic nozzle.
Definition at line 3219 of file layer1_static_optimization.py.
Referenced by _layer1_matched_eps().
|
protected |
Expansion ratio at which the CEA table's own exit pressure equals ``Pa``. For an isentropic (shifting) expansion dCf_vac/deps = Pe/Pc, so the secant slope of the table's Cf_vac between eps nodes is Pe/Pc at the interval midpoint. Interpolating ln(Pe/Pc) in ln(eps) between midpoints and solving Pe = Pa inverts the table the thrust model integrates -- not an isentrope at the chamber gamma. None when the table cannot say (2-D table, or Pa outside its eps range).
Definition at line 1386 of file layer1_static_optimization.py.
References _layer1_cea_ok(), max, and min.
Referenced by _layer1_isp_reference(), _layer1_matched_eps(), and _layer1_resolve_of_target().
|
protected |
Exit nozzle vs ambient-equivalent ``target``: asymmetric hinge beyond deadband, optional quad inside. Outside ``deadband_rel`` uses the asymmetric hinge used elsewhere; inside the deadband optionally adds ``inside_rel_quad_scale * rel**2`` to gently center on target (preference, not a hard gate).
Definition at line 1439 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value(), and _layer1_final_primary_objective_terms().
|
protected |
Definition at line 307 of file layer1_static_optimization.py.
References _layer1_inf_residual().
|
protected |
True when ``obj`` is on the feasible (weighted-sum) branch, not the 1e6 infeasibility floor.
Definition at line 325 of file layer1_static_optimization.py.
Referenced by _layer1_sync_best_from_worker_eval(), and _layer1_valley_escape_tier().
|
protected |
Recompute primary scalar penalty contributions (matches inner objective, excluding Cf/length/momentum).
Definition at line 2899 of file layer1_static_optimization.py.
References _layer1_exit_pressure_sq_term(), and max.
|
protected |
Re-solve the derived DOFs against the tank pressures the final config actually carries.
Finalisation assembles the emitted design from more than one source: the geometry comes
from ``best_config``/``last_eval_config`` while the tank pressures are taken from a
separate ``x`` (see the fallback chain below it). Those need not come from the same
candidate, and when they do not, the throat is solved for one pair of tank pressures and
then shipped with another -- the reported engine overshot thrust by 4-6% and, in the worst
case, did not solve at all ("Supply < Demand at all Pc") when re-evaluated as written.
Solving once more here closes the loop: whatever pressures ended up on the config, the
throat and expansion ratio are the ones that hit the target for THOSE pressures.
Definition at line 3602 of file layer1_static_optimization.py.
References _layer1_apply_chamber_geometry_to_config(), _layer1_solve_derived_geometry(), _quantize_chamber_od_m(), and max.
|
protected |
Hard geometric constraints, as INFEASIBILITY -- never as weighted penalties. A weight on a shape preference only moves the fixed point of the scalarised sum; it cannot express "this design cannot be built". These two genuinely cannot: * ``layer1_min_Lcyl_over_D`` -- the CONSTANT-AREA length is where impinging sprays actually mix. Only total L_chamber/D was gated, which lets the convergent cone masquerade as mixing length. Paired with spray.evaporation.x_star_limit, which spray.py already raises on. * ``layer1_max_element_pitch_m`` -- element spacing on the injector face. eta_mixing (Rupe) sees only momentum ratio, so nothing charged for spreading a fixed element count over a bigger face. Without this the optimiser buys chamber diameter free. Both return 0.0 when unset, so behaviour is unchanged unless configured.
Definition at line 1004 of file layer1_static_optimization.py.
References _req_lookup(), and max.
Referenced by _compute_objective_value().
|
protected |
Ideal ambient Isp from the CEA table [s]: c* (Cf_vac - eps Pa/Pc) / g0. Shifting equilibrium, the same table the thrust model integrates. NaN when unavailable.
Definition at line 1263 of file layer1_static_optimization.py.
References _layer1_cea_ok().
Referenced by _layer1_isp_merit_s(), _layer1_isp_reference(), and _layer1_resolve_of_target().
|
protected |
The declared igniter port's keep-outs (engine.core.injectors.layout), or None.
Definition at line 201 of file layer1_static_optimization.py.
References _requirement_float().
Referenced by _layer1_centre_clear_m().
|
protected |
Definition at line 302 of file layer1_static_optimization.py.
References _layer1_infeasibility_gate_eps(), and max.
Referenced by _compute_objective_value(), and _layer1_feasible_for_primary_objective().
|
protected |
Infer feasibility residual from scalar objective (parallel worker path).
Definition at line 318 of file layer1_static_optimization.py.
References max.
Referenced by _eval_candidate().
|
protected |
Definition at line 291 of file layer1_static_optimization.py.
References _requirement_float(), and max.
Referenced by _layer1_inf_residual().
|
protected |
One sentence on WHICH hard constraint held the best candidate out of the feasible set. A run whose every candidate sat on the 1e6 infeasibility floor used to end with "objective inf" and "Validation failed", which told the user nothing. Re-evaluate the best design in-process with the infeasibility trace on and name the dominant gate.
Definition at line 5361 of file layer1_static_optimization.py.
References _compute_objective_value().
|
protected |
The injector-plate entries of Layer 1's constants dict, from the config and requirements. Nothing declared under ``injector.plate`` => flat face, plenum back: exactly the constraints this optimizer had before. ``layer1_injector_plate_support`` reads ``injector.plate.support`` when the schema carries it; a rim-retained plug defaults to simply supported.
Definition at line 220 of file layer1_static_optimization.py.
References _closure_plate_stress_coeff(), _layer1_plate(), and _requirement_float().
Referenced by _layer1_declared_limit_gates().
|
protected |
Exhaustive search over the element count along the iso-area path. ``iso_area = (i_n, (i_d, ...), (i_s, ...))``: moving the count n -> n' at fixed jet diameters changes the injector flow area by n'/n, so every neighbouring count is a different injector (dP, O/F, Pc all move) and CMA, stepping one integer at a time, rarely crosses between them -- four seeds ended at n = 5, 5, 7 and 13 with objectives 20 % apart. Scaling d by sqrt(n/n') and the hole pitch by n/n' keeps the flow areas and both pitch circles, so each count is scored as the same injector re-divided. Every reachable count is evaluated through the pool (one parallel batch per round); the best improvement is taken and the scan repeats from it.
Definition at line 10471 of file layer1_static_optimization.py.
References _snap_integer_dims(), and _x_solved_or().
Referenced by run_hybrid_optimization().
|
protected |
Delivered Isp with the requirement-pinned operating point held at its requirement [s].
O/F, and Pc when a target is set, are specifications with their own deadbands; the figure
of merit must not buy Isp by moving them. Ideal Isp is re-evaluated with O/F clamped to its
deadband and Pc to its aim band, and the delivered efficiency is kept::
Isp_merit = Isp * Isp_ideal(Pc', O/F') / Isp_ideal(Pc, O/F)
Inside both bands this is the delivered Isp exactly. Without a CEA table it is the
delivered Isp.
Definition at line 1282 of file layer1_static_optimization.py.
References _layer1_ideal_isp_s(), and max.
Referenced by _compute_objective_value().
|
protected |
(Isp_ref [s], eps_ref): ideal ambient Isp at the requirement point, expanded to Pe = Pa. The normaliser of the performance term -- an ideal engine at the target O/F and reference Pc, with the expansion ratio where the table's own exit pressure is ambient (the maximum of Cf_vac - eps Pa/Pc), clamped to the searchable eps range.
Definition at line 1341 of file layer1_static_optimization.py.
References _layer1_cea_ok(), _layer1_eps_for_exit_pressure_cea(), and _layer1_ideal_isp_s().
Referenced by _layer1_merit_weights().
|
protected |
Propellant this engine needs beyond an ideal one, as a fraction: Isp_ref/Isp - 1. At fixed total impulse I = F t_b the propellant is I/(g0 Isp) (Sutton & Biblarz ch. 2), so this equals (m_prop - m_prop_ideal)/m_prop_ideal: linear in the propellant the delivered Isp costs, the same currency as the chamber-mass term. 0 when either Isp is unavailable.
Definition at line 1325 of file layer1_static_optimization.py.
Referenced by _compute_objective_value().
|
protected |
Two-sided cost on L* outside ``target +/- deadband/2``, saturating. Replaces the one-sided "don't grow past target" shape now that the target is a PHYSICAL quantity rather than a preference. Under-shooting is now just as wrong as over-shooting: below the band the droplets do not finish evaporating (c* falls), above it you are carrying chamber you do not need. Free anywhere inside the band -- a 0.1 m window is finer than the correlation's own accuracy, so there is nothing to gain by resolving inside it. Still saturating (e²/(1+e²), bounded in [0,1)) so an unreachable target can never outvote a hard gate -- the failure mode that made the original quadratic 91% of the objective.
Definition at line 936 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
L* the chamber needs in order to vaporise a spray of this fineness [m].
L* and SMD are not independent knobs -- L* exists to buy residence time, and how much
residence time you need is set by how long the droplets take to evaporate:
tau_res = L* * c* / (R * Tc) (chamber volume / volumetric gas flow)
tau_vap = D32^2 / k_evap (d^2-law)
Holding the required margin ``tau_res / tau_vap`` fixed and solving for L* gives
L*_required ∝ D32^2
so the target scales as the SQUARE of SMD. That exponent is the d^2-law, not a fit; only
the anchor point is empirical, and it is stated as a pair the user can move:
``smd_ref_um`` -> ``Lstar_ref_m``.
Anchored at 99 um -> 1.10 m, the implied targets are::
50 um -> 0.28 m 70 um -> 0.55 m 99 um -> 1.10 m
120 um -> 1.62 m 150 um -> 2.53 m
Clamping to [``Lstar_min_m``, ``Lstar_max_m``] is meaningful information, not a fudge: a
target pinned at the ceiling means the spray is too coarse to vaporise inside the chamber
envelope the requirements allow, and the honest fix is a finer spray, not a longer engine.
Definition at line 890 of file layer1_static_optimization.py.
Referenced by _layer1_resolve_lstar_target().
|
protected |
One-sided SATURATING cost on L* above ``target_m``: e²/(1+e²), e=(L*-target)/target. Bounded in [0, 1) on purpose. The first version of this was a bare quadratic, and it reproduced exactly the pathology it was written to avoid: against a target L* cannot physically reach (~1.24 m at this design point), ((L*-0.6)/0.6)² × 4000 came to 4899 of a 5363 objective -- 91% -- so the optimizer sold the momentum-ratio gate (R fell to 0.90, validation FAILED) chasing an L* it was never going to reach. Same shape as the W_SMD=2000 trap against an unreachable 50 µm target. Saturating means the WORST an L* miss can ever cost is W_LSTAR, so it can express a preference without outvoting a hard gate no matter how the target is set. A chamber DRY-MASS penalty does not do this job. Wall mass ~ pi*D*L*t but chamber volume ~ pi*D^2*L/4, so mass/volume ~ 4t/D -- a FATTER chamber is more mass-efficient per unit volume. Charging for mass therefore buys a short wide chamber at the SAME L*, which is what was measured (D 0.131 -> 0.144 m, L_eng 0.327 -> 0.290 m, L* unchanged at 1.4986). L* is the variable that actually has no opposing force anywhere in the objective: more residence time is pure reward (vaporisation -> c* -> thrust). One-sided so that anything at or below target is free -- this expresses "don't grow the chamber past what you need", not "prefer a small chamber".
Definition at line 1052 of file layer1_static_optimization.py.
References max.
|
protected |
Expansion ratio that expands to ``Pa`` at this result's Pc and O/F. The CEA table's own exit pressure (shifting equilibrium, what the thrust model integrates) when a 3-D table is at hand; the chamber-gamma isentrope otherwise, which over-expands (Pe/Pa 0.93 at the 6.5 kN point).
Definition at line 3249 of file layer1_static_optimization.py.
References _layer1_eps_for_exit_pressure(), and _layer1_eps_for_exit_pressure_cea().
Referenced by _layer1_rebuild_final_config(), and _layer1_solve_derived_geometry().
|
protected |
Weights of the figure of merit: {W_ISP, W_MASS, Isp_ref_s, eps_ref, m_prop_ref_kg}.
``layer1_W_ISP`` defaults to 1000, so the isp penalty reads in tenths of a percent of an
ideal engine's propellant. An unset ``layer1_W_MASS`` prices chamber mass at the same rate
per kg as that propellant, (W_ISP / m_prop_ref) = 2 W_MASS / m_ref at the reference mass --
the fixed-total-impulse exchange. No CEA table: both terms keep their configured values
and the Isp term is off.
Definition at line 1358 of file layer1_static_optimization.py.
References _layer1_isp_reference(), and _requirement_float().
|
protected |
Momentum-ratio sign-off on the configured band (``slack`` > 1 widens it about 1).
Definition at line 2203 of file layer1_static_optimization.py.
References max.
|
protected |
:func:`_compute_objective_value` with its terms and context.
Definition at line 5021 of file layer1_static_optimization.py.
References _compute_objective_value().
Referenced by _eval_candidate().
|
protected |
The injector.plate block as a dict ({} when undeclared): how the plug is machined.
Definition at line 212 of file layer1_static_optimization.py.
Referenced by _layer1_injector_plate_constants().
|
protected |
Dimensionless thrust / O-F / exit-pressure mismatches (not weighted optimizer penalties). The Layer 1 scalar objective multiplies these kinds of errors by ``W_THRUST``, ``W_OF``, ``W_EXIT`` (order 1e2–1e4); the weighted sum will never approach machine epsilon. Use these metrics (especially ``rms_primary``) to judge whether the **physics** matches are tight.
Definition at line 1466 of file layer1_static_optimization.py.
|
protected |
Rebuild the emitted design from the winning vector through the WORKER pipeline.
Finalisation used to stitch the design together from several sources -- geometry from
``best_config`` / ``last_eval_config``, tank pressures from whichever of
``best_config_x`` / ``last_eval_config_x`` / ``best_x`` was populated. Those need not
describe the same candidate, and with the tank lock on they did not: the throat was
solved for one pair of pressures and shipped with another, so the reported engine
overshot thrust by 4-6% and, re-evaluated as written, did not solve at all
("Supply < Demand at all Pc").
This does exactly what ``_eval_candidate`` does, once, on the winner: apply x (which
locks the tanks and solves the fuel ring pitch), evaluate, solve the throat and expansion
ratio against THOSE pressures to convergence, and hand back a config whose every field
came from one vector. Returns None if the winner cannot be evaluated, in which case the
caller falls back to the old snapshot path.
Definition at line 3357 of file layer1_static_optimization.py.
References _apply_x_to_worker_config_inplace(), _layer1_apply_chamber_geometry_to_config(), _layer1_matched_eps(), _layer1_solve_derived_geometry(), _quantize_chamber_od_m(), max, and min.
|
protected |
Align impinging x0 jet diameters with ``optimal_of_ratio`` and clip to Layer-1 bounds.
Definition at line 1647 of file layer1_static_optimization.py.
References _expected_geom_ao_af_for_unit_momentum_ratio(), _rescale_impinging_jet_diameters_for_mr_target(), and _write_impinging_jet_diameters_to_config().
|
protected |
(target_m, deadband_m) for the L* penalty. When ``layer1_Lstar_from_smd`` is on (default) the target is the physical one from :func:`_layer1_lstar_target_from_smd`; a fixed ``layer1_Lstar_target_m`` is the opt-out. Falls back to the fixed target whenever SMD is unavailable, so a diagnostics gap cannot silently switch the penalty off.
Definition at line 1744 of file layer1_static_optimization.py.
References _layer1_lstar_target_from_smd().
Referenced by _compute_objective_value().
|
protected |
The O/F Layer 1 designs to, and a warning when it is not the one requested. A target outside the propellant's CEA table (a blank template keeps the previous propellant's O/F) cannot be evaluated. Rather than abort, design to the O/F of peak ideal ambient Isp at ``Pc_pa`` inside the table -- the conventional starting point (Sutton & Biblarz ch. 5) -- or, without a table, the nearest table edge, and say so.
Definition at line 5548 of file layer1_static_optimization.py.
References _layer1_cea_ok(), _layer1_eps_for_exit_pressure_cea(), and _layer1_ideal_isp_s().
|
protected |
The site's ambient pressure [Pa]: the engine solver's own (runner._get_ambient_pressure). ``compute_ambient_pressure_from_elevation`` (the 1976 standard atmosphere) at ``environment.elevation``; sea level without one. Layer 1 runs every evaluation at this pressure and targets it as the exit pressure. It used to compute its own isothermal exponential, which read 94 069.7 Pa at the LE4 site's 626.67 m while the solver -- forward mode, the Time-Series tab, Layer X -- evaluates the design at 94 020.4 Pa.
Definition at line 1225 of file layer1_static_optimization.py.
|
protected |
Replace searched ``A_throat`` / ``expansion_ratio`` with solved values. Mutates ``x[0]`` / ``x[2]`` and ``config`` in place so that the objective terms, the cached design and the finalised config all see the same solved geometry that was actually evaluated. Returns the evaluation result for the solved geometry (or the input ``result`` when nothing was derived). Falling back is always safe: if the requirement is unreachable inside the configured bounds the value clamps to the bound and the ordinary thrust / exit-pressure penalty carries the remaining residual, which the infeasibility gradient can still descend.
Definition at line 3681 of file layer1_static_optimization.py.
References _layer1_apply_chamber_geometry_to_config(), _layer1_derive_fuel_spacing(), _layer1_matched_eps(), _quantize_chamber_od_m(), and max.
Referenced by _eval_candidate(), _layer1_finalize_derived_geometry(), and _layer1_rebuild_final_config().
|
protected |
Final stability sign-off: (passed, reasons). ``require_stable_state`` means 'stable', not 'stable or marginal'. Margins are checked at face value -- a hidden 5 % let a chug gate margin of 0.9975 (Nyquist gain margin 0.998, an unstable loop) pass -- and an unknown chug gain margin is a failure, not a pass.
Definition at line 2168 of file layer1_static_optimization.py.
References max.
|
protected |
Write the ACHIEVED operating point into ``chamber_geometry.design_*``. ``design_MR`` / ``design_pressure`` / ``design_thrust`` are supposed to describe the design the config represents. Nothing ever wrote them: `config_schemas` builds them with ``getattr(chamber, 'design_MR', 2.55)``, so an optimised config carried whatever the template started with. Observed on a real emitted design -- MR 2.55 / 350 psi / 7000 N stamped on an engine actually solved at O/F ~1.68 / 420 psi / 7200 N. That is not cosmetic: ``backend/routers/geometry.py`` reads ``design_MR`` and feeds it straight into ``solve_chamber_geometry_with_cea``, so the Chamber Geometry tab drew the contour at the stale mixture ratio -- and 2.55 sits OUTSIDE the shipped CEA cache range (``MR_range: [1.0, 2.5]``), i.e. extrapolating past the table edge. Warns rather than raises when the achieved MR falls outside the cache range: the design is still real, but anything reading design_MR against that cache is extrapolating.
Definition at line 3110 of file layer1_static_optimization.py.
|
protected |
Keep ``best_objective`` / ``best_x`` aligned with parallel ``_eval_candidate`` results. When ``parent_objective`` is supplied, re-run the full parent ``objective()`` once on a new global best so ``iteration_history``, ``best_config``, and penalty breakdown fields stay populated (parallel workers only return scalars).
Definition at line 5305 of file layer1_static_optimization.py.
References _layer1_feasible_scalar_objective().
Referenced by run_cma_core().
|
protected |
Relative thrust deadband for the objective. 2% when the throat is searched (the historical value: thrust is a soft target CMA has to negotiate). 0.1% when the throat is SOLVED from thrust -- the derivation lands every candidate on target, so a wide deadband only lets edge-sitting winners through with a 2-3% miss priced at ~1-3 objective points (measured: 7341 N against 7200 with no thrust penalty at all). ``layer1_thrust_deadband_rel`` overrides both.
Definition at line 178 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Total chamber-wall thickness (both sides) for the OD -> gas-side conversion. Thin alias for :func:`engine.optimizer.utils.total_wall_thickness_m`: the wall is DERIVED as ``2 x (metal case + ablative liner when enabled)`` from the fields that own those layers (``design_requirements.metal_wall_thickness_per_side_m`` and ``ablative_cooling.initial_thickness``). Layer 3 re-sizing the liner therefore updates the wall on the next run automatically — there is no lump wall field and no write-back (the old one overwrote metal+ablative with ablative alone, so rerun geometry grew past what physically fits the OD envelope).
Definition at line 93 of file layer1_static_optimization.py.
Referenced by create_layer1_apply_x_to_config().
|
protected |
Sigma-boost tier for a search stuck on the infeasible plateau (0 = none). Only while no feasible design has been found. The tiers used to fire on absolute objective magnitudes (best > 100/150/300), which a shaping floor that never reaches zero -- the chamber-mass or performance term -- always exceeds, so every feasible run was kicked 4-7 times mid-convergence and blank ones never. Once feasible, restarts and refreshes do the exploring.
Definition at line 330 of file layer1_static_optimization.py.
References _layer1_feasible_scalar_objective().
Referenced by run_cma_core().
|
protected |
Flag Layer-2 pressure curves that no longer match the tank pressures Layer 1 just set. The initial tank pressure exists twice, owned by different layers and never reconciled: Layer 1 writes ``lox_tank/fuel_tank.initial_pressure_psi``; Layer 2 writes ``pressure_curves.initial_lox/fuel_pressure_pa``. Re-running Layer 1 moves the tanks and silently leaves the curves describing the previous design -- observed 11.3 psi out on the LOX side and 24.9 psi on the fuel side of a real emitted config. This matters beyond EngineDesign. Tank pressure is the UPSTREAM BOUNDARY CONDITION for the feed-system twin (docs/adr/0001), which EngineDesign's optimizer will import directly for Layer X. Two disagreeing values for one boundary condition is exactly the kind of thing that silently poisons a twin, so say so loudly rather than letting it cross the boundary. Detection only -- which layer should win is a design call, not something to guess here.
Definition at line 3174 of file layer1_static_optimization.py.
|
protected |
True when the LOX pitch circle is inside (or on) the fuel's: D_pitch = n s / pi with one n for both rings, so the spacings order the rings. ``fallback`` when either is unusable.
Definition at line 395 of file layer1_static_optimization.py.
Referenced by _impinging_resultant_tilt_deg(), and _resultant_tilt_breakeven_deg().
|
protected |
Copy diagnostics and injector_pressure from runner.evaluate for Layer 1 summaries. Stored-validation path builds a partial ``initial_performance`` dict; without these, momentum_ratio_R / injector ΔP metrics do not propagate to ``final_performance``.
Definition at line 2882 of file layer1_static_optimization.py.
|
protected |
Whether the Layer-1 inner loop uses the single-call native ed_evaluate. On whenever the accelerator is enabled (the default). Set ED_LAYER1_NATIVE_EVAL=0 to force the full Python path for the inner loop (debugging / A-B parity) without disabling the accelerator elsewhere.
Definition at line 5030 of file layer1_static_optimization.py.
Referenced by _eval_candidate().
|
protected |
Snap a chamber diameter to a stock increment; returns the OUTER diameter [m]. Ablative sleeve, chamber tube and case are bought in fixed sizes -- typically half-inch steps -- so a continuous optimum like 4.2 in is not purchasable: you buy 4.0 or 4.5 and the design you build is not the design that was optimised. Snapping inside the evaluation means every candidate the optimizer scores is one you can actually order, so the returned optimum is already manufacturable rather than something to round afterwards (rounding afterwards silently moves contraction ratio, L*, and wall thickness off the optimum). ``snap_target`` picks WHICH diameter lands on the increment, because only one of them can: bore = OD - wall, and the wall is rarely a whole increment (a 1.13 in wall turns a 6.00 in OD into a 4.87 in bore). ``"outer"`` snaps the tube you buy; ``"bore"`` snaps the gas-side diameter, for when the liner ID is what comes in fixed sizes. Either way the OUTER diameter is returned, since that is what the geometry writer takes. increment_in <= 0 disables snapping and returns the value unchanged.
Definition at line 4086 of file layer1_static_optimization.py.
References max.
Referenced by _apply_x_to_worker_config_inplace(), _compute_objective_value(), _layer1_finalize_derived_geometry(), _layer1_rebuild_final_config(), _layer1_solve_derived_geometry(), and create_layer1_apply_x_to_config().
|
protected |
Normalized hinge² outside [lo, hi].
Definition at line 1545 of file layer1_static_optimization.py.
References max.
Referenced by _compute_objective_value().
|
protected |
Read one requirement from either a dict or the pydantic DesignRequirementsConfig. Layer 1 hands this module a plain dict in the worker objective but the model object when the value is pulled off config.design_requirements, so a bare .get() silently returns the default for half the call sites.
Definition at line 961 of file layer1_static_optimization.py.
Referenced by _layer1_contraction_theta(), _layer1_declared_limit_gates(), and _layer1_geometry_infeasibility().
|
protected |
Parse a checkbox-style flag from Layer-1 ``requirements``. Explicit ``None`` (or a missing key) means *unset* and takes ``default``. Accepts the string forms the frontend/YAML can produce so a config saying ``false`` is not read as truthy.
Definition at line 271 of file layer1_static_optimization.py.
|
protected |
Parse float from Layer-1 ``requirements``; treat explicit ``None`` as *unset*.
Definition at line 172 of file layer1_static_optimization.py.
Referenced by _layer1_centre_clear_m(), _layer1_igniter_keepouts(), _layer1_infeasibility_gate_eps(), _layer1_injector_plate_constants(), and _layer1_merit_weights().
|
protected |
Rescale jet diameters so A_O/A_F matches MR at R≈1 while preserving A_O·A_F. YAML / UI seed orifices are not O/F-tuned; Layer 1 applies this before x0 so CMA/L-BFGS still optimize ``d_jet_O`` and ``d_jet_F`` from a physics-aligned starting point.
Definition at line 1597 of file layer1_static_optimization.py.
References _expected_geom_ao_af_for_unit_momentum_ratio(), and max.
Referenced by _layer1_rescale_impinging_seed_jets_for_mr().
|
protected |
The outward tilt this design is allowed, in degrees.
Two modes, and the default is the old one exactly:
* ``from_reach = False`` -- the operator's constant. Previous behaviour.
* ``from_reach = True`` -- derived from the design's own geometry. ``breakeven_deg`` is the
angle at which the fan arrives at the liner exactly at the throat plane; dividing the
chamber length by ``margin`` and re-taking the arctangent gives the angle that arrives at
``margin`` chamber lengths instead, which is the same thing as::
allowed = atan( tan(breakeven) / margin )
Why this exists: an outward fan is a hazard only if it REACHES the liner, and the angle at
which it does is set by ``r_wall - r_imp`` over the chamber length. ``r_imp`` is an output
the optimizer moves freely, so a constant allowance silently changes meaning between runs.
Measured: 6.0 deg was justified against r_imp = 37 mm (break-even 9.6) and the converged
design landed at r_imp = 44.1 mm, where break-even is 7.21 -- still safe, but on 1.25x
rather than the 1.6x that was intended, and nothing said so.
A non-finite or non-positive break-even falls back to the constant rather than to zero: a
degenerate geometry should not silently forbid every candidate.
Definition at line 519 of file layer1_static_optimization.py.
Referenced by _compute_objective_value().
|
protected |
Outward tilt at which the spray fan just reaches the liner at the throat plane [deg].
``layer1_resultant_tilt_max_deg`` is a CONSTANT the operator sets, but what makes a given
tilt safe is geometry the optimizer is free to move underneath it::
r_imp = r_inner + L_imp * tan(theta_inner) where the fans actually start
reach = (r_wall - r_imp) / tan(alpha) how far they run before the liner
safe <=> reach > L_chamber
so the break-even angle is ``atan2(r_wall - r_imp, L_chamber)``. Sizing the allowance by
hand is a trap: an allowance justified at one impingement radius stops being justified
when the ring pair moves out. Measured while setting this design up -- 6.0 deg was chosen
against r_imp = 37 mm (break-even 9.6 deg) and the converged design landed at r_imp =
44.1 mm, where break-even is 7.21 deg. Still inside, but on 1.25x rather than the 1.6x
that was intended, and nothing would have said so.
Returns NaN when the geometry is degenerate. This is a REPORTING aid; it deliberately does
not move the gate, which stays exactly where the operator put it.
Definition at line 473 of file layer1_static_optimization.py.
References _lox_ring_inboard().
Referenced by _compute_objective_value().
|
protected |
Snap integer dimensions to nearest integer.
Ensures cache consistency and physical validity for discrete variables.
Args:
x: Candidate vector
integer_indices: List of indices to snap (e.g., [6] for n_orifices)
Returns:
Snapped vector with integer dimensions rounded
Definition at line 4215 of file layer1_static_optimization.py.
Referenced by _layer1_cma_warmstart_candidates(), _layer1_iso_area_count_scan(), run_cma_core(), and run_hybrid_optimization().
|
protected |
Keep a parent-side copy of the last successful worker ``evaluate()`` for validation replay.
Definition at line 367 of file layer1_static_optimization.py.
Referenced by _layer1_cma_warmstart_candidates(), and run_cma_core().
|
protected |
Squared, scale-normalized penalty on unequal propellant tank pressures. Equal tank pressures do NOT fall out of momentum matching: the two propellants have different densities, different feed-system losses, and (because the orifices are sized/angled differently) different injector ΔP. So driving the tanks toward a common pressure is its own objective, and the optimizer pays for it by reshaping orifice area / velocity / angle while still holding R≈1 and SMD.
Definition at line 1850 of file layer1_static_optimization.py.
Referenced by _compute_objective_value().
|
protected |
Prefer unified ``chamber_geometry``; many YAMLs leave legacy ``chamber`` null.
Definition at line 157 of file layer1_static_optimization.py.
|
protected |
Definition at line 1638 of file layer1_static_optimization.py.
Referenced by _layer1_rescale_impinging_seed_jets_for_mr().
|
protected |
The candidate vector AS EVALUATED, falling back to the proposal. Derived DOFs are solved inside the worker and their bounds are collapsed, so the vector CMA proposed still carries the seed for them. Only ``x_solved`` describes the design that was actually scored -- record anything else and the winner reported back is not the winner that was measured.
Definition at line 350 of file layer1_static_optimization.py.
Referenced by _layer1_iso_area_count_scan(), and run_cma_core().
| list[list[int]] engine.optimizer.layers.layer1_static_optimization.compute_blocks_from_elites | ( | ElitePool | elite_pool, |
| int | num_blocks, | ||
| int | dim, | ||
| str | method = "random", | ||
| float | overlap_fraction = 0.0, | ||
| np.random.Generator | rng = None ) |
Compute variable blocks for re-optimization. Methods: - "random": Randomly partition variables. - "corr_greedy": Use correlation matrix of standardized elites. Distance = 1 - abs(Correlation).
Definition at line 10534 of file layer1_static_optimization.py.
References min.
Referenced by run_hybrid_optimization().
| Callable engine.optimizer.layers.layer1_static_optimization.create_layer1_apply_x_to_config | ( | list | bounds, |
| float | max_chamber_od, | ||
| float | max_nozzle_exit, | ||
| str | injector_type = "pintle", | ||
| float | chamber_od_increment_in = 0.0, | ||
| str | chamber_od_snap_target = "outer", | ||
| Optional[dict] | derive_constants = None, | ||
| Tuple[float, float] | derive_spacing_F_range = (0.0, float("inf")) ) |
Create the apply_x_to_config function with dependencies. Returns a function that converts optimizer variables to engine config.
Definition at line 3941 of file layer1_static_optimization.py.
References _layer1_apply_chamber_geometry_to_config(), _layer1_derive_fuel_spacing(), _layer1_derive_matched_tank_pressure(), _layer1_total_wall_thickness_m(), _quantize_chamber_od_m(), and max.
| Tuple[np.ndarray, float, int] engine.optimizer.layers.layer1_static_optimization.run_cma_core | ( | Callable[[np.ndarray], float] | objective_fn, |
| np.ndarray | x0, | ||
| float | sigma0, | ||
| list | bounds, | ||
| int | budget, | ||
| int | popsize, | ||
| np.ndarray | cma_stds = None, | ||
| int | seed = None, | ||
| Optional[ElitePool] | elite_pool = None, | ||
| Optional[Callable[[np.ndarray], float]] | true_objective_fn = None, | ||
| Optional[Dict[str, Any]] | valley_escape_tracker = None, | ||
| logger = None, | |||
| Optional[ProcessPoolExecutor] | executor = None, | ||
| Optional[list] | integer_dims = None, | ||
| int | od_index = -1, | ||
| float | od_step_m = 0.0, | ||
| Optional[Dict[int, float]] | fixed_variables = None, | ||
| Optional[dict] | eval_cache = None, | ||
| Optional[Callable[[np.ndarray], Tuple[int, ...]]] | make_cache_key_fn = None, | ||
| Optional[Any] | stop_event = None, | ||
| Optional[np.ndarray] | embed_base = None, | ||
| Optional[List[int]] | embed_idx = None, | ||
| Optional[Callable[[np.ndarray], float]] | full_objective_fn = None ) |
Core re-usable CMA-ES wrapper with optional parallel evaluation.
``embed_base``/``embed_idx``: the search is over a sub-vector (a block); each candidate is
written into a copy of ``embed_base`` at ``embed_idx`` and the FULL vector is scored by the
worker pool, so a block ranks on the same objective as Stage A. ``full_objective_fn`` is
the full-vector parent objective used for best-tracking sync.
Args:
objective_fn: The function CMA-ES optimizes (could include penalties).
x0: Initial mean.
sigma0: Initial step size.
bounds: List of (min, max) for EACH dimension.
budget: Max function evaluations.
popsize: Population size.
cma_stds: Coordinate-wise standard deviations (optional scaling).
seed: Random seed.
elite_pool: Optional pool to capture all candidates evaluated.
true_objective_fn: If provided, used to evaluate candidates for ElitePool
and best-so-far tracking (ignoring the penalized objective).
If None, objective_fn is used.
executor: Optional ProcessPoolExecutor for parallel evaluation.
integer_dims: List of integer dimension indices for snapping.
eval_cache: Optional evaluation cache dict.
Returns:
(best_x, best_f, evals_used)
Note: best_f returned is the one derived from true_objective_fn if present,
otherwise objective_fn.
Definition at line 10134 of file layer1_static_optimization.py.
References _layer1_cma_discrete_options(), _layer1_sync_best_from_worker_eval(), _layer1_valley_escape_tier(), _snap_integer_dims(), _store_last_good_eval_bundle_from_worker_res(), _x_solved_or(), max, and min.
Referenced by run_hybrid_optimization().
| Tuple[np.ndarray, float, int] engine.optimizer.layers.layer1_static_optimization.run_hybrid_optimization | ( | Callable[[np.ndarray], float] | objective, |
| list | bounds, | ||
| np.ndarray | x0, | ||
| HybridOptimizerConfig | hybrid_config, | ||
| int | total_budget = 3000, | ||
| logger = None, | |||
| log_status_fn = None, | |||
| update_progress_fn = None, | |||
| Optional[Dict[str, Any]] | valley_escape_tracker = None, | ||
| Optional[ProcessPoolExecutor] | executor = None, | ||
| Optional[list] | integer_dims = None, | ||
| int | od_index = -1, | ||
| float | od_step_m = 0.0, | ||
| Optional[Dict[int, float]] | fixed_variables = None, | ||
| Optional[dict] | eval_cache = None, | ||
| Optional[Callable[[np.ndarray], Tuple[int, ...]]] | make_cache_key_fn = None, | ||
| Optional[Any] | stop_event = None, | ||
| Optional[int] | seed = None, | ||
| int | popsize = 16, | ||
| Optional[Tuple[int, Tuple[int, ...], Tuple[int, ...]]] | iso_area = None ) |
Run Hybrid CMA-ES + Block Re-optimization.
``iso_area`` (impinging): after Stage A and before every refresh, every element count is
scored along the iso-area path (see _layer1_iso_area_count_scan) and the best is taken.
``seed`` makes the whole search a deterministic function of its inputs. It was not:
this function built ``np.random.default_rng()`` with no seed and called ``run_cma_core``
without ``seed=`` in Stage A, in every block and in every refresh, so CMA seeded itself
from the clock. ``layer1_random_seed`` reached the warm start and nothing after it --
measured, three runs of one config at seed 37 gave three different injectors (included
angle 89 / 87 / 83 deg). Every ``run_cma_core`` call below now takes a seed derived from
this one, distinct per stage so no two stages replay the same sample stream.
``popsize`` is the Stage A / refresh population. It was hardcoded to 16 while the caller
computed and logged 48; the block stage keeps its own smaller population.
Logic:
1. Stage A: Global Exploration (Standard CMA-ES)
2. Loop Cycles:
a. Stage B: Build Blocks (Random or Correlation-based)
b. Stage C: Block Re-optimization (Soft freezing)
3. Stage D: Global Refresh (Periodic)
Args:
objective: Main objective function (returns float).
bounds: List of (min, max).
x0: Initial guess.
hybrid_config: Configuration.
total_budget: Max evals.
Returns:
(best_x, best_f, total_evals)
Definition at line 10647 of file layer1_static_optimization.py.
References _layer1_iso_area_count_scan(), _snap_integer_dims(), compute_blocks_from_elites(), max, min, and run_cma_core().
| np.ndarray engine.optimizer.layers.layer1_static_optimization.run_layer1_global_search | ( | Callable[[np.ndarray], float] | objective, |
| list | bounds, | ||
| np.ndarray | x0, | ||
| int | max_evals = 150, | ||
| int | random_seed = 42 ) |
Lightweight global search for Layer 1 using random sampling + short DE. This is intended to very quickly improve the starting point before the main local optimizer (L-BFGS-B) runs in the orchestrator. - Keeps evaluation budget small (max_evals) to avoid long runtimes. - Always respects the provided bounds. - Falls back gracefully if scipy's differential_evolution is unavailable.
Definition at line 5415 of file layer1_static_optimization.py.
| Tuple[PintleEngineConfig, Dict[str, Any]] engine.optimizer.layers.layer1_static_optimization.run_layer1_optimization | ( | PintleEngineConfig | config_obj, |
| PintleEngineRunner | runner, | ||
| Dict[str, Any] | requirements, | ||
| float | target_burn_time, | ||
| Dict[str, float] | tolerances, | ||
| Dict[str, Any] | pressure_config, | ||
| Optional[Callable[[str, float, str], None]] | update_progress = None, | ||
| Optional[Callable[[str, str], None]] | log_status = None, | ||
| Optional[Callable[[int, float, float], None]] | objective_callback = None, | ||
| Optional[Any] | stop_event = None, | ||
| Optional[int] | layer1_max_iterations = None, | ||
| Optional[int] | layer1_cma_restarts = None, | ||
| bool | layer1_smoke = False ) |
Run complete Layer 1 optimization: geometry + initial tank pressures.
This function contains ALL Layer 1 optimization logic:
- Setup (bounds, initial guess)
- Objective function definition
- Optimization loop (CMA-ES with random restarts + L-BFGS-B)
- Validation
- Results packaging
Note:
Default ``max_iterations`` is 150 for robust convergence (override via ``layer1_max_iterations``
for smoke tests). Design vector is **10** DOFs for pintle and **13** for impinging injectors
(paired unlike doublets: shared ``n_doublets`` for LOX/fuel counts, independent jets per side).
Random CMA restarts default to 3 (override via ``layer1_cma_restarts``).
Set ``layer1_smoke=True`` to force pure CMA-ES (ignore ``hybrid_cma_blocks``) and,
unless ``layer1_cma_restarts`` is set explicitly, use a single CMA restart for short runs.
Args:
config_obj: Base engine configuration
runner: Engine runner (for validation)
requirements: Design requirements dict
target_burn_time: Target burn time [s]
tolerances: Tolerance dict (thrust, apogee)
pressure_config: Pressure configuration dict
update_progress: Optional progress callback (stage, progress, message)
log_status: Optional status logging callback (stage, message)
objective_callback: Optional callback for objective history (iteration, objective, best_objective)
layer1_smoke: When True, force pure CMA-ES and (if ``layer1_cma_restarts`` is unset) a single restart.
Returns:
optimized_config: Optimized engine configuration
results: Results dict with performance, validation, history, etc.
Definition at line 5587 of file layer1_static_optimization.py.
|
protected |
Definition at line 82 of file layer1_static_optimization.py.
|
protected |
Definition at line 3105 of file layer1_static_optimization.py.
|
protected |
Definition at line 3107 of file layer1_static_optimization.py.
|
protected |
Definition at line 3106 of file layer1_static_optimization.py.
|
protected |
Definition at line 1172 of file layer1_static_optimization.py.
|
protected |
Definition at line 4391 of file layer1_static_optimization.py.
|
protected |
Definition at line 4392 of file layer1_static_optimization.py.
|
protected |
Definition at line 128 of file layer1_static_optimization.py.
|
protected |
Definition at line 1171 of file layer1_static_optimization.py.
|
protected |
Definition at line 115 of file layer1_static_optimization.py.
|
protected |
Definition at line 114 of file layer1_static_optimization.py.
|
protected |
Definition at line 119 of file layer1_static_optimization.py.
|
protected |
Definition at line 122 of file layer1_static_optimization.py.
|
protected |
Definition at line 110 of file layer1_static_optimization.py.
|
protected |
Definition at line 126 of file layer1_static_optimization.py.
|
protected |
Definition at line 132 of file layer1_static_optimization.py.
|
protected |
Definition at line 137 of file layer1_static_optimization.py.
|
protected |
Definition at line 136 of file layer1_static_optimization.py.
|
protected |
Definition at line 129 of file layer1_static_optimization.py.
|
protected |
Definition at line 45 of file layer1_static_optimization.py.
|
protected |
Definition at line 1131 of file layer1_static_optimization.py.
|
protected |
Definition at line 3933 of file layer1_static_optimization.py.
|
protected |
Definition at line 3934 of file layer1_static_optimization.py.
|
protected |
Definition at line 3936 of file layer1_static_optimization.py.
|
protected |
Definition at line 3937 of file layer1_static_optimization.py.
|
protected |
Definition at line 3935 of file layer1_static_optimization.py.
|
protected |
Definition at line 3932 of file layer1_static_optimization.py.
| engine.optimizer.layers.layer1_static_optimization.cma = None |
Definition at line 62 of file layer1_static_optimization.py.
| float engine.optimizer.layers.layer1_static_optimization.DEFAULT_CONTRACTION_HALF_ANGLE_DEG = 45.0 |
Definition at line 979 of file layer1_static_optimization.py.
| engine.optimizer.layers.layer1_static_optimization.fun = float(fun) |
Definition at line 7990 of file layer1_static_optimization.py.
| engine.optimizer.layers.layer1_static_optimization.success = success |
Definition at line 7991 of file layer1_static_optimization.py.
| float engine.optimizer.layers.layer1_static_optimization.TOTAL_WALL_THICKNESS_M = 0.0254 |
Definition at line 90 of file layer1_static_optimization.py.
| engine.optimizer.layers.layer1_static_optimization.x = np.asarray(x, dtype=float) |
Definition at line 7989 of file layer1_static_optimization.py.