Skip to content

1 — Time series get re-implemented, despite loading pandas #1696

Description

@patnr

Part of a set of structural observations — see #1695 (index) for context.

Description

pandas is a direct dependency (pyproject.toml) and is imported in 15 files, but it's used almost exclusively for CSV ingestion convenience. The actual backbone that carries a time axis through every computation is a hand-rolled Period/Periods dataclass (common/time_utils.py), used throughout common/variables.py, core/result/results.py, and presentation/json_result/result/emission.py, rather than a pandas.DatetimeIndex. Domain-specific logic (calendar-day vs. stream-day rate conventions, cumulative-volume semantics) could be a thin wrapper class around a Series/DataFrame instead.

Some concrete costs of the current approach:

  • Period.__contains__ implements half-open interval membership by hand, and get_period_indices finds indices by calling self.start_dates.index(...) / self.all_dates.index(...) — an O(n) linear scan through a Python list, every time it's invoked (a pattern repeated at several other call sites in common/utils/rates.py too). A pandas.DatetimeIndex gives interval membership, boundary handling, and O(log n) lookup (slice_indexer, get_indexer) as built-ins.
  • libecalc/common/utils/rates.py implements its own reindex, for_periods, and resampling logic (TimeSeriesBoolean.resample, TimeSeriesVolumesCumulative.resample, etc.) on top of the same Period/Periods types — essentially re-deriving Series.reindex/Series.resample/Series.asfreq one method at a time, without the correctness properties (frequency inference, DST handling, vectorized alignment) that pandas already tests for.
  • presentation/yaml/mappers/variables_mapper/get_global_time_vector.py:get_global_time_vector builds the single shared "global" time axis that every input source ultimately gets resampled onto — the merge point for however many independent sources a model has. The INFLUENCE_TIME_VECTOR keyword controlling that merge is a per-source boolean, defaulting to TRUE, so a reader has to scan every TIME_SERIES entry and mentally OR the flags to know what timesteps the whole model will actually be evaluated at.

Examples

Business/User Value

Removes O(n) linear scans on the hot path of every period lookup, removes a hand-maintained reimplementation of reindex/resample logic that pandas already tests for frequency inference, DST handling, and vectorized alignment, and would make the global-time-vector merge logic inspectable via standard pandas index operations instead of manually scanning keyword flags.

Files

  • common/time_utils.py
  • common/variables.py
  • core/result/results.py
  • presentation/json_result/result/emission.py
  • libecalc/common/utils/rates.py
  • presentation/yaml/mappers/variables_mapper/get_global_time_vector.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions