Plots the Transient data and returns Axes.

        :param axes: Matplotlib axes to plot the lightcurve into. Useful for user specific modifications to the plot.
        :param filename: Name of the file to be plotted in.
        :param outdir: The directory in which to save the file in.
        :param save: Whether to save the plot. (Default value = True)
        :param show: Whether to show the plot. (Default value = True)
        :param plot_others: Whether to plot inactive bands. (Default value = True)
        :param color: Color of the data.
        :param kwargs: Additional keyword arguments to pass in the Plotter methods.
        Available in the online documentation under at `redback.plotting.Plotter`.
        `print(Transient.plot_data.__doc__)` to see all options!
        :return: The axes with the plot.


        :param figure: Figure can be given if defaults are not satisfying.
        :param axes: Axes can be given if defaults are not satisfying.
        :param filename: Name of the file to be plotted in.
        :param outdir: The directory in which to save the file in.
        :param save: Whether to save the plot. (Default value = True)
        :param show: Whether to show the plot. (Default value = True)
        :param ncols: Number of columns to use on the plot. Default is 2.
        :param nrows: Number of rows to use on the plot. If None are given this will
                      be inferred from ncols and the number of filters.
        :param figsize: Size of the figure. A default based on ncols and nrows will be used if None is given.
        :param filters: Which bands to plot. Will use default filters if None is given.
        :param kwargs: Additional keyword arguments to pass in the Plotter methods.
        Available in the online documentation under at `redback.plotting.Plotter`.
        `print(Transient.plot_multiband.__doc__)` to see all options!
        :return: The axes.


        Fit a GP to the data using george and scipy minimization.

        :param mean_model: Mean model to use in the GP fit. Can be a string to refer to a redback model, a callable, or None
        :param kernel: George GP to use. User must ensure this is set up correctly.
        :param prior: Prior to use when fitting with a mean model.
        :param use_frequency: Whether to use the effective frequency in a 2D GP fit. Cannot be used with most mean models.
        :return: Named tuple with George GP object and additional useful data.


        :param model: The model used to plot the lightcurve.
        :param filename: The output filename. Otherwise, use default which starts with the name
                         attribute and ends with *lightcurve.png.
        :param figure: Figure can be given if defaults are not satisfying.
        :param axes: Axes to plot in if given.
        :param save:Whether to save the plot.
        :param show: Whether to show the plot.
        :param random_models: Number of random posterior samples plotted faintly. (Default value = 100)
        :param posterior: Posterior distribution to which to draw samples from. Is optional but must be given.
        :param outdir: Out directory in which to save the plot. Default is the current working directory.
        :param model_kwargs: Additional keyword arguments to be passed into the model.
        :param kwargs: Additional keyword arguments to pass in the Plotter methods.
        Available in the online documentation under at `redback.plotting.Plotter`.
        `print(Transient.plot_multiband_lightcurve.__doc__)` to see all options!

        :return: The axes.


Loads data from specified directory and file, and returns it as a tuple.

        :param processed_file_path: Path to the processed file to load
        :type processed_file_path: str
        :param data_mode: Name of the data mode.
                          Must be from ['magnitude', 'flux_density', 'all']. Default is magnitude.
        :type data_mode: str, optional

        :return: Six elements when querying magnitude or flux_density data, Eight for 'all'
        :rtype: tuple


Constructor method to built object from Open Access Catalogue

        :param name: Name of the transient.
        :type name: str
        :param data_mode: Data mode used. Must be from `OpticalTransient.DATA_MODES`. Default is magnitude.
        :type data_mode: str, optional
        :param active_bands:
            Sets active bands based on array given.
            If argument is 'all', all unique bands in `self.bands` will be used.
        :type active_bands: Union[np.ndarray, str]
        :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
        :type plotting_order: Union[np.ndarray, str], optional
        :param use_phase_model: Whether to use a phase model.
        :type use_phase_model: bool, optional

        :return: A class instance
        :rtype: OpticalTransient


        :return: Path to the metadata table.
        :rtype: str


Sets the metadata from the event table.


        :return: The transient directory given the name of the transient.
        :rtype: str


        :return: The transient directory path
        :rtype: str


Thin wrapper around requests.Request, logging URL sent and Content-Type received

  See https://requests.readthedocs.io/en/master/api/#requests.Request for args

  Returns:
      requests.Response -- The response to the request


Called when a worker tasks completes
    Arguments:
      exception {Exception} -- if an error occurs
      result {} - the response from  the worker task


Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString


Create the menu entries and toolbar icons inside the QGIS GUI.


Removes the plugin menu item and icon from QGIS GUI.


Add a search parameter to the parameter table


Run method that performs all the real work


Load HarmonyQGIS class from file HarmonyQGIS.

    :param iface: A QGIS interface instance.
    :type iface: QgsInterface


Main entry point.

    :param parameters: Command line parameters.
    :param arguments: Command line arguments.


Handle layers being added to the registry so they show up in canvas.

        :param layers: list<QgsMapLayer> list of map layers that were added

        .. note:: The QgsInterface api does not include this method,
            it is added here as a helper to facilitate testing.


Get pointer to the active layer (layer selected in the legend).


Read a string


Read a data string (length is specified twice)


Read a variable with a specified data type


    Read a structure, with the array and structure descriptors given as
    `array_desc` and `structure_desc` respectively.


    Read an array of type `typecode`, with the array descriptor given as
    `array_desc`.


Function to read in a full record


Function to read in a type descriptor


Function to read in an array descriptor


Function to read in a structure descriptor


Function to read in a tag descriptor


    Read an IDL .sav file

    Parameters
    ----------
    file_name : str
        Name of the IDL save file.
    idict : dict, optional
        Dictionary in which to insert .sav file variables
    python_dict: bool, optional
        By default, the object return is not a Python dictionary, but a
        case-insensitive dictionary with item, attribute, and call access
        to variables. To get a standard Python dictionary, set this option
        to True.
    uncompressed_file_name : str, optional
        This option only has an effect for .sav files written with the
        /compress option. If a file name is specified, compressed .sav
        files are uncompressed to this file. Otherwise, read will use
        the `tempfile` module to determine a temporary filename
        automatically, and will remove the temporary file upon successfully
        reading it in.
    verbose : bool, optional
        Whether to print out information about the save file, including
        the records read, and available variables.

    Returns
    ----------
    idl_dict : AttrDict or dict
        If `python_dict` is set to False (default), this function returns a
        case-insensitive dictionary with item, attribute, and call access
        to variables. If `python_dict` is set to True, this function
        returns a Python dictionary with all variable names in lowercase.
        If `idict` was specified, then variables are written to the
        dictionary specified, and the updated dictionary is returned.


    Reshape an LLC grid data array into separate east and west hemisphere arrays.

    This function takes an array representing data on the LLC grid and separates it into two arrays,
    one for the eastern hemisphere (tiles 1-6) and one for the western hemisphere (tiles 8-13). Tile 7 is for Arctic but not included here.
    The function does not perform any rotation on the data, meaning that the u and v components
    (typically representing eastward and northward velocity components in oceanographic data) remain mixed for the llc grid layout

    Parameters:
    -----------
    dd : numpy.ndarray or list of numpy.ndarray
        The input data array(s) to be reshaped. Each array should be of size 13*nx**2,
        where nx is the size of the LLC grid. The input can also be a list of such arrays.
    nx : int, optional
        The size of one side of the LLC grid. Default is 4320, suitable for the llc4320 model.

    Returns:
    --------
    (deast, dwest) : tuple
        deast : numpy.ndarray or list of numpy.ndarray
            The eastern hemisphere data array(s), each with dimensions (4320x3, 4320x2).
        dwest : numpy.ndarray or list of numpy.ndarray
            The western hemisphere data array(s), each with dimensions (4320x2, 4320x3),
            non-rotated (x is latitude, y is longitude).

    Examples:
    ---------
    # Reshaping a single data array
    east, west = mds2d(data_array)

    # Reshaping a list of data arrays
    reshaped_data_list = mds2d(list_of_data_arrays)

    Notes:
    ------
    The input data should be structured with specific tiles corresponding to different parts of
    the global grid. The function assumes that tiles 1-6 represent the eastern hemisphere and
    tiles 8-13 represent the western hemisphere. Tiles 7 Arctic is not included.


We ignore SIGINT. It's up to our parent to kill us in the typical condition
    of this arising from ``^C`` on a terminal. If someone is manually killing
    us with that signal, well... nothing will happen.


Apply units to data that's just been read in.


Initialize an empty field array to be filled in later.


        Figure out dtype for field.

        Priority is:
        1. override_dict
        2. self.arbor.field_info
        3. self.arbor.field_info._data_types
        4. self.default_dtype


Figure out which objects are responsible for storing field data.


Read fields from disk.


Only keep items on the fields list.


Read fields from disk for a single tree.


Load any relevant data from the file header.


        Distinguish field sources.

        Distinguish fields to be read from disk, from the file header,
        and from arbor properties.


Initialize empty field arrays.


Get fields from arbor/tree_node properties.


Get fields from file header.


Read field data for all halos in the file.


Read field data for a given set of halos.


Read all requested fields from disk, header, or arbor properties.


Add an analysis field.


Add an alias field.


Add a derived field.


        Add vector and magnitude fields for a field with
        x/y/z components.


Divide fields into those to be read and those to generate.


Set data paths.


Set the name of the file from which to get metadata.


        Read relevant parameters from parameter file or file header
        and detect fields.


        Set "cm" units for explicitly comoving.
        Note, we are using comoving units all the time since
        we are dealing with data at multiple redshifts.


        Cosmology calculator with self-consistent parameters and units.

        See :ref:`yt:cosmology-calculator` for more information.


Create field io objects.


        Get all files that hold field data and make them known
        to the i/o system.


Setup field containers and definitions.


Set the default tree node selector as maximum mass.


Determine if trees have been planted.


Create arrays to construct root nodes.


The dict of arrays for storing node information.


Initialize the node_info arrays.


        Return True if arrays of uids and descendent uids have
        been read in. Setup has also completed if tree is already
        grown.


        Create arrays of uids and desc_uids and attach them to the
        root node.


        Return True if a tree has been fully assembled, i.e.,
        the hierarchy of ancestor tree nodes has been built.


        Construct the hierarchy of ancestors and descendents
        for all nodes in the tree.


Call the correct function for building a given attribute.


        Reset all data structures for a single node.

        The goal is to clear as many data structures as
        possible without rendering the node object useless,
        if they are intended to be kept around.

        Calling reset_node on a non-root node should not make
        the non-root node useless.

        Calling reset_node on a root node will render any
        generated non-root nodes useless.


        Call the provided function over a list of nodes.

        If possible, group nodes by common data files to speed
        things up.

        Parameters
        ----------
        func : function
            Function to be called on an array of nodes.
        pbar : optional, string or yt.funcs.TqdmProgressBar
            A progress bar to be updated with each iteration.
            If a string, a progress bar will be created and the
            finish function will be called. If a progress bar is
            provided, the finish function will not be called.
            Default: None (no progress bar).
        root_nodes : optional, array of root TreeNodes
            Array of nodes over which the function will be called.
            If None, the list will be self[:] (i.e., all
            root_nodes).
            Default: None.

        Returns
        -------
        rvals : list
            return values from calling func on each node.
            These will have the same order as the original node list.


        This is called at the beginning of _node_io_loop.

        In different frontends, this can be used to group nodes by
        common data files. If nodes is None, we want all root
        nodes in the Arbor.

        Below is the default behavior, which does the bare minimum
        of returning:
        list of [None] : meaning all nodes come in a single group
            associated with no particular data file.
        list containing array of all provided nodes: meaning there
            is no specific grouping to be done
        None : meaning the nodes do not have to be reordered after
            being processed.

        See the implementation in individual frontends for
        more informative examples.

        Returns
        -------
        data_files : list
            list of data files that will be used
        index_list : list of arrays
            indices of the provided array of nodes associated
            with each of the data files
        return_order : int array
            array of indices used to reorder the return values
            to the order of the provided nodes


        If given a string, return an array of field values for the
        roots of all trees.
        If given an integer, return a tree from the list of trees.


Create root nodes given an index or slice from uid array.


Root node generator.


Create a root node given its index in the array of uids.


Create a non-root node in a tree.


Store a TreeNode attribute an array for retrieval later.


A dictionary containing information for each available field.


Return total number of trees.


Unit system registry.


Value of the Hubble parameter.


The simulation box size.


        Create a unyt_array using the Arbor's unit system.

        Parameters
        ----------

        input_array : Iterable
            A tuple, list, or array to attach units to
        units: String unit specification, unit symbol or astropy object
            The units of the array. Powers must be specified using python syntax
            (cm**3, not cm^3).
        dtype : string or NumPy dtype object
            The dtype of the returned array data

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("consistent_trees/tree_0_0_0.dat")
        >>> a.arr([1,2,3], "kg")
        unyt_array([1, 2, 3], 'kg')


        Create a unyt_quantity using the Arbor's unit system.

        Parameters
        ----------

        input_array : Iterable
            A tuple, list, or array to attach units to
        units: String unit specification, unit symbol or astropy object
            The units of the array. Powers must be specified using python syntax
            (cm**3, not cm^3).
        dtype : string or NumPy dtype object
            The dtype of the returned array data

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("consistent_trees/tree_0_0_0.dat")
        >>> a.quan(34, "cm")
        unyt_quantity(34, 'cm')


        Helper function for creating
        :class:`~ytree.data_structures.node_container.NodeContainer` objects.

        See :class:`~ytree.data_structures.node_container.NodeContainer` for more
        information.


        Select halos from the arbor based on a set of criteria given as a string.

        Halos matching the criteria will be returned through a generator. Matches
        are returned as soon as they are found, allowing you to begin working
        with them before the search has completed. The progress bar will update
        to report the number of matches found as the search progresses.

        Parameters
        ----------

        criteria : string
            A string that will eval to a Numpy-like selection operation
            performed on a TreeNode object called "tree".
            Example: 'tree["tree", "redshift"] > 1'
        trees : optional, list or array of TreeNodes
            A list or array of TreeNode objects in which to search. If none given,
            the search is performed over the full arbor.
        select_from : deprecated, do not use
            This keyword is no longer required and using it does nothing.
        fields : deprecated, do not use
            This keyword is no longer required and using it does nothing.

        Returns
        -------

        halos : :class:`~ytree.data_structures.tree_node.TreeNode` generator
            A generator yielding all TreeNodes meeting the criteria.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("tree_0_0_0.dat")
        >>> for halo in a.select_halos('tree["tree", "redshift"] > 1'):
        ...     print (halo["mass"])
        >>>
        >>> halos = list(a.select_halos('tree["prog", "mass"].to("Msun") >= 1e10'))
        >>> print (len(halos))


r"""
        Add an empty field to be filled by analysis operations.

        Parameters
        ----------
        name : string
            Field name.
        units : string
            Field units.
        dtype : optional, type
            Data type for field values. If None, the default data type
            of the arbor is used.
            Default: None.
        default: optional, numeric
            Default field value when field is initialized.
            Default: 0.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("tree_0_0_0.dat")
        >>> a.add_analysis_field("robots", "Msun * kpc")
        >>> # Set field for some halo.
        >>> my_tree = a[0]
        >>> my_tree["tree"][7]["robots"] = 1979.816


r"""
        Add a field as an alias to another field.

        Parameters
        ----------
        alias : string
            Alias name.
        field : string
            The field to be aliased.
        units : optional, string
            Units in which the field will be returned.
        force_add : optional, bool
            If True, add field even if it already exists and warn the
            user and raise an exception if dependencies do not exist.
            If False, silently do nothing in both instances.
            Default: True.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("tree_0_0_0.dat")
        >>> # "Mvir" exists on disk
        >>> a.add_alias_field("mass", "Mvir", units="Msun")
        >>> print (a["mass"])


r"""
        Add a field that is a function of other fields.

        Parameters
        ----------
        name : string
            Field name.
        function : callable
            The function to be called to generate the field.
            This function should take two arguments, the
            arbor and the data structure containing the
            dependent fields.  See below for an example.
        units : optional, string
            The units in which the field will be returned.
        dtype : optional, type
            The data type of the field array. If none, use the
            default type set by Arbor._default_dtype.
        description : optional, string
            A short description of the field.
        vector_field: optional, bool
            If True, field is an xyz vector.
            Default: False.
        force_add : optional, bool
            If True, add field even if it already exists and warn the
            user and raise an exception if dependencies do not exist.
            If False, silently do nothing in both instances.
            Default: True.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("tree_0_0_0.dat")
        >>> def _redshift(field, data):
        ...     return 1. / data["scale"] - 1
        ...
        >>> a.add_derived_field("redshift", _redshift)
        >>> print (a["redshift"])


        Add vector fields for a set of x,y,z component fields.

        This will add a general vector field that returns the combined
        x, y, z components as a single Nx3 array. A <field>_magnitude
        field with the quadrature sum of the components is also added.

        Parameters
        ----------
        name : string
            The name of the field. Component x,y,z fields must exist.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("tree_0_0_0.dat")
        >>> for ax in 'xyz':
        >>>     a.add_analysis_field(f"thing_{ax}")
        >>> fn = a.save_arbor()
        >>> a_new = ytree.load(fn)
        >>> a_new.add_vector_field("thing")
        >>> print (a_new["thing"])
        >>> print (a_new["thing_magnitude"])


        Check if input file works with a specific Arbor class.
        This is used with :func:`~ytree.data_structures.arbor.load` function.


r"""
        Save the arbor to a file.

        The saved arbor can be re-loaded as an arbor.

        Parameters
        ----------
        filename : optional, string
            Output file keyword.  If filename ends in ".h5",
            the main header file will be just that.  If not,
            filename will be <filename>/<basename>.h5.
            Default: "arbor".
        fields : optional, list of strings
            The fields to be saved.  If not given, all
            fields will be saved.
        trees : optional, list or array of TreeNodes
            If given, only save trees stemming from these nodes.
            If not provide, all trees will be saved.
        save_in_place : optional, bool or None
            If True, analysis fields will be saved to the original
            arbor, even if only a subset of all trees is provided
            with the trees keyword. This will essentially "update"
            the arbor in place. If False and only a subset of
            all trees is provided, a new arbor will be created
            containing only the trees provided. If set to None,
            behavior is determined by the type of arbor loaded.
            If the arbor is a YTreeArbor (i.e., saved with
            save_arbor), save_in_place will be set to True. If
            not of this type, it will be set to False.
            Default: None
        save_roots_only : optional, bool
            If True, only field values of each node are saved.
            If False, field data for the entire tree stemming
            from that node are saved.
            Default:  False.
        max_file_size : optional, float
            The maximum number of nodes saved to a single file.
            Smaller numbers will result in more files. Performance
            may change somewhat with different values.
            Default: 524288 (2^19).

        Returns
        -------
        header_filename : string
            The filename of the saved arbor.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("rockstar_halos/trees/tree_0_0_0.dat")
        >>> fn = a.save_arbor()
        >>> # reload it
        >>> a2 = ytree.load(fn)


        Return a node self._trees.

        These cannot be generated easily, so we keep them.


        Construct all trees.

        Since nodes are spread out over multiple files, we will
        plant all trees and create all ancestor/descendent links.

        The links will be held by the nodes themselves and we will
        not store the nodes in an array until _setup_tree is called.


        Walk the tree and place all nodes into an array.

        This is required for field access.


