@@ -1393,6 +1393,60 @@ def _validate_cubes_coords(
13931393 )
13941394
13951395
1396+ def _calculate_CFAD (
1397+ cube : iris .cube .Cube , vertical_coordinate : str , bin_edges : list [float ]
1398+ ) -> iris .cube .Cube :
1399+ """Calculate a Contour Frequency by Altitude Diagram (CFAD).
1400+
1401+ Parameters
1402+ ----------
1403+ cube: iris.cube.Cube
1404+ A cube of the data to be turned into a CFAD. It should be a minimum
1405+ of two dimensions with one being a user specified vertical coordinate.
1406+ vertical_coordinate: str
1407+ The vertical coordinate of the cube for the CFAD to be calculated over.
1408+ bin_edges: list[float]
1409+ The bin edges for the histogram. The bins need to be specified to
1410+ ensure consistency across the CFAD, otherwise it cannot be interpreted.
1411+ """
1412+ # Setup empty array for containing the CFAD data.
1413+ CFAD_values = np .zeros (
1414+ (len (cube .coord (vertical_coordinate ).points ), len (bin_edges ) - 1 )
1415+ )
1416+
1417+ # Set iterator for CFAD values.
1418+ i = 0
1419+
1420+ # Calculate the CFAD as a histogram summing to one for each level.
1421+ for level_cube in cube .slices_over (vertical_coordinate ):
1422+ # Note setting density to True does not produce the correct
1423+ # normalization for a CFAD, where each row must sum to one.
1424+ CFAD_values [i , :] = (
1425+ np .histogram (level_cube .data .reshape (level_cube .data .size ), bins = bin_edges )[
1426+ 0
1427+ ]
1428+ / level_cube .data .size
1429+ )
1430+ i += 1
1431+ # calculate central points for bins
1432+ bins = (np .array (bin_edges [:- 1 ]) + np .array (bin_edges [1 :])) / 2.0
1433+ bin_bounds = np .array ((bin_edges [:- 1 ], bin_edges [1 :])).T
1434+ # Now construct the coordinates for the cube.
1435+ vert_coord = cube .coord (vertical_coordinate )
1436+ bin_coord = iris .coords .DimCoord (
1437+ bins , bounds = bin_bounds , standard_name = cube .standard_name , units = cube .units
1438+ )
1439+ # Now construct the cube that is to be output.
1440+ CFAD = iris .cube .Cube (
1441+ CFAD_values ,
1442+ dim_coords_and_dims = [(vert_coord , 0 ), (bin_coord , 1 )],
1443+ standard_name = cube .standard_name ,
1444+ units = "1" ,
1445+ )
1446+ CFAD .attributes ["type" ] = "Contour Frequency by Altitude Diagram (CFAD)"
1447+ return CFAD
1448+
1449+
13961450####################
13971451# Public functions #
13981452####################
0 commit comments