        Take one or more screenshots of the widget and save the images to a file.
        The images can be used to create a video.

        This function cannot be called multiple times within one cell.

        Note: this is a new feature and might not work on all systems.
        It was tested on python 2.7.10 and 3.5.2 on MacOSX.

        Parameters
        ----------
        times : (float, list), optional
            If this argument is not given a screenshot of the widget will be made
            as it is (without integrating the simulation). If a float is given, then the
            simulation will be integrated to that time and then a screenshot will
            be taken. If a list of floats is given, the simulation will be integrated
            to each time specified in the array. A separate screenshot for
            each time will be saved.
        prefix : (str), optional
            This string will be part of the output filename for each image.
            Follow by a five digit integer and the suffix .png. By default the
            prefix is './screenshot' which outputs images in the current
            directory with the filnames screenshot00000.png, screenshot00001.png...
            Note that the prefix can include a directory.
        resetCounter : (bool), optional
            Resets the output counter to 0.
        archive : (rebound.Simulationarchive), optional
            Use a REBOUND Simulationarchive. Thus, instead of integratating the
            Simulation from the current time, it will use the Simulationarchive
            to load a snapshot. See examples for usage.
        mode : (string), optional
            Mode to use when querying the Simulationarchive. See Simulationarchive
            documentation for details. By default the value is "snapshot".

        Examples
        --------

        First, create a simulation and widget. All of the following can go in
        one cell.

        >>> sim = rebound.Simulation()
        >>> sim.add(m=1.)
        >>> sim.add(m=1.e-3,x=1.,vy=1.)
        >>> w = sim.widget()
        >>> w

        The widget should show up. To take a screenshot, simply call

        >>> w.takeScreenshot()

        A new file with the name screenshot00000.png will appear in the
        current directory.

        Note that the takeScreenshot command needs to be in a separate cell,
        i.e. after you see the widget.

        You can pass an array of times to the function. This allows you to
        take multiple screenshots, for example to create a movie,

        >>> times = [0,10,100]
        >>> w.takeScreenshot(times)


        This function sets the data arrays in the plot according to the simulation in self.sim.
        Needs to be called after setup() to actually show something on the figure.


Returns True if array a contains at least one element that is not None. Returns False otherwise.


