Exemplo n.º 1
0
def warn(message, category="default", status={}):
    """Trigger a warning, an error or just ignore based on the value defined in
    the :py:attr:`~radis.lbl.loader.DatabankLoader.warnings` dictionary.

    The warnings can thus be deactivated selectively by setting the SpectrumFactory
    :attr:`~radis.lbl.loader.DatabankLoader.warnings` attribute. All warnings
    can be disabled by setting it to ``False``.

    Parameters
    ----------
    message: str
        what to print
    category: str
        one of the keys of self.warnings.
    status: dict
        status for all warning categories. Can be one of ``'warn'``, ``'ignore'``,
        ``'print'``, ``'error'``

    Examples
    --------
    ::

        if not ((df.Erotu > tol).all() and (df.Erotl > tol).all()):
            warn(
                "There are negative rotational energies in the database",
                "NegativeEnergiesWarning",
            )

    """
    # TODO (refactor): make it possible to run warn(NegativeEnergiesWarning("message"))
    # instead of warn("message, "NegativeEnergiesWarning")
    # ex :
    # if isinstance(message, Warning):
    #     etc.

    if status == False:
        return

    action = status[category]

    WarningType = WarningClasses[category]

    if action in "warn":
        warnings.warn(WarningType(message))
    elif action == "once":
        warnings.warn(WarningType(message))
        # keep 'once' but ignore WarningType with simplefilters
        warnings.simplefilter("ignore", WarningType)
    elif action == "ignore":
        pass
    elif action == "print":  # just print the message, in red
        printr(message)
    elif action == "error":
        raise WarningType(message)
    else:
        raise ValueError("Unexpected action for warning: {0}".format(action))
Exemplo n.º 2
0
def warn(message, category="default", status={}):
    """Trigger a warning, an error or just ignore based on the value defined
    in the :py:attr:`~radis.lbl.loader.DatabankLoader.warnings` dictionary

    The warnings can thus be deactivated selectively by setting the SpectrumFactory
    :attr:`~radis.lbl.loader.DatabankLoader.warnings` attribute. All warnings
    can be disabled by setting it to ``False``.

    Parameters
    ----------

    message: str
        what to print

    category: str
        one of the keys of self.warnings.

    status: dict
        status for all warning categories. Can be one of ``'warn'``, ``'ignore'``,
        ``'print'``, ``'error'``

    """

    if status == False:
        return

    action = status[category]

    WarningType = WarningClasses[category]

    if action in "warn":
        warnings.warn(WarningType(message))
    elif action == "once":
        warnings.warn(WarningType(message))
        # keep 'once' but ignore WarningType with simplefilters
        warnings.simplefilter("ignore", WarningType)
    elif action == "ignore":
        pass
    elif action == "print":  # just print the message, in red
        printr(message)
    elif action == "error":
        raise WarningType(message)
    else:
        raise ValueError("Unexpected action for warning: {0}".format(action))
Exemplo n.º 3
0
def warn(message, category='default', status={}):
    ''' Trigger a warning, an error or just ignore based on the value defined
    in the :py:attr:`~radis.lbl.loader.DatabankLoader.warnings` dictionary

    The warnings can thus be deactivated selectively by setting the SpectrumFactory
     :attr:`~radis.lbl.loader.DatabankLoader.warnings` attribute

    Parameters
    ----------

    message: str
        what to print

    category: str
        one of the keys of self.warnings

    status: dict
        status for all warning categories. Can be one of ``'warn'``, ``'ignore'``,
        ``'print'``, ``'error'``

    '''

    action = status[category]

    WarningType = WarningClasses[category]

    if action == 'warn':
        warnings.warn(WarningType(message))
    elif action == 'once':
        warnings.warn(WarningType(message))
        # keep 'once' but ignore WarningType with simplefilters
        warnings.simplefilter('ignore', WarningType)
    elif action == 'ignore':
        pass
    elif action == 'print':  # just print the message, in red
        printr(message)
    elif action == 'error':
        raise WarningType(message)
    else:
        raise ValueError('Unexpected action for warning: {0}'.format(action))
Exemplo n.º 4
0
def IgnoreMissingDatabase(err, file='', warnings=True):
    ''' A function to deal with MissingDatabases errors. If :data:`~radis.test.utils.IGNORE_MISSING_DATABASES`
    is ``True``, just print a warning. Else, raise the error
    
    Parameters
    ----------
    
    err: an Error
    
    file: str
        where the error occured. Use ``file=__file__`` on function call
    '''
    # TODO: make IGNORE_MISSING_DATABASES a ~/.radis parameter
    if IGNORE_MISSING_DATABASES:
        if warnings:
            import sys
            print(sys.exc_info())
            printr('In {0}: Database not defined: {1}'.format(
                file, err.filename) + '\n Ignoring the test')
        return True
    else:
        raise err
Exemplo n.º 5
0
def load_h5_cache_file(
    cachefile,
    use_cached,
    metadata,
    current_version,
    last_compatible_version=OLDEST_COMPATIBLE_VERSION,
    verbose=True,
):
    """Function to load a h5 cache file

    Parameters
    ----------

    cachefile: str
        cache file path

    use_cached: str
        use cache file if value is not ``False``:

        - if ``True``, use (and generate if doesnt exist) cache file.
        - if ``'regen'``, delete cache file (if exists) so it is regenerated
        - if ``'force'``, use cache file and raises an error if it doesnt exist

        if using the cache file, check if the file is deprecated. If it
        is deprecated, regenerate the file unless ``'force'`` was used
        (in that case, raise an error)

    metadata: dict
        values are compared to cache file attributes. If they dont match,
        the file is considered deprecated. See ``use_cached`` to know
        how to handle deprecated files

    current_version: str
        version is compared to cache file version (part of attributes).
        If current version is superior, a simple warning is triggered.

    last_compatible_version: str
        if file version is inferior to this, file is considered deprecated.
        See ``use_cached`` to know how to handle deprecated files.
        Default :data:`~radis.OLDEST_COMPATIBLE_VERSION`.

    Returns
    -------

    df: pandas DataFrame, or None
        None if no cache file was found, or if it was deleted


    See Also
    --------

    :data:`~radis.OLDEST_COMPATIBLE_VERSION`

    """

    # 1. know if we have to load the file
    if not use_cached:
        return None
    elif use_cached == "regen" and exists(cachefile):
        os.remove(cachefile)
        if verbose:
            printm("Deleted h5 cache file : {0}".format(cachefile))
        return None

    # 2. check the file is here
    if not exists(cachefile):
        if use_cached == "force":
            raise ValueError("Cache file {0} doesnt exist".format(cachefile))
        else:
            return None  # File doesn't exist. It's okay.

    # 3. read file attributes to know if it's deprecated
    try:
        check_not_deprecated(
            cachefile,
            metadata,
            current_version=current_version,
            last_compatible_version=last_compatible_version,
        )
    # ... if deprecated, raise an error only if 'force'
    except DeprecatedFileError as err:
        if use_cached == "force":
            raise err
        else:
            if verbose:
                printr("File {0} deprecated:\n{1}\nDeleting it!".format(
                    cachefile, str(err)))
            os.remove(cachefile)
            return None
    # 4. File is not not deprecated: read the content.
    else:
        df = None
        if verbose >= 2:
            printm("Reading cache file ({0})".format(cachefile))
        try:
            df = pd.read_hdf(cachefile, "df")
        except KeyError as err:  # An error happened during file reading.
            # Fail safe by deleting cache file (unless we explicitely wanted it
            # with 'force')
            if use_cached == "force":
                raise
            else:
                if verbose:
                    printr("An error happened during cache file reading " +
                           "{0}:\n{1}\n".format(cachefile, str(err)) +
                           "Deleting cache file to regenerate it")
                os.remove(cachefile)
                df = None

    return df
Exemplo n.º 6
0
def check_cache_file(fcache, use_cached=True, metadata={}, verbose=True):
    """Quick function that check status of cache file generated by RADIS:

    Parameters
    ----------

    fcache: str
        cache file name

    use_cached: ``True``, ``False``, ``'force'``, ``'regen'``
        see notes below. Default ``True``.

    metadata: dict
        attributes to check

    verbose: boolean
        print stuff

    Notes
    -----

    The function first checks the existence of ``fcache``. What is does depends
    on the value of ``use_cached``:

    - if ``True``, check it exists.
    - if ``'regen'``, delete cache file to regenerate it later.
    - if ``'force'``, raise an error if file doesnt exist.

    Then look if it is deprecated (we just look at the attributes, the file
    is never fully read). Deprecation is done by :py:func:`~radis.misc.cache_files.check_not_deprecated`
    comparing the ``metadata=`` content.

    - if deprecated, deletes it to regenerate later unless 'force' was used

    See Also
    --------

    :py:func:`~radis.misc.cache_files.check_not_deprecated`
    """

    # Test existence of file:
    if not use_cached:
        return  # we dont want a cache file, no need to test it
    elif use_cached == "regen":
        if exists(fcache):
            os.remove(fcache)
            if verbose:
                print(("Deleted h5 cache file : {0}".format(fcache)))
    elif use_cached == "force":
        if not exists(fcache):
            raise ValueError("Cache file {0} doesnt exist".format(fcache))
    else:  # use_cached == True
        pass  # just use the file as is

    # If file is still here, test if it is deprecated:
    # (we just read the attributes, the file is never fully read)
    if exists(fcache):
        if verbose:
            print(("Using cache file: {0}".format(fcache)))
        try:
            check_not_deprecated(
                fcache,
                metadata=metadata,
                current_version=radis.__version__,
                last_compatible_version=OLDEST_COMPATIBLE_VERSION,
            )
        except DeprecatedFileError as err:
            if use_cached == "force":
                raise
            else:  # delete file to regenerate it in the end of the script
                if verbose:
                    printr("File {0} deprecated:\n{1}\nDeleting it!".format(
                        fcache, str(err)))
                os.remove(fcache)

    return
Exemplo n.º 7
0
def fetch_astroquery(molecule,
                     isotope,
                     wmin,
                     wmax,
                     verbose=True,
                     cache=True,
                     metadata={}):
    ''' Wrapper to Astroquery [1]_ fetch function to download a line database 

    Notes
    -----

    Astroquery [1]_ is itself based on [HAPI]_

    Parameters
    ----------

    molecule: str, or int
        molecule name or identifier

    isotope: int
        isotope number 

    wmin, wmax: float  (cm-1)
        wavenumber min and max 
    
    Other Parameters
    ----------------

    verbose: boolean
        Default ``True``

    cache: boolean
        if ``True``, tries to find a ``.h5`` cache file in the Astroquery 
        :py:attr:`~astroquery.query.BaseQuery.cache_location`, that would match 
        the requirements. If not found, downloads it and saves the line dataframe 
        as a ``.h5`` file in the Astroquery.

    metadata: dict
        if ``cache=True``, check that the metadata in the cache file correspond
        to these attributes. Arguments ``molecule``, ``isotope``, ``wmin``, ``wmax``
        are already added by default. 

    References
    ----------

    .. [1] `Astroquery <https://astroquery.readthedocs.io>`_ 
    
    See Also
    --------
    
    :py:func:`astroquery.hitran.reader.download_hitran`, 
    :py:func:`astroquery.hitran.reader.read_hitran_file`, 
    :py:attr:`~astroquery.query.BaseQuery.cache_location`

    '''

    # Check input
    if not is_float(molecule):
        mol_id = get_molecule_identifier(molecule)
    else:
        mol_id = molecule
        molecule = get_molecule(mol_id)
    assert is_float(isotope)

    empty_range = False

    # If cache, tries to find from Astroquery:
    if cache:
        # Update metadata with physical properties from the database.
        metadata.update({
            'molecule': molecule,
            'isotope': isotope,
            'wmin': wmin,
            'wmax': wmax
        })

        fcache = join(
            Hitran.cache_location,
            CACHE_FILE_NAME.format(
                **{
                    'molecule': molecule,
                    'isotope': isotope,
                    'wmin': wmin,
                    'wmax': wmax
                }))
        check_cache_file(fcache=fcache,
                         use_cached=cache,
                         metadata=metadata,
                         verbose=verbose)
        if exists(fcache):
            try:
                return get_cache_file(fcache, verbose=verbose)
            except Exception as err:
                if verbose:
                    printr(
                        'Problem reading cache file {0}:\n{1}\nDeleting it!'.
                        format(fcache, str(err)))
                os.remove(fcache)


