Download data from ECMWF MACC Reanalysis API.

    Parameters
    ----------
    filename : str
        full path of file where to save data, ``.nc`` appended if not given
    params : str or sequence of str
        keynames of parameter[s] to download
    startdate : datetime.datetime or datetime.date
        UTC date
    stopdate : datetime.datetime or datetime.date
        UTC date
    lookup_params : bool, default True
        optional flag, if ``False``, then codes are already formatted
    server : ecmwfapi.api.ECMWFDataServer
        optionally provide a server object, default is ``None``
    target : callable
        optional function that calls ``server.retrieve`` to pass to thread

    Returns
    -------
    t : thread
        a thread object, use it to check status by calling `t.is_alive()`

    Notes
    -----
    To download data from ECMWF requires the API client and a registration
    key. Please read the documentation in `Access ECMWF Public Datasets
    <https://confluence.ecmwf.int/display/WEBAPI/Access+ECMWF+Public+Datasets>`_.
    Follow the instructions in step 4 and save the ECMWF registration key
    as `$HOME\.ecmwfapirc` or set `ECMWF_API_KEY` as the path to the key.

    This function returns a daemon thread that runs in the background. Exiting
    Python will kill this thread, however this thread will not block the main
    thread or other threads. This thread will terminate when the file is
    downloaded or if the thread raises an unhandled exception. You may submit
    multiple requests simultaneously to break up large downloads. You can also
    check the status and retrieve downloads online at
    http://apps.ecmwf.int/webmars/joblist/. This is useful if you kill the
    thread. Downloads expire after 24 hours.

    .. warning:: Your request may be queued online for an hour or more before
        it begins to download

    Precipitable water :math:`P_{wat}` is equivalent to the total column of
    water vapor (TCWV), but the units given by ECMWF MACC Reanalysis are kg/m^2
    at STP (1-atm, 25-C). Divide by ten to convert to centimeters of
    precipitable water:

    .. math::
        P_{wat} \\left( \\text{cm} \\right) \
        = TCWV \\left( \\frac{\\text{kg}}{\\text{m}^2} \\right) \
        \\frac{100 \\frac{\\text{cm}}{\\text{m}}} \
        {1000 \\frac{\\text{kg}}{\\text{m}^3}}

    The keynames available for the ``params`` argument are given by
    :const:`pvlib.iotools.ecmwf_macc.PARAMS` which maps the keys to codes used
    in the API. The following keynames are available:

    =======  =========================================
    keyname  description
    =======  =========================================
    tcwv     total column water vapor in kg/m^2 at STP
    aod550   aerosol optical depth measured at 550-nm
    aod469   aerosol optical depth measured at 469-nm
    aod670   aerosol optical depth measured at 670-nm
    aod865   aerosol optical depth measured at 865-nm
    aod1240  aerosol optical depth measured at 1240-nm
    =======  =========================================

    If ``lookup_params`` is ``False`` then ``params`` must contain the codes
    preformatted according to the ECMWF MACC Reanalysis API. This is useful if
    you want to retrieve codes that are not mapped in
    :const:`pvlib.iotools.ecmwf_macc.PARAMS`.

    Specify a custom ``target`` function to modify how the ECMWF API function
    ``server.retrieve`` is called. The ``target`` function must have the
    following signature in which the parameter definitions are similar to
    :func:`pvlib.iotools.get_ecmwf_macc`. ::


        target(server, startdate, stopdate, params, filename) -> None

    Examples
    --------
    Retrieve the AOD measured at 550-nm and the total column of water vapor for
    November 1, 2012.

    >>> from datetime import date
    >>> from pvlib.iotools import get_ecmwf_macc
    >>> filename = 'aod_tcwv_20121101.nc'  # .nc extension added if missing
    >>> params = ('aod550', 'tcwv')
    >>> start = end = date(2012, 11, 1)
    >>> t = get_ecmwf_macc(filename, params, start, end)
    >>> t.is_alive()
    True