Trees are grown when they are planted.


    Load an Arbor, determine the type automatically.

    Parameters
    ----------
    filename : string
        Input filename.
    method : optional, string
        The type of Arbor to be loaded.  Existing types are:
        ConsistentTrees, Rockstar, TreeFarm, YTree.  If not
        given, the type will be determined based on characteristics
        of the input file.
    kwargs : optional, dict
        Additional keyword arguments are passed to _is_valid and
        the determined type.

    Returns
    -------
    Arbor

    Examples
    --------

    >>> import ytree
    >>> # saved Arbor (ytree format)
    >>> a = ytree.load("arbor/arbor.h5")
    >>> # Amiga Halo Finder
    >>> a = ytree.load("ahf_halos/snap_N64L16_000.parameter",
    ...                hubble_constant=0.7)
    >>> # consistent-trees
    >>> a = ytree.load("tiny_ctrees/locations.dat")
    >>> a = ytree.load("consistent_trees/tree_0_0_0.dat")
    >>> a = ytree.load("ctrees_hlists/hlists/hlist_0.12521.list")
    >>> # consistent-trees-hdf5
    >>> a = ytree.load("consistent_trees_hdf5/soa/forest.h5")
    >>> # LHaloTree
    >>> a = ytree.load("my_halos/trees_063.0")
    >>> # LHaloTree-hdf5
    >>> a = ytree.load("TNG50-4-Dark/trees_sf1_099.0.hdf5",
    ...                box_size=35, hubble_constant=0.6774,
    ...                omega_matter=0.3089, omega_lambda=0.6911)
    >>> # Moria
    >>> a = ytree.load("moria/moria_tree_testsim050.hdf5")
    >>> # Rockstar
    >>> a = ytree.load("rockstar_halos/out_0.list")
    >>> # treefarm
    >>> a = ytree.load("my_halos/fof_subhalo_tab_025.0.h5")
    >>> # TreeFrog
    >>> a = ytree.load("treefrog/VELOCIraptor.tree.t4.0-131.walkabletree.sage.forestID.foreststats.hdf5")


    Save the arbor to a file.

    This is the internal function called by Arbor.save_arbor.


    Determine if we can just output new analysis fields to
    sidecar files and skip saving the rest.

    If updating return filenames associated with currently loaded arbor.


Figure out the output filename.


Get the list of fields to be saved.


    Write all data files by grouping trees together.

    Return arrays of number of nodes and trees written to each file
    as well as a dictionary of root fields.

    If update is True, use the file layout of the arbor instead of
    calculating from max_file_size.


Write data file for a single group of trees.


Write the header file.


    Copy analysis field data from one set of trees to another.

    The new tree list is likely to be the list of all trees in the arbor.
    The purpose of this is to allow saving in place of a subset of trees
    (including non-rootes) back into the original arbor.


Return the index of this node in a list of all nodes in the tree.


Set the tree_id manually in CatalogArbors.


Find the root node.


Walk descendents until root.


        If a root node, delete field data.
        If not root node, do nothing.


Return the descendent node.


Return a generator of ancestor nodes.


Array of uids for all nodes in the tree.


Array of descendent uids for all nodes in the tree.


Number of nodes in the tree.


        Array of NodeLink objects with the ancestor/descendent structure.

        This is only used by conventional Arbor objects, i.e., not
        CatalogArbor objects.


        Return field values for this TreeNode, progenitor list, or tree.

        Parameters
        ----------
        key : string or tuple
            If a single string, it can be either a field to be queried or
            one of "tree" or "prog".  If a field, then return the value of
            the field for this TreeNode.  If "tree" or "prog", then return
            the list of TreeNodes in the tree or progenitor list.

            If a tuple, this can be either (string, string) or (string, int),
            where the first argument must be either "tree" or "prog".
            If second argument is a string, then return the field values
            for either the tree or the progenitor list.  If second argument
            is an int, then return the nth TreeNode in the tree or progenitor
            list list.

        Examples
        --------
        >>> # virial mass for this halo
        >>> print (my_tree["mvir"].to("Msun/h"))

        >>> # all TreeNodes in the progenitor list
        >>> print (my_tree["prog"])
        >>> # all TreeNodes in the entire tree
        >>> print (my_tree["tree"])

        >>> # virial masses for the progenitor list
        >>> print (my_tree["prog", "mvir"].to("Msun/h"))

        >>> # the 3rd TreeNode in the progenitor list
        >>> print (my_tree["prog", 2])

        Returns
        -------
        float, ndarray/unyt_array, TreeNode


Return default slice to select the whole forest.


        An iterator over all TreeNodes in the forest.

        This is different from _tree_nodes in that we don't walk
        through the ancestors lists. We just yield every TreeNode
        there is.


        An iterator over all TreeNodes in the tree beneath,
        starting with this TreeNode.

        For internal use only. Use the following instead:

        >>> for my_node in my_tree['tree']:
        ...     print (my_node)

        Examples
        --------

        >>> for my_node in my_tree._tree_nodes:
        ...     print (my_node)


        Return the field array indices for all TreeNodes in
        the tree beneath, starting with this TreeNode.


        An iterator over all TreeNodes in the progenitor list,
        starting with this TreeNode.

        For internal use only. Use the following instead:

        >>> for my_node in my_tree['prog']:
        ...     print (my_node)

        Examples
        --------

        >>> for my_node in my_tree._prog_nodes:
        ...     print (my_node)


        Return the field array indices for all TreeNodes in
        the progenitor list, starting with this TreeNode.


r"""
        Save the tree to a file.

        The saved tree can be re-loaded as an arbor.

        Parameters
        ----------
        filename : optional, string
            Output file keyword.  Main header file will be named
            <filename>/<filename>.h5.
            Default: "tree_<uid>".
        fields : optional, list of strings
            The fields to be saved.  If not given, all
            fields will be saved.

        Returns
        -------
        filename : string
            The filename of the saved arbor.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("rockstar_halos/trees/tree_0_0_0.dat")
        >>> # save the first tree
        >>> fn = a[0].save_tree()
        >>> # reload it
        >>> a2 = ytree.load(fn)


r"""
    Add a TreeNodeSelector to the registry of known selectors, so they
    can be chosen with :func:`~ytree.data_structures.arbor.Arbor.set_selector`.

    Parameters
    ----------
    name : string
        Name of the selector.
    function : callable
        The associated function.

    Examples
    --------

    >>> import ytree
    >>> def max_value(ancestors, field):
    ...     vals = np.array([a[field] for a in ancestors])
    ...     return ancestors[np.argmax(vals)]
    >>> ytree.add_tree_node_selector("max_field_value", max_value)
    >>> a = ytree.load("tree_0_0_0.dat")
    >>> a.set_selector("max_field_value", "mass")
    >>> print (a[0]["prog"])


r"""
    Return the TreeNode with the maximum value of the given field.

    Parameters
    ----------
    ancestors : list of TreeNode objects
        List of TreeNode objects from which to select.
    field : string
        Field to be used for selection.

    Returns
    -------
    TreeNode object


r"""
    Return the TreeNode with the minimum value of the given field.

    Parameters
    ----------
    ancestors : list of TreeNode objects
        List of TreeNode objects from which to select.
    field : string
        Field to be used for selection.

    Returns
    -------
    TreeNode object


        Add an operation to the AnalysisPipeline.

        An operation is a function that minimally takes in a target object
        and performs some actions on or with it. This function may alter the
        object's state, attach attributes, write out data, etc. Operations
        are used to create a pipeline of actions performed in sequence on a list
        of objects, such as all halos in a merger tree. The function can,
        optionally, return True or False to act as a filter, determining if the
        rest of the pipeline should be carried out (if True) or if the pipeline
        should stop and move on to the next object (if False).

        Parameters
        ----------
        function : callable
            The function to be called for each node/halo.
        *args : positional arguments
            Any additional positional arguments to be provided to the funciton.
        always_do: optional, bool
            If True, always perform this operation even if a prior filter has
            returned False. This can be used to add house cleaning operations
            that should always be run.
            Default: False
        **kwargs : keyword arguments
            Any keyword arguments to be provided to the function.


        Add a recipe to the AnalysisPipeline.

        An recipe is a function that accepts an AnalysisPipeline and adds a
        series of operations with calls to add_operation. This is a way of
        creating a shortcut for a series of operations.

        Parameters
        ----------
        function : callable
            A function accepting an AnalysisPipeline object.
        *args : positional arguments
            Any additional positional arguments to be provided to the funciton.
        **kwargs : keyword arguments
            Any keyword arguments to be provided to the function.

        Examples
        --------
        >>> def print_field_value(node, field):
        ...     print (f"Node {node} has {field} of {node[field]}.")
        >>>
        >>> def print_many_things(pipeline, fields):
        ...    for field in fields:
        ...        pipeline.add_operation(print_field_value, field)
        >>>
        >>> ap = ytree.AnalysisPipeline()
        >>> ap.add_recipe(print_many_things, ["mass", "virial_radius"])


Create output directories and do any other preliminary steps.


        Process a node through the AnalysisPipeline.

        All operations added to the AnalysisPipeline will be run on the
        provided target.

        Parameters
        ----------
        target : :class:`~ytree.data_structures.tree_node.TreeNode`
            The node on which to run the analysis pipeline.


        Save the merger tree plot.

        Parameters
        ----------
        filename: optional, str
            The output filename. If none given, the uid of the head
            node is used.
            Default: None.

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("tree_0_0_0.dat")
        >>> p = ytree.TreePlot(a[0])
        >>> p.save('tree.png')


The minimum halo mass to be included in the plot.


The minimum halo mass to main halo mass.


The field to determine the size of each circle.