#    tbl = Hitran.query_lines_async(molecule_number=mol_id,
#                                     isotopologue_number=isotope,
#                                     min_frequency=wmin / u.cm,
#                                     max_frequency=wmax / u.cm)

#    # Download using the astroquery library
    try:
        response = Hitran.query_lines_async(molecule_number=mol_id,
                                            isotopologue_number=isotope,
                                            min_frequency=wmin / u.cm,
                                            max_frequency=wmax / u.cm)
    except KeyError as err:
        raise KeyError(str(err)+' <<w this error occured in Astroquery. Maybe these molecule '+\
                       '({0}) and isotope ({1}) are not supported'.format(molecule, isotope)) from err

    # Deal with usual errors
    if response.status_code == 404:
        # Maybe there are just no lines for this species in this range
        # In that case we usually end up with errors like:

        # (<class 'Exception'>, Exception('Query failed: 404 Client Error:
        # Not Found for url: http://hitran.org/lbl/api?numax=25000&numin=19000&iso_ids_list=69\n',),
        # <traceback object at 0x7f0967c91708>)

        if response.reason == 'Not Found':
            # Let's bet it's just that there are no lines in this range
            empty_range = True
            if verbose:
                print((
                    'No lines for {0} (id={1}), iso={2} in range {3:.2f}-{4:.2f}cm-1. '
                    .format(molecule, mol_id, isotope, wmin, wmax)))
        else:
            raise ValueError(
                'An error occured during the download of HITRAN files ' +
                'for {0} (id={1}), iso={2} between {3:.2f}-{4:.2f}cm-1. '.
                format(molecule, mol_id, isotope, wmin, wmax) +
                'Are you online?\n' +
                'See details of the error below:\n\n {0}'.format(
                    response.reason))
    elif response.status_code == 500:

        raise ValueError('{0} while querying the HITRAN server: '.format(response.status_code)+\
                         '\n\n{0}'.format(response.text))

    # Process response

    # Rename columns from Astroquery to RADIS format
    rename_columns = {
        'molec_id': 'id',
        'local_iso_id': 'iso',
        'nu': 'wav',
        'sw': 'int',
        'a': 'A',
        'gamma_air': 'airbrd',
        'gamma_self': 'selbrd',
        'elower': 'El',
        'n_air': 'Tdpair',
        'delta_air': 'Pshft',
        'global_upper_quanta': 'globu',
        'global_lower_quanta': 'globl',
        'local_upper_quanta': 'locu',
        'local_lower_quanta': 'locl',
        'line_mixing_flag': 'lmix',
        'gp': 'gp',
        'gpp': 'gpp',
    }

    if not empty_range:
        #        _fix_astroquery_file_format(filename)
        # Note: as of 0.9.16 we're not fixing astroquery_file_format anymore.
        # maybe we should.
        tbl = Hitran._parse_result(response)
        df = tbl.to_pandas()
        df = df.rename(columns=rename_columns)
    else:
        df = pd.DataFrame(columns=list(rename_columns.values()))

    # Cast type to float64
    cast_type = {
        'wav': np.float64,
        'int': np.float64,
        'A': np.float64,
        'airbrd': np.float64,
        'selbrd': np.float64,
        'El': np.float64,
        'Tdpair': np.float64,
        'Pshft': np.float64,
    }
    for c, typ in cast_type.items():
        df[c] = df[c].astype(typ)

    # cached file mode but cached file doesn't exist yet (else we had returned)
    if cache:
        if verbose:
            print('Generating cached file: {0}'.format(fcache))
        try:
            save_to_hdf(df,
                        fcache,
                        metadata=metadata,
                        version=radis.__version__,
                        key='df',
                        overwrite=True,
                        verbose=verbose)
        except:
            if verbose:
                print(sys.exc_info())
                print(
                    'An error occured in cache file generation. Lookup access rights'
                )
            pass

    return df