Returns a deep copy of the particle. The particle is not added to any simulation by default.


        Returns a rebound.Orbit object with the keplerian orbital elements
        corresponding to the particle around the passed primary
        (rebound.Particle) If no primary is passed, defaults to Jacobi coordinates
        (with mu = G*Minc, where Minc is the total mass from index 0 to the particle's index, inclusive).

        Examples
        --------

        >>> sim = rebound.Simulation()
        >>> sim.add(m=1.)
        >>> sim.add(x=1.,vy=1.)
        >>> orbit = sim.particles[1].orbit(sim.particles[0]) # Heliocentric coordinates
        >>> print(orbit.e) # gives the eccentricity

        Parameters
        ----------
        primary : rebound.Particle
            Central body (Optional. Default uses Jacobi coordinates)
        G : float
            Gravitational constant (Optional. Default takes G from simulation in which particle is in)

        Returns
        -------
        A rebound.Orbit object


        Returns a nested list of xyz positions along the osculating orbit of the particle.
        If primary is not passed, returns xyz positions along the Jacobi osculating orbit
        (with mu = G*Minc, where Minc is the total mass from index 0 to the particle's index, inclusive).

        Parameters
        ----------
        Npts    : int, optional
            Number of points along the orbit to return  (default: 100)
        primary : rebound.Particle, optional
            Primary to use for the osculating orbit (default: Jacobi center of mass)
        samplingAngle: str, optional
            This determines which angle is sampled linearly. Can be:
              - "M" (mean anomaly)
              - "E" (eccentric anomaly)
              - "f" (true anomaly)
        duplicateEndpoint: bool, optional
            If true, then the first and last point will be identical for closed orbits. This is useful for some plotting tools. The default is true for eccentric orbits. The argument has no effect for hyperbolic orbits (because the endpoints are not identical).


Get or set the xyz position coordinates of the particle.


Get or set the xyz velocity coordinates of the particle.


Get or set the particle's hash.  If set to a string, the corresponding integer hash is calculated.


Copy coordinates (and only coordinates) from particle p to self


Return the index for the snapshot just before t


        Returns a Rotation object that maps the 3D fromv vector to the 3D tov vector, i.e., Rotation * fromv = tov.
        Specifically, the rotation is done counterclockwise around the fromv cross tov axis.

        Arguments
        ---------
        fromv: list-like (e.g. list, numpy array), or character
            Input 3D vector that Rotation will map to vector tov
        tov: list-like (e.g. list, numpy array), or character
            Output 3D vector when Rotation is applied to fromv

        Examples
        --------

        >>> fromv = [2,3,-5]                                            # An arbitrary vector
        >>> rot = rebound.Rotation.from_to(fromv=fromv, tov=[0,0,1])    # Get a rotation that maps fromv to the z axis
        >>> print(rot * fromv)                                          # When our rotation acts on fromv, we get back [0,0,1]


        Consider an orbit, which in a reference coordinate system has standard orbital angles Omega, inc, omega.
        This returns a rotation object 'rot' that rotates vectors into this inclined orbital plane. The vector [1,0,0]
        is rotated such that it points towards the pericenter of the orbit. Murray & Dermott Eq. 2.121 (left hand side)

        Arguments
        ---------
        Omega: float
            Longitude of ascending node (default 0)
        inc: float
            Inclination (default 0)
        omega: float
            Argument of pericenter (default 0)

        Examples
        --------

        >>> a, e, inc, Omega, omega = 1, 0.1, 0.2, 0.3, 0.4             # Make up arbitrary numbers
        >>> rot = rebound.Rotation.orbit(Omega=Omega, inc=inc, omega=omega) # Initialize a Rotation to that specific orbit
        >>> sim = rebound.Simulation()
        >>> sim.add(m=1)
        >>> sim.add(a=a, e=e, inc=inc, Omega=Omega, omega=omega)        # 3D orbit
        >>> sim.add(a=a, e=e)                                           # Orbit in the xy plane
        >>> print(sim.particles[1].xyz)
        >>> print(rot * sim.particles[2].xyz)                           # Same location as other particle after applying rot


        Returns a rotation object that rotates vectors into a new coordinate system with the z axis pointing along
        the vector newz. If newx is passed, the new x axis will point along newx. If not, the new x axis defaults
        to the intersection betweeen the new xy plane (normal to newz) and the original xy plane (specifically along
        the z cross newz direction). The new y axis completes a right-handed coordinate system.

        If passed, newx should be perpendicular to newz. This function will only take the component of newx that is
        perpendicular to newz, in order to avoid any rounding issues.

        Arguments
        ---------
        newz: list-like (e.g. list, numpy array)
            3D vector to use as the new z axis
        newx: list-like (e.g. list, numpy array)
            3D vector to use as the new x axis. If not passed, defaults to the intersection between the new xy plane
            (normal to newz) and the original xy plane (along the z cross newz direction).

        Examples
        --------

        >>> sim = rebound.Simulation()                  # Initialize a sim with two Jupiters on arbitrary inclined orbits
        >>> sim.add(m=1)
        >>> sim.add(m=1e-3, a=1, inc=0.3, Omega=4.2)
        >>> sim.add(m=1e-3, a=2, inc=0.1, Omega=0.5)    # Get a rotation to new axes where z points along total ang. momentum L. Didn't specify newx,
        >>> rot = rebound.Rotation.to_new_axes(newz=sim.angular_momentum()) # so it points along line of nodes between our original xy plane
        >>> sim.rotate(rot)                             # and the new plane perp. to L. Rotate our simulation into this new reference system
        >>> print(sim.angular_momentum())     # Now the total angular momentum points in the z direction as we expect.


        Returns a three vector with orbital elements Omega, inc, omega.
        Note: the angles might not always be in the correct quadrant and might be
        inconsistent with REBOUND's standard definition of orbital elements.


Returns a Rotation object's inverse rotation.


Returns a normalized copy of the Rotation object.


        This function can be used to initialize the variational particles that are
        part of a Variation.

        Note that rather than using this convenience function, one can
        also directly manipulate the particles' coordinate using the following
        syntax:

        >>> var = sim.add_variation()
        >>> var.particles[0].x = 1.

        The ``vary()`` function is useful for initializing variations corresponding to
        changes in one of the orbital parameters for a particle on a bound
        Keplerian orbit.

        The function supports both first and second order variations in the following
        classical orbital parameters:
          a, e, inc, omega, Omega, f
        as well as the Pal (2009) coordinates:
          a, h, k, ix, iy, lambda
        and in both cases the mass m of the particle. The advantage of the Pal coordinate
        system is that all derivatives are well behaved (infinitely differentiable).
        Classical orbital parameters on the other hand exhibit coordinate singularities,
        for example when e=0.

        The following example initializes the variational particles corresponding to a
        change in the semi-major axis of the particle with index 1:

        >>> var = sim.add_variation()
        >>> var.vary(1,"a")

        Parameters
        ----------
        particle_index : int
            The index of the particle that should be varied. The index starts at 0 and runs through N-1. The first particle added to a simulation receives the index 0, the second 1, and the on.
        variation : string
            This parameter determines which orbital parameter is varied.
        variation2: string, optional
            This is only used for second order variations which can depend on two varying parameters. If omitted, then it is assumed that the parameter variation is variation2.
        primary: Particle, optional
            By default, variational particles are created in the Heliocentric frame.
            Set this parameter to use any other particles as a primary (e.g. the center of mass).


        Access the variational particles corresponding to this set of variational equations.

        The function returns a list of particles which are sorted in the same way as those in
        sim.particles

        The particles are pointers and thus can be modified.

        If there are N real particles, this function will also return a list of N particles (all of which are
        variational particles).


        Access the lrescale parameter.

        This is a property because sim.add_variation() returns a copy of the struct, so need to find up-to-date reb_variational_configuration struct in simulation.


        Set the lrescale parameter.

        This is a property because sim.add_variation() returns a copy of the struct, so need to find up-to-date reb_variational_configuration struct in simulation.


Initialize Cartesian vector from its magnitude and two spherical angles theta (polar angle measured from z) and phi (azimuthal angle measured from x)

    Arguments
    ---------
    magnitude: float
        Magnitude of the vector
    theta: float
        Polar angle of the vector, i.e. measured from the z axis
    phi: float
        Azimuthal angle of the vector, i.e. measured counterclockwise from the x axis

    Returns
    -------
    List of [x,y,z] components


Return spherical angle theta measured from z axis

    Arguments
    ---------
    vector: List-like (e.g., list, numpy array)
        3D Cartesian vector to convert to spherical coordinates

    Returns
    -------
    List [magnitude, theta, phi] of vector magnitude, polar angle theta (from z axis) and azimuthal angle phi (from x axis)


    Add the planet of the outer Solar System as a test problem.
    Data taken from NASA Horizons.


    Add all planets of the Solar System as a test problem.
    Data taken from NASA Horizons.


        Get or set the internal coordinate system.

        Available coordinate systems are:

        - ``'jacobi'`` (default)
        - ``'democraticheliocentric'``
        - ``'whds'``
        - ``'barycentric'``


        Get or set the WHFast Kernel.

        Available kernels are:

        - ``'default'`` (standard WH kernel, kick)
        - ``'modifiedkick'`` (modified kick for newtonian gravity)
        - ``'composition'`` (Wisdom's composition method)
        - ``'lazy'`` (Lazy implementer's method)


        Get or set the adaptive mode that determines how the timestep is chosen in IAS15.

        Available adaptive_modes are:

        - ``'individual'`` (timescale estimate based on individual particles)
        - ``'global'`` (used to be the default until 01/2024, global estimate)
        - ``'PRS23'`` (The default. Described in Pham, Rein, Spiegel 2023)
        - ``'Aarseth85'`` (Aarseth 1985 algorithm)


        Get or set the pericenter switching mode.

        Available kernels are:

        - ``'FULL_BS'`` (Integrate entire system with BS)
        - ``'PARTIAL_BS'`` (Integrate only the Kepler step with BS)
        - ``'FULL_IAS15'`` (Integrate entire system with IAS15)


Get or set the type of operator splitting type for phi0.


Get or set the type of operator splitting type for phi1.


Get or set the type of SABA integrator.


Destructor.

        Method that will be executed once for this test case class.
        It will execute after all tests methods.

        Clears up the functional test directory.


Clean-up Test.

        This method will be executed after each test function.


Setup Test.

    This method will be executed before each test function.


Post setup Test.


Post Setup Test.


Assert results by comparing certain products.


Ensures release and creation date time is fixed for the test.


Assert by comparing some products.


Private utility to slice MRO data for the tests.


Private utility to slice INSIGHT data for the tests.


Private utility to generate the OREX configuration file.


Counts lines of code for the files under the indicated path.


Private utility to generate the BepiColombo configuration file.


Private utility to generate the INSIGHT configuration file.


Private utility to generate the MAVEN configuration file.


Creates a new SPICE kernel data set cropped between two dates.

    The intended usage of this tool is to support the testing of
    NPB.

    Note that this tool requires the NAIF utilities ``CKSLICER``
    and ``SPKMERGE`` to be setup in the system and to be included in the PATH.

    The tool is based on the ``SKD SLICER TOOL``'`` by Ricardo Valles (ESS/ESAC)

    :param kernels_dir:
    :param out_kernels_dir:
    :param lsk_file:
    :param sclk_file:
    :param start_time:
    :param stop_time:
    :param timetype:
    :return:


Slice CK files.


Slice SPK files.


Tes Post Setup.

    This method will be executed before each test function.


Clean-up Test.

    This method will be executed after each test function.


Generate test MKs.


Main routine for the NAIF PDS4 Bundler.

    This routine gets the command line arguments or the parameter
    arguments and runs the archive generation pipeline.

    :param config: XML Configuration file
    :param plan: Release plan file listing the kernels to be archived.
                 If this argument is not provided, all the kernels found in
                 the kernels directory specified in the configuration file
                 in addition to new meta-kernels will be included in the
                 increment
    :type plan: str
    :param faucet: Optional indication for end point of the pipeline.
                   Allowed values are: `clear``, ``plan``, ``list``,
                   ``checks``, ``staging``, ``bundle``, and ``labels``.
    :type faucet: str
    :param log: Write log in file. The file is written in the
                ``working_directory`` specified in the configuration file.
    :type log: bool
    :param silent: Log will not be prompted on the terminal during execution
    :type silent: bool
    :param verbose: Full log will be prompted on the terminal  during
                    execution. If argument is set to True, silent argument
                    is omitted
    :type verbose: bool
    :param diff: Optional generation of diff reports for products. Allowed
                 values are: ``files``, ``log``, and ``all``.
    :type diff: str
    :param debug: Indicate whether if the pipeline is running in debug mode.
                  If so the format of the logging is different and the files
                  generated in a failed run are not cleaned up.
    :type debug: bool
    :param clear: Indicates if the pipeline will run only to clear previous
    run and specifies the file that indicates the files to be cleared.
    :type clear: str
    :param kerlist: Release list file listing the kernels to be archived along
                 with their description.
    :type kerlist: str
    :param checksum: Obtain MD5 Sums for products defined in the Checksum Registry
                     file generated by a previous run. These files are stored
                     in the ``working_directory`` specified in the configuration
                     and have a ``*.checksum`` extension.
                     If no Checksum Registry files are available product labels from
                     the staging directory will be used. This argument is useful
                     if large files have already been processed by a previous run.
    :type checksum: bool


Convert between XML and JSON.

    The following XML-to-Python-dict snippet parses entities as well as
    attributes following this XML-to-JSON "specification". It is the most
    general solution handling all cases of XML.

    https://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html

    :param etree: Element Tree read from XML file
    :type etree: dict
    :return: XML File converted into a JSON file
    :rtype: dict


Returns the MD5 sum (checksum) of the provided file.

    :param fname: Filename
    :type fname: str
    :return: Checksum value of the file
    :rtype: str


Creates a directory and raises an error if the directory exists.

    :param src: Source directory with path.
    :type src: str
    :param dest: Destination directory with path.
    :type dest: str


Creates a directory if not present.

    :param dir: Directory path.
    :type dir: str


Given a SPICE kernel provide the SPICE kernel type.

    :param kernel: SPICE Kernel name
    :type kernel: str
    :return: SPICE Kernel type of the input SPICE kernel name
    :rtype: str


Given a SPICE kernel provide the PDS3 SPICE kernel type.

    :param kernel: SPICE Kernel name
    :type kernel: str
    :return: PDS3 SPICE Kernel type of the input SPICE kernel name
    :rtype: str


Given a SPICE kernel type provide the SPICE kernel extension.

    :param kernel_type: SPICE kernel type
    :type kernel_type: str
    :return: SPICE Kernel extension
    :rtype: str


Adds Carriage Return (``<CR>``) to a line.

    :param line: Input line
    :type line: str
    :param eol: EOL defined by the configuration file
    :type eol: str
    :return: Input line with CR
    :rtype: str


Adds Carriage Return (``<CR>``) to a file.

    :param line: Input file
    :type line: str
    :param eol: End of Line character as indicated by the configuration file
    :type eol: str
    :raise: If CR cannot be added to the file


Check if given list contains any duplicates.

    :param list_of_elements: List of SPICE kernel names
    :type list_of_elements: list
    :return: True if the input list contains
             duplicates, False otherwise
    :rtype: bool


Fill a template with uppercase keywords preceded with ``$``.

    :param object: List object
    :type object: object
    :param product_file: Resulting file
    :type product_file: str
    :param product_dictionary: Dictionary of keys to replace
    :type product_dictionary: dict


Generate a list of kernels from a Meta-kernel.

    This function assumes that the meta-kernel will contain a PATH_SYMBOLS
    definition that will be present in each kernel entry preceded by a dollar
    sign ``$``.

    If no kernel is found an error is raised.

    :param mk: Meta-kernel path from which the list of kernels is generated
    :type mk: str
    :param setup: NPB run Setup Object
    :type setup: object
    :return: List of kernels present in the meta-kernel
    :rtype: list


Check if a list has consecutive numbers.

    Check if a list of names with enumeration include all the elements
    in such a way that the enumeration contains all expected numbers.

    :param lst: List of names that include an enumeration
    :type lst: list
    :return: Check if the list has a complete enumeration
    :rtype: bool


Compare two files.

    Compares two files and provides the logic to determine whether if the
    comparison should be added to the log or to an individual file with the
    comparison. The default name of the possible resulting file is::

       diff_`fromfile'[extension removed]_`tofile'[extension_removed].html

    The format for the log output is ASCII and follows a simplified Unix
    diff format.

    The format for the file output is HTML and mocks a simplified Unix
    GUI diff tool such as tkdiff.

    :param fromfile: Path of first file to be compared
    :type fromfile: str
    :param tofile: Path of second file to be compared
    :type tofile: str
    :param dir: Resulting diff files destination directory
    :type dir: str
    :param display: Indication if the fie will only be written in log or
                    if a specific diff file will be generated
    :type display: str
    :return: True if the files are different, False if they are the same.
    :rtype: bool


March patterns to filename.

    Given a SPICE kernel name, a SPICE Kernel name with patterns, and the
    possible patterns, provide a dictionary with the patterns as keys and
    the patterns values as value after matching it between the SPICE Kernel
    name with patterns and without patterns.

    For example, given the following arguments:

         * name: ``insight_v01.tm``
         * name_w_pattern: ``insight_v$VERSION.tm``

    The function will return: ``{VERSION: '01'}``

    :param name: Name of the SPICE Kernel
    :type name: str
    :param name_w_pattern: Name of the SPICE Kernel with patterns
    :type name_w_pattern: str
    :param patterns: List of the possible patterns present in the
                     SPICE Kernel name with patterns
    :type patterns: list
    :return: Dictionary providing the patterns and their value as defined
             by the SPICE kernel
    :rtype: dict


Length of a string in bytes.

    :param strn: string
    :type strn: str
    :return: length of string in bytes
    :rtype: int


List sorting function.

    :param path: path to be sorted
    :type path: str
    :return: sorting result
    :rtype: str


Extract checksum from the checksum registry.

    All the checksum registries will be checked.

    :param path: Product path
    :type path: str
    :param working_directory: checksum registry path
    :type working_directory: str
    :return: MD5 Sum for the file indicated by path
    :rtype: str


Extract checksum from a label rather than calculating it.

    :param path: Product path
    :type path: str
    :return: MD5 Sum for the file indicated by path
    :rtype: str


Extract comment from SPICE DAF file.

    :param path: Path of SPICE kernel
    :type path: str
    :return: SPICE kernel comment
    :rtype: list


Check if a string is present in a file.

    You can also provide the number of times that string is repeated.

    :param file: File where the string is searched
    :type file: str
    :param str_to_check: String to search
    :type str_to_check: str
    :param repetitions: Number of repetitions, default is 1
    :type repetitions: int
    :return: True if the string is present in the file, False otherwise
    :rtype: bool


Replace string in a file.

    :param file: File to replace the string from
    :type file: str
    :param old_string: String present in file to be substituted
    :type old_string: str
    :param new_string: String to be replaced
    :type new_string: str
    :param setup: NPB run Setup Object
    :type setup: object


Reformat multi-line key value for PDS3 labels.

    For example if the ``MAKLABEL`` key value has multiple entries, it needs to
    be reformatted.

    :param value: PDS3 key value
    :type value: str
    :return: PDS3 key value reformatted
    :rtype: str


Obtain the kernel mapping.

    :return: Kernel Mapping
    :rtype: str


Check if the SPICE Kernel has the adequate architecture.

    All SPICE kernels must have a NAIF file ID word as the first "word" on
    the first line of the kernel. This "word" describes the architecture
    of the kernel.

    A binary kernel could have the following architectures:

      * ``DAF``: The file is based on the DAF architecture.
      * ``DAS``: The file is based on the DAS architecture.
      * ``XFR``: The file is in a SPICE transfer file format.

    For an archive only ``DAF`` is acceptable.

    Text kernels must have ``KPL`` (Kernel Pool File) architecture.

    NPB checks if binary kernels have a ``DAF`` architecture and text kernels
    a ``KPL`` architecture.

    :param path: SPICE Kernel or ORBNUM path
    :type path: str
    :return: Error message if error present
    :rtype: str


Check if the SPICE Kernel has the adequate architecture.

    PDS4 Bundles require LTL-IEEE binary kernels and PDS3 data sets require
    BIG-IEEE binary kernels. This behavior can be changed via configuration.

    This method ensures that the endianness of binary kernels is the
    appropriate one according to the configuration.

    :param path: Binary SPICE kernel path
    :type path: str
    :return: Error message if error present
    :rtype: list


Check NON-ASCII characters for a file.

    :param file: Path to file to check
    :return: Resulting error messages
    :rtype: list


Check file EOL.

    :param file: Path to file to check
    :param eol: Expected End of Line
    :return: Resulting error messages
    :rtype: str


Check SPICE text kernel line length.

    :param file: Path to file to check
    :return: Resulting error messages
    :rtype: str


Check if the file has read permissions.

    This method ensures that the file has the adequate file permissions.

    :param path: file path
    :type path: str
    :return: Error message if error present
    :rtype: none


SPICE Exception handler.

    This function is used as a decorator to catch and display SpiceyPy errors.

    A wrapper is inserted as a workaround to unmask the docstring of the
    wrapped function. See: https://github.com/sphinx-doc/sphinx/issues/3783


Returns the current date and time in ``%Y-%m-%dT%H:%M:%S`` format.

    :param format: Time format from configuration.
    :type format: string
    :return: Current date and time
    :rtype: str


Returns the current date in ``%Y-%m-%d`` format.

    :param date: If present, forces a current date otherwise is obtained from
                 the system
    :type date: str
    :return: Current date
    :rtype: str


Returns the creation date and time.

    The date is either in ``maklabel`` or ``infomod2``
    ``%Y-%m-%dT%H:%M:%S.%f`` format.

    :param format: Time format
    :type format: str
    :return: Current time
    :rtype: str


Returns the coverage of a SPK file.

    The function assumes that the appropriate kernels have already been loaded.

    :param path: File path
    :type path: str
    :param main_name: Mission observer name.
    :type main_name: str
    :param date_format: Date format, the default is the one
                        provided by the PDS4 Information Model 2.0 that
                        rounds the milliseconds and then implements an
                        inward addition for the coverage start time and
                        inward subtraction for the coverage stop time.
                        The other option is the ``MAKLABEL`` style that
                        rounds to the second.
    :type date_format: str
    :raise: if the date_format parameter argument is not ``infomod2`` or
            ``maklabel``
    :return: start and finish coverage
    :rtype: list of str


Returns the coverage of a CK file.

    The function assumes that the appropriate kernels have already been loaded.

    :param path: File path
    :type path: str
    :param timsys: Determines whether if the time system is SCLK or not
    :type timsys: str
    :param date_format: Date format, the default is the one
                        provided by the PDS4 Information Model 2.0 that
                        rounds the milliseconds and then implements an
                        inward addition for the coverage start time and
                        inward subtraction for the coverage stop time.
                        The other option is the ``MAKLABEL`` style that
                        rounds to the millisecond.
    :type date_format: str
    :raise: if the date_format parameter argument is not ``infomod2`` or
            ``maklabel``
    :param system: If the time system is not SCLK, then it can be UTC or TDB
    :type system: str
    :return: start and finish coverage
    :rtype: list of str


Returns the coverage of a PCK file.

    The function assumes that the appropriate kernels have already been loaded.

    :param path: File path
    :type path: str
    :param date_format: Date format, the default is the one
                        provided by the PDS4 Information Model 2.0 that
                        rounds the milliseconds and then implements an
                        inward addition for the coverage start time and
                        inward subtraction for the coverage stop time.
                        The other option is the MAKLABEL style that
                        rounds to the second.
    :type date_format: str
    :param system: Determine the output ime system: UTC or TDB
    :type system: str
    :raise: if the date_format parameter argument is not ``infomod2`` or
            ``maklabel``
    :return: start and finish coverage
    :rtype: list of str


Returns the coverage of a DSK file.

    The function assumes that the appropriate kernels (LSK) have already been
    loaded.

    This function is based on the DSKLBL ( Generate an MGSO or PDS DSK
    label file ) subroutine that belongs to the MAKLABEL NAIF utility.

    :param path: File path
    :type path: str
    :param date_format: Date format, the default is the one
                        provided by the PDS4 Information Model 2.0 that
                        rounds the milliseconds and then implements an
                        inward addition for the coverage start time and
                        inward subtraction for the coverage stop time.
                        The other option is the MAKLABEL style that
                        rounds to the second
    :type date_format: str
    :param system: Determine the output ime system: UTC or TDB
    :type system: str
    :raise: if the date_format parameter argument is not ``infomod2`` or
            ``maklabel``
    :return: start and finish coverage
    :rtype: list of str


Convert ET (ephemeris time) to a Date Time string.

    :param beget: Start ephemeris time (ET)
    :type beget: float
    :param endet: End ephemeris time (ET)
    :type endet: float
    :param date_format: Date format, the default is the one
                        provided by the PDS4 Information Model 2.0 that
                        rounds the milliseconds and then implements an
                        inward addition for the coverage start time and
                        inward subtraction for the coverage stop time.
                        The other option is the MAKLABEL style that
                        rounds to the second
    :type date_format: str
    :param kernel_type: Indicates whether if it is a text or binary kernel
    :type kernel_type: str
    :param system: Determine the output ime system: UTC or TDB
    :type system: str
    :return: Start and Stop dates
    :rtype: list of str


Returns the creation date of a given PDS3 label.

    :param path: File path
    :type path: str
    :return: Creation date
    :rtype: str


Parses a date string using the following formats:
        * %Y-%b-%d-%H:%M:%S
        * %Y-%m-%dT%H:%M:%S

    :param date_str: Stop time to determine list of years
    :type date_str: str
    :return: date corresponding to the input str
    :rtype: datetime


Add file to the list.

        :param element: SPICE Kernel product or ORBNUM product to be added to the list
        :type element: str


Add SPICE kernel or ORBNUM file to the list.

        :param kernel: SPICE kernel or ORBNUM file added to the list
        :type kernel: str


Extract the Kernel List information from the configuration file.


Read Release Plan from the main module input.

        :param plan: Release Plan name
        :type plan: str


Write the Release Plan if not provided.

        :return: True if a release plan has been generated, False if it has
                 been provided as input
        :rtype: bool


Write the Kernel List product.

        The list is not an archival product but an NPB by-product, therefore
        it is not generated by any of the product classes.


Read the Kernel List.

        Note that the format that the kernel list has to follow is very
        strict, including no whitespace at the end of each line and Line-feed
        EOL.

        :param kerlist: Kernel List path
        :type kerlist: str


Write the complete Kernel List using the former ones.


Validation of the Kernel List.

        The validation of the Kernel List performs the following checks:

         * check that the list has the same number of ``FILE``, ``MAKLABEL_OPTIONS``,
           and ``DESCRIPTION`` entries.
         * check list against plan
         * check that list for duplicate files
         * check that all files listed in the list are on the ``kernels_directory``
         * check that the files are not in the ``bundle_directory``
         * display all the ``MAKLABL_OPTIONS`` used
         * check that all the ``MAKLBL_OPTIONS`` are in the template for PDS3
         * check that the list has no duplicates
         * check that the list has no bad characters
         * if the ``-d DIFF --diff DIFF`` argument is used, compare the kernel
           list with the kernel list of the previous release -if avaialble.


Validation of the complete Kernel List.

        The complete Kernel List is generated by NPB by merging all the
        available Kernel List files. These kernel list files must be located
        in the ``working_directory`` as specified by the NPB configuration.

        In principle all the kernels that have ever been added to the archive
        should be present.

        The validation of the complete Kernel List performs the following checks:

         * check that the list has the same number of ``FILE``, ``MAKLABEL_OPTIONS``,
           and ``DESCRIPTION`` entries
         * check all the ``MAKLABL_OPTIONS`` used
         * check that the list has no duplicates


Check the SPICE kernel and ORBNUM products from the kernel list.

        The products present in the Kernel List --whether if generated by NPB
        or provided by the user-- will be checked and if issues are found they
        will be reported as ``WARNING`` or ``ERROR`` messages.

        The checks performed to the products are the following:

         * identify if a SPICE kernel is present in multiple kernel directories
         * check End of Line character for text SPICE kernels and ORBNUM files.
         * check text SPICE kernels and ORBNUM files for non-ASCII characters.
         * check if text SPICE kernels have more than 80 characters per line.
         * validate kernel architecture
         * check endianness and permissions of binary kernels


Determine product logical identifier (LID).

        :return: product LID
        :rtype: str


Determine product logical identifier (VID).

        :return: product VID
        :rtype: str


Read the kernel list to return the description.

        The generated kernel list file must be used because it contains the
        description.

        :return: Kernel Description from the Kernel List
        :rtype: str


Read the kernel list to return the ``MAKLABEL_OPTIONS``.

        The generated kernel list file must be used because it contains the
        ``MAKLABEL_OPTIONS``.

        :return: ``MAKLABEL_OPTIONS`` from kernel list
        :rtype: str


Determine the product coverage.


Extract IDs from CK.

        :return: List of IDs present in the CK
        :rtype: list


Extract IDs from IK.

        :return: List of IDs present in the IK
        :rtype: list


Check if the provided Meta-kernel version is correct.


Write the Meta-kernel.


**Compare the Meta-kernel with the previous version**.

        The MK is compared with a previous version of the MK. If no prior
        MK is found, the new MK is compared to NPB's MK template.


Perform a basic validation of the Meta-kernel.

        The validation consists of:

           * load the kernel with the SPICE API ``FURNSH``
           * count the loaded kernels with SPICE API ``KTOTAL``
           * compare the number of kernels in the kernel pool with the length
             of the MK collection list attribute
           * check that line lengths are less than 80 characters


Determine Meta-kernel coverage.

        Meta-kernel coverage is determined by:

        *  for whole mission meta-kernels ``start_date_time`` and ``stop_date_time``
           are set to the coverage provided by spacecraft SPK, CKs, or to other
           dates at the discretion of the archive producer. These other dates might
           be required for missions whose SPks and CKs do not explicitly cover the
           dates required by the archive, e.g.: a lander mission with a fixed
           position provided by an SPK with extended coverage

        *  for yearly mission meta-kernels ``start_date_time`` and ``stop_date_time``
           are set to the coverage from ``Jan 1 00:00`` of the year to either the
           end of coverage provided by spacecraft SPK or CKs, or the end of
           the year (whichever is earlier)


Read and process an ORBNUM file header.

        Defines the record_fixed_length attribute that provides the length of
        a record.

        :return: ORBNUM header line
        :rtype: str


Reformat UTC strings in the ORBNUM file.

        Re-process the UTC string fields of an ORBNUM sample row
        to remove blank spaces.

        :param sample_record: sample row with UTC string with blank spaces
        :type sample_record: str
        :return: sample row with UTC string with dashes
        :rtype: str


Read and interpret the records of an ORBNUM file.

        Read an orbnum file and set the number of records attribute,
        the length of the records attribute, determine which lines have blank
        records and, perform simple checks of the records.

        :return: number of records of ORBNUM file
        :rtype: str


Maps the event keyword to the event name/description.

        :param event: ORBNUM event key
        :type event: str
        :return: ORBNUM event description
        :rtype: str


Maps the event keyword to the opposite event keyword.

        :param event: ORBNUM event key
        :type event: str
        :return: ORBNUM opposite event keyword
        :rtype: str


Write the ORBNUM table character description.

        Write the orbnum table character description information
        determination event and the PCK kernel used.


Determine the coverage of the ORNBUM file.

        The coverage of the ORBNUM file can be determined in three different
        ways:

           *  If there is a one to one correspondence with an SPK
              file, the SPK file can be provided with the ``<kernel>``
              tag. The tag can be a path to a specific kernel that
              does not have to be part of the increment, a pattern
              of a kernel present in the increment or a pattern of
              a kernel present in the final directory of the archive.

           *  If there is a quasi one to one correspondence with an
              SPK file with a given cutoff time prior to the end
              of the SPK file, the SPK file can be provided with the
              ``<kernel>`` tag. The tag can be a path to a specific kernel
              that does not have to be part of the increment, a pattern
              of a kernel present in the increment or a pattern of
              a kernel present in the final directory of the archive.
              Currently, the only cutoff pattern available is the
              boundary of the previous day of the SPK coverage stop
              time.

           *  A user can provide a look-up table with this file, as follows::

                <lookup_table>
                   <file name="maven_orb_rec_210101_210401_v1.orb">
                      <start>2021-01-01T00:00:00.000Z</start>
                      <finish>2021-04-01T01:00:00.000Z</finish>
                   </file>
                </lookup_table>

              Note that in this particular case the first three and
              last three lines of the orbnum files would have provided::

                   Event UTC PERI
                   ====================
                   2021 JAN 01 00:14:15
                   2021 JAN 01 03:50:43
                   2021 JAN 01 07:27:09
                   (...)
                   2021 MAR 31 15:00:05
                   2021 MAR 31 18:36:29
                   2021 MAR 31 22:12:54

           *  If nothing is provided NPB will provide the coverage based on
              the event time of the first orbit and the opposite event time
              of the last orbit.


Write and validate the Collection inventory.


Write the PDS4 Collection product.


This method uses the previous index file to generate the new one.

        There is a NAIF Perl script that will generate an index file from a
        kernel list file. Please contact the NAIF if you are interested in such
        script.


Validate the PDS4 Inventory Product.

        The Inventory is validated by checking that all the products listed
        are present in the archive.


Validate the PDS3 Index.

        The Inventory is validated by checking that all the products listed
        are present in the archive and comparing the index file with the
        previous one.


**Compare the Inventory Product with another Inventory**.

        The Inventory Product is compared with the previous
        version and if it does not exist with the sample INSIGHT inventory
        product.


Determine whether if ``<CR>`` has to be added to the SPICEDS.


Check if the SPICEDS product needs to be generated.

        :return: True if the SPICEDS products needs to be generated, False otherwise
        :rtype: bool


**Compare the SPICEDS Product with another SPICEDS**.

        The SPICEDS Product is compared with the previous
        version and if it does not exist with the sample INSIGHT SPICEDS
        product.


Write the Readme product.


Write and label the Checksum file.

        :param history: True if the checksum will be generated with the archive
                        history, False otherwise
        :type history: bool


Reads the current checksum file.

        Reads the current checksum file, determines the version of the
        new checksum file, and adds the checksum file itself and its label.

        :param add_previous_checksum: True if there is a previous checksum file to
                                  be added, False otherwise
        :type add_previous_checksum: bool


Write the Checksum file and determine its start and stop time.

        This method can also be used to determine the start and stop time of
        the checksum file, necessary to determine these times for the
        miscellaneous collection before the checksum is actually written.

        :param history: Archive History
        :type history: dict
        :param set_coverage: Determines the start and stop of the checksum file
                             if set to True, False otherwise
        :type set_coverage: bool
        :return:


**Compare the Checksum with the previous Checksum file**.

        The Checksum file is compared with the previous version.


Try to validate the PDS3 document.

        The outcome of the validation is an INFO or a WARNING log message.


Write the Label.


**Compare the Label with another label**.

        The product label is compared to a similar label. The label with which
        the generated label is compared to is determined
        by the first criteria that is met from the following list:

           * find a different version of the same label
           * find the label of a product of the same kind (e.g.: same kernel
             type)
           * use a label of a product of the same kind from INSIGHT available
             from the NPB package.


Format the SPICE kernel description appropriately.

        The first line goes from character 33 to 78.
        Successive lines go from character  1 to 78.
        Last line has a blank space after the full stop.

        :return: Formatted label description
        :rtype: str


Insert or update a label in a text kernel.

        The routine inserts the label, after the first line containing the
        kernel architecture specification and removes extra empty lines at the
        end of the kernel file.


Insert or update a label in a binary kernel.

        The routine inserts the label in the kernel comment.


For a label provide all the parameters required for an ORBNUM field character.

        :param name: Name field
        :type name: str
        :param number: Number field
        :type number: str
        :param location: Location field
        :type location: str
        :param type: Type field
        :type type: str
        :param length: Length field
        :type length: str
        :param format: Format field
        :type format: str
        :param description: Description field
        :type description: str
        :param unit: Unit field
        :type unit: str
        :param blanks: Blank space missing constant indication
        :type blanks: str
        :return: Field Character for ORBNUM PDS4 label
        :rtype: str


Add a Product to the Collection.

        :param element: Product to add to Collection
        :type element: object


Determine the name of the Meta-kernel(s) to be generated.

        :return: Dictionary of meta-kernels to be generated. The keys list the
                 meta-kernels and the values whether if they are provided by the
                 user or not.
        :rtype: dictionary.


Validate the SPICE Kernels collection.

        The SPICE Kernels collection validation performs the following checks:

           * check that all the kernels from the kernel list are present
           * check that all the kernels have been labeled
           * display the key elements of the labels for the user to do a visual
             inspection. The key elements are: ``logical_identifier``, ``version_id``,
             ``title``, ``description``, ``start_date_time``, ``stop_date_time``,
             ``file_name``, ``file_size``, ``md5_checksum``, ``object_length``,
             ``kernel_type``, and ``encoding_type``.


Report the Collection generation step.


Start the generation of the log for the execution.


Write log, file list, and checksum registry files when NPB stops.


Function to signal a NPB error message.

    The File List and Checksum Registry files are also written.

    :param message: Error message
    :type message: str
    :param setup: Setup object, if provided a file will be written
    :type setup: object


Lists all the files in the staging area.


Copy files from ``staging_directory`` to the ``bundle_directory``.


Validate the Bundle.

        The two implemented steps are to check checksum files against the
        updated bundle history and checking the bundle times.


Check the correctness of the bundle times.


Validate the bundle updated history with the checksum files.

        This method validates all the archive Checksum files with the "Archive
        History". The "Archive history" is obtained by extracting the
        previous releases and the Collections that correspond to each release
        from the Bundle labels. The other products' information is extracted
        from the collection inventories.

        The archive history is then provided as a dictionary with releases
        as keys and each key contains a list of files for that release.

        The validation is performed by comparing each release entry of the
        dictionary with the release checksum file ``checksum_v???.tab``.

        In parallel the method writes in the execution log the complete bundle
        release history, providing an ordered list of files released for each
        release number.


Performs the following checks to the loaded configuration items:

        * IM, Line Feed, and Date Time format NAIF recommendations
        * Archive increment start and finish times
        * Transform relative to absolute paths
        * Existence of kernel directories
        * IM, XML model, and Schema Location coherence
        * Check existence of templates according to the IM
        * Meta-kernel configuration
        * Presence of uppercase characters in the kernel list configuration


Loads the kernels required to run NPB.

        Note that kernels that
        are not required might be loaded as well, but given that the
        required memory is not much, we stay on the safe side by loading
        additional kernels.


Clears the files generated by a previous run.

        Clears the files generated by a previous run when specified with the
        clear argument and the kernel list of the previous run.

        Please note that newly created directories will not be erased.

        :param debug: If True, the by-product files are not cleaned up. This is
                      useful when testing
        :type debug: bool


Add file fo Product List.

        Adds a product to the run by-product Product List.

        :param file: Product to be added
        :type file: str


Add checksum to Checksum record.

        Adds a MD5sum entry with the product it corresponds to for the run
        by-product Checksum record file.

        :param path: File path for checksum
        :type path: str
        :param checksum: Checksum value for checksum
        :type checksum: str


Write the run by-product File List.


Write the run by-product Checksum Record.


    Takes a string path, returns true if exists or
    prints error message and returns false if it doesn't.


    Takes a path for a new or existing directory. Creates directory
    and sub-directories if not already present.


    Takes an output directory path and a file path to a zipped archive.
    If file is a valid zip, it extracts all to the output directory.


    Takes a path to a directory containing tifs and
    and a list of the tif filenames.
    Deletes any tifs containing only NaN values.


    If recognised jupytertheme dark mode is being used,
    reformat matplotlib settings for improved dark mode visibility.
    Return True if matplotlib settings adjusted or False if not


eclick and erelease are the press and release events


        Plots an image in grayscale.
        Parameters:
        - image: 2D array of raster values
        - vmin: Minimum value for colormap
        - vmax: Maximum value for colormap
        - return_ax: Option to return plot axis


    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.


    Compute saturation vapor pressure over water or ice
    according to ECMWF IFS documentation (7.93).


Compute saturation vapor pressure according to ECMWF IFS documentation (7.92).


    Compute relative humidity from specific humidity
    following the implementation in the IFS model.


    Integrate ERA5 geopotential from surfce to a reference pressure
    level p_ref.


    Load a climate delta and if target_date_time is given,
    interpolate it to that date and time of the year.


    Does the following:
        - load a climate delta
        - for specific variables (ta and hur) also load surface
          climate delta,
          as well as HIST surface pressure. This is to extend
          the 3D climate deltas with surface values which makes
          the interpolation to the ERA5 model levels more precise.
        - vertically interpolate climate deltas to ERA5 model levels


    In the 3D climate deltas, replace the value just below
    the surface by the surface climate delta value and insert
    it at HIST surface pressure. This improves the precision
    of the climate deltas during interpolation to the ERA5 model levels.
    All 3D climate delta values below the historical surface pressure
    are set to the surface value (constant extrapolation). This is
    because within the orography the GCM climate delta is assumed
    to be incorrect.


    Vertically interpolate climate delta onto ERA5 model levels.
    If delta_sfc and ps_hist are given, surface values will
    be inserted into the 3D climate delta at the height of
    the surface pressure. This gives a more precise interpolation.
    Climate delta values below the surface are set to the surface
    climate delta because below the surface, the GCM climate delta
    is considered unreliable and thus constant extrapolation
    seems more reasonable.


    Interpolate 3D array in vertical (pressure) dimension using the
    logarithm of pressure.
    extrapolate:
        - off: no extrapolation
        - linear: linear extrapolation
        - constant: constant extrapolation
        - nan: set to nan


    Vertical interpolation helper function with numba njit for
    fast performance.
    Loop over time lat and lon dimensions and interpolate each column
    individually
    extrapolate:
        - off: no extrapolation
        - linear: linear extrapolation
        - constant: constant extrapolation
        - nan: set to nan


    Numba helper function for interpolation of 1d vertical column.
    Does constant extrapolation which is used for the climate deltas.
    extrapolate:
        - off: no extrapolation
        - linear: linear extrapolation
        - constant: constant extrapolation
        - nan: set to nan


    Find lowest GCM pressure level among p_ref_opts that lies
    above the minimum pressure (e.g. currently set to 90% surface pressure)
    in both ERA and PGW climate.
    Also ensure that during the iterations, no reference pressure level
    at lower altitude than during last iterations is used. This is to
    prevent the iteration algorithm to oscillate between two reference
    pressure levels and not converge.


	This function performs a temporal smoothing of an annual timeseries
    (typically daily resolution) using a spectral filter
    (Bosshard et al. 2011).

	Input:
		Input 1: Path to a netcdf file of the annual cycle to be smoothed.
        Normally this is the change in a specific variable between
        two simulations (e.g. warming).
        Can be 4 or 3 dimensional, where the time is one dimension
        and the others are space dimensions.
		Input 2: The name of the variable within the given netcdf file
		Input 3: Path to the output file

	Output:
		A netcdf file containing the smoothed annual cycle.


    Estimation of the harmonics according to formula 12.19 -
    12.23 on p. 264 in Storch & Zwiers

    Is incomplete since it is only for use in surrogate smoothing
    --> only the part of the formulas that is needed there

    Parameters
    ----------
    ts :  1D numpy array
        Passes a time series

    Returns
    -------
        hcts : a reconstructed smoothed timeseries
                (the more modes are summed the less smoothing)
        mean : the mean of the timeseries (needed for reconstruction)


    Method to do lat/lon bilinear interpolation for periodic or non-periodic
    grid either with xesmf (i_use_xesmf), or with an xarray-only
    implementation if the xesmf package is not installed.

    Parameters
    ----------

    ds_gcm: xr.array
        Passes the original grid and data from the gcm
    ds_era5 : xr.array
        Passes the target grid data to interpolate to
    var_name : string
        Passes the name of the variable to interpolate

    Returns
    -------
    ds_regridded : np.ndarray
        ds_gcm interpolated to the ds_era5 grid


Point cloud based NaN-ignoring interpolation from unstructured to regular lon/lat grid

    This function takes an xarray 2D array with individual lon/lat coordinates and
    uses pyvista.interpolate() to interpolate that grid to a regular lon/lat grid. This function
    will ignore all NaN values present in the unstructured grid.

    Parameters
    ----------

    da_era5_land_fr : xr.array
        Passes the ERA5 land fraction and grid data
    da_delta : xr.array
        Passes the unstructured array from which to interpolate
    kernel_radius : int
        Passes a maximal distance for interpolation in meters. Only applicable for ocean variables
    sharpness : float
        Passes a sharpness coefficent. The higher value it has the less contribution is associated with farther away grid points.
        Only applicable for ocean variables

    Returns
    -------
    new_era5_grid : np.2darray
        Original values interpolated onto the target grid


Interpolation wrapper that allows for each variable to be assigned a custom scheme

    This function implements for different variables different kinds of interpolation. Default is bi-linear
    interpolation from regular grid to regular grid.

    Parameters
    ----------

    origin_grid : xr.DataSet
        Passes the GCM original grid structure and values
    target_grid : xr.DataSet
        Passes target grid structure to interpolate to
    i_use_xesmf : boolean
        Passes booloean to adjust which bi-linear scheme is used, only applicable for athmospheric variables
    nan_interp_kernel_radius : int
        Passes a maximal distance for interpolation in meters. Only applicable for ocean variables
    nan_interp_sharpness : float
        Passes a sharpness coefficent. The higher value it has the less contribution is associated with farther away grid points.
        Only applicable for ocean variables

    Returns
    -------
    new_era5_grid : xr.DataSet
        Original values interpolated onto the target grid


Combines TOS and TS temperature as a weighted average according to land and ocean contribution

    This functions assumes that all fields are on the same grid!

    Parameters
    ----------
    tos_field : 2d.nparray
        Passes TOS field on ERA5 grid
    ts_field : 2d.nparray
        Passes TS field on ERA5 grid
    land_frac : 2d.nparray
        Passes land fraction on ERA5 grid
    ice_field : 2d.nparray
        Passes sea ice fraction on ERA5 grid

    Returns
    -------
    combined_ts : 2d.nparray
        Returns combined temperature fields


    Debugging function to test time interpolation. Is called if input
    inputg argument --debug_mode is set to "interpolate_time".


Compute relative humidity from specific humidity.


Plot and define the 3 draggable rectangles


Clear the graph


Connect signals and slots.


_nSpectraWidget = QWidget()
    _nSpectraLayout = QHBoxLayout(_nSpectraWidget)
    _nSpectraLabel = QLabel('
Number of Spectra:
')
    _nSpectraLabel.setFixedHeight(35)
    _nSpectraLayout.addWidget(_nSpectraLabel)
    _nSpectraEntry = QLineEdit('')
    _nSpectraEntry.setReadOnly(True)
    #_nSpectraEntry.setMaximumWidth(30)
    _nSpectraLayout.addWidget(_nSpectraEntry)
    mainLeftLayout.addWidget(_nSpectraWidget)

    _avgPDWidget = QWidget()
    _avgPDLayout = QHBoxLayout(_avgPDWidget)
    _avgPDLabel = QLabel('
Avg. Photodiode:
')
    _avgPDLabel.setFixedHeight(35)
    _avgPDLayout.addWidget(_avgPDLabel)
    _avgPDEntry = QLineEdit('')
    _avgPDEntry.setReadOnly(True)
    _avgPDLayout.addWidget(_avgPDEntry)
    mainLeftLayout.addWidget(_avgPDWidget)


    imageWidget = QWidget()
    imageLayout = QHBoxLayout(imageWidget)
    imageLayout.setContentsMargins(0, 0, 0, 0)

    img1_dir = os.path.join(os.path.dirname(sys.modules[__name__].__file__), os.pardir, os.pardir, 'resources', 'WATSON_placeholder.png')
    pixmap1 = QPixmap(img1_dir)
    pixmap1 = pixmap1.scaledToWidth(0.92*self.mainImgScrollContainer.width())
    self.imageWATSON = QLabel()
    self.imageWATSON.setPixmap(pixmap1)

    imageLayout.addWidget(self.imageWATSON)

    self.imageACI = QLabel(imageWidget)
    img2_dir = os.path.join(os.path.dirname(sys.modules[__name__].__file__), os.pardir, os.pardir, 'resources', 'ACI_placeholder.png')
    pixmap2 = QPixmap(img2_dir)
    #pixmap2 = pixmap2.scaled(0.95*self.imageWATSON.width(), 0.95*self.imageWATSON.height(), Qt.KeepAspectRatio)
    pixmap2 = pixmap2.scaledToWidth(0.85*self.imageWATSON.height())
    self.imageACI.setPixmap(pixmap2)
    self.imageACI.setFixedSize(pixmap2.width(), pixmap2.height())
    print(self.imageWATSON.width(), self.imageWATSON.height())
    print(pixmap2.width(), pixmap2.height())

    #p = self.imageWATSON.geometry().bottomRight() - self.imageACI.geometry().bottomRight() - QPoint(-10, 0)
    #self.imageACI.move(p)
    self.imageACI.move(QPoint(3, 160))

    mainImgLayout.addWidget(imageWidget)


A property for distance


Convert an integer notice type to a string.

    Parameters
    ----------
    notice_type_int : int
        The notice type. For possible values, see :class:`gcn.NoticeType`.
    flavor : str
        The GCN format flavor.

    Returns
    -------
    str
        The Kafka topic corresponding to the notice type.

    Example
    -------

    >>> notice_type_int_to_str(150, 'voevent')
    'LVC_PRELIMINARY'

    >>> notice_type_int_to_str(5000, 'voevent')
    'UNKNOWN'


Get a Kafka topic name for the given GCN Classic notice type string.

    Parameters
    ----------
    notice_type_str : str
        The notice type string, as returned :meth:`notice_type_int_to_str`.
    flavor : str
        The GCN format flavor.

    Returns
    -------
    str
        The Kafka topic corresponding to the notice type.

    Example
    -------

    >>> topic_for_notice_type('LVC_PRELIMINARY', 'voevent')
    'gcn.classic.voevent.LVC_PRELIMINARY'


Produce a heartbeat message once per second.


Pump GCN Classic notices to a Kafka broker.

    Specify the Kafka client configuration in environment variables using the
    conventions described in
    https://docs.confluent.io/platform/current/installation/docker/config-reference.html#confluent-enterprise-ak-configuration:

    * Start the environment variable name with `KAFKA_`.
    * Convert to upper-case.
    * Replace periods (`.`) with single underscores (`_`).
    * Replace dashes (`-`) with double underscores (`__`).
    * Replace underscores (`-`) with triple underscores (`___`).


 stupid power spectrum calculator.

        f1 f2 must be density fields in configuration or fourier space.

        For convenience if f1 is strictly overdensity in fourier space,
        (zero mode is zero) the code still works.

        Returns k, p or k, p * n, N if average is False


 Down samples a fourier space field. Size can be scalar or vector.

        Hermitian should be handled correctly. But I have only tested this
        on hermitian compressed fields.


 discover directories and files that can be htar or hsi put.

        A directory will be htarred if it is a leaf directory, or if
        it matches any of the patterns in leaflist.

        Any files that is not included in a tar file is will be copied with hsi put

        relpath : if True, return relative to rootdir
        leaflist :
        returns

            tarables, extrafiles

        tarables is a list of directories ready to be tarred.

        extrafiles is a list of files ready to be copied.


mode can be c, t, x


y is the parameter, as defined in (6), assumed to be an np.ndarray.


    i = ID of the shell
    N_part_shell = number of particles in the shell
    rho_mean = the aveage density in the Universe
    last_cell_size = size of the last, non-infinite cell


    Calculates the lower limit of the i-th bin for the constant volume binning in the
    non-compact space (constant volume in the compact space)

    i = the ID of the boundary
    d_s = the diameter of the 4D sphere
    N_r_bin = Number of the radial bins
    R_sim = the radius of the simulation volume in real space


    i = ID of the shell
    N_part_shell = number of particles in the shell
    rho_mean = the aveage density in the Universe
    R_sim = the radius of the simulation volume in real space


    Function for calculating voronoi volumes
    Input:
        - points: array containing the coordinates of the input particles
    Returns:
        - vol: array containing the volumes of all cells


    Function for calculating the potential of Cubic spline kernel (Monaghan & Lattanzio, 1985)
    Input:
        - r: distance from the particle
        - h: softening length
    Returns:
        - cubic spline potential value (assuming unit masses and G=1 units)


    A function for calculating the Navarro-Frenk-White profile
    Input:
        - r: distance from the center
        - rho0: density parameter of the NFW profile
        - Rs: scale lenght of the halo
    Returns:
        - NFW profile values at "r" input distances


    Hubble parameter at given redshift using astropy.
    Input:
        - z: redshift
        - H0: Hubble constant in km/s/Mpc units
        - Om: non-relativistic matter density parameter
        - Ol: dark energy density parameter
        - DE_model: Dark Energy model name. must be "Lambda", "w0", or "CPL"
        - DE_params: list of the parameters of the DE model.
            -> "Lambda": not used
            -> "w0": [w0]
            -> "CPL": [w0,wa]
    Returns:
        - Hz: Hubble parameter at z redshift in km/s/Mpc units


    Function for calculating various halo parameters
    Input:
        - p: a StePS_Particle_Catalog containing the particles of the simulation
        - idx: ID of the central particle candidate of the halo
        - halo_particleindexes: list of indexes of the particles that can be potentially part of the halo
        - HaloID: ID of the new halo
        - massdefnames: a list containing the mass definition names
        - massdefdenstable: an array containing the density limits of the mass definitions
        - npartmin: minimal particle number of a halo
        - centermode: method for identifying the center of the halo. Implemented methods:
            -> "CENTRALPARTICLE": the coordinates of the central particle is the halo center (fast)
            -> "CENTEROFMASSNPARTMIN": using center of mass of the most inner npartmin particles as center (more physical)
        - boundonly: If True, only bound particles will be considered during the parameter estimation.
        - rho_b: background densiy
    Returns:
        - returndict: A dictionary containing all calculated halo parameters such us position, velocity, mass, radius, angular momentum, spin parameters, scale radius, energy, velocity dispersion, etc.


    Function for writing out IC in hdf5 format.
    Parameters:
        dataarray - numpy array containing the particle data (coordinates, velocities, masses)
        outputfilename - name of the output file
        Linearsize - Linear size of the IC (simulation)
        Redshift - initial redshift
        OmegaM - Matter density
        OmegaL - Dark energy density
        HubbleParam - Hubble parameter
        precision - Floating point precision of the IC (0: 32bit; 1: 64bit)


    Function to convert a StePS ascii file to Gadget format.
    infile: input StePS ascii file
    outfile: output Gadget file


Create a config file


Mock various crds calls from Step


Disable crds steppars (by setting the environment variable)


Reset logging configuration to DEFAULT_CONFIGURATION


Fixture to make sure the root logger is unchanged


    A few tests are easier to understand and write when
    using the models in the library as a list. Generally
    this should be avoided in the pipeline but tests are
    different beasts.


Fixture to generate a few models with group ids from _GROUP_IDS


    Fixture that creates a simple association, saves it (and the models)
    to disk, and returns the path of the saved association


    Helper function to modify the association at `example_asn_path`
    by adding an attribute `attr` to the member list (at index
    `member_index`) with value `value`. This is used to modify
    the `group_id` or `exptype` of a certain member for some tests.

    If member_index is iterable each returned value will be used as an
    index


Collect the list of all reftypes for child Steps that are not skipped.
        Overridden reftypes are included but handled normally later by the
        Pipeline version of the get_ref_override() method defined below.


Return a list of the unskipped Step objects launched by `self`.

        Steps are also excluded if `Step.prefetch_references` is False.


        Merge the config parameters from a pipeline config reference file into the
        config obtained from each step

        Parameters
        ----------
        cls : jwst.stpipe.pipeline.Pipeline class
            The pipeline class

        refcfg : ConfigObj object
            The ConfigObj created from crds cfg files from each of the steps
            in the pipeline

        ref_file : string
            The name of the pipeline crds step config file

        Returns
        -------
        ConfigObj of the merged parameters, with those from the pipeline cfg having
        precedence over those from the individual steps


        Precache all of the expected reference files before the Step's
        process method is called.

        Handles opening `input_file` as a model if it is a filename.

        input_file:  filename, model container, or model

        Returns
        -------
        None


        Save to a file.

        Parameters
        ----------
        path : string or callable
            File path to save to.
            If function, it takes one argument that is
            model.meta.filename and returns the full path string.

        dir_path : str
            Directory to save to. If not None, this will override
            any directory information in the ``path``

        Returns
        -------
        output_path: str
            The file path the model was saved in.


        Create a step from a configuration file.

        Parameters
        ----------
        config_file : path or readable file-like object
            The config file to load parameters from

        parent : Step instance, optional
            The parent step of this step.  Used to determine a
            fully-qualified name for this step, and to determine
            the mode in which to run this step.

        name : str, optional
            If provided, use that name for the returned instance.
            If not provided, the following are tried (in order):
            - The ``name`` parameter in the config file
            - The filename of the config file
            - The name of returned class

        Returns
        -------
        step : Step instance
            If the config file has a ``class`` parameter, the return
            value will be as instance of that class.  The ``class``
            parameter in the config file must specify a subclass of
            ``cls``.  If the configuration file has no ``class``
            parameter, then an instance of ``cls`` is returned.

            Any parameters found in the config file will be set
            as member variables on the returned `Step` instance.


        Create a step from a configuration file.

        Parameters
        ----------
        args : list of str
            Commandline arguments

        Returns
        -------
        step : Step instance
            If the config file has a ``class`` parameter, the return
            value will be as instance of that class.

            Any parameters found in the config file will be set
            as member variables on the returned `Step` instance.


        Create a step from a configuration file fragment.

        Parameters
        ----------
        config : configobj.Section instance
            The config file fragment containing parameters for this
            step only.
        parent : Step instance, optional
            The parent step of this step.  Used to determine a
            fully-qualified name for this step, and to determine
            the mode in which to run this step.
        name : str, optional
            If provided, use that name for the returned instance.
            If not provided, try the following (in order):
            - The ``name`` parameter in the config file fragment
            - The name of returned class
        config_file : str or pathlib.Path, optional
            The path to the config file that created this step, if
            any.  This is used to resolve relative file name
            parameters in the config file.

        Returns
        -------
        step : instance of cls
            Any parameters found in the config file fragment will be
            set as member variables on the returned `Step` instance.


        Class method to get a filename for a dataset.

        Parameters
        ----------
        dataset : str, Path, DataModel, ModelLibrary, Sequence
            Dataset to be inspected for a filename.

        Returns
        -------
        filename : str or None
            Filename as a string or None if no filename could be determined.


        Class method to get the CRDS parameters and observatory for a given dataset.

        Parameters
        ----------
        dataset : str, Path, DataModel, ModelLibrary, Sequence
            Dataset to use for determining CRDS parameters.

        Returns
        -------
        parameters : dict
            Dictionary of parameters to pass to CRDS.
        observatory : str
            Observatory to pass to CRDS.


        Retrieve logs from the most recent run of this step.

        Returns
        -------
        list of str


        Run handles the generic setup and teardown that happens with
        the running of each step.  The real work that is unique to
        each step type is done in the `process` method.


        Hook that allows subclasses to set mission-specific metadata on each
        step result before that result is saved.

        Parameters
        ----------
        result : a datamodel that is an instance of AbstractDataModel or
                 collections.abc.Sequence
                 One step result (potentially of many).

        reference_files_used : list of tuple
            List of reference files used when running the step, each
            a tuple in the form (str reference type, str reference URI).


        Remove a known Step filename suffix from a filename
        (if present).

        Parameters
        ----------
        name : str
            Filename.

        Returns
        -------
        str
            Filename with any known suffix removed.
        str
            Separator that delimited the original suffix.


Prefetch reference files,  nominally called when
        self.prefetch_references is True.  Can be called explicitly
        when self.prefetch_refences is False.


        This is where real work happens. Every Step subclass has to
        override this method. The default behaviour is to raise a
        NotImplementedError exception.


        Creates and runs a new instance of the class.

        Gets a config file from CRDS if one is available

        To set configuration parameters, pass a ``config_file`` path or
        keyword arguments.  Keyword arguments override those in the
        specified ``config_file``.

        Any positional ``*args`` will be passed along to the step's
        ``process`` method.

        Note: this method creates a new instance of `Step` with the given
        ``config_file`` if supplied, plus any extra ``*args`` and ``**kwargs``.
        If you create an instance of a Step, set parameters, and then use
        this ``call()`` method, it will ignore previously-set parameters, as
        it creates a new instance of the class with only the ``config_file``,
        ``*args`` and ``**kwargs`` passed to the ``call()`` method.

        If not used with a ``config_file`` or specific ``*args`` and ``**kwargs``,
        it would be better to use the `run` method, which does not create
        a new instance but simply runs the existing instance of the `Step`
        class.


Create a default filename based on the input name


Return first non-None attribute in step hierarchy

        Parameters
        ----------
        attribute : str
            The attribute to retrieve

        default : obj
            If attribute is not found, the value to use

        parent_first : bool
            If `True`, allow parent definition to override step version

        Returns
        -------
        value : obj
            Attribute value or default if not found


Because Step precaching precedes calls to get_reference_file() almost
        immediately, true precaching has been moved to Pipeline where the
        interleaving of precaching and Step processing is more of an
        issue. This null method is intended to be overridden in Pipeline by
        true precache operations and avoids having to override the more complex
        Step.run() instead.


        Saves the given model using the step/pipeline's naming scheme

        Parameters
        ----------
        model : a instance of AbstractDataModel
            The model to save.

        suffix : str
            The suffix to add to the filename.

        idx : object
            Index identifier.

        output_file : str
            Use this file name instead of what the Step
            default would be.

        force : bool
            Regardless of whether ``save_results`` is `False`
            and no ``output_file`` is specified, try saving.

        components : dict
            Other components to add to the file name.

        Returns
        -------
        output_paths : [str[, ...]]
            List of output file paths the model(s) were saved in.


Create the output path

        Parameters
        ----------
        step : Step
            The `Step` in question.

        basepath : str or None
            The basepath to use. If None, `output_file`
            is used. Only the basename component of the path
            is used.

        ext : str or None
            The extension to use. If none, `output_ext` is used.
            Can include the leading period or not.

        suffix : str or None or False
            Suffix to append to the filename.
            If None, the `Step` default will be used.
            If False, no suffix replacement will be done.

        components : dict
            dict of string replacements.

        Returns
        -------
        The fully qualified path name.

        Notes
        -----
        The values found in the `components` dict are placed in the string
        where the "{components}" replacement field is specified separated by
        underscores.


Wrapper around observatory-specific datamodels.open function.


Open a datamodel

        Primarily a wrapper around ``DataModel.open`` to
        handle `Step` peculiarities

        Parameters
        ----------
        init : object
            The object to open

        Returns
        -------
        datamodel : instance of AbstractDataModel
            Object opened as a datamodel


Create an input path for a given file path

        If ``file_path`` has no directory path, use ``self.input_dir``
        as the directory path.

        Parameters
        ----------
        file_path : str or obj
            The supplied file path to check and modify.
            If anything other than `str`, the object
            is simply passed back.

        Returns
        -------
        full_path : str or obj
            File path using ``input_dir`` if the input
            had no directory path.


Set the input directory

        If sufficient information is at hand, set a value
        for the attribute `input_dir`.

        Parameters
        ----------
        input_ : str
            Input to determine path from.

        exclusive : bool
            If True, only set if an input directory is not already
            defined by a parent Step. Otherwise, always set.


        Export this step's parameters to an ASDF config file.

        Parameters
        ----------
        filename : str or pathlib.Path
            Path to config file.

        include_metadata : bool, optional
            Set to True to include metadata that is required
            for submission to CRDS.


Update step parameters

        Only existing parameters are updated. Otherwise, new keys
        found in ``parameters`` are ignored.

        Parameters
        ----------
        parameters : dict
            Parameters to update.

        Notes
        -----
        ``parameters`` is presumed to have been produced by the
        `Step.get_pars` method. As such, the "steps" key is treated
        special in that it is a dict whose keys are the steps assigned
        directly as parameters to the current step. This is standard
        practice for `Pipeline`-based steps.


Build the ConfigObj to initialize a Step

        A Step config is built in the following order:

        - CRDS parameter reference file
        - Local parameter reference file
        - Step keyword arguments

        Parameters
        ----------
        input : str or None
            Input file

        kwargs : dict
            Keyword arguments that specify Step parameters.

        Returns
        -------
        config, config_file : ConfigObj, str
            The configuration and the config filename.


Retrieve either specified or pipeline-supplied suffix

    Parameters
    ----------
    suffix : str or None
        Suffix to use if specified.

    step : Step or None
        The step to retrieve the suffix.

    default_suffix : str
        If the pipeline does not supply a suffix,
        use this.

    Returns
    -------
    suffix : str or None
        Suffix to use


Context manager to preserve step parameters

    Ensure step parameters are not modified during a block
    of operations. Allows local reuse of a Step instance without
    having to worry about side-effects on that Step. If used with
    a `Pipeline`, all substep parameters are also restored.

    Yields
    ------
    saved_pars: dict
        The saved parameters.


Verify that value is a DataModel.


Verify that value is either a string (nominally a reference file path)
    or a DataModel (possibly one with no corresponding file.)


Read the file `config_file` and return the parsed configuration.


    Load the spec file corresponding to the given class.

    Parameters
    ----------
    cls: `Step`-derived or `Step` instance
        A class or instance of a `Step`-based class.

    preserve_comments: bool
        This argument is deprecated and appears to have no
        effect on the returned spec.
        True to keep comments in the resulting `ConfigObj`

    Returns
    -------
    spec_file: ConfigObj
        The resulting configuration object


    Merges a configuration tree into another one.

    Unlike merge in configobj itself, this one updates inline
    comments and does not treat non-dict Mappings as config
    sections.

    Parameters
    ----------
    into : `configobj.Section`
        The configuration tree to merge into

    new : `configobj.Section` or dict
        The source of new configuration values


    Create a ConfigObj from a dict.

    Parameters
    ----------
    d: dict
        The dictionary to merge into the resulting ConfigObj.

    spec: ConfigObj
        The specification to validate against.
        If None, just convert dictionary into a ConfigObj.

    root_dir: str
        The base directory to use for file-based parameters.

    allow_missing: bool
        If a parameter is not defined and has no default in the spec,
        set that parameter to its specification.


    Parse config_file, in INI format, and do validation with the
    provided specfile.

    Parameters
    ----------
    config: ConfigObj
        The configuration to validate.

    spec: ConfigObj
        The specification to validate against.

    section: ConfigObj or None
        The specific section of config to validate.
        If None, then all sections are validated.

    validator: extern.configobj.validator.Validator or None
        The validator to use. If None, the default will be used.

    root_dir: str
        The directory to use as the basis for any file-based parameters.

    allow_missing: bool
        If a parameter is not defined and has no default in the spec,
        set that parameter to its specification.


Do blind type inferring.


Parse scalar strings into scalar python types.


Applies the configuration to the root logger.


Removes the configuration from the root logger.


Context manager that applies the configuration to the root logger


    Loads a logging configuration file.  The format of this file is
    defined in LogConfig.spec.

    Parameters
    ----------
    config_file : str, pathlib.Path instance or readable file-like object

    Returns
    -------
    LogConfig
        The configuration object or None if no valid config is found.


    Generate hook from string, function, Step or Step instance

    Parameters
    ----------
    step : `stpipe.step.Step`
        Parent step instance to which this hook is attached, i.e. "self"
    hooktype : str, "pre" or "post"
        Type of hook pre-hook , or post-hook
    num : int
        The number, in order, of the pre- or post-hook in the list
    command : str or `stpipe.step.Step` instance

    Returns
    -------
    `stpipe.step.Step`


    Given a file path to a config file or Python module path, return a
    Step class and a configuration object.


    Given a configspec, sets up an argparse argument parser that
    understands its arguments.

    The \"path\" in the configspec becomes a dot-separated identifier
    in the commandline arguments.  For example, in the following
    configfile::

        [foo]
          [[bar]]
             baz = 2

    The "baz" variable can be changed with ``--foo.bar.baz=42``.


    Overrides any configuration values in `config` with values from the
    parsed commandline arguments `args`.


    Create a step from a configuration file and return it.  Don't run it.

    Parameters
    ----------
    args : list of str
        Commandline arguments

    cls : Step class
        The step class to use.  If none is provided, the step

    apply_log_cfg : bool
        If True, apply the logging configuration. If False,
        any provided log configuration will be ignored.

    Returns
    -------
    step : Step instance
        If the config file has a `class` parameter, or the commandline
        specifies a class, the return value will be as instance of
        that class.

        Any parameters found in the config file or on the commandline
        will be set as member variables on the returned `Step`
        instance.

    step_class: Step class
        As defined by `cls` parameter or .cfg file.

    positional: list of strings
        Positional parameters after arg parsing

    DOES NOT RUN THE STEP


    Create a step from a configuration file and run it.

    Parameters
    ----------
    args : list of str
        Commandline arguments

    cls : Step class
        The step class to use.  If none is provided, the step

    Returns
    -------
    step : Step instance
        If the config file has a `class` parameter, or the commandline
        specifies a class, the return value will be as instance of
        that class.

        Any parameters found in the config file or on the commandline
        will be set as member variables on the returned `Step`
        instance.


    If the input is a recognized alias, return the
    corresponding fully-qualified class name.  Otherwise
    return the input unmodified.

    Parameters
    ----------
    name : str
        If name contains "::" only the package with
        a name matching the characters before "::"
        will be searched for the matching step.

    Returns
    -------
    str


    Import the Python class `full_name` given in full Python package format,
    e.g.::

        package.another_package.class_name

    Return the imported class. Optionally, if `subclassof` is not None
    and is a Python class, make sure that the imported class is a
    subclass of `subclassof`.


    Import the Python class `full_name` given in full Python package format,
    e.g.::

        package.subpackage.subsubpackage.function_name

    Return the imported function.


    Return the full path of the given Step subclass `step_class`, if
    it exists or None if it does not.


        Convert this config to an AsdfFile, which may be
        used to write the config to a file.

        Parameters
        ----------
        include_metadata : bool, optional
            Set to True to include metadata that is required
            for submission to CRDS.

        Returns
        -------
        asdf.AsdfFile


        Create a StepConfig from an open AsdfFile.

        Parameters
        ----------
        asdf_file : asdf.AsdfFile

        Returns
        -------
        stpipe.config.StepConfig

        Raises
        ------
        asdf.ValidationError
            If the file does not validate against any of the
            recognized schemas.


    Export a step's current parameters to a StepConfig object.

    Parameters
    ----------
    step : stpipe.Step

    Returns
    -------
    stpipe.config.StepConfig


    Validate an ASDF file against the config schema.

    Parameters
    ----------
    asdf_file : asdf.AsdfFile
        Open config file.
    schema_uri : str
        StepConfig schema URI (must be registered with the ASDF entry point).

    Raises
    ------
    asdf.ValidationError


Perform the formatting

        Parameters
        ----------
        format_string : str
            The string to be formatted

        kwargs : dict
            The key/value pairs to insert into the string

        Returns
        -------
        formatted : str
            The formatted string.


        Association dictionary used to create the library.

        Note that changes to the models may cause this information
        to fall "out-of-sync" with the models. For example, borrowing
        and changing a models "group_id" metadata will not change
        the "group_id" entry for the member at the same index in the
        association dictionary returned for this property.

        This is "read-only" to reduce the chances that the
        information in this dictionary will conflict with
        the model metadata.


        A ``set`` of association member "group_id" values

        This property (similar to ``asn``) can fall "out-of-sync"
        with the model metadata. The names returned here will
        only reflect the "group_id" at the time of library creation.


        A ``dict`` with "group_id" as keys. Each value contains
        a ``list`` of indices of members that shared that "group_id".

        Note that this is based on the member entries in the association
        used to create the ModelLibrary. Updating the "group_id" of a model
        in the library will NOT change the values returned by this property
        (and will not change the association data available at ``asn``).


        "borrow" a model from the library.

        Every model "borrowed" from the library must be returned before
        the library is closed (see the exceptions described below).

        For an "on_disk" library a calling this function will cause
        the corresponding model to be loaded from disk.

        Parameters
        ----------
        index : int
            The index of the model within the library. As the library
            size does not change this is unique to this model for this
            library.

        Returns
        -------
        model : DataModel

        Raises
        ------
        `ClosedLibraryError`
            If the library is not "open" (used in a ``with`` context).

        `BorrowError`
            If the model at this index is already "borrowed".


        Determine the temporary path to use to save a model
        at the provided index in the library.


        "shelve" a model, returning it to the library.

        All borrowed models must be "shelved" before the library is
        closed (see notes about exceptions below).

        For an "on_disk" model shelving a model may cause
        a temporary file to be written (see "modify" below).

        Parameters
        ----------
        model : DataModel
            DataModel to return to the library at the provided index.

        index : int, optional
            The index within the library where the model will be stored.
            If the same model (checked by ``id(model)``) was previously
            borrowed and the index is not provided, the borrowed index
            will be used. If providing a new DataModel (one not borrowed
            from the library) the index must be provided, and the new
            model replaces the prior model at that index.

        modify : bool, optional, default=True
            For an "on_disk" library, temporary files will only be written
            when modify is True. For a library that is not "on_disk"
            this option has no effect and any modifications made to the model
            while it was borrowed will persist.

        Raises
        ------
        `ClosedLibraryError`
            If the library is not "open" (used in a ``with`` context).

        `BorrowError`
            If an unknown model is provided (without an index) or
            if the model at the provided index has not been "borrowed"


        Assign association member information to an opened model.

        This will be called:

            - when a model is loaded (for the first time) in ``_load_member``
            - when the library is created (if the library was provided a
              list of open models)

        This will assign the following metadata attributes (setting
        for example ``model.meta.group_id`` to the value of
        ``member["group_id"]``):

            - group_id
            - exptype
            - tweakreg_catalog

        and (when available from the association) assign the following
        metadata attributes based on the association information:

            - set ``meta.asn.table_name`` to ``asn["table_name"]``
            - set ``meta.asn.pool_name`` to ``asn["pool_name"]``

        Parameters
        ----------
        model : DataModel
            Model to be updated (in place).

        member : dict
            Dictionary containing contents of the "member" entry
            (include "exptype", "expname", "group_id", etc...)


        Load a model for the association member at the provided index.

        This will be called when the model at the provided index:
            - is not already loaded
            - does not have a temporary file

        Parameters
        ----------
        index : int

        Returns
        -------
        model : DataModel


        .. warning:: This save is NOT used by Step/Pipeline. This is
                     intentional as the Step/Pipeline has special requirements.

        For now this is a very basic "save". It does not:

            - check that the library contains no duplicate filenames
            - propagate asn_pool and other non-member asn information

        It will save:
            - models with filenames determined by ``_model_to_filename``
            - a very simple association that contains only 1 product that
              lists ``expname`` ``exptype`` and ``group_id``  for each model
              in a file named "asn.json".

        Parameters
        ----------
        path : Path or str
            Directory in which to store the models and generated
            association for this library.

        Returns
        -------
        association_path : Path
            The path to the saved association file.


        Called from `stpipe.Step.run` after `stpipe.Step.process` has
        completed. This method will call `stpipe.Step.finalize_result`
        for each model in the library.

        Parameters
        ----------
        step : Step
            The step calling this method.

        reference_files_used : list
            List of reference files used during the execution of this
            step.