Whether to scale circle sizes based on log of size field.


    Regenerate the TreeNode using the provided arbor.

    This is to be used when the original arbor associated with the
    TreeNode no longer exists.

    If new_index is None, assume the arbor has the same structure
    as it did before. If new_index is not None, assume the node
    is now a root.


    Iterate over a list of trees in parallel.

    Trees are divided up between the available processor groups. Analysis
    field values can then be assigned to halos within the tree. The trees
    will be saved either at the end of the loop or after a number of trees
    given by the ``save_every`` keyword are completed.

    This uses the yt
    :func:`~yt.utilities.parallel_tools.parallel_analysis_interface.parallel_objects`
    function, which is parallelized with MPI underneath and so is suitable
    for parallelism across compute nodes.

    Parameters
    ----------
    trees : list of :class:`~ytree.data_structures.tree_node.TreeNode` objects
        The trees to be iterated over in parallel.
    save_every : optional, int or False
        Number of trees to be completed before results are saved. This is
        used to save intermediate results in case scripts need to be restarted.
        If None, save will only occur after iterating over all trees. If False,
        no saving will be done.
        Default: None
    save_in_place : optional, bool or None
        If True, analysis fields will be saved to the original
        arbor, even if only a subset of all trees is provided
        with the trees keyword. If False and only a subset of
        all trees is provided, a new arbor will be created
        containing only the trees provided. If set to None,
        behavior is determined by the type of arbor loaded.
        If the arbor is a YTreeArbor (i.e., saved with
        save_arbor), save_in_place will be set to True. If
        not of this type, it will be set to False.
        Default: None
    save_roots_only : optional, bool
        If True, only field values of each node are saved.
        If False, field data for the entire tree stemming
        from that node are saved.
        Default:  False.
    filename : optional, string
        The name of the new arbor to be saved. If None, the naming convention
        will follow the filename keyword of the
        :func:`~ytree.data_structures.arbor.Arbor.save_arbor` function.
        Default: None
    njobs : optional, int
        The number of process groups for parallel iteration. Set to 0 to make
        the same number of process groups as available processors. Hence,
        each tree will be allocated to a single processor. Set to a number
        less than the total number of processors to create groups with multiple
        processors, which will allow for further parallelization within a tree.
        For example, running with 8 processors and setting njobs to 4 will result
        in 4 groups of 2 processors each.
        Default: 0
    dynamic : optional, bool
        Set to False to divide iterations evenly among process groups. Set to
        True to allocate iterations with a task queue. If True, the number of
        processors available will be one fewer than the total as one will act
        as the task queue server.
        Default: False

    Examples
    --------

    >>> import ytree
    >>> a = ytree.load("arbor/arbor.h5")
    >>> a.add_analysis_field("test_field", default=-1, units="Msun")
    >>> trees = list(a[:])
    >>> for tree in ytree.parallel_trees(trees):
    ...     for node in tree["forest"]:
    ...         node["test_field"] = 2 * node["mass"] # some analysis

    See Also
    --------
    parallel_tree_nodes, parallel_nodes


    Iterate over nodes in a single tree in parallel.

    Nodes are divided up between the available processor groups. Analysis
    field values can then be assigned to each node (halo).

    Note, unlike the parallel_trees and parallel_nodes function, no saving
    is performed internally. Results saving with the
    :func:`~ytree.data_structures.arbor.Arbor.save_arbor` must be done
    manually.

    This uses the yt
    :func:`~yt.utilities.parallel_tools.parallel_analysis_interface.parallel_objects`
    function, which is parallelized with MPI underneath and so is suitable
    for parallelism across compute nodes.

    Parameters
    ----------
    tree : :class:`~ytree.data_structures.tree_node.TreeNode`
        The tree whose nodes will be iterated over.
    group : optional, str ("forest", "tree", or "prog")
        Determines the nodes to be iterated over in the tree: "forest" for
        all nodes in the forest, "tree" for all nodes in the tree, or "prog"
        for all nodes in the line of main progenitors.
        Default: "forest"
    njobs : optional, int
        The number of process groups for parallel iteration. Set to 0 to make
        the same number of process groups as available processors. Hence,
        each node will be allocated to a single processor. Set to a number
        less than the total number of processors to create groups with multiple
        processors, which will allow for further parallelization. For example,
        running with 8 processors and setting njobs to 4 will result in 4
        groups of 2 processors each.
        Default: 0
    dynamic : optional, bool
        Set to False to divide iterations evenly among process groups. Set to
        True to allocate iterations with a task queue. If True, the number of
        processors available will be one fewer than the total as one will act
        as the task queue server.
        Default: False

    Examples
    --------

    >>> import ytree
    >>> a = ytree.load("arbor/arbor.h5")
    >>> a.add_analysis_field("test_field", default=-1, units="Msun")
    >>> trees = list(a[:])
    >>> for tree in trees:
    ...     for node in ytree.parallel_tree_nodes(tree):
    ...         node["test_field"] = 2 * node["mass"] # some analysis

    See Also
    --------
    parallel_trees, parallel_nodes


    Iterate over all nodes in a list of trees in parallel.

    Both trees and/or nodes within a tree are divided up between available
    process groups using multi-level parallelism. Analysis field values can
    then be assigned to all nodes (halos). Trees will be saved either at the
    end of the loop over all trees or after a number of trees given by the
    ``save_every`` keyword are completed.

    This uses the yt
    :func:`~yt.utilities.parallel_tools.parallel_analysis_interface.parallel_objects`
    function, which is parallelized with MPI underneath and so is suitable
    for parallelism across compute nodes.

    Parameters
    ----------
    trees : list of :class:`~ytree.data_structures.tree_node.TreeNode` objects
        The trees to be iterated over in parallel.
    group : optional, str ("forest", "tree", or "prog")
        Determines the nodes to be iterated over in the tree: "forest" for
        all nodes in the forest, "tree" for all nodes in the tree, or "prog"
        for all nodes in the line of main progenitors.
        Default: "forest"
    save_every : optional, int or False
        Number of trees to be completed before results are saved. This is
        used to save intermediate results in case scripts need to be restarted.
        If None, save will only occur after iterating over all trees. If False,
        no saving will be done.
        Default: None
    save_in_place : optional, bool or None
        If True, analysis fields will be saved to the original
        arbor, even if only a subset of all trees is provided
        with the trees keyword. This will essentially "update"
        the arbor in place. If False and only a subset of
        all trees is provided, a new arbor will be created
        containing only the trees provided. If set to None,
        behavior is determined by the type of arbor loaded.
        If the arbor is a YTreeArbor (i.e., saved with
        save_arbor), save_in_place will be set to True. If
        not of this type, it will be set to False.
        Default: None
    filename : optional, string
        The name of the new arbor to be saved. If None, the naming convention
        will follow the filename keyword of the
        :func:`~ytree.data_structures.arbor.Arbor.save_arbor` function.
        Default: None
    njobs : optional, tuple of ints
        The number of process groups for parallel iteration over trees and
        nodes within each tree. The first value sets behavior for iteration
        over trees and the second for iteration over nodes in a tree. For
        example, set to (1, 0) to parallelize only over nodes in a tree and
        (0, 1) to parallelize only over trees. For multi-level parallelism
        set the first value to a number less than the total number of
        processors and the second to 0. For example, if running with 8
        processors, set njobs to (2, 0) to iterate over each tree with a
        group of 4 processors. Within each tree, each of the 4 processors
        in the group will work on a single node. If set to None, njobs will
        be set to (0, 1) if there are most trees than processors (tree
        parallel) and (1, 0) otherwise (node parallel).
        Default: None
    dynamic : optional, tuples of bools
        Toggles task queue on/off for parallelism over trees (first value)
        and nodes within a tree (second). Set to a value False to divide
        iterations evenly among process groups. Set to True to allocate
        iterations with a task queue. If True, the number of
        processors available will be one fewer than the total as one will
        act as the task queue server. Yes, this can be set to (True, True).
        Try it.
        Default: (False, False)

    Examples
    --------

    >>> import ytree
    >>> a = ytree.load("arbor/arbor.h5")
    >>> a.add_analysis_field("test_field", default=-1, units="Msun")
    >>> trees = list(a[:])
    >>> for node in ytree.parallel_nodes(trees):
    ...     node["test_field"] = 2 * node["mass"] # some analysis

    See Also
    --------
    parallel_trees, parallel_tree_nodes


Check file exists in place or in test data dir.


r"""Parallel safe directory maker.


A Python3-safe function for getting hdf5 attributes.

    If an attribute is supposed to be a string, this will return it as such.

    This was taken from yt.


    Read an hdf5 attribute.  If there exists another attribute
    named <attr>_units, use that to assign units and return
    as either a unyt_array or unyt_quantity.


    Read an hdf5 dataset.  If that dataset has a "units" attribute,
    return that as well, but do not cast as a unyt_array.


Read lines from a file faster than f.readlines().


Round 0.5 up to 1 and so on.


Compare all fields for all trees in two arbors.


Compare all fields between two trees.


Compare all datasets between two hdf5 files.


Unit tests for get_node.


Unit tests for get_leaf_nodes.


Unit tests for get_root_nodes.


Generate special fields from the arbor/treenode.


Should be an hdf5 file with a few key attributes.


Resolve the dictionary of desc_uids into trees.


        We don't actually attach the tree's _ancestors during planting,
        so do it here.


        Get this tree's ancestors from the main ancestor dictionary.

        This arbor stores every tree's ancestors in a dictionary.
        When we finally need it, grab it from the arbor and attach
        it to the tree.


        File should end in .csv and start with three lines of the
        following format.
        #<fieldname>,<fieldname>,<fieldname>
        #<type>,<type>,<type>
        #<units>,<units>,<units>

        For example:
        #uid,desc_uid,mass,redshift
        #int,int,float,float
        #None,None,"Msun",None


        Load as a yt dataset.

        Merger tree data is loaded as a yt dataset, providing full access
        to yt functionality. Fields are accessed with the naming convention,
        ("halos", <field name>).

        Examples
        --------

        >>> import ytree
        >>> a = ytree.load("arbor/arbor.h5")
        >>>
        >>> ds = a.ytds
        >>> sphere = ds.sphere(ds.domain_center, (5, "Mpc"))
        >>> print (sphere["halos", "mass"])
        >>>
        >>> for node in a.get_nodes_from_selection(sphere):
        ...     print (node["position"])


        File should end in .h5, be loadable as an hdf5 file,
        and have "arbor_type" attribute.


Check for desc_uids missing from uid list.


        Calculate snapshots and snapshot-offsets where each forest appears last.

        For N forests and M snapshots, the data files contain two MxN arrays of:
        - the size of forest i in each snapshot j
        - the offset of forest i in each snapshot j

        In this function, we calculate two things for each forest:
        - the last (i.e. latest in time) snapshot in which the forest exists
        - the file offset within that last snapshot

        Since ytree reads from the root backward, this tell us where to start
        reading for any given forest.


Find the proper parameter filename if given a data file instead.


    Parse consistent-trees header information.

    Parse ascii text from a file or list of strings to get:
    - cosmology parameters
    - box size
    - fields and units
    - optionally, number of trees and end of header file offset

    Return a dictionary of field information.


        File should end in .dat and have a line in the header
        with the string, "Consistent Trees".


Get all out_*.list files and sort them in reverse order.


File should end in .list.


        File should end in .h5, be loadable as an hdf5 file,
        and have a "data_type" attribute.


        Read fields from disk for a single tree.

        Here we accept a list of fields and return a dictionary of NumPy
        arrays for each field.

        dtypes will be an optional dictionary of type for each field

        f will optionally be the already-opened file handle.

        If root_only is true, we only want the field value for the root
        of the tree.

        Below is the example for ctrees.


r"""Add root fields in bulk to same time.


