Skip to content

Commit 4d82cc0

Browse files
clmouldgeograham
andauthored
Adding documentation, delete unnecessary fn and argument (#4128)
* Adding documentation, delete unnecessary fn and argument * remove unnecessary argument * updating values in test * pre commit fixes * commit image added to docs * edit docstring * add currents fn back in * reword figure caption * change input of ToroidalHarmonicsConstraint so that it takes ToroidalHarmonicsSelectionResult and update notebook and tests * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Update documentation/source/equilibria/equilibria.rst Co-authored-by: geograham <[email protected]> * Additions to docs and fix broken test * replace == with assert almost equal --------- Co-authored-by: geograham <[email protected]>
1 parent cafab59 commit 4d82cc0

File tree

7 files changed

+185
-71
lines changed

7 files changed

+185
-71
lines changed

bluemira/equilibria/optimisation/harmonics/harmonics_constraints.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
ToroidalHarmonicConstraintFunction,
2828
)
2929
from bluemira.equilibria.optimisation.harmonics.toroidal_harmonics_approx_functions import ( # noqa: E501
30-
ToroidalHarmonicsParams,
30+
ToroidalHarmonicsSelectionResult,
3131
coil_toroidal_harmonic_amplitude_matrix,
3232
)
3333
from bluemira.utilities.tools import is_num
@@ -194,17 +194,20 @@ class ToroidalHarmonicConstraint(UpdateableConstraint):
194194

195195
def __init__(
196196
self,
197-
ref_harmonics_cos: npt.NDArray[np.float64],
198-
ref_harmonics_sin: npt.NDArray[np.float64],
199-
ref_harmonics_cos_amplitudes: npt.NDArray[np.float64],
200-
ref_harmonics_sin_amplitudes: npt.NDArray[np.float64],
201-
th_params: ToroidalHarmonicsParams,
197+
th_result: ToroidalHarmonicsSelectionResult,
202198
relative_tolerance_cos: float | npt.NDArray[np.float64] = 1e-3,
203199
relative_tolerance_sin: float | npt.NDArray[np.float64] = 1e-3,
204200
constraint_type: str = "equality",
205201
weights: float | np.ndarray = 1.0,
206202
):
207203
self.constraint_type = constraint_type
204+
205+
ref_harmonics_cos = th_result.cos_m
206+
ref_harmonics_sin = th_result.sin_m
207+
ref_harmonics_cos_amplitudes = th_result.cos_amplitudes
208+
ref_harmonics_sin_amplitudes = th_result.sin_amplitudes
209+
th_params = th_result.th_params
210+
208211
tolerance_cos = np.abs(relative_tolerance_cos * ref_harmonics_cos_amplitudes)
209212
tolerance_sin = np.abs(relative_tolerance_sin * ref_harmonics_sin_amplitudes)
210213
tolerance = np.append(tolerance_cos, tolerance_sin, axis=0)

