        If a catalogue is not supplied, this will generate one by cutting up
        the image into cutouts.


        Simple function that outputs png files from the input fits files

        Parameters
        ----------
        Scores : string
            Score of sample

        Returns
        -------
        png : image object
            Images are created and saved in the output folder


        Stores the LOF object to the output directory to allow quick
        rerunning on new data.


        Does the work in actually running the algorithm.

        Parameters
        ----------
        features : pd.DataFrame or similar
            The input features to run the algorithm on. Assumes the index is
            the id of each object and all columns are to be used as features.

        Returns
        -------
        pd.DataFrame
            Contains the same original index of the features input and the
            anomaly scores. More negative is more anomalous.


        Stores the iforest object to the output directory to allow quick
        rerunning on new data.


        Does the work in actually running isolation forest.

        Parameters
        ----------
        features : pd.DataFrame or similar
            The input features to run iforest on. Assumes the index is the id
            of each object and all columns are to
            be used as features.

        Returns
        -------
        pd.DataFrame
            Contains the same original index of the features input and the
            anomaly scores. More negative is more anomalous.


        Does the work in actually running the scaler.

        Parameters
        ----------
        df : pd.DataFrame or similar
            The input anomaly scores to rescale.

        Returns
        -------
        pd.DataFrame

        Contains the same original index and columns of the features input
        with the anomaly score scaled according to the input arguments in
        __init__.


        Simple function that is dominated by the (predicted) user score in
        regions where we are reasonably sure about our ability to predict that
        score, and is dominated by the anomaly score from an algorithms in
        regions we have little data.

        Parameters
        ----------
        nearest_neighbour_distance : array
            The distance of each instance to its nearest labelled neighbour.
        user_score : array
            The predicted user score for each instance
        anomaly_score : array
            The actual anomaly score from a machine learning algorithm

        Returns
        -------
        array
            The final anomaly score for each instance, penalised by the
            predicted user score as required.


        Calculates the distance of each instance to its nearest labelled
        neighbour.

        Parameters
        ----------
        features_with_labels : pd.DataFrame
            A dataframe where the first columns are the features  and the last
            two columns are 'human_label' and 'score' (the anomaly score from
            the ML algorithm).

        Returns
        -------
        array
            Distance of each instance to its nearest labelled neighbour.


        Uses machine learning to predict the user score for all the data. The
        labels are provided in the column 'human_label' which must be -1 if no
        label exists.

        Parameters
        ----------
        features_with_labels : pd.DataFrame
            A dataframe where the first columns are the features  and the last
            two columns are 'human_label' and 'score' (the anomaly score from
            the ML algorithm).

        Returns
        -------
        dict
            Dictionary containing the predicted user score for each instance
            and, if applicable for the regression algorithm, an estimate of
            the uncertainty that can be used as an aquisition score.


Convenience function to correctly combine dataframes.


        Does the work in actually running the NeighbourScore.

        Parameters
        ----------
        features_with_labels : pd.DataFrame
            A dataframe where the first columns are the features  and the last
            two columns are 'human_label' and 'score' (the anomaly score from
            the ML algorithm).

        Returns
        -------
        pd.DataFrame
            Contains the final scores using the same index as the input.


        Stores the estimator object to the output directory to allow quick
        rerunning on new data.


        Calculates the expected improvement to use as an acquisition function.
        Same as used in Walmsley et al. 2021. Code taken from
        https://modal-python.readthedocs.io/en/latest/_modules/modAL/acquisition.html#max_EI

        Parameters
        ----------
        mean : np.array
            The predicted mean from the GP
        std : np.array
            The standard deviation from the GP
        max_val : float
            The current maximum user score seen so far


        Does the work in actually running estimator.

        Parameters
        ----------
        data : pd.DataFrame or similar
            The anomalies dataframe that must include the column human_labels.

        Returns
        -------
        pd.DataFrame
            Contains the same original index of the features input and the
            anomaly scores.


    Converts a pybdsf fits/srl/gaul file to a pandas dataframe to be given
    directly to an ImageDataset object.

    Parameters
    ----------
    catalogue_file : string
        Pybdsf catalogue in fits table format or srl using csv separators
    image_file:
        The image corresponding to this catalogue (to extract pixel information
        and naming information)
    remove_point_sources: bool, optional
        If true will remove all sources with an S_Code of 'S'
    merge_islands: bool, optional
        If true, will locate all sources belonging to a particular island and
        merge them, using the centre of mass as the new source centre
    min_components: int, optional
        If greater than zero, not only will point sources be removed but also
        islands containing fewer than min_components Gaussians. The catalogue
        will then use the centre of mass of the island as the source's centre.
        This effectively enforces merge_islands to be true and forces the
        source identifier key to the Isl_id.
    adaptive_size: bool, optional
        If true, will include a size column in the output catalogue to indicate
        the expected size of the source (in pixels). This requires the island
        contours to be saved as a json file which must be provided.
    islands_file : string, optional
        A json file containing the output of the island[idx].contour paramter
        when running pybdsf from python. This should be a dictionary with the
        island index as key and the contour (a list of x values and a list of
        y values) as value.
    read_csv_kwargs: dict, optional
        Will pass these directly to panda's read_csv function to allow reading
        in of a variety of file structures (e.g. different delimiters)
    colnames: dict, optional
        Allows you to choose the column names for "source_identifier" (which
        column to use to identify the source), "Isl_id", "Peak_flux" and
        "S_Code" (if
        remove_point_sources is true)


    Creates a catalogue of the most anomalous sources in the form of an excel
    spreadsheet that includes cutout images.

    Parameters
    ----------
    image_dataset : astronomaly.data_management.image_reader.ImageDataset
        The image dataset
    scores : pd.DataFrame
        The list of objects to convert to spreadsheet. NOTE: This must already
        be sorted in the order you want in the spreadsheet and limited to the
        number you want displayed.
    filename : str, optional
        Filename for spreadsheet, by default 'anomaly_catalogue.xlsx'
    ignore_nearby_sources : bool, optional
        If true, will search for nearby objects before adding to the
        spreadsheet and will only add if no source is found within
        source_radius degrees, by default True
    source_radius : float, optional
        Number of degrees to exclude nearby sources by in degrees, default
        0.016 degrees


    Creates a catalogue that contains sources which require a larger window
    or cutout size. Also contains the recommended windows size required.

    Parameters
    ----------
    image_dataset : astronomaly.data_management.image_reader.ImageDataset
        The image dataset
    features : pd.DataFrame
        Dataframe containing the extracted features about the sources. Used to
        obtain the ellipse warning column.
    filename : str, optional
        Filename for spreadsheet, by default 'ellipse_catalogue.csv'


        Matplotlib event handler for left and right arrows to cycle through
        images.

        Parameters
        ----------
        event

        Returns
        -------


