77from datetime import datetime , date
88from typing import Union , Mapping , Sequence
99
10- # pyCSEP libraries
11- import csep .core
12- import csep .utils
13-
1410# third-party libraries
1511import numpy
1612import pandas
1713import scipy .stats
1814import seaborn
1915import yaml
16+ from matplotlib import pyplot
17+ from matplotlib .lines import Line2D
18+
19+ # pyCSEP libraries
20+ import csep .core
21+ import csep .utils
2022from csep .core .catalogs import CSEPCatalog
2123from csep .core .exceptions import CSEPCatalogException
2224from csep .core .forecasts import GriddedForecast
2931from csep .models import EvaluationResult
3032from csep .utils .calc import cleaner_range
3133from csep .utils .plots import plot_spatial_dataset
32- from matplotlib import pyplot
33- from matplotlib .lines import Line2D
3434
3535# floatCSEP libraries
3636import floatcsep .utils .accessors
@@ -237,9 +237,7 @@ def read_region_cfg(region_config, **kwargs):
237237 return region_config
238238
239239
240- def timewindow2str (
241- datetimes : Union [Sequence [datetime ], Sequence [Sequence [datetime ]]]
242- ) -> Union [str , list [str ]]:
240+ def timewindow2str (datetimes : Sequence ) -> Union [str , list [str ]]:
243241 """
244242 Converts a time window (list/tuple of datetimes) to a string that represents it. Can be a
245243 single timewindow or a list of time windows.
@@ -250,10 +248,10 @@ def timewindow2str(
250248 Returns:
251249 A sequence of strings for each time window
252250 """
253- if isinstance (datetimes [ 0 ] , datetime ):
251+ if all ( isinstance (i , datetime ) for i in datetimes ):
254252 return "_" .join ([j .date ().isoformat () for j in datetimes ])
255253
256- elif isinstance (datetimes [ 0 ] , (list , tuple )):
254+ elif all ( isinstance (i , (list , tuple )) for i in datetimes ):
257255 return ["_" .join ([j .date ().isoformat () for j in i ]) for i in datetimes ]
258256
259257
@@ -320,14 +318,17 @@ def timewindows_ti(
320318 try :
321319 timelimits = pandas .date_range (
322320 start = start_date , end = end_date , periods = periods , freq = frequency
323- ).to_pydatetime ()
321+ )
322+ print (timelimits )
323+ timelimits = timelimits .to_pydatetime ()
324324 except ValueError as e_ :
325325 raise ValueError (
326326 "The following experiment parameters combinations are possible:\n "
327327 " (start_date, end_date)\n "
328328 " (start_date, end_date, intervals)\n "
329329 " (start_date, end_date, timewindow)\n "
330- " (start_date, intervals, timewindow)\n "
330+ " (start_date, intervals, timewindow)\n " ,
331+ e_ ,
331332 )
332333
333334 if growth == "incremental" :
@@ -365,34 +366,74 @@ def timewindows_td(
365366 testing window, as :py:class:`datetime.datetime`.
366367 """
367368
368- frequency = None
369+ frequency = parse_timedelta_string (timehorizon )
370+ offset = parse_timedelta_string (timeoffset )
369371
370- if timehorizon :
371- n , unit = timehorizon .split ("-" )
372+ if frequency :
373+ n , unit = frequency .split ("-" )
372374 frequency = f"{ n } { _PD_FORMAT [_UNITS .index (unit )]} "
375+ if offset :
376+ n , unit = offset .split ("-" )
377+ offset = f"{ n } { _PD_FORMAT [_UNITS .index (unit )]} "
373378
374379 periods = timeintervals + 1 if timeintervals else timeintervals
375380
376- try :
377- offset = timeoffset .split ("-" ) if timeoffset else None
378- start_offset = (
379- start_date + pandas .DateOffset (** {offset [1 ]: float (offset [0 ])})
380- if offset
381- else start_date
382- )
383- end_offset = (
384- end_date - pandas .DateOffset (** {offset [1 ]: float (offset [0 ])})
385- if offset
386- else start_date
387- )
381+ windows = []
388382
389- lower_limits = pandas .date_range (
390- start = start_date , end = end_offset , periods = periods , freq = frequency
391- ).to_pydatetime ()[:- 1 ]
392- upper_limits = pandas .date_range (
393- start = start_offset , end = end_date , periods = periods , freq = frequency
394- ).to_pydatetime ()[:- 1 ]
395- except ValueError as e_ :
383+ if start_date and end_date and timehorizon and timeoffset :
384+
385+ current_start = start_date
386+ current_end = start_date
387+ while current_end < end_date :
388+ next_window = pandas .date_range (
389+ start = current_start , periods = 2 , freq = frequency
390+ ).tolist ()
391+
392+ current_end = next_window [1 ]
393+
394+ windows .append ((current_start , current_end ))
395+
396+ current_start = pandas .date_range (start = current_start , periods = 2 , freq = offset )[
397+ 1
398+ ].to_pydatetime ()
399+
400+ elif start_date and timeintervals and timehorizon and timeoffset :
401+
402+ for _ in range (timeintervals ):
403+ next_window = pandas .date_range (
404+ start = start_date , periods = 2 , freq = frequency
405+ ).tolist ()
406+ lower_bound = start_date
407+ upper_bound = next_window [1 ]
408+ windows .append ((lower_bound , upper_bound ))
409+ start_date = pandas .date_range (start = start_date , periods = 2 , freq = offset )[
410+ 1
411+ ].to_pydatetime ()
412+
413+ elif start_date and end_date and timeintervals :
414+ if timeintervals == 1 :
415+ log .warning ("Only 1 time window is presentL. Consider using exp_class: ti" )
416+
417+ timelimits = pandas .date_range (
418+ start = start_date , end = end_date , periods = periods , freq = frequency
419+ ).tolist ()
420+ windows = [(i , j ) for i , j in zip (timelimits [:- 1 ], timelimits [1 :])]
421+
422+ # Case 2: (start_date, end_date, timehorizon)
423+ elif start_date and end_date and timehorizon :
424+ timelimits = pandas .date_range (
425+ start = start_date , end = end_date , periods = periods , freq = frequency
426+ ).tolist ()
427+ windows = [(i , j ) for i , j in zip (timelimits [:- 1 ], timelimits [1 :])]
428+
429+ # Case 3: (start_date, timeintervals, timehorizon)
430+ elif start_date and timeintervals and timehorizon :
431+ timelimits = pandas .date_range (
432+ start = start_date , end = end_date , periods = periods , freq = frequency
433+ ).tolist ()
434+ windows = [(i , j ) for i , j in zip (timelimits [:- 1 ], timelimits [1 :])]
435+
436+ else :
396437 raise ValueError (
397438 "The following experiment parameters combinations are possible:\n "
398439 " (start_date, end_date, timeintervals)\n "
@@ -401,14 +442,7 @@ def timewindows_td(
401442 " (start_date, end_date, timehorizon, timeoffset)\n "
402443 " (start_date, timeinvervals, timehorizon, timeoffset)\n "
403444 )
404-
405- # if growth == 'incremental':
406- # timewindows = [(i, j) for i, j in zip(timelimits[:-1],
407- # timelimits[1:])]
408- # elif growth == 'cumulative':
409- # timewindows = [(timelimits[0], i) for i in timelimits[1:]]
410-
411- # return timewindows
445+ return windows
412446
413447
414448def parse_nested_dicts (nested_dict : dict ) -> dict :
@@ -466,17 +500,18 @@ def sequential_likelihood(
466500 """
467501 Performs the likelihood test on Gridded Forecast using an Observed Catalog.
468502
469- Note: The forecast and the observations should be scaled to the same time period before calling this function. This increases
470- transparency as no assumptions are being made about the length of the forecasts. This is particularly important for
471- gridded forecasts that supply their forecasts as rates.
503+ Note: The forecast and the observations should be scaled to the same time period before
504+ calling this function. This increases transparency as no assumptions are being made about
505+ the length of the forecasts. This is particularly important for gridded forecasts that
506+ supply their forecasts as rates.
472507
473508 Args:
474509 gridded_forecasts: list csep.core.forecasts.GriddedForecast
475510 observed_catalogs: list csep.core.catalogs.Catalog
476- timewindows: list str.
477511 seed (int): used fore reproducibility, and testing
478- random_numbers (numpy.ndarray): random numbers used to override the random number generation.
479- injection point for testing.
512+ random_numbers (numpy.ndarray): random numbers used to override the random number
513+ generation injection point for testing.
514+
480515 Returns:
481516 evaluation_result: csep.core.evaluations.EvaluationResult
482517 """
@@ -535,17 +570,19 @@ def sequential_information_gain(
535570 gridded_forecasts: list csep.core.forecasts.GriddedForecast
536571 benchmark_forecasts: list csep.core.forecasts.GriddedForecast
537572 observed_catalogs: list csep.core.catalogs.Catalog
538- timewindows: list str.
539573 seed (int): used fore reproducibility, and testing
540- random_numbers (numpy.ndarray): random numbers used to override the random number generation.
541- injection point for testing.
574+ random_numbers (numpy.ndarray): random numbers used to override the random number
575+ generation injection point for testing.
542576
543577 Returns:
544578 evaluation_result: csep.core.evaluations.EvaluationResult
545579 """
546580
547581 information_gains = []
548582
583+ gridded_forecast = None
584+ observed_catalog = None
585+
549586 for gridded_forecast , reference_forecast , observed_catalog in zip (
550587 gridded_forecasts , benchmark_forecasts , observed_catalogs
551588 ):
@@ -587,6 +624,7 @@ def sequential_information_gain(
587624 result .obs_name = observed_catalog .name
588625 result .status = "normal"
589626 result .min_mw = numpy .min (gridded_forecast .magnitudes )
627+
590628 return result
591629
592630
0 commit comments