bluemira/equilibria/optimisation/harmonics/toroidal_harmonics_approx_functions.py

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,11 @@ def toroidal_harmonic_grid_and_coil_setup(
256256
R coordinate of the toroidal focus point in cylindrical coordinates
257257
Z_0:
258258
Z coordinate of the toroidal focus point in cylindrical coordinates
259+
tau_limit:
260+
How the maximum tau value is chosen. The three options are:
261+
- LCFS: use the maximum extent of the LCFS
262+
- COIL: use the maximum area within all the coils
263+
- MANUAL: use a specified limit
259264
min_tau_value:
260265
The minimum tau for the toroidal coordinate approximation region,
261266
lower min tau means a larger region of space (maximum tau is at focus)
@@ -799,10 +804,10 @@ def toroidal_harmonics_to_positions(
799804
800805
Returns
801806
-------
802-
:
803-
collocation matrix for cos components
804-
:
807+
harmonics2collocation_cos:
805808
collocation matrix for cos components
809+
harmonics2collocation_sin:
810+
collocation matrix for sin components
806811
807812
Raises
808813
------
@@ -918,7 +923,6 @@ def toroidal_harmonic_approximation(
918923
max_harmonic_mode: int = 5,
919924
*,
920925
plasma_mask: bool = False,
921-
from_psi_fit: bool = True,
922926
) -> ToroidalHarmonicsSelectionResult:
923927
"""
924928
Calculate the toroidal harmonic (TH) amplitudes/coefficients for a given
@@ -954,10 +958,6 @@ def toroidal_harmonic_approximation(
954958
plasma_mask:
955959
Whether or not to apply a mask to the error metric (within the psi_norm flux
956960
surface)
957-
from_psi_fit:
958-
If True then the toroidal harmonics approximation of the coilset contribution
959-
to psi is calculated from fit to the psi values at certain collocation points.
960-
Otherwise, it is calculated from the coilset currents
961961
962962
Returns
963963
-------
@@ -983,13 +983,9 @@ def toroidal_harmonic_approximation(
983983
max_harmonic_mode,
984984
len(th_params.th_coil_names),
985985
)
986-
collocation = (
987-
None
988-
if not from_psi_fit
989-
else collocation_points(
990-
eq.get_LCFS(),
991-
PointType.GRID_POINTS,
992-
)
986+
collocation = collocation_points(
987+
eq.get_LCFS(),
988+
PointType.GRID_POINTS,
993989
)
994990

995991
true_coilset_psi, fixed_psi, collocation_psi = _separate_psi_contributions(
@@ -1011,26 +1007,19 @@ def toroidal_harmonic_approximation(
10111007
sin_m_chosen = mode_values[mode_id[mode_id >= max_harmonic_mode]]
10121008

10131009
# Calculate psi using the combination of poloidal mode numbers (m) selected in
1014-
# this iteration
1015-
if not from_psi_fit:
1016-
error_new, approximate_coilset_psi, cos_amps, sin_amps = (
1017-
_approximation_direct_from_currents(
1018-
eq, th_params, cos_m_chosen, sin_m_chosen, true_coilset_psi, mask
1019-
)
1020-
)
1021-
else:
1022-
error_new, approximate_coilset_psi, cos_amps, sin_amps = (
1023-
_approximation_from_psi_fitting(
1024-
th_params,
1025-
n_degrees_of_freedom,
1026-
collocation,
1027-
mode_id,
1028-
max_harmonic_mode,
1029-
collocation_psi,
1030-
mask,
1031-
true_coilset_psi,
1032-
)
1010+
# this iteration at the collocation points
1011+
error_new, approximate_coilset_psi, cos_amps, sin_amps = (
1012+
_approximation_from_psi_fitting(
1013+
th_params,
1014+
n_degrees_of_freedom,
1015+
collocation,
1016+
mode_id,
1017+
max_harmonic_mode,
1018+
collocation_psi,
1019+
mask,
1020+
true_coilset_psi,
10331021
)
1022+
)
10341023
# If the new error is less than the previously lowest error, then select the
10351024
# current combination of poloidal mode numbers (m), amplitudes and associated psi
10361025
if error_new < error:

documentation/source/equilibria/equilibria.rst

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,122 @@ calculation of the Jacobian of the field constraints. Instead, we choose
659659
to constrain the poloidal field at the centre of the inside edge of each
660660
coil, where the field is generally the highest.
661661

662+
663+
Toroidal Harmonic constraints
664+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
665+
An equilibrium poloidal field has a plasma and coilset contribution. We can use Toroidal Harmonic (TH) functions to approximate the coilset contribution to the poloidal magnetic flux using equations :eq:`PoloidalFlux` and :eq:`ToroidalHarmonics`.
666+
667+
.. math::
668+
:label: PoloidalFlux
669+
670+
\psi = R A = \frac{R_0 \sinh \tau}{\Delta} A
671+
672+
.. math::
673+
:label: ToroidalHarmonics
674+
675+
\begin{aligned}
676+
A(\tau, \sigma) &= \sum_{m=0}^{\infty} A_m^{\cos} \epsilon_m m! \sqrt{\frac{2}{\pi}}
677+
\Delta^{\frac{1}{2}} \textbf{Q}_{m-\frac{1}{2}}^{1}(\cosh \tau) \cos(m \sigma) \\
678+
&+ A_m^
679+
{\sin}
680+
\epsilon_m m! \sqrt{\frac{2}{\pi}} \Delta^{\frac{1}{2}}
681+
\textbf{Q}_{m-\frac{1}{2}}^{1}(\cosh \tau) \sin(m \sigma)\end{aligned}
682+
683+
where
684+
685+
- :math:`\psi` is poloidal flux
686+
687+
- :math:`m` is the poloidal mode number
688+
689+
- :math:`A_m^{\cos, \sin}` are harmonic amplitudes
690+
691+
- :math:`\varepsilon_m = 1` for :math:`m = 0` and :math:`\varepsilon_m = 2` for :math:`m \ge 1`
692+
693+
- :math:`\Delta = \cosh(\tau) - \cos(\sigma)`
694+
695+
- :math:`\textbf{Q}_{\nu}^{\mu}` is Olver's definition of the associated Legendre function of the second kind.
696+
697+
Toroidal coordinates are defined as :math:`\tau = \ln\frac{d_1}{d_2}` and :math:`\sigma = sign(z - z_0) \arccos\frac{d_1^2 + d_2^2 - 4 R_0^2}{2 d_1 d_2}` where, :math:`d_1^2 = (R + R_0)^2 + (z - z_0)^2` and :math:`d_2^2 = (R - R_0)^2 + (z - z_0)^2`, and :math:`R_0` and :math:`Z_0` are the coordinates of the focus point.
698+
699+
Toroidal harmonic amplitudes can be implemented as a set of constraints or targets in a coilset optimisation. The TH amplitudes are used to preserve the coilset contribution in the region occupied by the core plasma (i.e. the region characterised by closed flux surfaces), enabling modification of the poloidal magnetic configuration outside the core region without (significantly) altering the plasma equilibrium.
700+
701+
Potential benefits of using TH as a set of constraints include:
702+
703+
- We can choose not to re-solve for the plasma equilibrium at each optimisation step, since the coilset contribution to the core plasma (within the LCFS) is constrained.
704+
705+
- We have a minimal set of constraints (a set of harmonic amplitudes) for the core plasma contribution, which can reduce the dimensionality of the problem we are considering.
706+
707+
To set up a toroidal harmonic constraint, we first find the significant poloidal modes and their amplitude values using equations :eq:`PoloidalFlux` and :eq:`ToroidalHarmonics`.
708+
709+
The user chooses the:
710+
711+
- Number of degrees of freedom (DoF) appropriate for the given optimisation problem – this limits the number of poloidal modes that can be used in the TH approximation. The default value will allow DoF up to the number of coilset currents being optimised.
712+
713+
- Normalised psi value of the flux surface within which the coilset contribution to psi will be constrained.
714+
715+
Then these values are input in `toroidal_harmonic_approximation`, which iterates through all the combinations of cos and sin modes up to the DoF limit. For each iteration:
716+
717+
- Psi values for a set of sampled positions within the selected flux surface are found and used to determine the amplitudes of the contributing poloidal modes.
718+
719+
- L2 norm of the error between the approximated coilset psi and the true coilset psi is calculated.
720+
721+
The `toroidal_harmonic_approximation` returns the result as a `ToroidalHarmonicsSelectionResult` for the approximate psi with the smallest difference to the true coilset psi in the selected closed flux region. This contains all the information needed to set up a `ToroidalHarmonicConstraint`, as well as supporting information that can be used in analysis.
722+
723+
A `ToroidalHarmonicsSelectionResult` contains the combination of modes (and their amplitude values) that gives the best approximation when compared using an L2 norm of the error across the psi map. These can be then implemented as an :math:`A\bf{x} = b` constraint or magnetic target using equation :eq:`THAmplitudeCurrentRelation`.
724+
725+
.. math::
726+
:label: THAmplitudeCurrentRelation
727+
728+
A_m^{\cos, \sin} = \frac{\mu_0 I_c}{2^{\frac{5}{2}}} factorial\_term \frac{\sinh(
729+
\tau_c)}
730+
{\Delta_c^{\frac{1}{2}}} P_{m - \frac{1}{2}}^{-1}(\cosh(\tau_c)) ^{\cos}_{\sin}(m
731+
\sigma_c)
732+
733+
where
734+
735+
- :math:`A_m^{\cos, \sin}` are hamonic amplitudes for a single coil
736+
737+
- subscript :math:`c` refers to a single coil
738+
739+
- :math:`I_c, \tau_c, \sigma_c` are the coil current, and coil position in toroidal coordinates.
740+
741+
- :math:`P_{m - \frac{1}{2}}^{-1}` is the associated Legendre function of the first kind.
742+
743+
- :math:`\Delta_c = \cosh(\tau_c) - \cos(\sigma_c)`
744+
745+
- :math:`factorial\_term = \prod_{i=0}^{m-1} \left( 1 + \frac{1}{2(m-i)}\right)`
746+
747+
.. figure:: th-flux-comparison.png
748+
:name: fig:th-flux-comparison
749+
750+
Diagram showing a comparison of coilset psi calculated in bluemira and the approximation of coilset psi found using toroidal harmonic functions.
751+
752+
See `here`_ or F. W. J. Olver (1997b) Asymptotics and Special Functions. A. K. Peters, Wellesley, MA. for more information on the Legendre functions used in the TH approximation.
753+
754+
.. _here: https://dlmf.nist.gov/14
755+
756+
Note 1:
757+
758+
The default TH approximation region is set to encompass the the maximum extent of the LCFS, with its focus point at the effective centre of the plasma. However, the function `toroidal_harmonic_grid_and_coil_setup` can be used to approximate a region with a different area and focus point. The optional arguments, which are used to specify where the approximation region is placed, are:
759+
760+
- the maximum extent of the LCFS,
761+
762+
- the maxmimum area that is contained within all coils,
763+
764+
- a user-specified tau limit.
765+
766+
Lower min tau means a larger region of space (the maximum tau is at the focus point).
767+
768+
Note 2:
769+
770+
If a coil is within the TH approximation region then its contribution must be kept fixed during an optimisation. The coilset 'control coils' must be set to be the same as the `th_coil_names` returned in the `ToroidalHarmonicsSelectionResult` while setting up the optimisation problem. Please see 'examples/equilibria/Toroidal_Harmonics_Optimisation_Set_Up.ex.py' for an example.
771+
772+
773+
.. figure:: th-region-and-coils.png
774+
:name: fig:th-region
775+
776+
Diagram showing the default TH approximation region.
777+
662778
Coil position optimisation and constraints
663779
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
664780

174 KB
Loading
120 KB
Loading

examples/equilibria/Toroidal_Harmonics_Optimisation_Set_Up.ex.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@
106106
n_degrees_of_freedom=6,
107107
max_harmonic_mode=5,
108108
plasma_mask=True,
109-
from_psi_fit=True,
110109
)
111110

112111
# %% [markdown]
@@ -133,12 +132,8 @@
133132
# %%
134133
# Create a constraint
135134
th_constraint = ToroidalHarmonicConstraint(
136-
ref_harmonics_cos=result.cos_m,
137-
ref_harmonics_sin=result.sin_m,
138-
ref_harmonics_cos_amplitudes=result.cos_amplitudes,
139-
ref_harmonics_sin_amplitudes=result.sin_amplitudes,
135+
th_result=result,
140136
constraint_type="inequality",
141-
th_params=th_params,
142137
)
143138
# Ensure control coils are set to those that can be used in the toroidal
144139
# harmonic approximation
@@ -147,6 +142,7 @@
147142
# Show the constraint region
148143
f, ax = plt.subplots()
149144
th_constraint.plot(ax=ax)
145+
eq.coilset.plot(ax=ax)
150146
eq.plot(ax=ax)
151147

152148
# %%

0 commit comments

Comments
 (0)