-
Notifications
You must be signed in to change notification settings - Fork 99
Stable diags #11, #21, #24 #483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 12 commits
f0a35d6
6c2c3b7
e3cdd7d
4744307
dbb50d1
f753421
436d987
a2e5556
8f31833
efb9da4
68d0af0
6c0d132
12b13dd
8372788
f834cdf
4760ec7
eb2ad4c
a4efd9c
fa8138b
ee719fb
20cb588
8ebd176
c9eeb6c
f9e332a
f9f8838
be51855
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,6 +94,14 @@ | |
| <field field_ref="forcing__dt_force" /> | ||
| </file> | ||
|
|
||
| <file id="lfric_aviation" name="lfric_aviation" output_freq="6h" convention="UGRID" enabled=".TRUE."> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest removing changes for this file - it's an idealised example for which these diagnostics don't make a lot of sense |
||
| <field field_ref="aviation__geopot_thickness_850"/> | ||
| <field field_ref="aviation__geopot_thickness_500"/> | ||
| <field field_ref="aviation__snow_probability"/> | ||
| <field field_ref="aviation__conv_cloud_base_icao_height"/> | ||
| <field field_ref="aviation__conv_cloud_top_icao_height"/> | ||
| </file> | ||
|
|
||
| <file id="lfric_averages" name="lfric_averages" output_freq="12h" convention="UGRID" enabled=".TRUE."> | ||
| <field field_ref="theta" operation="average" /> | ||
| <field field_ref="exner" operation="average" /> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -991,6 +991,13 @@ | |
| <!-- Vertical integrals --> | ||
| <field id="processed__sw_aer_optical_depth_rts" field_ref="radiation__sw_aer_optical_depth_rts" grid_ref="vert_sum_face_grid"/> | ||
| <field id="processed__lw_aer_optical_depth_rts" field_ref="radiation__lw_aer_optical_depth_rts" grid_ref="vert_sum_face_grid"/> | ||
| <!-- Aviation diagnostics --> | ||
| <field id="aviation__geopot_thickness_850" name="aviation_geopot_thickness_850" standard_name="atmosphere_layer_thickness_expressed_as_geopotential_height_difference" long_name="geopotential_height_thickness_between_1000hPa_and_850hPa" unit="m" domain_ref="face"/> | ||
| <field id="aviation__geopot_thickness_500" name="aviation_geopot_thickness_500" standard_name="atmosphere_layer_thickness_expressed_as_geopotential_height_difference" long_name="geopotential_height_thickness_between_1000hPa_and_500hPa" unit="m" domain_ref="face"/> | ||
| <field id="aviation__snow_probability" name="aviation_snow_probability" long_name="surface_snow_probability" domain_ref="face"/> | ||
| <field id="aviation__conv_cloud_base_icao_height" name="aviation_conv_cloud_base_icao_height" long_name="height_of_convective_cloud_base" unit="kft" domain_ref="face" /> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if these should be in the "convection__" section, to mirror how they appear in section 5 of the UM? |
||
| <field id="aviation__conv_cloud_top_icao_height" name="aviation_conv_cloud_top_icao_height" long_name="height_of_convective_cloud_top" unit="kft" domain_ref="face" /> | ||
|
|
||
| </field_group> | ||
|
|
||
| <!-- Integer diagnostic group --> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,275 @@ | ||
| !----------------------------------------------------------------------------- | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ! (C) Crown copyright 2025 Met Office. All rights reserved. | ||
| ! The file LICENCE, distributed with this code, contains details of the terms | ||
| ! under which the code may be used. | ||
| !----------------------------------------------------------------------------- | ||
| ! | ||
| ! The main entry point for calculating section 20 aviation diagnostics. | ||
| ! | ||
| ! Code Owner: Please refer to the UM file CodeOwners.txt | ||
| ! This file currently belongs in section: physics_schemes_interface | ||
| ! whilst discussions are ongoing about its final location. | ||
| ! | ||
| module aviation_diags_alg_mod | ||
|
|
||
| use constants_mod, only: r_def, i_def, l_def, str_long, RMDI | ||
| use field_mod, only: field_type | ||
| use field_collection_mod, only: field_collection_type | ||
| use io_config_mod, only: use_xios_io | ||
| use initialise_diagnostics_mod, only: init_diag => init_diagnostic_field | ||
|
|
||
| use lfric_xios_diag_mod, only: get_axis_dimension, get_axis_values | ||
| use log_mod, only: log_event, & | ||
| log_level_always, log_level_error, & | ||
| log_level_info, log_level_debug | ||
|
|
||
| use aviation_thickness_snow_kernel_mod, & | ||
| only: aviation_thickness_snow_kernel_type | ||
| use aviation_icao_heights_kernel_mod, & | ||
| only: aviation_icao_heights_kernel_type | ||
|
|
||
| implicit none | ||
|
|
||
| private | ||
| public :: aviation_diags_alg | ||
|
|
||
| contains | ||
|
|
||
| ! Algorithm to calculate the section 20 aviation diagnostics. | ||
| subroutine aviation_diags_alg(plev_geopot, convection_fields) | ||
| implicit none | ||
|
|
||
| ! Arguments | ||
| type(field_type), intent(in) :: plev_geopot | ||
| type(field_collection_type), intent(inout) :: convection_fields | ||
|
|
||
| ! calculate thickness from geopotential height at pressure levels. | ||
| call from_plev_geopot(plev_geopot) | ||
|
|
||
| ! calculate icao heights of top and base of cloud from their pressures. | ||
| call icao_heights(convection_fields) | ||
|
|
||
| end subroutine aviation_diags_alg | ||
|
|
||
| SUBROUTINE from_plev_geopot(plev_geopot) | ||
| ! Calculate diagnostics from plvel_geopot. | ||
| ! - Thickness from geopotential height at pressure levels. | ||
|
|
||
| ! Arguments | ||
| type(field_type), intent(in) :: plev_geopot | ||
|
|
||
| ! Local variables | ||
|
|
||
| ! These flags tell us which results are requested at this time step. | ||
| logical(l_def) :: thick_850_flag, thick_500_flag, snow_probability_flag | ||
|
|
||
| ! The array of pressure levels. | ||
| integer(i_def) :: nplev | ||
| real(r_def), allocatable :: plevs(:) | ||
| integer(i_def) :: plevs_alloc_stat | ||
|
|
||
| ! Level indices for the three pressure levels we want to read. | ||
| integer(i_def) :: i1000, i850, i500 | ||
|
|
||
| ! Approximate equality tolerance - is there a common variable somewhere? | ||
| real(r_def), parameter :: plev_tol = 0.1_r_def | ||
|
|
||
| ! The output fields we produce. | ||
| type( field_type ) :: thick_850, thick_500, snow_probability | ||
|
|
||
| integer(i_def) :: i | ||
|
|
||
| character(len=str_long) :: message | ||
|
|
||
|
|
||
| ! Check the request flags. | ||
| snow_probability_flag = & | ||
| init_diag(snow_probability, 'aviation__snow_probability') | ||
| thick_850_flag = & | ||
| init_diag(thick_850, 'aviation__geopot_thickness_850') | ||
| thick_500_flag = & | ||
| init_diag(thick_500, 'aviation__geopot_thickness_500') | ||
|
|
||
| ! Anything to do? | ||
| if ( .not. (thick_850_flag .or. & | ||
| thick_500_flag .or. & | ||
| snow_probability_flag) ) then | ||
| return | ||
| end if | ||
|
|
||
| if ( .not. use_xios_io ) then | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest removing this - xios is really the only option, so it's doing lots of if-tests for no real benefit! |
||
| return | ||
| endif | ||
|
|
||
| ! Initialise required fields to 1. | ||
| if ( snow_probability_flag ) then | ||
| message = 'Section 20: snow probability requested' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess these are useful for debugging, but are they needed on main? I believe init_diag prints this information under some log level (perhaps trace instead of debug) |
||
| call log_event( message, log_level_debug ) | ||
| call invoke( setval_c(snow_probability, 0.0_r_def)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think these pre-initialisations to 0 or 1 are needed, because the field is entirely written to inside the kernel, so can be removed |
||
| end if | ||
|
|
||
| if ( thick_850_flag ) then | ||
| message = 'Section 20: geopot thick 850 requested' | ||
| call log_event( message, log_level_debug ) | ||
| ! Todo: Why 1 and not 0? | ||
| call invoke( setval_c(thick_850, 1.0_r_def)) | ||
| end if | ||
|
|
||
| if ( thick_500_flag ) then | ||
| message = 'Section 20: geopot thick 500 requested' | ||
| call log_event( message, log_level_debug ) | ||
| call invoke( setval_c(thick_500, 1.0_r_def)) | ||
| end if | ||
|
|
||
| ! Get the array of pressure levels. | ||
| nplev = get_axis_dimension('pressure_levels') | ||
| if (nplev <= 0) then | ||
| message = 'Section 20: No pressure levels' | ||
| call log_event( message, log_level_error ) | ||
| return | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. log_level_error should terminate the model, so the returns are redundant |
||
| end if | ||
|
|
||
| allocate(plevs(nplev), stat=plevs_alloc_stat) | ||
| if (plevs_alloc_stat /= 0) then | ||
| message = 'Section 20: allocate(plevs) failed' | ||
| call log_event( message, log_level_error ) | ||
| return | ||
| end if | ||
| plevs = get_axis_values('pressure_levels',nplev) | ||
|
|
||
| ! Find the level indices for our three pressures of interest. | ||
| ! Assumes hPa. | ||
| i1000 = -1 | ||
| i850 = -1 | ||
| i500 = -1 | ||
| do i = 1, nplev | ||
|
|
||
| ! 1000? | ||
| if (abs(plevs(i) - 100000.0_r_def) < plev_tol) then | ||
| i1000 = i | ||
|
|
||
| ! 850? | ||
| else if (abs(plevs(i) - 85000.0_r_def) < plev_tol) then | ||
| i850 = i | ||
|
|
||
| ! 500? | ||
| else if (abs(plevs(i) - 50000.0_r_def) < plev_tol) then | ||
| i500 = i | ||
|
|
||
| end if | ||
| end do | ||
|
|
||
| ! Check we found the required levels. | ||
| if (i1000 == -1) then | ||
| message = 'Section 20: could not find 1000hPa' | ||
| call log_event( message, log_level_error ) | ||
| return | ||
| end if | ||
|
|
||
| if ((thick_850_flag .or. snow_probability_flag) .and. i850 == -1) then | ||
| message = 'Section 20: could not find 850hPa' | ||
| call log_event( message, log_level_error ) | ||
| return | ||
| end if | ||
|
|
||
| if (thick_500_flag .and. i500 == -1) then | ||
| message = 'Section 20: could not find 500hPa' | ||
| call log_event( message, log_level_error ) | ||
| return | ||
| end if | ||
|
|
||
| ! Call the kernel to subtract the levels. | ||
| ! Todo: Comment why we initialise to 1.0 and not 0.0. I can't remember. | ||
| call invoke( aviation_thickness_snow_kernel_type( & | ||
| thick_850, thick_500, snow_probability, & | ||
| plev_geopot, & | ||
| thick_850_flag, thick_500_flag, snow_probability_flag, & | ||
| i1000, i850, i500)) | ||
|
|
||
| ! Write the fields | ||
| if (thick_850_flag) call thick_850%write_field() | ||
| if (thick_500_flag) call thick_500%write_field() | ||
| if (snow_probability_flag) call snow_probability%write_field() | ||
|
|
||
| ! Clean up. | ||
| if (allocated(plevs)) then | ||
| deallocate(plevs) | ||
| end if | ||
|
|
||
| end subroutine from_plev_geopot | ||
|
|
||
|
|
||
| subroutine icao_heights(convection_fields) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I don't think this is the right place to be calling this code - I think it should be called directly from the convection diagnostics routines, the same as happens in the UM. Currently I don't believe this will be working correctly, specifically if the ICAO height has been requested but the pressure diagnostic hasn't. I would suggest removing this. In conv_diags_mod (and the Comorph equivalent) you will need to add the init_diag calls just before the pres_cv_base/top is initialised, and use the output of this to force the pres_cv_base/top to be initialised if the ICAO equivalent has been requested. Then in the output section where the pres_cv_base/top are written, you can call the icao_kernel on these fields and then output there (if the field is requested). You shouldn't need the pre-initialisation to rmdi after making my other suggested changes to the kernel. |
||
| ! Calculate ICAO heights of top and base of cloud from their pressures. | ||
|
|
||
| ! Arguments. | ||
| type(field_collection_type), intent(inout) :: convection_fields | ||
|
|
||
| ! Locals. | ||
| character(len=str_long) :: message | ||
|
|
||
| ! Pressure fields to unpack. | ||
| type(field_type), pointer :: conv_cloud_base_pressure | ||
| type(field_type), pointer :: conv_cloud_top_pressure | ||
|
|
||
| ! Height fields to create and write. | ||
| type(field_type) :: conv_cloud_base_icao_height | ||
| type(field_type) :: conv_cloud_top_icao_height | ||
|
|
||
| ! Request flags. | ||
| logical(l_def) :: base_height_flag | ||
| logical(l_def) :: top_height_flag | ||
|
|
||
| ! Which heights are requested this time step? | ||
| top_height_flag = init_diag( & | ||
| conv_cloud_top_icao_height, 'aviation__conv_cloud_top_icao_height') | ||
|
|
||
| base_height_flag = init_diag( & | ||
| conv_cloud_base_icao_height, 'aviation__conv_cloud_base_icao_height') | ||
|
|
||
| if (base_height_flag .or. top_height_flag) then | ||
| message = 'section 20: cloud icao heights on' | ||
| call log_event( message, log_level_debug ) | ||
| else | ||
| ! Nothing requested at this time step. | ||
| return | ||
| end if | ||
|
|
||
|
|
||
| ! Cloud base. | ||
| if (base_height_flag) then | ||
| call convection_fields%get_field( & | ||
| 'convection__pres_cv_base', conv_cloud_base_pressure) | ||
| call invoke( & | ||
| setval_c(conv_cloud_base_icao_height, rmdi), & | ||
| aviation_icao_heights_kernel_type(conv_cloud_base_icao_height, & | ||
| conv_cloud_base_pressure)) | ||
|
|
||
| call conv_cloud_base_icao_height%write_field() | ||
|
|
||
| ! Is it necessary/safe to remove this field now? | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need steering on this question please. |
||
| ! Did the get trigger an unpack which we need to now remove? | ||
| ! Based on https://code.metoffice.gov.uk/trac/lfric_apps/ticket/189 | ||
| ! call convection_fields%remove_field('convection__pres_cv_base') | ||
|
|
||
| end if | ||
|
|
||
| ! Cloud top. | ||
| if (top_height_flag) then | ||
| call convection_fields%get_field( & | ||
| 'convection__pres_cv_top', conv_cloud_top_pressure) | ||
| call invoke( & | ||
| setval_c(conv_cloud_top_icao_height, rmdi), & | ||
| aviation_icao_heights_kernel_type(conv_cloud_top_icao_height, & | ||
| conv_cloud_top_pressure)) | ||
|
|
||
| call conv_cloud_top_icao_height%write_field() | ||
|
|
||
| ! Is it necessary/safe to remove this field now? | ||
| ! call convection_fields%remove_field('convection__pres_cv_top') | ||
|
|
||
| end if | ||
|
|
||
| end subroutine icao_heights | ||
|
|
||
| end module aviation_diags_alg_mod | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't find documentation for the
<file>and<field_group>tags.