Skip to content

Commit 39758ed

Browse files
committed
feat: Add new alarm forecast and temporal evaluation functions and tutorials with updated data and plotting utilities.
1 parent 5e6d217 commit 39758ed

13 files changed

+2056
-6
lines changed

csep/__init__.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
'load_gridded_forecast',
5555
'load_catalog_forecast',
5656
'load_alarm_forecast',
57+
'load_temporal_forecast',
58+
'compute_temporal_observations',
5759
'utc_now_datetime',
5860
'strptime_to_utc_datetime',
5961
'datetime_to_utc_epoch',
@@ -640,3 +642,111 @@ def load_alarm_forecast(fname, name=None, score_field='alarm_score',
640642

641643
return forecast
642644

645+
646+
def load_temporal_forecast(fname, time_col='time', probability_col='probability',
647+
delimiter=',', **kwargs):
648+
""" Load temporal probability forecast from CSV file.
649+
650+
This function loads time-series probability forecasts where each row represents
651+
a time window (e.g., day) with an associated probability of earthquake occurrence.
652+
Observations should be computed separately from a catalog using
653+
compute_temporal_observations().
654+
655+
Args:
656+
fname (str): Path to temporal forecast CSV file
657+
time_col (str): Name of time/index column (default: 'time')
658+
probability_col (str): Name of probability column (default: 'probability')
659+
delimiter (str): CSV delimiter character. Default: ','
660+
661+
Returns:
662+
dict: Dictionary containing:
663+
- 'times': Time indices (numpy array or DatetimeIndex)
664+
- 'probabilities': Forecast probabilities (numpy array)
665+
- 'metadata': Additional information (dict)
666+
667+
Raises:
668+
FileNotFoundError: If the CSV file does not exist
669+
ValueError: If required columns are missing
670+
671+
Example:
672+
>>> # Load temporal forecast
673+
>>> data = csep.load_temporal_forecast('daily_forecast.csv')
674+
>>> catalog = csep.load_catalog('events.csv')
675+
>>>
676+
>>> # Compute observations from catalog
677+
>>> observations = csep.compute_temporal_observations(
678+
... catalog, data['times'], magnitude_min=4.0
679+
... )
680+
>>>
681+
>>> # Evaluate with temporal Molchan diagram
682+
>>> from csep.utils import plots
683+
>>> ax, ass, sigma = plots.plot_temporal_Molchan_diagram(
684+
... data['probabilities'], observations, name='DailyM4+'
685+
... )
686+
"""
687+
# Sanity checks
688+
if not os.path.exists(fname):
689+
raise FileNotFoundError(
690+
f"Could not locate file {fname}. Unable to load temporal forecast.")
691+
692+
times, probabilities, metadata = readers.temporal_forecast_csv(
693+
filename=fname,
694+
time_col=time_col,
695+
probability_col=probability_col,
696+
delimiter=delimiter
697+
)
698+
699+
return {
700+
'times': times,
701+
'probabilities': probabilities,
702+
'metadata': metadata
703+
}
704+
705+
706+
def compute_temporal_observations(catalog, times, magnitude_min=None,
707+
start_time=None, time_delta=None):
708+
""" Compute binary observations from a catalog for temporal forecast evaluation.
709+
710+
This function counts whether one or more earthquakes occurred in each time
711+
window, creating a binary observation vector suitable for temporal ROC
712+
and Molchan evaluation.
713+
714+
Args:
715+
catalog: A CSEPCatalog object containing observed earthquakes
716+
times (array-like): Array representing forecast time windows.
717+
Can be datetime objects OR integer indices (1, 2, 3, ...).
718+
If integers, use start_time and time_delta.
719+
magnitude_min (float, optional): Minimum magnitude threshold.
720+
start_time (str or datetime, optional): Start time of the forecast.
721+
Required if times are integer indices.
722+
Example: '2024-01-01'
723+
time_delta (str, optional): Duration of each time window.
724+
Required if times are integer indices.
725+
Examples: '1D' (1 day), '1H' (1 hour), '7D' (1 week)
726+
727+
Returns:
728+
numpy.ndarray: Binary array (1 if event occurred in window, 0 otherwise)
729+
730+
Example:
731+
>>> # With datetime times in CSV
732+
>>> data = csep.load_temporal_forecast('forecast.csv')
733+
>>> catalog = csep.load_catalog('events.csv')
734+
>>> observations = csep.compute_temporal_observations(
735+
... catalog, data['times'], magnitude_min=4.0
736+
... )
737+
>>>
738+
>>> # With integer indices (1, 2, 3, ...)
739+
>>> observations = csep.compute_temporal_observations(
740+
... catalog, data['times'],
741+
... start_time='2024-01-01',
742+
... time_delta='1D',
743+
... magnitude_min=4.0
744+
... )
745+
"""
746+
return readers.compute_temporal_observations(
747+
catalog=catalog,
748+
times=times,
749+
magnitude_min=magnitude_min,
750+
start_time=start_time,
751+
time_delta=time_delta
752+
)

0 commit comments

Comments
 (0)