bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions ===================================================================== .. py:module:: bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions .. autoapi-nested-parse:: Spherical harmonics classes and calculations. Classes ------- .. autoapisummary:: bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.PointType bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.Collocation Functions --------- .. autoapisummary:: bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.coil_harmonic_amplitude_matrix bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.harmonic_amplitude_marix bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.collocation_points bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.fs_fit_metric bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.coils_outside_fs_sphere bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.get_psi_harmonic_amplitudes bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.spherical_harmonic_approximation bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.plot_psi_comparision Module Contents --------------- .. py:function:: coil_harmonic_amplitude_matrix(input_coils: bluemira.equilibria.coils.CoilSet, max_degree: int, r_t: float, sh_coil_names: list, sig_figures: int = 15) -> numpy.ndarray Construct matrix from harmonic amplitudes at given coil locations. To get an array of spherical harmonic amplitudes/coefficients (A_l) which can be used in a spherical harmonic approximation of the vacuum/coil contribution to the poloidal flux (psi) do: A_l = matrix harmonic amplitudes @ vector of coil currents A_l can be used as constraints in optimisation, see spherical_harmonics_constraint. N.B. for a single filament (coil): .. math:: A_{l} = \frac{1}{2} \mu_{0} I_{f} \sin{\theta_{f}} (\frac{r_{t}}{r_{f}})^l \frac{P_{l} \cos{\theta_{f}}}{\sqrt{l(l+1)}} Where l = degree, and :math: P_{l} \cos{\theta_{f}} are the associated Legendre polynomials of degree l and order (m) = 1. :param input_coils: Bluemira CoilSet :param max_degree: Maximum degree of harmonic to calculate up to :param r_t: Typical length scale (e.g. radius at outer midplane) :param sh_coil_names: Names of the coils to use with SH approximation (always located outside bdry_r) :param sig_figures: Number of significant figures for rounding currents2harmonics values :returns: Matrix of harmonic amplitudes :rtype: currents2harmonics .. py:function:: harmonic_amplitude_marix(collocation_r: numpy.ndarray, collocation_theta: numpy.ndarray, r_t: float, sig_figures: int = 15) -> numpy.ndarray Construct matrix from harmonic amplitudes at given points (in spherical coords). The matrix is used in a spherical harmonic approximation of the vacuum/coil contribution to the poloidal flux (psi): .. math:: \psi = \sum{A_{l} \frac{r^{l+1}}{r_{t}^l} \sin{\theta_{f}} \frac{P_{l} \cos{\theta_{f}}}{\sqrt{l(l+1)}}} Where l = degree, A_l are the spherical harmonic coefficients/amplitudes, and :math: P_{l} \cos{\theta_{f}} are the associated Legendre polynomials of degree l and order (m) = 1. N.B. Vacuum Psi = Total Psi - Plasma Psi. :param collocation_r: R values of collocation points :param collocation_theta: Theta values of collocation points :param r_t: Typical length scale (e.g. radius at outer midplane) :param sig_figures: Number of significant figures for rounding harmonics2collocation values :returns: **harmonics2collocation** -- Matrix of harmonic amplitudes (to get spherical harmonic coefficients use matrix @ coefficients = vector psi_vacuum at collocation points) :rtype: np.array .. py:class:: PointType(*args, **kwds) Bases: :py:obj:`enum.Enum` .. autoapi-inheritance-diagram:: bluemira.equilibria.optimisation.harmonics.harmonics_approx_functions.PointType :parts: 1 :private-bases: Class for use with collocation_points function. User can choose how the collocation points are distributed. .. py:attribute:: ARC .. py:attribute:: ARC_PLUS_EXTREMA .. py:attribute:: RANDOM .. py:attribute:: RANDOM_PLUS_EXTREMA .. py:attribute:: GRID_POINTS .. py:class:: Collocation Dataclass for collocation point locations. .. py:attribute:: r :type: numpy.ndarray .. py:attribute:: theta :type: numpy.ndarray .. py:attribute:: x :type: numpy.ndarray .. py:attribute:: z :type: numpy.ndarray .. py:function:: collocation_points(plasma_boundary: bluemira.geometry.coordinates.Coordinates, point_type: PointType, n_points: int = 10, seed: int | None = None, grid_num: tuple[int, int] | None = None) -> Collocation Create a set of collocation points for use wih spherical harmonic approximations. Points are found within the user-supplied boundary and should correspond to the LCFS (or similar) of a chosen equilibrium. Current functionality is for: - equispaced points on an arc of fixed radius, - equispaced points on an arc plus extrema, - random points within a circle enclosed by the boundary, - random points plus extrema, - a grid of points containing the boundary. :param n_points: Number of points/targets (not including extrema - these are added automatically if relevant). For use with point_type 'arc', 'arc_plus_extrema', 'random', 'random_plus_extrema', or 'grid_num'. For 'grid_num' it will create an n_points by n_points grid (see grid_num for a non square grid.) :param plasma_boundary: XZ coordinates of the plasma boundary :param point_type: Method for creating a set of points: 'arc', 'arc_plus_extrema', 'random', or 'random_plus_extrema', 'grid_points' :param seed: Seed value to use with a random point distribution, defaults to `RNGSeeds.equilibria_harmonics.value`. For use with 'random' or 'random_plus_extrema' point_type. :param grid_num: Tuple with the number of desired grid points in the x and z direction. For use with 'grid_points' point_type. :returns: Collocation points .. py:function:: fs_fit_metric(coords1: bluemira.geometry.coordinates.Coordinates, coords2: bluemira.geometry.coordinates.Coordinates) -> float Calculate the value of the metric used for evaluating the SH&TH approximation. This is equal to 1 for non-intersecting flux surfaces, and 0 for identical surfaces. The flux surface of interest is usually the LCFS, or a closed flux surface that is close to the last closed flux surface., e.g., psi_norm = 0.95 or 0.98. :param coords1: Coordinates of plasma boundary from input equilibrium state :param coords2: Coordinates of plasma boundary from approximation equilibrium state :returns: Measure of how 'good' the approximation is. fit_metric_value = total area within one but not both FSs / (input FS area + approximation FS area) :rtype: fit_metric_value .. py:function:: coils_outside_fs_sphere(eq: bluemira.equilibria.equilibrium.Equilibrium, psi_norm: float | None = None) -> tuple[list, float] Find the coils located outside of the sphere containing the core plasma, e.g., LCFS of the equilibrium state. :param eq: Starting equilibrium to use for our approximation :returns: * *c_names or not_too_close_coils* -- coil names selected appropriately for use of SH approximation * *bdry_r* -- maximum radial value for fs of starting equilibria * *psi_norm* -- Normalised flux value of the surface of interest. None value will default to LCFS. .. py:function:: get_psi_harmonic_amplitudes(vacuum_psi: numpy.ndarray, grid: bluemira.equilibria.grid.Grid, collocation: Collocation, r_t: float, sig_figures: int = 15) -> numpy.ndarray Calculate the Spherical Harmonic (SH) amplitudes/coefficients needed to produce a SH approximation of the vacuum (i.e. control coil) contribution to the poloidal flux (psi).The number of degrees used in the approximation is one less than the number of collocation points. :param vacuum_psi: Psi contribution from coils that we wish to approximate :param grid: Associated grid :param collocation: Collocation points :param r_t: Typical length scale for spherical harmonic approximation (default = maximum x value of LCFS). :param sig_figures: Number of significant figures for rounding psi_harmonic_amplitudes values :returns: SH coefficients for given number of degrees :rtype: psi_harmonic_amplitudes .. py:function:: spherical_harmonic_approximation(eq: bluemira.equilibria.equilibrium.Equilibrium, n_points: int = 8, point_type: PointType = PointType.ARC_PLUS_EXTREMA, grid_num: tuple[int, int] | None = None, acceptable_fit_metric: float = 0.01, psi_norm: float | None = None, nlevels: int = 50, seed: int | None = None, sig_figures: int = 15, *, plot: bool = False) -> tuple[list, numpy.ndarray, int, float, numpy.ndarray, float, numpy.ndarray] Calculate the spherical harmonic (SH) amplitudes/coefficients needed as a reference value for the 'spherical_harmonics_constraint' used in coilset optimisation. Use a FS fit metric to determine the required number of degrees. The number of degrees used in the approximation is one less than the number of collocation points. :param eq: Equilibria to use as starting point for approximation. We will approximate psi using SHs - the aim is to keep the core plasma contribution fixed (using SH amplitudes as constraints) while being able to vary the vacuum (coil) contribution, so that we do not need to re-solve for the equilibria during optimisation. :param n_points: Number of desired collocation points (default=8) excluding extrema (always +4 automatically) :param point_type: Name that determines how the collocation points are selected, (default="arc_plus_extrema"). The following options are available for collocation point distribution: - 'arc' = equispaced points on an arc of fixed radius, - 'arc_plus_extrema' = 'arc' plus the min and max points of either the LCFS or a flux surface with a chosen normalised flux value. in the x- and z-directions (4 points total), - 'random', - 'random_plus_extrema'. - 'grid_points' :param grid_num: Number of points in x-direction and z-direction, to use with grid point distribution. :param acceptable_fit_metric: The default flux surface (FS) used for this metric is the LCFS. (psi_norm value is used to select an alternative) If the FS found using the SH approximation method perfectly matches the FS of the input equilibria then the fit metric = 0. A fit metric of 1 means that they do not overlap at all. fit_metric_value = total area within one but not both FSs / (input FS area + approximation FS area) :param psi_norm: Normalised flux value of the surface of interest. None value will default to LCFS. :param nlevels: Plot setting, higher n = greater number of contour lines :param seed: Seed value to use with random point distribution :param sig_figures: Number of significant figures for rounding during SH approximation :param plot: Whether or not to plot the results :returns: * *sh_coil_names* -- Names of the coils to use with SH approximation (always located outside bdry_r) * *coil_current_harmonic_amplitudes* -- SH coefficients/amplitudes for required number of degrees * *degree* -- Number of degrees required for a SH approx with the desired fit metric * *fit_metric_value* -- Fit metric achieved * *approx_total_psi* -- Total psi obtained using the SH approximation * *bdry_r* -- Approximation boundary - sphere containing core plasma for chosen equilibrium. * *sh_eq.coilset.current* -- Coil currents found using the spherical harmonic approximation :raises EquilibriaError: Problem not setup for harmonics .. note:: The coil_harmonic_amplitude_matrix often has a high sensitivity to small numbers. To address numerical reproducability across different machines: - Even harmonic amplitudes are set to zero. - Currents found using lstsq are rounded before being used to calculate the FS fit metric. .. py:function:: plot_psi_comparision(grid: bluemira.equilibria.grid.Grid, eq: bluemira.equilibria.equilibrium.Equilibrium, vac_psi_app: numpy.ndarray, axes: list[matplotlib.pyplot.Axes] | None = None, nlevels: int = 50, original_flux_surface: bluemira.geometry.coordinates.Coordinates | None = None, approx_flux_surface: bluemira.geometry.coordinates.Coordinates | None = None, *, show: bool = True) -> tuple[matplotlib.pyplot.Axes, Ellipsis] Create plot comparing an original psi to psi obtained from harmonic approximation. :param grid: Need x and z values to plot psi. :param eq: Starting Equilibrium :param vac_psi_app: Approximation Vacuum Psi (contribution from entire coilset) :param axes: List of Matplotlib Axes objects set by user :param nlevels: Plot setting, higher n = greater number of contour lines :param original_flux_surface: Coordinates of flux surcae of interest (e.g. LCFS) for starting equilibrium :param approx_flux_surface: Coordinates of flux surcae of interest (e.g. LCFS) from approximation :param show: Whether or not to display the plot :returns: The Matplotlib Axes objects for each subplot. :rtype: plot1, plot2, plot3, plot4 :raises ValueError: 4 plots must be provided