Creates the plots and binds the event handler


    Converts a tractor fits file to a pandas dataframe to be given
    directly to an ImageDataset object.

    Parameters
    ----------
    catalogue_files : string
        tractor catalogue in fits table format
    image_file:
        The image corresponding to this catalogue (to extract pixel information
        and naming information)


    Simple function that outputs a certain number of png files
    from the input fits files

    Parameters
    ----------
    image_dataset : astronomaly.data_management.image_reader.ImageDataset
        The image dataset
    number_of_images : integer
        Sets the number of images to be created by the function
    data_dir : directory
        Location of data directory.
        Needed to create output folder for the images.

    Returns
    -------
    png : image object
        Images are created and saved in the output folder


    Function that removes the corrupt or missing file
    from the metadata and from the metadata index.

    Parameters
    ----------
    met : pd.DataFrame
        The metadata of the dataset
    ind : string
        The index of the metadata
    idx : string
        The index of the source file


    Protege requires an initial sample to obtain user scores for. This sorts
    the features by the first column (assuming it corresponds to the first
    principal component) and then selects N sources (usually 10) equally spaced
    across this feature.

    Parameters
    ----------
    features : pd.DataFrame
        The features to select sources from. Assumed to already by PCA reduced.
    N : int
        The number of initial sources to select


        Does the work in actually running the pipeline stage.

        Parameters
        ----------
        features : pd.DataFrame or similar
            The input features to run on. Assumes the index is the id
            of each object and all columns are to be used as features.

        Returns
        -------
        pd.DataFrame
            Returns a dataframe with the same index as the input features and
            two columns, one for each dimension of the UMAP plot.


        Does the work in actually running the pipeline stage.

        Parameters
        ----------
        features : pd.DataFrame or similar
            The input features to run on. Assumes the index is the id
            of each object and all columns are to be used as features.

        Returns
        -------
        pd.DataFrame
            Returns a dataframe with the same index as the input features and
            two columns, one for each dimension of the t-SNE plot.


    Computes the power spectral density for an input image. Translation and
    rotation invariate features.

    Parameters
    ----------
    img : np.ndarray
        Input image
    nbins : int
        Number of frequency bins to use. Frequency will range from 1 pixel to
        the largest axis of the input image, measured in pixels.

    Returns
    -------
    np.ndarray
        Power spectral density at each frequency


        Because the number of features may not be known till runtime, we can
        only create the labels of these features at runtime.


        Does the work in actually extracting the PSD

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        array
            Contains the extracted PSD features


    Histograms the flux values of the pixels into a given number of bins.

    Parameters
    ----------
    img : np.ndarray
        Input image
    nbins : int
        Number of bins to use.
    norm : boolean
        If true, normalises the image first so that histogram will be of values
        from zero to one.

    Returns
    -------
    bins
        x-axis bins for the histogram
    values
        Histogram values in each bin from zero to one


        Does the work in actually extracting the histogram

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        array
            Contains the extracted flux histogram features


        Runs the appropriate CNN model

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        array
            Contains the extracted deep features


        Creates the augmentation function from dictionary aug_params.

        Parameters
        ----------
        aug_params : dict
            A dictionary of augmentation parameters to use.


        Trains the BYOL model on an image dataset.

        Parameters
        ----------
        training_image_dataset : An Astronomaly ImageDataset object
            The dataset to train the model on.
        validation_image_dataset : An Astronomaly ImageDataset object
            The dataset to validate the model on. If None, the model will not
            be validated.


        Does the work in extracting the requested properties using photutils.

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        Array
            Features


        Convenience function to reshape images appropriate for deep learning.

        Parameters
        ----------
        images : np.ndarray, list
            Array of list of images

        Returns
        -------
        np.ndarray
            Converted array compliant with CNN


        Compiles the default autoencoder model. Note this model is designed to
        operate on 128x128 images. While it can run on different size images
        this can dramatically change the size of the final feature space.

        Parameters
        ----------
        input_image_shape : tuple
            The expected shape of the input images. Can either be length 2 or 3
            (to include number of channels).


        Actually train the autoencoder.

        Parameters
        ----------
        training_data : np.ndarray, list
            Either array or list of images. It's recommended that this data be
            augmented with translation or rotation (or both).
        batch_size : int, optional
            Number of samples used to update weights in each iteration. A
            larger batch size can be more accurate but requires more memory and
            is slower to train.
        epochs : int, optional
            Number of full passes through the entire training set.


        Returns the deep encoded features for an array of images.

        Parameters
        ----------
        images : np.ndarray
            Input images (nobjects x image_shape). For a single image,
            provide [image] as an array is expected.

        Returns
        -------
        np.ndarray
            Deep features (nobjects x nfeatures)


        Saves Keras model in HDF5 format

        Parameters
        ----------
        filename : string
            Location for saved model


        Runs the trained autoencoder to get the encoded features of the input
        image.

        Parameters
        ----------
        image : np.ndarray
            Cutout to run autoencoder on

        Returns
        -------
        np.ndarray
            Encoded features


        Does the work in flattening the image

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        Array
            Flattened image


    Finds the contours of an image that meet a threshold

    Parameters
    ----------
    img : np.ndarray
        Input image (must be greyscale)
    threshold : float
        What threshold to use

    Returns
    -------
    contours
        opencv description of contours (each contour is a list of x,y values
        and there may be several contours, given as a list of lists)
    hierarchy
        opencv description of how contours relate to each other (see opencv
        documentation)


    Fits an ellipse to a contour and returns a binary image representation of
    the ellipse.

    Parameters
    ----------
    contour : np.ndarray
        Array of x,y values describing the contours (as returned by opencv's
        findCountours function)
    image : np.ndarray
        The original image the contour was fit to.
    return_params : bool
        If true also returns the parameters of the fitted ellipse

    Returns
    -------
    np.ndarray
        2d binary image with representation of the ellipse


    Draws a contour onto an image for diagnostic purposes

    Parameters
    ----------
    contour : np.ndarray
        Array of x,y values describing the contours (as returned by opencv's
        findCountours function)
    image : np.ndarray
        The original image the contour was fit to.
    filled : bool, optional
        If true will fill in the contour otherwise will return an outline.
    Returns
    -------
    np.ndarray
        The image with the drawn contour on top


    Utility function to determine which contour contains the points given.
    Note by default this will only return the first contour it finds to contain
    x0, y0.

    Parameters
    ----------
    contours : np.ndarray
        Array of x,y values describing the contours (as returned by opencv's
        findCountours function)
    x0 : int
        x value to test
    y0 : int
        y value to test

    Returns
    -------
    contour : np.ndarray
        Returns the single contour that contains (x0,y0)


    Checks and flags images when the contour extends beyond the image size.
    Used to check whether the image size (window size) must be increased.

    Parameters
    ----------
    img : np.ndarray
        Input image (must be 2d, no channel information)
    threshold :
        Threshold values for drawing the outermost contour.
    return_params : bool
        If true also returns the parameters of the fitted ellipse

    Returns
    -------
    boolean
        Value that flags whether the ellipse extending beyond the image or not.


        Does the work in actually extracting the ellipse fitted features

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        array
            Contains the extracted ellipse fitted features


        Does the work in actually extracting the Hu moments

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        array
            Contains the Hu moments for each contour level


        Takes light curve data for a single object and computes the features
        based on the available columns.

        Parameters
        ----------
        lc_data: pandas DataFrame
            Light curve of a single object

        Returns
        -------
        array
            An array of the calculated features or an array of nan values
            incase there is an error during the feature extraction process


    A standardised way of flattening the swt2d coefficients
    They are stored as n_levels -> (cA, (cH, cV, cD)) where each of the sets
    of coeffcients has a list of [npixels, npixels]

    Parameters
    ----------
    wavelet_coeffs : list
        Exactly as output by pywt

    Returns
    -------
    np.ndarray
        Flattened coefficients
    labels
        The labels of the coefficients


    Because the number of features may not be known till runtime, we can
    only create the labels of these features at runtime.


    Inverse function to restore a flattened array to pywt structure.

    Parameters
    ----------
    flat_coeffs : np.ndarray
        Flattened array of coefficients
    nlev : int
        Number of levels wavelet decomposition was performed with
    image_shape : tuple
        Shape of original images

    Returns
    -------
    list
        pywt compatible coefficient structure


    Perform wavelet decomposition on single image

    Parameters
    ----------
    img : np.ndarray
        Image
    level : int, optional
        Level of depth for the wavelet transform
    wavelet_family : string or pywt.Wavelet object
        Which wavelet family to use

    Returns
    -------
    np.ndarray
        Flattened array of coefficients
    labels
        The labels of the coefficients


        Does the work in actually extracting the wavelets

        Parameters
        ----------
        image : np.ndarray
            Input image

        Returns
        -------
        pd.DataFrame
            Contains the extracted wavelet features


        Stores the mean and components of the PCA to disk. Makes use of the
        original features information to label the columns.

        Parameters
        ----------
        features : pd.DataFrame or similar
            The original feature set the PCA was run on.


Actually does the PCA reduction and returns a dataframe.


        Stores the mean and components of the truncated SVD to disk. Makes use
        of the original features information to label the columns.

        Parameters
        ----------
        features : pd.DataFrame or similar
            The original feature set the truncated SVD was run on.


Actually does the SVD reduction and returns a dataframe.


    Formats a function of a PipelineStage or Dataset object to ensure proper
    recording of the function and its arguments. args and kwargs should be
    exactly those passed to the function.

    Parameters
    ----------
    func_name : str
        Name of the stage

    Returns
    -------
    str
        Formatted function call


    Actually logs a message. Ensures the logger has been set up first.

    Parameters
    ----------
    msg : str
        Log message
    level : str, optional
        DEBUG, INFO, WARNING or ERROR, by default 'INFO'


    Reads the log to check if this function has already been called with the
    same arguments (this may still result in the function being rerun if the
    input data has changed).

    Parameters
    ----------
    class_name : str
        Name of PipelineStage
    local_variables : dict
        List of all local variables.

    Returns
    -------
    args_same, bool
        True if the function was last called with the same arguments.
    checksum, int
        Reads the checksum stored in the log file and returns it.


        Saves the output of this pipeline stage.

        Parameters
        ----------
        output : pd.DataFrame
            Whatever the output is of this stage.
        filename : str
            File name of the output file.
        file_format : str, optional
            File format can be provided to override the class's file format


        Loads previous output of this pipeline stage.

        Parameters
        ----------
        filename : str
            File name of the output file.
        file_format : str, optional
            File format can be provided to override the class's file format

        Returns
        -------
        output : pd.DataFrame
            Whatever the output is of this stage.


        Returns a checksum on the first few rows of a DataFrame to allow
        checking if the input changed.

        Parameters
        ----------
        data : pd.DataFrame or similar
            The input data on which to compute the checksum

        Returns
        -------
        checksum : str
            The checksum


        This is the external-facing function that should always be called
        (rather than _execute_function). This function will automatically check
        if this stage has already been run with the same arguments and on the
        same data. This can allow a much faster user experience avoiding
        rerunning functions unnecessarily.

        Warning - all columns in data not 'human_label' or 'score' are assumed
        to be features.

        Parameters
        ----------
        data : pd.DataFrame
            Input data on which to run this pipeline stage on.

        Returns
        -------
        pd.DataFrame
            Output


        This function should be called for pipeline stages that perform feature
        extraction so require taking a Dataset object as input.
        This is an external-facing function that should always be called
        (rather than _execute_function). This function will automatically check
        if this stage has already been run with the same arguments and on the
        same data. This can allow a much faster user experience avoiding
        rerunning functions unnecessarily.

        Parameters
        ----------
        dataset : Dataset
            The Dataset object on which to run this feature extraction
            function, by default None

        Returns
        -------
        pd.Dataframe
            Output


        This is the main function of the PipelineStage and is what should be
        implemented when inheriting from this class.

        Parameters
        ----------
        data : Dataset object, pd.DataFrame
            Data type depends on whether this is feature extraction stage (so
            runs on a Dataset) or any other stage (e.g. anomaly detection)

        Raises
        ------
        NotImplementedError
            This function must be implemented when inheriting this class.


Allows for any clean up tasks that might be required.


reads fortran binary file exported by cvode.f90/cvode_save


Compute production and loss reactions (vs z) for a given species.
    Must input sol from read_evolve_output


        Integrates atomsphere to photochemical equilibrium using the backward
        Euler method.

        Parameters
        ----------
        nsteps : integer, optional
            The number of steps the integrator takes to find photochemical
            equilibrium. The default value is 1000.

        Returns
        -------
        converged : bool
            If True, then the code converged to equilibrium. If False,
            the code did not converge.