r"""Reads the default LHaloTree file header.

    Args:
        filename (str): Full path to file that header should be read from.

    Returns:
         tuple (int, np.ndarray): The size of the file header and the number
             of halos in each header.


r"""Writes the default LHaloTree file header.

    Args:
        filename (str): Full path to file that should be written to.
        nhalos_per_tree (np.ndarray): The number of halos in each tree that
            will be written to the file.

    Returns:
        int: The size of the header that was written.


r"""Read one or more halos from a memmapped file.

    Args:
        filename (str, np.memmap): Either the full path to the file that should
            be read via memmap or an existing memmapped file.
        start (int, optional): Index of halo in memmap where read should start.
            Defaults to 0.
        nhalo (int, optional): Number of halos that should be read. Defaults to
            None and all halos following start are read.
        header_size (int, optional): Size of the header preceeding trees in the
            file. If this is not provided and filename is a path, it will be set
            to 0.
        item_dtype (np.dtype, optional): Data type of each halo entry. Defaults
            to dtype_header_default.

    Returns:
        np.ndarray: Structure array of halo data.


r"""Save one or more halos to a memmapped file.

    Args:
        filename (str, np.memmap): Either the full path to the file that should
            be saved to via memmap or an existing memmapped file.
        data (np.ndarray): Structured array of halo data that should be saved.
        start (int, optional): Index in memmap where halos should be written.
            Defaults to 0.
        header_size (int, optional): Size of the header preceeding trees in the
            file. If this is not provided and filename is a path, it will be set
            to 0.


r"""Read one or more halos from the file using np.fromfile.

    Args:
        filename (str, file): Either the full path to the file that should be
           openned and read or an existing open file object.
        start (int, optional): Index of halo in file (relative to the end of the
            header) where read should start. Defaults to 0.
        nhalo (int, optional): Number of halos that should be read. Defaults to
            all halos.
        header_size (int, optional): Size of the header preceeding trees in the
            file. Defaults to 0.
        item_dtype (np.dtype, optional): Data type of each halo entry. Defaults
            to dtype_header_default.

    Returns:
        np.ndarray: Structure array of halo data.


r"""Save one or more halos to a file using np.tofile.

    Args:
        filename (str, file): Either the full path to the file that should be
           openned and saved to or an existing open file object.
        data (np.ndarray): Structured array of halo data that should be saved.
        start (int, optional): Index in file (in halso) where halos should be
            written. Defaults to 0.
        header_size (int, optional): Size of the header preceeding trees in the
            file. Defaults to 0.


r"""Read trees from a file.

    Args:
        filename (str, np.memmap): Either the full path to the file that should
            be read via memmap or an existing memmapped file.
        **kwargs: Additional keyword arguments are passed to _read_from_mmap.

    Returns:
        dict: Arrays of fields for each halo.


r"""Save trees to a file.

    Args:
        filename (str, np.memmap): Either the full path to the file that should
            be saved to via memmap or an existing memmapped file.
        data (dict): Arrays of fields for each halo.
        item_dtype (np.dtype, optional): Data type of each halo entry. Defaults
            to dtype_header_default.
        **kwargs: Additional keyword arguments are passed to _save_to_mmap.


r"""Verify that the provided file exists. If it is None, and a suffix
        is provided, the file will be searched for in the same directory as
        self.filename.

        Args:
            filename (str): Full path that should be verified or None if the
                file should be searched for.
            suffix (str, optional): Suffix that should be used to search for a
                file if filename is None or dosn't exist. Defaults to None and
                no search is performed.
            error_tag (str, optional): Tag to use for error message in case
                where file dosn't exist. Defaults to None and 'File' is used.
            silent (bool, optional): If True, messages about located files are
                not printed. Defaults to False.

        Returns:
            str: Verified full path to the file.

        Raises:
            IOError: If filename is not a valid path and suffix is None.
            IOError: If a filename matching suffix cannot be located.


r"""dict: Key/value pairs read from the parameter file.


r"""str: Units of velocity.


r"""str: Units of length.


r"""str: Units of mass.


r"""np.ndarray: Array of scale factors at each snapshot.


r"""Read a single tree from the file.

        Args:
            treenum (int): Index of the tree that should be returned. If -1,
                data for every tree in the file will be returned.
            halonum (int, optional): If provided, this is the index of a
                particular halo within the tree that should be returned. If not
                provided, the entire tree is returned.
            fd (file, optional): Open file identifier. If not provided, the file
                is opened for the read and then closed.
            skip_add_fields (bool, optional): If True, the calculated fields
                will not be added or checked for. Defaults to False.
            validate (bool, optional): If True, the resulting data will be
                validated. Defaults to False.

        Returns:
            dict: Dictionary of fields for each halo in the file/tree/halo.


r"""Read a single halo entry from a tree in the file.

        Args:
            treenum (int): Index of the tree that contains the requested halo.
            halonum (int): Index of the halo within its tree.
            **kwargs: Additional keyword arguments are passed to
                read_single_tree.

        Returns:
            np.ndarray, dict: Dictionary or single element structured array with
                fields for the corresponding halo.


r"""Read an entry for a single tree root. First check to see if the root
        was chached.

        Args:
            treenum (int): Index of the tree that data should be returned for.
                If -1, the data for every root in the file is returned.
            **kwargs: Additional keyword arguments are passed to
                read_single_tree in the event that the root data is not cached.

        Returns:
            np.ndarray, dict: Dictionary or single element structured array with
                fields for the corresponding root.


r"""Read a all lhalotrees from the file.

        Args:
            **kwargs: All keyword arguments are passed to read_single_tree.

        Returns:
            dict, np.ndarray: Dictionary or structured array with fields for
                each halo in the file.


r"""Add computed fields to the numpy array.

        Args:
            treenum (int): Index of tree in file.
            tree (dict): Dictionary of fields for each halo in the tree.
            halonum (int, optional): Index of halo in the tree if tree contains
                a single halo.
            validate (bool, optional): If True, the resulting data will be
                validated. Defaults to False.

        Returns:
            dict: Dictionary of fields for each halo with added fields.


r"""Check that the tree conforms to expectation.

        Args:
            treenum (int): Index of the tree being validated in the file.
            tree (dict): Dictionary of fields for each halo in the tree.
            halonum (int): Index of halo in tree if this is a single halo.
                Defaults to None and tree is treated as a complete tree.

        Raises:
            AssertionError: If the tree does not have the expected number of
                halos.
            AssertionError: If the tree does not have all of the expected fields
                from the default LHaloTree format.
            AssertionError: If any of the halos have fields pointing to halos
                outside the tree (indicies exceeding nhalos).
            AssertionError: If there are any halos in a FOF group that are not
                in the same snapshot as the central.
            AssertionError: If the progenitors/descendants of any halo are not
                backwards/forwards in time.


