From 88faf33b44336aa053dbf109398a4f0a810da323 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Fri, 29 May 2026 16:41:40 +0100
Subject: [PATCH 01/20] new diagnostics needed
---
applications/lfric_atm/metadata/field_def_diags.xml | 2 ++
.../source/algorithm/jules_extra_alg_mod.x90 | 3 ++-
.../source/diagnostics/jules_soil_diags_mod.x90 | 7 ++++++-
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index a17d884f90..8ce47824f9 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -637,6 +637,8 @@
+
+
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 68241339ae..c3d2a16062 100644
--- a/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90
+++ b/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90
@@ -290,7 +290,8 @@ contains
surface_runoff, sub_surface_runoff, &
water_table, soil_moist_wilt, &
soil_moist_crit, soil_moist_sat, &
- grid_canopy_water,grid_throughfall)
+ grid_canopy_water,grid_throughfall, &
+ soil_sat_frac, wetness_under_soil)
! Output sea ice diagnostics
call output_diags_for_jules_seaice(tile_fraction, sea_ice_thickness, &
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 a3db5c3613..ac95601295 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
subroutine output_diags_for_jules_soil(tile_fraction, soil_moisture_content, &
canopy_water, soil_moisture, &
@@ -101,7 +103,8 @@ contains
surface_runoff, sub_surface_runoff, &
water_table, soil_moist_wilt, &
soil_moist_crit, soil_moist_sat, &
- grid_canopy_water,grid_throughfall)
+ grid_canopy_water,grid_throughfall, &
+ soil_sat_frac, wetness_under_soil)
use jules_control_init_mod, only : n_land_tile
@@ -140,6 +143,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
From 68ca1a799261dc8b70fb4f9e617a52053ce1620c Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Thu, 4 Jun 2026 16:49:24 +0100
Subject: [PATCH 02/20] add snow prognostics
---
applications/lfric_atm/metadata/field_def_diags.xml | 2 ++
.../source/algorithm/jules_extra_alg_mod.x90 | 1 +
.../source/diagnostics/jules_snow_diags_mod.x90 | 6 +++++-
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 8ce47824f9..46e9719734 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -606,6 +606,7 @@
+
@@ -1011,6 +1012,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 c3d2a16062..3e0a7ad6dc 100644
--- a/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90
+++ b/interfaces/jules_interface/source/algorithm/jules_extra_alg_mod.x90
@@ -277,6 +277,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, &
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 d48f4f0140..bae757384e 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90
@@ -74,6 +74,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 +92,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 +109,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')
From 946049d937b19e76934e4bee7fd15a1eb9a9a6cb Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Thu, 4 Jun 2026 16:55:59 +0100
Subject: [PATCH 03/20] forgot doxygen comments
---
.../jules_interface/source/diagnostics/jules_snow_diags_mod.x90 | 2 ++
1 file changed, 2 insertions(+)
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 bae757384e..4aae8eec3b 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_snow_diags_mod.x90
@@ -62,6 +62,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
From 009038299065ef2f1fc0f10eb59c771d9e46ef4c Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Tue, 21 Jul 2026 20:34:26 +0100
Subject: [PATCH 04/20] sea and sea-ice temperature
---
applications/lfric_atm/metadata/field_def_diags.xml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 46e9719734..920ffde086 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -527,6 +527,10 @@
+
+
+ zoomed__sea_ice_temperature
+ zoomed__sea_temperature
From 51c312bdf685f8e68877408213b4446858cd6594 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Wed, 22 Jul 2026 11:25:52 +0100
Subject: [PATCH 05/20] bugfixes
---
.../source/diagnostics/jules_snow_diags_mod.x90 | 1 +
.../source/diagnostics/jules_soil_diags_mod.x90 | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
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 4aae8eec3b..40bfe5b8ae 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
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
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 ac95601295..a48e6efd09 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_soil_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_soil_diags_mod.x90
@@ -119,7 +119,8 @@ contains
water_table, &
soil_moist_wilt, &
soil_moist_crit, &
- soil_moist_sat
+ soil_moist_sat, &
+ soil_sat_frac, wetness_under_soil
! Diagnostics computed within the kernel
type( field_type ), intent(in) :: throughfall
From 417d2669c024ef3f5fd30988b656215f4b530253 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Thu, 23 Jul 2026 14:59:03 +0100
Subject: [PATCH 06/20] fix sea-ice area fraction for coupled models
---
applications/lfric_atm/metadata/field_def_diags.xml | 8 ++++----
applications/lfric_atm/metadata/grid_def_main.xml | 10 ++++++++++
.../source/physics/multidata_field_dimensions_mod.F90 | 2 +-
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 920ffde086..002a1227cc 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -496,9 +496,11 @@
-
+
+ surface__tile_fraction
+
+
- zoomed__sea_ice_tile
zoomed__sea_tile
surface__sea_ice_tile / (surface__sea_ice_tile + surface__sea_tile + 1.0e-16)
@@ -527,9 +529,7 @@
-
- zoomed__sea_ice_temperature
zoomed__sea_temperature
diff --git a/applications/lfric_atm/metadata/grid_def_main.xml b/applications/lfric_atm/metadata/grid_def_main.xml
index bf68a5bcf5..6c004a19ed 100644
--- a/applications/lfric_atm/metadata/grid_def_main.xml
+++ b/applications/lfric_atm/metadata/grid_def_main.xml
@@ -132,6 +132,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/science/gungho/source/physics/multidata_field_dimensions_mod.F90 b/science/gungho/source/physics/multidata_field_dimensions_mod.F90
index b53cbfbdfd..79d9484c26 100644
--- a/science/gungho/source/physics/multidata_field_dimensions_mod.F90
+++ b/science/gungho/source/physics/multidata_field_dimensions_mod.F90
@@ -95,7 +95,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( &
From ecb42ccd1e0039bf9c590749027c724cd4744f38 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Thu, 23 Jul 2026 15:18:43 +0100
Subject: [PATCH 07/20] sea_ice surface temperature
---
applications/lfric_atm/metadata/field_def_diags.xml | 11 ++++++-----
applications/lfric_atm/metadata/grid_def_main.xml | 2 +-
.../source/diagnostics/jules_imp_diags_mod.x90 | 13 +++++++++++--
3 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 002a1227cc..4ffd8ed576 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -499,14 +499,14 @@
surface__tile_fraction
-
+
- 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)
@@ -530,9 +530,10 @@
- zoomed__sea_temperature
+ zoomed__sea_temperature
+
diff --git a/applications/lfric_atm/metadata/grid_def_main.xml b/applications/lfric_atm/metadata/grid_def_main.xml
index 6c004a19ed..18df3c3df4 100644
--- a/applications/lfric_atm/metadata/grid_def_main.xml
+++ b/applications/lfric_atm/metadata/grid_def_main.xml
@@ -132,7 +132,7 @@
-
+
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 13a36d4bf6..e263c891ac 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
@@ -9,7 +9,8 @@ module jules_imp_diags_mod
use constants_mod, only: l_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_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
@@ -259,7 +260,8 @@ 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
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_imp' )
@@ -289,6 +291,13 @@ 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
+
if (init_diag(grid_canopy_evap, 'surface__grid_canopy_evap')) then
call invoke(weighted_ave_kernel_type(grid_canopy_evap, &
canopy_evap, tile_fraction, &
From 3d06e070f2bc4190ceba862898d92d86b50a33c3 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Fri, 24 Jul 2026 14:13:07 +0100
Subject: [PATCH 08/20] xios doesn't work for sea-ice fraction
---
.../lfric_atm/metadata/field_def_diags.xml | 5 +---
.../lfric_atm/metadata/grid_def_main.xml | 10 -------
.../diagnostics/jules_seaice_diags_mod.x90 | 26 ++++++++++++++++---
3 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 1e45ede8c0..280b32989a 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -500,10 +500,7 @@
-
- surface__tile_fraction
-
-
+
zoomed__sea_tile
surface__sea_ice_tile / (surface__sea_ice_tile + surface__sea_tile + 1.0e-16)
diff --git a/applications/lfric_atm/metadata/grid_def_main.xml b/applications/lfric_atm/metadata/grid_def_main.xml
index b312e33fea..954b013f96 100644
--- a/applications/lfric_atm/metadata/grid_def_main.xml
+++ b/applications/lfric_atm/metadata/grid_def_main.xml
@@ -140,16 +140,6 @@
-
-
-
-
-
-
-
-
-
-
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..2db721952e 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
@@ -7,11 +7,13 @@
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 jules_control_init_mod, only: first_sea_ice_tile, &
+ n_sea_ice_tile
+ use initialise_diagnostics_mod, only: init_diag => init_diagnostic_field
implicit none
@@ -46,7 +48,9 @@ contains
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
+ real(r_def) :: num_sice_tiles
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_seaice' )
@@ -65,6 +69,20 @@ 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
+
if ( LPROF ) call stop_timing( id, 'diags.jules_seaice' )
end subroutine output_diags_for_jules_seaice
From 2930e2662ac4bef723877ea8c0d5069157dbc969 Mon Sep 17 00:00:00 2001
From: Ubuntu
Date: Mon, 10 Aug 2026 14:45:09 +0000
Subject: [PATCH 09/20] Add open sea sensible heat flux and evaporation
diagnostics
Adds surface__sea_heat_flux and surface__sea_moisture_flux, equivalent
to UM STASH 3-228 SFC SH FLX FROM OPEN SEA:SEA MN and 3-232 EVAP FROM
OPEN SEA: SEA MEAN.
This is an XML-only change. The open-sea tile is extracted from the
existing surface__tile_heat_flux and surface__tile_moisture_flux fields
using the surface_tiles_sea_zoom axis, then the pseudo-level coordinate
is dropped, following the pattern already used for surface__sea_tile and
surface__sea_temperature.
A third field is then needed for each because the UM diagnostics are sea
means. JULES applies h_sea = (1 - ice_fract) * h_sea and the equivalent
for e_sea in the "Calculate sea mean diagnostics" block of
jules_ssi_sf_implicit, so the flux is averaged over the whole sea
portion of the grid-box with the sea-ice part contributing zero. The
LFRic tiled fluxes are per unit open water, being formed as a residual
divided by the open-sea tile fraction, so they are multiplied by
(1 - surface__sea_ice_fraction) to match. The rescaling cannot be
combined with the earlier steps as it needs both operands on the same
grid.
Some of the content of this change has been produced with the assistance
of Anthropic Claude Opus 5 (Claude Code).
---
applications/lfric_atm/metadata/field_def_diags.xml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 280b32989a..af9e23d7ad 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -560,7 +560,16 @@
+
+
+
+ zoomed__sea_heat_flux
+ temporary__sea_heat_flux * (1.0 - surface__sea_ice_fraction)
+
+
+ zoomed__sea_moisture_flux
+ temporary__sea_moisture_flux * (1.0 - surface__sea_ice_fraction)
From b451ebbb7ba7c3f5bb97e494029f85e3ac8dd768 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Mon, 10 Aug 2026 15:53:11 +0100
Subject: [PATCH 10/20] fix names
---
applications/lfric_atm/metadata/field_def_diags.xml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index af9e23d7ad..c0129eac96 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -563,13 +563,13 @@
- zoomed__sea_heat_flux
- temporary__sea_heat_flux * (1.0 - surface__sea_ice_fraction)
+ zoomed__sea_heat_flux
+ surface__sea_tile_heat_flux * (1.0 - surface__sea_ice_fraction)
- zoomed__sea_moisture_flux
- temporary__sea_moisture_flux * (1.0 - surface__sea_ice_fraction)
+ zoomed__sea_moisture_flux
+ surface__sea_tile_moisture_flux * (1.0 - surface__sea_ice_fraction)
From 2ba3ad87a76dc9b390983522787e977cc96727b9 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Mon, 10 Aug 2026 16:04:48 +0100
Subject: [PATCH 11/20] add to OS file
---
rose-stem/app/lfric_atm/file/file_def_diags_oper_nwp_gl.xml | 2 ++
1 file changed, 2 insertions(+)
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..75d2861db3 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
@@ -146,6 +146,8 @@
+
+
From 0f9215d8536bb4540e24b69cc84ce7d86d0c7f95 Mon Sep 17 00:00:00 2001
From: Ubuntu
Date: Tue, 11 Aug 2026 08:51:35 +0000
Subject: [PATCH 12/20] Add sea-ice top melt heat flux diagnostic
Adds seaice__sea_mean_topmelt_heat_flux, equivalent to UM STASH 3-235
SEAICE TOP MELT LH FLX:SEA MEAN.
Unlike the open sea flux diagnostics this cannot be done in XML alone.
The UM sums sf_diag%sice_mlt_htf over the sea-ice categories, but LFRic
never sets sf_diag%simlt so that array is never filled. The underlying
melt rate is available though, as fluxes%sice_melt is copied onto the
sea-ice tiles of snowice_melt in jules_imp_kernel_mod, so the diagnostic
is reconstructed from there. Averaging over the tiles has to be done in
the code rather than in XIOS, following the precedent set for
surface__sea_ice_tile.
The tile order is land, sea, sea-ice, so averaging the tiled melt rate
over the sea and sea-ice tiles, weighted by their fractions, divides by
the marine fraction of the grid-box. This gives the ice_fract_ncat
weighting the UM applies in jules_ssi_sf_implicit directly, with no
rescaling needed in XML, because jules_imp_kernel_mod sets the melt rate
on the sea tile to zero and so only the sea-ice contributes to the sum.
The latent heat of fusion then converts the melt rate to an energy flux.
Note this covers only the surface melt contribution. The second term the
UM accumulates in sice_htf, where the ice surface temperature overshoots
the melting point, has no LFRic equivalent as sice_htf is never called.
Some of the content of this change has been produced with the assistance
of Anthropic Claude Opus 5 (Claude Code).
---
.../lfric_atm/metadata/field_def_diags.xml | 2 ++
.../source/algorithm/jules_extra_alg_mod.x90 | 6 +++-
.../diagnostics/jules_seaice_diags_mod.x90 | 31 ++++++++++++++++---
3 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index c0129eac96..531a87939f 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -638,6 +638,8 @@
seaice__sea_ice_pensolar * seaice__sea_ice_fraction
+
+
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 8c8ac35e4f..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
@@ -304,7 +307,8 @@ contains
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_seaice_diags_mod.x90 b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
index 2db721952e..ab0de683f7 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_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 Processes diagnostics for jules_extra_alg
module jules_seaice_diags_mod
@@ -11,7 +14,9 @@ module jules_seaice_diags_mod
use field_mod, only: field_type
use timing_mod, only: start_timing, stop_timing, tik, LPROF
use sci_weighted_ave_kernel_mod, only: weighted_ave_kernel_type
- use jules_control_init_mod, only: first_sea_ice_tile, &
+ use driver_water_constants_mod, only: latent_heat_h2o_fusion
+ use jules_control_init_mod, only: first_sea_tile, n_sea_tile, &
+ first_sea_ice_tile, &
n_sea_ice_tile
use initialise_diagnostics_mod, only: init_diag => init_diagnostic_field
@@ -25,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
@@ -32,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)
@@ -42,14 +49,15 @@ 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, weights_one, &
- sea_ice_tile
+ sea_ice_tile, sea_ice_topmelt
real(r_def) :: num_sice_tiles
integer( tik ) :: id
@@ -83,6 +91,21 @@ contains
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__sea_mean_topmelt_heat_flux')) then
+ call invoke(weighted_ave_kernel_type(sea_ice_topmelt, &
+ snowice_melt, tile_fraction, &
+ first_sea_tile, &
+ n_sea_tile + n_sea_ice_tile), &
+ inc_a_times_X(latent_heat_h2o_fusion, sea_ice_topmelt))
+ call sea_ice_topmelt%write_field()
+ end if
+
if ( LPROF ) call stop_timing( id, 'diags.jules_seaice' )
end subroutine output_diags_for_jules_seaice
From ac579908adc16949670ef4947d031795cbc94f2a Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Tue, 11 Aug 2026 10:19:59 +0100
Subject: [PATCH 13/20] name updates
---
applications/lfric_atm/metadata/field_def_diags.xml | 11 +++++------
.../source/diagnostics/jules_seaice_diags_mod.x90 | 2 +-
.../app/lfric_atm/file/file_def_diags_oper_nwp_gl.xml | 1 +
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 531a87939f..d6965c786b 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -563,13 +563,13 @@
- zoomed__sea_heat_flux
- surface__sea_tile_heat_flux * (1.0 - surface__sea_ice_fraction)
+ 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)
+ zoomed__sea_moisture_flux
+ surface__sea_tile_moisture_flux * (1.0 - surface__sea_ice_fraction)
@@ -638,8 +638,7 @@
seaice__sea_ice_pensolar * seaice__sea_ice_fraction
-
-
+
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 ab0de683f7..10f1987b55 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
@@ -97,7 +97,7 @@ contains
! 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__sea_mean_topmelt_heat_flux')) then
+ 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, &
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 75d2861db3..001bef4d64 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
@@ -148,6 +148,7 @@
+
From b484e19473ef504341b693ef157ed8463e3a0436 Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Tue, 11 Aug 2026 10:46:04 +0100
Subject: [PATCH 14/20] fixes to code
---
.../source/diagnostics/jules_seaice_diags_mod.x90 | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
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 10f1987b55..c6c0b8c678 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
@@ -10,7 +10,7 @@
module jules_seaice_diags_mod
- use constants_mod, only: r_def
+ use constants_mod, only: r_def, i_def
use field_mod, only: field_type
use timing_mod, only: start_timing, stop_timing, tik, LPROF
use sci_weighted_ave_kernel_mod, only: weighted_ave_kernel_type
@@ -59,6 +59,7 @@ contains
type( field_type ) :: sea_ice_fraction, weights_one, &
sea_ice_tile, sea_ice_topmelt
real(r_def) :: num_sice_tiles
+ integer(i_def) :: num_ssi_tiles
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_seaice' )
@@ -98,10 +99,11 @@ contains
! 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
+ num_ssi_tiles = n_sea_tile + n_sea_ice_tile
call invoke(weighted_ave_kernel_type(sea_ice_topmelt, &
snowice_melt, tile_fraction, &
first_sea_tile, &
- n_sea_tile + n_sea_ice_tile), &
+ num_ssi_tiles), &
inc_a_times_X(latent_heat_h2o_fusion, sea_ice_topmelt))
call sea_ice_topmelt%write_field()
end if
From 3c340f261acb6adc8c2d1ec63012bcbeabe88257 Mon Sep 17 00:00:00 2001
From: Ubuntu
Date: Tue, 11 Aug 2026 09:52:29 +0000
Subject: [PATCH 15/20] Add land-mean surface heat and latent heat flux
diagnostics
Adds surface__land_mean_heat_flux and surface__land_mean_latent_heat,
the surface sensible and latent heat fluxes averaged over the land
portion of the grid-box, matching the UM's land-mean surface flux
diagnostics.
Both are computed with weighted_ave_kernel_type over the land tiles,
weighted by the grid-box tile fractions. Because the land tile
fractions sum to the land fraction, that average divides by the land
fraction and so reproduces the UM sum over land tiles of the tiled flux
weighted by the land-relative tile fraction: LFRic's tile_fraction is a
grid-box fraction, and the JULES interface divides it by the land
fraction when it fills frac_surft. The tiled fields used are the same
ones the UM sums, ftl_surft and le_surft.
The latent heat flux is only accumulated when it has been requested, so
the new diagnostic is added to the existing test that activates it, and
both diagnostics are output on the second loop only, alongside the
other tile-averaged diagnostics.
The two fields are added to the lfric_atm field definitions and to the
hourly instantaneous group of the operational global output stream,
alongside the other grid-mean surface fluxes there.
Some of the content of this change has been produced with the
assistance of Anthropic Claude Opus 5 (Claude Code).
---
.../lfric_atm/metadata/field_def_diags.xml | 2 ++
.../diagnostics/jules_imp_diags_mod.x90 | 32 +++++++++++++++++--
.../file/file_def_diags_oper_nwp_gl.xml | 2 ++
3 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index d6965c786b..336407efe2 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -565,6 +565,7 @@
zoomed__sea_heat_flux
surface__sea_tile_heat_flux * (1.0 - surface__sea_ice_fraction)
+
@@ -572,6 +573,7 @@
surface__sea_tile_moisture_flux * (1.0 - surface__sea_ice_fraction)
+
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 41740d8962..f8a91bb6c0 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_imp_diags_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 Processes diagnostics for jules_imp_alg
module jules_imp_diags_mod
@@ -39,6 +42,7 @@ 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 ) :: snomlt_surf_htf_flag
logical( l_def ) :: soil_evap_flag
logical( l_def ) :: soil_surf_ht_flux_flag
@@ -139,10 +143,13 @@ 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')
+ if ((grid_latent_heat_flag .or. land_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) &
call invoke(setval_c(latent_heat,0.0_r_def))
! diagnostics which are needed in BL code, so allocate on 1st loop
@@ -261,7 +268,8 @@ contains
! Local variables
type( field_type ) :: land_surface_temperature, grid_canopy_evap, &
grid_surface_temperature, grid_latent_heat, grid_sublimation, &
- sea_ice_surface_temperature
+ sea_ice_surface_temperature, land_mean_heat_flux, &
+ land_mean_latent_heat
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_imp' )
@@ -291,6 +299,16 @@ contains
call land_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
+
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, &
@@ -323,6 +341,14 @@ 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
+
else !loop=1
! Diagnostics computed within the kernel - these are computed on 1st loop
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 001bef4d64..f5235ed971 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
@@ -19,6 +19,8 @@
+
+
From db25b618bccd1f57b15e40a0df84cb568c6690fb Mon Sep 17 00:00:00 2001
From: iboutle <135141261+iboutle@users.noreply.github.com>
Date: Tue, 11 Aug 2026 12:09:19 +0100
Subject: [PATCH 16/20] change order
---
.../source/diagnostics/jules_imp_diags_mod.x90 | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
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 f8a91bb6c0..a1d5407caa 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
@@ -299,6 +299,13 @@ 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.
@@ -309,13 +316,6 @@ contains
call land_mean_heat_flux%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
-
if (init_diag(grid_canopy_evap, 'surface__grid_canopy_evap')) then
call invoke(weighted_ave_kernel_type(grid_canopy_evap, &
canopy_evap, tile_fraction, &
From 8ace74f53a284a05fb5092fd88196f8b8b18cee4 Mon Sep 17 00:00:00 2001
From: Ubuntu
Date: Tue, 11 Aug 2026 11:15:14 +0000
Subject: [PATCH 17/20] Add sea and sea-ice mean surface heat and latent heat
flux diagnostics
Adds surface__ssi_mean_heat_flux and surface__ssi_mean_latent_heat, the
surface sensible and latent heat fluxes averaged over the sea and
sea-ice portion of the grid-box, matching the UM's mean sea surface
sensible heat flux and its open sea and sea-ice latent heat flux.
Both are computed with weighted_ave_kernel_type over the sea and
sea-ice tiles, weighted by the grid-box tile fractions. The tile order
is land, sea, sea-ice, so those tiles are contiguous, and because their
fractions sum to the marine fraction the average divides by it and so
gives a mean over the marine portion of the grid-box.
For the sensible heat flux this reproduces the UM residual, the
grid-box mean flux less the land contribution divided by the marine
fraction, because the interface fills the sea tile with exactly the
residual needed to make the tile fractions and tiled fluxes recover the
grid-box mean. For the latent heat flux it reproduces the UM sum of
the sea-mean evaporation and sea-ice sublimation terms, since JULES
rescales those by fractions of the sea whereas the tile fractions here
are fractions of the grid-box.
The two fields are added to the lfric_atm field definitions and to the
hourly instantaneous group of the operational global output stream,
alongside the land means.
Some of the content of this change has been produced with the
assistance of Anthropic Claude Opus 5 (Claude Code).
---
.../lfric_atm/metadata/field_def_diags.xml | 2 +
.../diagnostics/jules_imp_diags_mod.x90 | 37 ++++++++++++++++---
.../file/file_def_diags_oper_nwp_gl.xml | 2 +
3 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 336407efe2..4ab48c1d29 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -566,6 +566,7 @@
zoomed__sea_heat_flux
surface__sea_tile_heat_flux * (1.0 - surface__sea_ice_fraction)
+
@@ -574,6 +575,7 @@
+
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 a1d5407caa..8e5d3c36ae 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
@@ -10,9 +10,10 @@
module jules_imp_diags_mod
- use constants_mod, only: l_def, r_def
+ use constants_mod, only: i_def, l_def, r_def
use field_mod, only: field_type
use jules_control_init_mod, only: n_surf_tile, n_land_tile, &
+ n_sea_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, &
@@ -43,6 +44,7 @@ module jules_imp_diags_mod
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
@@ -144,12 +146,13 @@ contains
latent_heat_flag = init_diag(latent_heat, 'surface__latent_heat')
grid_latent_heat_flag = samp_diag('surface__grid_latent_heat')
land_mean_latent_heat_flag = samp_diag('surface__land_mean_latent_heat')
- if ((grid_latent_heat_flag .or. land_mean_latent_heat_flag) .and. &
- .not. latent_heat_flag) then
+ 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 .or. &
- land_mean_latent_heat_flag) &
+ 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
@@ -269,13 +272,19 @@ contains
type( field_type ) :: land_surface_temperature, grid_canopy_evap, &
grid_surface_temperature, grid_latent_heat, grid_sublimation, &
sea_ice_surface_temperature, land_mean_heat_flux, &
- land_mean_latent_heat
+ land_mean_latent_heat, ssi_mean_heat_flux, ssi_mean_latent_heat
+ integer( i_def ) :: num_ssi_tiles
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_imp' )
! Output prognostic fields - always output these on 2nd loop
if (loop == 2) then
+
+ ! The tile order is land, sea, sea-ice, so the sea and sea-ice tiles are
+ ! contiguous and can be averaged over together
+ num_ssi_tiles = n_sea_tile + n_sea_ice_tile
+
call tile_heat_flux%write_field('surface__tile_heat_flux')
call tile_moisture_flux%write_field('surface__tile_moisture_flux')
call tile_temperature%write_field('surface__tile_temperature')
@@ -316,6 +325,16 @@ contains
call land_mean_heat_flux%write_field()
end if
+ ! As above, but over the sea and sea-ice tiles, 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, num_ssi_tiles))
+ 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, &
@@ -349,6 +368,14 @@ contains
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, num_ssi_tiles))
+ 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/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 f5235ed971..42a6285a75 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
@@ -21,6 +21,8 @@
+
+
From 14cd336987d21350588f9653582f3e2675cc829d Mon Sep 17 00:00:00 2001
From: Ubuntu
Date: Tue, 11 Aug 2026 12:04:53 +0000
Subject: [PATCH 18/20] Derive the number of sea and sea-ice tiles in
jules_control_init
The diagnostics that average over the marine portion of the grid-box
each worked out the number of sea plus sea-ice tiles for themselves.
Derive it once as n_ssi_tile in jules_control_init, alongside the other
tile counts and indices, and use it from jules_imp_diags and
jules_seaice_diags.
n_surf_tile is now expressed in terms of it as well, so the two counts
cannot drift apart.
Some of the content of this change has been produced with the
assistance of Anthropic Claude Opus 5 (Claude Code).
---
.../diagnostics/jules_imp_diags_mod.x90 | 20 +++++++------------
.../diagnostics/jules_seaice_diags_mod.x90 | 9 +++------
.../source/support/jules_control_init_mod.f90 | 16 +++++++++++----
3 files changed, 22 insertions(+), 23 deletions(-)
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 8e5d3c36ae..10d7b8e54a 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_imp_diags_mod.x90
@@ -10,10 +10,10 @@
module jules_imp_diags_mod
- use constants_mod, only: i_def, l_def, r_def
+ 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, &
- n_sea_tile, first_sea_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, &
@@ -273,18 +273,12 @@ contains
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( i_def ) :: num_ssi_tiles
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_imp' )
! Output prognostic fields - always output these on 2nd loop
if (loop == 2) then
-
- ! The tile order is land, sea, sea-ice, so the sea and sea-ice tiles are
- ! contiguous and can be averaged over together
- num_ssi_tiles = n_sea_tile + n_sea_ice_tile
-
call tile_heat_flux%write_field('surface__tile_heat_flux')
call tile_moisture_flux%write_field('surface__tile_moisture_flux')
call tile_temperature%write_field('surface__tile_temperature')
@@ -325,13 +319,13 @@ contains
call land_mean_heat_flux%write_field()
end if
- ! As above, but over the sea and sea-ice tiles, so dividing by the marine
- ! fraction and giving a mean over the sea and sea-ice portion of the
- ! grid-box.
+ ! 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, num_ssi_tiles))
+ first_sea_tile, n_ssi_tile))
call ssi_mean_heat_flux%write_field()
end if
@@ -372,7 +366,7 @@ contains
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, num_ssi_tiles))
+ first_sea_tile, n_ssi_tile))
call ssi_mean_latent_heat%write_field()
end if
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 c6c0b8c678..ae37ff9aff 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
@@ -10,12 +10,12 @@
module jules_seaice_diags_mod
- use constants_mod, only: r_def, i_def
+ use constants_mod, only: r_def
use field_mod, only: field_type
use timing_mod, only: start_timing, stop_timing, tik, LPROF
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_sea_tile, &
+ 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
@@ -59,7 +59,6 @@ contains
type( field_type ) :: sea_ice_fraction, weights_one, &
sea_ice_tile, sea_ice_topmelt
real(r_def) :: num_sice_tiles
- integer(i_def) :: num_ssi_tiles
integer( tik ) :: id
if ( LPROF ) call start_timing( id, 'diags.jules_seaice' )
@@ -99,11 +98,9 @@ contains
! 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
- num_ssi_tiles = n_sea_tile + n_sea_ice_tile
call invoke(weighted_ave_kernel_type(sea_ice_topmelt, &
snowice_melt, tile_fraction, &
- first_sea_tile, &
- num_ssi_tiles), &
+ 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
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
From 6211ca46270023dd4aa41cdb57f3f14565113950 Mon Sep 17 00:00:00 2001
From: Ubuntu
Date: Tue, 11 Aug 2026 12:35:12 +0000
Subject: [PATCH 19/20] Add the open sea roughness length diagnostic
The sea tile of z0m_tile is filled from the JULES prognostic z0msea in
jules_exp_kernel_mod, so extracting it needs no new code: a zoom onto
the sea tile in the XML gives the open sea roughness length directly.
Some of the content of this change has been produced with the assistance
of Anthropic Claude Opus 5 (Claude Code).
---
applications/lfric_atm/metadata/field_def_diags.xml | 2 ++
rose-stem/app/lfric_atm/file/file_def_diags_oper_nwp_gl.xml | 1 +
2 files changed, 3 insertions(+)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 4ab48c1d29..0f71d805d9 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -511,6 +511,8 @@
1.0 - (surface__sea_ice_tile + surface__sea_tile)
+
+ zoomed__z0m_sea
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 42a6285a75..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 @@
+
From 15088dbad7b97e464709e67489d26526df5eb8b5 Mon Sep 17 00:00:00 2001
From: Ubuntu
Date: Tue, 11 Aug 2026 15:57:26 +0000
Subject: [PATCH 20/20] Add the mean over ice sea-ice thickness and temperature
diagnostics
Adds seaice__ice_mean_thickness and seaice__ice_mean_temperature, the
sea-ice thickness and bulk temperature aggregated from the categories
onto a single level, matching the UM's sea-ice depth and sea-ice
temperature after timestep. Those two UM fields are the non-category
twins of the by-category thickness and top layer temperature, and are
what the UM uses when only one category is active.
Both are formed with weighted_ave_kernel_type over the sea-ice
categories, weighted by the category fractions, so the kernel divides
by the total ice fraction and returns a mean over the ice. For the
temperature this is exactly the bulk temperature that sice_htf forms
internally, which is otherwise held only in the JULES prognostic
structure and so cannot be output. For the thickness the same average
is correct because the category thicknesses are physical depths, as
their use in the conduction term of sice_htf shows, rather than
fraction weighted quantities.
The weights are the sea-ice tile fractions already extracted from the
tile fractions for seaice__sea_ice_fraction. These are fractions of
the grid-box whereas JULES works in fractions of the marine portion,
but the normalisation cancels in the ratio so the result is unchanged.
Where there is no ice the total weight is zero, the kernel leaves the
output at zero, and both fields should be masked on the ice fraction
before use.
Some of the content of this change has been produced with the
assistance of Anthropic Claude Opus 5 (Claude Code).
---
.../lfric_atm/metadata/field_def_diags.xml | 2 ++
.../diagnostics/jules_seaice_diags_mod.x90 | 25 +++++++++++++++++--
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/applications/lfric_atm/metadata/field_def_diags.xml b/applications/lfric_atm/metadata/field_def_diags.xml
index 0f71d805d9..d4124b8a96 100644
--- a/applications/lfric_atm/metadata/field_def_diags.xml
+++ b/applications/lfric_atm/metadata/field_def_diags.xml
@@ -645,6 +645,8 @@
+
+
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 ae37ff9aff..8daf956b7a 100644
--- a/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
+++ b/interfaces/jules_interface/source/diagnostics/jules_seaice_diags_mod.x90
@@ -56,8 +56,9 @@ contains
melt_pond_depth
! Diagnostics locally computed here from other fields
- type( field_type ) :: sea_ice_fraction, weights_one, &
- sea_ice_tile, sea_ice_topmelt
+ 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
@@ -105,6 +106,26 @@ contains
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