diff --git a/CMakeLists.txt b/CMakeLists.txt index c44d8e64ff..8830394df4 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,6 @@ LIST(APPEND PROCESS_SRCS heat_transport_variables.f90 buildings_variables.f90 water_usage_variables.f90 - constraint_equations.f90 constants.f90 build_variables.f90 current_drive_variables.f90 diff --git a/documentation/proc-pages/development/add-vars.md b/documentation/proc-pages/development/add-vars.md index 12852133c6..cc7457d864 100644 --- a/documentation/proc-pages/development/add-vars.md +++ b/documentation/proc-pages/development/add-vars.md @@ -187,78 +187,32 @@ After following the instruction to add an input variable, you can make the varia ## Add a constraint equation -Constraint equations are added to *PROCESS* in the following way: +Constraint equations are added to *PROCESS* in the `process/constraints.py` file. They are registered with the `ConstraintManager` whenever the application is run. Each equation has a unique name that is currently an integer, however upgrades to the input file format in the future will allow arbitrary hashable constraint names. -1.
- Increment the parameter `ipeqns` in module `numerics` in the source file - `numerics.f90` in order to accommodate the new constraint. -
-2.- Add a line to `lablcc` in the source file `numerics.f90` decribing the - constraint equation. -
-3.- Add a line to the FORD description of `lablcc` the source file `numerics.f90`. -
-4.- Add a new Fortran `case` statement to routine `CONSTRAINT_EQNS` in source - file `constraint_equations.f90`. -
-5.- Then add a new subrountine including the `constraints` module ensuring that - all the variables used in the formula are contained in the modules specified - via `use, XX only: XX` statements. Use a similar formulation to that used - for the existing constraint equations, remembering that the code will try - to force `cc(i)` to be zero. -
-6.- If the constraint is using a f-value, notify the constraint equation - number on the f-value description. -
- -- Remember that if an inequality is being added, a new f-value iteration - variable may also need to be added to the code. -
+A constraint is simply added by registering the constraint to the manager using a decorator. -```fortran - do i = i1,i2 - ! The constraint value in physical units is - ! a) for consistency equations, the quantity to be equated, or - ! b) for limit equations, the limiting value. - ! The symbol is = for a consistency equation, < for an upper limit - ! or > for a lower limit. - select case (icc(i)) - ... - ! Equation for fusion power upper limit - case (9); call constraint_eqn_009(args) +```python +@ConstraintManager.register_constraint(1234, "m", "=") +def my_constraint_function(): ... ``` +The arguments to the `register_constraint` function are: -```fortran - subroutine constraint_eqn_009(args) - !! Equation for fusion power upper limit - !! author: P B Lloyd, CCFE, Culham Science Centre - !! args : output structure : residual error; constraint value; - !! residual error in physical units; output string; units string - !! Equation for fusion power upper limit - !! #=# physics - !! #=#=# fp_fusion_total_max_mw, p_fusion_total_max_mw - !! and hence also optional here. - !! Logic change during pre-factoring: err, symbol, units will be assigned only if present. - !! fp_fusion_total_max_mw : input real : f-value for maximum fusion power - !! p_fusion_total_max_mw : input real : maximum fusion power (MW) - !! p_fusion_total_mw : input real : fusion power (MW) - use constraint_variables, only: fp_fusion_total_max_mw, p_fusion_total_max_mw - use physics_variables, only: p_fusion_total_mw - implicit none - type (constraint_args_type), intent(out) :: args - - args%cc = 1.0D0 - fp_fusion_total_max_mw * p_fusion_total_max_mw/p_fusion_total_mw - args%con = p_fusion_total_max_mw * (1.0D0 - args%cc) - args%err = p_fusion_total_mw * args%cc - args%symbol = '<' - args%units = 'MW' - - end subroutine constraint_eqn_009 -``` +- Name (again, currently an integer) +- Unit (for output reporting purposes) +- Symbol (e.g. =, >=, <=. Again, for output reporting purposes) + + +`my_constraint_function` should be named appropriately and return a `ConstraintResult` which contains the: + +- Normalised residual error +- Constraint value +- Constraint error +```python +@ConstraintManager.register_constraint(1234, "m", "=") +def my_constraint_function(): + normalised_residual = ... + value = ... + error = ... + return ConstraintResult(normalised_residual, value, error) +``` \ No newline at end of file diff --git a/examples/single_model_evaluation.ipynb b/examples/single_model_evaluation.ipynb index abbee3cab6..7a46661367 100644 --- a/examples/single_model_evaluation.ipynb +++ b/examples/single_model_evaluation.ipynb @@ -238,6 +238,9 @@ "metadata": {}, "outputs": [], "source": [ + "from process.constraints import ConstraintManager\n", + "\n", + "\n", "def run_impurities(w_imp_fracs):\n", " \"\"\"Calculate responses to W impurities.\"\"\"\n", " n = w_imp_fracs.shape[0]\n", @@ -253,7 +256,7 @@ " single_run.models.physics.physics()\n", "\n", " # Evaluate constraint equation 15 (L-H threshold constraint)\n", - " con15_value, _, _, _, _ = process.fortran.constraints.constraint_eqn_015()\n", + " con15_value = ConstraintManager.evaluate_constraint(15).normalised_residual\n", "\n", " # Need to copy values\n", " p_plasma_rad_mw[i] = process.fortran.physics_variables.p_plasma_rad_mw.item()\n", @@ -372,7 +375,7 @@ ], "metadata": { "kernelspec": { - "display_name": "process", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -386,7 +389,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.9" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/process/caller.py b/process/caller.py index 9721fa7367..3df4190087 100644 --- a/process/caller.py +++ b/process/caller.py @@ -7,6 +7,7 @@ import numpy as np from tabulate import tabulate +import process.constraints as constraints from process import fortran as ft from process.final import finalise from process.io.mfile import MFile @@ -75,7 +76,7 @@ def call_models(self, xc: np.ndarray, m: int) -> tuple[float, np.ndarray]: self._call_models_once(xc) # Evaluate objective function and constraints objf = objective_function(ft.numerics.minmax) - conf, _, _, _, _ = ft.constraints.constraint_eqns(m, -1) + conf, _, _, _, _ = constraints.constraint_eqns(m, -1) if objf_prev is None and conf_prev is None: # First run: run again to check idempotence diff --git a/process/constraints.py b/process/constraints.py new file mode 100644 index 0000000000..0fd0dd3789 --- /dev/null +++ b/process/constraints.py @@ -0,0 +1,2430 @@ +from collections.abc import Callable, Hashable +from dataclasses import dataclass +from typing import ClassVar, Literal + +import numpy as np + +import process.fortran as fortran +from process.exceptions import ProcessError, ProcessValueError + +ConstraintSymbolType = Literal["=", ">=", "<="] + + +@dataclass +class ConstraintResult: + """The constraint quantities given the current state of the code + (aka given an evaluation at the point x). + """ + + normalised_residual: float + """The normalised residual of the constraint.""" + constraint_value: float + """The value of the constraint (in the physical units).""" + constraint_error: float + """The residual error of the constraint (in the physical units).""" + + +@dataclass +class ConstraintRegistration: + """Contains the constraint equation and metadata about the constraint.""" + + name: Hashable + """The name (often a number) of the constraint. It can be any hashable e.g. a string.""" + constraint_equation: Callable[[], ConstraintResult] + """The constraint equation that, when called, returns the normalised resiudal, + constraint value, and constraint error. + """ + units: str + """The units of the constraint value and error.""" + symbol: ConstraintSymbolType + """The type of constraint (<=, >=, ==). Only used for writing output diagnostics, + this does not impact the calculations. + """ + + +class ConstraintManager: + """A singleton class that manages the registration of constraint equations + and metadata. + + This class maintains an internal registry of constraints indexed by their names. + Classmethods provide access to this registry or to directly evaluate constraints. + """ + + _constraint_registry: ClassVar[dict[Hashable, ConstraintRegistration]] = {} + """An internal registry of the PROCESS constraint equations""" + + def __init__(self): + raise NotImplementedError(f"{self.__class__.__name__} cannot be instantiated.") + + @classmethod + def num_constraints(cls): + """Return the number of constraints currently in the registry""" + return len(cls._constraint_registry) + + @classmethod + def register_constraint( + cls, name: Hashable, units: str, symbol: ConstraintSymbolType + ) -> Callable[[], Callable[[], ConstraintResult]]: + """A decorator to add a constraint equation with metadata to the registry. + + The decorator should wrap a function with no argument which returns a + ConstraintResult. + + :param name: the name of the constraint and how it can be indexed from the registry + :type name: Hashable + :param units: the units of the constraint written to the output files + :type units: str + :param symbol: the symbol of the constraint written to the output files + :type symbol: str + """ + + def wrapper(func: Callable[[], ConstraintResult]): + if name in cls._constraint_registry: + raise ValueError(f"Constraint {name} already exists.") + cls._constraint_registry[name] = ConstraintRegistration( + name, func, units, symbol + ) + + return func + + return wrapper + + @classmethod + def get_constraint(cls, name: Hashable): + """Retrieves a constraint registration from the registry given its name. + Returns None if no constraint with the name exists. + + :param name: the name of the constraint + :type name: Hashable + :returns: the constraint registration object + :rtype: ConstraintRegistration | None + """ + return cls._constraint_registry.get(name) + + @classmethod + def evaluate_constraint(cls, name: Hashable): + """Evalutes a constraint with a given name. + :param name: the name of the constraint + :type name: Hashable + :returns: the result of evaluating the constraint + :rtype: ConstraintResult | None + """ + registration = cls.get_constraint(name) + + if registration is not None: + return registration.constraint_equation() + + return None + + +@ConstraintManager.register_constraint(1, "", "=") +def constraint_equation_1(): + """Relationship between beta, temperature (keV) and density + + author: J Morris + + beta: total plasma beta + beta_{ft}: fast alpha beta component + beta_{NBI}: neutral beam beta component + n_e: electron density [/m3] + n_i: total ion density [/m3] + T_e: density weighted average electron temperature [keV] + T_i: density weighted average ion temperature [keV] + B_{tot}: total toroidal + poloidal field [T] + """ + cc = ( + 1.0 + - ( + fortran.physics_variables.beta_fast_alpha + + fortran.physics_variables.beta_beam + + 2.0e3 + * fortran.constants.rmu0 + * fortran.constants.electron_charge + * ( + fortran.physics_variables.dene * fortran.physics_variables.ten + + fortran.physics_variables.nd_ions_total + * fortran.physics_variables.tin + ) + / fortran.physics_variables.btot**2 + ) + / fortran.physics_variables.beta + ) + return ConstraintResult( + normalised_residual=cc, + constraint_value=(fortran.physics_variables.beta * (1.0 - cc)), + constraint_error=(fortran.physics_variables.beta * cc), + ) + + +@ConstraintManager.register_constraint(2, "MW/m3", "=") +def constraint_equation_2(): + """author: J. Morris + + i_rad_loss: switch for radiation loss term usage in power balance (see User Guide): + - 0 total power lost is scaling power plus radiation (needed for ipedestal=2,3) + - 1 total power lost is scaling power plus core radiation only + - 2 total power lost is scaling power only, with no additional + allowance for radiation. This is not recommended for power plant models. + + i_plasma_ignited: switch for ignition assumption: + - 0 do not assume plasma ignition; + - 1 assume ignited (but include auxiliary power in costs) + + pden_electron_transport_loss_mw: electron transport power per volume (MW/m3) + pden_ion_transport_loss_mw: ion transport power per volume (MW/m3) + pden_plasma_rad_mw: total radiation power per volume (MW/m3) + pden_plasma_core_rad_mw: total core radiation power per volume (MW/m3) + f_alpha_plasma: fraction of alpha power deposited in plasma + pden_alpha_total_mw: alpha power per volume (MW/m3) + pden_non_alpha_charged_mw: non-alpha charged particle fusion power per volume (MW/m3) + pden_plasma_ohmic_mw: ohmic heating power per volume (MW/m3) + p_hcd_injected_total_mw: total auxiliary injected power (MW) + vol_plasma: plasma volume (m3) + """ + # pscaling: total transport power per volume (MW/m3) + + pscaling = ( + fortran.physics_variables.pden_electron_transport_loss_mw + + fortran.physics_variables.pden_ion_transport_loss_mw + ) + # Total power lost is scaling power plus radiation: + if fortran.physics_variables.i_rad_loss == 0: + pnumerator = pscaling + fortran.physics_variables.pden_plasma_rad_mw + elif fortran.physics_variables.i_rad_loss == 1: + pnumerator = pscaling + fortran.physics_variables.pden_plasma_core_rad_mw + else: + pnumerator = pscaling + + # if plasma not ignited include injected power + if fortran.physics_variables.i_plasma_ignited == 0: + pdenom = ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.pden_alpha_total_mw + + fortran.physics_variables.pden_non_alpha_charged_mw + + fortran.physics_variables.pden_plasma_ohmic_mw + + fortran.current_drive_variables.p_hcd_injected_total_mw + / fortran.physics_variables.vol_plasma + ) + else: + # if plasma ignited + pdenom = ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.pden_alpha_total_mw + + fortran.physics_variables.pden_non_alpha_charged_mw + + fortran.physics_variables.pden_plasma_ohmic_mw + ) + + cc = 1.0 - pnumerator / pdenom + + return ConstraintResult(cc, pdenom * (1.0 - cc), pdenom * cc) + + +@ConstraintManager.register_constraint(3, "MW/m3", "=") +def constraint_equation_3(): + """Global power balance equation for ions + i_plasma_ignited: switch for ignition assumption + - 0 do not assume plasma ignition; + - 1 assume ignited (but include auxiliary power in costs) + + pden_ion_transport_loss_mw: ion transport power per volume (MW/m3) + piepv: ion/electron equilibration power per volume (MW/m3) + f_alpha_plasma: fraction of alpha power deposited in plasma + f_pden_alpha_ions_mw: alpha power per volume to ions (MW/m3) + p_hcd_injected_ions_mw: auxiliary injected power to ions (MW) + vol_plasma: plasma volume (m3) + """ + # No assume plasma ignition: + if fortran.physics_variables.i_plasma_ignited == 0: + cc = 1.0 - ( + fortran.physics_variables.pden_ion_transport_loss_mw + + fortran.physics_variables.piepv + ) / ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_ions_mw + + fortran.current_drive_variables.p_hcd_injected_ions_mw + / fortran.physics_variables.vol_plasma + ) + return ConstraintResult( + cc, + ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_ions_mw + + fortran.current_drive_variables.p_hcd_injected_ions_mw + / fortran.physics_variables.vol_plasma + ) + * (1.0 - cc), + ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_ions_mw + + fortran.current_drive_variables.p_hcd_injected_ions_mw + / fortran.physics_variables.vol_plasma + ) + * cc, + ) + + # Plasma ignited: + cc = 1.0 - ( + fortran.physics_variables.pden_ion_transport_loss_mw + + fortran.physics_variables.piepv + ) / ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_ions_mw + ) + return ConstraintResult( + cc, + ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_ions_mw + ) + * (1.0 - cc), + ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_ions_mw + ) + * cc, + ) + + +@ConstraintManager.register_constraint(4, "MW/m3", "=") +def constraint_equation_4(): + """Global power balance equation for electrons + author: P B Lloyd, CCFE, Culham Science Centre + + i_rad_loss: switch for radiation loss term usage in power balance + - 0 total power lost is scaling power plus radiation (needed for ipedestal=2,3) + - 1 total power lost is scaling power plus core radiation only + - 2 total power lost is scaling power only, with no additional + allowance for radiation. This is not recommended for power plant models. + + i_plasma_ignited: switch for ignition assumption: + - 0 do not assume plasma ignition; + - 1 assume ignited (but include auxiliary power in costs) + + pden_electron_transport_loss_mw: electron transport power per volume (MW/m3) + pden_plasma_rad_mw: total radiation power per volume (MW/m3) + pden_plasma_core_rad_mw: total core radiation power per volume (MW/m3) + f_alpha_plasma: fraction of alpha power deposited in plasma + f_pden_alpha_electron_mw: alpha power per volume to electrons (MW/m3) + piepv: ion/electron equilibration power per volume (MW/m3) + p_hcd_injected_electrons_mw: auxiliary injected power to electrons (MW) + vol_plasma: plasma volume (m3) + """ + # pscaling: total transport power per volume (MW/m3) + + pscaling = fortran.physics_variables.pden_electron_transport_loss_mw + # Total power lost is scaling power plus radiation: + if fortran.physics_variables.i_rad_loss == 0: + pnumerator = pscaling + fortran.physics_variables.pden_plasma_rad_mw + elif fortran.physics_variables.i_rad_loss == 1: + pnumerator = pscaling + fortran.physics_variables.pden_plasma_core_rad_mw + else: + pnumerator = pscaling + + # if plasma not ignited include injected power + if fortran.physics_variables.i_plasma_ignited == 0: + pdenom = ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_electron_mw + + fortran.physics_variables.piepv + + fortran.current_drive_variables.p_hcd_injected_electrons_mw + / fortran.physics_variables.vol_plasma + ) + else: + # if plasma ignited + pdenom = ( + fortran.physics_variables.f_alpha_plasma + * fortran.physics_variables.f_pden_alpha_electron_mw + + fortran.physics_variables.piepv + ) + + cc = 1.0 - pnumerator / pdenom + return ConstraintResult(cc, pdenom * (1.0 - cc), pdenom * cc) + + +@ConstraintManager.register_constraint(5, "/m3", "<=") +def constraint_equation_5(): + """Equation for density upper limit + author: P B Lloyd, CCFE, Culham Science Centre + + fdene: f-value for density limit + dene: electron density (/m3) + dnelimt: density limit (/m3) + dnla: line averaged electron density (m-3) + + i_density_limit: + - 1 old ASDEX; + - 2 Borrass model for ITER (I); + - 3 Borrass model for ITER (II); + - 4 JET edge radiation; + - 5 JET simplified; + - 6 Hugill-Murakami Mq limit; + - 7 Greenwald limit + """ + # Apply Greenwald limit to line-averaged density + if fortran.physics_variables.i_density_limit == 7: + return ConstraintResult( + fortran.physics_variables.dnla / fortran.physics_variables.dnelimt + - 1.0 * fortran.constraint_variables.fdene, + fortran.constraint_variables.fdene * fortran.physics_variables.dnelimt, + fortran.constraint_variables.fdene * fortran.physics_variables.dnelimt + - fortran.physics_variables.dnla, + ) + + cc = ( + fortran.physics_variables.dene / fortran.physics_variables.dnelimt + - 1.0 * fortran.constraint_variables.fdene + ) + return ConstraintResult( + cc, + fortran.physics_variables.dnelimt * (1.0 - cc), + fortran.physics_variables.dene * cc, + ) + + +@ConstraintManager.register_constraint(6, "", "<=") +def constraint_equation_6(): + """Equation for epsilon beta-poloidal upper limit + author: P B Lloyd, CCFE, Culham Science Centre + + fbeta_poloidal_eps: f-value for epsilon beta-poloidal + beta_poloidal_eps_max: maximum (eps*beta_poloidal) + eps: inverse aspect ratio + beta_poloidal: poloidal beta + """ + cc = ( + (fortran.physics_variables.eps * fortran.physics_variables.beta_poloidal) + / fortran.physics_variables.beta_poloidal_eps_max + - 1.0 * fortran.constraint_variables.fbeta_poloidal_eps + ) + return ConstraintResult( + cc, + fortran.physics_variables.beta_poloidal_eps_max * (1.0 - cc), + (fortran.physics_variables.eps * fortran.physics_variables.beta_poloidal) * cc, + ) + + +@ConstraintManager.register_constraint(7, "/m3", "=") +def constraint_equation_7(): + """Equation for hot beam ion density + + i_plasma_ignited: switch for ignition assumption: + - 0 do not assume plasma ignition + - 1 assume ignited (but include auxiliary power in costs) + O + bviously, i_plasma_ignited must be zero if current drive is required. + If i_plasma_ignited=1, any auxiliary power is assumed to be used only + during plasma start-up, and is excluded from all steady-state + power balance calculations. + beam_density_out: hot beam ion density from calculation (/m3) + nd_beam_ions: hot beam ion density, variable (/m3) + """ + if fortran.physics_variables.i_plasma_ignited == 1: + raise ProcessValueError( + "Do not use constraint equation 7 if i_plasma_ignited=1" + ) + + cc = ( + 1.0 + - fortran.physics_variables.beam_density_out + / fortran.physics_variables.nd_beam_ions + ) + return ConstraintResult( + cc, + fortran.physics_variables.nd_beam_ions * (1.0 - cc), + fortran.physics_variables.nd_beam_ions * cc, + ) + + +@ConstraintManager.register_constraint(8, "MW/m2", "<=") +def constraint_equation_8(): + """Equation for neutron wall load upper limit + + fwalld: f-value for maximum wall load + walalw: allowable wall-load (MW/m2) + pflux_fw_neutron_mw: average neutron wall load (MW/m2) + """ + return ConstraintResult( + ( + fortran.physics_variables.pflux_fw_neutron_mw + / fortran.constraint_variables.walalw + - 1.0 * fortran.constraint_variables.fwalld + ), + fortran.constraint_variables.fwalld * fortran.constraint_variables.walalw, + fortran.constraint_variables.fwalld * fortran.constraint_variables.walalw + - fortran.physics_variables.pflux_fw_neutron_mw, + ) + + +@ConstraintManager.register_constraint(9, "MW", "<=") +def constraint_equation_9(): + """Equation for fusion power upper limit + + fp_fusion_total_max_mw: f-value for maximum fusion power + p_fusion_total_max_mw: maximum fusion power (MW) + p_fusion_total_mw: fusion power (MW) + """ + cc = ( + fortran.physics_variables.p_fusion_total_mw + / fortran.constraint_variables.p_fusion_total_max_mw + - 1.0 * fortran.constraint_variables.fp_fusion_total_max_mw + ) + return ConstraintResult( + cc, + fortran.constraint_variables.p_fusion_total_max_mw * (1.0 - cc), + fortran.physics_variables.p_fusion_total_mw * cc, + ) + + +@ConstraintManager.register_constraint(11, "m", "=") +def constraint_equation_11(): + """Equation for radial build + author: P B Lloyd, CCFE, Culham Science Centre + + rbld: sum of thicknesses to the major radius (m) + rmajor: plasma major radius (m) + """ + cc = 1.0 - fortran.build_variables.rbld / fortran.physics_variables.rmajor + return ConstraintResult( + cc, + fortran.physics_variables.rmajor * (1.0 - cc), + fortran.physics_variables.rmajor * cc, + ) + + +@ConstraintManager.register_constraint(12, "V.sec", ">=") +def constraint_equation_12(): + """Equation for volt-second capability lower limit + author: P B Lloyd, CCFE, Culham Science Centre + + vs_plasma_total_required: total V-s needed (Wb) + vs_plasma_total_required (lower limit) is positive; vs_cs_pf_total_pulse (available) is negative + fvs: f-value for flux-swing (V-s) requirement (STEADY STATE) + vs_cs_pf_total_pulse: total flux swing for pulse (Wb) + """ + # vs_cs_pf_total_pulse is negative, requires sign change + cc = ( + 1.0 + - fortran.constraint_variables.fvs + * (-fortran.pfcoil_variables.vs_cs_pf_total_pulse) + / fortran.physics_variables.vs_plasma_total_required + ) + + return ConstraintResult( + cc, + fortran.pfcoil_variables.vs_plasma_total_required * (1.0 - cc), + fortran.pfcoil_variables.vs_plasma_total_required * cc, + ) + + +@ConstraintManager.register_constraint(13, "sec", ">=") +def constraint_equation_13(): + """Equation for burn time lower limit + + author: P B Lloyd, CCFE, Culham Science Centre + + ft_burn: f-value for minimum burn time + t_burn: burn time (s) (calculated if i_pulsed_plant=1) + t_burn_min: minimum burn time (s) + """ + return ConstraintResult( + 1.0 + - fortran.constraint_variables.ft_burn + * fortran.times_variables.t_burn + / fortran.constraint_variables.t_burn_min, + fortran.constraint_variables.t_burn_min / fortran.constraint_variables.ft_burn, + fortran.constraint_variables.t_burn_min / fortran.constraint_variables.ft_burn + - fortran.times_variables.t_burn, + ) + + +@ConstraintManager.register_constraint(15, "MW", ">=") +def constraint_equation_15(): + """Equation for L-H power threshold limit + author: P B Lloyd, CCFE, Culham Science Centre + + fl_h_threshold: f-value for L-H power threshold + p_l_h_threshold_mw: L-H mode power threshold (MW) + p_plasma_separatrix_mw: power to conducted to the divertor region (MW) + """ + return ConstraintResult( + 1.0 + - fortran.constraint_variables.fl_h_threshold + * fortran.physics_variables.p_plasma_separatrix_mw + / fortran.physics_variables.p_l_h_threshold_mw, + fortran.physics_variables.p_l_h_threshold_mw, + fortran.physics_variables.p_l_h_threshold_mw + - fortran.physics_variables.p_plasma_separatrix_mw + / fortran.constraint_variables.fl_h_threshold, + ) + + +@ConstraintManager.register_constraint(16, "MW", ">=") +def constraint_equation_16(): + """Equation for net electric power lower limit + author: P B Lloyd, CCFE, Culham Science Centre + + fpnetel: f-value for net electric power + p_plant_electric_net_mw: net electric power (MW) + pnetelin: required net electric power (MW) + """ + return ConstraintResult( + 1.0 + - fortran.constraint_variables.fpnetel + * fortran.heat_transport_variables.p_plant_electric_net_mw + / fortran.constraint_variables.pnetelin, + fortran.constraint_variables.pnetelin, + fortran.heat_transport_variables.p_plant_electric_net_mw + - fortran.constraint_variables.pnetelin / fortran.constraint_variables.fpnetel, + ) + + +@ConstraintManager.register_constraint(14, "", "=") +def constraint_equation_14(): + """Equation to fix number of NBI decay lengths to plasma centre + author: P B Lloyd, CCFE, Culham Science Centre + + n_beam_decay_lengths_core: neutral beam e-decay lengths to plasma centre + tbeamin: permitted neutral beam e-decay lengths to plasma centre + """ + cc = ( + 1.0 + - fortran.current_drive_variables.n_beam_decay_lengths_core + / fortran.current_drive_variables.tbeamin + ) + return ConstraintResult( + cc, + fortran.current_drive_variables.tbeamin * (1.0 - cc), + fortran.current_drive_variables.tbeamin * cc, + ) + + +@ConstraintManager.register_constraint(17, "MW/m3", "<=") +def constraint_equation_17(): + """Equation for radiation power upper limit + author: P B Lloyd, CCFE, Culham Science Centre + + f_alpha_plasma: fraction of alpha power deposited in plasma + p_hcd_injected_total_mw: total auxiliary injected power (MW) + vol_plasma: plasma volume (m3) + pden_alpha_total_mw: alpha power per volume (MW/m3) + pden_non_alpha_charged_mw: non-alpha charged particle fusion power per volume (MW/m3) + pden_plasma_ohmic_mw: ohmic heating power per volume (MW/m3) + fradpwr: f-value for core radiation power limit + pden_plasma_rad_mw: total radiation power per volume (MW/m3) + """ + # Maximum possible power/vol_plasma that can be radiated (local) + pradmaxpv = ( + fortran.current_drive_variables.p_hcd_injected_total_mw + / fortran.physics_variables.vol_plasma + + fortran.physics_variables.pden_alpha_total_mw + * fortran.physics_variables.f_alpha_plasma + + fortran.physics_variables.pden_non_alpha_charged_mw + + fortran.physics_variables.pden_plasma_ohmic_mw + ) + + cc = ( + fortran.physics_variables.pden_plasma_rad_mw / pradmaxpv + - 1.0 * fortran.constraint_variables.fradpwr + ) + return ConstraintResult( + cc, pradmaxpv * (1.0 - cc), fortran.physics_variables.pden_plasma_rad_mw * cc + ) + + +@ConstraintManager.register_constraint(18, "MW/m2", "<=") +def constraint_equation_18(): + """Equation for divertor heat load upper limit + author: P B Lloyd, CCFE, Culham Science Centre + + fpflux_div_heat_load_mw: f-value for divertor heat load + pflux_div_heat_load_max_mw: heat load limit (MW/m2) + pflux_div_heat_load_mw: divertor heat load (MW/m2) + """ + cc = ( + fortran.divertor_variables.pflux_div_heat_load_mw + / fortran.divertor_variables.pflux_div_heat_load_max_mw + - 1.0 * fortran.constraint_variables.fpflux_div_heat_load_mw + ) + return ConstraintResult( + cc, + fortran.divertor_variables.pflux_div_heat_load_max_mw * (1.0 - cc), + fortran.divertor_variables.pflux_div_heat_load_mw * cc, + ) + + +@ConstraintManager.register_constraint(19, "MVA", "<=") +def constraint_equation_19(): + """Equation for MVA (power) upper limit: resistive TF coil set + author: P B Lloyd, CCFE, Culham Science Centre + + p_cp_resistive_mw: peak resistive TF coil inboard leg power (total) (MW) + p_tf_leg_resistive_mw: TF coil outboard leg resistive power (total) (MW) + fmva: f-value for maximum MVA + mvalim: MVA limit for resistive TF coil set (total) (MW) + """ + totmva = ( + fortran.tfcoil_variables.p_cp_resistive_mw + + fortran.tfcoil_variables.p_tf_leg_resistive_mw + ) + + cc = ( + totmva / fortran.constraint_variables.mvalim + - 1.0 * fortran.constraint_variables.fmva + ) + return ConstraintManager( + cc, fortran.constraint_variables.mvalim * (1.0 - cc), totmva * cc + ) + + +@ConstraintManager.register_constraint(20, "m", "<=") +def constraint_equation_20(): + """Equation for neutral beam tangency radius upper limit + author: P B Lloyd, CCFE, Culham Science Centre + + fportsz: f-value for neutral beam tangency radius limit + rtanmax: maximum tangency radius for centreline of beam (m) + rtanbeam: neutral beam centreline tangency radius (m) + """ + cc = ( + fortran.current_drive_variables.rtanbeam + / fortran.current_drive_variables.rtanmax + - 1.0 * fortran.constraint_variables.fportsz + ) + return ConstraintResult( + cc, + fortran.current_drive_variables.rtanmax * (1.0 - cc), + fortran.current_drive_variables.rtanbeam * cc, + ) + + +@ConstraintManager.register_constraint(21, "", ">=") +def constraint_equation_21(): + """Equation for minor radius lower limit + author: P B Lloyd, CCFE, Culham Science Centre + + frminor: f-value for minor radius limit + rminor: plasma minor radius (m) + aplasmin: minimum minor radius (m) + """ + cc = ( + 1.0 + - fortran.constraint_variables.frminor + * fortran.physics_variables.rminor + / fortran.build_variables.aplasmin + ) + return ConstraintResult( + cc, + fortran.build_variables.aplasmin * (1.0 - cc), + fortran.build_variables.aplasmin * cc, + ) + + +@ConstraintManager.register_constraint(23, "m", "<=") +def constraint_equation_23(): + """Equation for conducting shell radius / rminor upper limit + author: P B Lloyd, CCFE, Culham Science Centre + + rminor: plasma minor radius (m) + dr_fw_plasma_gap_outboard: gap between plasma and first wall, outboard side (m) + dr_fw_outboard: outboard first wall thickness, initial estimate (m) + dr_blkt_outboard: outboard blanket thickness (m) + fr_conducting_wall: f-value for conducting wall radius / rminor limit + f_r_conducting_wall: maximum ratio of conducting wall distance to plasma minor radius for vertical stability + """ + # conducting shell radius (m) + rcw = ( + fortran.physics_variables.rminor + + fortran.build_variables.dr_fw_plasma_gap_outboard + + fortran.build_variables.dr_fw_outboard + + fortran.build_variables.dr_blkt_outboard + ) + + cc = ( + rcw + / ( + fortran.physics_variables.f_r_conducting_wall + * fortran.physics_variables.rminor + ) + - 1.0 * fortran.constraint_variables.fr_conducting_wall + ) + return ConstraintManager( + cc, + fortran.physics_variables.f_r_conducting_wall + * fortran.physics_variables.rminor + * (1.0 - cc), + rcw * cc, + ) + + +@ConstraintManager.register_constraint(24, "", "<=") +def constraint_equation_24(): + """Equation for beta upper limit + author: P B Lloyd, CCFE, Culham Science Centre + + i_beta_component: switch for beta limit scaling (constraint equation 24): + - 0 apply limit to total beta; + - 1 apply limit to thermal beta; + - 2 apply limit to thermal + neutral beam beta + - 3 apply limit to toroidal beta + istell: switch for stellarator option (set viadevice.dat):
+ - 0 use tokamak model;
+ - 1 use stellarator model
+ fbeta_max: f-value for beta limit
+ beta_max: allowable beta
+ beta: total plasma beta (calculated if ipedestal =3)
+ beta_fast_alpha: fast alpha beta component
+ beta_beam: neutral beam beta component
+ bt: toroidal field
+ btot: total field
+ """
+ # Include all beta components: relevant for both tokamaks and stellarators
+ if (
+ fortran.physics_variables.i_beta_component == 0
+ or fortran.stellarator_variables.istell != 0
+ ):
+ cc = (
+ fortran.physics_variables.beta / fortran.physics_variables.beta_max
+ - 1.0 * fortran.constraint_variables.fbeta_max
+ )
+ con = fortran.physics_variables.beta_max
+ err = (
+ fortran.physics_variables.beta_max
+ - fortran.physics_variables.beta / fortran.constraint_variables.fbeta_max
+ )
+ # Here, the beta limit applies to only the thermal component, not the fast alpha or neutral beam parts
+ elif fortran.physics_variables.i_beta_component == 1:
+ cc = (
+ (
+ fortran.physics_variables.beta
+ - fortran.physics_variables.beta_fast_alpha
+ - fortran.physics_variables.beta_beam
+ )
+ / fortran.physics_variables.beta_max
+ - 1.0 * fortran.constraint_variables.fbeta_max
+ )
+ con = fortran.physics_variables.beta_max
+ err = (
+ fortran.physics_variables.beta_max
+ - (
+ fortran.physics_variables.beta
+ - fortran.physics_variables.beta_fast_alpha
+ - fortran.physics_variables.beta_beam
+ )
+ / fortran.constraint_variables.fbeta_max
+ )
+ # Beta limit applies to thermal + neutral beam: components of the total beta, i.e. excludes alphas
+ elif fortran.physics_variables.i_beta_component == 2:
+ cc = (
+ (fortran.physics_variables.beta - fortran.physics_variables.beta_fast_alpha)
+ / fortran.physics_variables.beta_max
+ - 1.0 * fortran.constraint_variables.fbeta_max
+ )
+ con = fortran.physics_variables.beta_max * (1.0 - cc)
+ err = (
+ fortran.physics_variables.beta - fortran.physics_variables.beta_fast_alpha
+ ) * cc
+ # Beta limit applies to toroidal beta
+ elif fortran.physics_variables.i_beta_component == 3:
+ cc = (
+ (
+ fortran.physics_variables.beta
+ * (fortran.physics_variables.btot / fortran.physics_variables.bt) ** 2
+ )
+ / fortran.physics_variables.beta_max
+ - 1.0 * fortran.constraint_variables.fbeta_max
+ )
+ con = fortran.physics_variables.beta_max
+ err = (
+ fortran.physics_variables.beta_max
+ - (
+ fortran.physics_variables.beta
+ * (fortran.physics_variables.btot / fortran.physics_variables.bt) ** 2
+ )
+ / fortran.constraint_variables.fbeta_max
+ )
+
+ return ConstraintResult(cc, con, err)
+
+
+@ConstraintManager.register_constraint(25, "T", "<=")
+def constraint_equation_25():
+ """Equation for peak toroidal field upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fpeakb: f-value for maximum toroidal field
+ bmxlim: maximum peak toroidal field (T)
+ b_tf_inboard_peak: mean peak field at TF coil (T)
+ """
+ cc = (
+ fortran.tfcoil_variables.b_tf_inboard_peak / fortran.constraint_variables.bmxlim
+ - 1.0 * fortran.constraint_variables.fpeakb
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.bmxlim * (1.0 - cc),
+ fortran.tfcoil_variables.b_tf_inboard_peak * cc,
+ )
+
+
+@ConstraintManager.register_constraint(26, "A/m2", "<=")
+def constraint_equation_26():
+ """Equation for Central Solenoid current density upper limit at EOF
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fjohcreal: f-value for central solenoid current at end-of-flattop
+ j_cs_critical_flat_top_end: allowable central solenoid current density at end of flat-top (A/m2)
+ j_cs_flat_top_end: central solenoid overall current density at end of flat-top (A/m2)
+ """
+ return ConstraintResult(
+ fortran.pfcoil_variables.j_cs_flat_top_end
+ / fortran.pfcoil_variables.j_cs_critical_flat_top_end
+ - 1.0 * fortran.constraint_variables.fjohc,
+ fortran.pfcoil_variables.j_cs_critical_flat_top_end,
+ fortran.pfcoil_variables.j_cs_critical_flat_top_end
+ - fortran.pfcoil_variables.j_cs_flat_top_end
+ / fortran.constraint_variables.fjohc,
+ )
+
+
+@ConstraintManager.register_constraint(27, "A/m2", "<=")
+def constraint_equation_27():
+ """Equation for Central Solenoid current density upper limit at BOP
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fjohc0: f-value for central solenoid current at beginning of pulse
+ j_cs_critical_pulse_start: allowable central solenoid current density at beginning of pulse (A/m2)
+ j_cs_pulse_start: central solenoid overall current density at beginning of pulse (A/m2)
+ """
+ return ConstraintResult(
+ fortran.pfcoil_variables.j_cs_pulse_start
+ / fortran.pfcoil_variables.j_cs_critical_pulse_start
+ - 1.0 * fortran.constraint_variables.fjohc0,
+ fortran.pfcoil_variables.j_cs_critical_pulse_start,
+ fortran.pfcoil_variables.j_cs_critical_pulse_start
+ - fortran.pfcoil_variables.j_cs_pulse_start
+ / fortran.constraint_variables.fjohc0,
+ )
+
+
+@ConstraintManager.register_constraint(28, "", ">=")
+def constraint_equation_28():
+ """Equation for fusion gain (big Q) lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fqval: pf-value for Q
+ bigq: Fusion gain; P_fusion / (P_injection + P_ohmic)
+ bigqmin: minimum fusion gain Q
+ i_plasma_ignited : input integer : switch for ignition assumption:
+ - 0 do not assume plasma ignition;
+ - 1 assume ignited (but include auxiliary power in costs)
+ Obviously, ignite must be zero if current drive is required.
+ If i_plasma_ignited=1, any auxiliary power is assumed to be used only
+ during plasma start-up, and is excluded from all steady-state
+ power balance calculations.
+ """
+ if fortran.physics_variables.i_plasma_ignited != 0:
+ raise ProcessValueError("Do not use constraint 28 if i_plasma_ignited=1")
+
+ cc = (
+ 1.0
+ - fortran.constraint_variables.fqval
+ * fortran.current_drive_variables.bigq
+ / fortran.constraint_variables.bigqmin
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.bigqmin * (1.0 - cc),
+ fortran.constraint_variables.bigqmin * cc,
+ )
+
+
+@ConstraintManager.register_constraint(29, "m", "=")
+def constraint_equation_29():
+ """Equation for inboard major radius: This is a consistency equation
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ rmajor: plasma major radius (m) (iteration variable 3)
+ rminor: plasma minor radius (m)
+ rinboard: plasma inboard radius (m)
+ """
+ cc = (
+ 1.0
+ - (fortran.physics_variables.rmajor - fortran.physics_variables.rminor)
+ / fortran.build_variables.rinboard
+ )
+ return ConstraintResult(
+ cc,
+ fortran.build_variables.rinboard * (1.0 - cc),
+ fortran.build_variables.rinboard * cc,
+ )
+
+
+@ConstraintManager.register_constraint(30, "MW", "<=")
+def constraint_equation_30():
+ """Equation for injection power upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ p_hcd_injected_total_mw: total auxiliary injected power (MW)
+ fpinj: f-value for injection power
+ p_hcd_injected_max: Maximum allowable value for injected power (MW)
+ """
+ return ConstraintResult(
+ fortran.current_drive_variables.p_hcd_injected_total_mw
+ / fortran.current_drive_variables.p_hcd_injected_max
+ - 1.0 * fortran.constraint_variables.fpinj,
+ fortran.current_drive_variables.p_hcd_injected_max,
+ fortran.current_drive_variables.p_hcd_injected_max
+ - fortran.current_drive_variables.p_hcd_injected_total_mw
+ / fortran.constraint_variables.fpinj,
+ )
+
+
+@ConstraintManager.register_constraint(31, "Pa", "<=")
+def constraint_equation_31():
+ """Equation for TF coil case stress upper limit (SCTF)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fstrcase: f-value for TF coil case stress
+ sig_tf_case_max: Allowable maximum shear stress in TF coil case (Tresca criterion) (Pa)
+ sig_tf_case: Constrained stress in TF coil case (Pa)
+ """
+ return ConstraintResult(
+ fortran.tfcoil_variables.sig_tf_case / fortran.tfcoil_variables.sig_tf_case_max
+ - 1.0 * fortran.constraint_variables.fstrcase,
+ fortran.tfcoil_variables.sig_tf_case_max,
+ fortran.tfcoil_variables.sig_tf_case_max
+ - fortran.tfcoil_variables.sig_tf_case / fortran.constraint_variables.fstrcase,
+ )
+
+
+@ConstraintManager.register_constraint(32, "Pa", "<=")
+def constraint_equation_32():
+ """Equation for TF coil conduit stress upper limit (SCTF)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fstrcond: f-value for TF coil conduit stress
+ sig_tf_wp_max: Allowable maximum shear stress in TF coil conduit (Tresca criterion) (Pa)
+ sig_tf_wp: Constrained stress in TF conductor conduit (Pa)
+ """
+ return ConstraintResult(
+ fortran.tfcoil_variables.sig_tf_wp / fortran.tfcoil_variables.sig_tf_wp_max
+ - 1.0 * fortran.constraint_variables.fstrcond,
+ fortran.tfcoil_variables.sig_tf_wp_max,
+ fortran.tfcoil_variables.sig_tf_wp_max
+ - fortran.tfcoil_variables.sig_tf_wp / fortran.constraint_variables.fstrcond,
+ )
+
+
+@ConstraintManager.register_constraint(33, "A/m2", "<=")
+def constraint_equation_33():
+ """Equation for TF coil operating/critical J upper limit (SCTF)
+ author: P B Lloyd, CCFE, Culham Science Centre
+ args : output structure : residual error; constraint value;
+
+ fiooic: f-value for TF coil operating current / critical
+ jwdgcrt: critical current density for winding pack (A/m2)
+ j_tf_wp: winding pack current density (A/m2)
+ """
+ if fortran.constraint_variables.fiooic > 0.7:
+ fortran.error_handling.report_error(285)
+
+ cc = (
+ fortran.tfcoil_variables.j_tf_wp / fortran.tfcoil_variables.jwdgcrt
+ - 1.0 * fortran.constraint_variables.fiooic
+ )
+ return ConstraintResult(
+ cc,
+ fortran.tfcoil_variables.jwdgcrt * (1.0 - cc),
+ fortran.tfcoil_variables.j_tf_wp * cc,
+ )
+
+
+@ConstraintManager.register_constraint(34, "V", "<=")
+def constraint_equation_34():
+ """Equation for TF coil dump voltage upper limit (SCTF)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fvdump: f-value for dump voltage
+ vdalw: max voltage across TF coil during quench (kV)
+ vtfskv: voltage across a TF coil during quench (kV)
+ """
+ return ConstraintResult(
+ fortran.tfcoil_variables.vtfskv / fortran.tfcoil_variables.vdalw
+ - 1.0 * fortran.constraint_variables.fvdump,
+ fortran.tfcoil_variables.vdalw,
+ fortran.tfcoil_variables.vdalw - fortran.tfcoil_variables.vtfskv,
+ )
+
+
+@ConstraintManager.register_constraint(35, "A/m2", "<=")
+def constraint_equation_35():
+ """Equation for TF coil J_wp/J_prot upper limit (SCTF)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fjprot: f-value for TF coil winding pack current density
+ jwdgpro: allowable TF coil winding pack current density, for dump temperature
+ rise protection (A/m2)
+ j_tf_wp: winding pack current density (A/m2)
+ """
+ return ConstraintResult(
+ fortran.tfcoil_variables.j_tf_wp / fortran.tfcoil_variables.jwdgpro
+ - 1.0 * fortran.constraint_variables.fjprot,
+ fortran.tfcoil_variables.jwdgpro,
+ fortran.tfcoil_variables.j_tf_wp - fortran.tfcoil_variables.jwdgpro,
+ )
+
+
+@ConstraintManager.register_constraint(36, "K", ">=")
+def constraint_equation_36():
+ """Equation for TF coil s/c temperature margin lower limit (SCTF)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ ftmargtf: f-value for TF coil temperature margin
+ tmargtf: TF coil temperature margin (K)
+ tmargmin_tf: minimum allowable temperature margin : TF coils (K)
+ """
+ return ConstraintResult(
+ 1.0
+ - fortran.constraint_variables.ftmargtf
+ * fortran.tfcoil_variables.tmargtf
+ / fortran.tfcoil_variables.tmargmin_tf,
+ fortran.tfcoil_variables.tmargmin_tf,
+ fortran.tfcoil_variables.tmargmin_tf - fortran.tfcoil_variables.tmargtf,
+ )
+
+
+@ConstraintManager.register_constraint(37, "1E20 A/Wm2", "<=")
+def constraint_equation_37():
+ """Equation for current drive gamma upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fgamcd: f-value for current drive gamma
+ gammax: maximum current drive gamma
+ eta_cd_norm_hcd_primary: normalised current drive efficiency (1.0e20 A/W-m2)
+ """
+ cc = (
+ fortran.current_drive_variables.eta_cd_norm_hcd_primary
+ / fortran.constraint_variables.gammax
+ - 1.0 * fortran.constraint_variables.fgamcd
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.gammax * (1.0 - cc),
+ fortran.current_drive_variables.eta_cd_norm_hcd_primary * cc,
+ )
+
+
+@ConstraintManager.register_constraint(39, "K", "<=")
+def constraint_equation_39():
+ """Equation for first wall temperature upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ ftpeak: f-value for first wall peak temperature
+ temp_fw_max: maximum temperature of first wall material (K) (i_thermal_electric_conversion>1)
+ temp_fw_peak: peak first wall temperature (K)
+ """
+ if fortran.fwbs_variables.temp_fw_peak < 1.0:
+ raise ProcessValueError(
+ "temp_fw_peak = 0 implies i_pulsed_plant=0; do not use constraint 39 if i_pulsed_plant=0"
+ )
+ cc = (
+ fortran.fwbs_variables.temp_fw_peak / fortran.fwbs_variables.temp_fw_max
+ - 1.0 * fortran.constraint_variables.ftpeak
+ )
+ return ConstraintResult(
+ cc,
+ fortran.fwbs_variables.temp_fw_max * (1.0 - cc),
+ fortran.fwbs_variables.temp_fw_peak * cc,
+ )
+
+
+@ConstraintManager.register_constraint(40, "MW", ">=")
+def constraint_equation_40():
+ """Equation for auxiliary power lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fauxmn: f-value for minimum auxiliary power
+ p_hcd_injected_total_mw: total auxiliary injected power (MW)
+ auxmin: minimum auxiliary power (MW)
+ """
+ cc = (
+ 1.0
+ - fortran.constraint_variables.fauxmn
+ * fortran.current_drive_variables.p_hcd_injected_total_mw
+ / fortran.constraint_variables.auxmin
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.auxmin * (1.0 - cc),
+ fortran.constraint_variables.auxmin * cc,
+ )
+
+
+@ConstraintManager.register_constraint(41, "sec", ">=")
+def constraint_equation_41():
+ """Equation for plasma current ramp-up time lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ ft_current_ramp_up: f-value for plasma current ramp-up time
+ t_current_ramp_up: plasma current ramp-up time for current initiation (s)
+ t_current_ramp_up_min: minimum plasma current ramp-up time (s)
+ """
+ cc = (
+ 1.0
+ - fortran.constraint_variables.ft_current_ramp_up
+ * fortran.times_variables.t_current_ramp_up
+ / fortran.constraint_variables.t_current_ramp_up_min
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.t_current_ramp_up_min * (1.0 - cc),
+ fortran.constraint_variables.t_current_ramp_up_min * cc,
+ )
+
+
+@ConstraintManager.register_constraint(42, "sec", ">=")
+def constraint_equation_42():
+ """Equation for cycle time lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ ftcycl: f-value for cycle time
+ t_cycle: full cycle time (s)
+ tcycmn: minimum cycle time (s)
+ """
+ if fortran.constraint_variables.tcycmn < 1.0:
+ raise ProcessValueError(
+ "tcycmn = 0 implies that i_pulsed_plant=0; do not use constraint 42 if i_pulsed_plant=0"
+ )
+
+ cc = (
+ 1.0
+ - fortran.constraint_variables.ftcycl
+ * fortran.times_variables.t_cycle
+ / fortran.constraint_variables.tcycmn
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.tcycmn * (1.0 - cc),
+ fortran.constraint_variables.tcycmn * cc,
+ )
+
+
+@ConstraintManager.register_constraint(43, "deg C", "=")
+def constraint_equation_43():
+ """Equation for average centrepost temperature: This is a consistency equation (TART)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ temp_cp_average: average temp of TF coil inboard leg conductor (C)e
+ tcpav2: centrepost average temperature (C) (for consistency)
+ itart: switch for spherical tokamak (ST) models:
+ - 0 use conventional aspect ratio models;
+ - 1 use spherical tokamak models
+ """
+ if fortran.physics_variables.itart == 0:
+ raise ProcessValueError("Do not use constraint 43 if itart=0")
+
+ if fortran.tfcoil_variables.i_tf_sup == 0:
+ temp_cp_average = fortran.tfcoil_variables.temp_cp_average - 273.15
+ tcpav2 = fortran.tfcoil_variables.tcpav2 - 273.15
+ else:
+ temp_cp_average = fortran.tfcoil_variables.temp_cp_average
+ tcpav2 = fortran.tfcoil_variables.tcpav2
+
+ cc = 1.0 - temp_cp_average / tcpav2
+
+ return ConstraintResult(cc, tcpav2 * (1.0 - cc), tcpav2 * cc)
+
+
+@ConstraintManager.register_constraint(44, "deg C", "<=")
+def constraint_equation_44():
+ """Equation for centrepost temperature upper limit (TART)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fptemp: f-value for peak centrepost temperature
+ ptempalw: maximum peak centrepost temperature (K)
+ tcpmax: peak centrepost temperature (K)
+ itart: switch for spherical tokamak (ST) models:
+ - 0: use conventional aspect ratio models;
+ - 1: use spherical tokamak models
+ """
+ if fortran.physics_variables.itart == 0:
+ raise ProcessValueError("Do not use constraint 44 if itart=0")
+
+ if fortran.tfcoil_variables.i_tf_sup == 0: # ! Copper case
+ ptempalw = fortran.tfcoil_variables.ptempalw - 273.15
+ tcpmax = fortran.tfcoil_variables.tcpmax - 273.15
+ else:
+ ptempalw = fortran.tfcoil_variables.ptempalw
+ tcpmax = fortran.tfcoil_variables.tcpmax
+
+ cc = tcpmax / ptempalw - 1.0 * fortran.constraint_variables.fptemp
+ return ConstraintResult(cc, ptempalw * (1.0 - cc), tcpmax * cc)
+
+
+@ConstraintManager.register_constraint(45, "", ">=")
+def constraint_manager_45():
+ """Equation for edge safety factor lower limit (TART)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fq: f-value for edge safety factor
+ q95 : safety factor 'near' plasma edge
+ (unless i_plasma_current = 2 (ST current scaling), in which case q = mean edge safety factor qbar)
+ q95_min: lower limit for edge safety factor
+ itart : input integer : switch for spherical tokamak (ST) models:
+ - 0 use conventional aspect ratio models;
+ - 1 use spherical tokamak models"""
+ if fortran.physics_variables.itart == 0:
+ raise ProcessValueError("Do not use constraint 45 if itart=0")
+
+ cc = (
+ 1.0
+ - fortran.constraint_variables.fq
+ * fortran.physics_variables.q95
+ / fortran.physics_variables.q95_min
+ )
+ return ConstraintResult(
+ cc,
+ fortran.physics_variables.q95_min * (1.0 - cc),
+ fortran.physics_variables.q95_min * cc,
+ )
+
+
+@ConstraintManager.register_constraint(46, "", "<=")
+def constraint_equation_46():
+ """Equation for Ip/Irod upper limit (TART)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ eps: inverse aspect ratio
+ fipir: f-value for Ip/Irod upper limit
+ c_tf_total: total (summed) current in TF coils (A)
+ plasma_current: plasma current (A)
+ itart: switch for spherical tokamak (ST) models:
+ - 0: use conventional aspect ratio models;
+ - 1: use spherical tokamak models
+ """
+ if fortran.physics_variables.itart == 0:
+ raise ProcessValueError("Do not use constraint 46 if itart=0")
+
+ # maximum ratio of plasma current to centrepost current
+ cratmx = 1.0 + 4.91 * (fortran.physics_variables.eps - 0.62)
+ cc = (
+ fortran.physics_variables.plasma_current / fortran.tfcoil_variables.c_tf_total
+ ) / cratmx - 1.0 * fortran.constraint_variables.fipir
+
+ return ConstraintResult(
+ cc,
+ cratmx * (1.0 - cc),
+ fortran.physics_variables.plasma_current
+ / fortran.tfcoil_variables.c_tf_total
+ * cc,
+ )
+
+
+@ConstraintManager.register_constraint(48, "", "<=")
+def constraint_equation_48():
+ """Equation for poloidal beta upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fbeta_poloidal: rf-value for poloidal beta
+ beta_poloidal_max: maximum poloidal beta
+ beta_poloidal: poloidal beta
+ """
+ cc = (
+ fortran.physics_variables.beta_poloidal
+ / fortran.constraint_variables.beta_poloidal_max
+ - 1.0 * fortran.constraint_variables.fbeta_poloidal
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.beta_poloidal_max * (1.0 - cc),
+ fortran.physics_variables.beta_poloidal * cc,
+ )
+
+
+@ConstraintManager.register_constraint(50, "Hz", "<=")
+def constraint_equation_50():
+ """IFE option: Equation for repetition rate upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+ author: S I Muldrew, CCFE, Culham Science Centre
+ """
+ cc = (
+ fortran.ife_variables.reprat / fortran.ife_variables.rrmax
+ - 1.0 * fortran.ife_variables.frrmax
+ )
+ return ConstraintResult(
+ cc, fortran.ife_variables.rrmax * (1.0 - cc), fortran.ife_variables.reprat * cc
+ )
+
+
+@ConstraintManager.register_constraint(51, "V.s", "=")
+def constraint_equation_51():
+ """Equation to enforce startup flux = available startup flux
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ vs_plasma_res_ramp: resistive losses in startup V-s (Wb)
+ vs_plasma_ind_ramp: internal and external plasma inductance V-s (Wb))
+ vs_cs_pf_total_ramp: total flux swing for startup (Wb)
+ """
+ cc = 1.0 - fortran.pfcoil_variables.fvs_cs_pf_total_ramp * abs(
+ (
+ fortran.physics_variables.vs_plasma_res_ramp
+ + fortran.physics_variables.vs_plasma_ind_ramp
+ )
+ / fortran.pfcoil_variables.vs_cs_pf_total_ramp
+ )
+ return ConstraintResult(
+ cc,
+ fortran.pfcoil_variables.vs_cs_pf_total_ramp * (1.0 - cc),
+ fortran.pfcoil_variables.vs_cs_pf_total_ramp * cc,
+ )
+
+
+@ConstraintManager.register_constraint(52, "", ">=")
+def constraint_equation_52():
+ """Equation for tritium breeding ratio lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ ftbr: f-value for minimum tritium breeding ratio
+ tbr: tritium breeding ratio (i_blanket_type=2,3 (KIT HCPB/HCLL))
+ tbrmin: minimum tritium breeding ratio (If i_blanket_type=1, tbrmin=minimum 5-year time-averaged tritium breeding ratio)
+ """
+ cc = (
+ 1.0
+ - fortran.constraint_variables.ftbr
+ * fortran.fwbs_variables.tbr
+ / fortran.constraint_variables.tbrmin
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.tbrmin * (1.0 - cc),
+ fortran.constraint_variables.tbrmin * cc,
+ )
+
+
+@ConstraintManager.register_constraint(53, "neutron/m2", "<=")
+def constraint_equation_53():
+ """Equation for fast neutron fluence on TF coil upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fflutf: f-value for maximum TF coil nuclear heating
+ nflutfmax: max fast neutron fluence on TF coil (n/m2)
+ nflutf: peak fast neutron fluence on TF coil superconductor (n/m2)
+ """
+ cc = (
+ fortran.fwbs_variables.nflutf / fortran.constraint_variables.nflutfmax
+ - 1.0 * fortran.constraint_variables.fflutf
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.nflutfmax * (1.0 - cc),
+ fortran.fwbs_variables.nflutf * cc,
+ )
+
+
+@ConstraintManager.register_constraint(54, "MW/m3", "<=")
+def constraint_equation_54():
+ """Equation for peak TF coil nuclear heating upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fptfnuc: f-value for maximum TF coil nuclear heating
+ ptfnucmax: maximum nuclear heating in TF coil (MW/m3)
+ ptfnucpm3: nuclear heating in the TF coil (MW/m3) (blktmodel>0)
+ """
+ cc = (
+ fortran.fwbs_variables.ptfnucpm3 / fortran.constraint_variables.ptfnucmax
+ - 1.0 * fortran.constraint_variables.fptfnuc
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.ptfnucmax * (1.0 - cc),
+ fortran.fwbs_variables.ptfnucpm3 * cc,
+ )
+
+
+@ConstraintManager.register_constraint(56, "MW/m", "<=")
+def constraint_equation_56():
+ """Equation for power through separatrix / major radius upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fpsepr: f-value for maximum Psep/R limit
+ pseprmax: maximum ratio of power crossing the separatrix to plasma major radius (Psep/R) (MW/m)
+ p_plasma_separatrix_mw: power to be conducted to the divertor region (MW)
+ rmajor: plasma major radius (m)
+ """
+ cc = (
+ (
+ fortran.physics_variables.p_plasma_separatrix_mw
+ / fortran.physics_variables.rmajor
+ )
+ / fortran.constraint_variables.pseprmax
+ - 1.0 * fortran.constraint_variables.fpsepr
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.pseprmax * (1.0 - cc),
+ (
+ fortran.physics_variables.p_plasma_separatrix_mw
+ / fortran.physics_variables.rmajor
+ )
+ * cc,
+ )
+
+
+@ConstraintManager.register_constraint(59, "", "<=")
+def constraint_equation_59():
+ """Equation for neutral beam shine-through fraction upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fnbshinef: f-value for maximum neutral beam shine-through fraction
+ f_p_beam_shine_through_max: maximum neutral beam shine-through fraction
+ f_p_beam_shine_through: neutral beam shine-through fraction
+ """
+ cc = (
+ fortran.current_drive_variables.f_p_beam_shine_through
+ / fortran.constraint_variables.f_p_beam_shine_through_max
+ - 1.0 * fortran.constraint_variables.fnbshinef
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.f_p_beam_shine_through_max * (1.0 - cc),
+ fortran.current_drive_variables.f_p_beam_shine_through * cc,
+ )
+
+
+@ConstraintManager.register_constraint(60, "K", ">=")
+def constraint_equation_60():
+ """Equation for Central Solenoid s/c temperature margin lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ ftmargoh: f-value for central solenoid temperature margin
+ temp_cs_margin: Central solenoid temperature margin (K)
+ tmargmin_cs: Minimum allowable temperature margin : CS (K)
+ """
+ return ConstraintResult(
+ 1.0
+ - fortran.constraint_variables.ftmargoh
+ * fortran.pfcoil_variables.temp_cs_margin
+ / fortran.tfcoil_variables.tmargmin_cs,
+ fortran.tfcoil_variables.tmargmin_cs,
+ fortran.tfcoil_variables.tmargmin_cs - fortran.pfcoil_variables.temp_cs_margin,
+ )
+
+
+@ConstraintManager.register_constraint(61, "", ">=")
+def constraint_equation_61():
+ """Equation for availability lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ favail: F-value for minimum availability
+ cfactr: Total plant availability fraction
+ avail_min: Minimum availability
+ """
+ cc = (
+ 1.0
+ - fortran.cost_variables.favail
+ * fortran.cost_variables.cfactr
+ / fortran.cost_variables.avail_min
+ )
+ return ConstraintResult(
+ cc,
+ fortran.cost_variables.avail_min * (1.0 - cc),
+ fortran.cost_variables.cfactr * cc,
+ )
+
+
+@ConstraintManager.register_constraint(62, "", ">=")
+def constraint_equation_62():
+ """Lower limit on f_alpha_energy_confinement the ratio of alpha particle to energy confinement times
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ falpha_energy_confinement: f-value for lower limit on f_alpha_energy_confinement the ratio of alpha particle to energy confinement
+ t_alpha_confinement: alpha particle confinement time (s)
+ t_energy_confinement: global thermal energy confinement time (sec)
+ f_alpha_energy_confinement_min: Lower limit on f_alpha_energy_confinement the ratio of alpha particle to energy confinement times
+ """
+ cc = (
+ 1.0
+ - fortran.constraint_variables.falpha_energy_confinement
+ * (
+ fortran.physics_variables.t_alpha_confinement
+ / fortran.physics_variables.t_energy_confinement
+ )
+ / fortran.constraint_variables.f_alpha_energy_confinement_min
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.f_alpha_energy_confinement_min,
+ (
+ fortran.physics_variables.t_alpha_confinement
+ / fortran.physics_variables.t_energy_confinement
+ )
+ * cc,
+ )
+
+
+@ConstraintManager.register_constraint(63, "", "<=")
+def constraint_equation_63():
+ """Upper limit on niterpump (vacuum_model = simple)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fniterpump: f-value for constraint that number of pumps < tfno
+ tfno: number of TF coils (default = 50 for stellarators)
+ niterpump: number of high vacuum pumps (real number), each with the throughput
+ """
+ cc = (
+ fortran.vacuum_variables.niterpump / fortran.tfcoil_variables.n_tf_coils
+ - 1.0 * fortran.constraint_variables.fniterpump
+ )
+ return ConstraintResult(
+ cc,
+ fortran.tfcoil_variables.n_tf_coils,
+ fortran.tfcoil_variables.n_tf_coils * cc,
+ )
+
+
+@ConstraintManager.register_constraint(64, "", "<=")
+def constraint_equation_64():
+ """Upper limit on Zeff
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fzeffmax: f-value for maximum zeff
+ zeffmax: maximum value for Zeff
+ zeff: plasma effective charge
+ """
+ cc = (
+ fortran.physics_variables.zeff / fortran.constraint_variables.fzeffmax
+ - 1.0 * fortran.constraint_variables.ffzeffmax
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.fzeffmax,
+ fortran.constraint_variables.fzeffmax * cc,
+ )
+
+
+@ConstraintManager.register_constraint(65, "Pa", "<=")
+def constraint_equation_65():
+ """Upper limit on stress of the vacuum vessel that occurs when the TF coil quenches.
+ author: Timothy Nunn, UKAEA
+
+ fmaxvvstress: f-value for constraint on maximum VV stress
+ max_vv_stress: Maximum permitted stress of the VV (Pa)
+ vv_stress_quench: Stress of the VV (Pa)
+ """
+ cc = (
+ fortran.sctfcoil_module.vv_stress_quench
+ / fortran.tfcoil_variables.max_vv_stress
+ - 1.0 * fortran.constraint_variables.fmaxvvstress
+ )
+ return ConstraintResult(
+ cc,
+ fortran.tfcoil_variables.max_vv_stress,
+ fortran.tfcoil_variables.max_vv_stress * cc,
+ )
+
+
+@ConstraintManager.register_constraint(66, "MW", "<=")
+def constrain_equation_66():
+ """Upper limit on rate of change of energy in poloidal field
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fpoloidalpower: f-value for constraint on rate of change of energy in poloidal field
+ maxpoloidalpower: Maximum permitted absolute rate of change of stored energy in poloidal field (MW)
+ peakpoloidalpower: Peak absolute rate of change of stored energy in poloidal field (MW) (11/01/16)
+ """
+ cc = (
+ fortran.pf_power_variables.peakpoloidalpower
+ / fortran.pf_power_variables.maxpoloidalpower
+ - 1.0 * fortran.constraint_variables.fpoloidalpower
+ )
+ return ConstraintResult(
+ cc,
+ fortran.pf_power_variables.maxpoloidalpower,
+ fortran.pf_power_variables.maxpoloidalpower * cc,
+ )
+
+
+@ConstraintManager.register_constraint(67, "MW/m2", "<=")
+def constraint_equation_67():
+ """Simple upper limit on radiation wall load
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fradwall: f-value for upper limit on radiation wall load
+ pflux_fw_rad_max: Maximum permitted radiation wall load (MW/m^2)
+ pflux_fw_rad_max_mw: Peak radiation wall load (MW/m^2)
+ """
+ cc = (
+ fortran.constraint_variables.pflux_fw_rad_max_mw
+ / fortran.constraint_variables.pflux_fw_rad_max
+ - 1.0 * fortran.constraint_variables.fradwall
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.pflux_fw_rad_max,
+ fortran.constraint_variables.pflux_fw_rad_max * cc,
+ )
+
+
+@ConstraintManager.register_constraint(68, "MWT/m", "<=")
+def constraint_equation_68():
+ """Upper limit on Psep scaling (PsepB/qAR)
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fpsepbqar: f-value for upper limit on psepbqar, maximum Psep*Bt/qAR limit
+ psepbqarmax: maximum permitted value of ratio of Psep*Bt/qAR (MWT/m)
+ p_plasma_separatrix_mw: Power to conducted to the divertor region (MW)
+ bt: toroidal field on axis (T) (iteration variable 2)
+ q95: safety factor q at 95% flux surface
+ aspect: aspect ratio (iteration variable 1)
+ rmajor: plasma major radius (m) (iteration variable 3)
+ i_q95_fixed: Switch that allows for fixing q95 only in this constraint.
+ q95_fixed: fixed safety factor q at 95% flux surface
+ """
+ if fortran.constraint_variables.i_q95_fixed == 1:
+ cc = (
+ (
+ (
+ fortran.physics_variables.p_plasma_separatrix_mw
+ * fortran.physics_variables.bt
+ )
+ / (
+ fortran.constraint_variables.q95_fixed
+ * fortran.physics_variables.aspect
+ * fortran.physics_variables.rmajor
+ )
+ )
+ / fortran.constraint_variables.psepbqarmax
+ - 1.0 * fortran.constraint_variables.fpsepbqar
+ )
+ err = (
+ fortran.physics_variables.p_plasma_separatrix_mw
+ * fortran.physics_variables.bt
+ ) / (
+ fortran.constraint_variables.q95_fixed
+ * fortran.physics_variables.aspect
+ * fortran.physics_variables.rmajor
+ ) - fortran.constraint_variables.psepbqarmax
+ else:
+ cc = (
+ (
+ (
+ fortran.physics_variables.p_plasma_separatrix_mw
+ * fortran.physics_variables.bt
+ )
+ / (
+ fortran.physics_variables.q95
+ * fortran.physics_variables.aspect
+ * fortran.physics_variables.rmajor
+ )
+ )
+ / fortran.constraint_variables.psepbqarmax
+ - 1.0 * fortran.constraint_variables.fpsepbqar
+ )
+ err = (
+ fortran.physics_variables.p_plasma_separatrix_mw
+ * fortran.physics_variables.bt
+ ) / (
+ fortran.physics_variables.q95
+ * fortran.physics_variables.aspect
+ * fortran.physics_variables.rmajor
+ ) - fortran.constraint_variables.psepbqarmax
+
+ return ConstraintResult(cc, fortran.constraint_variables.psepbqarmax, err)
+
+
+@ConstraintManager.register_constraint(72, "Pa", "<=")
+def constraint_equation_72():
+ """Upper limit on central Solenoid Tresca yield stress
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ In the case if the bucked and wedged option ( i_tf_bucking >= 2 ) the constrained
+ stress is the largest the largest stress of the
+ - CS stress at maximum current (conservative as the TF inward pressure is not taken
+ into account)
+ - CS stress at flux swing (no current in CS) from the TF inward pressure
+ This allow to cover the 2 worst stress scenario in the bucked and wedged design
+ Otherwise (free standing TF), the stress limits are only set by the CS stress at max current
+ Reverse the sign so it works as an inequality constraint (tmp_cc > 0)
+ This will have no effect if it is used as an equality constraint because it will be squared.
+
+ foh_stress: f-value for Tresca yield criterion in Central Solenoid
+ alstroh: allowable hoop stress in Central Solenoid structural material (Pa)
+ s_shear_cs_peak: Maximum shear stress coils/central solenoid (Pa)
+ sig_tf_cs_bucked: Maximum shear stress in CS case at flux swing (no current in CS)
+ can be significant for the bucked and weged design
+ i_tf_bucking: switch for TF structure design
+ """
+ # bucked and wedged desing
+ if (
+ fortran.tfcoil_variables.i_tf_bucking >= 2
+ and fortran.build_variables.i_tf_inside_cs == 0
+ ):
+ cc = (
+ max(
+ fortran.pfcoil_variables.s_shear_cs_peak,
+ fortran.tfcoil_variables.sig_tf_cs_bucked,
+ )
+ / fortran.pfcoil_variables.alstroh
+ - 1.0 * fortran.constraint_variables.foh_stress
+ )
+ err = fortran.pfcoil_variables.alstroh - max(
+ fortran.pfcoil_variables.s_shear_cs_peak,
+ fortran.tfcoil_variables.sig_tf_cs_bucked,
+ )
+ # Free standing CS
+ else:
+ cc = (
+ fortran.pfcoil_variables.s_shear_cs_peak / fortran.pfcoil_variables.alstroh
+ - 1.0 * fortran.constraint_variables.foh_stress
+ )
+ err = (
+ fortran.pfcoil_variables.alstroh - fortran.pfcoil_variables.s_shear_cs_peak
+ )
+
+ return ConstraintResult(cc, fortran.pfcoil_variables.alstroh, err)
+
+
+@ConstraintManager.register_constraint(73, "MW", ">=")
+def constraint_equation_73():
+ """Lower limit to ensure separatrix power is greater than the L-H power + auxiliary power
+ Related to constraint 15
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fplhsep: F-value for Psep >= Plh + Paux : for consistency of two values of separatrix power
+ p_l_h_threshold_mw: L-H mode power threshold (MW)
+ p_plasma_separatrix_mw: power to be conducted to the divertor region (MW)
+ p_hcd_injected_total_mw : inout real : total auxiliary injected power (MW)
+ """
+ cc = (
+ 1.0
+ - fortran.physics_variables.fplhsep
+ * fortran.physics_variables.p_plasma_separatrix_mw
+ / (
+ fortran.physics_variables.p_l_h_threshold_mw
+ + fortran.current_drive_variables.p_hcd_injected_total_mw
+ )
+ )
+ return ConstraintResult(
+ cc,
+ fortran.physics_variables.p_plasma_separatrix_mw,
+ fortran.physics_variables.p_plasma_separatrix_mw * cc,
+ )
+
+
+@ConstraintManager.register_constraint(74, "K", "<=")
+def constraint_equation_74():
+ """Upper limit to ensure TF coil quench temperature < tmax_croco
+ ONLY used for croco HTS coil
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fcqt: f-value: TF coil quench temparature remains below tmax_croco
+ croco_quench_temperature: CroCo strand: Actual temp reached during a quench (K)
+ tmax_croco: CroCo strand: maximum permitted temp during a quench (K)
+ """
+ cc = (
+ fortran.tfcoil_variables.croco_quench_temperature
+ / fortran.tfcoil_variables.tmax_croco
+ - 1.0 * fortran.constraint_variables.fcqt
+ )
+ return ConstraintResult(
+ cc,
+ fortran.tfcoil_variables.croco_quench_temperature,
+ fortran.tfcoil_variables.croco_quench_temperature * cc,
+ )
+
+
+@ConstraintManager.register_constraint(75, "A/m2", "<=")
+def constraint_equation_75():
+ """Upper limit to ensure that TF coil current / copper area < Maximum value
+ ONLY used for croco HTS coil
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ copperA_m2: TF coil current / copper area (A/m2)
+ copperA_m2_max: Maximum TF coil current / copper area (A/m2)
+ f_coppera_m2: f-value for TF coil current / copper area < copperA_m2_max
+ """
+ cc = (
+ fortran.rebco_variables.coppera_m2 / fortran.rebco_variables.coppera_m2_max
+ - 1.0 * fortran.rebco_variables.f_coppera_m2
+ )
+ return ConstraintResult(
+ cc, fortran.rebco_variables.coppera_m2, fortran.rebco_variables.coppera_m2 * cc
+ )
+
+
+@ConstraintManager.register_constraint(76, "m-3", "<=")
+def constraint_equation_76():
+ """Upper limit for Eich critical separatrix density model: Added for issue 558
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ Eich critical separatrix density model
+ Added for issue 558 with ref to http://iopscience.iop.org/article/10.1088/1741-4326/aaa340/pdf
+
+ alpha_crit: critical ballooning parameter value
+ nesep_crit: critical electron density at separatrix [m-3]
+ kappa: plasma separatrix elongation (calculated if i_plasma_geometry = 1-5, 7 or 9)
+ triang: plasma separatrix triangularity (calculated if i_plasma_geometry = 1, 3-5 or 7)
+ aspect: aspect ratio (iteration variable 1)
+ p_plasma_separatrix_mw: power to conducted to the divertor region (MW)
+ dlimit(7)array : density limit (/m3) as calculated using various models
+ fnesep: f-value for Eich critical separatrix density
+ """
+ # TODO: why on earth are these variables being set here!? Should they be local?
+ fortran.physics_variables.alpha_crit = (fortran.physics_variables.kappa**1.2) * (
+ 1.0 + 1.5 * fortran.physics_variables.triang
+ )
+ fortran.physics_variables.nesep_crit = (
+ 5.9
+ * fortran.physics_variables.alpha_crit
+ * (fortran.physics_variables.aspect ** (-2.0 / 7.0))
+ * (((1.0 + (fortran.physics_variables.kappa**2.0)) / 2.0) ** (-6.0 / 7.0))
+ * ((fortran.physics_variables.p_plasma_separatrix_mw * 1.0e6) ** (-11.0 / 70.0))
+ * fortran.physics_variables.dlimit[6]
+ )
+
+ cc = (
+ fortran.physics_variables.nesep / fortran.physics_variables.nesep_crit
+ - 1.0 * fortran.constraint_variables.fnesep
+ )
+ return ConstraintResult(
+ cc, fortran.physics_variables.nesep, fortran.physics_variables.nesep * cc
+ )
+
+
+@ConstraintManager.register_constraint(77, "A/turn", "<=")
+def constraint_equation_77():
+ """Equation for maximum TF current per turn upper limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fcpttf: f-value for TF coil current per turn
+ cpttf_max : allowable TF coil current per turn [A/turn]
+ c_tf_turn : TF coil current per turn [A/turn]
+ """
+ cc = (
+ fortran.tfcoil_variables.c_tf_turn / fortran.tfcoil_variables.cpttf_max
+ - 1.0 * fortran.constraint_variables.fcpttf
+ )
+ return ConstraintResult(
+ cc, fortran.tfcoil_variables.cpttf_max, fortran.tfcoil_variables.cpttf_max * cc
+ )
+
+
+@ConstraintManager.register_constraint(78, "", ">=")
+def constraint_equation_78():
+ """Equation for Reinke criterion, divertor impurity fraction lower limit
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ freinke : input : f-value for Reinke criterion (itv 147)
+ fzmin : input : minimum impurity fraction from Reinke model
+ fzactual : input : actual impurity fraction
+ """
+ cc = (
+ 1.0
+ - fortran.constraint_variables.freinke
+ * fortran.reinke_variables.fzactual
+ / fortran.reinke_variables.fzmin
+ )
+ return ConstraintResult(
+ cc,
+ fortran.reinke_variables.fzmin * (1.0 - cc),
+ fortran.reinke_variables.fzmin * cc,
+ )
+
+
+@ConstraintManager.register_constraint(79, "A/turn", "<=")
+def constraint_equation_79():
+ """Equation for maximum CS field
+ author: P B Lloyd, CCFE, Culham Science Centre
+
+ fb_cs_limit_max: F-value for CS mmax field (cons. 79, itvar 149)
+ b_cs_limit_max: Central solenoid max field limit [T]
+ b_cs_peak_pulse_start: maximum field in central solenoid at beginning of pulse (T)
+ b_cs_peak_flat_top_end: maximum field in central solenoid at end of flat-top (EoF) (T)
+ (Note: original code has "b_cs_peak_flat_top_end/b_cs_peak_pulse_start | peak CS field [T]".)
+ """
+ cc = (
+ max(
+ fortran.pfcoil_variables.b_cs_peak_flat_top_end,
+ fortran.pfcoil_variables.b_cs_peak_pulse_start,
+ )
+ / fortran.pfcoil_variables.b_cs_limit_max
+ - 1.0 * fortran.pfcoil_variables.fb_cs_limit_max
+ )
+ return ConstraintResult(
+ cc,
+ fortran.pfcoil_variables.b_cs_limit_max,
+ max(
+ fortran.pfcoil_variables.b_cs_peak_flat_top_end,
+ fortran.pfcoil_variables.b_cs_peak_pulse_start,
+ )
+ * cc,
+ )
+
+
+@ConstraintManager.register_constraint(80, "MW", ">=")
+def constraint_equation_80():
+ """Equation for p_plasma_separatrix_mw lower limit
+ author: J Morris, Culham Science Centre
+ args : output structure : residual error; constraint value; residual error in physical units;
+ output string; units string
+ Lower limit p_plasma_separatrix_mw
+ #=# physics
+ #=#=# fp_plasma_separatrix_min_mw, p_plasma_separatrix_mw
+ Logic change during pre-factoring: err, symbol, units will be assigned only if present.
+ fp_plasma_separatrix_min_mw : input : F-value for lower limit on p_plasma_separatrix_mw (cons. 80, itvar 153)
+ p_plasma_separatrix_min_mw : input : Minimum power crossing separatrix p_plasma_separatrix_mw [MW]
+ p_plasma_separatrix_mw : input : Power crossing separatrix [MW]
+ """
+ cc = (
+ 1.0
+ - fortran.physics_variables.fp_plasma_separatrix_min_mw
+ * fortran.physics_variables.p_plasma_separatrix_mw
+ / fortran.constraint_variables.p_plasma_separatrix_min_mw
+ )
+ return ConstraintResult(
+ cc,
+ fortran.constraint_variables.p_plasma_separatrix_min_mw,
+ fortran.constraint_variables.p_plasma_separatrix_min_mw * cc,
+ )
+
+
+@ConstraintManager.register_constraint(81, "m-3", ">=")
+def constraint_equation_81():
+ """Lower limit to ensure central density is larger that the pedestal one
+ author: S Kahn, Culham Science Centre
+ args : output structure : residual error; constraint value;
+ residual error in physical units; output string; units string
+ Lower limit ne0 > neped
+ !#=# physics
+ !#=#=# ne0, neped
+ Logic change during pre-factoring: err, symbol, units will be
+ assigned only if present.
+ fne0 : input : F-value for constraint on ne0 > neped
+ ne0 : input : Central electron density [m-3]
+ neped : input : Electron density at pedestal [m-3]
+ """
+ cc = (
+ 1.0
+ - fortran.physics_variables.fne0
+ * fortran.physics_variables.ne0
+ / fortran.physics_variables.neped
+ )
+ return ConstraintResult(
+ cc, fortran.physics_variables.fne0, fortran.physics_variables.fne0 * cc
+ )
+
+
+@ConstraintManager.register_constraint(82, "m", ">=")
+def constraint_equation_82():
+ """Equation for toroidal consistency of stellarator build
+ author: J Lion, IPP Greifswald
+
+ ftoroidalgap: f-value for constraint toroidalgap > dx_tf_inboard_out_toroidal
+ toroidalgap: minimal gap between two stellarator coils
+ dx_tf_inboard_out_toroidal: total toroidal width of a tf coil
+ """
+ return ConstraintResult(
+ 1.0
+ - fortran.tfcoil_variables.ftoroidalgap
+ * fortran.tfcoil_variables.toroidalgap
+ / fortran.tfcoil_variables.dx_tf_inboard_out_toroidal,
+ fortran.tfcoil_variables.toroidalgap,
+ fortran.tfcoil_variables.toroidalgap
+ - fortran.tfcoil_variables.dx_tf_inboard_out_toroidal
+ / fortran.tfcoil_variables.ftoroidalgap,
+ )
+
+
+@ConstraintManager.register_constraint(83, "m", ">=")
+def constraint_equation_83():
+ """Equation for radial consistency of stellarator build
+ author: J Lion, IPP Greifswald
+
+ f_avspace: f-value for constraint available_radial_space > required_radial_space
+ available_radial_space: avaible space in radial direction as given by each s.-configuration
+ required_radial_space: required space in radial direction
+ """
+ cc = (
+ 1.0
+ - fortran.build_variables.f_avspace
+ * fortran.build_variables.available_radial_space
+ / fortran.build_variables.required_radial_space
+ )
+ return ConstraintResult(
+ cc,
+ fortran.build_variables.available_radial_space * (1.0 - cc),
+ fortran.build_variables.required_radial_space * cc,
+ )
+
+
+@ConstraintManager.register_constraint(84, "", ">=")
+def constraint_equation_84():
+ """Equation for the lower limit of beta
+ author: J Lion, IPP Greifswald
+
+ fbeta_min: f-value for constraint beta-beta_fast_alpha > beta_min
+ beta_min: Lower limit for beta
+ beta: plasma beta
+ """
+ cc = (
+ 1.0
+ - fortran.constraint_variables.fbeta_min
+ * fortran.physics_variables.beta
+ / fortran.physics_variables.beta_min
+ )
+ return ConstraintResult(
+ cc,
+ fortran.physics_variables.beta_min * (1.0 - cc),
+ fortran.physics_variables.beta * cc,
+ )
+
+
+@ConstraintManager.register_constraint(85, "years", "=")
+def constraint_equation_85():
+ """Equality constraint for the centerpost (CP) lifetime
+ Author : S Kahn
+
+ Depending on the chosen option i_cp_lifetime:
+ - 0 : The CP full power year lifelime is set by the user (cplife_input)
+ - 1 : The CP lifelime is equal to the divertor one
+ - 2 : The CP lifetime is equal to the breeding blankets one
+ - 3 : The CP lifetime is equal to the plant one
+
+ cplife: calculated CP full power year lifetime (years)
+ life_blkt_fpy: calculated first wall/blanket power year lifetime (years)
+ divlife: calculated divertor power year lifetime (years)
+ i_cp_lifetime: switch chosing which plant element the CP
+ the CP lifetime must equate
+ """
+ # The CP lifetime is equal to the the divertor one
+ if fortran.cost_variables.i_cp_lifetime == 0:
+ cc = 1.0 - fortran.cost_variables.cplife / fortran.cost_variables.cplife_input
+
+ elif fortran.cost_variables.i_cp_lifetime == 1:
+ cc = 1.0 - fortran.cost_variables.cplife / fortran.cost_variables.divlife
+
+ # The CP lifetime is equal to the tritium breeding blankets / FW one
+ elif fortran.cost_variables.i_cp_lifetime == 2:
+ cc = 1.0 - fortran.cost_variables.cplife / fortran.fwbs_variables.life_blkt_fpy
+
+ elif fortran.cost_variables.i_cp_lifetime == 3:
+ cc = 1.0 - fortran.cost_variables.cplife / fortran.cost_variables.tlife
+
+ return ConstraintResult(
+ cc,
+ fortran.cost_variables.divlife * (1.0 - cc),
+ fortran.cost_variables.divlife * cc,
+ )
+
+
+@ConstraintManager.register_constraint(86, "m", "<=")
+def constraint_equation_86():
+ """Upper limit on the turn edge length in the TF winding pack
+ Author : S Kahn
+
+ t_turn_tf: TF coil turn edge length including turn insulation [m]
+ f_t_turn_tf: f-value for TF turn edge length constraint
+ t_turn_tf_max: TF turn edge length including turn insulation upper limit [m]
+ """
+ cc = (
+ fortran.tfcoil_variables.t_turn_tf / fortran.tfcoil_variables.t_turn_tf_max
+ - 1.0 * fortran.tfcoil_variables.f_t_turn_tf
+ )
+ return ConstraintResult(
+ cc,
+ fortran.tfcoil_variables.t_turn_tf_max * (1.0 - cc),
+ fortran.tfcoil_variables.t_turn_tf_max * cc,
+ )
+
+
+@ConstraintManager.register_constraint(87, "MW", "<=")
+def constraint_equation_87():
+ """Equation for TF coil cryogenic power upper limit
+ author: S. Kahn, CCFE, Culham Science Centre
+
+ p_cryo_plant_electric_mw: cryogenic plant power (MW)
+ f_crypmw: f-value for maximum cryogenic plant power
+ p_cryo_plant_electric_max_mw: Maximum cryogenic plant power (MW)
+ """
+ cc = (
+ fortran.heat_transport_variables.p_cryo_plant_electric_mw
+ / fortran.heat_transport_variables.p_cryo_plant_electric_max_mw
+ - 1.0 * fortran.heat_transport_variables.f_crypmw
+ )
+ return ConstraintResult(
+ cc,
+ fortran.heat_transport_variables.p_cryo_plant_electric_max_mw * (1.0 - cc),
+ fortran.heat_transport_variables.p_cryo_plant_electric_mw * cc,
+ )
+
+
+@ConstraintManager.register_constraint(88, "", "<=")
+def constraint_equation_88():
+ """Equation for TF coil vertical strain upper limit (absolute value)
+ author: CPS Swanson, PPPL, USA
+
+ fstr_wp: f-value for TF coil strain
+ str_wp_max: Allowable maximum TF coil vertical strain
+ str_wp: Constrained TF coil vertical strain
+ """
+ return ConstraintResult(
+ abs(fortran.tfcoil_variables.str_wp) / fortran.tfcoil_variables.str_wp_max
+ - 1.0 * fortran.constraint_variables.fstr_wp,
+ fortran.tfcoil_variables.str_wp_max,
+ fortran.tfcoil_variables.str_wp_max
+ - abs(fortran.tfcoil_variables.str_wp) / fortran.constraint_variables.fstr_wp,
+ )
+
+
+@ConstraintManager.register_constraint(89, "A/m2", "<=")
+def constraint_equation_89():
+ """Upper limit to ensure that the Central Solenoid [OH] coil current / copper area < Maximum value
+ author: G Turkington, CCFE, Culham Science Centre
+
+ copperaoh_m2: CS coil current at EOF / copper area [A/m2]
+ copperaoh_m2_max: maximum coil current / copper area [A/m2]
+ f_copperaoh_m2: f-value for CS coil current / copper area
+ """
+ cc = (
+ fortran.rebco_variables.copperaoh_m2 / fortran.rebco_variables.copperaoh_m2_max
+ - 1.0 * fortran.rebco_variables.f_copperaoh_m2
+ )
+ return ConstraintResult(
+ cc,
+ fortran.rebco_variables.copperaoh_m2,
+ fortran.rebco_variables.copperaoh_m2 * cc,
+ )
+
+
+@ConstraintManager.register_constraint(90, "", ">=")
+def constraint_equation_90():
+ """Lower limit for CS coil stress load cycles
+ author: A. Pearce, G Turkington CCFE, Culham Science Centre
+
+ fncycle: f-value for constraint n_cycle > n_cycle_min
+ n_cycle: Allowable number of cycles for CS
+ n_cycle_min: Minimum required cycles for CS
+ """
+ if (
+ fortran.cost_variables.ibkt_life == 1
+ and fortran.cs_fatigue_variables.bkt_life_csf == 1
+ ):
+ fortran.cs_fatigue_variables.n_cycle_min = fortran.cost_variables.bktcycles
+
+ cc = (
+ 1.0
+ - fortran.constraint_variables.fncycle
+ * fortran.cs_fatigue_variables.n_cycle
+ / fortran.cs_fatigue_variables.n_cycle_min
+ )
+ return ConstraintResult(
+ cc,
+ fortran.cs_fatigue_variables.n_cycle_min * (1.0 - cc),
+ fortran.cs_fatigue_variables.n_cycle * cc,
+ )
+
+
+@ConstraintManager.register_constraint(91, "MW", ">=")
+def constraint_equation_91():
+ """Lower limit to ensure ECRH te is greater than required te for ignition
+ at lower values for n and B. Or if the design point is ECRH heatable (if i_plasma_ignited==0)
+ stellarators only (but in principle usable also for tokamaks).
+ author: J Lion, IPP Greifswald
+
+ fecrh_ignition: f-value for constraint powerht_local > powerscaling
+ max_gyrotron_frequency: Max. av. gyrotron frequency
+ te0_ecrh_achievable: Max. achievable electron temperature at ignition point
+ """
+ # Achievable ECRH te needs to be larger than needed te for igntion
+ if fortran.physics_variables.i_plasma_ignited == 0:
+ cc = (
+ 1.0
+ - fortran.constraint_variables.fecrh_ignition
+ * (
+ fortran.stellarator_variables.powerht_constraint
+ + fortran.current_drive_variables.p_hcd_primary_extra_heat_mw
+ )
+ / fortran.stellarator_variables.powerscaling_constraint
+ )
+ else:
+ cc = (
+ 1.0
+ - fortran.constraint_variables.fecrh_ignition
+ * fortran.stellarator_variables.powerht_constraint
+ / fortran.stellarator_variables.powerscaling_constraint
+ )
+
+ return ConstraintResult(
+ cc,
+ fortran.stellarator_variables.powerscaling_constraint * (1.0 - cc),
+ fortran.stellarator_variables.powerht_constraint * cc,
+ )
+
+
+@ConstraintManager.register_constraint(92, "", "=")
+def constraint_equation_92():
+ """Equation for checking is D/T ratio is consistent, and sums to 1.
+ author: G Turkington, UKAEA
+
+ f_deuterium: fraction of deuterium ions
+ f_tritium: fraction of tritium ions
+ f_helium3: fraction of helium-3 ions
+ """
+ f_deuterium = 1.0 - (
+ fortran.physics_variables.f_tritium + fortran.physics_variables.f_helium3
+ )
+ cc = 1.0 - (
+ f_deuterium
+ + fortran.physics_variables.f_tritium
+ + fortran.physics_variables.f_helium3
+ )
+
+ return ConstraintResult(cc, 1.0, cc)
+
+
+def constraint_eqns(m: int, ieqn: int):
+ """Evaluates the constraints given the current state of PROCESS.
+
+ :param m: The number of constraints to evaluate
+ :param ieqn: Evaluates the 'ieqn'th constraint equation (index starts at 1)
+ or all equations if <= 0
+ """
+
+ if ieqn > 0:
+ i1 = ieqn - 1
+ i2 = ieqn
+ else:
+ i1 = 0
+ i2 = m
+
+ cc, con, err, symbol, units = [], [], [], [], []
+
+ for i in range(i1, i2):
+ constraint_id = fortran.numerics.icc[i].item()
+ try:
+ constraint = ConstraintManager.get_constraint(constraint_id)
+
+ if constraint is None:
+ tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units = getattr(
+ fortran.constraints, f"constraint_eqn_{constraint_id:03d}"
+ )()
+ else:
+ result = constraint.constraint_equation()
+ tmp_cc, tmp_con, tmp_err = (
+ result.normalised_residual,
+ result.constraint_value,
+ result.constraint_error,
+ )
+ tmp_symbol, tmp_units = constraint.symbol, constraint.units
+
+ except AttributeError as e:
+ error_msg = f"Constraint equation {i + 1} cannot be found"
+ raise ProcessError(error_msg) from e
+
+ if np.isnan(tmp_cc) or np.isinf(tmp_cc) or abs(tmp_cc) > 9.99e99:
+ error_msg = (
+ f"Constraint equation {constraint_id} returned an invalid residual"
+ )
+
+ raise ProcessValueError(error_msg, cc=tmp_cc)
+
+ # Reverse the sign so it works as an inequality constraint (cc(i) > 0)
+ # This will have no effect if it is used as an equality constraint because it will be squared.
+ cc.append(-tmp_cc)
+ con.append(tmp_con)
+ err.append(tmp_err)
+ symbol.append(tmp_symbol)
+ units.append(tmp_units)
+
+ return np.array(cc), np.array(con), np.array(err), symbol, units
+
+
+def init_constraint_variables():
+ """Initialise the constraint variables"""
+ fortran.constraint_variables.auxmin = 0.1
+ fortran.constraint_variables.beta_poloidal_max = 0.19
+ fortran.constraint_variables.bigqmin = 10.0
+ fortran.constraint_variables.bmxlim = 12.0
+ fortran.constraint_variables.fauxmn = 1.0
+ fortran.constraint_variables.fbeta_poloidal_eps = 1.0
+ fortran.constraint_variables.fbeta_poloidal = 1.0
+ fortran.constraint_variables.fbeta_max = 1.0
+ fortran.constraint_variables.fbeta_min = 1.0
+ fortran.constraint_variables.fcpttf = 1.0
+ fortran.constraint_variables.fr_conducting_wall = 1.0
+ fortran.constraint_variables.fdene = 1.0
+ fortran.constraint_variables.fdtmp = 1.0
+ fortran.constraint_variables.fflutf = 1.0
+ fortran.constraint_variables.fp_fusion_total_max_mw = 1.0
+ fortran.constraint_variables.fgamcd = 1.0
+ fortran.constraint_variables.fpflux_div_heat_load_mw = 1.0
+ fortran.constraint_variables.fiooic = 0.5
+ fortran.constraint_variables.fipir = 1.0
+ fortran.constraint_variables.q95_fixed = 3.0
+ fortran.constraint_variables.fjohc = 1.0
+ fortran.constraint_variables.fjohc0 = 1.0
+ fortran.constraint_variables.fjprot = 1.0
+ fortran.constraint_variables.fl_h_threshold = 1.0
+ fortran.constraint_variables.fmva = 1.0
+ fortran.constraint_variables.fnbshinef = 1.0
+ fortran.constraint_variables.fncycle = 1.0
+ fortran.constraint_variables.fnesep = 1.0
+ fortran.constraint_variables.foh_stress = 1.0
+ fortran.constraint_variables.fpeakb = 1.0
+ fortran.constraint_variables.fpinj = 1.0
+ fortran.constraint_variables.fpnetel = 1.0
+ fortran.constraint_variables.fportsz = 1.0
+ fortran.constraint_variables.fpsepbqar = 1.0
+ fortran.constraint_variables.fpsepr = 1.0
+ fortran.constraint_variables.fptemp = 1.0
+ fortran.constraint_variables.fptfnuc = 1.0
+ fortran.constraint_variables.fq = 1.0
+ fortran.constraint_variables.fqval = 1.0
+ fortran.constraint_variables.fradpwr = 0.99
+ fortran.constraint_variables.fradwall = 1.0
+ fortran.constraint_variables.freinke = 1.0
+ fortran.constraint_variables.frminor = 1.0
+ fortran.constraint_variables.fstrcase = 1.0
+ fortran.constraint_variables.fstrcond = 1.0
+ fortran.constraint_variables.fstr_wp = 1.0
+ fortran.constraint_variables.fmaxvvstress = 1.0
+ fortran.constraint_variables.ftbr = 1.0
+ fortran.constraint_variables.ft_burn = 1.0
+ fortran.constraint_variables.ftcycl = 1.0
+ fortran.constraint_variables.ftmargoh = 1.0
+ fortran.constraint_variables.ftmargtf = 1.0
+ fortran.constraint_variables.ft_current_ramp_up = 1.0
+ fortran.constraint_variables.ftpeak = 1.0
+ fortran.constraint_variables.fvdump = 1.0
+ fortran.constraint_variables.fvs = 1.0
+ fortran.constraint_variables.fvvhe = 1.0
+ fortran.constraint_variables.fwalld = 1.0
+ fortran.constraint_variables.fzeffmax = 1.0
+ fortran.constraint_variables.gammax = 2.0
+ fortran.constraint_variables.i_q95_fixed = 0
+ fortran.constraint_variables.pflux_fw_rad_max = 1.0
+ fortran.constraint_variables.mvalim = 40.0
+ fortran.constraint_variables.f_p_beam_shine_through_max = 1e-3
+ fortran.constraint_variables.nflutfmax = 1.0e23
+ fortran.constraint_variables.p_plasma_separatrix_min_mw = 150.0
+ fortran.constraint_variables.f_fw_rad_max = 3.33
+ fortran.constraint_variables.pflux_fw_rad_max_mw = 0.0
+ fortran.constraint_variables.pnetelin = 1.0e3
+ fortran.constraint_variables.p_fusion_total_max_mw = 1.5e3
+ fortran.constraint_variables.psepbqarmax = 9.5
+ fortran.constraint_variables.pseprmax = 25.0
+ fortran.constraint_variables.ptfnucmax = 1e-3
+ fortran.constraint_variables.tbrmin = 1.1
+ fortran.constraint_variables.t_burn_min = 1.0
+ fortran.constraint_variables.tcycmn = 0.0
+ fortran.constraint_variables.t_current_ramp_up_min = 1.0
+ fortran.constraint_variables.vvhealw = 1.0
+ fortran.constraint_variables.walalw = 1.0
+ fortran.constraint_variables.f_alpha_energy_confinement_min = 5.0
+ fortran.constraint_variables.falpha_energy_confinement = 1.0
+ fortran.constraint_variables.fniterpump = 1.0
+ fortran.constraint_variables.zeffmax = 3.6
+ fortran.constraint_variables.fpoloidalpower = 1.0
+ fortran.constraint_variables.fpsep = 1.0
+ fortran.constraint_variables.fcqt = 1.0
+ fortran.constraint_variables.fecrh_ignition = 1.0
diff --git a/process/final.py b/process/final.py
index 87d3c46819..d0d4e495a2 100644
--- a/process/final.py
+++ b/process/final.py
@@ -2,13 +2,13 @@
from tabulate import tabulate
+import process.constraints as constraints
from process import output as op
from process import (
process_output as po,
)
from process.fortran import (
constants,
- constraints,
numerics,
)
from process.objectives import objective_function
@@ -67,20 +67,15 @@ def output_evaluation():
f2py_compatible_to_string(i)
for i in numerics.lablcc[numerics.icc[: numerics.neqns + numerics.nineqns] - 1]
]
- units = [f2py_compatible_to_string(i) for i in units]
- physical_constraint = [
- f"{c} {u}" for c, u in zip(value.tolist(), units, strict=False)
- ]
- physical_residual = [
- f"{c} {u}" for c, u in zip(residual.tolist(), units, strict=False)
- ]
+ physical_constraint = [f"{c} {u}" for c, u in zip(value, units, strict=False)]
+ physical_residual = [f"{c} {u}" for c, u in zip(residual, units, strict=False)]
table_data = {
"Constraint Name": labels,
- "Constraint Type": symbols.tolist(),
+ "Constraint Type": symbols,
"Physical constraint": physical_constraint,
"Constraint residual": physical_residual,
- "Normalised residual": residual_error.tolist(),
+ "Normalised residual": residual_error,
}
po.write(constants.nout, tabulate(table_data, headers="keys"))
diff --git a/process/init.py b/process/init.py
index a51c835a59..8a9cad0072 100644
--- a/process/init.py
+++ b/process/init.py
@@ -12,6 +12,7 @@
from process.blanket_library import init_blanket_library, init_primary_pumping_variables
from process.build import init_build_variables
from process.buildings import init_buildings_variables
+from process.constraints import ConstraintManager, init_constraint_variables
from process.costs import init_cost_variables
from process.cs_fatigue import init_cs_fatigue_variables
from process.current_drive import init_current_drive_variables
@@ -271,7 +272,7 @@ def init_all_module_vars():
init_vacuum_variables()
init_pf_power_variables()
init_build_variables()
- fortran.constraint_variables.init_constraint_variables()
+ init_constraint_variables()
init_pulse_variables()
init_rebco_variables()
init_reinke_variables()
@@ -1134,7 +1135,7 @@ def check_process(inputs): # noqa: ARG001
def set_active_constraints():
"""Set constraints provided in the input file as 'active'"""
num_constraints = 0
- for i in range(fortran.numerics.ipeqns):
+ for i in range(ConstraintManager.num_constraints()):
if fortran.numerics.icc[i] != 0:
fortran.numerics.active_constraints[fortran.numerics.icc[i] - 1] = True
num_constraints += 1
diff --git a/process/input.py b/process/input.py
index 64a77d215e..7a13934fe2 100644
--- a/process/input.py
+++ b/process/input.py
@@ -9,6 +9,7 @@
from warnings import warn
from process import fortran
+from process.constraints import ConstraintManager
from process.exceptions import ProcessValidationError, ProcessValueError
from process.utilities.f2py_string_patch import (
f2py_compatible_to_string,
@@ -104,10 +105,10 @@ def __post_init__(self):
"maxcal": InputVariable(fortran.global_variables, int, range=(0, 10000)),
"minmax": InputVariable(fortran.numerics, int),
"neqns": InputVariable(
- fortran.numerics, int, range=(1, fortran.numerics.ipeqns.item())
+ fortran.numerics, int, range=(1, ConstraintManager.num_constraints())
),
"nineqns": InputVariable(
- fortran.numerics, int, range=(1, fortran.numerics.ipeqns.item())
+ fortran.numerics, int, range=(1, ConstraintManager.num_constraints())
),
"alphaj": InputVariable(fortran.physics_variables, float, range=(0.0, 10.0)),
"alphan": InputVariable(fortran.physics_variables, float, range=(0.0, 10.0)),
diff --git a/process/scan.py b/process/scan.py
index 1e634bd44a..5e334ca88c 100644
--- a/process/scan.py
+++ b/process/scan.py
@@ -3,6 +3,7 @@
import numpy as np
from tabulate import tabulate
+import process.constraints as constraints
import process.process_output as process_output
from process.caller import write_output_files
from process.exceptions import ProcessValueError
@@ -10,7 +11,6 @@
build_variables,
constants,
constraint_variables,
- constraints,
cost_variables,
cs_fatigue_variables,
current_drive_variables,
@@ -470,8 +470,8 @@ def post_optimise(self, ifail: int):
equality_constraint_table.append([
name,
sym[i],
- f"{con2[i]} {f2py_compatible_to_string(lab[i])}",
- f"{err[i]} {f2py_compatible_to_string(lab[i])}",
+ f"{con2[i]} {lab[i]}",
+ f"{err[i]} {lab[i]}",
con1[i],
])
process_output.ovarre(
@@ -513,8 +513,8 @@ def post_optimise(self, ifail: int):
inequality_constraint_table.append([
name,
sym[i],
- f"{con2[i]} {f2py_compatible_to_string(lab[i])}",
- f"{err[i]} {f2py_compatible_to_string(lab[i])}",
+ f"{con2[i]} {lab[i]}",
+ f"{err[i]} {lab[i]}",
])
process_output.ovarre(
constants.mfile,
diff --git a/process/utilities/errorlist.json b/process/utilities/errorlist.json
index 0b7290dacd..34f27887fb 100644
--- a/process/utilities/errorlist.json
+++ b/process/utilities/errorlist.json
@@ -12,8 +12,8 @@
"errors": [
{
"no": 1,
- "level": 3,
- "message": "CONSTRAINTS: Do not use constraint 7 if i_plasma_ignited=1"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 2,
@@ -27,38 +27,38 @@
},
{
"no": 4,
- "level": 3,
- "message": "CONSTRAINTS: Do not use constraint 28 if i_plasma_ignited=1"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 5,
- "level": 3,
- "message": "CONSTRAINTS: temp_fw_peak = 0 ==> i_pulsed_plant=0; do not use constraint 39 if i_pulsed_plant=0"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 6,
- "level": 3,
- "message": "CONSTRAINTS: tcycmn = 0 ==> i_pulsed_plant=0; do not use constraint 42 if i_pulsed_plant=0"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 7,
- "level": 3,
- "message": "CONSTRAINTS: Do not use constraint 43 if itart=0"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 8,
- "level": 3,
- "message": "CONSTRAINTS: Do not use constraint 44 if itart=0"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 9,
- "level": 3,
- "message": "CONSTRAINTS: Do not use constraint 45 if itart=0"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 10,
- "level": 3,
- "message": "CONSTRAINTS: Do not use constraint 46 if itart=0"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 11,
@@ -67,18 +67,18 @@
},
{
"no": 12,
- "level": 3,
- "message": "CONSTRAINTS: Do not use constraint 50 if ife=0"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 13,
- "level": 3,
- "message": "CONSTRAINTS: No such constraint equation number..."
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 14,
- "level": 3,
- "message": "CONSTRAINTS: NaN/infty error for constraint equation..."
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 15,
@@ -202,12 +202,12 @@
},
{
"no": 39,
- "level": 1,
+ "level": 0,
"message": "REMOVED"
},
{
"no": 40,
- "level": 2,
+ "level": 0,
"message": "REMOVED"
},
{
@@ -257,7 +257,7 @@
},
{
"no": 50,
- "level": 3,
+ "level": 0,
"message": "REMOVED"
},
{
@@ -292,23 +292,23 @@
},
{
"no": 57,
- "level": 3,
- "message": "CONVXC: Illegal iteration variable number"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 58,
"level": 3,
- "message": "CONVXC: Iteration variable is zero; change its initial value or lower bound"
+ "message": "REMOVED"
},
{
"no": 59,
"level": 3,
- "message": "CONVXC: NaN error for iteration variable"
+ "message": "REMOVED"
},
{
"no": 60,
- "level": 3,
- "message": "CONVXC: scale(i) = 0 for iteration variable"
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 61,
@@ -1187,8 +1187,8 @@
},
{
"no": 236,
- "level": 3,
- "message": "CHECK: The 1/R toroidal B field dependency constraint is being depreciated."
+ "level": 0,
+ "message": "REMOVED"
},
{
"no": 237,
@@ -1452,8 +1452,8 @@
},
{
"no": 289,
- "level": 3,
- "message": "CHECK: Constraint equation 22 has been deprecated."
+ "level": 0,
+ "message": "REMOVED"
}
]
}
diff --git a/source/fortran/constraint_equations.f90 b/source/fortran/constraint_equations.f90
deleted file mode 100755
index 1df6e6967d..0000000000
--- a/source/fortran/constraint_equations.f90
+++ /dev/null
@@ -1,3442 +0,0 @@
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-module constraints
- !! author: J Morris
- !!
- !! Module defining the constraint equations and the routine that evaluates the
- !! constraint equations.
-
- ! Import modules
-#ifndef dp
- use, intrinsic :: iso_fortran_env, only: dp=>real64
-#endif
- use error_handling, only: report_error, idiags, fdiags
-
- implicit none
-
- public :: constraint_eqns
-
-! type constraint_args_type
-! real(dp) :: cc
-! !! Residual error in constraint equation
-! real(dp) :: con
-! !! constraint value for constraint equation in physical units
-! real(dp) :: err
-! !! residual error in constraint equation in physical units
-! character(len=1) :: symbol
-! !! `=<`, `>`, `<` symbol for constraint equation denoting its type
-! character(len=10) :: units
-! !! constraint units in constraint equation
-! end type
-
-contains
-
- subroutine constraint_eqns(m,ieqn,cc,con,err,symbol,units)
- !! Routine that formulates the constraint equations
- !!
- !! **author: P J Knight** (UKAEA)
- !!
- !! **author: J Morris** (UKAEA)
- !!
- !! if `ieqn` is zero or negative, evaluate all the constraint equations, otherwise
- !! evaluate only the `ieqn`th equation. The code attempts to make \( cc(i) = 0 \) for all
- !! \( i \in \{1,\cdots,m\} \) equations. All relevant consistency equations should be active in
- !! order to make a self-consistent machine.
- !!
- !! **References**
- !!
- !! 1.
- use numerics, only: icc
-
- implicit none
-
- integer, intent(in) :: m
- !! Number of constraint equations to solve
-
- integer, intent(in) :: ieqn
- !! Switch for constraint equations to evaluate;
-
- real(dp), dimension(m), intent(out) :: cc
- !! Residual error in equation i
-
- real(dp), optional, dimension(m), intent(out) :: con
- !! constraint value for equation i in physical units
-
- real(dp), optional, dimension(m), intent(out) :: err
- !! residual error in equation i in physical units
-
- character(len=1), optional, dimension(m), intent(out) :: symbol
- !! `=<`, `>`, `<` symbol for equation i denoting its type
-
- character*10, optional, dimension(m), intent(out) :: units
- !! constraint units in equation i
-
- ! Local variables
- integer :: i, i1, i2
-
- real(dp) :: tmp_cc = 0
- !! Residual error in constraint equation
- real(dp) :: tmp_con = 0
- !! constraint value for constraint equation in physical units
- real(dp) :: tmp_err = 0
- !! residual error in constraint equation in physical units
- character(len=1) :: tmp_symbol = ' '
- !! `=<`, `>`, `<` symbol for constraint equation denoting its type
- character(len=10) :: tmp_units = ' '
- !! constraint units in constraint equation
-
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! If ieqn is positive, only evaluate the 'ieqn'th constraint residue,
- ! otherwise evaluate all m constraint residues
- if (ieqn > 0) then
- i1 = ieqn ; i2 = ieqn
- else
- i1 = 1 ; i2 = m
- end if
-
- ! Consistency (equality) constraints should converge to zero.
- do i = i1,i2
-
- ! The constraint value in physical units is
- ! a) for consistency equations, the quantity to be equated, or
- ! b) for limit equations, the limiting value.
- ! The symbol is = for a consistency equation, < for an upper limit
- ! or > for a lower limit.
- select case (icc(i))
-
- ! Relationship between beta, temperature (keV) and density
- case (1); call constraint_eqn_001(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Global plasma power balance equation
- case (2); call constraint_eqn_002(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Global power balance equation for ions
- case (3); call constraint_eqn_003(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Global power balance equation for electrons
- case (4); call constraint_eqn_004(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for density upper limit
- case (5); call constraint_eqn_005(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for epsilon beta-poloidal upper limit
- case (6); call constraint_eqn_006(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for hot beam ion density
- case (7); call constraint_eqn_007(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for neutron wall load upper limit
- case (8); call constraint_eqn_008(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for fusion power upper limit
- case (9); call constraint_eqn_009(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Obsolete
- case (10); call constraint_eqn_010(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for radial build
- case (11); call constraint_eqn_011(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for volt-second capability lower limit
- case (12); call constraint_eqn_012(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for burn time lower limit
- case (13); call constraint_eqn_013(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation to fix number of NBI decay lengths to plasma centre
- case (14); call constraint_eqn_014(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for L-H power threshold limit
- case (15); call constraint_eqn_015(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for net electric power lower limit
- case (16); call constraint_eqn_016(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for radiation power upper limit
- case (17); call constraint_eqn_017(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for divertor heat load upper limit
- case (18); call constraint_eqn_018(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for MVA upper limit
- case (19); call constraint_eqn_019(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for neutral beam tangency radius upper limit
- case (20); call constraint_eqn_020(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for minor radius lower limit
- case (21); call constraint_eqn_021(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Obsolete
- case (22); call constraint_eqn_022(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for conducting shell radius / rminor upper limit
- case (23); call constraint_eqn_023(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for beta upper limit
- case (24); call constraint_eqn_024(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for peak toroidal field upper limit
- case (25); call constraint_eqn_025(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for Central Solenoid current density upper limit at EOF
- case (26); call constraint_eqn_026(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for Central Solenoid current density upper limit at BOP
- case (27); call constraint_eqn_027(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for fusion gain (big Q) lower limit
- case (28); call constraint_eqn_028(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for inboard major radius
- case (29); call constraint_eqn_029(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for injection power upper limit
- case (30); call constraint_eqn_030(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for TF coil case stress upper limit (SCTF)
- case (31); call constraint_eqn_031(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for TF coil conduit stress upper limit (SCTF)
- case (32); call constraint_eqn_032(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for TF coil operating/critical J upper limit (SCTF)
- case (33); call constraint_eqn_033(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for TF coil dump voltage upper limit (SCTF)
- case (34); call constraint_eqn_034(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for TF coil J_wp/J_prot upper limit (SCTF)
- case (35); call constraint_eqn_035(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for TF coil s/c temperature margin lower limit (SCTF)
- case (36); call constraint_eqn_036(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for current drive gamma upper limit
- case (37); call constraint_eqn_037(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for first wall temperature upper limit
- case (39); call constraint_eqn_039(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for auxiliary power lower limit
- case (40); call constraint_eqn_040(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for plasma current ramp-up time lower limit
- case (41); call constraint_eqn_041(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for cycle time lower limit
- case (42); call constraint_eqn_042(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for average centrepost temperature
- case (43); call constraint_eqn_043(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for centrepost temperature upper limit (TART)
- case (44); call constraint_eqn_044(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for edge safety factor lower limit (TART)
- case (45); call constraint_eqn_045(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for Ip/Irod upper limit (TART)
- case (46); call constraint_eqn_046(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for TF coil toroidal thickness upper limit
- case (47); call constraint_eqn_047(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for poloidal beta upper limit
- case (48); call constraint_eqn_048(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Issue #508 Remove RFP option Equation to ensure reversal parameter F is negative
- case (49); call constraint_eqn_049(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! IFE option: Equation for repetition rate upper limit
- case (50); call constraint_eqn_050(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation to enforce startup flux = available startup flux
- case (51); call constraint_eqn_051(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for tritium breeding ratio lower limit
- case (52); call constraint_eqn_052(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for fast neutron fluence on TF coil upper limit
- case (53); call constraint_eqn_053(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for peak TF coil nuclear heating upper limit
- case (54); call constraint_eqn_054(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for helium concentration in vacuum vessel upper limit
- case (55); call constraint_eqn_055(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for power through separatrix / major radius upper limit
- case (56); call constraint_eqn_056(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Obsolete
- case (57); call constraint_eqn_057(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Obsolete
- case (58); call constraint_eqn_058(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for neutral beam shine-through fraction upper limit
- case (59); call constraint_eqn_059(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for Central Solenoid s/c temperature margin lower limit
- case (60); call constraint_eqn_060(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for availability limit
- case (61); call constraint_eqn_061(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Lower limit on f_alpha_energy_confinement the ratio of alpha particle to energy confinement times
- case (62); call constraint_eqn_062(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Upper limit on niterpump (vacuum_model = simple)
- case (63); call constraint_eqn_063(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Upper limit on Zeff
- case (64); call constraint_eqn_064(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Limit TF dump time to calculated quench time
- case (65); call constraint_eqn_065(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Limit on rate of change of energy in poloidal field
- case (66); call constraint_eqn_066(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Simple upper limit on radiation wall load
- case (67); call constraint_eqn_067(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! New Psep scaling (PsepB/qAR)
- case (68); call constraint_eqn_068(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Ensure separatrix power is less than value from Kallenbach divertor
- case (69); call constraint_eqn_069(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Separatrix temperature consistency
- case (70); call constraint_eqn_070(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Separatrix density consistency
- case (71); call constraint_eqn_071(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Central Solenoid Tresca yield criterion
- case (72); call constraint_eqn_072(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! ensure separatrix power is greater than the L-H power + auxiliary power
- case (73); call constraint_eqn_073(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! ensure TF coil quench temperature < tmax_croco
- case (74); call constraint_eqn_074(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! ensure that TF coil current / copper area < Maximum value ONLY used for croco HTS coil
- case (75); call constraint_eqn_075(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Eich critical separatrix density model
- case (76); call constraint_eqn_076(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for maximum TF current per turn upper limit
- case (77); call constraint_eqn_077(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for Reinke criterion, divertor impurity fraction lower limit
- case (78); call constraint_eqn_078(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Equation for maximum CS field
- case (79); call constraint_eqn_079(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Lower limit p_plasma_separatrix_mw
- case (80); call constraint_eqn_080(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint equation making sure that ne(0) > ne(ped)
- case (81); call constraint_eqn_081(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint equation making sure that stellarator coils dont touch in toroidal direction
- case (82); call constraint_eqn_082(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint ensuring radial build consistency for stellarators
- case (83); call constraint_eqn_083(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for lower limit of beta
- case (84); call constraint_eqn_084(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for CP lifetime
- case (85); call constraint_eqn_085(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for turn dimension
- case (86); call constraint_eqn_086(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for cryogenic power
- case (87); call constraint_eqn_087(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for TF coil strain
- case (88); call constraint_eqn_088(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! ensure that OH coil current / copper area < Maximum value ONLY used for croco HTS coil
- case (89); call constraint_eqn_089(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for minimum CS stress load cycles
- case (90); call constraint_eqn_090(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for indication of ECRH ignitability
- case (91); call constraint_eqn_091(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- ! Constraint for D/T ratio
- case (92); call constraint_eqn_092(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- case default
-
- idiags(1) = icc(i)
- call report_error(13)
- tmp_cc = 0
- tmp_con = 0
- tmp_err = 0
- tmp_symbol = ' '
- tmp_units = ' '
-
- end select
-
- cc(i) = tmp_cc
- if (present(con)) then
- con(i) = tmp_con
- if (present(err)) err(i) = tmp_err
- if (present(symbol)) symbol(i) = tmp_symbol
- if (present(units)) units(i) = tmp_units
- end if
-
- if (isnan(cc(i)).or.(abs(cc(i))>9.99D99)) then
-
- ! Add debugging lines as appropriate...
- select case (icc(i))
-
- ! Relationship between beta, temperature (keV) and density (consistency equation)
- case (1); call constraint_err_001()
- ! Equation for net electric power lower limit
- case (16); call constraint_err_016()
- ! Equation for injection power upper limit
- case (30); call constraint_err_030()
- ! Limit on rate of change of energy in poloidal field
- case (66); call constraint_err_066()
-
- end select
-
- idiags(1) = icc(i) ; fdiags(1) = cc(i)
- call report_error(14)
-
- end if
-
- end do
- ! Issue 505 Reverse the sign so it works as an inequality constraint (cc(i) > 0)
- ! This will have no effect if it is used as an equality constraint because it will be squared.
- cc = -cc
-
- end subroutine constraint_eqns
-
- !--- Error-handling routines
-
- subroutine constraint_err_001()
- !! Error in: Relationship between beta, temperature (keV) and density (consistency equation)
- !! author: P B Lloyd, CCFE, Culham Science Centre
- use physics_variables, only: beta_fast_alpha, beta_beam, dene, ten, nd_ions_total, tin, btot, beta
- write(*,*) 'beta_fast_alpha = ', beta_fast_alpha
- write(*,*) 'beta_beam = ', beta_beam
- write(*,*) 'dene = ', dene
- write(*,*) 'ten = ', ten
- write(*,*) 'nd_ions_total = ', nd_ions_total
- write(*,*) 'tin = ', tin
- write(*,*) 'btot = ',btot
- write(*,*) 'beta = ', beta
- end subroutine
-
- subroutine constraint_err_016()
- !! Error in: Equation for net electric power lower limit
- !! author: P B Lloyd, CCFE, Culham Science Centre
- use constraint_variables, only: fpnetel, pnetelin
- use heat_transport_variables, only: p_plant_electric_net_mw
- implicit none
- write(*,*) 'fpnetel = ', fpnetel
- write(*,*) 'p_plant_electric_net_mw = ', p_plant_electric_net_mw
- write(*,*) 'pnetelin = ', pnetelin
- end subroutine
-
- subroutine constraint_err_030()
- !! Error in: Equation for injection power upper limit
- !! author: P B Lloyd, CCFE, Culham Science Centre
- use current_drive_variables, only: p_hcd_injected_total_mw, p_hcd_injected_max
- use constraint_variables, only: fpinj
- implicit none
- write(*,*) 'fpinj = ', fpinj
- write(*,*) 'p_hcd_injected_max = ', p_hcd_injected_max
- write(*,*) 'p_hcd_injected_total_mw = ', p_hcd_injected_total_mw
- end subroutine
-
- subroutine constraint_err_066()
- !! Error in: Limit on rate of change of energy in poloidal field
- !! author: P B Lloyd, CCFE, Culham Science Centre
- use constraint_variables, only: fpoloidalpower
- use pf_power_variables, only: maxpoloidalpower, peakpoloidalpower
- implicit none
- write(*,*) 'fpoloidalpower = ', fpoloidalpower
- write(*,*) 'maxpoloidalpower = ', maxpoloidalpower
- write(*,*) 'peakpoloidalpower = ', peakpoloidalpower
- end subroutine constraint_err_066
-
- !---
-
- subroutine constraint_eqn_001(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- !! author: J Morris
- !! category: equality constraint
- !!
- !! Relationship between beta, temperature (keV) and density
- !!
- !! \begin{equation}
- !! c_i = 1 - \frac{1}{\beta}\left( \beta_{ft} + \beta_{NBI} + 2 \times 10^3 \mu_0 e
- !! \left( \frac{n_e T_e + n_i T_i}{B_{tot}^2} \right) \right)
- !! \end{equation}
- !!
- !! - \( \beta \) -- total plasma beta
- !! - \( \beta_{ft} \) -- fast alpha beta component
- !! - \( \beta_{NBI} \) -- neutral beam beta component
- !! - \( n_e \) -- electron density [m\(^3\)]
- !! - \( n_i \) -- total ion density [m\(^3\)]
- !! - \( T_e \) -- density weighted average electron temperature [keV]
- !! - \( T_i \) -- density weighted average ion temperature [keV]
- !! - \( B_{tot} \) -- total toroidal + poloidal field [T]
-
- use physics_variables, only: beta_fast_alpha, beta_beam, dene, ten, nd_ions_total, tin, btot, beta
- use constants, only: electron_charge,rmu0
-
- implicit none
-
- ! type(constraint_args_type), intent(out) :: args
- real(dp), intent(out) :: tmp_cc
- real(dp), intent(out) :: tmp_con
- real(dp), intent(out) :: tmp_err
- character(len=1), intent(out) :: tmp_symbol
- character(len=10), intent(out) :: tmp_units
-
- !! constraint derived type
-
- tmp_cc = 1.0D0 - (beta_fast_alpha + beta_beam + &
- 2.0D3*rmu0*electron_charge * (dene*ten + nd_ions_total*tin)/btot**2 )/beta
- tmp_con = beta * (1.0D0 - tmp_cc)
- tmp_err = beta * tmp_cc
- tmp_symbol = '='
- tmp_units = ''
-
- end subroutine constraint_eqn_001
-
- subroutine constraint_eqn_002(tmp_cc, tmp_con, tmp_err, tmp_symbol, tmp_units)
- !! author: J. Morris
- !! category: equality constraint
- !!
- !! Global plasma power balance equation
- !!
- !! \begin{equation} c_i =
- !! \end{equation}
- !!
- !! i_rad_loss : input integer : switch for radiation loss term usage in power balance (see User Guide):device.dat):