        Creats an initial tracking data where for each rule, the validity and the applied
        status is False

        Args:
            rule_mapping (dict): The mapping from rule to fields
            rules_override (dict): The override of mapping from rule to fields
            metadata_format (str): The format of the metadata file (eg. echo10, dif10)

        Returns:
            (dict): A dictionary in the form:
            {
                "rule_id": [
                    {
                    "field": "field_name",
                    "valid": "validity_status",
                    "applied": "applied_status"
                    },
                    ...
                ],
                ...
            }


        Updates the tracking value for `rule_id` and `field` with the `validity` status

        Args:
            rule_id (str): The id of the rule
            field (str): The field that the rule is applied to
            validity (bool): The validity status of the rule for the field


        Reads the tracking data for `rule_id` and `field`

        Args:
            rule_id (str): The id of the rule
            field (str): The field path

        Returns:
            (dict): A dict of form: {
                "field": "field_value",
                "valid": "validity_status",
                "applied": "applied_status"
            } for the `rule_id` and `field`


        Converts the input datetime string to iso datetime object

        Args:
            datetime_string (str): the datetime string

        Returns:
            (datetime.datetime) If the string is valid iso string, False otherwise


        Converts the input date string to iso datetime object

        Args:
            date_string (str): the datestring

        Returns:
            (datetime.datetime) If the string is valid iso string, False otherwise


        Performs the Date/DateTime ISO Format Check - checks if the datetime
        is valid ISO formatted datetime string

        Args:
            datetime_string (str): The datetime string

        Returns:
            (dict) An object with the validity of the check and the instance


        Performs the Date/DateTime Format Check
        Checks if the datetime_string is a valid ISO date or ISO datetime string

        Args:
            datetime_string (str): The date or datetime string

        Returns:
            (dict) An object with the validity of the check and the instance


        Compares two datetime values based on the argument relation
        Returns:
            (dict) An object with the validity of the check and the instance


        Validates the collection datetime against the datetime of the last granule in the collection

        Args:
            datetime_string (str): datetime string
            collection_shortname (str): ShortName of the parent collection
            sort_key (str): choice of start_date and end_date
            time_key (str): choice of time_end and time_start
        Returns:
            (dict) An object with the validity of the check and the instance


        Validates the collection EndingDatetime against the datetime of the last granule in the collection

        Args:
            ending_datetime (str): EndingDatetime string
            collection_shortname (str): ShortName of the parent collection

        Returns:
            (dict) An object with the validity of the check and the instance


        Validates the collection BeginningDateTime against the datetime of the last granule in the collection

        Args:
            beginning_datetime (str): BeginningDateTime string
            collection_shortname (str): ShortName of the parent collection

        Returns:
            (dict) An object with the validity of the check and the instance


Reads the xml schema file


Reads the json schema file


        Validate passed content based on the schema and return any errors
        Args:
            content_to_validate (str): The metadata content as a json string
        Returns:
            (dict) A dictionary that gives the validity of the schema and errors if they exist


        Cleans up the error log given by the XML Validator and builds an error object in
        the format accepted by our program

        Args:
            error_log (str): The error log as output by the xml validator
            paths (list): All available paths in the document file

        Returns:
            (dict): The formatted error dictionary


        Validate passed content based on the schema and return any errors

        Args:
            content_to_validate (bytes): The metadata content as a xml string

        Returns:
            (dict) A dictionary that gives the validity of the schema and errors if they exist


        Runs schema validation on the metadata

        Args:
            metadata (str): The original metadata (either xml or json string)

        Returns:
            (dict): Result of the validation from xml and json schema validators


        Extracts anything that starts with 'http' from `text_with_urls`.
        This is required for catching "wrong" urls that aren't extracted by `URLExtract.find_urls()` because they are not urls at all
        An example: https://randomurl
        Args:
            text_with_urls (str, required): The text that contains the URLs where the check needs to be performed

        Returns:
            (list) List of texts that start with 'http' from `text_with_urls`


        Checks the health and status of the URLs included in `text_with_urls`
        Args:
           text_with_urls (str, required): The text that contains the URLs where the check needs to be performed
        Returns:
            (dict) An object with the validity of the check and the instance/results


        Checks if the doi link given in the text is a valid doi link

        Returns:
            (dict) An object with the validity of the check and the instance/results


        Checks if the length of the string is valid based on the extent
        and relation provided in the args

        Args:
            string (str): The input string
            args (list): [extent (int), relation (str)] The extent and the relation

        Returns:
            (dict) An object with the validity of the check and the instance


        Compares two strings based on the relationship

        Returns:
            (dict) An object with the validity of the check and the instance


        Checks if `value` is in `keywords_list`

        Args:
            value (str/int): The value of the field
            keyword_list (list): The controlled keywords list

        Returns:
            (dict) An object with the validity of the check and the instance


        Checks if the GCMD keyword hierarchy is correct

        Args:
            args (list): List of the keyword in order of hierarchy
                example: ['EARTH SCIENCE', "ATMOSPHERE", "ATMOSPHERIC PRESSURE", None]

        Returns:
            (dict) An object with the validity of the check and the instance


        Checks if the GCMD location keyword hierarchy is correct

        Args:
            args (list): List of the keyword in order of hierarchy
                example: ['CONTINENT', "AFRICA", "CENTRAL AFRICA", "ANGOLA", None]

        Returns:
            (dict) An object with the validity of the check and the instance


        Checks if the Chrono Units keyword hierarchy is correct

        Args:
            args (list): List of the keyword in order of hierarchy
                example: ['PHANEROZOIC','CENOZOIC','QUATERNARY','PLEISTOCENE','CALABRIAN']

        Returns:
            (dict) An object with the validity of the check and the instance


        Validates the instrument shortname provided in the granule metadata
        against the instrument shortname provided at the collection level.

        Args:
            instrument_shortname (str): shortname of the instrument
            collection_shortname (str): Shortname of the parent collection
            version (str):              version of the collection
            dataset_id (str):           Entry title of the parent collection

        Returns:
            (dict) An object with the validity of the check and the instance


        Validates the platform shortname provided in the granule metadata
        against the platform shortname provided at the collection level.

        Args:
            platform_shortname (str): shortname of the platform
            collection_shortname (str): Shortname of the parent collection
            version (str):              version of the collection
            dataset_id (str):           Entry title of the parent collection

        Returns:
            (dict) An object with the validity of the check and the instance


        Validates the data format provided in the granule metadata
        against the data format provided at the collection level.

        Args:
            granule_data_format (str): data format in the collection
            collection_shortname (str): Shortname of the parent collection
            version (str):              version of the collection
            dataset_id (str):           Entry title of the parent collection

        Returns:
            (dict) An object with the validity of the check and the instance


        Gets the path values recursively while handling list or dictionary in `subset_of_metadata_content`
        Adds the values to `container`

        Args:
            subset_of_metadata_content (dict or list or str):
                        The value of the field at a certain point;
                        changes during each level of recursion
            path_list (list): The path of the field as a list
                         Example: 'Collection/RangeDateTime/StartDate' ->
                                  ['Collection', 'RangeDateTime', 'StartDate']
            container (set): The container that holds all the path values
            query_params (list): The [key, value] pair to distinguish a field in umm-c
                                eg: ["Type", "DELETE"]


        Gets the value of the field from the metadata (input_json)

        Args:
            path_string (str): The path of the field. Example: 'Collection/RangeDateTime/StartDate'

        Returns:
            (bool, set) If the path exists, (True, set of values of the path);
                        else (False, empty set)


        Process the argument by calling the provided function with the given arguments.

        Args:
            arg: The argument to be processed.
            func: The function to be called.
            relation: The relation argument.
            external_data: The external data argument.
            external_relation: The external relation argument.

        Returns:
            A dict containing the updated invalid_values list and the updated validity flag.


        Runs the custom check based on `func` to the `content_to_validate`'s `field_dict` path

        Args:
            content_to_validate (dict): The metadata content
            field_dict (dict): The field dictionary of the form:
                {
                    "fields": relavant fields,
                    "relation": relation between the fields
                }
            func (function): The function reference to the check
            external_data (list): External data required by the check if any

        Returns:
            (dict): The result of the check in the form:
                {
                    "valid": "Validity status (bool)",
                    "value": "The instance value/s"
                }


        Checks that if the value for url_type is "USE SERVICE API",
        the mime_type should be one of the values from a controlled list
        For all other cases, the check should be valid


        Checks if one of the specified fields is populated
        At least one of the `field_values` should not be null
        It is basically a OneOf check


        Checks if the Extended_Metadata field in the DIF schema is being
        utilized to specify whether or not the collection is a Standard Product.
        This check is needed because DIF schema does not have a dedicated field
        for Standard Product, and the Extended_Metadata field is also utilized
        for other things.


        Determines if a description has been provided for the License URL if a
        License URL has been provided in the metadata.

        Args:
            url_field (string): license URL string
            description_field (string): string describing the URL


        Checks if sensor is provided at the granule level if provided at
        collection level


        Appends `value` if it doesn't exist in `list_of_values`
        `list_of_values` is an ordered list


Creates a dependency ordering; basically independent checks are added first


        Returns all the rule_ids that are based on a check_id

        Args:
            check_id (str): The check id to find the rules based on

        Returns:
            list: list of all the rule_ids that are based on the check_id


        Creates a rule ordering based on the dependencies

        Returns:
            (list): ordered list of rules


        Check whether passed concept id is valid

        Returns:
            (bool) True if the concept id is valid, False otherwise


        Constructs CMR API URL based on the concept ID.
        It assumes that the concept_id is already valid.

        Returns:
            (str) The URL constructed based on the concept ID


        Logs errors in self.errors

        Args:
            error_message_code (str): The key to the ERROR_MESSAGES dict
            kwargs (dict): Any keyword arguments required for the error string


        Downloads metadata by calling the CMR API

        Returns:
            (str) The JSON string if download is successful, None otherwise


        Concept ID can be for a collection or granule. This function determines which one it is.

        Returns:
            (str)   "collection" when the concept_id is a collection
                    "granule" when the concept_id is a granule
                    "invalid" when the concept_id is neither collection nor granule, or invalid concept id


Loads json schema file


