Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
| maggiehendry | Maggie Hendry | Met Office | 2026-08-21 |
| DanCopsey | Dan Copsey | Met Office | 2026-08-24 |
| Pierre-siddall | Pierre Siddall | Met Office | 2026-08-26 |
| mo-arthurargles | Arthur Argles | Met Office | 2026-09-04 |
237 changes: 217 additions & 20 deletions src/control/shared/next_gen_biogeochem_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ MODULE next_gen_biogeochem_mod

SUBROUTINE next_gen_biogeochem( &
!IN control vars
asteps_since_triffid,land_pts,nnpft,nmasst,veg3_ctrl, &
asteps_since_triffid,a_step,land_pts,nnpft,nmasst,veg3_ctrl, &
ainfo, &
!IN parms
litter_parms,red_parms, &
Expand Down Expand Up @@ -62,6 +62,9 @@ SUBROUTINE next_gen_biogeochem( &
! INTEGERS with INTENT in
!----------------------------------------------------------------------------
INTEGER, INTENT(IN) :: land_pts, nnpft, nmasst
INTEGER, INTENT(IN) :: a_step
! Current atmospheric timestep number, used to
! determine when the phenology timestep falls due.

!----------------------------------------------------------------------------
! Variables with INTENT inout
Expand Down Expand Up @@ -113,7 +116,7 @@ SUBROUTINE next_gen_biogeochem( &
! Call the Vegetation Biogeochemistry model
IF (veg_index_pts > 0) CALL veg3_run_ctrl( &
!IN Control vars
asteps_since_triffid,land_pts,nnpft,nmasst,veg_index_pts, &
asteps_since_triffid,a_step,land_pts,nnpft,nmasst,veg_index_pts, &
veg_index,veg3_ctrl,ainfo, &
!IN parms
litter_parms,red_parms, &
Expand All @@ -130,8 +133,8 @@ END SUBROUTINE next_gen_biogeochem
!------------------------------------------------------------------------------
SUBROUTINE veg3_run_ctrl( &
!IN Control vars
asteps_since_triffid,land_pts,nnpft,nmasst,veg_index_pts, &
veg_index,veg3_ctrl,ainfo, &
asteps_since_triffid,a_step,land_pts,nnpft,nmasst, &
veg_index_pts,veg_index,veg3_ctrl,ainfo, &
!IN parms
litter_parms,red_parms, &
!IN state
Expand All @@ -140,7 +143,6 @@ SUBROUTINE veg3_run_ctrl( &
)

!Only get the data structures - the data comes through the calling tree

USE veg3_parm_mod, ONLY: veg3_ctrl_type,litter_parm_type,red_parm_type
USE veg3_field_mod, ONLY: veg_state_type,red_state_type,red_veg3_couple
USE veg3_litter_mod, ONLY: veg3_litter
Expand All @@ -162,6 +164,10 @@ SUBROUTINE veg3_run_ctrl( &
! IN Number of atmospheric timesteps since last call
! to TRIFFID.

INTEGER, INTENT(IN) :: a_step
! IN Current atmospheric timestep number, used to
! determine when the phenology timestep falls due.

!-----------------------------------------------------------------------------
! Objects with INTENT IN
!-----------------------------------------------------------------------------
Expand All @@ -188,39 +194,54 @@ SUBROUTINE veg3_run_ctrl( &
REAL:: &
npp_dr(land_pts,nnpft), &
! Mean NPP for driving vegetation (kg C/m2/s).
g_leaf_dr(land_pts,nnpft), &
! Mean phenology-driven leaf turnover rate for driving litterfall and
! vegetation dynamics (s-1).
local_litter(land_pts,nnpft), &
! Litter production (kg C/m2/s).
growth(land_pts,nnpft), &
! growth (kg C/m2/s).
mort_add(land_pts,nnpft,nmasst), &
mort_add(land_pts,nnpft,nmasst)
! mortality above baseline (/m2)
demographic_lit(land_pts,nnpft)
! demographic litter aggregated to PFT

!End of headers

!Initialise Arrays
npp_dr(:,:) = 0.0
mort_add(:,:,:) = 0.0
npp_dr(:,:) = 0.0
g_leaf_dr(:,:) = 0.0
mort_add(:,:,:) = 0.0

!-----------------------------------------------------------------------------
! Work out the phenology at its own timestep, appending to the accumulated
! leaf turnover rates, and (on the vegetation dynamics timestep) diagnose
! the mean phenology-driven leaf turnover rate for driving litterfall and
! vegetation dynamics. This mirrors the phenology/TRIFFID timestep split in
! veg-veg2a_jls_mod.
!-----------------------------------------------------------------------------
CALL veg3_phenol_couple(veg_index_pts,veg_index,veg3_ctrl,land_pts,nnpft, &
a_step,asteps_since_triffid,veg_state,g_leaf_dr)

! Now call vegetation model
IF (asteps_since_triffid == veg3_ctrl%nstep_trif) THEN

!Call veg3_phenol()

!Call Litter
CALL veg3_Litter( &
!IN Control vars
veg_index_pts,veg_index,veg3_ctrl,land_pts,nnpft, &
!IN parms
litter_parms, &
!IN fields
g_leaf_dr, &
!IN state
veg_state, &
! OUT Fields
local_litter &
!OUT Diagnostics
)

! Record driving g_leaf_dr and convert to s-1 -> (360 days)-1
veg_state%g_leaf_dr_out(:,:) = g_leaf_dr * rsec_per_day * 360.0

!CALL Allocation/Nitrogen/NSC


Expand All @@ -229,13 +250,16 @@ SUBROUTINE veg3_run_ctrl( &
! Use the accumulated npp from sf_expl. Copy to new variable for driving
! veg dynamics

npp_dr = veg_state%npp_acc / (rsec_per_day * veg3_ctrl%triffid_period)
! Reset accumulation to zero - note this can be used to pass a negative flux back to JULES.
npp_dr = veg_state%npp_acc / veg3_ctrl%dt_red

! Record driving npp_dr and convert to s-1 -> (360 days)-1
veg_state%npp_dr_out(:,:) = npp_dr * rsec_per_day * 360

! Reset accumulation to zero - note this can be used to pass a negative flux
! back to JULES.
veg_state%npp_acc(:,:)=0.0
growth = npp_dr - local_litter

!Call Litter

!Call Allocation/Nitrogen/NSC

!Now on Mass classes
Expand All @@ -251,16 +275,14 @@ SUBROUTINE veg3_run_ctrl( &
!Call Veg Dynamics - in this case RED
CALL veg3_red_dynamic( &
!IN control vars
rsec_per_day,veg_index_pts,veg_index,veg3_ctrl,land_pts, &
veg3_ctrl%dt_red,veg_index_pts,veg_index,veg3_ctrl,land_pts, &
nnpft,nmasst, &
!IN RED_parms
red_parms, &
!IN fields
growth,mort_add, &
!IN state
veg_state,red_state, &
! OUT Fields
demographic_lit &
veg_state,red_state &
!OUT Diagnostics
)

Expand All @@ -282,4 +304,179 @@ SUBROUTINE veg3_run_ctrl( &

END SUBROUTINE veg3_run_ctrl

!------------------------------------------------------------------------------
SUBROUTINE veg3_phenol_couple( &
!IN Control vars
veg_index_pts,veg_index,veg3_ctrl,land_pts,nnpft, &
a_step,asteps_since_triffid, &
!IN state
veg_state, &
!OUT Diagnostics
g_leaf_dr &
)

! Diagnoses leaf phenology and the mean phenology-driven leaf turnover rate
! that drives litterfall/vegetation dynamics, in veg1/veg2.

!Only get the data structures - the data comes through the calling tree
USE jules_vegetation_mod, ONLY: l_phenol
USE veg3_parm_mod, ONLY: veg3_ctrl_type
USE veg3_field_mod, ONLY: veg_state_type
USE phenol_mod, ONLY: phenol

!Access some parameters direct from module
USE conversions_mod, ONLY: rsec_per_day

IMPLICIT NONE

!----------------------------------------------------------------------------
! Integers with INTENT IN
!----------------------------------------------------------------------------
INTEGER, INTENT(IN) :: land_pts,nnpft,veg_index_pts,veg_index(land_pts)

INTEGER, INTENT(IN) :: a_step
! Current atmospheric timestep number, used to
! determine when the phenology timestep falls due.

INTEGER, INTENT(IN) :: asteps_since_triffid
! Number of atmospheric timesteps since last call to
! vegetation dynamics.

!-----------------------------------------------------------------------------
! Objects with INTENT IN
!-----------------------------------------------------------------------------
TYPE(veg3_ctrl_type),INTENT(IN) :: veg3_ctrl

!-----------------------------------------------------------------------------
! Objects with INTENT INOUT
!-----------------------------------------------------------------------------
TYPE(veg_state_type),INTENT(IN OUT) :: veg_state

!-----------------------------------------------------------------------------
! Reals with INTENT OUT
!-----------------------------------------------------------------------------
REAL, INTENT(OUT) :: g_leaf_dr(land_pts,nnpft)
! Mean phenology-driven leaf turnover rate for driving
! litterfall and vegetation dynamics (s-1).

!-----------------------------------------------------------------------------
!Local Vars
!-----------------------------------------------------------------------------
REAL :: &
gam_trif, &
! Inverse vegetation dynamics coupling timestep ((360d)-1).
lai_bal_dummy(land_pts)
! Dummy lai to pass into phenol routine, gets around bug where
! FORTRAN does not accept veg_state%lai_bal as optional
! argument.

INTEGER :: l,n,k
! Loop counters.

!End of headers

g_leaf_dr(:,:) = 0.0

!-----------------------------------------------------------------------------
! Work out the phenology at its own timestep, appending to the accumulated
! leaf turnover rates. This is called independently of the vegetation
! dynamics timestep, mirroring the phenology/TRIFFID timestep split in
! veg-veg2a_jls_mod.
!-----------------------------------------------------------------------------
IF (l_phenol .AND. MOD(a_step,veg3_ctrl%nstep_phen) == 0) THEN

veg_state%phen(:,:) = 1.0
lai_bal_dummy(:) = 0.0

DO n = 1,nnpft
lai_bal_dummy(:) = veg_state%lai_bal(:,n)

! Diagnose the mean leaf turnover rate driving phenology over the
! elapsed phenology period, mirroring g_leaf_day in veg-veg2a_jls_mod.
DO k = 1,veg_index_pts
l = veg_index(k)
veg_state%g_leaf_day(l,n) = veg_state%g_leaf_acc(l,n) / &
veg3_ctrl%dt_phen_360d
END DO

CALL phenol(land_pts,veg_index_pts,n,veg_index,veg3_ctrl%dt_phen_360d, &
veg_state%g_leaf_day(:,n),veg_state%canht(:,n), &
veg_state%lai(:,n),veg_state%g_leaf_phen(:,n),lai_bal_dummy)

DO k = 1,veg_index_pts
l = veg_index(k)

! Save the diagnosed LAI immediately following the phenology update,
veg_state%lai_phen(l,n) = veg_state%lai(l,n)

! Accumulate the mean phenological leaf turnover rate for driving
! vegetation dynamics.
veg_state%g_leaf_phen_acc(l,n) = veg_state%g_leaf_phen_acc(l,n) &
+ veg_state%g_leaf_phen(l,n) * &
veg3_ctrl%dt_phen_360d

! Reset the accumulated physiological leaf turnover ready for the
! next phenology period.
veg_state%g_leaf_acc(l,n) = 0.0

IF (veg_state%lai_bal(l,n) > 0) veg_state%phen(l,n) = &
veg_state%lai(l,n)/veg_state%lai_bal(l,n)

END DO

END DO

END IF

!-----------------------------------------------------------------------------
! On the vegetation dynamics timestep, diagnose the mean phenology-driven
! leaf turnover rate that will drive litterfall and vegetation dynamics.
!-----------------------------------------------------------------------------
IF (asteps_since_triffid == veg3_ctrl%nstep_trif) THEN

! Calculate the inverse vegetation dynamics coupling timestep.
gam_trif = 360.0 / REAL(veg3_ctrl%triffid_period)

DO n = 1,nnpft
DO k = 1,veg_index_pts
l = veg_index(k)

IF (l_phenol) THEN
! Diagnose the mean phenological leaf turnover rate over the
! coupling period, in JULES-standard per-second units.
g_leaf_dr(l,n) = veg_state%g_leaf_phen_acc(l,n) * &
gam_trif / (rsec_per_day * 360.0)

! Reset the accumulated phenological turnover ready for the next
! coupling period.
veg_state%g_leaf_phen_acc(l,n) = 0.0
ELSE
! No phenology - fall back to the raw accumulated physiological
! leaf turnover rate, as in veg-veg2a_jls_mod.
g_leaf_dr(l,n) = veg_state%g_leaf_acc(l,n) * gam_trif / &
(rsec_per_day * 360.0)

veg_state%g_leaf_acc(l,n) = 0.0
END IF

! Ensure the turnover will not remove more leaf than is present over
! the vegetation dynamics timestep. If it does, reduce the rate so
! that the turnover does not exceed the current LAI.
IF (veg_state%lai(l,n) > 0.0) THEN
IF (g_leaf_dr(l,n) * veg3_ctrl%dt_red > 1.0) THEN
g_leaf_dr(l,n) = 1.0 / veg3_ctrl%dt_red

END IF
ELSE
g_leaf_dr(l,n) = 0.0

END IF

END DO
END DO

END IF

END SUBROUTINE veg3_phenol_couple

END MODULE next_gen_biogeochem_mod
8 changes: 5 additions & 3 deletions src/control/shared/surf_couple_extra_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ MODULE surf_couple_extra_mod
!
! [Met Office Ref SC0237]
! *****************************COPYRIGHT****************************************
!
! Some of the content of this file has been produced with the assistance of
! Met Office Github Copilot Enterprise.
USE um_types, ONLY: real_jlslsm

IMPLICIT NONE
Expand Down Expand Up @@ -1073,7 +1076,7 @@ SUBROUTINE surf_couple_extra( &

CALL next_gen_biogeochem( &
!IN control vars
asteps_since_triffid,land_pts,nnpft,nmasst,veg3_ctrl, &
asteps_since_triffid,a_step,land_pts,nnpft,nmasst,veg3_ctrl, &
ainfo, &
!IN parms
litter_parms,red_parms, &
Expand All @@ -1087,10 +1090,9 @@ SUBROUTINE surf_couple_extra( &
! - Uses non-veg tilepts
! - Accesses fields via USE statements

! Note use lai_bal for now as we don't yet have phenology
CALL sparm (land_pts,nsurft,surft_pts,ainfo%surft_index, &
veg_state%frac,veg_state%canht, &
veg_state%lai_bal,psparms%z0m_soil_gb, &
veg_state%lai,psparms%z0m_soil_gb, &
psparms%catch_snow_surft,psparms%catch_surft, &
psparms%z0_surft,psparms%z0h_bare_surft,urban_param%ztm_gb)

Expand Down
Loading
Loading