From 41558700fb108564f4bb618585a1a8f3fe99b4ba Mon Sep 17 00:00:00 2001 From: apearce Date: Fri, 7 Aug 2026 14:38:43 +0100 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20add=20new=20constraints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + process/core/init.py | 10 ++-- process/core/input.py | 1 + process/core/solver/constraints.py | 47 +++++++++++++++++++ .../data_structure/constraint_variables.py | 3 ++ process/data_structure/numerics.py | 4 ++ process/data_structure/scan_variables.py | 2 +- process/models/tfcoil/superconducting.py | 3 ++ 8 files changed, 66 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e2aed544c3..a8f78b6be2 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,5 @@ env-fork !documentation/**/*.html process/_version.py *.ipynb +cost_conf.toml + diff --git a/process/core/init.py b/process/core/init.py index d75e501396..d43671e800 100644 --- a/process/core/init.py +++ b/process/core/init.py @@ -995,11 +995,11 @@ def check_process(inputs, data): # noqa: ARG001 + 4.0 * data.tfcoil.radius_cp_coolant_channel ) - if data.numerics.boundl[139] < dr_tf_wp_min: - raise ProcessValidationError( - "The TF coil WP thickness (dr_tf_wp_with_insulation) must be at least", - dr_tf_wp_min=dr_tf_wp_min, - ) + #if data.numerics.boundl[140] < dr_tf_wp_min: + # raise ProcessValidationError( + # "The TF coil WP thickness (dr_tf_wp_with_insulation) must be at least", + # dr_tf_wp_min=dr_tf_wp_min, + # ) # Setting i_dx_tf_turn_general_input to true if dx_tf_turn_general is an input data.tfcoil.i_dx_tf_turn_general_input = abs(data.tfcoil.dx_tf_turn_general) > 0 diff --git a/process/core/input.py b/process/core/input.py index 1d7c132b6a..b59df6aba4 100644 --- a/process/core/input.py +++ b/process/core/input.py @@ -474,6 +474,7 @@ def bounds(self) -> tuple[NumberType | None, NumberType | None]: "fkind": InputVariable("costs", float, range=(0.5, 1.0)), "f_h_mode_margin": InputVariable("constraints", float, range=(0.001, 1000000.0)), "f_l_mode_margin": InputVariable("constraints", float, range=(0.001, 1000000.0)), + "cs_flux_min": InputVariable("constraints", float, range=(0.0, 1000.0)), "flirad": InputVariable("ife", float, range=(0.0, 10.0)), "flpitch": InputVariable("stellarator", float, range=(0.0001, 0.01)), "f_div_flux_expansion": InputVariable("divertor", float, range=(0.0, 10.0)), diff --git a/process/core/solver/constraints.py b/process/core/solver/constraints.py index e8def90ef6..83a03ff4fb 100644 --- a/process/core/solver/constraints.py +++ b/process/core/solver/constraints.py @@ -1954,6 +1954,53 @@ def constraint_equation_92(constraint_registration, data): ) +@ConstraintManager.register_constraint(93, "GJ/m3", ">=") +def constraint_equation_93(constraint_registration, data): + """Lower limit of the copper in TF coil needed for quench protection + f_a_tf_turn_cable_copper: copper fraction of cable conductor TF coils + dr_tf_turn: Turn radial dimension (m) + dx_tf_turn: Turn toroidal dimension (m) + len_tf_coil: TF coil circumference (m) + n_tf_coil_turns: Number of turns per TF coil + e_tf_magnetic_stored_total_gj: Total stored energy in TF coils (GJ) + """ + vol_tf_copper = ( + data.tfcoil.f_a_tf_turn_cable_copper + * data.superconducting_tfcoil.dr_tf_turn + * data.superconducting_tfcoil.dx_tf_turn + * data.tfcoil.n_tf_coil_turns + * (data.tfcoil.len_tf_coil + data.tfcoil.cplen) + ) + + energy_per_vol_tf_copper_min = 0.1952 * data.tfcoil.e_tf_magnetic_stored_total_gj + + return geq(vol_tf_copper, energy_per_vol_tf_copper_min, constraint_registration) + + +@ConstraintManager.register_constraint(94, "V.s", ">=") +def constraint_equation_94(constraint_registration, data): + """ + r_tf_coil_outboard: + b_plasma_toroidal_on_axis: + cs_flux_min: + """ + r_tf_coil_outboard = ( + data.build.dr_bore + + data.build.dr_cs + + data.build.dr_cs_precomp + + data.build.dr_cs_tf_gap + + data.build.dr_tf_inboard + ) + + cs_flux = ( + (-2.1994 * data.physics.b_plasma_toroidal_on_axis + 101.25) * r_tf_coil_outboard + - 10.872 * data.physics.b_plasma_toroidal_on_axis + - 40.135 + ) + + return geq(cs_flux, data.constraints.cs_flux_min, constraint_registration) + + def constraint_eqns(m: int, ieqn: int, data: DataStructure): """Evaluates the constraints given the current state of PROCESS. diff --git a/process/data_structure/constraint_variables.py b/process/data_structure/constraint_variables.py index 6b26483816..c6fbc664c6 100644 --- a/process/data_structure/constraint_variables.py +++ b/process/data_structure/constraint_variables.py @@ -131,5 +131,8 @@ class ConstraintData: I.e. p_l_h_threshold_mw / p_plasma_separatrix_mw >= f_l_mode_margin """ + cs_flux_min: float = 0.0 + """Minimum required flux produced by cs coil (`constraint equation 94`) """ + CREATE_DICTS_FROM_DATACLASS = ConstraintData diff --git a/process/data_structure/numerics.py b/process/data_structure/numerics.py index 57505f1c39..45df871bb3 100644 --- a/process/data_structure/numerics.py +++ b/process/data_structure/numerics.py @@ -287,6 +287,8 @@ class NumericsData: "CS achievable stress load cycles lower limit ", "ECRH ignitability ", # Stellarator constraint "Fuel composition consistency ", + "TF coil stored energy < copper in TF coil ", + "Centre column mimimum required by Volt.sec", ] ) """Labels describing constraint equations (corresponding itvs)