bluemira.utilities.tools ======================== .. py:module:: bluemira.utilities.tools .. autoapi-nested-parse:: A collection of miscellaneous tools. Attributes ---------- .. autoapisummary:: bluemira.utilities.tools.wrap bluemira.utilities.tools.norm bluemira.utilities.tools.dot bluemira.utilities.tools.cross Classes ------- .. autoapisummary:: bluemira.utilities.tools.NumpyJSONEncoder bluemira.utilities.tools.EinsumWrapper bluemira.utilities.tools.ColourDescriptor Functions --------- .. autoapisummary:: bluemira.utilities.tools.json_writer bluemira.utilities.tools.numpy_to_vtk bluemira.utilities.tools.write_csv bluemira.utilities.tools.asciistr bluemira.utilities.tools.levi_civita_tensor bluemira.utilities.tools.floatify bluemira.utilities.tools.iterable_to_list bluemira.utilities.tools.is_num bluemira.utilities.tools.is_num_array bluemira.utilities.tools.abs_rel_difference bluemira.utilities.tools.set_random_seed bluemira.utilities.tools.flatten_iterable bluemira.utilities.tools.consec_repeat_elem bluemira.utilities.tools.slope bluemira.utilities.tools.yintercept bluemira.utilities.tools.ten_power bluemira.utilities.tools.sig_fig_round bluemira.utilities.tools.cross_2d bluemira.utilities.tools.cross_2d_3d bluemira.utilities.tools.cartesian_to_polar bluemira.utilities.tools.polar_to_cartesian bluemira.utilities.tools.toroidal_to_cylindrical bluemira.utilities.tools.cylindrical_to_toroidal bluemira.utilities.tools.compare_dicts bluemira.utilities.tools.get_module bluemira.utilities.tools._loadfromspec bluemira.utilities.tools.get_class_from_module bluemira.utilities.tools.array_or_num bluemira.utilities.tools.deprecation_wrapper bluemira.utilities.tools.qtapp_instance Module Contents --------------- .. py:class:: NumpyJSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) Bases: :py:obj:`json.JSONEncoder` .. autoapi-inheritance-diagram:: bluemira.utilities.tools.NumpyJSONEncoder :parts: 1 :private-bases: A JSON encoder that can handle numpy arrays. .. py:method:: default(o) Override the JSONEncoder default object handling behaviour for np.arrays. :returns: The default json encoder object .. py:function:: json_writer(data: dict[str, Any], file: os.PathLike | str | None = None, *, return_output: bool = False, cls: type[json.JSONEncoder] = NumpyJSONEncoder, **kwargs) -> str | None Write json in the bluemria style. :param data: dictionary to write to json :param filename: filename to write to :param return_output: return the json as a string :param cls: json encoder child class :param kwargs: all further kwargs passed to the json writer :returns: The json dictionary if requested .. py:function:: numpy_to_vtk(data, output_name, scaling=(1, 1, 1)) Convert a numpy array to a VTK image data file. .. py:function:: write_csv(data: numpy.ndarray, base_name: str, col_names: list[str], metadata: str = '', ext: str = '.csv', comment_char: str = '#') Write data in comma-separated value format. :param data: Array of data to be written to csv file. Will raise an error if the dimensionality of the data is not two :param base_name: Name of file to write to, minus the extension. :param col_names: List of strings for column headings for each data field provided. :param metadata: Optional argument for metadata to be written as a header. :param ext: Optional argument for file extension, defaults to ".csv". :param comment_char: Optional argument to specify character(s) to prepend to metadata lines as a comment character (defaults to "#"). :raises ValueError: Columns names not available for all columns .. py:function:: asciistr(length: int) -> str Get a string of characters of desired length. Current max is 52 characters :param length: number of characters to return :rtype: str of length specified :raises ValueError: String length > 52 characters .. py:function:: levi_civita_tensor(dim: int = 3) -> numpy.ndarray N dimensional Levi-Civita Tensor. :param dim: The number of dimensions for the LCT :rtype: np.array (n_0,n_1,...n_n) .. rubric:: Notes The Levi-Civita symbol in n dimensions is defined as: .. math:: \epsilon_{i_1 i_2 \dots i_n} = \begin{cases} \\ +1 & \text{for even permutation of } (1, 2, \dots, n) \\ -1 & \text{for odd permutation of } (1, 2, \dots, n) \\ 0 & \text{for indices are equal} \\ \end{cases} For dim=3, this looks like: .. math:: \epsilon_{ijk} = \begin{cases} 1 & \text{if } (i, j, k) \text{ is } (0, 1, 2), (1, 2, 0), (2, 0, 1) \\ -1 & \text{if } (i, j, k) \text{ is } (0, 2, 1), (2, 1, 0), (1, 0, 2) \\ 0 & \text{otherwise} \end{cases} .. py:class:: EinsumWrapper Preallocator for einsum versions of dot, cross and norm. .. py:attribute:: norm_strs .. py:attribute:: dot_1x1 :value: 'i, i -> ...' .. py:attribute:: dot_1x2 :value: 'i, ik -> k' .. py:attribute:: dot_2x1 :value: 'ij, j -> i' .. py:attribute:: dot_2x2 :value: 'ij, jk -> ik' .. py:attribute:: dot_1xn :value: 'y, {}yz -> {}z' .. py:attribute:: dot_nx1 :value: '{}z, z -> {}' .. py:attribute:: dot_nxn :value: '{}y, {}yz -> {}z' .. py:attribute:: cross_strs .. py:attribute:: cross_lcts .. py:method:: norm(ix: numpy.ndarray, axis: int = 0) -> numpy.ndarray Emulates some of the functionality of np.linalg.norm for 2D arrays. Specifically: np.linalg.norm(ix, axis=0) np.linalg.norm(ix, axis=1) For optimum speed and customisation use np.einsum modified for your use case. :param ix: Array to perform norm on :param axis: axis for the norm to occur on :returns: The norm of the array :raises ValueError: Matrix dimensions >2 unsupported .. py:method:: dot(ix: numpy.ndarray, iy: numpy.ndarray, out: numpy.ndarray | None = None) -> numpy.ndarray A dot product emulation using np.einsum. For optimum speed and customisation use np.einsum modified for your use case. Should follow the same mechanics as np.dot, a few examples: ein_str = 'i, i -> ...' ein_str = 'ij, jk -> ik' # Classic dot product ein_str = 'ij, j -> i' ein_str = 'i, ik -> k' ein_str = 'aij, ajk -> aik' # for loop needed with np.dot :param ix: First array :param iy: Second array :param out: output array for inplace dot product :returns: The dot product of the array :raises ValueError: Undefined dot product behaviour for array shapes .. py:method:: cross(ix: numpy.ndarray, iy: numpy.ndarray, out: numpy.ndarray | None = None) -> numpy.ndarray A row-wise cross product of a 2D matrices of vectors. This function mirrors the properties of np.cross such as vectors of 2 or 3 elements. 1D is also accepted but just do x * y. Only 7D has similar orthogonal properties above 3D. For optimum speed and customisation use np.einsum modified for your use case. :param ix: 1st array to cross :param iy: 2nd array to cross :param out: output array for inplace cross product :returns: the cross product of the arrays :raises ValueError: If the dimensions of the cross product are > 3 .. py:data:: wrap .. py:data:: norm .. py:data:: dot .. py:data:: cross .. py:function:: floatify(x: numpy.typing.ArrayLike) -> float Converts the np array or float into a float by returning the first element or the element itself. :returns: the extracted float :raises ValueError: If array like object has more than 1 element :raises TypeError: If object is None .. rubric:: Notes This function aims to avoid numpy warnings for float(x) for >0 rank scalars it emulates the functionality of float conversion .. py:class:: ColourDescriptor Colour Descriptor for use with dataclasses .. py:attribute:: _default :value: '#' .. py:method:: __set_name__(_, name: str) Set the attribute name from a dataclass .. py:method:: __get__(obj: Any, _) -> str Get the hex colour :returns: The hex colour string .. py:method:: __set__(obj: Any, value: str | tuple[float, Ellipsis] | bluemira.display.palettes.ColorPalette) Set the colour .. rubric:: Notes The value can be anything accepted by matplotlib.colors.to_hex .. py:function:: iterable_to_list(obj: Any | collections.abc.Iterable[Any]) -> list[Any] Convert object(s) to an explicit list of objects :returns: The object converted to a list .. py:function:: is_num(thing: Any) -> bool Determine whether or not the input is a number. :param thing: The input which we need to determine is a number or not :returns: Whether or not the input is a number .. py:function:: is_num_array(thing: Any) -> bool :func:`~bluemira.utilities.tools.is_num` but also includes arrays :returns: Whether or not the input is a number .. py:function:: abs_rel_difference(v2: float, v1_ref: float) -> float Calculate the absolute relative difference between a new value and an old reference value. :param v2: The new value to compare to the old :param v1_ref: The old reference value :returns: The absolute relative difference between v2 and v1ref .. py:function:: set_random_seed(seed_number: int, no_sequences: int = 1) -> list[numpy.random.SeedSequence] Sets the random seed number in numpy and NLopt. Useful when repeatable results are desired in Monte Carlo methods and stochastic optimisation methods. :param seed_number: The random seed number, preferably a very large integer :param no_sequences: The number of seed sequences to produce :returns: The requested seed sequences .. py:function:: flatten_iterable(iters: collections.abc.Iterable[Any]) Expands a nested iterable structure, flattening it into one iterable :param iters: The object(s) to de-nest :Yields: elements of iterable .. rubric:: Notes Does not cater for nested dictionaries .. py:function:: consec_repeat_elem(arr: numpy.ndarray, num_rep: int) -> numpy.ndarray Get array of repeated elements with n or more repeats :param arr: array to find repeats in :param num_rep: number of repetitions to find :returns: The repeated element array .. py:function:: slope(arr: numpy.ndarray) -> float Calculate gradient of a 2x2 point array :returns: The gradient of the array .. py:function:: yintercept(arr: numpy.ndarray) -> tuple[float, float] Calculate the y intercept and gradient of an array :returns: The y-intercept of the array .. py:function:: ten_power(x) Get the power for the base ten notation, set 0 to 0. :returns: the nearest log10 power .. py:function:: sig_fig_round(x, s, low_lim=-16) Fuction to round to a given number of significant figures, with any number below a lower limit set to zero. :param x: value or values to round. :param s: number of significant figures :param low_lim: power below which values are set to 0, default: low_lim = -16 (i.e, numbers below 1e-16) :returns: Rounded value .. py:function:: cross_2d(v1: numpy.typing.ArrayLike, v2: numpy.typing.ArrayLike) -> numpy.float64 Cross products of 2d vectors, since numpy >= v2 deprecated support for 2d vector inputs in np.cross. :param v1: 2d vector :param v2: 2d vector :returns: The cross product of the two vectors .. py:function:: cross_2d_3d(v1: numpy.typing.ArrayLike, v2: numpy.typing.ArrayLike) -> numpy.ndarray Cross products of pairs of 2d or 3d vectors, since numpy >= v2 deprecated support for 2d vector inputs in np.cross. For when needing to handle both cases :param v1: Vector 1 :param v2: Vector 2 :returns: The cross product of the two vectors .. py:function:: cartesian_to_polar(x: numpy.ndarray, z: numpy.ndarray, x_ref: float = 0.0, z_ref: float = 0.0) -> tuple[numpy.ndarray, numpy.ndarray] Convert from 2-D Cartesian coordinates to polar coordinates about a reference point. :param x: Radial coordinates :param z: Vertical coordinates :param x_ref: Reference radial coordinate :param z_ref: Reference vertical coordinate :returns: * *r* -- Polar radial coordinates * *phi* -- Polar angle coordinates .. py:function:: polar_to_cartesian(r: numpy.ndarray, phi: numpy.ndarray, x_ref: float = 0.0, z_ref: float = 0.0) -> tuple[numpy.ndarray, numpy.ndarray] Convert from 2-D polar to Cartesian coordinates about a reference point. :param r: Polar radial coordinates :param phi: Polar angle coordinates :param x_ref: Reference radial coordinate :param z_ref: Reference vertical coordinate :returns: * *x* -- Radial coordinates * *z* -- Vertical coordinate .. py:function:: toroidal_to_cylindrical(R_0: float, Z_0: float, tau: numpy.ndarray, sigma: numpy.ndarray) Convert from toroidal coordinates to cylindrical coordinates in the poloidal plane Toroidal coordinates are denoted by (\tau, \sigma, \phi) Cylindrical coordinates are denoted by (r, z, \phi) We are in the poloidal plane so take the angle \phi = 0 .. math:: R = R_{0} \frac{\sinh{\tau}}{\cosh{\tau} - \cos{\sigma}} z = R_{0} \frac{\sin{\tau}}{\cosh{\tau} - \cos{\sigma}} + z_{0} :param R_0: r coordinate of focus in poloidal plane :param Z_0: z coordinate of focus in poloidal plane :param tau: the tau coordinates to transform :param sigma: the sigma coordinates to transform :returns: Tuple of transformed coordinates in cylindrical form :rtype: R, Z .. py:function:: cylindrical_to_toroidal(R_0: float, Z_0: float, R: numpy.ndarray, Z: numpy.ndarray) Convert from cylindrical coordinates to toroidal coordinates in the poloidal plane Toroidal coordinates are denoted by (\tau, \sigma, \phi) Cylindrical coordinates are denoted by (r, z, \phi) We are in the poloidal plane so take the angle \phi = 0 .. math:: \tau = \ln\frac{d_{1}}{d_{2}} \sigma = sign(z - z_{0}) \arccos\frac{d_{1}^2 + d_{2}^2 - 4 R_{0}^2}{2 d_{1} d_{2}} d_{1}^2 = (R + R_{0})^2 + (z - z_{0})^2 d_{2}^2 = (R - R_{0})^2 + (z - z_{0})^2 :param R_0: r coordinate of focus in poloidal plane :param Z_0: z coordinate of focus in poloidal plane :param R: the r coordinates to transform :param Z: the z coordinates to transform :returns: Tuple of transformed coordinates in toroidal form :rtype: tau, sigma .. py:function:: compare_dicts(d1: dict[str, Any], d2: dict[str, Any], *, almost_equal: bool = False, verbose: bool = True, rtol: float = 1e-05, atol: float = 1e-08) -> bool Compares two dictionaries. Will print information about the differences between the two to the console. Dictionaries are compared by length, keys, and values per common keys :param d1: The reference dictionary :param d2: The dictionary to be compared with the reference :param almost_equal: Whether or not to use np.isclose and np.allclose for numbers and arrays :param verbose: Whether or not to print to the console :param rtol: The relative tolerance parameter, used if ``almost_equal`` is True :param atol: The absolute tolerance parameter, used if ``almost_equal`` is True :rtype: Whether or not the dictionaries are the same .. py:function:: get_module(name: str) -> types.ModuleType Load module dynamically. :param name: Filename or python path (a.b.c) of module to import :returns: Loaded module :raises ImportError: Unable to import module .. py:function:: _loadfromspec(name: str) -> types.ModuleType Load module from filename. :param name: Filename of module to import :returns: Loaded module :raises ImportError: Unable to import module :raises FileNotFoundError: Cant find specified module file :raises ModuleNotFoundError: Cant find module .. py:function:: get_class_from_module(name: str, default_module: str = '') -> type Load a class from a module dynamically. :param name: Filename or python path (a.b.c) of module to import, with specific class to load appended following :: e.g. my_package.my_module::my_class. If the default_module is provided then only the class name (e.g. my_class) needs to be provided. :param default_module: The default module to search for the class, by default "". If provided then if name does not contain a module path then this the default module will be used to search for the class. Can be overridden if the name provides a module path. :returns: Loaded class :raises ImportError: Unable to import class from module .. py:function:: array_or_num(array: Any) -> numpy.ndarray | float Always returns a numpy array or a float :param array: The value to convert into a numpy array or number. :rtype: The value as a numpy array or number. :raises TypeError: If the value cannot be converted to a numpy or number. .. py:function:: deprecation_wrapper(message: collections.abc.Callable[[Any], Any] | str | None) -> collections.abc.Callable[[Any], Any] Deprecate any callable. :param message: The callable to deprecate or the message to show :returns: The wrapped function .. py:function:: qtapp_instance() -> PySide6.QtWidgets.QApplication Get at QtWidgets.QApplication instance Can be used as a crude way to detect ipython/jupyter instances :returns: QApplication instance