@@ -183,6 +183,80 @@ def collapse_by_hour_of_day(
183183 return collapsed_cube
184184
185185
186+ def collapse_by_validity_time (
187+ cube : iris .cube .Cube | iris .cube .CubeList ,
188+ method : str ,
189+ additional_percent : float = None ,
190+ ** kwargs ,
191+ ) -> iris .cube .Cube :
192+ """Collapse a cube around validity time for multiple cases.
193+
194+ First checks if the data can be aggregated easily. Then creates a new cube
195+ by slicing over the time dimensions, removing the time dimensions,
196+ re-merging the data, and creating a new time coordinate. It then collapses
197+ by the new time coordinate for a specified method using the collapse
198+ function.
199+
200+ Arguments
201+ ---------
202+ cube: iris.cube.Cube | iris.cube.CubeList
203+ Cube to collapse by validity time or CubeList that will be converted
204+ to a cube before collapsing by validity time.
205+ method: str
206+ Type of collapse i.e. method: 'MEAN', 'MAX', 'MIN', 'MEDIAN',
207+ 'PERCENTILE'. For 'PERCENTILE' the additional_percent must be specified.
208+
209+ Returns
210+ -------
211+ cube: iris.cube.Cube
212+ Single variable collapsed by lead time based on chosen method.
213+
214+ Raises
215+ ------
216+ ValueError
217+ If additional_percent wasn't supplied while using PERCENTILE method.
218+ """
219+ if method == "PERCENTILE" and additional_percent is None :
220+ raise ValueError ("Must specify additional_percent" )
221+ # Ensure the cube can be aggregated over multiple times.
222+ cube_to_collapse = ensure_aggregatable_across_cases (cube )
223+ # Convert to a cube that is split by validity time.
224+ # Slice over cube by both time dimensions to create a CubeList.
225+ new_cubelist = iris .cube .CubeList (
226+ cube_to_collapse .slices_over (["forecast_period" , "forecast_reference_time" ])
227+ )
228+ # Remove forecast_period and forecast_reference_time coordinates.
229+ for sub_cube in new_cubelist :
230+ sub_cube .remove_coord ("forecast_period" )
231+ sub_cube .remove_coord ("forecast_reference_time" )
232+ # Create new CubeList by merging with unique = False to produce a validity
233+ # time cube.
234+ merged_list_1 = new_cubelist .merge (unique = False )
235+ # Create a new "fake" coordinate and apply to each remaining cube to allow
236+ # final merging to take place into a single cube.
237+ equalised_validity_time = iris .coords .AuxCoord (
238+ points = 0 , long_name = "equalised_validity_time" , units = "1"
239+ )
240+ for sub_cube , eq_valid_time in zip (
241+ merged_list_1 , range (len (merged_list_1 )), strict = True
242+ ):
243+ sub_cube .add_aux_coord (equalised_validity_time .copy (points = eq_valid_time ))
244+
245+ # Merge CubeList to create final cube.
246+ final_cube = merged_list_1 .merge_cube ()
247+ # Collapse over fake_time_coord to represent collapsing over validity time.
248+ if method == "PERCENTILE" :
249+ collapsed_cube = collapse (
250+ final_cube ,
251+ "equalised_validity_time" ,
252+ method ,
253+ additional_percent = additional_percent ,
254+ )
255+ else :
256+ collapsed_cube = collapse (final_cube , "equalised_validity_time" , method )
257+ return collapsed_cube
258+
259+
186260# TODO
187261# Collapse function that calculates means, medians etc across members of an
188262# ensemble or stratified groups. Need to allow collapse over realisation
0 commit comments