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

Add VerticalFieldConstraint and function to estimate plasma equilibrium field #3076

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions bluemira/equilibria/optimisation/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,49 @@
return 2


class VerticalFieldConstraint(AbsoluteMagneticConstraint):
"""
Absolute vertical field (Bz) constraint.
"""

def __init__(
self,
x: Union[float, np.ndarray],
z: Union[float, np.ndarray],
target_value: float,
weights: Union[float, np.ndarray] = 1.0,
tolerance: Union[float, np.ndarray] = 1e-6,
):
super().__init__(
x,
z,
target_value,
weights=weights,
tolerance=tolerance,
f_constraint=AxBConstraint,
constraint_type="equality",
)

def control_response(self, coilset: CoilSet) -> np.ndarray:
"""
Calculate control response of a CoilSet to the constraint.
"""
return coilset.Bz_response(self.x, self.z, control=True)

def evaluate(self, eq: Equilibrium) -> np.ndarray:
"""
Calculate the value of the constraint in an Equilibrium.
"""
return eq.Bz(self.x, self.z)

def plot(self, ax):
"""
Plot the constraint onto an Axes.
"""
kwargs = {"marker": "^", "markersize": 8, "color": "b", "linestyle": "None"}
ax.plot(self.x, self.z, **kwargs)

Check warning on line 593 in bluemira/equilibria/optimisation/constraints.py

View check run for this annotation

Codecov / codecov/patch

bluemira/equilibria/optimisation/constraints.py#L592-L593

Added lines #L592 - L593 were not covered by tests


class PsiConstraint(AbsoluteMagneticConstraint):
"""
Absolute psi value constraint.
Expand Down
42 changes: 41 additions & 1 deletion bluemira/plasma_physics/rules_of_thumb.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
A collection of simple 0-D rules of thumb for tokamak plasmas.
"""

from typing import Optional

import numpy as np

from bluemira.base.constants import EV_TO_J, K_BOLTZMANN, MU_0
from bluemira.base.constants import EV_TO_J, K_BOLTZMANN, MU_0, MU_0_4PI
from bluemira.plasma_physics.collisions import coulomb_logarithm, spitzer_conductivity


Expand Down Expand Up @@ -282,3 +284,41 @@
"""
nu = q_star / q_0 - 1.0
return np.log(1.65 + 0.89 * nu)


def estimate_vertical_field(
R_0: float,
A: float,
I_p: float,
beta_p_th: float,
l_i: float,
kappa_95: Optional[float] = None,
) -> float:
"""
Estimate the vertical field to keep the plasma in equilibrium.

Parameters
----------
R_0:
Plasma major radius [m]
A:
Plasma aspect ratio
I_p:
Plasma current [A]
beta_p_th:
Thermal poloidal beta
l_i:
Normalised internal inductance
kappa:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kappa_95

Plasma elongation at the 95th percentile flux surface

Notes
-----
See e.g. Ferrara et al., "Alcasim simulation code for Alcator C-Mod"
https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4178094

The kappa term is not always present in textbooks and the like, and
is almost certainly irrelevant at the end of breakdown.
"""
k_term = 1.0 if kappa_95 is None else np.sqrt(2.0 / (1.0 + kappa_95**2))
return -MU_0_4PI * I_p / R_0 * (beta_p_th + 0.5 * l_i - 1.5 + np.log(8 * A * k_term))

Check warning on line 324 in bluemira/plasma_physics/rules_of_thumb.py

View check run for this annotation

Codecov / codecov/patch

bluemira/plasma_physics/rules_of_thumb.py#L323-L324

Added lines #L323 - L324 were not covered by tests
Copy link
Contributor

@je-cook je-cook Mar 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have a couple line test for this to an expected result?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, could you add a test to test_rules_of_thumb?

29 changes: 27 additions & 2 deletions tests/equilibria/test_optimisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
import numpy as np

from bluemira.equilibria import Equilibrium
from bluemira.equilibria import Breakdown, Equilibrium
from bluemira.equilibria.coils import Coil, CoilSet
from bluemira.equilibria.grid import Grid
from bluemira.equilibria.optimisation.constraints import (
FieldNullConstraint,
IsofluxConstraint,
MagneticConstraintSet,
VerticalFieldConstraint,
)
from bluemira.equilibria.optimisation.problem import (
TikhonovCurrentCOP,
)
from bluemira.equilibria.optimisation.problem import TikhonovCurrentCOP
from bluemira.equilibria.profiles import CustomProfile
from bluemira.equilibria.solve import PicardIterator
from bluemira.optimisation import Algorithm


def coilset_setup(materials=False):
Expand Down Expand Up @@ -79,3 +83,24 @@ def test_isoflux_constrained_tikhonov_current_optimisation():
],
decimal=5,
)


def test_vertical_field_constraint():
coilset = coilset_setup()
grid = Grid(4.5, 14, -9, 9, 65, 65)
eq = Breakdown(coilset, grid)

bz_constraint = VerticalFieldConstraint(9, 0.0, -0.75, 1.0, tolerance=1e-6)
targets = MagneticConstraintSet([bz_constraint])
opt_problem = TikhonovCurrentCOP(
eq.coilset,
eq,
targets,
gamma=1e-18,
opt_algorithm=Algorithm.SLSQP,
opt_conditions={"max_eval": 5},
)

coilset = opt_problem.optimise()

np.testing.assert_allclose(eq.Bz(9.0, 0.0), -0.75, rtol=1e-6)