Exemplo n.º 8
0
def fetch_astroquery(
    molecule, isotope, wmin, wmax, verbose=True, cache=True, expected_metadata={}
):
    """Download a HITRAN line database to a Pandas DataFrame.

    Wrapper to Astroquery [1]_ fetch function

    Parameters
    ----------
    molecule: str, or int
        molecule name or identifier
    isotope: int
        isotope number
    wmin, wmax: float  (cm-1)
        wavenumber min and max

    Other Parameters
    ----------------
    verbose: boolean
        Default ``True``
    cache: boolean or ``'regen'``
        if ``True``, tries to find a ``.h5`` cache file in the Astroquery
        :py:attr:`~astroquery.query.BaseQuery.cache_location`, that would match
        the requirements. If not found, downloads it and saves the line dataframe
        as a ``.h5`` file in the Astroquery.
        If ``'regen'``, delete existing cache file to regerenate it.
    expected_metadata: dict
        if ``cache=True``, check that the metadata in the cache file correspond
        to these attributes. Arguments ``molecule``, ``isotope``, ``wmin``, ``wmax``
        are already added by default.

    Notes
    -----
    The HITRAN module in Astroquery [1]_ is itself based on [HAPI]_

    References
    ----------
    .. [1] `Astroquery <https://astroquery.readthedocs.io>`_

    See Also
    --------
    :py:func:`astroquery.hitran.reader.download_hitran`,
    :py:func:`astroquery.hitran.reader.read_hitran_file`,
    :py:attr:`~astroquery.query.BaseQuery.cache_location`

    """
    # Check input
    if not is_float(molecule):
        mol_id = get_molecule_identifier(molecule)
    else:
        mol_id = molecule
        molecule = get_molecule(mol_id)
    assert is_float(isotope)

    empty_range = False

    if cache:
        # Cache file location in Astroquery cache
        # TODO: move full HITRAN databases in ~/radisdb cache like io/hitemp/fetch_hitemp ?
        fcache = join(
            Hitran.cache_location,
            CACHE_FILE_NAME.format(
                **{"molecule": molecule, "isotope": isotope, "wmin": wmin, "wmax": wmax}
            ),
        )
        # ... Update metadata with physical properties from the database.
        expected_metadata.update(
            {"molecule": molecule, "isotope": isotope, "wmin": wmin, "wmax": wmax}
        )
        if cache == "regen":
            if exists(fcache):
                if verbose:
                    print(f"Cache file {fcache} deleted to be regenerated")
                os.remove(fcache)
        else:
            # Load cache file if valid
            check_cache_file(
                fcache=fcache,
                use_cached=cache,
                expected_metadata=expected_metadata,
                verbose=verbose,
            )
            if exists(fcache):
                try:
                    return get_cache_file(fcache, verbose=verbose)
                except Exception as err:
                    if verbose:
                        printr(
                            "Problem reading cache file {0}:\n{1}\nDeleting it!".format(
                                fcache, str(err)
                            )
                        )
                    os.remove(fcache)

    # Download using the astroquery library
    try:
        response = Hitran.query_lines_async(
            molecule_number=mol_id,
            isotopologue_number=isotope,
            min_frequency=wmin / u.cm,
            max_frequency=wmax / u.cm,
        )
    except KeyError as err:
        raise KeyError(
            str(err)
            + " <<w this error occured in Astroquery. Maybe these molecule "
            + "({0}) and isotope ({1}) are not supported".format(molecule, isotope)
        ) from err

    # Deal with usual errors
    if response.status_code == 404:
        # Maybe there are just no lines for this species in this range
        # In that case we usually end up with errors like:

        # (<class 'Exception'>, Exception('Query failed: 404 Client Error:
        # Not Found for url: http://hitran.org/lbl/api?numax=25000&numin=19000&iso_ids_list=69\n',),
        # <traceback object at 0x7f0967c91708>)

        if response.reason == "Not Found":
            # Let's bet it's just that there are no lines in this range
            empty_range = True
            if verbose:
                print(
                    (
                        "No lines for {0} (id={1}), iso={2} in range {3:.2f}-{4:.2f}cm-1. ".format(
                            molecule, mol_id, isotope, wmin, wmax
                        )
                    )
                )
        else:
            raise ValueError(
                "An error occured during the download of HITRAN files "
                + "for {0} (id={1}), iso={2} between {3:.2f}-{4:.2f}cm-1. ".format(
                    molecule, mol_id, isotope, wmin, wmax
                )
                + "Are you online?\n"
                + "See details of the error below:\n\n {0}".format(response.reason)
            )
    elif response.status_code == 500:

        raise ValueError(
            "{0} while querying the HITRAN server: ".format(response.status_code)
            + "\n\n{0}".format(response.text)
        )

    # Process response

    # Rename columns from Astroquery to RADIS format
    rename_columns = {
        "molec_id": "id",
        "local_iso_id": "iso",
        "nu": "wav",
        "sw": "int",
        "a": "A",
        "gamma_air": "airbrd",
        "gamma_self": "selbrd",
        "elower": "El",
        "n_air": "Tdpair",
        "delta_air": "Pshft",
        "global_upper_quanta": "globu",
        "global_lower_quanta": "globl",
        "local_upper_quanta": "locu",
        "local_lower_quanta": "locl",
        "line_mixing_flag": "lmix",
        "gp": "gp",
        "gpp": "gpp",
    }

    if not empty_range:
        tbl = Hitran._parse_result(response)
        df = tbl.to_pandas()
        df = df.rename(columns=rename_columns)
    else:
        df = pd.DataFrame(columns=list(rename_columns.values()))

    # Cast type to float64
    cast_type = {
        "wav": np.float64,
        "int": np.float64,
        "A": np.float64,
        "airbrd": np.float64,
        "selbrd": np.float64,
        "El": np.float64,
        "Tdpair": np.float64,
        "Pshft": np.float64,
    }
    for c, typ in cast_type.items():
        df[c] = df[c].astype(typ)

    # cached file mode but cached file doesn't exist yet (else we had returned)
    if cache:
        new_metadata = {
            "molecule": molecule,
            "isotope": isotope,
            "wmin": wmin,
            "wmax": wmax,
        }
        if verbose:
            print(
                "Generating cache file {0} with metadata :\n{1}".format(
                    fcache, new_metadata
                )
            )
        try:
            save_to_hdf(
                df,
                fcache,
                metadata=new_metadata,
                version=radis.__version__,
                key="df",
                overwrite=True,
                verbose=verbose,
            )
        except PermissionError:
            if verbose:
                print(sys.exc_info())
                print("An error occured in cache file generation. Lookup access rights")
            pass

    return df
