neural_lam.utils.time
=====================

.. py:module:: neural_lam.utils.time

.. autoapi-nested-parse::

   Time-delta conversion and interior/boundary time-axis alignment.



Functions
---------

.. autoapisummary::

   neural_lam.utils.time.apply_time_crop
   neural_lam.utils.time.get_integer_time
   neural_lam.utils.time.get_time_crop_slice
   neural_lam.utils.time.get_time_step


Module Contents
---------------

.. py:function:: apply_time_crop(da: xarray.DataArray, crop_dim: str, crop_slice: slice) -> xarray.DataArray

   Apply a :func:`get_time_crop_slice` result to ``da``, logging removals.

   :param da: Dataarray to crop.
   :type da: xr.DataArray
   :param crop_dim: Dimension to crop along.
   :type crop_dim: str
   :param crop_slice: Positional slice to keep.
   :type crop_slice: slice

   :returns: ``da`` cropped, or unchanged when the slice keeps everything.
   :rtype: xr.DataArray


.. py:function:: get_integer_time(tdelta: datetime.timedelta) -> tuple[int, str]

   Express a :class:`datetime.timedelta` as an integer number of time units.

   :param tdelta: The time interval to convert.
   :type tdelta: datetime.timedelta

   :returns: * *int* -- Integer value of the timedelta in the largest unit that divides
               it exactly, or ``1`` if no such unit exists.
             * *str* -- The time unit as a string (``'weeks'``, ``'days'``, ``'hours'``,
               ``'minutes'``, ``'seconds'``, ``'milliseconds'``,
               ``'microseconds'``). Returns ``'unknown'`` if no unit divides
               evenly.

   .. rubric:: Examples

   >>> from datetime import timedelta
   >>> get_integer_time(timedelta(days=14))
   (2, 'weeks')
   >>> get_integer_time(timedelta(hours=5))
   (5, 'hours')
   >>> get_integer_time(timedelta(milliseconds=1000))
   (1, 'seconds')
   >>> get_integer_time(timedelta(days=0.001))
   (1, 'unknown')


.. py:function:: get_time_crop_slice(da_requested: xarray.DataArray, da_available: xarray.DataArray, da_requested_is_forecast: bool = False, da_available_is_forecast: bool = False, num_past_steps: int = 1, num_future_steps: int = 1, requested_max_lead: numpy.timedelta64 | None = None) -> tuple[str, slice]

   Return the ``da_requested`` dimension and slice ``da_available`` covers.

   Callers holding several dataarrays on the same time axis (interior state
   and forcing) apply this one slice to all of them so they stay aligned.

   :param da_requested: Driving dataarray whose times must be supported (typically interior
                        state).
   :type da_requested: xr.DataArray
   :param da_available: Dataarray that must cover the requested windows (typically boundary
                        forcing).
   :type da_available: xr.DataArray
   :param da_requested_is_forecast: Whether each side is in forecast mode (``analysis_time`` +
                                    ``elapsed_forecast_duration`` dims) instead of plain ``time``.
   :type da_requested_is_forecast: bool
   :param da_available_is_forecast: Whether each side is in forecast mode (``analysis_time`` +
                                    ``elapsed_forecast_duration`` dims) instead of plain ``time``.
   :type da_available_is_forecast: bool
   :param num_past_steps: Window size around each requested time, measured in ``da_available``
                          steps.
   :type num_past_steps: int
   :param num_future_steps: Window size around each requested time, measured in ``da_available``
                            steps.
   :type num_future_steps: int
   :param requested_max_lead: Largest lead read from a forecast ``da_requested`` per sample; each
                              ``analysis_time`` needs coverage out to it. Defaults to the full
                              forecast length.
   :type requested_max_lead: np.timedelta64, optional

   :returns: The dimension to crop along (``"analysis_time"`` for a forecast
             ``da_requested``, else ``"time"``) and the positional slice to keep.
   :rtype: tuple of (str, slice)

   :raises ValueError: If no requested time is covered at all.


.. py:function:: get_time_step(times: numpy.ndarray) -> numpy.timedelta64

   Calculate the (constant) time step from a 1D time array.

   :param times: 1D array of datetime64 or timedelta64 values.
   :type times: np.ndarray

   :returns: **time_step** -- The constant spacing between successive values.
   :rtype: np.timedelta64

   :raises ValueError: If fewer than two values are given, or if the spacing is not
       constant.


