bluemira.equilibria.find ======================== .. py:module:: bluemira.equilibria.find .. autoapi-nested-parse:: Methods for finding O- and X-points and flux surfaces on 2-D arrays. Classes ------- .. autoapisummary:: bluemira.equilibria.find.Xpoint bluemira.equilibria.find.Opoint bluemira.equilibria.find.Lpoint bluemira.equilibria.find.OPointCalcOptions Functions --------- .. autoapisummary:: bluemira.equilibria.find.o_point_fallback_calculator bluemira.equilibria.find.find_OX_points bluemira.equilibria.find.get_contours bluemira.equilibria.find.find_flux_surf bluemira.equilibria.find.find_LCFS_separatrix bluemira.equilibria.find.grid_2d_contour bluemira.equilibria.find.in_plasma bluemira.equilibria.find.in_zone Module Contents --------------- .. py:class:: Xpoint(x: float, z: float, psi: float) Bases: :py:obj:`PsiPoint` .. autoapi-inheritance-diagram:: bluemira.equilibria.find.Xpoint :parts: 1 :private-bases: X-point class. .. py:attribute:: __slots__ :value: () .. py:class:: Opoint(x: float, z: float, psi: float) Bases: :py:obj:`PsiPoint` .. autoapi-inheritance-diagram:: bluemira.equilibria.find.Opoint :parts: 1 :private-bases: O-point class. .. py:attribute:: __slots__ :value: () .. py:class:: Lpoint(x: float, z: float, psi: float) Bases: :py:obj:`PsiPoint` .. autoapi-inheritance-diagram:: bluemira.equilibria.find.Lpoint :parts: 1 :private-bases: Limiter point class. .. py:attribute:: __slots__ :value: () .. py:class:: OPointCalcOptions(*args, **kwds) Bases: :py:obj:`enum.Enum` .. autoapi-inheritance-diagram:: bluemira.equilibria.find.OPointCalcOptions :parts: 1 :private-bases: O point estimation fallback options .. py:attribute:: RAISE .. py:attribute:: GRID_CENTRE .. py:attribute:: MAJOR_RADIUS .. py:function:: o_point_fallback_calculator(o_point_fallback: OPointCalcOptions, x: numpy.typing.NDArray, z: numpy.typing.NDArray, psi: numpy.typing.NDArray | collections.abc.Callable[[float, float], float] | None, R_0: float | None = None) -> list[Opoint] Calculate fallback options for O point finding. :param o_point_fallback: Selection of fallback type :param x: x point(s) to use. If using psi callable the x point itself :param z: z point(s) to use. If using psi callable the z point itself :param psi: psi array or callable. When the callable is used psi is calculated with x and z as inputs, :param R_0: R_O value used for major radius fallback :returns: Calculated O-point :raises ValueError: Raised when R_0 not provided for major radius fallback :raises EquilibriaError: Raised when raise fallback is used .. py:function:: find_OX_points(x: numpy.typing.NDArray[numpy.float64], z: numpy.typing.NDArray[numpy.float64], psi: numpy.typing.NDArray[numpy.float64], limiter: bluemira.equilibria.limiter.Limiter | None = None, *, field_cut_off: float = 1.0, o_point_fallback: OPointCalcOptions = OPointCalcOptions.GRID_CENTRE, R_0: float | None = None) -> tuple[list[Opoint], list[Xpoint | Lpoint]] Finds O-points and X-points by minimising the poloidal field. :param x: The spatial x coordinates of the grid points [m] :param z: The spatial z coordinates of the grid points [m] :param psi: The poloidal magnetic flux map [V.s/rad] :param limiter: The limiter to use (if any) :param field_cut_off: The field above which local minima are not searched [T]. Must be > 0.1 T :returns: * *o_points* -- The O-points in the psi map * **x_points** (*List[Union[Xpoint,LPoint]]*) -- The X-points and L-points in the psi map .. rubric:: Notes :math:`\lvert{\nabla}{\psi}{\lvert}^{2} = 0` Local minima brute-forced, and subsequent accurate locations of the points found by local optimisation. For speed, does this on existing psi map (not exactly at optimum). Points are order w.r.t. central grid coordinates. .. py:function:: get_contours(x: numpy.typing.NDArray[numpy.float64], z: numpy.typing.NDArray[numpy.float64], array: numpy.typing.NDArray[numpy.float64], value: float) -> list[numpy.typing.NDArray[numpy.float64]] Get the contours of a value in continuous array. :param x: The x value array :param z: The z value array :param array: The value array :param value: The value of the desired contour in the array :type value: f :returns: The list of arrays of value contour(s) in the array .. py:function:: find_flux_surf(x: numpy.typing.NDArray[numpy.float64], z: numpy.typing.NDArray[numpy.float64], psi: numpy.typing.NDArray[numpy.float64], psinorm: float, o_points: list[Opoint] | None = None, x_points: list[Xpoint] | None = None) -> numpy.typing.NDArray[numpy.float64] Picks a flux surface with a normalised psinorm relative to the separatrix. Uses least squares to retain only the most appropriate flux surface. This is taken to be the surface whose geometric centre is closest to the O-point :param x: The spatial x coordinates of the grid points [m] :param z: The spatial z coordinates of the grid points [m] :param psi: The poloidal magnetic flux map [V.s/rad] :param psinorm: The normalised psi value of the desired flux surface [-] :param o_points: O-points to use to calculate psinorm :param x_points: X-points to use to calculate psinorm (saves time if you have them) :returns: The flux surface coordinate array :raises EquilibriaError: No flux surface found at psi_norm .. rubric:: Notes :math:`{\Psi}_{N} = {\psi}_{O}-N({\psi}_{O}-{\psi}_{X})` Uses matplotlib hacks to pick contour surfaces on psi(X, Z). .. py:function:: find_LCFS_separatrix(x: numpy.typing.NDArray[numpy.float64], z: numpy.typing.NDArray[numpy.float64], psi: numpy.typing.NDArray[numpy.float64], o_points: list[Opoint] | None = None, x_points: list[Xpoint] | None = None, *, double_null: bool = False, psi_n_tol: float = 1e-06, delta_start: float = 0.01, rtol: float = 0.001) -> tuple[bluemira.geometry.coordinates.Coordinates, bluemira.geometry.coordinates.Coordinates | list[bluemira.geometry.coordinates.Coordinates]] Find the "true" LCFS and separatrix(-ices) in an Equilibrium. :param x: The spatial x coordinates of the grid points [m] :param z: The spatial z coordinates of the grid points [m] :param psi: The poloidal magnetic flux map [V.s/rad] :param o_points: The O-points in the psi map :param x_points: The X-points in the psi map :param double_null: Whether or not to search for a double null separatrix. :param psi_n_tol: The normalised psi tolerance to use :param delta_start: Search range value. Will search for the transition from a "closed" to "open" flux surface for normalised flux values between 1 - delta_start and 1 + delta_start. :returns: * *lcfs* -- The last closed flux surface * *separatrix* -- The plasma separatrix (first open flux surface). Will return a list of Coordinates for double_null=True, with all four separatrix legs being captured. .. rubric:: Notes We need to find the transition between the LCFS and the first "open" flux surface. In theory this would be for psi_norm = 1, however because of grids and interpolation this isn't exactly the case. So we search for the normalised flux value where the flux surface first goes from being open to closed. .. py:function:: grid_2d_contour(x: numpy.ndarray, z: numpy.ndarray) -> tuple[numpy.ndarray, numpy.ndarray] Grid a smooth contour and get the outline of the cells it encompasses. :param x: The closed ccw x coordinates :param z: The closed ccw z coordinates :returns: * *x_new* -- The x coordinates of the grid-coordinates * *z_new* -- The z coordinates of the grid-coordinates .. py:function:: in_plasma(x: numpy.typing.NDArray[numpy.float64], z: numpy.typing.NDArray[numpy.float64], psi: numpy.typing.NDArray[numpy.float64], o_points: list[Opoint] | None = None, x_points: list[Xpoint] | None = None, *, include_edges: bool = False) -> numpy.typing.NDArray[numpy.float64] Get a psi-shaped mask of psi where 1 is inside the plasma, 0 outside. :param x: The radial coordinates of the grid points :param z: The vertical coordinates of the grid points :param psi: The poloidal magnetic flux map [V.s/rad] :param o_points: O-points to use to calculate psinorm :param x_points: X-points to use to calculate psinorm (saves time if you have them) :rtype: Masking matrix for the location of the plasma [0 outside/1 inside] .. py:function:: in_zone(x: numpy.typing.NDArray[numpy.float64], z: numpy.typing.NDArray[numpy.float64], zone: numpy.typing.NDArray[numpy.float64], *, include_edges: bool = False) Get a masking matrix for a specified zone. :param x: The x coordinates array :param z: The z coordinates array :param zone: The array of point coordinates delimiting the zone :rtype: The masking array where 1 denotes inside the zone, and 0 outside