Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RZIp vertical stability criterion #3606

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from
38 changes: 19 additions & 19 deletions bluemira/codes/process/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from enum import IntEnum, auto
from importlib import resources
from pathlib import Path
from typing import TYPE_CHECKING, Literal, TypeVar
Expand All @@ -21,7 +21,7 @@
from bluemira.utilities.tools import flatten_iterable

if TYPE_CHECKING:
from collections.abc import Iterable
from collections.abc import Sequence


# Create dummy PROCESS objects. Required for docs to build properly and
Expand Down Expand Up @@ -113,25 +113,25 @@ def value(self, new_value):
self._value = new_value


class Impurities(Enum):
class Impurities(IntEnum):
"""
PROCESS impurities Enum
"""

H = 1
He = 2
Be = 3
C = 4
N = 5
O = 6 # noqa: E741
Ne = 7
Si = 8
Ar = 9
Fe = 10
Ni = 11
Kr = 12
Xe = 13
W = 14
H = auto()
He = auto()
Be = auto()
C = auto()
N = auto()
O = auto() # noqa: E741
Ne = auto()
Si = auto()
Ar = auto()
Fe = auto()
Ni = auto()
Kr = auto()
Xe = auto()
W = auto()

def files(self) -> dict[str, Path]:
"""
Expand Down Expand Up @@ -162,8 +162,8 @@ def id(self):
return f"fimp({self.value:02})"

def read_impurity_files(
self, filetype: Iterable[Literal["lz", "z2", "z"]]
) -> tuple[list[ImpurityDataHeader]]:
self, filetype: Sequence[Literal["lz", "z2", "z"]]
) -> tuple[list[ImpurityDataHeader], ...]:
"""Get contents of impurity data files"""
files = self.files()
return tuple(
Expand Down
22 changes: 17 additions & 5 deletions bluemira/equilibria/coils/_coil.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class Coil(CoilFieldsMixin):
"_flag_sizefix",
"_j_max",
"_number",
"_resistance",
"_x",
"_x_boundary",
"_z",
Expand All @@ -148,6 +149,7 @@ def __init__(
b_max: float = np.nan,
discretisation: float = np.nan,
n_turns: int = 1,
resistance: float = 0,
*,
psi_analytic: bool = False,
Bx_analytic: bool = True,
Expand All @@ -172,6 +174,7 @@ def __init__(
self.ctype = ctype
self.name = name
self.n_turns = n_turns
self.resistance = resistance

self._number = CoilNumber.generate(self.ctype)
if self.name is None:
Expand All @@ -196,6 +199,7 @@ def __repr__(self):
f"{type(self).__name__}({self.name} ctype={self.ctype.name} x={self.x:.2g}"
f" z={self.z:.2g} dx={self.dx:.2g} dz={self.dz:.2g}"
f" current={self.current:.2g} j_max={self.j_max:.2g} b_max={self.b_max:.2g}"
f" resistance={self.resistance:.2g}"
f" discretisation={self.discretisation:.2g})"
)

Expand Down Expand Up @@ -369,11 +373,7 @@ def position(self, values: np.ndarray):
@ctype.setter
def ctype(self, value: str | np.ndarray | CoilType):
"""Set coil type"""
self._ctype = (
value
if isinstance(value, CoilType)
else CoilType[value[0] if isinstance(value, np.ndarray) else value]
)
self._ctype = CoilType(value[0] if isinstance(value, np.ndarray) else value)

@dx.setter
def dx(self, value: float | None):
Expand Down Expand Up @@ -414,6 +414,16 @@ def b_max(self, value: float):
"""Set coil max field"""
self._b_max = floatify(value)

@property
def resistance(self):
"""Get coil resistance"""
return self._resistance

@resistance.setter
def resistance(self, value: float):
"""Set coil resistance"""
self._resistance = value

@discretisation.setter
def discretisation(self, value: float):
"""Set coil discretisation"""
Expand All @@ -424,6 +434,7 @@ def assign_material(
self,
j_max: float = NBTI_J_MAX,
b_max: float = NBTI_B_MAX,
resistance: float = 0,
) -> None:
"""
Assigns EM material properties to coil
Expand All @@ -442,6 +453,7 @@ def assign_material(
"""
self.j_max = j_max
self.b_max = b_max
self.resistance = resistance

def get_max_current(self):
"""Get max current"""
Expand Down
133 changes: 131 additions & 2 deletions bluemira/equilibria/coils/_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@

from bluemira.base.constants import MU_0
from bluemira.equilibria.constants import X_TOLERANCE
from bluemira.magnetostatics.greens import greens_Bx, greens_Bz, greens_psi
from bluemira.magnetostatics.greens import (
greens_Bx,
greens_Bz,
greens_dbz_dx,
greens_psi,
)
from bluemira.magnetostatics.semianalytic_2d import (
semianalytic_Bx,
semianalytic_Bz,
Expand Down Expand Up @@ -59,6 +64,50 @@ def __init__(
self._Bx_analytic = Bx_analytic
self._Bz_analytic = Bz_analytic

def dB_d(self, x: float | np.ndarray, z: float | np.ndarray):
"""
dB_d of Coilset

Parameters
----------
x:
The x values at which to calculate the dB_d response
z:
The z values at which to calculate the dB_d response
sum_coils:
sum over coils
control:
operations on control coils only

Returns
-------
:
Differential of magnetic field
"""
return self.dB_d_response(x, z) * self.current

def dB_d_response(self, x: float | np.ndarray, z: float | np.ndarray):
"""
Unit dB_d of Coilset

Parameters
----------
x:
The x values at which to calculate the dB_d response
z:
The z values at which to calculate the dB_d response
sum_coils:
sum over coils
control:
operations on control coils only

Returns
-------
:
Differential of magnetic field response
"""
return self._mix_control_method(x, z, greens_dbz_dx, None, disable_analytic=True)

def psi(self, x: float | np.ndarray, z: float | np.ndarray):
"""
Calculate poloidal flux at (x, z)
Expand Down Expand Up @@ -593,6 +642,34 @@ def Bz(
"""
return self._sum(super().Bz(x, z), sum_coils=sum_coils, control=control)

def dB_d(
self,
x: np.ndarray,
z: np.ndarray,
*,
sum_coils: bool = True,
control: bool = False,
) -> np.ndarray:
"""
dB_d of Coilset

Parameters
----------
x:
The x values at which to calculate the dB_d response
z:
The z values at which to calculate the dB_d response
sum_coils:
sum over coils
control:
operations on control coils only

Returns
-------
Differential of magnetic field
"""
return self._sum(super().dB_d(x, z), sum_coils=sum_coils, control=control)

def psi_response(
self,
x: np.ndarray,
Expand Down Expand Up @@ -660,7 +737,7 @@ def Bz_response(
control: bool = False,
) -> np.ndarray:
"""
Bz of Coilset
Unit Bz of Coilset

Parameters
----------
Expand All @@ -679,6 +756,58 @@ def Bz_response(
"""
return self._sum(super().Bz_response(x, z), sum_coils=sum_coils, control=control)

def dB_d_response(
self,
x: np.ndarray,
z: np.ndarray,
*,
sum_coils: bool = False,
control: bool = False,
) -> np.ndarray:
"""
Unit dB_d of Coilset

Parameters
----------
x:
The x values at which to calculate the dB_d response
z:
The z values at which to calculate the dB_d response
sum_coils:
sum over coils
control:
operations on control coils only

Returns
-------
:
Differential of magnetic field response
"""
return self._sum(
super().dB_d_response(x, z), sum_coils=sum_coils, control=control
)

def control_F(self, coil_grp: CoilGroup, *, control: bool = False) -> np.ndarray:
"""
Returns the Green's matrix element for the coil mutual force.

\t:math:`Fz_{i,j}=-2\\pi X_i\\mathcal{G}(X_j,Z_j,X_i,Z_i)`

Parameters
----------
coil_grp`:
the coil group to calculate against
control:
operations on control coils only
"""
if control:
inds = self._control_ind
inds2 = coil_grp._control_ind
else:
inds = inds2 = slice(None)

return super().control_F(coil_grp)[inds][:, inds2]

def _stored_greens(
self, bgreen: np.ndarray, *, sum_coils: bool = True, control: bool = False
) -> np.ndarray:
Expand Down
Loading
Loading