Loads all the schema files to object variables


        Maps the `data_type` and `function` to the corresponding function
        in the corresponding class

        Args:
            data_type (str): The data type
            function (str): The name of the function

        Returns:
            (func): The function reference


        Gets the success, failure, warning messages for the `rule_id`
        msg_type can be any one of 'failure', 'remediation'


Formats the message for `rule_id` based on the result


Performs Schema check


Checks if the dependent check called `dependency` is valid


Checks if the dependent checks are valid


Process a single field according to the given rule and update result_dict


Run the check function for `rule_id` and update `result_dict`


Performs custom checks


        Runs all checks on the `metadata_content`

        Args:
            metadata_content (str): The downloaded metadata content

        Returns:
            (dict): The results of the jsonschema check and all custom checks


            Sometimes the XML values contain attributes.
            In such a case, the returned value for a field looks something like:

            >> doc["DIF"]["ISO_Topic_Category"]
                OrderedDict([('@uuid', '26ebb539-cae2-4961-9252-7f367642fa57'), ('#text', 'IMAGERY/BASE MAPS/EARTH COVER')]) #noqa

            instead of the regular:
            >> doc["DIF"]["ISO_Topic_Category"]
                IMAGERY/BASE MAPS/EARTH COVER

            this postprocessor is used to get the regular value even in cases
            where attrs are present


Downloads and maintains a copy of the csv files from the gcmd server once a day


        Creates the hierarchy dictionary from the values from the csv

        Args:
            rows (list): List of list of row values from the csv file

        Returns:
            (dict): The lookup dictionary for GCMD hierarchy


        Reads keywords from the corresponding csv based on the kind of keyword

        Args:
            keyword_kind (str): The kind of keyword
                (could be: sciencekeywords, projects, providers, instruments, locations)
            columns (list of int, optional): The columns to read. Defaults to None.
                If columns is provided, returns keywords from that specific column
                If not, returns all useful keywords based on the keyword kind

        Returns:
            (list): list of keywords or list of list of rows from the csv


Converts a list to a nested dict


Merges child dict to the parent dict avoiding repetitions


        Validates if the input_keyword is a valid keyword from all_keywords

        Args:
            all_keywords (dict): The dictionary of science keywords
            input_keyword (list): The input keyword as a list based on the hierarchy

        Returns:
            (bool, str/None): The validity of the keyword and the invalid keyword (if any)


Validates GCMD science keywords


Validates GCMD instrument short name and long name consistency


Validates GCMD instrument short name


Validates GCMD instrument long name


Validates whether a given instrument short name has a corresponding long name


Validates GCMD Platform short name


Validates GCMD Platform long name


Validates GCMD platform type


Validates whether a given platform short name has a corresponding long name


Validates GCMD platform short name and long name consistency


Validates GCMD provider short name


Validates GCMD provider long name


Validates GCMD provider short name and long name consistency


Validates GCMD spatial keyword


Validates the Location hierarchy against GCMD 'locations' list


Validates GCMD campaign short name and long name consistency


Validates GCMD Campaign Short Name


Validates GCMD Campaign Long Name


Validates whether a given campaign short name has a corresponding long name


Validates GCMD Granule Data Format


Validates the Online Resource Type against GCMD 'rucontent' list


Validates the Mime Type against GCMD 'MimeType' list


Validates the Horizontal Resolution Range against GCMD 'horizontalresolutionrange' list


Validates the vertical Resolution Range against GCMD 'verticalresolutionrange' list


Validates the temporal Resolution Range against GCMD 'temporalresolutionrange' list


    Adds an inner title to a given axis, with location loc.

    from http://matplotlib.sourceforge.net/examples/axes_grid/demo_axes_grid2.html


    Convert date to decimal year

    %In: toDecimalYear(datetime(2020, 10, 10))
    %Out: 2020.7732240437158


Plot historical simulations and observations


    Resampling algorithm by Douglas C. Brinkerhoff

    Parameters
    ----------
    observed : pandas.DataFrame
        A dataframe with observations
    simulated : pandas.DataFrame
        A dataframe with simulations
    calibration_start : float
        Start year for calibration
    calibration_end : float
        End year for calibration
    fudge_factor : float
        Tolerance for simulations. Calculated as fudge_factor * standard deviation of observed
    n_samples : int
        Number of samples to draw.


Download files from list of urls.


Select only the desired data files from CMR response.


Perform a scrolling CMR query for files matching input criteria.


Context manager to patch joblib to report into tqdm progress bar given as argument