Exemplo n.º 9
0
def check_cache_file(use_cached, fcache, metadata={}, verbose=True):
    ''' Quick function that check status of cache file generated by RADIS:

    First test its existence: function of the value of ``use_cached``:

    - if True, ok
    - if 'regen', delete cache file to regenerate it later. 
    - if 'force', raise an error if file doesnt exist. 

    Then look if it is deprecated (we just look at the attributes, the file 
    is never fully read)

    - if deprecated, delete it to regenerate later unless 'force' was used
    
    Parameters
    ----------
    
    use_cached: True, False, 'force', 'regen'
        see description above
        
    fcache: str
        cache file name
        
    metadata: dict
        attributes to check
        
    verbose: boolean
        print stuff
    
    
    '''

    # Test existence of file:
    if not use_cached:
        return  # we dont want a cache file, no need to test it
    elif use_cached == 'regen':
        if exists(fcache):
            os.remove(fcache)
            if verbose:
                print(('Deleted h5 cache file : {0}'.format(fcache)))
    elif use_cached == 'force':
        if not exists(fcache):
            raise ValueError('Cache file {0} doesnt exist'.format(fcache))
    else:  # use_cached == True
        pass  # just use the file as is

    # If file is still here, test if it is deprecated:
    # (we just read the attributes, the file is never fully read)
    if exists(fcache):
        if verbose:
            print(('Using cache file: {0}'.format(fcache)))
        try:
            check_not_deprecated(
                fcache,
                metadata=metadata,
                current_version=radis.__version__,
                last_compatible_version=OLDEST_COMPATIBLE_VERSION)
        except DeprecatedFileError as err:
            if use_cached == 'force':
                raise
            else:  # delete file to regenerate it in the end of the script
                if verbose:
                    printr('File {0} deprecated:\n{1}\nDeleting it!'.format(
                        fcache, str(err)))
                os.remove(fcache)

    return
