@@ -81,13 +81,12 @@ def is_matching_field(self, field: Any):
8181 endStep = field .metadata ("endStep" )
8282 date = field .metadata ("date" )
8383 time = field .metadata ("time" )
84-
84+
8585 assert stepType == "accum" , f"Not an accumulated variable: { stepType } "
8686
8787 base_datetime = datetime .datetime .strptime (str (date ) + str (time ).zfill (4 ), "%Y%m%d%H%M" )
8888 start = base_datetime + datetime .timedelta (hours = startStep )
8989 flag = start == self .start_datetime
90-
9190 end = base_datetime + datetime .timedelta (hours = endStep )
9291 flag = flag and (end == self .end_datetime )
9392 return flag
@@ -445,24 +444,69 @@ def available_steps(self, start, end) -> dict:
445444
446445
447446class EaEndaIntervalsCollection (EraIntervalsCollection ):
448- def available_steps (self , start , end ) -> dict :
447+
448+ forecast_period : int = datetime .timedelta (hours = 12 )
449+
450+ def available_steps (self ) -> dict :
449451 """Return the IntervalsCollection time steps available to build/search an available interval
450452
451- Parameters:
452- ----------
453- start (datetime.datetime): step (=leadtime) from the forecast where interval begins
454- end (datetime.datetime): step (=leadtime) from the forecast where interval ends
455-
456453 Return:
457454 -------
458455 _ (dict[List[int]]) : dictionary listing the available steps between start and end for each base
459456
460457 """
461- print ("❌❌❌ untested" )
462458 return {
463459 6 : [[i , i + 3 ] for i in range (0 , 18 , 1 )],
464460 18 : [[i , i + 3 ] for i in range (0 , 18 , 1 )],
465461 }
462+
463+ def search_interval (self , current : datetime .datetime ) -> Interval :
464+
465+ steps = self .available_steps ()
466+ current_hour = current .hour
467+ if (current_hour - 6 ) % 24 <= int (self .forecast_period .seconds // 3600 ) and (current_hour - 6 ) > 0 :
468+ start_guess = 6
469+ else :
470+ start_guess = 18
471+ print (start_guess , current_hour ,[i [1 ] for i in steps [start_guess ]])
472+ end_times = [i [1 ] for i in steps [start_guess ]]
473+ assert (current_hour - start_guess ) % 24 in end_times , f"No available forecast for { current } "
474+
475+ delta = datetime .timedelta (hours = ((current_hour - start_guess ) % 24 ))
476+ print (current_hour , int (self .forecast_period .seconds // 3600 ), delta , start_guess )
477+ assert delta <= self .forecast_period , f"{ current } is too far from a forecast start"
478+ start = current - delta
479+
480+ return Interval (current - datetime .timedelta (hours = 3 ), current , start )
481+
482+ def build_intervals (self ) -> list [Interval ]:
483+ """Build the list of intervals to accumulate the data on the IntervalsCollection
484+
485+ available steps --> checking the closest base datetime for each hour
486+ difference should be implemented
487+ """
488+
489+ start = self .valid_date - self .accumulation_period
490+ current = self .valid_date
491+ lst = []
492+ while current > start :
493+ chosen = self .search_interval (current )
494+ current = current - (chosen .end_datetime - chosen .start_datetime )
495+ chosen .sign = 1
496+ # avoid infinite loop
497+ assert current < chosen .end_datetime
498+ # if start matches a forecast start, no additional interval needed
499+ lst .append (chosen )
500+
501+ # if start does not match a forecast start, one additional interval needed
502+ if current < start :
503+ assert start - current < self .forecast_period , f"{ current } selects a forecast too far in the past"
504+ assert current .hour in self .available_steps ()
505+ chosen = Interval (start - datetime .timedelta (hours = 3 ), start , current )
506+ # must substract the accumulated value from forecast start
507+ chosen .sign = - 1
508+ lst .append (chosen )
509+ return lst
466510
467511
468512class RrOperIntervalsCollection (IntervalsCollection ):
0 commit comments