def get_ecmwf_macc(filename, params, startdate, stopdate, lookup_params=True,
                   server=None, target=_ecmwf):
    """
    Download data from ECMWF MACC Reanalysis API.

    Parameters
    ----------
    filename : str
        full path of file where to save data, ``.nc`` appended if not given
    params : str or sequence of str
        keynames of parameter[s] to download
    startdate : datetime.datetime or datetime.date
        UTC date
    stopdate : datetime.datetime or datetime.date
        UTC date
    lookup_params : bool, default True
        optional flag, if ``False``, then codes are already formatted
    server : ecmwfapi.api.ECMWFDataServer
        optionally provide a server object, default is ``None``
    target : callable
        optional function that calls ``server.retrieve`` to pass to thread

    Returns
    -------
    t : thread
        a thread object, use it to check status by calling `t.is_alive()`

    Notes
    -----
    To download data from ECMWF requires the API client and a registration
    key. Please read the documentation in `Access ECMWF Public Datasets
    <https://confluence.ecmwf.int/display/WEBAPI/Access+ECMWF+Public+Datasets>`_.
    Follow the instructions in step 4 and save the ECMWF registration key
    as `$HOME\.ecmwfapirc` or set `ECMWF_API_KEY` as the path to the key.

    This function returns a daemon thread that runs in the background. Exiting
    Python will kill this thread, however this thread will not block the main
    thread or other threads. This thread will terminate when the file is
    downloaded or if the thread raises an unhandled exception. You may submit
    multiple requests simultaneously to break up large downloads. You can also
    check the status and retrieve downloads online at
    http://apps.ecmwf.int/webmars/joblist/. This is useful if you kill the
    thread. Downloads expire after 24 hours.

    .. warning:: Your request may be queued online for an hour or more before
        it begins to download

    Precipitable water :math:`P_{wat}` is equivalent to the total column of
    water vapor (TCWV), but the units given by ECMWF MACC Reanalysis are kg/m^2
    at STP (1-atm, 25-C). Divide by ten to convert to centimeters of
    precipitable water:

    .. math::
        P_{wat} \\left( \\text{cm} \\right) \
        = TCWV \\left( \\frac{\\text{kg}}{\\text{m}^2} \\right) \
        \\frac{100 \\frac{\\text{cm}}{\\text{m}}} \
        {1000 \\frac{\\text{kg}}{\\text{m}^3}}

    The keynames available for the ``params`` argument are given by
    :const:`pvlib.iotools.ecmwf_macc.PARAMS` which maps the keys to codes used
    in the API. The following keynames are available:

    =======  =========================================
    keyname  description
    =======  =========================================
    tcwv     total column water vapor in kg/m^2 at STP
    aod550   aerosol optical depth measured at 550-nm
    aod469   aerosol optical depth measured at 469-nm
    aod670   aerosol optical depth measured at 670-nm
    aod865   aerosol optical depth measured at 865-nm
    aod1240  aerosol optical depth measured at 1240-nm
    =======  =========================================

    If ``lookup_params`` is ``False`` then ``params`` must contain the codes
    preformatted according to the ECMWF MACC Reanalysis API. This is useful if
    you want to retrieve codes that are not mapped in
    :const:`pvlib.iotools.ecmwf_macc.PARAMS`.

    Specify a custom ``target`` function to modify how the ECMWF API function
    ``server.retrieve`` is called. The ``target`` function must have the
    following signature in which the parameter definitions are similar to
    :func:`pvlib.iotools.get_ecmwf_macc`. ::


        target(server, startdate, stopdate, params, filename) -> None

    Examples
    --------
    Retrieve the AOD measured at 550-nm and the total column of water vapor for
    November 1, 2012.

    >>> from datetime import date
    >>> from pvlib.iotools import get_ecmwf_macc
    >>> filename = 'aod_tcwv_20121101.nc'  # .nc extension added if missing
    >>> params = ('aod550', 'tcwv')
    >>> start = end = date(2012, 11, 1)
    >>> t = get_ecmwf_macc(filename, params, start, end)
    >>> t.is_alive()
    True

    """
    if not filename.endswith('nc'):
        filename += '.nc'
    if lookup_params:
        try:
            params = '/'.join(PARAMS.get(p) for p in params)
        except TypeError:
            params = PARAMS.get(params)
    startdate = startdate.strftime('%Y-%m-%d')
    stopdate = stopdate.strftime('%Y-%m-%d')
    if not server:
        server = ECMWFDataServer()
    t = threading.Thread(target=target, daemon=True,
                         args=(server, startdate, stopdate, params, filename))
    t.start()
    return t