r"""Check that the tree/halo has all of the expected fields.

        Args:
            tree (dict): Dictionary of fields for each halo in the tree.

        Raises:
            AssertionError: If the tree does not have all of the expected fields.


        Parse the file header, get things like:
        - cosmological parameters
        - box size
        - list of fields


        This is where we figure out how many trees there are,
        create the array to hold them, and instantiate a root
        tree_node for each tree.


Return True if we are able to initialize a reader.


Set some filename conventions.


Checking if this has the proper crm prefix and suffix.


        Take an educated guess at the crm filename.

        Return None if our guess does not exist.


Check if file has the proper suffix.


Get all *.parameter files and sort them in reverse order.


File must end in .parameter.


        Get both a CRM file and a parameter file.

        Raise an exception if we can't get both.


We have a whole thing here...


Guess parameter filename from the crm filename.


        Read the CRMratio2 file and hand out a dictionary of
        uid: desc_uid for each data file.


        Filename must end in .parameter or match the CRM naming
        convention.


Parse an AHF log or parameter file.


        Figure out the various additional filenames we're going to need here.

        If prefixes for the ahf and mtree files have been set, then we need to
        look out for this and adjust.


        Get header sizes from the two data files ending
        in .AHF_halos and .AHF_mtree.


        Get header information from the .log and .parameter
        files. Use that to get the name of the data file.


        Compute the tree from the graph.

        AHF computes a graph, where a given halo can
        have both multiple progenitors and descendents.

        Use the weight function to determine a unique
        descendent for each halo.

        descendent = max (M_ij = N_ij^2 / (N_i * N_j)),

        where:
           N_ij: number of shared particles
           N_i : number of particles in halo i
           N_j : number of particles in halo j


        Read map of progenitors to descendents.
        This is the ".AHF_mtree" file.


Use data from the mtree file to get descendent ids.


        Return index locations of the root node in this file.

        We use this to find the location of the root node in
        the arbor on the ytree side.


        Return the file number as a field-like array.

        We use this to find the index of the root node in the arbor.


        Return the index of a halo in a tree.

        We use this to get the right node from a given root node.


    Import uvfits, create a concatenated obs.
    *Returns:*
      - tuple: (script, concat_obs_info)


    Runs clean. Uses a little logic on the arguments to perform
    output-path determination magic.

    Args:
        obs_info: ObsInfo object
        casa_output_dir, fits_output_dir: obvious
        threshold: Clean threshold, in Janskys.
        niter: Max number of iterations per Clean invocation, passed to
            CASA-Clean.
        mask: String representing the mask apertures, passed to CASA-Clean.
        modelimage: Path to initial model (if any), passed to CASA-Clean.

    Returns:
        script


(Otherwise known as 'Re-Clean')


Loads the pixel data as a numpy array


    Return a string containing a DS9-compatible region file describing all the
    sources in sourcelist.


    Return a string containing a DS9-compatible region file describing the simple
    circular mask aperture objects.


Returns the RMS of the data about the median.
    Args:
        data: a numpy array


Remove all values above a threshold from the array.
    Uses iterative clipping at sigma value until nothing more is getting clipped.
    Args:
        data: a numpy array


Returns the inner region of a image, according to f.

    Resulting area is 4/(f*f) of the original.
    Args:
        data: a numpy array


 returns the rms value of a iterative sigma clipped subsection of an image
    Args:
        data: A numpy array
        sigma: sigma value used for clipping
        f: determines size of subsection, result will be 1/fth of the image size


    Args
    ----
    curve: function f(r)
        mapping radius *in pixels* from centre -> pb. corr. value.
    shape: numpy.ndarray.shape
        Shape of the numpy array to generate (2D)
    pointing_centre: tuple (x,y)
        x,y co-ordinates of the pointing centre
        (NB uses zero-based indexing a'la numpy)


    Generates a primary-beam response map.

    Args:
        flux_map: Path to the (inaccurate) default CASA-generated flux map.
        pb_sensitivity_curve: Primary beam sensitivity as a function of radius
            in units of image pixels. (Should be 1.0 at the exact centre).
        cutoff_radius: Radius at which to mask the output image (avoids
            extremely high corrected values for noise fluctuations at large
            radii). Units: image pixels.
    Returns:
        pbmap (pyrap.images.image): Pyrap image object containing the 'flux'
            map (i.e. primary beam response values).


    Updates the primary beam response maps for cleaned images in an ObsInfo object.

    Args:
        obs (ObsInfo): Observation to generate maps for.
        pb_sensitivity_curve: Primary beam sensitivity as a function of radius
            in units of image pixels. (Should be 1.0 at the exact centre).
        cutoff_radius: Radius at which to mask the output image (avoids
            extremely high corrected values for noise fluctuations at large
            radii). Units: image pixels.


    # find CUDA SDK path and set CUDA_SDK_PATH
    try:
        cudaSDKPath = env['CUDA_SDK_PATH']
    except:
        paths=[home + '/NVIDIA_CUDA_SDK', # i am just guessing here
               home + '/Apps/NVIDIA_CUDA_SDK',
               home + '/Apps/CudaSDK',
               '/usr/local/NVIDIA_CUDA_SDK',
               '/usr/local/CUDASDK',
               '/usr/local/cuda_sdk',
               '/Developer/NVIDIA CUDA SDK',
               '/Developer/CUDA SDK',
               '/Developer/CUDA',
               '/Developer/GPU Computing/C',
               programfiles + 'NVIDIA Corporation/NVIDIA CUDA SDK',
               programfiles + 'NVIDIA/NVIDIA CUDA SDK',
               programfiles + 'NVIDIA CUDA SDK',
               programfiles + 'CudaSDK',
               homedrive + '/NVIDIA CUDA SDK',
               homedrive + '/CUDA SDK',
               homedrive + '/CUDA/SDK']
        pathFound = False
        for path in paths:
            if os.path.isdir(path):
                pathFound = True
                print('scons: CUDA SDK found in ' + path)
                cudaSDKPath = path
                break
        if not pathFound:
            sys.exit("Cannot find the CUDA SDK path. Please set env['CUDA_SDK_PATH'] to point to your SDK path")
    env['CUDA_SDK_PATH'] = cudaSDKPath

    # cuda libraries
    if env['PLATFORM'] == 'posix':
        cudaSDKSubLibDir = '/linux'
    elif env['PLATFORM'] == 'darwin':
        cudaSDKSubLibDir = '/darwin'
    else:
        cudaSDKSubLibDir = ''


Estimate offset field between burst and simamp.


Estimate polynomial here.


        Create the flag file for masking out areas of low correlation.

        @param flagFilename (\a string) The file name for the output flag file
        @param threshold (\a float) The correlation threshold for mask generation, default 0.1


Ensure that the window sizes are valid for the code to work.


Make sure that a DEM is available for processing the given data.


Estimate azimuth misregistration.


Estimate offsets for the overlap regions of the bursts.


Create geometry files corresponding to burst overlaps.


Run one ampcor process.


Estimate constant offset in range.


Filter the resulting offset field images.


Determine if GPU modules are available.


Estimate separation in frequency due to unit pixel misregistration.


Compute coherence using scipy convolve 2D.


Create additional layers for performing ESD.


Try with GPU module.


Estimate dense offset field between merged reference bursts and secondary bursts.


Resample burst by burst.


Create coregistered overlap secondarys.


Add one swath to the VRT.


Estimate offsets using geometry


Create overlap interferograms.


Convert a isceobj.Util.Poly2D {poly} into zerodop.GPUresampslc.GPUresampslc.PyPloy2d


Resample burst by burst with GPU


Create coregistered overlap secondary image.


    Merge SLCs using the same format/tools in runMergeBursts.py to get the
    full SLC to use in denseOffsets


    This function removes the range Hamming window imposed on the signal
    bandwidth:     range bandwidth
    samplingRate:  range sampling rate
    alpha:         alpha of the Hamming window


    This routine forms interferogram and possibly removes topographic and ionospheric phases.
    all the following indexes start from 1
    overlapBox[0]: first line
    overlapBox[1]: last line
    overlapBox[2]: first sample
    overlapBox[3]: last sample


generate subband images


    compute coherence uisng only interferogram (phase).
    This routine still follows the regular equation for computing coherence,
    but assumes the amplitudes of reference and secondary are one, so that coherence
    can be computed using phase only.

    inf: interferogram
    win: window size
    edge: 0: remove all non-full convolution samples

          1: remove samples computed from less than half convolution
             (win=5 used to illustration below)
             * * *
             * * *
             * * *
             * * *
             * * *

          2: remove samples computed from less than quater convolution
             (win=5 used to illustration below)
             * * *
             * * *
             * * *

          3: remove non-full convolution samples on image edges

          4: keep all samples


merge burst interferograms and compute coherence


    xmlDirname:  xml dir name
    wrapName:    input interferogram
    corrfile:    input coherence file
    unwrapName:  output unwrapped interferogram
    nrlks:       number of range looks of the interferogram
    nalks:       number of azimuth looks of the interferogram


    30-APR-2018
    This routine moves the original unwrapped files to a directory and takes looks


    calculate an empirical ramp between Sentinel-1A/B
    29-JUN-2018

    swathList:        self._insar.getValidSwathList(self.swaths)
    width:            single-look image width after merging
    numberRangeLooks: number of range looks in the processing of ionosphere estimation
    passDirection:    descending/ascending


    This routine merge, unwrap and compute ionosphere swath by swath, and then
    adjust phase difference between adjacent swaths caused by relative range timing
    error between adjacent swaths.

    This routine includes the following steps in the merged-swath processing:
    merge(self, ionParam)
    unwrap(self, ionParam)
    ionosphere(self, ionParam)


    compute offset corresponding to center Doppler frequency
    firstline, lastline, firstcolumn, lastcolumn: index of original 1-look burst, index starts from 1.

    output: first lines > 0, last lines < 0


    This program performs Gaussian filtering with adaptive window size.
    ionos: ionosphere
    wgt: weight
    size_max: maximum window size
    size_min: minimum window size


    This function filters image using gaussian filter

    we projected the ionosphere value onto the ionospheric layer, and the indexes are integers.
    this reduces the number of samples used in filtering
    a better method is to project the indexes onto the ionospheric layer. This way we have orginal
    number of samples used in filtering. but this requries more complicated operation in filtering
    currently not implemented.
    a less accurate method is to use ionsphere without any projection


calculate azimuth shift caused by ionosphere using ionospheric phase


    doing multiple looking

    ATTENTION:
    NO AVERAGING BY DIVIDING THE NUMBER OF TOTAL SAMPLES IS DONE.


esd after ionosphere correction


    inputData:   input numpy 2-d array
    lengtho:     length of output array
    widtho:      width of output array
    nrli:        number of range looks input
    nali:        number of azimuth looks input
    nrlo:        number of range looks output
    nalo:        number of azimuth looks output


    Cunren Liang, January 2018
    adjust the position of the first valid line, last valid line, first valid sample and last valid sample,
    so that in the subsequent multiple looking process only samples from the same burst fall in a multilooing
    window.

    INPUT:
    swaths: frames
    box[0](length): length of the merged image
    box[1](width): width of merged image
    box[2](sensingStart): sensingStart of merged image
    box[3](nearRange): nearRange of merged image
    box[4](dt): timeSpacing of merged image
    box[5](dr): rangeSpacing of merged image
    nalks: number of azimuth looks to be taken
    nrlks: number of range looks to be taken
    edge: edges around valid samples to be removed

    in multiple looking
    avalid: There are three possible values:
            'strict':          avalid = nalks, this strictly follows azimuth number of looks, to make sure each
                               resulting pixel contains exactly azimuth number of looks pixels.
            'adaptive':        this tries avalid values starting from nalks, to make sure there are no gaps
                               between bursts
            1<=avalid<=nalks:  specifying an avalid value (integer)

            for all of the three cases, if there are >=avalid pixels used to do multiple looking on the upper/lower
            edge, the resulting line is considered to be valid.
            for all of teh three cases, 1<=avalid<=nalks

    rvalid: the same thing in range.

    RESULT OF THIS FUNCTION: the following are changed:
        swaths[i].bursts[j].firstValidLine
        swaths[i].bursts[j].firstValidSample
        swaths[i].bursts[j].numValidLines
        swaths[i].bursts[j].numValidSamples

    WARNING: the overlap area (valid line and valid sample) between two adjacent bursts/subswaths should
    (supposing that avalid=nalks, rvalid=nrlks)
    number of overlap valid lines - 2*edge >= 2 * nalks
    number of overlap valid samples - 2*edge >= 2 * nrlks
    otherwise, there may be blank lines or columns between adjacent bursts/subswaths.
    normally the overlap area between ajacent bursts is larger than 100 lines, and the overlap area between
    adjacent subswaths is larger than 600 samples. Therefore, this should at least support 50(az) * 300(rg)
    looks, which is enough for most applications.

    a burst of a subswath usually overlaps with two bursts of the adjacent subswaths. The two bursts may have
    different starting ranges (difference is usually about 150 samples). Even if this is the case, there are
    still more than 400 samples left, which should at least support 200 (rg) looks.


    Merge burst products into single file.
    Simple numpy based stitching


    Merge burst products to make it look like stripmap.
    Currently will merge interferogram, lat, lon, z and los.


Create burst interferograms.


Run method for split spectrum.


Check if input data is raw / slc.


Check if SLC is zero doppler / native doppler.


Generate split spectrum SLCs.


    Replace the value of invalid 'data' cells (indicated by 'invalid')
    by the value of the nearest valid data cell

    Input:
        data:    numpy array of any dimension
        invalid: a binary array of same shape as 'data'.
                 data value are replaced where invalid is True
                 If None (default), use: invalid  = np.isnan(data)

    Output:
        Return a filled array.


Generalized geocoding of all the files listed above.


Kind can either be coarse, refined or fine.


    Crop the frame.

    Parameters to change:
    startingRange
    farRange
    sensingStart
    sensingStop
    sensingMid
    numberOfLines
    numberOfSamples
    dopplerVsPixel


Crop step based on region of interest.


Geocode a swath file using corresponding lat, lon files


        Takes a lat, lon, height triplet and returns azimuth time and range.
        Assumes zero doppler for now.


Computed the adjusted starting lines based on matching in overlapping regions


coregister bursts by spectral diversity


    numberLooksScanSAR: number of looks of the ScanSAR system
    numberRangeLooks:   number of range looks to take
    numberAzimuthLooks: number of azimuth looks to take
    keep:               whether keep intermediate files


Load the track using Product Manager.


Save the track to XML files using Product Manager.


geocode final products


estimate frame offsets.


estimate swath offsets.


unwrap filtered interferogram


create subband interferograms


define directory names for ionospheric correction


compute geometric offset


coregister bursts by cross correlation


Test method to demonstrate utility.


estimate SLC offsets


rectify range offset


unwrap subband interferograms


compute coherence using a window


    scale amplitude and interferogram, and balace the two channels of amplitude image
    according to equation (2) in
    Howard A. Zebker and Katherine Chen, Accurate Estimation of Correlation in InSAR Observations
    IEEE GEOSCIENCE AND REMOTE SENSING LETTERS, VOL. 2, NO. 2, APRIL 2005.
    the operation of the program does not affect coherence estimation


    compute swath offset
    frame:                frame object
    image:                image for doing matching
    outputfile:           output txt file for saving swath offset
    crossCorrelation:     whether do matching
    numberOfAzimuthLooks: number of looks to take in azimuth before matching


estimate offset of two adjacent swaths using matching


    compute frame offset
    track:                track object
    image:                image for doing matching
    outputfile:           output txt file for saving frame offset
    crossCorrelation:     whether do matching
    matchingMode:         how to match images. 0: ScanSAR full-aperture image, 1: regular image


    estimate offset of two adjacent frames using matching
    matchingMode:  0: ScanSAR full-aperture image
                   1: regular image


estimate offset fied


Estimate dense offset field between a pair of SLCs.


    orbit:  orbit of the image to be cropped
    swath:  swath of the image to be cropped
    slc:    image to be cropped
    orbit2: orbit of the other image
    swath2: swath of the other image


resample original ionosphere and ionospheric correction


compute doppler for a track


estimate between radar image and dem


simulate a radar image by computing gradient of a dem image.


filt offset fied


compute range and azimuth offsets


    currently we cannot set left/right looking.
    works for right looking, but left looking probably not supported.


geocode offset fied


match a pair of SLCs


download DEM and water body


    bbox:        [s, n, w, e]
    demType:     can be 'version3' or 'nasadem'. nasadem is also tested.
    resolution:  1 or 3, NASADEM only available in 1-arc sec resolution


    download water body
    water body. (0) --- land; (-1) --- water; (-2) --- no data.

    set no-value pixel inside of latitude [-56, 60] to -1
    set no-value pixel outside of latitidue [-56, 60] to -2

    look at this figure for SRTM coverage:
    https://www2.jpl.nasa.gov/srtm/images/SRTM_2-24-2016.gif


    mosaic swaths

    #PART 1. REGULAR INPUT PARAMTERS
    frame:                 frame
    inputFiles:            input file list
    outputfile:            output mosaic file
    rangeOffsets:          range offsets
    azimuthOffsets:        azimuth offsets
    numberOfRangeLooks:    number of range looks of the input files
    numberOfAzimuthLooks:  number of azimuth looks of the input files
    updateFrame:           whether update frame parameters

    #PART 2. PARAMETERS FOR COMPUTING PHASE DIFFERENCE BETWEEN SUBSWATHS
    phaseCompensation:     whether do phase compensation for each swath
    phaseDiff:             pre-computed compensation phase for each swath
    phaseDiffFixed:        if provided, the estimated value will snap to one of these values, which is nearest to the estimated one.
    snapThreshold:         this is used with phaseDiffFixed
    snapSwath:             indicate whether snap to fixed values for each swath phase diff, must be specified if phaseDiffFixed!=None
    pcRangeLooks:          number of range looks to take when compute swath phase difference
    pcAzimuthLooks:        number of azimuth looks to take when compute swath phase difference
    filt:                  whether do filtering when compute swath phase difference

    #PART 3. RESAMPLING METHOD
    resamplingMethod:      0: amp resampling. 1: int resampling.


    mosaic swaths (this is simplified version of swathMosaic to update parameters only)

    frame:                 frame
    rangeOffsets:          range offsets
    azimuthOffsets:        azimuth offsets
    numberOfRangeLooks:    number of range looks of the input files
    numberOfAzimuthLooks:  number of azimuth looks of the input files


    read a chunk of image
    the indexes (startSample, endSample, startLine, endLine) are included and start with zero

    memmap is not used, because it is much slower


    find the first/last non-zero line/sample
    all indexes start from zero


    find file in vrt in another directory
    xmlfile: vrt file
    relative_path: True: return relative (to current directory) path of the file
                   False: return absolute path of the file


    doing multiple looking
    ATTENSION: original array changed after running this function


doing multiple looking


    Compute coherence using scipy convolve 2D. Same as "def cal_coherence(inf, win=5):" in funcs.py in insarzd

    #still use standard coherence estimation equation, but with magnitude removed.
    #for example, equation (2) in
    #H. Zebker and K. Chen, Accurate Estimation of Correlation in InSAR Observations,
    #IEEE GEOSCIENCE AND REMOTE SENSING LETTERS, VOL. 2, NO. 2, APRIL 2005.


    compute range and azimuth offsets using orbit. all range/azimuth indexes start with 0
    referenceSample:  reference sample where offset is computed, no need to be integer
    referenceLine:    reference line where offset is computed, no need to be integer


reformat geometrical offset as ampcor output format


    cull offsets using fortran program from ROI_PAC
    numThreshold: minmum number of offsets left


fit a polynomial to the offset
       order=0 also works, output is mean offset


create water boday in radar coordinates


    track:       track object
    t:           time for computing earth radius and altitude, normally mid azimuth time
    wrapName:    input interferogram
    corName:     input coherence file
    unwrapName:  output unwrapped interferogram
    nrlks:       number of range looks of the interferogram
    nalks:       number of azimuth looks of the interferogram


unwrap interferogram using original snaphu program


a filter wrapper


take a burst sequence and output mosaicked file


take a burst sequence and output the magnitude


fixedValues can be a list or numpy array


    mosaic frames

    track:                 track
    inputFiles:            input file list
    output file:           output mosaic file
    rangeOffsets:          range offsets
    azimuthOffsets:        azimuth offsets
    numberOfRangeLooks:    number of range looks of the input files
    numberOfAzimuthLooks:  number of azimuth looks of the input files
    updateTrack:           whether update track parameters
    phaseCompensation:     whether do phase compensation for each frame
    phaseDiffFixed:        if provided, the estimated value will snap to one of these values, which is nearest to the estimated one.
    snapThreshold:         this is used with phaseDiffFixed
    resamplingMethod:      0: amp resampling. 1: int resampling. 2: slc resampling


    mosaic frames (this simplified version of frameMosaic to only update parameters)

    track:                 track
    rangeOffsets:          range offsets
    azimuthOffsets:        azimuth offsets
    numberOfRangeLooks:    number of range looks of the input files
    numberOfAzimuthLooks:  number of azimuth looks of the input files


    read a chunk of image
    the indexes (startSample, endSample, startLine, endLine) are included and start with zero

    memmap is not used, because it is much slower

    tested against readImage in runSwathMosaic.py


compute and filter ionospheric phase


        compute standard deviation of ionospheric phase
        fl:  lower band center frequency
        fu:  upper band center frequency
        cor: coherence, must be numpy array


    This routine computes ionosphere and remove the relative phase unwrapping errors

    lowerUnw:        lower band unwrapped interferogram
    upperUnw:        upper band unwrapped interferogram
    wgt:             weight
    fl:              lower band center frequency
    fu:              upper band center frequency
    adjFlag:         method for removing relative phase unwrapping errors
                       0: mean value
                       1: polynomial
    dispersive:      compute dispersive or non-dispersive
                       0: dispersive
                       1: non-dispersive


    #This can make use multiple threads (set environment variable: OMP_NUM_THREADS)
    linear equations:  H theta = s
    W:                 weight matrix


    fit a surface to a 2-d matrix

    data:   input 2-d data
    weight: corresponding 2-d weight
    order:  order. must >= 1

    zero samples in data and weight are OK.


    This program performs Gaussian filtering with adaptive window size.
    Cunren Liang, 11-JUN-2020

    data:     input raw data, numpy array
    std:      standard deviation of raw data, numpy array
    size_min: minimum filter window size
    size_max: maximum filter window size (size_min <= size_max, size_min == size_max is allowed)
    std_out0: standard deviation of output data
    fit:      whether do fitting before gaussian filtering


    reformat masked areas coordinates that are ready to use
    'maskedAreas' is a 2-D list. Each element in the 2-D list is a four-element list: [firstLine,
    lastLine, firstColumn, lastColumn], with line/column numbers starting with 1. If one of the
    four elements is specified with -1, the program will use firstLine/lastLine/firstColumn/
    lastColumn instead.

    output is a 2-D list containing the corresponding python-list/array-format indexes.


Checks to see if the value is a list greater than the defined length threshhold. If so,
        dump the array to a file and return a string value indictating the file name. Otherwise,
        return the normal value.


Calculate motion compenstation correction for Doppler centroid


    Set the peg point, mocomp heights, and mocomp velocities.
    From information provided in the sensor object
    Possible named input peg (in degrees) is used to set the peg
    rather than using the one given in the Frame.


calculate incidence and squint angles to radar data points


Populate some extra fields.


Return the doppler centroid as defined in the HDF5 file.


        self.parse()
        Extract doppler information as needed by mocomp


Populate the scene object with metadata


Extract the I and Q channels from the image file


            Parse both imagery and instrument files and create
            objects representing the platform, instrument and scene


Populate the platform object with metadata


Populate the instrument object with metadata


Exports GeoTiff to ISCE format.


Parse a date-time string with microsecond precision and return a datetime object


Extract orbit information from the orbit file


        Extract orbit information from xml annotation
        WARNING! Only use this method if orbit file is not available


        Set doppler values to zero since the metadata doppler values are unreliable.
        Also, the SLC images are zero doppler.


Read doppler values from the doppler file and fit a polynomial


Create the appropriate metadata objects from our CEOSFormat metadata


For now, call a wrapped version of ALOS_pre_process


            Use the xml definition of the field positions, names and lengths to
            parse a CEOS data file


Estimate a polynomial that represents the carrier on a given burst. To be used with resampling.


Responsible for parsing multiple slices meant to be stitched.


Read the AUX CAL file for elevation angle antenna pattern.


read image and get parameters


read meta data from leader


        compute azimuth FM rate, copied from Piyush's code.
        azimuthTime: middle of the scene should be a good time


reformat Doppler coefficients


reformat orbit from platformPositionRecord


compute start time of raw burst


            # create linear FM signal
            # ns: number of samples
            # it: time interval of the samples
            # offset: offset
            # k: linear FM rate
            #offset-centered, this applies to both odd and even cases


        Validate inputs provided by user.
        Populat tiff and xml list using SAFE folder names.


Populate the bounding box from metadata.


Extract Beta nought look up table from calibration file.


Extract Noise look up table from calibration file.


Extract pixel-by-pixel slant range file for GRD images.


Extract Slant Range to Ground Range polynomial


Extract Sigma nought look up table from calibration file.


    outputfile: (char) output file
    nrgout:     (int)  number of output samples
    nazout:     (int)  number of output lines
    delta:      (int)  edge to be removed of the overlap area (number of samples)
    diffflag:   (int)  whether output the overlap area as two-band BIL image. 0: yes, otherwise: no
    n:          (int)  number of input file
    inputfile:  (char list) [value_of_out_1, value_of_out_2, value_of_out_3...] input files to mosaic
    nrgin:      (int list)  [value_of_out_1, value_of_out_2, value_of_out_3...] input file widths
    nrgoff:     (int list)  [value_of_out_1, value_of_out_2, value_of_out_3...] input file range offsets
    nazoff:     (int list)  [value_of_out_1, value_of_out_2, value_of_out_3...] input file azimuth offsets
    phc:        (float list) [value_of_out_1, value_of_out_2, value_of_out_3...] input file compensation phase
    oflag:      (int list)  [value_of_out_1, value_of_out_2, value_of_out_3...] overlap area mosaicking flag

    for each frame
    range offset is relative to the first sample of last subswath
    azimuth offset is relative to the uppermost line


    inputfile:  input file
    outputfile: output file
    nrg:     file width
    nrlks:   number of looks in range (default: 4)
    nalks:   number of looks in azimuth (default: 4)
    ft:      file type (default: 0)
               0: signed char
               1: int
               2: float
               3: double
               4: complex (real and imagery: float)
               5: complex (real and imagery: double)
    sum:     sum method (default: 0)
               0: simple sum
               1: power sum (if complex, do this for each channel seperately)
    avg:     take average (default: 0)
               0: no
               1: yes


see extract_burst.c for usage


Basline files are given as grids


Baseline files are txt files with a single value in them


compute burst synchronization


command line parser.


Load the product using Product Manager.


Save the product to an XML file using Product Manager.


    Load the track using Product Manager.
    trackDir: where *.track.xml is located
    date: YYMMDD


    Save the track to XML files using Product Manager.
    track: track object
    #trackDir: where *.track.xml is located
    date: YYMMDD


    idir:          input directory where data of each date is located. only folders are recognized
    dateReference: reference date, str type format: 'YYMMDD'


return ALOS-2 acquisition mode


Determine if GPU modules are available.


compute subband parameters


remove common items of list1 and list2 from list1


idir:          input directory where data of each date is located. only folders are recognized


create scripts to process an InSAR stack


read baseline file generated by alosStack


Command line parser.


generate shapely Polygon


Select nearest neighbor acquisitions to form seqential pairs.


    safe_dict: returned by def get_dates(inps):
    num_connetions: number of subsequent dates to pair up with a date

    This routine first groups the Dates. Dates of same starting ranges is put in a group.
    Pairs within a same group are returned in pairs_same_starting_ranges
    Pairs connecting different groups are returned in pairs_diff_starting_ranges


    This routine searches for existing pairs for ionosphere estimation and exclude them from
    pairs_same_starting_ranges and pairs_diff_starting_ranges.


Create command line parser.


Create local zip file to populate.


Fetch annotation files.


Create VRTs for TIFF files.


Get safe directory path from zip name.


    compute burst phase ramps using azimuth ionospheric shift
    both regular and subband bursts are merged in a box defined by reference of stack


Estimate offsets for (the overlap regions of) the bursts.


update frame1 valid with frame2 valid


    check overlap among all acquistions, only keep the bursts that in the common overlap,
    and then renumber the bursts.


The main driver.


adjust valid samples by considering number of looks


Merging using VRTs.


Create subband burst SLCs.


Return timestamp from SAFE name.


Drop secondary acquisitions that have different number of bursts
    than the reference acquisition.


extract common valid overlap region for the stack.


print group parameters


    threshold: time difference threshold in seconds between two slices in second.
    this routine checks, for a slice, if there are multiple ones.


return snwe of an acquisition consisting a number of slices


return snwe of the overlap of all acquistions


    check each group to see if it fully covers [s, n], if not remove the acquistion
    s: south bound
    n: north bound


checking if there are different starting ranges in each acquistion.


    for the same subswath starting ranges,
    if the number of acquistions < threshold, remove these acquistions


Generate offset fields burst by burst.


Automated download of orbits.


Gather existing orbits.


    burst:      input burst object
    nout:       number of output files
    outputfile: [value_of_out_1, value_of_out_2, value_of_out_3...] output files
    bw:         [value_of_out_1, value_of_out_2, value_of_out_3...] filter bandwidth divided by sampling frequency [0, 1]
    bc:         [value_of_out_1, value_of_out_2, value_of_out_3...] filter center frequency divided by sampling frequency
    rgRef:      reference range for moving center frequency to zero
    virtual: True or False


get all dates from pairs


interpolate data1 of numberRangeLooks1/numberAzimuthLooks1 to data2 of numberRangeLooks2/numberAzimuthLooks2


    f0 = SPEED_OF_LIGHT/radarWavelength
    fH = f0 + dcH
    fL = f0 + dcL
    wavelengthL = SPEED_OF_LIGHT/fL
    wavelengthH = SPEED_OF_LIGHT/fH

    frameH = copy.deepcopy(frame)
    frameH.subBandRadarWavelength = wavelengthH
    frameH.image.filename = highBandSlc
    with shelve.open(os.path.join(outDirH, 'data')) as db:
        db['frame'] = frameH

    frameL = copy.deepcopy(frame)
    frameL.subBandRadarWavelength = wavelengthL
    frameL.image.filename = lowBandSlc
    with shelve.open(os.path.join(outDirL, 'data')) as db:
        db['frame'] = frameL


Unpack HDF5 to binary SLC file.


Grab bbox from DEM file in geo coordinates


Multilook geometry files.


Extract relevant information only.


Prepare shelve/pickle file for the binary SLC file.


    ifgDirname = os.path.join(self.insar.ifgDirname, self.insar.lowBandSlcDirname)
    lowBandIgram = os.path.join(ifgDirname , 'filt_' + self.insar.ifgFilename)

    if '.flat' in lowBandIgram:
        lowBandIgram = lowBandIgram.replace('.flat', '.unw')
    elif '.int' in lowBandIgram:
        lowBandIgram = lowBandIgram.replace('.int', '.unw')
    else:
        lowBandIgram += '.unw'

    ifgDirname = os.path.join(self.insar.ifgDirname, self.insar.highBandSlcDirname)
    highBandIgram = os.path.join(ifgDirname , 'filt_' + self.insar.ifgFilename)

    if '.flat' in highBandIgram:
        highBandIgram = highBandIgram.replace('.flat', '.unw')
    elif '.int' in highBandIgram:
        highBandIgram = highBandIgram.replace('.int', '.unw')
    else:
        highBandIgram += '.unw'


focusing reference and producing geometry files


Extract required information from pickle file.


 raeder based on GDAL.

    Args:

        * file      -> File name to be read

    Kwargs:

        * processor -> the processor used for the InSAR processing. default: ISCE
        * bands     -> a list of bands to be extracted. If not specified all bands will be extracted.
        * dataType  -> if not specified, it will be extracted from the data itself
    Returns:
        * data : A numpy array with dimensions : number_of_bands * length * width


masking and Filtering


         h5OutName : Name of the HDF5 file for the InSAR stack

         platform_tracks : A list containing the platform_tracks to be stored
                           in the HDF5 file. If None all platform_tracks are
                           exctracted from pairs. If pairs does not contain information
                           about the platform_tracks, then all pairs in the pairsDict are
                           considered from a single platform single track.

         ref_pixel       : A dictionary containing refernce pixels for each platform_track.
                           eg: ref_pixDict = {'Sentinel1A/Track144':(500,300) , 'Sentinel1A/Track100':(440,700)}
                               first pixel is in y direction (lines) and second pixel in x direction (columns)


Split the range spectrum


Do the actual processing.


Clean up all the C pointers.


Do the pre processing using wallis filter (10 min vs 15 min in Matlab).


Do the pre processing using (orig - low-pass filter) = high-pass filter filter (3.9/5.3 min).


Do the pre processing using db scale (4 min).


Do the pre processing using sobel filter (4.5/5.8 min).


Do the pre processing using Laplacian filter (2.5 min / 4 min).


quick processing routine which calls autorift main function (user can define their own way by mimicing the workflow here).