Source code for pycif.plugins.models.lmdz_ico.ini_periods

from __future__ import annotations

from datetime import datetime
from logging import debug

import numpy as np
import pandas as pd

from ....utils.dates import date_range


[docs] def is_month_start(datetime: pd.Timestamp) -> bool: return ( datetime.is_month_start and datetime.hour == 0 and datetime.minute == 0 and datetime.second == 0 )
[docs] def ini_periods(self, **kwargs) -> None: # Keep old behaviour for month sub-simulations (maybe not needed) if self.period_freq in ("MS", "1MS"): ref_datei = pd.Timestamp(year=self.datei.year, month=self.datei.month, day=1) else: ref_datei = self.datei dates = pd.date_range(ref_datei, self.datef, freq=self.period_freq) subsimu_dates = [] # Simulation sub-periods, cut to a maximum length of 1 month for di, df in zip(dates[:-1], dates[1:]): subsimu_dates.append(di) # Both datetimes are in the same month if di.year == df.year and di.month == df.month: continue next_month = (di + pd.offsets.MonthBegin()).month # df is the first day of the month after di if df.month == next_month and is_month_start(df): continue # There is at least one month between di and df in_between = pd.date_range( di, df, freq="MS", normalize=True, inclusive="neither", ) subsimu_dates.extend(in_between.to_list()) # List of sub-simulation windows subsimu_dates.append(dates[-1]) self.subsimu_dates = pd.to_datetime(subsimu_dates).to_pydatetime() # type: ignore # pylint: disable=no-member if self.subsimu_dates[0] < self.datei: self.subsimu_dates[0] = self.datei if self.subsimu_dates[-1] < self.datef: self.subsimu_dates = np.append(self.subsimu_dates, self.datef) self.subsimu_intervals = { ddi: (ddi, ddf) for ddi, ddf in zip(self.subsimu_dates[:-1], self.subsimu_dates[1:]) } debug_msg = "LMDZ sub-simulation windows:\n" for dk, (di, df) in self.subsimu_intervals.items(): debug_msg += f"- {dk}: {di} - {df}\n" debug(debug_msg[:-1]) def get_input_dates( freq: str | pd.Timedelta, full_month: bool = False, ) -> dict[datetime, np.ndarray]: dates = {} for ddi, ddf in self.subsimu_intervals.values(): if full_month: ddi_month = pd.Timestamp(year=ddi.year, month=ddi.month, day=1) ddf_month = ddi_month + pd.DateOffset(months=1) dates[ddi] = date_range(ddi_month, ddf_month, period=freq) # type: ignore else: dates[ddi] = date_range(ddi, ddf, period=freq) # type: ignore return dates # List of time steps # WARNING: This part is critical for observations, modify with caution self.tstep_dates = get_input_dates(self.dt, full_month=True) # TODO: make the date inputs flexible (daily so far) self.input_dates = get_input_dates("1D", full_month=False) # Surface fluxes input dates self.flux_input_dates = get_input_dates(self.flux_freq, full_month=False) # Chemical fields input dates (full months) self.chem_input_dates = get_input_dates(self.chem_freq, full_month=True) # Mass fluxes input dates (full months at 3-hourly resolution) # Need to set input dates for meteo plugin here self.meteo_input_dates = get_input_dates(self.mass_fluxes_freq, full_month=True) # Initializes dictionary to keep in memory whether observations were # already dumped for a given period self.iniobs = {ddi: False for ddi in self.subsimu_dates} self.reset_obs = {ddi: True for ddi in self.subsimu_dates} # Initializes dictionary to keep in memory observations index information # Only "concs" component is used there self.chunk_indexes = { ddi: { comp: {spec: None for spec in self.chemistry.active_species} for comp in self.output_components } for ddi in self.subsimu_dates } # Run model or approximation with fake_end self.runsimu = {ddi: True for ddi in self.subsimu_dates} # Keep in memory whether a given period has a successor period # The info is used by the adjoint to fetch or not the restart file self.chain = {ddi: True for ddi in self.subsimu_dates[:-1]} self.chain[self.subsimu_dates[-2]] = False