Exemplo n.º 10
0
def load_h5_cache_file(
    cachefile,
    use_cached,
    valid_if_metadata_is={},
    relevant_if_metadata_above={},
    relevant_if_metadata_below={},
    current_version="",
    last_compatible_version=OLDEST_COMPATIBLE_VERSION,
    verbose=True,
):
    """Function to load a h5 cache file.

    Parameters
    ----------
    cachefile: str
        cache file path
    use_cached: str
        use cache file if value is not ``False``:

        - if ``True``, use (and generate if doesnt exist) cache file.
        - if ``'regen'``, delete cache file (if exists) so it is regenerated
        - if ``'force'``, use cache file and raises an error if it doesnt exist

        if using the cache file, check if the file is deprecated. If it
        is deprecated, regenerate the file unless ``'force'`` was used
        (in that case, raise an error)
    valid_if_metadata_is: dict
        values are compared to cache file attributes. If they dont match,
        the file is considered deprecated. See ``use_cached`` to know
        how to handle deprecated files

        .. note::
            if the file has extra attributes they are not compared
    current_version: str
        version is compared to cache file version (part of attributes).
        If current version is superior, a simple warning is triggered.
    last_compatible_version: str
        if file version is inferior to this, file is considered deprecated.
        See ``use_cached`` to know how to handle deprecated files.
        Default :data:`~radis.OLDEST_COMPATIBLE_VERSION`.
    relevant_if_metadata_above, relevant_if_metadata_below : dict
        values are compared to cache file attributes. If they don't match,
        the function returns a :py:class:`~radis.misc.warning.IrrelevantFileWarning`.
        For instance, load a line database file, only if it contains wavenumbers
        between 2300 and 2500 cm-1 ::

                load_h5_cache_file(..., relevant_if_metadata_above={'wav':2300};
                relevant_if_metadata_below={'wav':2500})

        Note that in such an example, the file data is not read. Only the
        file metadata is. If the metadata does not contain the key (e.g.: ``'wav'``)
        a :py:class:`~radis.misc.warning.DeprecatedFileWarning` is raised.

    Returns
    -------
    df: pandas DataFrame, or None
        None if no cache file was found, or if it was deleted


    See Also
    --------

    :data:`~radis.OLDEST_COMPATIBLE_VERSION`
    """

    # 1. know if we have to load the file
    if not use_cached:
        return None
    elif use_cached == "regen" and exists(cachefile):
        os.remove(cachefile)
        if verbose:
            printm("Deleted h5 cache file : {0}".format(cachefile))
        return None

    # 2. check the file is here
    if not exists(cachefile):
        if use_cached == "force":
            raise ValueError("Cache file {0} doesnt exist".format(cachefile))
        else:
            return None  # File doesn't exist. It's okay.

    # 3. read file attributes to know if it's deprecated
    try:
        check_not_deprecated(
            cachefile,
            metadata_is=valid_if_metadata_is,
            metadata_keys_contain=list(relevant_if_metadata_above.keys()) +
            list(relevant_if_metadata_below.keys()),
            current_version=current_version,
            last_compatible_version=last_compatible_version,
        )
    # ... if deprecated, raise an error only if 'force'
    except DeprecatedFileWarning as err:
        if use_cached == "force":
            raise err
        else:
            if verbose:
                printr("File {0} deprecated:\n{1}\nDeleting it!".format(
                    cachefile, str(err)))
            os.remove(cachefile)
            return None

    # 4. File is not not deprecated: read the the extremum wavenumbers.    raise
    if relevant_if_metadata_above is not None or relevant_if_metadata_below is not None:
        try:
            check_relevancy(
                cachefile,
                relevant_if_metadata_above,
                relevant_if_metadata_below,
            )
        # ... if irrelevant, raise an error only if 'force'
        except IrrelevantFileWarning as err:
            if verbose >= 2:
                from radis.misc.printer import printg

                printg("Database file {0} irrelevant and not loaded".format(
                    cachefile))
            raise err

    # 5. File is relevant: read the content.
    df = None
    if verbose >= 2:
        printm("Reading cache file ({0})".format(cachefile))
    try:
        df = pd.read_hdf(cachefile, "df")
    except KeyError as err:  # An error happened during file reading.
        # Fail safe by deleting cache file (unless we explicitely wanted it
        # with 'force')
        if use_cached == "force":
            raise
        else:
            if verbose:
                printr("An error happened during cache file reading " +
                       "{0}:\n{1}\n".format(cachefile, str(err)) +
                       "Deleting cache file to regenerate it")
            os.remove(cachefile)
            df = None

    return df