Read and return Obs


    Read and return HIRHAM5 data grouped by year

    n: monthly forcing (12

    Returns

    temp (n, m) array
    precip (n, m) array
    std_dev (n, m) array
    a (1, m) array
    m (1, m) array
    r (1, m) array
    f (1, m) array
    b (1, m) array


Plot target (PISM) and predicted (Emulator) speeds for validation


    Bayesian Information Criterion

    Calculates the Bayesian Information Criterion (BIC) under the assumption that the model errors or disturbances are independent and identically distributed according to a normal distribution and that the boundary condition that the derivative of the log likelihood with respect to the true variance is zero, this becomes (up to an additive constant, which depends only on n and not on the model). BIC is given by:

    BIC = n*ln(RSS/n) + ln(n)*k,

    where

    n = the number of data points in x, the number of observations, or equivalently, the sample size
    k = the number of parameters estimated by the model. For example, in multiple linear regression, the estimated parameters are the intercept, the q slope parameters, and the constant variance of the errors; thus, k = q + 2
    RSS = residual sums of squares (FIXME)

    Parameters
    ----------
    X : ndarray
        input observations
    Y : ndarray
        output observations

    Returns
    -------
    BIC : scalar
          The Bayesian Information Criterion (BIC)


    Stepwise model selection using the Bayesian Information Criterion (BIC)

    General function modeled after R's stepAIC function.

    Starts with full least squares model as in backward selection. If interactions=True, performs
    bidirectional stepwise selection. Otherwise only performs backwards selection.

    User may supply a list of variable names where the length of the list
    must equal n=X.shape[1]. Otherwise, a list of phony variables
    ["X1", "X2", ...,"Xn"] is generated.

    Then params_dict is generated from the names list.

    Parameters
    ----------
    X : array-like (n-d shaped)
        input model params
    Y : array_like (d shaped)
        input observations

    Returns
    -------
    V : array_like
        List of select model parameters including interactions, e.g.
        V = ["X1", "X2", "X1*X2"]


    Reads samples_file and response_file as a pandas.DataFrame. Removes samples that do
    not have a response by differencing the DataFrames based on "id", i.e.
    both samples_file and response_file must contain "id".

    Parameters
    ----------
    samples_file  : str
    response_file : str

    Returns
    -------
    X : pandas.DataFrame (ndarray if return_numpy=True)
    Y : pandas.DataFrame (ndarray if return_numpy=True)


    Draw n_samples Sobol sequences using the Saltelli method
    or using Latin Hypercube Sampling (LHS)

    Provide a dictionary with distributions of the form

    distributions = {
        "X1": scipy.stats.distributions.randint(0, 2),
        "X2": scipy.stats.distributions.truncnorm(-4 / 4.0, 4.0 / 4, loc=8, scale=4),
        "X3": scipy.stats.distributions.uniform(loc=5, scale=2),
    }

    Parameters
    ----------
    distributions : dictionary of scipy.stats.distributions.
    n_samples : number of samples to draw.
    method: drawing method. Either Latin Hypercube ("lhs")
            or Saltelli ("saltelli").

    Returns
    -------
    d : pandas.DataFrame


    Returns the distributions used by Aschwanden et al (2019):

    @article{Aschwanden2019,
    author = {Aschwanden, Andy and Fahnestock, Mark A. and Truffer, Martin and Brinkerhoff, Douglas J. and Hock, Regine and Khroulev, Constantine and Mottram, Ruth and Khan, S. Abbas},
    doi = {10.1126/sciadv.aav9396},
    issn = {2375-2548},
    journal = {Science Advances},
    month = {jun},
    number = {6},
    pages = {eaav9396},
    title = {{Contribution of the Greenland Ice Sheet to sea level over the next millennium}},
    url = {http://advances.sciencemag.org/lookup/doi/10.1126/sciadv.aav9396},
    volume = {5},
    year = {2019}
    }


    Root mean square difference between a and b

    a, b: array-like


    Returns estimate of R for a set of two traces.
    The Gelman-Rubin diagnostic tests for lack of convergence by comparing
    the variance between multiple chains to the variance within each chain.
    If convergence has been achieved, the between-chain and within-chain
    variances should be identical. To be most effective in detecting evidence
    for nonconvergence, each chain should have been initialized to starting
    values that are dispersed relative to the target distribution.

    Parameters
    ----------
    p, q : ndarray
           Arrays containing the 2 traces of a stochastic parameter. That is, an array of dimension m x 2, where m is the number of traces, n the number of samples.

    Returns
    -------
    Rhat : float
           Return the potential scale reduction factor, :math:`\hat{R}`.

    Notes
    -----
    The diagnostic is computed by:
      .. math:: \hat{R} = \sqrt{\frac{\hat{V}}{W}}
    where :math:`W` is the within-chain variance and :math:`\hat{V}` is
    the posterior variance estimate for the pooled traces. This is the
    potential scale reduction factor, which converges to unity when each
    of the traces is a sample from the target posterior. Values greater
    than one indicate that one or more chains have not yet converged.

    References
    ----------
    Brooks and Gelman (1998)
    Gelman and Rubin (1992)


    Compute the area absolute error between the predicted and target tensors.

    Parameters
    ----------
    preds : Tensor
        The predicted values as a PyTorch Tensor.
    target : Tensor
        The target values as a PyTorch Tensor.
    omegas : Tensor
        The omegas values as a PyTorch Tensor.
    area : Tensor
        The area values as a PyTorch Tensor.

    Returns
    -------
    Tensor
        The area absolute error as a PyTorch Tensor.

    Notes
    -----
    This function uses the '_area_absolute_error_update' and '_area_absolute_error_compute' functions
    to calculate the area absolute error.


        Update state with predictions and targets, and area.
        Args:
            preds: Predictions from model
            target: Ground truth values
            omegas: Weights
            area: Area of each cell


Computes absolute error over state.


        Update state with predictions and targets, and area.
        Args:
            preds: Predictions from model
            target: Ground truth values
            omegas: Weights


Update state with predictions and targets.
        Args:
            preds: Predictions from model
            target: Ground truth values
            weight: linear weights
            k: regularization constant


Computes mean squared error over state.


Updates and returns variables required to compute Mean Squared Error.
    Checks for same shape of input tensors.
    Args:
        preds: Predicted tensor
        target: Ground truth tensor
        weight: linear weights
        k: regularization constant


Computes Mean Squared Error with L2 regularization.
    Args:
        sum_squared_error: Sum of square of errors over all observations
        n_obs: Number of predictions or observations
        squared: Returns RMSE value if set to False.
    Example:
        >>> preds = torch.tensor([0., 1, 2, 3])
        >>> target = torch.tensor([0., 1, 2, 2])
        >>> weigth = torch.tensor([0.25, 0.5, 0.25, 0.25])
        >>> k = 1e-1
        >>> sum_squared_error, n_obs = _l2__mean_squared_error_update(preds, target, weight, k)
        >>> _l2_mean_squared_error_compute(sum_squared_error, n_obs)
        tensor(0.2609)


Computes mean squared error with L2 regularization.
    Args:
        preds: estimated labels
        target: ground truth labels
        squared: returns RMSE value if set to False
    Return:
        Tensor with MSE
    Example:
        >>> from torchmetrics.functional import mean_squared_error
        >>> x = torch.tensor([0., 1, 2, 3])
        >>> y = torch.tensor([0., 1, 2, 2])
        >>> w = torch.tensor([0.25, 0.5, 0.25, 0.25])
        >>> k = 1e-1
        >>> mean_squared_error(x, y, w, k)
        tensor(0.2609)


Select slices from dataset


        Passes the input tensor through each operation.

        Parameters
        ----------
        x : Tensor
            Input tensor.
        add_mean : bool, optional
            If True, adds mean to the predicted F.

        Returns
        -------
        Tensor
            Predicted F.


        Adds model specific arguments.

        Parameters
        ----------
        parent_parser : ArgumentParser
            Parent argument parser.

        Returns
        -------
        ArgumentParser
            Parent argument parser with added arguments.


        Configures optimizers.

        Returns
        -------
        Tuple[List[Optimizer], List[Dict[str, _LRScheduler]]]
            Tuple containing list of optimizers and list of schedulers.


        Defines a single step in the training loop.

        Parameters
        ----------
        batch : Tuple[Tensor, Tensor, Tensor, Tensor]
            Input batch.
        batch_idx : int
            Batch index.

        Returns
        -------
        Tensor
            Loss.


        Defines a single step in the validation loop.

        Parameters
        ----------
        batch : Tuple[Tensor, Tensor, Tensor, Tensor]
            Input batch.
        batch_idx : int
            Batch index.

        Returns
        -------
        Dict[str, Tensor]
            Dictionary containing tensors for x, f, f_pred, o, o_0.


Defines what to do at the end of each validation epoch.


Run the positive degree day model.

        Use temperature, precipitation, and standard deviation of temperature
        to compute the number of positive degree days, accumulation and melt
        surface mass fluxes, and the resulting surface mass balance.

        *temp*: array_like
            Input near-surface air temperature in degrees Celcius.
        *prec*: array_like
            Input precipitation rate in meter per year.
        *stdv*: array_like (default 0.0)
            Input standard deviation of near-surface air temperature in Kelvin.

        By default, inputs are N-dimensional arrays whose first dimension is
        interpreted as time and as periodic. Arrays of dimensions
        N-1 are interpreted as constant in time and expanded to N dimensions.
        Arrays of dimension 0 and numbers are interpreted as constant in time
        and space and will be expanded too. The largest input array determines
        the number of dimensions N.

        Return the number of positive degree days ('pdd'), surface mass balance
        ('smb'), and many other output variables in a dictionary.


Expand an array to the given shape


Interpolate an array through one year.


Compute instantaneous positive degree days from temperature.

        Use near-surface air temperature and standard deviation to compute
        instantaneous positive degree days (effective temperature for melt,
        unit degrees C) using an integral formulation (Calov and Greve, 2005).

        *temp*: array_like
            Near-surface air temperature in degrees Celcius.
        *stdv*: array_like
            Standard deviation of near-surface air temperature in Kelvin.


Compute accumulation rate from temperature and precipitation.

        The fraction of precipitation that falls as snow decreases linearly
        from one to zero between temperature thresholds defined by the
        `temp_snow` and `temp_rain` attributes.

        *temp*: array_like
            Near-surface air temperature in degrees Celcius.
        *prec*: array_like
            Precipitation rate in meter per year.


        Expand an array to the given shape.

        Parameters
        ----------
        array : np.ndarray
            The input array to be expanded.
        shape : Tuple[int, ...]
            The target shape to expand the array to.

        Returns
        -------
        np.ndarray
            The expanded array.

        Raises
        ------
        ValueError
            If the array cannot be expanded to the target shape.

        Examples
        --------
        >>> arr = np.array([1, 2, 3])
        >>> expanded_arr = _expand(arr, (3, 3))
        >>> print(expanded_arr)
        array([[1, 2, 3],
               [1, 2, 3],
               [1, 2, 3]])


        Integrate an array over one year.

        Parameters
        ----------
        array : np.ndarray
            The input array to be integrated.

        Returns
        -------
        np.ndarray
            The integrated array.

        Examples
        --------
        >>> arr = np.array([1, 2, 3, 4, 5])
        >>> integrated_arr = _integrate(arr)
        >>> print(integrated_arr)
        3.0


        Compute accumulation rate from temperature and precipitation.
        The fraction of precipitation that falls as snow decreases linearly
        from one to zero between temperature thresholds defined by the
        `temp_snow` and `temp_rain` attributes.

        Parameters
        ----------
        temperature : np.ndarray
            Near-surface air temperature in degrees Celcius. Shape: (N,).
        precipitation : np.ndarray
            Precipitation rate in meter per year. Shape: (N,).

        Returns
        -------
        np.ndarray
            Snow accumulation in meters. Shape: (N,).

        Raises
        ------
        ValueError
            If temperature and precipitation arrays have different shapes.


        Fractional part of a year

        Parameters
        ----------
        time : numpy.ndarray
            Decimal time

        Returns
        ----------
        year_fraction : numpy.ndarray
            Year fraction

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    time = np.array([1980.5])
        >>>    year_fraction = debm.year_fraction(time)
        array([0.5])


        The hour angle (radians) at which the sun reaches the solar angle `phi`

        Implements equation 11 in Krebs-Kanzow et al solved for h_phi.

        Equation 2 in Zeitz et al should be equivalent but misses "acos(...)".

        The return value is in the range [0, pi].

        Parameters
        ----------
        phi : float, list of floats or numpy.ndarray
            angle (radians)
        latitude : float, list of floats or numpy.ndarray
            latitude (radians)
        declination : float, list of floats or numpy.ndarray
            solar declination angle (radians)

        Returns
        ----------
        angle: numpy.ndarray
            hour angle (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    phi = np.array([np.pi / 4])
        >>>    latitude = np.array([np.pi / 4])
        >>>    declination = np.array([np.pi / 8])
        >>>    hour_angle = debm.hour_angle(phi, latitude, declination)
        >>>    hour_angle
        array([0.839038303283583])


        Solar longitude (radians) at current time in the year.

        Implements equation A2 in Zeitz et al.

        Parameters
        ----------
        year_fraction : numpy.ndarray
            fraction (1)
        eccentricity : numpy.ndarray
            eccentricity of the earth's orbit (1)
        perihelion_longigute : numpy.ndarray
            perihelion longitude (radians)

        Returns
        ----------
        solar_longitude: numpy.ndarray
            solar longitude at current time in the year (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    year_fraction = np.array([0.5])
        >>>    eccentricity = np.array([0.1])
        >>>    perihelion_longitude = np.array([np.pi/4])
        >>>    solar_longitude = debm.solar_longitude(year_fraction, eccentricity, perihelion_longitude)
        >>>    solar_longitude
        array([2.08753274])


        The unit-less factor scaling top of atmosphere insolation according to the Earth's
        distance from the Sun.

        The returned value is `(d_bar / d)^2`, where `d_bar` is the average distance from the
        Earth to the Sun and `d` is the *current* distance at a given time.

        Implements equation 2.2.9 from Liou (2002).

        Liou states: "Note that the factor (a/r)^2 never departs from the unity by more than
        3.5%." (`a/r` in Liou is equivalent to `d_bar/d` here.)

        Parameters
        ----------
        year_fraction : numpy.ndarray
            fraction (1)

        Returns
        ----------
        distance_factor_present_day: numpy.ndarray
            distance factor present day ()

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    year_fraction = np.array([0.5])
        >>>    distance_factor_present_day = debm.distance_factor_present_day(year_fraction)
        >>>    distance_factor_present_day
        array([0.966608])


        Solar declination (radians)

        Implements equation 2.2.10 from Liou (2002)

        Parameters
        ----------
        year_fraction : numpy.ndarray
            fraction (1)

        Returns
        ----------
        solar_declination: numpy.ndarray
            Solar declination present day ()

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    year_fraction = np.array([0.5])
        >>>    solar_declination = debm.solar_declination_present_day(year_fraction)
        array([0.402769])


        Solar declination (radians). This is the "paleo" version used when
        the trigonometric expansion (equation 2.2.10 in Liou 2002) is not valid.

        The return value is in the range [-pi/2, pi/2].

        Implements equation in the text just above equation A1 in Zeitz et al.

        See also equation 2.2.4 of Liou (2002).

        Parameters
        ----------
        obliquity : numpy.ndarray
            fraction (radians)
        solar_longitude : numpy.ndarray
            Solar longitude (radians)

        Returns
        ----------
        solar_declination: numpy.ndarray
            Solar declination paleo (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    obliquity = np.array([np.pi / 4])
        >>>    solar_longitude = np.array([np.pi * 3 / 4])
        >>>    solar_declination = debm.solar_declination_paleo(obliquity, solar_longitude)
        >>>   solar_declination
        array([0.55536037])


        Average top of atmosphere insolation (rate) during the daily melt period, in W/m^2.

        This should be equation 5 in Zeitz et al or equation 12 in Krebs-Kanzow et al, but both
        of these miss a factor of Delta_t (day length in seconds) in the numerator.

        To confirm this, see the derivation of equation 2.2.21 in Liou and note that

        omega = 2 pi (radian/day)

        or

        omega = (2 pi / 86400) (radian/second).

        The correct equation should say

        S_Phi = A * B^2 * (h_phi * sin(phi) * sin(delta) + cos(phi) * cos(delta) * sin(h_phi)),

        where

        A = (S0 * Delta_t) / (Delta_t_Phi * pi),
        B = d_bar / d.

        Note that we do not know Delta_t_phi but we can use equation 2 in Zeitz et al (or
        equation 11 in Krebs-Kanzow et al) to get

        Delta_t_phi = h_phi * Delta_t / pi.

        This gives

        S_Phi = C * B^2 * (h_phi * sin(phi) * sin(delta) + cos(phi) * cos(delta) * sin(h_phi))

        with

        C = (S0 * Delta_t * pi) / (h_phi * Delta_t * pi)

        or

        C = S0 / h_phi.

        Parameters
        ----------
        solar_constant : numpy.ndarray
            solar constant (W/m^2)
        distance_factor : numpy.ndarray
            distance factor (no units)
        hour_angle : numpy.ndarray
            hour angle (radians)
        latitude : numpy.ndarray
            latitude (radians)
        declination : numpy.ndarray
            declination (radians)

        Returns
        ----------
        insolation numpy.ndarray
            Solar declination paleo (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    solar_constant = np.array([1361.0])
        >>>    distance_factor = np.array([1.1])
        >>>    hour_angle = np.array([0.8])
        >>>    latitude = np.array([np.pi / 4])
        >>>    declination = np.array([np.pi / 8])
        >>>    insolation = debm.insolation(solar_constant, distance_factor, hour_angle, latitude, declination)
        >>>    insolation
        array([1282.10500694])


        Calculate orbital parameters (declination, distance_factor) given a time

        Parameters
        ----------
        time numpy.ndarray
            Time

        Returns
        ----------
        orbital_parameters dict
            Orbital parameters declination, distance_factor

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    time = np.array([2022.25])
        >>>    debm = DEBMModel()

        >>>    debm.orbital_parameters(time)
        (array([0.083785]), array([1.000671]))

        >>>    debm = DEBMModel(paleo_enabled=True)

        >>>    debm.orbital_parameters(time)
        (array([0.07843061]), array([0.99889585]))


Return the number of seconds in a year


        Albedo parameterized as a function of the melt rate

        See equation 7 in Zeitz et al.

        This function converts meltrate from m/yr to m/s before using it in the albedo
        so we can keep the same albedo parameters as in Zeitz et al.

        Parameters
        ----------
        melt_rate numpy.ndarray
            Melt rate (m/yr)

        Returns
        ----------
        albedo numpy.ndarray
            Albedo (1)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    melt_rate = np.array([1.0])

        >>>    debm = DEBMModel()
        >>>    albedo = debm.albedo(melt_rate)

        array([0.79704371])


        Atmosphere transmissivity (no units; acts as a scaling factor)

        See appendix A2 in Zeitz et al 2021.

        Parameters
        ----------
        elevation : numpy.ndarray
            elevation above the geoid (meters)

        Returns
        ----------
        transmissivity numpy.ndarray
            Transmissivity (1)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    elevation = np.array([0.0, 1000.0, 2000.0])
        >>>    transmissivity = debm.atmosphere_transmissivity(elevation)
        >>>    transmissivity
        array([0.65 , 0.682, 0.714])


Run the DEBM model.
        Use temperature, precipitation to compute accumulation and melt
        surface mass fluxes, and the resulting surface mass balance.
        *temperature*: array_like
            Input near-surface air temperature in degrees Celcius.
        *precipitation*: array_like
            Input precipitation rate in meter per year.
        By default, inputs are N-dimensional arrays whose first dimension is
        interpreted as time and as periodic. Arrays of dimensions
        N-1 are interpreted as constant in time and expanded to N dimensions.
        Arrays of dimension 0 and numbers are interpreted as constant in time
        and space and will be expanded too. The largest input array determines
        the number of dimensions N.
        Return surface mass balance
        ('smb'), and many other output variables in a dictionary.


        Compute accumulation rate from temperature and precipitation.
        The fraction of precipitation that falls as snow decreases linearly
        from one to zero between temperature thresholds defined by the
        `temp_snow` and `temp_rain` attributes.

        Parameters
        ----------
        temperature : torch.tensor
            Near-surface air temperature in degrees Celcius. Shape: (N,).
        precipitation : torch.tensor
            Precipitation rate in meter per year. Shape: (N,).

        Returns
        -------
        torch.tensor
            Snow accumulation in meters. Shape: (N,).

        Raises
        ------
        ValueError
            If temperature and precipitation arrays have different shapes.


        Fractional part of a year

        Parameters
        ----------
        time : numpy.tensor
            Decimal time

        Returns
        ----------
        year_fraction : numpy.tensor
            Year fraction

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    time = torch.array([1980.5])
        >>>    year_fraction = debm.year_fraction(time)
        array([0.5])


        The hour angle (radians) at which the sun reaches the solar angle `phi`

        Implements equation 11 in Krebs-Kanzow et al solved for h_phi.

        Equation 2 in Zeitz et al should be equivalent but misses "acos(...)".

        The return value is in the range [0, pi].

        Parameters
        ----------
        phi : float, list of floats or numpy.tensor
            angle (radians)
        latitude : float, list of floats or numpy.tensor
            latitude (radians)
        declination : float, list of floats or numpy.tensor
            solar declination angle (radians)

        Returns
        ----------
        angle: numpy.tensor
            hour angle (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    phi = torch.array([torch.pi / 4])
        >>>    latitude = torch.array([torch.pi / 4])
        >>>    declination = torch.array([torch.pi / 8])
        >>>    hour_angle = debm.hour_angle(phi, latitude, declination)
        >>>    hour_angle
        array([0.839038303283583])


        Solar longitude (radians) at current time in the year.

        Implements equation A2 in Zeitz et al.

        Parameters
        ----------
        year_fraction : numpy.tensor
            fraction (1)
        eccentricity : numpy.tensor
            eccentricity of the earth's orbit (1)
        perihelion_longigute : numpy.tensor
            perihelion longitude (radians)

        Returns
        ----------
        solar_longitude: numpy.tensor
            solar longitude at current time in the year (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    year_fraction = torch.array([0.5])
        >>>    eccentricity = torch.array([0.1])
        >>>    perihelion_longitude = torch.array([torch.pi/4])
        >>>    solar_longitude = debm.solar_longitude(year_fraction, eccentricity, perihelion_longitude)
        >>>    solar_longitude
        array([2.08753274])


        The unit-less factor scaling top of atmosphere insolation according to the Earth's
        distance from the Sun.

        The returned value is `(d_bar / d)^2`, where `d_bar` is the average distance from the
        Earth to the Sun and `d` is the *current* distance at a given time.

        Implements equation 2.2.9 from Liou (2002).

        Liou states: "Note that the factor (a/r)^2 never departs from the unity by more than
        3.5%." (`a/r` in Liou is equivalent to `d_bar/d` here.)

        Parameters
        ----------
        year_fraction : numpy.tensor
            fraction (1)

        Returns
        ----------
        distance_factor_present_day: numpy.tensor
            distance factor present day ()

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    year_fraction = torch.array([0.5])
        >>>    distance_factor_present_day = debm.distance_factor_present_day(year_fraction)
        >>>    distance_factor_present_day
        array([0.966608])


        Solar declination (radians)

        Implements equation 2.2.10 from Liou (2002)

        Parameters
        ----------
        year_fraction : numpy.tensor
            fraction (1)

        Returns
        ----------
        solar_declination: numpy.tensor
            Solar declination present day ()

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    year_fraction = torch.array([0.5])
        >>>    solar_declination = debm.solar_declination_present_day(year_fraction)
        array([0.402769])


        Solar declination (radians). This is the "paleo" version used when
        the trigonometric expansion (equation 2.2.10 in Liou 2002) is not valid.

        The return value is in the range [-pi/2, pi/2].

        Implements equation in the text just above equation A1 in Zeitz et al.

        See also equation 2.2.4 of Liou (2002).

        Parameters
        ----------
        obliquity : numpy.tensor
            fraction (radians)
        solar_longitude : numpy.tensor
            Solar longitude (radians)

        Returns
        ----------
        solar_declination: numpy.tensor
            Solar declination paleo (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    obliquity = torch.array([torch.pi / 4])
        >>>    solar_longitude = torch.array([torch.pi * 3 / 4])
        >>>    solar_declination = debm.solar_declination_paleo(obliquity, solar_longitude)
        >>>   solar_declination
        array([0.55536037])


        Average top of atmosphere insolation (rate) during the daily melt period, in W/m^2.

        This should be equation 5 in Zeitz et al or equation 12 in Krebs-Kanzow et al, but both
        of these miss a factor of Delta_t (day length in seconds) in the numerator.

        To confirm this, see the derivation of equation 2.2.21 in Liou and note that

        omega = 2 pi (radian/day)

        or

        omega = (2 pi / 86400) (radian/second).

        The correct equation should say

        S_Phi = A * B^2 * (h_phi * sin(phi) * sin(delta) + cos(phi) * cos(delta) * sin(h_phi)),

        where

        A = (S0 * Delta_t) / (Delta_t_Phi * pi),
        B = d_bar / d.

        Note that we do not know Delta_t_phi but we can use equation 2 in Zeitz et al (or
        equation 11 in Krebs-Kanzow et al) to get

        Delta_t_phi = h_phi * Delta_t / pi.

        This gives

        S_Phi = C * B^2 * (h_phi * sin(phi) * sin(delta) + cos(phi) * cos(delta) * sin(h_phi))

        with

        C = (S0 * Delta_t * pi) / (h_phi * Delta_t * pi)

        or

        C = S0 / h_phi.

        Parameters
        ----------
        solar_constant : numpy.tensor
            solar constant (W/m^2)
        distance_factor : numpy.tensor
            distance factor (no units)
        hour_angle : numpy.tensor
            hour angle (radians)
        latitude : numpy.tensor
            latitude (radians)
        declination : numpy.tensor
            declination (radians)

        Returns
        ----------
        insolation numpy.tensor
            Solar declination paleo (radians)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    solar_constant = torch.array([1361.0])
        >>>    distance_factor = torch.array([1.1])
        >>>    hour_angle = torch.array([0.8])
        >>>    latitude = torch.array([torch.pi / 4])
        >>>    declination = torch.array([torch.pi / 8])
        >>>    insolation = debm.insolation(solar_constant, distance_factor, hour_angle, latitude, declination)
        >>>    insolation
        array([1282.10500694])


        Calculate orbital parameters (declination, distance_factor) given a time

        Parameters
        ----------
        time numpy.tensor
            Time

        Returns
        ----------
        orbital_parameters dict
            Orbital parameters declination, distance_factor

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    time = torch.array([2022.25])
        >>>    debm = DEBMModel()

        >>>    debm.orbital_parameters(time)
        (array([0.083785]), array([1.000671]))

        >>>    debm = DEBMModel(paleo_enabled=True)

        >>>    debm.orbital_parameters(time)
        (array([0.07843061]), array([0.99889585]))


        Albedo parameterized as a function of the melt rate

        See equation 7 in Zeitz et al.

        This function converts meltrate from m/yr to m/s before using it in the albedo
        so we can keep the same albedo parameters as in Zeitz et al.

        Parameters
        ----------
        melt_rate numpy.tensor
            Melt rate (m/yr)

        Returns
        ----------
        albedo numpy.tensor
            Albedo (1)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    melt_rate = torch.array([1.0])

        >>>    debm = DEBMModel()
        >>>    albedo = debm.albedo(melt_rate)

        array([0.79704371])


        Atmosphere transmissivity (no units; acts as a scaling factor)

        See appendix A2 in Zeitz et al 2021.

        Parameters
        ----------
        elevation : numpy.tensor
            elevation above the geoid (meters)

        Returns
        ----------
        transmissivity numpy.tensor
            Transmissivity (1)

        Examples
        ----------

        >>>    import numpy as np
        >>>    from pism_emulator.models.debm import DEBMModel

        >>>    debm = DEBMModel()

        >>>    elevation = torch.array([0.0, 1000.0, 2000.0])
        >>>    transmissivity = debm.atmosphere_transmissivity(elevation)
        >>>    transmissivity
        array([0.65 , 0.682, 0.714])


Compute melt rates from snow precipitation and pdd sum.

        Snow melt is computed from the number of positive degree days (*pdd*)
        and the `pdd_factor_snow` model attribute. If all snow is melted and
        some energy (PDD) remains, ice melt is computed using `pdd_factor_ice`.

        *snow*: array_like
            Snow precipitation rate.
        *pdd*: array_like
            Number of positive degree days.


Compute instantaneous positive degree days from temperature.
        Use near-surface air temperature and standard deviation to compute
        instantaneous positive degree days (effective temperature for melt,
        unit degrees C) using an integral formulation (Calov and Greve, 2005).
        *temp*: array_like
            Near-surface air temperature in degrees Celcius.
        *stdv*: array_like
            Standard deviation of near-surface air temperature in Kelvin.


Compute accumulation rate from temperature and precipitation.
        The fraction of precipitation that falls as snow decreases linearly
        from one to zero between temperature thresholds defined by the
        `temp_snow` and `temp_rain` attributes.
        *temp*: array_like
            Near-surface air temperature in degrees Celcius.
        *prec*: array_like
            Precipitation rate in meter per year.


Compute melt rates from snow precipitation and pdd sum.
        Snow melt is computed from the number of positive degree days (*pdd*)
        and the `pdd_factor_snow` model attribute. If all snow is melted and
        some energy (PDD) remains, ice melt is computed using `pdd_factor_ice`.
        *snow*: array_like
            Snow precipitation rate.
        *pdd*: array_like
            Number of positive degree days.


Compute accumulationmulation rate from temperature and precipitation.

        The fraction of precipitation that falls as snow decreases linearly
        from one to zero between temperature thresholds defined by the
        `temp_snow` and `temp_rain` attributes.

        *temp*: array_like
            Near-surface air temperature in degrees Celcius.
        *prec*: array_like
            Precipitation rate in meter per year.


Make fake climate to test surface models


Create an artificial temperature and precipitation file.

    This function is used if pypdd.py is called as a script without an input
    file. The file produced contains an idealized, three-dimensional (t, x, y)
    distribution of near-surface air temperature, precipitation rate and
    standard deviation of near-surface air temperature to be read by
    `PDDModel.nco`.

    filename: str, optional
        Name of output file.


        The log likelihood and log prior could be written as
        log_likelihood = torch.distributions.StudentT(nu).log_prob(t).sum()
        log_prior = torch.distributions.Beta(alpha_b, beta_b).log_prob(X_bar).sum()
        but X_bar may contain negative values, for which the Beta distribution bails but torch.log
        returns NaN, which is then just ignored. We could do
        log_prior = torch.distributions.Beta(alpha_b, beta_b, validate_args=False).log_prob(X_bar).sum()


Transform Sin function expression.

    Input:
        function - list. [val1, val2, val3, val4]
        maskFunc - string; 'MASK1=(1, on, 2, off)'
        reach_len - int;
        tread_len - int;
        startPoint - tuple; (x, y)

    Output:
        func - string; "(amp, frq, shift, Mask)"


Transform a user defined function into a proper tread function

    Input:
        funcName - string; "SIN3"
        function - list; [1, 1, 0, "MASK1"]
        maskFunc - string; "MASK1=(1, on, 50, off)"
        reach_len - int
        tread_len - int
        startPoint - tuple; (0, 0)

    Output:
        string; "(1, 2.0, 0, MASK2)"


Validate reach parameters.
    This method will validate the following reach parameters:
        Length - int; default is 100
        Slope - int; default is 0

    In:
        reachPara - dict, containing information of reach parameters.
    Out:
        reachPara - dict, containing verified reach parameters.


Validate step parameters.
    This method will validate the following step parameters:
            tread length - int, default 10,
            riser height - int, default 2,
            riser length - int, default 1,
            tread function - string, default 'flat',
            repeat - int, default 1

    In:
        stepPara - dict, containing information of step parameters.
    Out:
        stepPara - dict, containing verified step parameters.


    Read information in fname file, and store it to proper output data.

    Out:
    reachPara - dictionary;
    stepsList - list; elem: dictionary


Return a mask function string.

    In:
    i - string; mask number
    start - mask start point
    end - mask end point

    Out:
    mask - string; 'MASKi=(start, on, end, off)


Convert user defined functions in each tread.

    In:
    seqNum - string; sequence number of function
    tread_function - string; functions user want to apply on this tread. ex: "SIN1+COS2"
    reachPara - dictionary;
                {'Length':int,
                 'Slope': float // this should be river slope
                 'UserFunctions':{}
                 ...
                }
    maskFun - string; mask function for this tread
    startPoint - [int, int]; x, y value for the tread starting point.

    Out:
    functions - list; elem: string, function declaration.


Basing on the step info, calculate out the functions needed.

    Two things are checked:
        1. Overall step length should be less or equal to reach length.
            -- a violation will ignore the exceeding steps.
        2. A reach always ends with a pool instead of a riser.
            -- a vilation will ignore the last riser.

    In:
    ind - string; index of this step segment
    step - dictionary;
            {'tread length': int,
             'riser height': float,  (riser height is the height of the riser)
             'riser length': int
             'repeat': int
             'tread function': string
            }
    startPoint - [int, float]; x and z value; starting point of this step
    reachPara - dictionary;
                {'Length':int,
                 'Slope': float // this should be river slope
                 'FUN1':[val1, val2, val3, val4]
                 'FUN2':[val1, val2, val3, val4]
                 ...
                }

    Out:
    stepFunctions - list; elem: string
    startPoint - [int, float]; x and z value; ending point of this step


Use reverbuilder to simulate centerline with given reach parameters and functions.

    Parameter:
        xlen - int; reach length
        slope - float; reach slope
        functions - list; elem: function declaration in riverbuilder format

    Output:
        s_v - array; values of centerline points along meandering stream.
        y_v - array; y values of centerline points along x-y coordinate system.
        riverSlope - river slope, not valley slope.


Return string of x with length equal to length of xtot.

    Input:
        x - int
        xtot - int

    Ex:
        1, 3 -> '1'
        1, 33 -> '01'
        1, 123 -> '001'

    Out:
        string


Use reverbuilder to simulate riverthalweg with given reach parameters and functions.

    Parameter:
        xlen - int; reach length
        slope - float; reach slope
        functions - list; elem: function declaration in riverbuilder format

    Output:
        x, y - numpy arrays representing points in x-z coordinate system.


    Parse an input file containing information of a specific
    step-pool river; calculate can return functions can be used
    to generate thalweg of this step-pool river, and plot info
    to plot a simulated image of the thalweg.

    Out:
    functions - list; elem: string
                //each string is a function declaration in riverbuilder
                    inputfile format.
    plot - matplotlib.pyplot plot object


Parse a file, return a dictionary

    fname -- str: path to file

    Return:
    outdict -- dictionary, both key and value are string

    Exception:
    IOError -- program will exit.


Check if the value for a key in a dictionary is valid, return updated dictionary

    fdict -- dictionary needs to be checked and updated
    name -- the key in fdict need to be checked
    defaultVal -- default value for name in fdict when checked failed
    valType -- str that indicate appropriate type of value for name in fdict
    sign -- -1, 0, or 1 represents whether value should be positive, real, or negative

    Return:
    fdict -- updated dictionary with correct value for name
    log -- str that is empty or alert information


name -- name of function


Given a dictionary, extract and parse all allowed functions in it and return a new dictionary

    fdict -- dictionary that may contains allowed functions which are in str type.

    Return:
    funDict -- dictionary that contains allowed functions which values are callable functions.
    log -- str that record all successfully parsed functions and alert msg.

    Constrains:
    Need to defined allowFun and modify funValCheck and forgeFun when the code is changed.


Check if parameter set string is correct for a function, return boolean

    name -- name of function
    val -- parameter set string in form (n1, n2, ...)


Check keys and values in dictionary, return updated dictionaries that
    contains all important information to build river and valley.

    fdict -- dictionary need to be checked

    Return:
    fdict -- updated dictionary with correct key and value pairs
    funDict -- dictionary with values as callable functions
    log -- string format log


Parse a string of different functions, return a callable aggregate function.

    funString -- string in format "SIN1+COS2+LINE3"
    funDict -- dictionary with key as individual function name,
                and value as corresponding callable function

    Return:
    outFun -- callable aggregated function
    log -- string log


Return an appropriate callable function for a given name.

    name -- the thing that we want to assign a function
    fdict -- dictionary to look up what kind of functions are needed for name
    funDict -- dictionary with key as individual function name,
                and value as corresponding callable function
    fun -- default function if the check is failed

    Return:
    outFun -- callable function for name
    log -- string log


Add levels to river or valley in a given direction.

    pattern -- regex pattern that match the name of levels
    fdict -- dictionary that gives information of levels wanted to add
    funDict -- dictionary contain individaul function information
    default_fun -- default function if check or parse fails
    direction -- string "left" or "right"
    obj -- a Channel object or Valley object

    Return:
    obj -- an updated obj with levels added
    log -- string log


Rebuild the channel again and again until a parameter reach target value.

    para - parameter that will be modified every loop
    target - target value of the parameter
    minimum - minimum offset set for the parameter
    obj - channel or river
    buildfun - function that used to build the parameter, ex: channel.createInnerChannel
    calfun - function that used to calculate the parameter

    Return:
    obj - object with a target paraName
    log - string log


Create a channel basing on information given in fdict and funDict.

    fdict -- dictionary contains parameter information for a channel
    funDict -- dictionary contains callable user defined functions

    Return:
    c -- channel that been built
    log -- string log


Create a valley basing on information given in fdict and funDict.

    fdict -- dictionary contains parameter information for a valley
    funDict -- dictionary contains callable user defined functions
    channel -- channel that will be passed to valley

    Return:
    valley -- valley that been built
    log -- string log


Plot levels to a figure.

    ax - the ax to draw to
    xdict - dictionary of values of x values of levels
    ydict - dictionary of values of y values of levels
    labelend - label added to each level, a string
    col - col of dots


    It parse parameters in inputfile, then output to outputfolder.

    fname - inputfile name, end with '.txt'.
    outfolder - output folder name.
    log - additional information want to added to log file.


Shape the centerline. Basically recalculate the centerline.


Create most inner channel of river

        leftFun -- function to calculate left inner bank
        rightFun -- function to calculate right innert bank
        thalwegFun -- function to calculate thalweg

        Value will be modified:
        self.levels_x
        self.levels_y
        self.levels_z
        self.levels_n


        Add boulders
        avail_pts - nested list;
                    elem: [set(available y values), (y1, z1), ...]


        Add check dam
        loc - location along meandering stream.
        height - height from the centerline point.
        thick - how thick is the dam.


Return x, y, z values for all levels in a secondary list


Outwrite xy values and xz values of all banks to output file.


 Construct channel based on the information stored in Channel.

        The construction follows following steps:
            1. Build up centerline.
            2. Build up thalweg.
            3. Build up inner channels.
            4. Build up xshape points.
            5. Build up outer banks.


Return y values and z values of XSection of given x

        n -- number of points to calculate XSection


Return y values and z values of Symmetric XSection of given x.

        ind - index of x value on centerline
        tzn - number of points on base
        n - number of points on XS


Add bank points to xshape points.

        y - y values for xshape points
        z - z values for xshape points
        ind - where the xshape points are calculated

        Return:
        y, z with bank points added


Calculate the z value for the centerline point.


Update the XShape points in XShape points Dictionary.

        pointsList -- [(x, y, z)]


        avail_pts - nested list;
                    elem: [set(available y values), (y1, z1), ...]


        area - list of range
                [(x_start, x_end), (y_start, y_end)]


        2D perlin function through the whole inner channel.
        height is the maximum difference of the noise.


 Smoothen centerline by taking average of neighbors.

        Input:
        degree - number of neighbors to take average
                    (1 means 1 left neighbor and 1 rightneighbor,
                     so 3 points in total.)


Calculate y values of centerline

        fun -- function used to calculate centerline


Return s vector from xy to sn system.


Return x vector, y vector, and n vector for an additional level.

        x_v -- array; x values of the centerline
        y_v -- array; y values of the centerline
        start -- array; values of previous level
        minimum -- float; minimum width offset
        direction -- "left" or "right"
        funInput -- array; values used as input to later function
        fun -- function use to calculate the level

        Return:
        level_x -- array; x values of the new level.
        level_y -- array; y values of the new level.
        level_n -- array; n values of the new level.


Clean up points of level cross over each other after it is transformed from sn to xy.

        level_x -- array; x values
        level_y -- array; y values
        direction -- "left" or "right"
        level_n -- array; n values

        Return:
        Clean up level_x and level_y.


Return a list of (x, y) tuples that are crossed by line from point1 to point2

        Return:
        [(xi, yi)] -- xi, yi are rounded to 1


 Calculate the height of a new added level.

            The height is calculated from its previous level and
                the slope of the pipe.


Calculate area covered by a list of vectors.


Convert points in a dictionary to a set with points in (x, y) format.

        innerPipePoints - dictionary;
                            key: int; x value
                            value: list; y values

        Return:
        innerPoints - set; element: (x, y)


Check if there are highcurve area and return a boolean list to indicate that.

        x_min - int; x value we start from to check
        x_max - int; x value we end on to check
        points_start - set; points in (x, y) format we want to check
        level_n - array; values of n values of level

        return:
        highcurvs - list of boolean; True means at this point there is a highcurv.


        Retrieve x values and y values for the outer shape of the covered_area

        covered_area - list of lists; index is x value, lists are y values
        x_min - int; x value we start from to draw the outer shape
        x_max - int; x value we end on to draw the outer shape
        direction - 'left' or 'right'
        points_start - set of tuples; contains starting points as in (x, y) format
        level_n - array; values of n values of level
        innerPipePoints - dictionary;
                            key: int; x value
                            value: list; y values

        Return:
        out_x - array; x values of level
        out_y - array; y values of level


Return an array is in range [0, 2*pi]


Return an array of y values based on a linear calculation.


Check if a mask is valid.

    A valid mask should be in form: [DIST1, 0/1, DIST2, 0/1, ...];
    The max dist should be smaller or equal to max value in array.
    The DIST should be increasing in each declaration.
    1 means on in the corresponding segment; 0 means off.
    A special mask is [ALL] indicates always on.

    Output:
    A valid mask with form:
    [(len1, True/False), (len2, True/False), ...]


Turn on and off on function calculation.

    Inputs:
    y_v - array. y values.
    x_v - array, x values.
    mask - list. [[len1, len2, True/False], [len2, len3, True/False],...]

    Return:
    an undated array with y values.


Return the sin values of the array.

    Input:
    array - the values in this array will be transform into 2*pi*xi/max_x
            before calculation.

    Output:
    array - the original array
    out_y - an array of sin values of the original array.


Return the cos values of the array.

    Input:
    array - the values in this array will be transform into 2*pi*xi/max_x
            before calculation.

    Output:
    array - the original array
    out_y - an array of cos values of the original array.


Return the sin^2 values of the array.

    Input:
    array - the values in this array will be transform into 2*pi*xi/max_x
            before calculation.

    Output:
    array - the original array
    out_y - an array of sin^2 values of the original array.


Return the cos^2 values of the array.

    Input:
    array - the values in this array will be transform into 2*pi*xi/max_x
            before calculation.

    Output:
    array - the original array
    out_y - an array of cos^2 values of the original array.


Calculate the offsets from a centerline.

    Input:
    s_v - array. Values feed to function to calculate the offsets.
            Can be thought as the x values of the line.
    start - array. Initial values that will be added to offsets.
            Can be thought as the y valuse of the line.
    minimum - minimum value of the offset.
    direction - string. 'left' or 'right'.
                'left' increases; 'right' decreases.
    fun - function used to calculate offsets.

    Output: an array contains offset values.


Return slope of two points.


Return an array of slope.
        si = (y(i+1) - y(i))/(x(i+1) - x(i))
        s(-1) will be the same as s(-2) to make it the same length.

    Inputs:
    x_v - array. x values.
    y_v - array. y values.

    Output:
    s_v - array. slopes.


Return an array of curvature.

    Inputs:
    x_v - array. x values.
    y_v - array. y values.

    Output:
    s_v - array. curvatures.


 Shields equation:
        the default sediment is sand
        data is from https://www.simetric.co.uk/si_materials.htm

        The result has unit in meters.


Transform a point from sn coodinate system to xy coodinate system.

    Inputs:
    x1, y1 - x, y values of point at the centerline.
    x2, y2 - x, y values of next point at the centerline.
    n - distance from the point we want to transform to the first point at
        centerline.

    Outputs:
    x, y - x, y values of point we want to transform.


Transform an array of points from sn coordinate system to xy coordinate system.
    The last point has the same x, y as the second last point to maintain the length.

    Inputs:
    x_v, y_v - x, y values of points at the centerline.
    n_v - offsets from the points to their corresponding centerline points.

    Output:
    out_x, out_y - x, y values of points need to be transformed.


Transform a point from xy coodinate system to sn coodinate system.

    Inputs:
    x1, y1 - x, y values of centerline point.
    x2, y2 - x, y values of offset point.
    direction - 'left' indicates positive; 'right' indicates negative.

    Output:
    n - distance from offset point to centerline point.


Linear function calculator.

    Inputs:
    x1, y1 - info of point 1.
    x2, y2 - info of point 2.
    x3 - x of point 3.

    Output:
    y of point 3.


Distance between neighbors in a line.

        The length will decrease by 1.


Return distance from point2 to perpendicular line of point1.
    The perpendicular line is in form: as a*x + b*y + c = 0

    slope -- slope at point1
    point1, point2 -- (x, y)


Return boolean if these two vectors intersect with each other

    vi_pj -- j point of vector i

    Reference:
    https://stackoverflow.com/questions/563198


Return y value of x on a given line p1 to p2.


Interpolation function to connect y1, y2 smoothly.

    x should be in [0, 1]


Return the result of a perlin function.

    x_v - uniformly places vector to calculate perlin function
    amplitude - maximum value of the result
    wavelength - how frequently will we comput a random value,
                 smaller wavelength means higher frequency.


Return the result of a cnoidal waves.

    Inputs:
    x_v - uniformly places array to calculate cnoidal function
    a - amplitude, maximum value of the result
    f - frequency
    s - phase shift
    m - elliptic parameter ([0, 1], closer to 1, sharper peak)
    mask - on and off indication of the function.

    Output:
    x_v, y_v - x, y values of cnoidal wave.


Return the result of a wave looked like steps.

    x_v - uniformly places vector to calculate perlin function
    a - amplitude, maximum value of the result
    f - frequency
    s - phase shift
    m - elliptic parameter ([0, 1], closer to 1, sharper peak)


    x_v - uniformly places vector to calculate high curvature function.
    a - amplitude, maximum value of the result
    f - frequency
    ps - phase shift
    p - sinuosity (with p>2, we should have high curvature function)


Returns the angle in radians between vectors v1 and v2


    line - list of points, each point is (x, y, ...),
            the order of points is the trend of the line


    1. Round points in ln to int (only x and y values)
    2. Remove duplicate points in ln (if both x and y matches)


grad converts h to the right gradient vector and return the dot product with (x,y)


Return x, y values for all levels in a secondary list.


Return x, y z values for everythin in a secondary list.


Outwrite xy values and xz values of all levels to output file.


GUI button command: opens browser window and adds selected file/folder to entry


Return an array of slope.
        si = (y(i+1) - y(i))/(x(i+1) - x(i))
        s(-1) will be the same as s(-2) to make it the same length.

    Inputs:
    x_v - array. x values.
    y_v - array. y values.

    Output:
    s_v - array. slopes.


This function plots a N number of Fourier coefficients reconstrution of input signals. Exports coefficients to csv or text file.
    in_csv= A csv file location with evenly spaced values (string).
    sort_by (optional) allows an unsorted csv to be sorted by a input index field header (string)
    out_folder= Folder to which plots and exported coefficients are saved (string).
    index_field is the csv header corresponding to the centerline position, the units parameter can be any length unit and is used strictly for plotting (empty is default).
    fields= A list of csv headers from which signals are plotted and reconstructed (list of strings)
    field_names (optional) if specified must be a list of strings with names for plotting titles
    R_2= R^2 threshold for signal reconstruction (float). 0.95 is default.
    n (0 is default) if not 0 and an int allows a number of Fourier components to specified (int), as opposed to the standard R^2 threshold (default)
    by_power (False is default) if True takes the N highest power components first
    by_bins (False is default) if True splits the FFT components into N bins, and selects the highest power frequency from each
    to_riverbuilder (False


    return
    out - str; "SIN[funID]=(amplitude, frequency, phase, "MASK0")"
                which mimic the curve represented by x_v, y_v


Create a bounding polygon from multiple lines.


Save lines with their IDs and points to a CSV file with 'X' and 'Y' columns.


Simulate a centerline with parameters provided by the user input file.

    fname - input file name.

    Output:
    The program will generate an image saved in 'simulatedCenterline' file.


Whether to treat a value as a scalar. Any non-iterable, string, or 0-D array


Logic for setting the window properties


Define a nice spectrum with twin x-axis, one with frequencies, the
	other one with periods.

	Parameters
	----------
	spectrum : 1d xarray.DataArray or 1darray
		The array where the spectrum is stored
	freqs: 1d vector, optional
		The frequency vector. If None, the frequency vector is inferred
		from the DataArray
	drop_zero_frequency : bool, optional
	    If True, do not plot the zero frequency
	ax : matplotlib axes, optional
		If None, uses the current axis.
	xlog : bool, optional
		If True, use log scaling for the x axis
	ylog : bool, optional
		If True, use log scaling for the y axis
	loglog : bool, optional
		If True, use log scaling for both axis
	variance_preserving : bool, optional
		If True, scale the spectrum by the log of frequencies to use the
		variance preserving form
	xlim : tuple, optional
		Set x-axis limits
	ylim : tuple, optional
		Set y-axis limits
	title : string, optional
		Set the title
	**kwargs : optional
		Additional arguments to matplotlib.pyplot.plot


Plot a logarithmic power law

	Parameters
	----------
	power : float
		The exponent of the power law
	scale_factor : float, optional
		The factor to scale the power law with
	ax : matplotlib axes, optional
		If None, uses the current axis.
	**kwargs : optional
		Additional arguments to matplotlib.pyplot.plot

	Returns
	-------
	lines : Line2D
		Return a Line2D object created by the matplotlib.axes.Axes.plot method


Fit a logarithmic spectral law based on the input  one
	dimensional spectrum

	Parameters
	----------
	freq : 1darray
		The frequency coordinates
	spectrum : 1darray
		The one-dimensional spectrum

	Returns
	-------
	power : float
		The power characteristic of a power law spectrul
	scale_factor: float
		The scale factor related to fit the power law with the input spectrum


	Define a nice spectrum with twin x-axis and twin y-axis, one with
	frequencies, the other one with periods, on a predefined axis
	object.

	Parameters
	----------
	x,y : array_like
		1D array defining the coordinates
	z : array_like
		2D array
	xlog, ylog, zlog : bool, optional
		Define if the x-axis, y-axis and z-axis are plotted with a
		log	scale
	** kwargs : optional keyword arguments
		See matplotlib.axes.Axes.contourf method in matplotlib
		documentation


	Return the amplitude spectrum from the Fourier Transform

	Parameters
	----------
	spectrum : DataArray
		A DataArray spectrum computed using xscale.spectral.fft.fft
	deg : bool, optional
		If True, return the phase spectrum in degrees. Default is to return
		the phase spectrum in radians

	Returns
	-------
	res : DataArray
		The phase spectrum


	Return the phase spectrum from the Fourier Transform

	Parameters
	----------
	spectrum : DataArray
		A DataArray spectrum computed using xscale.spectral.fft.fft
	deg : bool, optional
		If True, return the phase spectrum in degrees. Default is to return
		the phase spectrum in radians

	Returns
	-------
	res : DataArray
		The phase spectrum


	Return the Power Spectrum (PS) from the Fourier Transform

	Parameters
	----------
	spectrum : DataArray
		A DataArray spectrum computed using xscale.spectral.fft.fft

	Returns
	-------
	power_spectrum : DataArray
		The PS spectrum


	Return the Power Spectrum density (PSD) from the Fourier Transform

	Parameters
	----------
	spectrum : DataArray
		A DataArray spectrum computed using xscale.spectral.fft.fft

	Returns
	-------
	power_spectrum_density : DataArray
		The PSD spectrum


Compute the spectrum on several dimensions of xarray.DataArray objects
	using the Fast Fourrier Transform parrallelized with dask.

	Parameters
	----------
	array : xarray.DataArray
		Array from which compute the spectrum
	dim : str or sequence
		Dimensions along which to compute the spectrum
	dx : float or sequence, optional
		Define the resolution of the dimensions. If not precised,
		the resolution is computed directly from the coordinates associated
		to the dimensions.
	detrend : {None, 'mean', 'linear'}, optional
		Remove the mean or a linear trend before the spectrum computation
	tapering : bool, optional
		If True, tapper the data with a Tukey window
	shift : bool, optional
		If True, the frequency axes are shifted to center the 0 frequency,
		otherwise negative frequencies follow positive frequencies as in
		numpy.fft.ftt
	sym : bool, optional
		If True, force the spectrum to be symmetrical even if the input data
		is real
	chunks : int, tuple or dict, optional
		Chunk sizes along each dimension, e.g., ``5``, ``(5, 5)`` or
		``{'x': 5, 'y': 5}``

	Returns
	-------
	res : DataArray
		A multi-dimensional complex DataArray with the corresponding
		dimensions transformed in the Fourier space.

	Notes
	-----
	If the input data is real, a real fft is performed over the first
	dimension, which is faster. Then the transform over the remaining
	dimensions are computed with the classic fft.


This function is for private use only.


Perform a tappering of the data over the specified dimensions with a tukey window


Compute the normalization factor for Power Spectrum and Power Spectrum Density


Similar to numpy.fft.fttshift but based on dask.array


Similar to numpy.fft.ifttshift but based on dask.array


	Perform a singular spectrum analysis by computing the eigenvalues
	the lagged covariance matrix.

	Parameters
	----------
	x : dataArray
		A vector of length n.
	dim : str
	    Dimension along which compute the

	Returns
	-------
	res : dataArray
		A dataArray that returns the result from the singular spectrum analysis


Build the covariance matrix for singular spectrum analysis


Compute the reconstructed component from the SSA decomposition


	Generate a red noise

	Parameters
	----------
	alpha: float
		Autocorrelation coefficient of the red noise
	n: int
		Size of the vector
	c: float
		Mean of the vector

	Returns
	-------
	res: 1darray
		A vector of size n describing a rednoise process

	Examples
	--------
	>>> rednoise(0.8, 6)


	Generate a timeseries using an autoregressive process

	Parameters
	----------
	coeffs: iterable
		Coefficients of the autoregressive process
	n: int
		Size of the vector
	c: float
		Mean of the vector

	Returns
	-------
	res: 1darray
		A vector of size n describing an autoregressive process


	Generate a one dimensional window from `scipy.signal.get_window`

	Parameters
	----------


Generate a trend


	Generate a time-space DataArray to be used as an example with `xscale`
	functions


	Generate a time-space DataArray with two spatial dimensions ['x', 'y'] on a
	regular grid.


	Least squares polynomial fit.
	Fit a polynomial ``p(x) = p[deg] * x ** deg + ... + p[0]`` of degree `deg`
	Returns a vector of coefficients `p` that minimises the squared error.

	Parameters
	----------
	x : xarray.DataArray
		The array to fit
	deg : int, optional
		Degree of the fitting polynomial, Default is 1.
	dim : str, optional
		The dimension along which the data will be fitted. If not precised,
		the first dimension will be used
	coord : xarray.Coordinate, optional
		The coordinates used to based the fitting on.

	Returns
	-------
	output : xarray.DataArray
		Polynomial coefficients with a new dimension to sort the polynomial
		coefficients by degree


	Build an array from polynomial coefficients

	Parameters
	----------
	coefficients : xarray.DataArray
		The DataArray where the coefficients are stored
	coord : xarray.Coordinate
		The locations where the polynomials is evaluated

	Returns
	-------
	output : xarray.DataArray
		The polynomials evaluated at specified locations


	Compute a linear regression using a least-square method

	Parameters
	----------
	obj : xarray.DataArray or xarray.Dataset
		The array on which the linear regression is computed
	dim : str, optional
		The dimension along which the data will be fitted. If not precised,
		the first dimension will be used
	coord : xarray.Coordinate, optional
		The coordinates used to based the linear regression on.

	Returns
	-------
	slope : xarray.DataArray or xarray.Dataset
		An array containing the slope of the linear regression
	offset : xarray.DataArray or xarray.Dataset
		An array containing the offset of the linear regression


	Compute the trend over one dimension of the input array.

	Parameters
	----------
	array : xarray.DataArray
		The data on which the trend is computed
	dim : str, optional
		Dimension over which the array will be detrended
	type : {'constant', 'linear', 'quadratic'}, optional
		Type of trend to be computed. Default is 'linear'.

	Returns
	-------
	array_trend : xarray.DataArray
		The trend associated with the input data


	Remove a trend over one dimension of the data.

	Parameters
	----------
	array : xarray.DataArray or xarray.Dataset
		Data to be detrended
	dim : str, optional
		Dimension over which the array will be detrended
	type : {'constant', 'linear', 'quadratic'}, optional
		Type of trend to be removed. Default is 'linear'.

	Returns
	-------
	data_detrended : xarray.DataArray or xarray.Dataset
		The detrended data


	Least squares sinusoidal fit.
	Fit sinusoidal functions ``y = A[p] * sin(2 * pi * ax * f[1] + phi[1])``

	Parameters
	----------
	array : xarray.DataArray
		Data to be fitted
	periods: float or list of float
		The periods of the sinusoidal functions to be fitted
	dim : str, optional
		The dimension along which the data will be fitted. If not precised,
		the first dimension will be used
	unit : {'D', 'h', 'm', 's', 'ms', 'us', 'ns'}, optional
		If the fit uses a datetime dimension, the unit of the period may be
		specified here.

	Returns
	-------
	modes : Dataset
		A Dataset with the amplitude and the phase for each periods


	Evaluate a sinusoidal function based on a modal decomposition. Each mode is
	defined by a period, an amplitude and a phase. This function may usually
	be used after a sinusoidal fit using
	:py:func:`xscale.signal.fitting.sinfit`.

	Parameters
	----------
	modes : xarray.Dataset
		A dataset where the amplitude and phase are stored for each mode
	coord : xarray.Coordinates
		A coordinate array at which the sine functions are evaluated

	Returns
	-------
	res : xarray.DataArray


	Private function used to reorder to use the work dimension as the first
	dimension, stack all the dimensions except the first one


Convolve the current window with the data

		Parameters
		----------
		mode : {'reflect', 'periodic', 'any-constant'}, optional
			The mode parameter determines how the array borders are handled.
			Default is 'reflect'.
		weights : DataArray, optional
			Array to weight the result of the convolution close to the
			boundaries.
		trim : bool, optional
			If True, choose to only keep the valid data not affected by the
			boundaries.

		Returns
		-------
		res : xarray.DataArray
			Return a filtered DataArray


		Compute the boundary weights

		Parameters
		----------
		mode : {'reflect', 'periodic', 'any-constant'}, optional
			The mode parameter determines how the array borders are handled.
			Default is 'reflect'.
		mask : array-like, optional
			Specify the mask, if None the mask is inferred from missing values
		drop_dims : list, optional
			Specify dimensions along which the weights do not need to be
			computed

		Returns
		-------
		weights : xarray.DataArray or xarray.Dataset
			Return a DataArray or a Dataset containing the weights


		Do a tappering of the data using the current window

		Parameters
		----------
		overlap:

		Returns
		-------
		data_tappered : dask array
			The data tappered y the window

		Notes
		-----


		Plot the weights distribution of the window and the associated
		spectrum (work only for 1D and 2D windows).


Convolve the current window with the data


Helper function to print messages neatly


Performs anti-diagonal averaging from given hankel matrix
        Returns: Pandas DataFrame object containing the reconstructed series


Embed the time series with embedding_dimension window size.
        Optional: suspected_frequency changes embedding_dimension such that it is divisible by suspected frequency


Perform the Singular Value Decomposition and identify the rank of the embedding subspace
        Characteristic of projection: the proportion of variance captured in the subspace


View the contribution to variance of each singular value and its corresponding signal


Visualise the reconstruction of the hankel matrix/matrices passed to *hankel


Forecast from last point of original time series up to steps_ahead using recurrent methodology
        This method also fills any missing data from the original time series.


Takes a roms history or averages file (wildcards are possible) and returns a Xarray dataset including 4D mask, 3D grid coordinates and 4D depths


    This program use the Mellor-Ezer-Oey method (Mellor et al., 1994).
    The bathymetry is optimized for a given rx0 factor by doing a sequence
    of increase/decrease at adjacent cells.

    Usage:
    RetBathy, HmodifVal, ValueFct = smoothing_PlusMinus_rx0(MSK, Hobs, rx0max, AreaMatrix)

    ---MSK(eta_rho,xi_rho) is the mask of the grid
         1 for sea
         0 for land
    ---Hobs(eta_rho,xi_rho) is the raw depth of the grid
    ---rx0max is the target rx0 roughness factor
    ---AreaMatrix(eta_rho,xi_rho) is the matrix of areas at
       rho-points.


!
    @brief general parallel interpolation using dask and griddata
    @param xx 1d or 2d array of x locs where data is known
    @param yy 1d or 2d array of x locs where data is known
    @param z_array 1d or 2d array of x locs where data is known
    @param target_xi 2d array (or 1d grid spacing array)
    @param target_yi 2d array (or 1d grid spacing array)


!
    @brief 2d interpolation using dask and griddata
    @param xx np_2darray x coord array
    @param yy np_2darray y coord array
    @param z_array np_2darray response vals


    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees). Takes arrays.


Calculates the cartesian distances dx, dy of computational roms grid.
    Shape(dx)=shape(dy)=shape(lon_rho)
    Usage: dx,dy = cartesian_grid_2d(lon_u,lat_u,lon_v,lat_v)


convert one item to appropriate type


 parses metafile (file object or filename) into a dictionary of lists
        of floats, ints or strings


Reads in SothernOceanStateEstimate Temperatures and Salinities and returns them in a Xarray dataset.


    return u-, v-, and psi-masks based on input rho-mask

    Parameters
    ----------

    rmask : ndarray
        mask at CGrid rho-points

    Returns
    -------
    (umask, vmask, pmask) : ndarrays
        masks at u-, v-, and psi-points


Calculates from the salinity (Sal,psu), the in-situ Temperature
       (Temp, degC) and the in-situ pressure (Pres, dbar) the adiabatic
       temperature gradient (dTemp, K Dbar^-1).

         Check values:  dTemp  =     3.255976E-4 K dbar^-1
                  given Sal    =    40.0         psu
                        Temp   =    40.0         degC
                        Pres   = 10000.000       dbar


! Calculates from the salinity (sal, psu), the in-situ temperature
    ! (Temp, degC) and the in-situ pressure press, dbar) the potential
    ! temperature (Theta, degC) converted to the reference pressure
    ! (RPres, dbar). A Runge-Kutta procedure of the fourth order is used.
    !
    ! Check value: theta   =    36.89073  degC
    !         given sal    =    40.0      psu
    !               Temp   =    40.0      degC
    !               pres   = 10000.000    dbar
    !               rfpres =     0.000    dbar


! *********************************************************************
    ! Calculates from the salinity (sal, psu), potential temperature
    ! (theta, degC) and reference pressure (pres, dbar) the in-situ
    ! temperaure (Temp_insitu, degC) related to the in-situ pressure
    ! (rfpres, dbar) with the help of an iterative method.


img is an image of shape [n, m, 3], and rgb is a colormap of shape [k, 3].


        Update the clock files if the current clockfile is old and we haven't checked recently for new ones
        :param clockdir:
        :param ifolderthan_days:
        :param test_days:
        :return:


    Correction factor to add to MET to get UTC
    :param met:
    :param printCaveats:
    :param returnCaveats:
    :return:


Convert other times to

    Args:
        t (_type_): _description_
        plus (_type_, optional): _description_. Defaults to None.
        units (str, optional): _description_. Defaults to "days".
        stepby (_type_, optional): _description_. Defaults to None.
        nsteps (_type_, optional): _description_. Defaults to None.
        stepto (_type_, optional): _description_. Defaults to None.


        A simple name is the alphanumerics of the name in lower case.
        This folds + and - dec designations, but in practice not a problem
        :param name:
        :return:


    Location according to
    :param objectname:
    :return: (ra_deg, dec_deg)


Use spacetrack tles from database (not publicly available)


    Given theta,phi in radians, returns (open_coded_area_in_cm^2, cosfactor)

    theta = distance from center of FOV (boresight) in radians
    phi = angle around boresight in radians.
    This is moderate accuracy, but does not take into account, e.g. dead detectors.


    Convert detector ids to x,y positions

    This is tricky.  You can understand it, but it isn't worth it.

    :param detids: detector ids (ints 0...32767)
    :type detids: scalar int or convertible to a numpy array
    :return: x,y
    :rtype: x and y are each numpy arrays or scalars the same size as the original detids


    Produce a detector map filled with detector IDs

    -1 for unpopulated detector locations

    :return: detids[y, x]
    :rtype: uint16, shape = (173, 286)


Read in source catalog

    FIXME, should be more automatic


The source as a '|'-delimted string as used in ASCII catalog tables

        Args:
            ra (float): degrees
            dec (float): degrees
            name (str, optional): _description_. Defaults to "anonymous".
            catnum (int, optional): _description_. Defaults to -1.

        Returns:
            str: _description_


Position of source as a skyfield.Position


_Source position in instrument FOV given instrument pointing direction
            returns (thetangle,phi) where thetangle is the angular distance from
            the boresight and phi is the angle from the phi=0 axis of BAT.

            theta = tan(thetangle) gives the theta we use, which is the projected distance to a flat plane,
            but it is not useful for thetangle > 90 degrees

        Args:
            ra (float): ra of spacecraft boresight in degrees
            dec (float): dec of spacecraft boresight in degrees
            roll (float): roll is 'roll left' (CCW as seen from behind looking out along boresight) in degrees
        Returns:
            (theta:degree, phi:apAngle): location of source in spacecraft spherical coordinates


Default implementation does nothing

        Args:
            t (time): _description_