diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 9b01795782..d4124b8a96 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -500,18 +500,19 @@
-
+
- zoomed__sea_ice_tile
- zoomed__sea_tile
+ zoomed__sea_tile
surface__sea_ice_tile / (surface__sea_ice_tile + surface__sea_tile + 1.0e-16)
- zoomed__urban_tile
+ zoomed__urban_tile
- zoomed__land_ice_tile
+ zoomed__land_ice_tile
1.0 - (surface__sea_ice_tile + surface__sea_tile)
+
+ zoomed__z0m_sea
@@ -531,8 +532,11 @@
+
+ zoomed__sea_temperature
+
@@ -558,9 +562,22 @@
+
+
+
+ zoomed__sea_heat_flux
+ surface__sea_tile_heat_flux * (1.0 - surface__sea_ice_fraction)
+
+
+
+
+ zoomed__sea_moisture_flux
+ surface__sea_tile_moisture_flux * (1.0 - surface__sea_ice_fraction)
+
+
@@ -610,6 +627,7 @@
+
@@ -626,6 +644,9 @@
seaice__sea_ice_pensolar * seaice__sea_ice_fraction
+
+
+
@@ -641,6 +662,8 @@
+
+
@@ -1023,6 +1046,7 @@
+
diff --git a/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90 b/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90
index b4304ae136..55d0841406 100644
--- a/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90
+++ b/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90
@@ -3,6 +3,9 @@
! The file LICENCE, distributed with this code, contains details of the terms
! under which the code may be used.
!-------------------------------------------------------------------------------
+! Some of the content of this file has been produced with the assistance of
+! Anthropic Claude Opus 5 (Claude Code).
+!-------------------------------------------------------------------------------
!> @brief Interface to the JULES surf_couple_extra scheme
module jules_extra_alg_mod
@@ -285,6 +288,7 @@ contains
call output_diags_for_jules_snow(tile_fraction, tile_snow_mass, &
snowice_melt, &
snow_depth, tile_snow_rgrain, &
+ snow_under_canopy, n_snow_layers, &
snowpack_density, snow_layer_temp, &
snow_layer_thickness, snow_layer_ice_mass,&
snow_layer_liq_mass, snow_layer_rgrain, &
@@ -299,10 +303,12 @@ contains
water_table, soil_moist_wilt, &
soil_moist_crit, soil_moist_sat, &
grid_canopy_water,grid_throughfall, &
+ soil_sat_frac, wetness_under_soil, &
inland_basin_flow)
! Output sea ice diagnostics
- call output_diags_for_jules_seaice(tile_fraction, sea_ice_thickness, &
+ call output_diags_for_jules_seaice(tile_fraction, snowice_melt, &
+ sea_ice_thickness, &
sea_ice_temperature, sea_ice_conductivity, &
sea_ice_pensolar, melt_pond_fraction, &
melt_pond_depth)
diff --git a/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90 b/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
index c94975f491..10d7b8e54a 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
@@ -3,13 +3,18 @@
! The file LICENCE, distributed with this code, contains details of the terms
! under which the code may be used.
!-------------------------------------------------------------------------------
+! Some of the content of this file has been produced with the assistance of
+! Anthropic Claude Opus 5 (Claude Code).
+!-------------------------------------------------------------------------------
!> @brief Processes diagnostics for jules_imp_alg
module jules_imp_diags_mod
use constants_mod, only: l_def, r_def
use field_mod, only: field_type
- use jules_control_init_mod, only: n_surf_tile, n_land_tile
+ use jules_control_init_mod, only: n_surf_tile, n_land_tile, &
+ n_ssi_tile, first_sea_tile, &
+ n_sea_ice_tile, first_sea_ice_tile
use sci_weighted_ave_kernel_mod, only: weighted_ave_kernel_type
use timing_mod, only: start_timing, stop_timing, &
tik, LPROF
@@ -38,6 +43,8 @@ module jules_imp_diags_mod
logical( l_def ) :: rh1p5m_land_flag
logical( l_def ) :: latent_heat_flag
logical( l_def ) :: grid_latent_heat_flag
+ logical( l_def ) :: land_mean_latent_heat_flag
+ logical( l_def ) :: ssi_mean_latent_heat_flag
logical( l_def ) :: snomlt_surf_htf_flag
logical( l_def ) :: soil_evap_flag
logical( l_def ) :: soil_surf_ht_flux_flag
@@ -138,10 +145,14 @@ contains
! and save from 1st to 2nd loop
latent_heat_flag = init_diag(latent_heat, 'surface__latent_heat')
grid_latent_heat_flag = samp_diag('surface__grid_latent_heat')
- if (grid_latent_heat_flag .and. .not. latent_heat_flag) then
+ land_mean_latent_heat_flag = samp_diag('surface__land_mean_latent_heat')
+ ssi_mean_latent_heat_flag = samp_diag('surface__ssi_mean_latent_heat')
+ if ((grid_latent_heat_flag .or. land_mean_latent_heat_flag .or. &
+ ssi_mean_latent_heat_flag) .and. .not. latent_heat_flag) then
ignore = init_diag(latent_heat, 'surface__latent_heat', activate=.true.)
end if
- if (latent_heat_flag .or. grid_latent_heat_flag) &
+ if (latent_heat_flag .or. grid_latent_heat_flag .or. &
+ land_mean_latent_heat_flag .or. ssi_mean_latent_heat_flag) &
call invoke(setval_c(latent_heat,0.0_r_def))
! diagnostics which are needed in BL code, so allocate on 1st loop
@@ -259,7 +270,9 @@ contains
! Local variables
type( field_type ) :: land_surface_temperature, grid_canopy_evap, &
- grid_surface_temperature, grid_latent_heat, grid_sublimation
+ grid_surface_temperature, grid_latent_heat, grid_sublimation, &
+ sea_ice_surface_temperature, land_mean_heat_flux, &
+ land_mean_latent_heat, ssi_mean_heat_flux, ssi_mean_latent_heat
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_imp' )
@@ -289,6 +302,33 @@ contains
call land_surface_temperature%write_field()
end if
+ if(init_diag(sea_ice_surface_temperature, 'surface__sea_ice_surface_temperature')) then
+ call invoke(weighted_ave_kernel_type(sea_ice_surface_temperature, &
+ tile_temperature, tile_fraction, &
+ first_sea_ice_tile, n_sea_ice_tile))
+ call sea_ice_surface_temperature%write_field()
+ end if
+
+ ! Averaging the tiled flux over the land tiles, weighted by their grid-box
+ ! fractions, divides by the land fraction and so gives a mean over the
+ ! land portion of the grid-box.
+ if(init_diag(land_mean_heat_flux, 'surface__land_mean_heat_flux')) then
+ call invoke(weighted_ave_kernel_type(land_mean_heat_flux, &
+ tile_heat_flux, tile_fraction, &
+ 1, n_land_tile))
+ call land_mean_heat_flux%write_field()
+ end if
+
+ ! As above, but over the sea and sea-ice tiles, which are contiguous, so
+ ! dividing by the marine fraction and giving a mean over the sea and
+ ! sea-ice portion of the grid-box.
+ if(init_diag(ssi_mean_heat_flux, 'surface__ssi_mean_heat_flux')) then
+ call invoke(weighted_ave_kernel_type(ssi_mean_heat_flux, &
+ tile_heat_flux, tile_fraction, &
+ first_sea_tile, n_ssi_tile))
+ call ssi_mean_heat_flux%write_field()
+ end if
+
if (init_diag(grid_canopy_evap, 'surface__grid_canopy_evap')) then
call invoke(weighted_ave_kernel_type(grid_canopy_evap, &
canopy_evap, tile_fraction, &
@@ -314,6 +354,22 @@ contains
call grid_latent_heat%write_field()
end if
+ ! As above, a mean over the land portion of the grid-box
+ if (init_diag(land_mean_latent_heat, 'surface__land_mean_latent_heat')) then
+ call invoke(weighted_ave_kernel_type(land_mean_latent_heat, &
+ latent_heat, tile_fraction, &
+ 1, n_land_tile))
+ call land_mean_latent_heat%write_field()
+ end if
+
+ ! As above, a mean over the sea and sea-ice portion of the grid-box
+ if (init_diag(ssi_mean_latent_heat, 'surface__ssi_mean_latent_heat')) then
+ call invoke(weighted_ave_kernel_type(ssi_mean_latent_heat, &
+ latent_heat, tile_fraction, &
+ first_sea_tile, n_ssi_tile))
+ call ssi_mean_latent_heat%write_field()
+ end if
+
else !loop=1
! Diagnostics computed within the kernel - these are computed on 1st loop
diff --git a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90 b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
index 1129a35d79..8daf956b7a 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
@@ -3,15 +3,22 @@
! The file LICENCE, distributed with this code, contains details of the terms
! under which the code may be used.
!-------------------------------------------------------------------------------
+! Some of the content of this file has been produced with the assistance of
+! Anthropic Claude Opus 5 (Claude Code).
+!-------------------------------------------------------------------------------
!> @brief Processes diagnostics for jules_extra_alg
module jules_seaice_diags_mod
+ use constants_mod, only: r_def
use field_mod, only: field_type
use timing_mod, only: start_timing, stop_timing, tik, LPROF
-
- use jules_control_init_mod, only: first_sea_ice_tile, &
- n_sea_ice_tile
+ use sci_weighted_ave_kernel_mod, only: weighted_ave_kernel_type
+ use driver_water_constants_mod, only: latent_heat_h2o_fusion
+ use jules_control_init_mod, only: first_sea_tile, n_ssi_tile, &
+ first_sea_ice_tile, &
+ n_sea_ice_tile
+ use initialise_diagnostics_mod, only: init_diag => init_diagnostic_field
implicit none
@@ -23,6 +30,7 @@ contains
!> @brief Output diagnostics from jules_extra_alg
!> @param[in] tile_fraction Fraction of surface tiles
+ !> @param[in] snowice_melt Total snow and ice melt on tiles
!> @param[in] sea_ice_thickness Sea ice thickness
!> @param[in] sea_ice_temperature Sea ice layer temperature
!> @param[in] sea_ice_conductivity Sea ice conductivity
@@ -30,7 +38,8 @@ contains
!> @param[in] melt_pond_fraction Melt pond fraction
!> @param[in] melt_pond_depth Melt pond depth
- subroutine output_diags_for_jules_seaice(tile_fraction, sea_ice_thickness, &
+ subroutine output_diags_for_jules_seaice(tile_fraction, snowice_melt, &
+ sea_ice_thickness, &
sea_ice_temperature, sea_ice_conductivity, &
sea_ice_pensolar, melt_pond_fraction, &
melt_pond_depth)
@@ -40,13 +49,17 @@ contains
implicit none
! Prognostic fields to output
- type( field_type ), intent(in) :: tile_fraction, sea_ice_thickness, &
+ type( field_type ), intent(in) :: tile_fraction, snowice_melt, &
+ sea_ice_thickness, &
sea_ice_temperature, sea_ice_conductivity, &
sea_ice_pensolar, melt_pond_fraction, &
melt_pond_depth
! Diagnostics locally computed here from other fields
- type( field_type ) :: sea_ice_fraction
+ type( field_type ) :: sea_ice_fraction, weights_one, &
+ sea_ice_tile, sea_ice_topmelt, &
+ ice_mean_thickness, ice_mean_temperature
+ real(r_def) :: num_sice_tiles
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_seaice' )
@@ -65,6 +78,54 @@ contains
first_sea_ice_tile, n_sea_ice_tile))
call sea_ice_fraction%write_field('seaice__sea_ice_fraction')
+ ! Output sea-ice as a fraction of total grid-box
+ ! kernel calculates the avearge, so multiply after by number of tiles
+ ! to get the sum
+ if(init_diag(sea_ice_tile, 'surface__sea_ice_tile')) then
+ call tile_fraction%copy_field_properties(weights_one)
+ num_sice_tiles = real(n_sea_ice_tile, r_def)
+ call invoke(setval_c(weights_one, 1.0_r_def), &
+ weighted_ave_kernel_type(sea_ice_tile, &
+ tile_fraction, weights_one, &
+ first_sea_ice_tile, n_sea_ice_tile), &
+ inc_a_times_X(num_sice_tiles, sea_ice_tile))
+ call sea_ice_tile%write_field()
+ end if
+
+ ! Output the heat flux used in melting the top of the sea-ice, as a mean
+ ! over the marine portion of the grid-box. The tile order is land, sea,
+ ! sea-ice, so averaging over the sea and sea-ice tiles weighted by their
+ ! fractions divides by the marine fraction. The melt rate is zero on the
+ ! sea tile, so only the sea-ice contributes to the sum. It is converted
+ ! from a melt rate to an energy flux by the latent heat of fusion.
+ if(init_diag(sea_ice_topmelt, 'seaice__ssi_mean_topmelt_heat_flux')) then
+ call invoke(weighted_ave_kernel_type(sea_ice_topmelt, &
+ snowice_melt, tile_fraction, &
+ first_sea_tile, n_ssi_tile), &
+ inc_a_times_X(latent_heat_h2o_fusion, sea_ice_topmelt))
+ call sea_ice_topmelt%write_field()
+ end if
+
+ ! Aggregate the category thickness and temperature onto a single level by
+ ! averaging over the categories weighted by their fractions, which divides
+ ! by the total ice fraction and so gives a mean over the ice. This is how
+ ! sice_htf forms the bulk temperature, and the weights cancel in the ratio
+ ! so it does not matter that the fractions here are of the grid-box while
+ ! those in JULES are of the marine portion.
+ if(init_diag(ice_mean_thickness, 'seaice__ice_mean_thickness')) then
+ call invoke(weighted_ave_kernel_type(ice_mean_thickness, &
+ sea_ice_thickness, sea_ice_fraction, &
+ 1, n_sea_ice_tile))
+ call ice_mean_thickness%write_field()
+ end if
+
+ if(init_diag(ice_mean_temperature, 'seaice__ice_mean_temperature')) then
+ call invoke(weighted_ave_kernel_type(ice_mean_temperature, &
+ sea_ice_temperature, sea_ice_fraction, &
+ 1, n_sea_ice_tile))
+ call ice_mean_temperature%write_field()
+ end if
+
if ( LPROF ) call stop_timing( id, 'diags.jules_seaice' )
end subroutine output_diags_for_jules_seaice
diff --git a/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90 b/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90
index 294719b77a..9ecf6d0f08 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90
@@ -9,6 +9,7 @@ module jules_snow_diags_mod
use constants_mod, only: l_def, r_def
use field_mod, only: field_type
+ use integer_field_mod, only: integer_field_type
use timing_mod, only: start_timing, stop_timing, tik, LPROF
use sci_weighted_ave_kernel_mod, only: weighted_ave_kernel_type
@@ -62,6 +63,8 @@ contains
!> @param[in] snowice_melt Total snow and ice melt on tiles
!> @param[in] snow_depth Depth of snow on tiles
!> @param[in] tile_snow_rgrain Snow grain size on tiles
+ !> @param[in] snow_under_canopy Snow beneath the tile canopy
+ !> @param[in] n_snow_layers Number of snow layers on tiles
!> @param[in] snowpack_density Density of snow pack on tiles
!> @param[in] snow_layer_temp Temperature of snow layers on tiles
!> @param[in] snow_layer_thickness Thickness of snow layers on tiles
@@ -74,6 +77,7 @@ contains
subroutine output_diags_for_jules_snow(tile_fraction, tile_snow_mass, &
snowice_melt, &
snow_depth, tile_snow_rgrain, &
+ snow_under_canopy, n_snow_layers, &
snowpack_density, snow_layer_temp, &
snow_layer_thickness, snow_layer_ice_mass,&
snow_layer_liq_mass, snow_layer_rgrain, &
@@ -91,7 +95,8 @@ contains
snow_layer_thickness, &
snow_layer_ice_mass, &
snow_layer_liq_mass, &
- snow_layer_rgrain
+ snow_layer_rgrain, snow_under_canopy
+ type( integer_field_type ), intent(in) :: n_snow_layers
! Diagnostics computed within the kernel
type( field_type ), intent(in) :: grid_snow_mass
@@ -107,7 +112,9 @@ contains
call snowice_melt%write_field('snow__snowice_melt')
call snow_depth%write_field('snow__snow_depth')
call tile_snow_rgrain%write_field('snow__tile_snow_rgrain')
+ call n_snow_layers%write_field('snow__n_snow_layers')
call snowpack_density%write_field('snow__snowpack_density')
+ call snow_under_canopy%write_field('snow__snow_under_canopy')
call snow_layer_temp%write_field('snow__snow_layer_temp')
call snow_layer_thickness%write_field('snow__snow_layer_thickness')
call snow_layer_ice_mass%write_field('snow__snow_layer_ice_mass')
diff --git a/interfaces/jules_interface/source/diagnostics/jules_soil_diags_mod.x90 b/interfaces/jules_interface/source/diagnostics/jules_soil_diags_mod.x90
index 37b40f5436..fd927a4d15 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_soil_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_soil_diags_mod.x90
@@ -93,6 +93,8 @@ contains
!> @param[in] soil_moist_sat Soil moisture at saturation
!> @param[in,out] grid_canopy_water Grid canopy water
!> @param[in,out] grid_throughfall Grid throughfall
+ !> @param[in] soil_sat_frac Surface saturation fraction
+ !> @param[in] wetness_under_soil Deep soil saturation fraction
!> @param[in] inland_basin_flow Inland basin flow from rivers to soil
subroutine output_diags_for_jules_soil(tile_fraction, soil_moisture_content, &
@@ -103,6 +105,7 @@ contains
water_table, soil_moist_wilt, &
soil_moist_crit, soil_moist_sat, &
grid_canopy_water,grid_throughfall, &
+ soil_sat_frac, wetness_under_soil, &
inland_basin_flow)
use jules_control_init_mod, only : n_land_tile
@@ -119,6 +122,7 @@ contains
soil_moist_wilt, &
soil_moist_crit, &
soil_moist_sat, &
+ soil_sat_frac, wetness_under_soil, &
inland_basin_flow
! Diagnostics computed within the kernel
@@ -143,6 +147,8 @@ contains
call soil_moist_wilt%write_field('soil__soil_moist_wilt')
call soil_moist_crit%write_field('soil__soil_moist_crit')
call soil_moist_sat%write_field('soil__soil_moist_sat')
+ call soil_sat_frac%write_field('soil__soil_sat_frac')
+ call wetness_under_soil%write_field('soil__wetness_under_soil')
! Diagnostics locally computed here from other fields
if (grid_canopy_water_flag) then
diff --git a/interfaces/jules_interface/source/support/jules_control_init_mod.f90 b/interfaces/jules_interface/source/support/jules_control_init_mod.f90
index c47a3d643b..b0b8b15985 100644
--- a/interfaces/jules_interface/source/support/jules_control_init_mod.f90
+++ b/interfaces/jules_interface/source/support/jules_control_init_mod.f90
@@ -3,6 +3,9 @@
! The file LICENCE, distributed with this code, contains details of the terms
! under which the code may be used.
!----------------------------------------------------------------------------
+! Some of the content of this file has been produced with the assistance of
+! Anthropic Claude Opus 5 (Claude Code).
+!----------------------------------------------------------------------------
!> @brief Controls the setting of Jules high level variables which are either
!> fixed in LFRic or derived from LFRic inputs.
@@ -25,15 +28,16 @@ module jules_control_init_mod
integer(kind=i_def), protected :: n_land_tile
integer(kind=i_def), protected :: n_sea_ice_tile
+ integer(kind=i_def), protected :: n_ssi_tile
integer(kind=i_def), protected :: n_surf_tile
integer(kind=i_def), protected :: first_sea_tile
integer(kind=i_def), protected :: first_sea_ice_tile
integer(kind=i_def), protected :: soil_lev_tile
private
- public :: n_land_tile, n_sea_tile, n_sea_ice_tile, n_surf_tile, &
- first_sea_tile, first_sea_ice_tile, jules_control_init, &
- soil_lev_tile, n_surf_interp
+ public :: n_land_tile, n_sea_tile, n_sea_ice_tile, n_ssi_tile, &
+ n_surf_tile, first_sea_tile, first_sea_ice_tile, &
+ jules_control_init, soil_lev_tile, n_surf_interp
contains
@@ -147,9 +151,13 @@ subroutine jules_control_init()
n_sea_ice_tile = nice
nice_use = nice
+ ! Total number of sea and sea-ice tiles, used where a quantity is
+ ! averaged over the marine portion of the grid-box
+ n_ssi_tile = n_sea_tile + n_sea_ice_tile
+
! Total number of surface tiles, used to dimension LFRic
! multidata fields
- n_surf_tile = n_land_tile + n_sea_tile + n_sea_ice_tile
+ n_surf_tile = n_land_tile + n_ssi_tile
! Indices of the first sea and sea-ice tiles. By convection the tile
! order is always land, sea, sea-ice
diff --git a/rose-stem/app/lfric_atm/file/file_def_diags_oper_nwp_gl.xml b/rose-stem/app/lfric_atm/file/file_def_diags_oper_nwp_gl.xml
index fb5ee25716..b710d4aaec 100644
--- a/rose-stem/app/lfric_atm/file/file_def_diags_oper_nwp_gl.xml
+++ b/rose-stem/app/lfric_atm/file/file_def_diags_oper_nwp_gl.xml
@@ -7,6 +7,7 @@
+
@@ -19,6 +20,10 @@
+
+
+
+
@@ -146,6 +151,9 @@
+
+
+
diff --git a/science/gungho/source/physics/multidata_field_dimensions_mod.F90 b/science/gungho/source/physics/multidata_field_dimensions_mod.F90
index c9b6f96df6..b545c8bb2a 100644
--- a/science/gungho/source/physics/multidata_field_dimensions_mod.F90
+++ b/science/gungho/source/physics/multidata_field_dimensions_mod.F90
@@ -97,7 +97,7 @@ subroutine sync_multidata_field_dimensions()
call set_zoom_axis_attr( &
'surface_tiles_sea_ice_zoom_axis', &
get_multidata_field_dimension('land_tiles')+1, &
- 1, &
+ get_multidata_field_dimension('sea_ice_categories'), &
tolerate_missing_axes)
! Settings for some land tile zoom axes
call set_zoom_axis_attr( &