Evolves the atmosphere with the CVODE BDF integrator from Sundials.

        Parameters
        ----------
        t0 : float
            Starting time (s)
        usol_start : Array{float,2}
            Initial conditions. nq by nz array of atmospheric mixing ratios.
        t_eval : Vector{float}
            Times to evaluate the solution (s)
        rtol : float
            Relative tolerance. Probably don't go higher than 1e-3.
        atol : float
            Absolute tolerance. About 1e-25 works well for rtol=1e-3.
            For low rtol (~1e-5) then use rtol=~1e-30.
        fast_and_loose : bool
            If 1, then will use a fast approximation to the jacobian.
            If 0, then CVODE will compute a more accurate jacobian (slowly).
        outfile : string
            If a file path is given, the the solution will be appended to the file "outfile"
            throughout the simulation. If this is used, then None is returned

        Returns
        -------
        solution : Array{float,3}
            Array of dimension [len(t_eval),nq,nz] containing mixing ratios of the atmosphere at
            each time.


        Makes a dictionary of the atmosphere after integration to photochemical
        equilibrium

        Returns
        -------
        out : dict
            Dictionary containing the mixing ratio of all species in the atmosphere,
            temperature structure, total pressure, and total number density.

        Raises
        ------
        SystemExit
            When photochemical model has not been integrated to equilibrium.


        Makes a dictionary of the atmosphere before integration to photochemical
        equilibrium. This is typically the atmosphere described in the input file
        atmosphere_txt, unless the input atmosphere has been changed with the out2in
        method.

        Returns
        -------
        out : dict
            Dictionary containing the mixing ratio of all species in the input atmosphere,
            temperature structure, total pressure, and total number density.


        Makes dictionary of the surface fluxes of each species at photochemical
        equilibrium.

        Returns
        -------
        out : dict
            Surface flux of each species in the model in molecules/cm2/s. Positive
            flux means a flux into the atmosphere.

        Raises
        ------
        SystemExit
            When photochemical model has not been integrated to equilibrium.


Resets the problem by reading in the original input files (e.g. species_dat, ...)


        Changes the initial atmosphere to the output of the past integration.

        Raises
        ------
        SystemExit
            When photochemical model has not been integrated to equilibrium.


        Returns the right-hand-side of the system of ordinary differential equations
        defining photochemistry and transport.

        Parameters
        ----------
        usol_flat : rank-1 array with bounds (self.photo.neq)
            Atmospheric composition (mixing ratios) of all species in a single array.
            Correct order of the array is given by, for example, self.photo.usol_init.flatten('F').

        Returns
        -------
        rhs : rank-1 array with bounds (self.photo.neq)
            The right hand side of the model equations (change in mixing ratio/second)


        Returns the jacobian of the system of ordinary differential equations
        defining photochemistry and transport.

        Parameters
        ----------
        usol_flat : rank-1 array with bounds (self.photo.neq)
            Atmospheric composition (mixing ratios) of all species in a single array.
            Correct order of the array is given by, for example, self.photo.usol_init.flatten('F').

        Returns
        -------
        jac : rank-2 array with bounds (self.photo.neq, self.photo.lda)
            The right hand side of the model equations (change in mixing ratio/second)


        Writes the atomsphere at photochemical equilbirium to a file.

        Parameters
        ----------
        filename : string, optional
            Name of the output file (default is atmosphere.txt)
        overwrite: bool, optional
            If True, then a file with the name "filename" will be overwritten
            (default is False).

        Raises
        ------
        SystemExit
            When photochemical model has not been integrated to equilibrium or
            when filename is invalid.


read best NDEs from dat_dir


 return weights to correct for SMF and HMF implicit prior for
    **marginalized 1d posterior**.

    args:
        Y_sam (Nx2 array): sample of M*, Mh drawn from some posterior p(M*, Mh|X)

        sim (str): specify the simulation used

    kwargs:
        bins (int): specify the number of bins for the SMF and HMF used in correction

        version (int): specify version of dataset

    return:
        w_smf (N array): weights for correcting the SMF  priors respectively.

        w_hmf (N array): weights for correcting the HMF  priors respectively.


    Returns an approximate resampled array based on float weights.
    data: 1D array of values
    weights: corresponding 1D array of float weights


 Read Y and X data from subhalos of the haloflow2 simulations.

    args:
        dataset (str): specify training or test data. specify 'train' or 'test'

        obs (str): specify the observables to include


    Visualize features using t-SNE. This function is optimized for speed.

    Parameters
    ----------
    model : torch.nn.Module
        Trained model.
    train_loader : torch.utils.data.DataLoader
        DataLoader for the training set.
    test_loader : torch.utils.data.DataLoader
        DataLoader for the test set.
    n_samples : int
        Number of samples to visualize.
    test_domain_label : int
        Domain label for the test set.
    device : str
        Device to run visualization on.

    Returns
    -------
    np.ndarray
        t-SNE embeddings.
    np.ndarray
        Domain labels.


    Plot t-SNE embeddings of the feature space.

    Parameters
    ----------
    embeddings : np.ndarray
        t-SNE embeddings.
    domains : np.ndarray
        Domain labels.
    train_domains : list
        List of training domain labels.
    test_domain : int
        Test domain label.

    Returns
    -------
    None


Evaluate the model on the test set.


     Evaluate the domain classifier's accuracy.

    Parameters
    ----------
     model : torch.nn.Module
         Trained domain classifier model.
     dataloader : torch.utils.data.DataLoader
         DataLoader for the test set.
     device : str
         Device to run evaluation on.

     Returns
     -------
     float
         Domain classification accuracy.


    Example:
    ranks_list = [ranks_nde, ranks_nde_2]
    labels = ['NDE', 'NDE 2']
    plot_rank_statistics(ranks_list, labels)


    Example:
    alpha_list = [alpha_nde, alpha_nde_2]
    ecp_list = [ecp_nde, ecp_nde_2]
    labels = ['NDE', 'NDE 2']
    plot_coverage(alpha_list, ecp_list, labels)


    Plotting script for true vs predicted values.

    Parameters
    ----------
    ax : matplotlib axis
        Axis to plot on
    train_obs : str
        Observational data to train on.
        For now, it's either 'mags' or 'mags_morph'
    train_sim : str
        Simulation data to train on.
        For now, it's either 'TNG100', 'Eagle100', 'TNG50', 'TNG_ALL', 'Simba100'
    test_obs : str
        Observational data to test on.
        For now, it's either 'mags' or 'mags_morph'
    test_sim : str
        Simulation data to test on.
        For now, it's either 'TNG100', 'Eagle100', 'TNG50', 'TNG_ALL', 'Simba100'
    device : str
        Device to run on.
        For now, it's either 'cpu' or 'cuda'
    mass : str
        Mass to predict.
        For now, it's either 'halo' or 'halo'
    use_weights : bool
        Whether to use weights to correct for SMF and HMF implicit prior.

    Returns
    -------
    ax : matplotlib axis


train NN compression of summary statistics


bojective function for optuna


train Neural Posterior Estimator for haloflow2


validate Neural Posterior Estimator ensemble for haloflow2


WandB sweep for DANN finetuning.


WandB sweep for NPE training with DANN.


    Args:
        data: GeoDataFrame, containing delineations, requires CRS WGS 84 EPSG 4326.
        group_column: str, column name with label uniquely identifying each row geometry.
        partition_count: number of partitions to use with dask_geopandas.sjoin(), defaults to 10.
    Returns:
        GeoDataFrame with all overlapping geometries removed.
        Assigns overlapping sections to the geometry group_column with most area in common or is closest.


    Transform PyGEOS Geometry from one coordinate
    reference system to another
    Args:
        geometry: PyGEOS Geometry array
        epsg_from: string, anything accepted by pyproj.CRS.from_user_input(), (i.e., "EPSG:4326")
        epsg_to: string, anything accepted by pyproj.CRS.from_user_input(), (i.e., "EPSG:4326")
    Returns:
        PyGEOS Geometry array


    Transform GeoDataFrame to a PyGEOS Geometry array
    and set spatial reference identifier (SRID).
    Args:
        geometry: GeoSeries or GeoDataFrame
        srid: integer representing spatial reference identifier (i.e., 4326)
    Returns:
        PyGEOS Geometry array


    Transform a PyGEOS Geometry from one coordinate
    reference system to another and calculate area
    Args:
        geometry: PyGEOS Geometry array
        epsg_from: string, anything accepted by pyproj.CRS.from_user_input(), (i.e., "EPSG:4326")
        epsg_to: string, anything accepted by pyproj.CRS.from_user_input(), (i.e., "EPSG:4326")
    Returns:
        Numpy array of areas in meters square


    For a given district level GADM in a country, this
    subdivides the area enclosed by the GADM boundary and generates
    polygons based on areas enclosed by OSM linestrings.
    Args:
        gadm_data: GeoDataFrame, containing GADM delineations (downloaded from https://gadm.org/data.html), requires CRS WGS 84 EPSG 4326
        osm_data: PyGEOS Geometry array (or GeoDataFrame with slower performance), of linestrings that delineate blocks within GADMs, requires CRS WGS 84 EPSG 4326
        gadm_column: string, name of column containing gadm_code
        gadm_code: string, unique identification code for each GADM in gadm_column
    Returns:
        GeoDataFrame with enclosed block geometries for a given 'gadm_code', each block is assigned a unique 'block_id'.
        To alphanumeric suffix in the block_id is a geohash that can be decoded into a lat-lon using # http://geohash.co/
        Geometry projected in CRS WGS 84 EPSG 4326.


Return memory usage, str


    Computes the k-complexity value for an enclosed block, buildings, and street linestrings.
    Args:
        block_id: string, unique identification code
        block: GeoSeries of a single Polygon representing enclosed block
        buildings: GeoSeries of Points or Polygons representing buildings
        streets: GeoSeries of Linestrings or MultiLinestrings representing street networks
        buffer_radius: float (optional), defaults to 100 meters, extends disconnected street_linestrings to street network that are within a set tolerance in meters
        include_geometry: bool (optional), defaults to True, if False the block geometry will not be included and function will return a Pandas DataFrame
        srid: integer (optional), defaults to 3395, representing spatial reference identifier, for meter conversion
    Returns:
        DataFrame or GeoDataFrame for individual block geometry. Geometry projected in CRS 4326.


    Computes the k-complexity value for each layer of buildings within an enclosed block.
    Differs from compute_k() because provides a detailed rendering of the internal layers of building access.
    Args:
        block_id: string, unique identification code
        block: GeoSeries of a single Polygon representing enclosed block
        buildings: GeoSeries of Points or Polygons representing buildings
        streets: GeoSeries of Linestrings or MultiLinestrings representing street networks
        use_building_polygons: bool (optional), defaults to False to use default triangular voronoi. Set to True to contour parcels around building polygons (slower performance).
        buffer_radius: float (optional), extends disconnected street_linestrings to street network that are within a set tolerance in meters
        srid: integer (optional), defaults to 3395, representing spatial reference identifier, for meter conversion
        For info about shrink_value, segment_value, threshold_value see: http://docs.momepy.org/en/stable/generated/momepy.Tessellation.html
    Returns:
        GeoDataFrame with building-parcel and street geometries. Geometry output projected in CRS 4326.


Return weighted quantile cuts from a given series, values.


Convert pandas.DataFrame containing bounding box columns to a geopandas.GeoDataFrame
    Args:
        gpd_buildings: pandas.DataFrame returned from merge_pixels() function
    Returns:
        pandas.DataFrame converted to geopandas.GeoDataFrame with pixels formatted as geometries


    Joins GeoDataFrame of enclosed block geometries to a GeoDataFrame containing building footprints, uses an inner join with 'intersects' predicate
    Args:
        block_data: GeoDataFrame, output returned from build_blocks() function, requires CRS WGS 84 EPSG 4326 or 3395
        bldg_id_col: str, unique ID column in bldg_data
        bldg_data: GeoDataFrame, containing building geometries with building_area column, requires CRS WGS 84 EPSG 4326 or 3395 (accepts 'Polygon' or 'Point' geometries)
        use_dask_geopandas:, boolean, defaults to False, use dask_geopandas to peform join operation
    Returns:
        GeoDataFrame with building geometries mapped to bldg_id_col,'building_area','block_id','gadm_code','country_code'.
        Geometry projected in CRS WGS 84 EPSG 4326.


Burn a set of geometries into the given raster dataset
    Args:
        gpd_dataframe: geopandas.GeoDataFrame containing geometries to burn into raster
        xr_array: xarray.DataArray of target raster containing dimensions 'y' and 'x'
        encode: boolean, defaults to False, encodes geometry column label as integers
        fill: (optional) int or float, used as fill value for all areas not covered by input geometries
    Returns:
        xarray.DataArray in shape of 'x' and 'y' raster dimensions


Vectorize pixel coordinates in a xarray.DataArray raster
    Args:
        xr_array: xarray.DataArray of target raster containing dimensions 'y' and 'x'
    Returns:
        xarray.Dataset with corner coordinates of each pixel as data variables


 Read GeoTiff or .tif file format from LandScan and Worldpop for a particular country
    Args:
        dir_path: string or Path to the file to open, director must have this structure:
            Path(dir_path) / 'landscan/<filename>.tif' (single global file)
            Path(dir_path) / f'worldpop/{country_code}.tif' (multiple country files)
        country_code: string of 3-digit country codes ('country_code')
        gadm_gpd: geopandas.GeoDataFrame of GADM codes ('gadm_code') and geometries
        gadm_code: list of gadm_codes (optional)
    Returns:
        two xarray.DataArrays with 'x' and 'y 'dimension and single band population value,
        first object is 'landscan' and second object is 'wordpop'


Take a xarray Dataset representing a raster, map on column labels from GeoDataFrame, and return a concordance DataFrame associating pixels and labels
    Args:
        xr_array: xarray.DataArray of target raster containing dimensions 'y' and 'x'
        xr_name: str name of the raster value contained in the xr_array
        gpd_dataframe: geopandas.DataFrame containing labels and geometries to left join against the xr_array of pixels
    Returns:
        pandas.DataFrame containing rows for each unique pixel of xr_array with column labels from gpd_dataframe


Convert pandas.DataFrame containing bounding box columns to a geopandas.GeoDataFrame
    Args:
        pd_data: pandas.DataFrame returned from merge_pixels() function
    Returns:
        pandas.DataFrame converted to geopandas.GeoDataFrame with pixels formatted as geometries


Allocate raster population in pandas.DataFrame to block geometries
    Args:
        pixel_data: pandas.DataFrame returned from merge_pixels() function
        population_col: string, name of column containing pixel's population value (e.g.,'landscan','worldpop')
        country_code: string, three-digit country code
        buildings_dir: string or Path, of top level directory containing building files at country level
        blocks_dir: string or Path, of top level directory containing building files at country level
        gadm_code_list: list, list of gadm_codes in target region, defaults to False (optional)
        all_area: boolean, keep block_id and gadm_codes outside of gadm_code_list, defaults to False (optional)
        include_residual: boolean, allocate non-intersecting residual population over entire target area, defaults to False (optional)
    Returns:
        pandas.DataFrame with following columns: 'block_id', 'gadm_code', 'country_code', str(population_col + '_population')


    For a given country, the GADM directory contains multiple file levels
    so this convenience function just returns the path to the highest
    resolution GADM file within the directory
    Args:
        gadm_dir: directory containing all gadm files for a country
    Returns:
        Path to specific gadm file


    Map country_codes to Geofabrik country name
    Args:
        country_code: str, country code in ISO 3166-1 alpha-3 format
        country_dict: dictionary, maps country codes to Geofabrik file names
    Returns:
        Name of Geofabrik country for a corresponding country_code, str


    Map Geofabrik file names to country_codes in ISO 3166-1 alpha-3 format
    Args:
        geofabrik_name: str, Geofabrik country name
        country_dict: dictionary, maps country codes to Geofabrik file names
    Returns:
        File name of country_code for a corresponding Geofabrik country name, str
        Returns more than one country code for the following countries {'israel-and-palestine' : ['PSE', 'ISR'], 'malaysia-singapore-brunei' : ['BRN', 'MYS', 'SGP'], 'morocco' : ['MAR', 'ESH'], 'senegal-and-gambia' : ['GMB', 'SEN']}


    Planetary flux function

    Parameters
    ----------
    A : float or array-like
        Planetary geometric albedo
    Phi : float
        Planetary phase function
    Fstar : float or array-like
        Stellar flux [W/m**2/um]
    Rp : float
        Planetary radius [Earth radii]
    d : float
        Distance to star [pc]
    AU : bool, optional
        Flag that indicates d is in AU

    Returns
    -------
    Fplan : float or array-like
        Planetary flux [W/m**2/um]


    Planet-star flux ratio (Equation 11 from Robinson et al. 2016).

    :math:`\\frac{{F}_{p,\\lambda }}{{F}_{{\\rm{s}},\\lambda }}=A{\\rm{\\Phi }}(\\alpha ){\\left(\\displaystyle \\frac{{R}_{{\\rm{p}}}}{r}\\right)}^{2}`

    Parameters
    ----------
    A : float or array-like
        Planetary geometric albedo
    Phi : float
        Planetary phase function
    Rp : float
        Planetary radius [Earth radii]
    r : float
        Planetary orbital semi-major axis [AU]

    Returns
    -------
    FpFs : float or array-like
        Planet-star flux ratio


    Exoplanetary photon count rate (Equation 12 from Robinson et al. 2016)

    :math:`{c}_{{\\rm{p}}}=\\pi {{qf}}_{\\mathrm{pa}}{ \\mathcal T }\\displaystyle \\frac{\\lambda }{{hc}}{F}_{{\\rm{p}},\\lambda }(d)\\Delta \\lambda {\\left(\\displaystyle \\frac{D}{2}\\right)}^{2}`

    Parameters
    ----------
    q : float or array-like
        Quantum efficiency
    fpa : float
        Fraction of planetary light that falls within photometric aperture
    T : float
        Telescope and system throughput
    lam : float or array-like
        Wavelength [um]
    dlam : float or array-like
        Spectral element width [um]
    Fplan : float or array-like
        Planetary flux [W/m**2/um]
    D : float
        Telescope diameter [m]

    Returns
    -------
    cplan : float or array-like
        Exoplanetary photon count rate [1/s]


    Speckle count rate (Equation 19 from Robinson et al. 2016)

    :math:`{c}_{\\mathrm{sp}} = \\pi q{ \\mathcal T }C\\Delta \\lambda {F}_{{\\rm{s}},\\lambda }(d)\\displaystyle \\frac{\\lambda }{{hc}}{\\left(\\displaystyle \\frac{D}{2}\\right)}^{2}`

    Parameters
    ----------
    q : float or array-like
        Quantum efficiency
    T : float
        System throughput
    C : float, optional
        Coronagraph design contrast
    lam : float or array-like
        Wavelength [um]
    dlam : float or array-like
        Spectral element width [um]
    D : float
        Telescope diameter [m]
    Fstar : float or array-like
        Host star spectrum at distance of planet (TOA) [W/m**2/um]

    Returns
    -------
    cspeck : float or array-like
        Speckle photon count rate [1/s]


    Dark current photon count rate

    Parameters
    ----------
    De : float, optional
        Dark current [counts/s]
    X : float, optional
        Width of photometric aperture ( * lambda / diam)
    lam : float or array-like
        Wavelength [um]
    D : float
        Telescope diameter [m]
    theta :
        Angular size of lenslet or pixel [arcsec**2]
    DNHpix : float, optional
        Number of horizontal/spatial pixels for dispersed spectrum
    IMAGE : bool, optional
        Set to indicate imaging mode (not IFS)
    CIRC : bool, optional
        Set to use a circular aperture

    Returns
    -------
    cdark :
        Dark current photon count rate (s**-1)


    Read noise count rate (assuming detector has a maximum exposure time)

    Parameters
    ----------
    Re : float or array-like
        Read noise counts per pixel
    X : float, optional
        Width of photometric aperture ( * lambda / diam)
    lam : float or array-like
        Wavelength [um]
    D : float
        Telescope diameter [m]
    theta :
        Angular size of lenslet or pixel [arcsec**2]
    Dtmax : float, optional
        Detector maximum exposure time [hours]
    IMAGE : bool, optional
        Set to indicate imaging mode (not IFS)
    CIRC : bool, optional
        Set to use a circular aperture

    Returns
    -------
    cread : float or array-like
        Read noise photon count rate (s**-1)


    Fraction of Airy power contained in square or circular aperture

    Parameters
    ----------
    X : float, optional
        Width of photometric aperture ( * lambda / diam)
    CIRC : bool, optional
        Set to use a circular aperture

    Returns
    -------
    f_airy : float
        Fraction of planetary light that falls within photometric aperture X*lambda/D


    Calculate the Lambertian Phase Function from the phase angle,

    :math:`{{\\rm{\\Phi }}}_{{\\rm{L}}}(\\alpha )=\\displaystyle \\frac{\\mathrm{sin}\\alpha +(\\pi -\\alpha )\\mathrm{cos}\\alpha }{\\pi }`

    Parameters
    ----------
    alpha: float
        Planet phase angle [deg]

    Returns
    -------
    Phi : float
        Lambertian phase function


Adds new filter to wheel

        Parameters
        ----------
        filt : Filter
            New Filter object to be added to wheel
        name : string (optional)
            Name to give new filter attribute


    Computes SNR, noised data, and error on noised data.

    Parameters
    ----------
    Dt : float
        Telescope integration time in seconds
    Cratio : array
        Planet/Star flux ratio in each spectral bin
    cp : array
        Planet Photon count rate in each spectral bin
    cb : array
        Background Photon count rate in each spectral bin

    Returns
    -------
    cont : array
        Noised Planet/Star flux ratio in each spectral bin
    sigma : array
        One-sigma errors on flux ratio in each spectral bin
    SNR : array
        Signal-to-noise ratio in each spectral bin


    Interpolate the continuum of a spectrum over a masked absorption or emission
    band.

    Parameters
    ----------
    lam : array
        Wavelength grid (abscissa)
    cp : array
        Planet photon count rates or any spectrum
    icont : list
        Indicies of continuum (neighboring points)
    iband : list
        Indicies of spectral feature (the band)

    Returns
    -------
    ccont : list
        Continuum planet photon count rates across spectral feature, where
        len(ccont) == len(iband)


Set parameters of the model from a dictionary.


Divide the range between `start` and `stop` into uniform bins
	with spacing less than or equal to `target_spacing` and return the
	bin midpoints and the actual spacing.


        Prepare model before self.fetchSED(new_event=1) is called

        This method is made non-abstract intentionally, it is optional to
        implement and required only for models (e.g. AGN) which need to
        prepare SEDs for all Trest in advance

        Parameters
        ----------
        trest : ndarray[float64]
            The rest frame phases at which to calculate the flux. It is sorted
            in the ascending order
        external_id : int
             ID for event
        hostpars : tuple[float]
             Host parameters corresponded to HOST_PARAM_NAMES


Numpy array of dtype float64 with wavelengths in Angstrom


        Returns the flux at every wavelength, for a given phase.

        Parameters
        ----------
        trest : float
             The rest frame phase at which to calculate the flux
        maxlam : int
             A maximum number of wavelength bins. If your wavelength
             vector is longer than this number (default is arbitrary),
             program should abort
        external_id : int
             ID for event
        new_event : int
             1 if new event, 0 if same event
        hostpars : tuple[float]
             Host parameters corresponded to HOST_PARAM_NAMES

        Returns
        -------
        A numpy array of dtype float64 the same length as fetchSED_LAM containing the flux
        observed from 10 pc in erg / s / cm^2 / Angstrom


Returns the names of model parameters


        Returns the value of parameter 'varname'

        Parameters
        ----------
        varname : str
             A parameter name from self.parameter_names


        We allow users to override the default BayeSN parameter
        ranges by specifying the ARGLIST variable in the SNANA
        input file, but we have to parse that single string

        The keys in the string must  mirror those in bayesn.params
        (where they can mercifully be specified as separate lines)
        and must obey SNANA conventions
        i.e. the keys must be in the form:
        GEN[RANGE|PEAK|SIGMA]_<PARAM_NAME>: scalar or space-separated list

        Sets a dictionary bayesn_distrib_params with the mapping of
        key:value with value parsed as a scalar or list of floats

        and a dictionary bayesn_param_config with the mapping of
        PARAM_NAME: list of SNANA keys set (RANGE|PEAK|SIGMA)


        Distributions are defined by peak (i.e. mean), sigma and range
        but not all those keywords maybe supplied for each of the parameters
        This changes the interpretation of the distribution
        Only range = uniform
        Only peak = delta function
        Peak + sigma = Gaussian
        Peak + sigma + range = Gaussian with limited range


        Parse the BayeSN parameter distributions specified in
        bayesn.params or as a string in the ARGLIST in the SNANA .INPUT
        file and converts strings to floats appropriately for
        PEAK/RANGE/SIGMA/PAR


Returns the wavelength vector


        Returns the flux at every wavelength, for a given phase.

        Parameters
        ----------
        trest : float
             The rest frame phase at which to calculate the flux
        maxlam : int
             A maximum number of wavelength bins. If your wavelength
             vector is longer than this number (default is arbitrary),
             program should abort
        external_id : int
             ID for SN
        new_event : int
             1 if new event, 0 if same SN
        hostpars : str
             Comma separated list of host parameters

        Returns
        -------
        A list of length self.wavelen containing the flux at
        every wavelength in self.wave, at the phase trest


	Compute a matrix of spline coefficients.

	Given a set of knots at x, with values y, compute a matrix, J, which
	can be multiplied into y to evaluate the cubic spline at points
	x_int.

	Parameters
	----------
	x_int : :py:class:`numpy.array`
		Numpy array containing the locations which the output matrix will
		interpolate the spline to.
	x : :py:class:`numpy.array`
		Numpy array containing the locations of the spline knots.
	invkd : :py:class:`numpy.array`
		Precomputed matrix for generating second derivatives. Can be obtained
		from the output of ``invKD_irr``.
	allow_extrap : bool
		Flag permitting extrapolation. If True, the returned matrix will be
		configured to extrapolate linearly beyond the outer knots. If False,
		values which fall out of bounds will raise ValueError.

	Returns
	-------
	J : :py:class:`numpy.array`
		y independednt matrix whose product can be taken with y to evaluate
		the spline at x_int.


			Returns the flux at every wavelength, for a given phase.

			Parameters
			----------
			trest : float
			     The rest frame phase at which to calculate the flux
			maxlam : int
			     A maximum number of wavelength bins. If your wavelength
			     vector is longer than this number (default is arbitrary),
			     program should abort
			external_id : int
			     ID for SN
			new_event : int
			     1 if new event, 0 if same SN
			hostpars : str
			     Comma separated list of host parameters

			Returns
			-------
			A list of length self.wavelen containing the flux at
			every wavelength in self.wave, at the phase trest


			Returns the value of parameter 'varname'

			Parameters
			----------
			varname : str
			     A parameter name from self.parameter_names


Find index of element of `a` closest to x

    Parameters
    ----------
    a : np.array
        Sorted array
    x : number
        Value to loop up

    Returns
    -------
    int
        Valid index of a


        Return inverse cumulative distribution function

        Parameters
        ----------
        x : ndarray[float64]
            The random variable
        y : str
            The probability density function of x


        Return samples from inverse transformation sampling

        Parameters
        ----------
        sampling_size : int
            Desired sampling size


time step of damped random walk model. t must be larger than self.t


        Input: M_BH in unit of g.
        Return L_bol in erg/s


        Input: L_bol in erg/s
        Outbout: Mi


        Correct Fnu with its baseline (average value)
        Output: Fnu: spectral density along the frequency axes


        Input: BH mass in g
        return: Accretion rate at Eddington luminosity in g/s


        Input:
        ME_dot: Accretion rate at Eddington luminosity in g/s
        eddington ratio
        Return:
        MBH_dot: Black hole accretion rate


        calculate T0 based on standard disk model
        input:
        M: mass of the gravitating centre
        Mdot: accretion rate at previous time step
        r_in: the inner radius of the accretion disc
        output:
        T_0: Effective temperature at r0. Same as the maximum effective temperature at the disc surface (Tmax)


        return r0 based on standard disk model

        input: r_in: the inner radius of the accretion disc
        output: r0:  the initial radius of the ring


        calculate variable of integration x

        input:
        nu: frequency
        T0: Effective temperature at r0. Same as the maximum effective temperature at the disc surface (Tmax)
        r: radius of the accretion disc
        r0: the initial radius of the ring

        return: variable of integration x


        function to calculate flux based on standard disk model

        input:
        Mdot: accretion rate at previous time step
        nu: frequency
        rin: the inner radius of the accretion disc
        i: inclination
        d: distance
        M: mass of the gravitating centre
        output:
        flux at given time step


        Return timescale for DRW model.
        Input frequency v in Hz, i band magnitude (default is -23), Black hole mass in g (defalt is 10^9 solar mass).
        Return timescale in s.


        Return Structure Function at infinity in mag.
        Input frequency in Hz, i band magnitude (default is -23), Black hole mass in g (defalt is 10^9 solar mass).


convert from Fnu [erg/s/cm^2/Hz] to Flamb[erg/s/cm^2/AA]


convert from to Flamb[erg/s/cm^2/AA] to Fnu [erg/s/cm^2/Hz]


Eddington Ratio Distribution Function for blue galaxies (radiatively-efficient, less massive)


Returns the length of the wavelength vector


generate the full event, saved to self.sed, and saved to self.trest


    We provide 3 sets of input values to generate ligthcurve for debugging purpose. 2 of them are realistic objects with dbID available
    Code to plot eddington ratio distribution, spectrum available at the bottom of main(), comment out to use them


    uses chisquared info to get the poisson interval. Uses scipy.stats
    (imports in function).
    (http://stackoverflow.com/questions/14813530/poisson-confidence-interval-with-numpy)


converts velocity from heliocentric frame to Local Group frame


 look up velocity field to find peculiar velocity vector
		input needs to be heliocentric position (and in degrees)
		output is vector in galactic cartesian coordinates, in CMB frame


 convert helio redshift to cosmological redshift (zbar; in CMB frame)
		input needs to be vector in galactic cartesian coordinates, w.r.t. CMB frame
		components are: heliocentric motion, peculiar velocity (in radial direction)


build covariance matrix


    For each FITRES file (each FITOPT), this function:
      - First, loads the FITRES file with FITOPT identifier "FITOPT000" to obtain reference MU values
        (one per CID/IDSURVEY pair). These reference values replace the MUMODEL values.
      - Then, for each FITRES file, it:
           * Finds the first matching row for each of two CID/IDSURVEY pairs.
           * Computes delta = current MU - (reference MU from FITOPT000).
           * Scales each delta by the systematic scale factor (sys_scale).
           * Computes the final delta as the product: (delta1 * sys_scale) * (delta2 * sys_scale).
           * Saves all the info in a dictionary with individual columns.

    Returns a DataFrame with columns:
      [ 'FITOPT', 'CID1', 'MU1', 'RefMU1', 'Delta1',
        'CID2', 'MU2', 'RefMU2', 'Delta2', 'SysScale', 'FinalDelta' ]


Open the file to write the map


Function that reads the spectra of a single object

    Parameters
    ----------
    cid:

    base_name:

    Returns
    -------
    sn: a dictionary, with following keys
    - 'wave': wavelength
    - 'flux': fluxes in
    - 'fluxerr': flux error
    - 'tobs': time of observation
    - 'mjd': Median Julian Date


Function to read a light curve.

    Parameters
    ----------

    Returns
    -------


Used for matching COVOPTs to FITOPTs and MUOPTs


Evaluate stats for readme of datafile. Has no impact on actual
        datafiles.
        Status values:
            "SELECT"  ->  selected and written to disk
            "REJECT"  ->  rejected (e.g., too few detections)
            "UNDEFINED -> undefined data unit (e.g., could not assign season)


Teardown method for closing open files and clearing cache.


This function modifies the SNANA_READER data_dict. First it loads
            everything into the variables


sexagesimal to degrees. Sign must be the first character


Convert magnitude and magnitude error to flux, given a zeropoint.


Convert from heliocentric redshift to CMB-frame redshift.

    Parameters
    ----------
    z : float
        Heliocentric redshift.
    ra, dec: float
        RA and Declination in degrees (J2000).


Convert from CMB-frame redshift to heliocentric redshift.

    Parameters
    ----------
    z : float
        CMB-frame redshift.
    ra, dec: float
        RA and Declination in degrees (J2000).


Prepare the output directory based on format options (SNANA/etc)


Prepare input arguments from config file


Returns the eigenfunction grid, None if eigenfunctions are not present.


Checks if the dataset is MHD.


        Makes sure that the dataset is backwards compatible with new changes.
        Mainly used for older (<2.0.0) datasets.


        Returns the eigenfunctions based on the supplied getter function.

        Parameters
        ----------
        ev_guesses : complex, numpy.ndarray
            Eigenvalue guesses.
        ev_idxs : int, numpy.ndarray
            Indices of the eigenvalues to retrieve.
        getter_func : function
            Function to retrieve the eigenfunctions.

        Returns
        -------
        numpy.ndarray
            Array containing the eigenfunctions, items are dictionaries.


        Returns the continua. Each key corresponds to a multiple Numpy arrays,
        one for each dataset.


        Returns the parameters. Each key corresponds to multiple Numpy arrays,
        one for each dataset.


    Validates the given executable, then returns it. If the argument passed is
    None, defaults to the executable in the legolas home directory.

    Parameters
    ----------
    executable : str, ~os.PathLike
        The path to the legolas executable to use.

    Raises
    ------
    FileNotFoundError
        If the executable was not found.

    Returns
    -------
    executable : ~os.PathLike
        The (resolved) path to the executable to use.


    Validates the number of cpus passed to the multiprocessing pool.
    Defaults to the maximum available number if exceeded.

    Parameters
    ----------
    cpus : int
        The number of cpus to use.

    Returns
    -------
    cpus : int
        The number of cpus to use, limited to the maximum number available.


    Validates a list of parfiles.

    Parameters
    ----------
    files : (list of) str, (list of) ~os.PathLike
        Paths to the parfiles.

    Raises
    ------
    FileNotFoundError
        If one of the parfiles is not found.

    Returns
    -------
    files_list : list
        A list of resolved filepaths for the parfiles.


Worker initialisation for the multiprocessing module.


        Worker activation for the multiprocessing module.
        Calls the legolas executable as a subprocess with the parfile as argument.

        Parameters
        ----------
        parfile : str, ~os.PathLike
            The path to the parfile

        Returns
        -------
        call : :func:`subprocess.call`
            A call to a subprocess to run legolas.


        Terminates the multiprocessing workers after a forced interruption.
        Simply giving an interrupt terminates only the Python processes, but still
        keeps the Legolas calls running since those are subprocesses. This method first
        terminates all child processes (legolas), then the parents (workers).


        Executes the legolas executables and initialises the multiprocessing
        pool if requested.


    Ensures that the number of names matches the number of runs.

    Parameters
    ----------
    names : str, list[str]
        The basename(s) for the parfile(s).
    nb_runs : int
        Number of runs for which the parfiles are generated.

    Returns
    -------
    names : list[str]
        The basename(s) for the parfile(s).


    Validates the basenames for given parfiles.

    Parameters
    ----------
    basename : list[str]
        The basenames for the parfiles. If not given, defaults to "parfile[i]".

    Returns
    -------
    basename : list[str]
        The basename for a parfile.


    Validates and returns the output directory for the parfiles.

    Parameters
    ----------
    output_dir : str, ~os.PathLike
        The output directory to store the parfiles in. If not given, defaults to
        the current working directory.
    subdir : boolean
        If `.true.`, creates a subdirectory called `parfiles`.

    Raises
    ------
    NotADirectoryError
        If the output directory is not found.

    Returns
    -------
    output : ~os.PathLike
        The resolved path to the output directory with "parfiles" appended.


        Does typechecking on the various dictionary keys supplied to the parfile
        generator. Pops the key from the dictionary.

        Parameters
        ----------
        namelist : str
            One of the namelists ("gridlist", "savelist", etc.)
        name : str
            The key to check.
        allowed_dtypes : class, tuple
            Allowed types for that particular key. Either a single value or a tuple.

        Raises
        ------
        TypeError
            If the types do not match, e.g. if "gridpoints" is specified as a float
            value when it should be an integer.

        Returns
        -------
        item : any
            The item popped from the dictionary corresponding to the given key.


        Creates one major namelist from the given dictionary.

        Raises
        ------
        ParfileGenerationError
            - If the original dictionary is not empty after everything should be popped
            - If there is an inconsistency between array sizes of dictionary items


        Creates separate parfiles from the main namelist container and writes
        the individual parfiles to disk.

        Returns
        -------
        parfiles : list of str
            List containing the paths of the parfiles, can be passed to the legolas
            runner.


    Generates parfiles based on a given configuration dictionary.
    The separate namelists do not have to be taken into account, and a normal
    dictionary should be supplied where the keys correspond to the namelist
    items that are required. Typechecking is done automatically during parfile
    generation.

    Parameters
    ----------
    parfile_dict : dict
        Dictionary containing the keys to be placed in the parfile.
    basename : str
        The basename for the parfile, the `.par` suffix is added automatically and is
        not needed. If multiple parfiles are generated, these
        will be prepended by a 4-digit number (e.g. 0003myparfile.par).
        If not provided, the basename will default to `parfile`.
    output_dir : str, ~os.PathLike
        Output directory where the parfiles are saved, defaults to the current
        working directory if not specified. A subdirectory called `parfiles` will be
        created in which the parfiles will be saved.
    subdir : boolean
        If `True` (default), creates a subdirectory `parfiles` in the output folder.
    prefix_numbers : boolean
        If `True` prepends the `basename` by a n-digit number (e.g. xxxxmyparfile.par).
        The number of digits is specified by `nb_prefix_digits`.
    nb_prefix_digits : int
        Number of digits to prepend to the `basename` if `prefix_numbers` is `True`.
        Defaults to 4.

    Notes
    -----
    This routine is quite flexible and specifically designed for parametric studies.
    You can specify both single values and list-like items as dictionary items.
    This routine will automatically generate multiple parfiles if lists/numpy arrays
    are present.

    Returns
    -------
    parfiles : list
        A list with the paths to the parfiles that were generated. This list can be
        passed immediately to :func:`pylbo.run_legolas`.

    Examples
    --------
    This will generate a single parfile in a subdirectory `parfile` of the
    current working directory.

    >>> import pylbo
    >>> config = {
    >>>    "geometry": "Cartesian",
    >>>    "x_start": 0,
    >>>    "x_end": 1,
    >>>    "equilibrium_type": "resistive_homo",
    >>>    "gridpoints": 100,
    >>>    "write_eigenfunctions": True,
    >>>    "basename_datfile": "my_run",
    >>>    "output_folder": "output",
    >>> }
    >>> parfile = pylbo.generate_parfiles(config)

    This will generate 10 parfiles in the directory `my_parfiles` relative to
    the current working directory. The first parfile will have `x_end = 1.0` and 100
    gridpoints, the second one will have `x_end = 2.0` and 150 gridpoints, etc.

    >>> import pylbo
    >>> import numpy as np
    >>> config = {
    >>>    "geometry": "Cartesian",
    >>>    "x_start": 0,
    >>>    "x_end": np.arange(1, 11)
    >>>    "number_of_runs": 10
    >>>    "equilibrium_type": "resistive_homo",
    >>>    "gridpoints": np.arange(100, 600, 50),
    >>>    "write_eigenfunctions": True,
    >>>    "basename_datfile": "my_run",
    >>>    "output_folder": "output",
    >>> }
    >>> parfile_list = pylbo.generate_parfiles(config, output_dir="my_parfiles")


    Runs the legolas executable for a given list of parfiles. If more than one parfile
    is passed, the runs can be performed in parallel using the multiprocessing module.
    Parallelisation can be enabled by setting the `nb_cpus` kwarg to a number greater
    than one, and is disabled by default.
    Every CPU will have a single legolas executable subprocess associated
    with it.

    Parameters
    ----------
    parfiles : str, list, numpy.ndarray
        A string, list or array containing the paths to the parfile(s).
        Accepts the output of :func:`pylbo.generate_parfiles`.
    remove_parfiles : bool
        If `True`, removes the parfiles after running Legolas. This will also remove
        the containing folder if it turns out to be empty after the parfiles are
        removed. If there are other files still in the folder it remains untouched.
    nb_cpus : int
        The number of CPUs to use when running Legolas. If equal to 1 then
        parallelisation is disabled. Defaults to the maximum number of CPUs available
        if a number larger than the available number is specified.
    executable : str, ~os.PathLike
        The path to the legolas executable. If not specified, defaults to the
        standard one in the legolas home directory.

    Notes
    -----
    If multiprocessing is enabled, it is usually a good idea to have the number
    of runs requested divisible by the number of CPUs that are available. For example,
    if 24 runs are requested it is good practice to use either 2, 4, 6 or 8 CPUs,
    and avoid numbers like 3, 5 and 7.

    Examples
    --------
    The example below will run a list of parfiles using using a local legolas
    executable from the current directory, on 4 CPU's.

    >>> import pylbo
    >>> from pathlib import Path
    >>> files = sorted(Path("parfiles").glob("*.dat"))
    >>> pylbo.run_legolas(files, nb_cpus=4, executable="legolas")


    Plots the spectrum of a single dataset.

    Parameters
    ----------
    data : ~pylbo.data_containers.LegolasDataSet
        The dataset that should be used.
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.
    custom_figure : tuple
        Optional, in the form (fig, ax). If supplied no new figure will be created
        but this one will be used instead. `fig` refers to the matplotlib figure and
        `ax` to a (single) axes instance, meaning that you can pass a subplot as well.
    use_residuals : bool
        If `True`, colors the spectrum based on the residual in the datfile.

    Returns
    -------
    p : ~pylbo.visualisation.spectra.SingleSpectrumPlot
        The spectrum instance which can be used further to add continua,
        eigenfunctions, etc.


    Plots the spectrum of a dataset series.

    Parameters
    ----------
    data : ~pylbo.data_containers.LegolasDataSeries
        The dataseries that should be used.
    xdata : str, list, numpy.ndarray
        Data to use for the horizontal axis. This can either be a key from the
        parameters dictionary, or a list/numpy array containing actual data.
    use_squared_omega : bool
        If `True`, this will square the eigenvalues when they are plotted on the
        vertical axis. If `False` (default), either the real or imaginary part of the
        eigenvalues will be plotted depending on the value of `use_real_parts`.
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.
    custom_figure : tuple
        Optional, in the form (fig, ax). If supplied no new figure will be created
        but this one will be used instead. `fig` refers to the matplotlib figure and
        `ax` to a (single) axes instance, meaning that you can pass a subplot as well.

    Returns
    -------
    p : ~pylbo.visualisation.spectra.MultiSpectrumPlot
        The spectrum instance which can be used further to add continua,
        eigenfunctions, etc.


    Creates a merged spectrum from various datasets, useful in plotting multiple
    results from the shift-invert solver, for example. This draws every dataset
    in a different color by default, and creates a corresponding legend. Supply the
    optional argument `color` to draw all points in the same color.

    Parameters
    ----------
    data : ~pylbo.data_containers.LegolasDataSeries
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.
    custom_figure : tuple
        Optional, in the form (fig, ax). If supplied no new figure will be created
        but this one will be used instead. `fig` refers to the matplotlib figure and
        `ax` to a (single) axes instance, meaning that you can pass a subplot as well.
    interactive : bool
        If `True` (default), enables an interactive legend.
    legend : bool
        If `True` (default), draws a legend.

    Returns
    -------
    p : ~pylbo.visualisation.spectra.MultiSpectrumPlot
        The spectrumfigure instance, containing the plot.


    Compares two spectra.

    Parameters
    ----------
    ds1 : ~pylbo.data_containers.LegolasDataSet
        The first dataset, this one is put on the left panel.
    ds2 : ~pylbo.data_containers.LegolasDataSet
        The second dataset, this one is put on the right panel.
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.
    custom_figure : tuple
        The custom figure to use in the form (fig, axes).
    lock_zoom : bool
        If `True` (`False` by default), locks the zoom of both axis. When locked,
        zoomin in on one of the axis automatically scales the zoom on the other one
        as well.
    use_residuals : bool
        If `True`, colors the spectrum based on the residual in the datfile.

    Returns
    -------
    p : ~pylbo.visualisation.spectra.SpectrumComparisonPlot
        The figure instance containing the compared spectrum plot.


    Plots the equilibrium profiles.

    Parameters
    ----------
    data : ~pylbo.data_containers.LegolasDataSet
        The dataset or series that should be used.
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.
    interactive : bool
        If `True` (default), enables an interactive legend.

    Returns
    -------
    p : ~pylbo.visualisation.profiles.EquilibriumProfile
        The profile instance containing the equilibrium plots.


    Creates a plot of the balance equations.
    These should be as close to zero as possible over the entire grid.

    Parameters
    ----------
    data : ~pylbo.data_containers.LegolasDataSet
        The dataset that should be used
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.
    interactive : bool
        If `True` (default), enables an interactive legend.

    Returns
    -------
    p : ~pylbo.visualisation.profiles.EquilibriumBalance
        The profile instance containing the equilibrium balance plots.


    Plots the continua profiles.

    Parameters
    ----------
    data : ~pylbo.data_containers.LegolasDataSet
        The dataset or series that should be used.
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.
    interactive : bool
        If `True` (default), enables an interactive legend.

    Returns
    -------
    p : ~pylbo.visualisation.profiles.ContinuumProfile
        The profile instance containing the continua plots.


    Plots the continua profiles.

    Parameters
    ----------
    data : ~pylbo.data_containers.LegolasDataSet
        The dataset that should be used.
    figsize : tuple
        Optional figure size like the usual matplotlib (x, x) size.

    Returns
    -------
    p : ~pylbo.visualisation.matrices.MatrixFigure
        The instance containing the matrix plots.


        Determines what happens when the legend gets picked.

        Parameters
        ----------
        event : ~matplotlib.backend_bases.PickEvent
            The matplotlib pick event.


Makes the legend pickable, only used if interactive.


        Adds an item to the list of drawn items on the canvas.

        Parameters
        ----------
        item : object
            A single object, usually a return from the matplotlib plot or scatter
            methods.


        Checks if autoscaling is needed and if so, rescales the y-axis to the min-max
        value of the currently visible legend items.


    Calculates the thermal and slow continua.

    Returns
    -------
    Tuple[np.ndarray, np.ndarray, np.ndarray]
        A tuple containing the slow-, slow+ and thermal continua, in this order.


    Calculates the thermal continuum analytically, when the slow continuum is zero.

    Returns
    -------
    np.ndarray
        The thermal continuum.


    Solves the third-order polynomial that couples the slow and thermal continua.
    The thermal continuum corresponds to the purely imaginary solution.

    Parameters
    ----------
    coeff3 : np.ndarray
        The coefficient corresponding to the term :math:`\\omega^3`.
    coeff2 : np.ndarray
        The coefficient corresponding to the term :math:`\\omega^2`.
    coeff1 : np.ndarray
        The coefficient corresponding to the term :math:`\\omega^1`.
    coeff0 : np.ndarray
        The coefficient corresponding to the constant term.

    Returns
    -------
    Tuple[np.ndarray, np.ndarray, np.ndarray]
        A tuple containing the slow-, slow+ and thermal continua, in this order.


        Returns the list of continua colors.

        Returns
        -------
        The continua colors as a list.


        Setter for the continua colors attribute.

        Parameters
        ----------
        colors : list, numpy.ndarray
            The colors to use when plotting the continua as a list of strings.

        Raises
        ------
        ValueError
            If a wrong argument is passed or if it is of improper length.


Draws the matrices.


        Creates a default figure with a 1x1 subplot.

        Parameters
        ----------
        figlabel : str
            The label of the figure.
        figsize : tuple[int, int]
            The size of the figure.

        Returns
        -------
        fig : ~matplotlib.figure.Figure
            The figure on which to draw.
        ax : ~matplotlib.axes.Axes
            The axes on which to draw.


        Generates a unique figure id.

        Parameters
        ----------
        figlabel : str
            The label of the figure.

        Returns
        -------
        figure_id : str
            The unique figure id of the form "figure_type-x" where x is an integer.


Adds the figure to the stack.


        Adds a new subplot to a given matplotlib subplot, essentially "splitting" the
        axis into two. Position and placement depend on the loc argument.
        When called on a more complex subplot layout the overall gridspec remains
        untouched, only the `ax` object has its gridspec modified.
        On return, `tight_layout()` is called by default to prevent overlapping labels.

        Parameters
        ----------
        ax : ~matplotlib.axes.Axes
            The axes object, this will be "split" and a new axes will be added
            to the figure.
        loc : str
            The location of the new axes. Should be one of "left", "right", "top",
            "bottom". Defaults to "right".
        share : str
            Can be "x", "y" or "all". This locks axes zooming between both subplots.
        apply_tight_layout : bool
            Whether to call `tight_layout()` on the figure before return.

        Raises
        ------
        ValueError
            If the loc argument is invalid.

        Returns
        -------
        ~matplotlib.axes.Axes
            The axes instance that was added.


        Saves the current figure.

        Parameters
        ----------
        filename : str, ~os.PathLike
            The filename to which the current figure is saved.
        kwargs
            Default keyword arguments passed to :meth:`~matplotlib.pyplot.savefig`.


Shows the selected figure


        Makes the legend interactive.

        Parameters
        ----------
        legendhandler : ~pylbo.visualization.legend_handler.LegendHandler
            The legend handler.


        Adds an eigenfunction interface to the figure.

        Parameters
        ----------
        efhandler : ~pylbo.visualisation.eigenfunctions.eigfunc_interface.
        EigenfunctionInterface
            The eigenfunction interface.


    Simple decorator, when a routine is wrapped with this the plot will be
    cleared and redrawn on calling it.
    Useful for when the scaling is changed or artists are added/removed.


    Ensures that a given attribute is set.

    Parameters
    ----------
    obj : Any
        The object to check.
    attr : str
        The attribute to check.

    Raises
    ------
    ValueError
        If the attribute is not set.


    Converts an eigenfunction name to latex formatting. Numbers are replaced with a
    suffix corresponding to the geometry: :math:`(1, 2, 3)` becomes :math:`(x, y, z)`
    for Cartesian and :math:`(r, \\theta, z)` for cylindrical geometries. Symbols
    and letters are also converted to LaTeX.

    Parameters
    ----------
    ef_name : str
        The name of the eigenfunction.
    geometry : str, optional
        The geometry of the eigenfunction. The default is "Cartesian".
    real_part : bool, optional
        Whether the real part of the eigenfunction is being plotted. The default is
        None.


    Maps the background name to latex formatting.

    Parameters
    ----------
    bg_name : str
        The name of the background as given by the corresponding dictionary key.

    Returns
    -------
    str
        The latex formatted background name. If the background name has no mapping
        the original name is returned.


    Returns the validated eigenfunction name.

    Parameters
    ----------
    ds : ~pylbo.data_containers.LegolasDataSet
        The dataset containing the eigenfunctions.
    ef_name : str
        The name of the eigenfunction.

    Raises
    ------
    ValueError
        If the eigenfunction name is not valid.

    Returns
    -------
    str
        The validated eigenfunction name.


    Validates the location of the textbox.

    Parameters
    ----------
    loc : str
        The location of the textbox.

    Raises
    ------
    ValueError
        If the location is not one of "top left", "top right", "bottom left" or
        "bottom right".

    Returns
    -------
    str
        The validated location.


    Returns the coordinates of the textbox.

    Parameters
    ----------
    loc : str
        The location of the textbox.
    outside : bool
        Whether the textbox is outside the axes.
    width : float
        The width of the bounding box.
    height : float
        The height of the bounding box.

    Returns
    -------
    float
        The x-coordinate of the textbox.
    float
        The y-coordinate of the textbox.


    Convenience method to add a textbox to the given axes.

    Parameters
    ----------
    ax : ~matplotlib.axes.Axes
        The axes to add the textbox to.
    text : str
        The text to add to the textbox.
    x : float
        The x-coordinate of the textbox.
    y : float
        The y-coordinate of the textbox.
    coords : str, optional
        The coordinate system of the textbox. The default is "axes", options are
        "axes", "figure", and "data".
    fs : int, optional
        The fontsize of the textbox. The default is 15.
    alpha : float, optional
        The alpha value of the textbox. The default is 0.2.
    halign : str, optional
        The horizontal alignment of the textbox. The default is "center".
    color : str, optional
        The color of the textbox. The default is "grey".
    textcolor : str, optional
        The color of the text. The default is "black".
    boxstyle : str, optional
        The style of the textbox. The default is "round".

    Returns
    -------
    ~matplotlib.axes.Axes.text
        The textbox.


    Creates a textbox in one of the corners of the specified axis. This method is meant
    to create panel labels without having to manually specify the coordinates of the
    textbox.

    Parameters
    ----------
    ax : ~matplotlib.axes.Axes
        The axes to add the textbox to.
    text : str
        The text to add to the textbox.
    loc : str, optional
        The location of the textbox. The default is "top left", options are
        "top right", "bottom left" and "bottom right".
    fs : int, optional
        The fontsize of the textbox. The default is 15.
    alpha : float, optional
        The alpha value of the textbox. The default is 0.2.
    color : str, optional
        The color of the textbox. The default is "grey".
    textcolor : str, optional
        The color of the text. The default is "black".
    boxstyle : str, optional
        The style of the textbox. The default is "round". If `None` is passed
        no box will be drawn.
    bold : bool, optional
        Whether to bold the text. The default is False.
    outside : bool, optional
        Whether to place the textbox outside of the axis. The default is False.

    Raises
    ------
    ValueError
        If the location is not one of "top left", "top right", "bottom left" or
        "bottom right".

    Returns
    -------
    ~matplotlib.axes.Axes.text
        The textbox.


Adds the equilibria to the figure. Also sets the legend handler items


Adds the continua to the plot, also sets the legend handlers.


Draws the equilibrium balance equations.


        Returns the name of the part of the eigenmode solution to use, i.e.
        'real' or 'imag'.


        Returns an array of dicts with all eigenfunctions for every eigenvalue.
        The dictionaries will be updated with the derived eigenfunctions if they
        are available in the dataset.

        Parameters
        ----------
        ds : ~pylbo.data_containers.LegolasDataSet
            The dataset containing the eigenfunctions.
        omega : list[complex]
            The (approximate) eigenvalue(s) of the mode(s) to retrieve the
            eigenfunctions from.

        Returns
        -------
        np.ndarray
            An array of dicts with all eigenfunctions for every eigenvalue.


        Validates the complex factor.

        Parameters
        ----------
        complex_factor : complex
            The complex factor to validate.

        Returns
        -------
        complex
            The complex factor if it is valid, otherwise 1.


        Samples the background array on the eigenfunction grid.

        Parameters
        ----------
        bg : np.ndarray
            The background array with Gaussian grid spacing

        Returns
        -------
        np.ndarray
            The background array with eigenfunction grid spacing


        Returns the name of the background.

        Returns
        -------
        str
            The closest match between the eigenfunction name and the equilibrium
            name.

        Raises
        ------
        ValueError
            If the eigenfunction name is a magnetic vector potential component.


        Checks if a given value is a number.

        Parameters
        ----------
        val : float
            The value to check.
        attr_name : str
            The name of the value.

        Raises
        ------
        ValueError
            If the value is not a number.


        Checks is a given value is a numpy array.

        Parameters
        ----------
        array : np.ndarray
            The value to check.
        attr_name : str
            The name of the value.

        Raises
        ------
        ValueError
            If the value is not a numpy array.


        Calculates the mode solution.

        Parameters
        ----------
        efdata : dict
            The data for the eigenfunction. This should be a dictionary with the
            keys ``'ef'`` and ``'omega'``, with ``'ef'``containing the eigenfunction
            and ``'omega'`` the corresponding eigenvalue.
        u2 : Union[float, np.ndarray]
            The data for the :math:`u_2` coordinate.
        u3 : Union[float, np.ndarray]
            The data for the :math:`u_3` coordinate.
        t : Union[float, np.ndarray]
            The data for the time.

        Returns
        -------
        np.ndarray
            The mode solution.


        Returns
        -------
        matplotlib.axes.Axes
            Alias for the axes containing the eigenmode solution view.


        Returns
        -------
        np.ndarray
            The solutions for the eigenmode


Draws the eigenfunction(s) to the figure.


        Creates the axes for the colorbar.

        Parameters
        ----------
        width : float
            The width of the colorbar axes.
        Returns
        -------
        matplotlib.axes.Axes
            The axes for the colorbar.


        Creates a textbox on the axis with the value of the eigenfrequency.

        Parameters
        ----------
        ax : ~matplotlib.axes.Axes
            The axes to use for the textbox.
        **kwargs
            Additional keyword arguments to pass to :meth:`add_axis_label`.


        Creates a textbox on the figure with the value of the k2 and k3 coordinates.

        Parameters
        ----------
        ax : ~matplotlib.axes.Axes
            The axes to use for the textbox.
        **kwargs
            Additional keyword arguments to pass to :meth:`add_axis_label`.


        Creates a textbox on the figure with the value of the :math:`u_2-u_3`
        coordinates.

        Parameters
        ----------
        ax : ~matplotlib.axes.Axes
            The axes to use for the textbox.
        **kwargs
            Additional keyword arguments to pass to :meth:`add_axis_label`.


        Create the figure layout for the visualisation. Two panels are created:
        the top one for the eigenfunction and the bottom one for the visualisation.

        Parameters
        ----------
        figsize : tuple[int, int]
            The size of the figure.

        Returns
        -------
        fig : ~matplotlib.figure.Figure
            The figure to use for the visualisation.
        axes : dict
            The axes to use for the visualisation.


        Creates an animation of the eigenmode solution over a given time interval.

        Parameters
        ----------
        times : np.ndarray
            The times at which to create the animation.
        filename : str
            The filename of the animation.
        fps : float
            The frames per second of the animation.
        dpi : int
            The resolution of the animation.


        Sets the coordinate data.

        Parameters
        ----------
        u1 : np.ndarray
            The 1D :math:`u_1` coordinate array.
        u2 : np.ndarray
            The 1D :math:`u_2` coordinate array.
        u3 : np.ndarray
            The 1D :math:`u_3` coordinate array.


        Broadcasts a 1D array to a 3D array with the same shape as the coordinate data.

        Parameters
        ----------
        array : np.ndarray
            The 1D array to broadcast.

        Returns
        -------
        np.ndarray
            The broadcasted array.


Logs an info message only if the progress bar is inactive.


        Validates and sets the VTK data type.

        Parameters
        ----------
        dtype : str
            The VTK data type. Valid values are "float32" and "float64".

        Raises
        ------
        ValueError
            If the VTK data type is not valid.


        Writes the VTK file header. This includes the VTK file version, the
        data type, the grid dimensions and the number of points.

        Parameters
        ----------
        vtkfile : str
            The name of the VTK file to write to.


        Writes the VTK grid coordinates.

        Parameters
        ----------
        vtkfile : str
            The name of the VTK file to write to.


        Writes the VTK point data start marker, i.e. the 'POINT_DATA' statement and
        the number of points.

        Parameters
        ----------
        vtkfile : str
            The name of the VTK file to write to.


        Writes a 3D VTK scalar field with a given fieldname. If `fielddata` is
        smaller than `1e-12` everywhere the field is not written to the VTK file.

        Parameters
        ----------
        vtkfile : str
            The name of the VTK file to write to.
        fieldname : str
            The name of the field.
        fielddata : ndarray
            The field data.


        Writes auxiliary coordinate data to the VTK file, for example the theta values
        in cylindrical geometry. These are needed for appropriate transformations
        to draw vector fields in e.g. ParaView.

        Parameters
        ----------
        vtkfile : str
            The name of the VTK file to write to.


        Exports the mode solution to a VTK file.

        Parameters
        ----------
        filename : str
            The name of the VTK file to write to.
        time : Union[float, np.ndarray]
            The time(s) at which to export the mode solution.
        names : Union[str, list[str]], optional
            The name(s) of the mode(s) to export.
        bg_names : Union[str, list[str]], optional
            The name(s) of the equilibrium background(s) to export.
        dtype : str, optional
            The VTK data type, defaults to "float32" (32 bit floating point).
            Can be set to "float64" (64 bit floating point) but uses more memory.
        starting_index : int, optional
            The starting index for filenames, defaults to 0.