Migrate jules_pftparm metadata to jules-shared #41 left an unresolved feature resulting from the implementation of the duplicate namelist functionality in LFRic apps, but not in JULES standalone. The presence of length keyword in the metadata causes the configurator tool to declare the variable as an array, which causes problems when trying to assign the value from config%jules_pftparm to jules_pftparm. For now length=: resides in jules-um & jules-standalone rather than jules-shared. This required an amendment in the parent metadata, for each item for example:
jules-um & jules-standalone
[namelist:jules_pftparm=a_wl_io]
length=:
And also amendments in jules-lfric
[namelist:jules_pftparm=a_wl_io]
fail-if=
!ns=
but this was unsatisfactory and a long term solution was required. After discussion, the best solution was to treat the jules_pftparm namelist in the same way as LFRic apps i.e. one per PFT, allowing the metadata to be as fully shared as possible. JULES standalone and the UM would also benefit from vastly improved management of the namelist inputs for different surface configurations. See the JULES wiki Redesigning JULES tile input which documents the issues. This issue explores this implementation in JULES standalone.
⚠️ Monstrous upgrade macro ⚠️
The upgrade macro has been made more complicated as a result of the need to correct many jules_pftparm items entries that are trigger ignored, before applying the macro required for this ticket. This reinforces the need for better management of this namelist. The reasons for these errors and how they have been rectified in this macro are:
- Upgrade macro was not robust as they only included existing configurations based on
npft = [5, 9, 13] and have not included a default e.g. setting them all to missing data, which would be picked up by the validator macro or the checking routines in JULES at runtime.
- Added a macro to fix the issue based on the existing macro or set to missing data e.g.
fire_mort_io (vn5.3_t872), INFERNO (vn4.4_t136), radiation parameters for scaling against observations (no macro)
- Namelist has been copied from existing configurations with a different number of PFTs and the trigger ignored values have not been updated to the new configuration.
- Where the item was of the form
[x]*npft, the upgrade macro was robust, an upgrade macro didn't exist or the value was different from the upgrade macro and there weren't too may apps affected in Rose stem, I took a pragmatic approach and corrected these by hand e.g. rose-stem/app/loobos_jules_es_1p0*; vn5.5_t864, vn5.3_t766, vn4.8_t541
- Error when applying the upgrade macro, but existing upgrade macro is robust.
- Repeated the existing upgrade macro in this upgrade macro.
The upgrade macro in this issue has been split into two. The first part of the macro (vn8.2_t115a) corrects the jules_pftparm namelist and the second (vn8.2_t115) converts the corrected namelist into one namelist per PFT. This is useful as the corrections to the namelist can easily be seen before they are split into separate namelists. These may need to be combined before it is merged to main and is a question for James Bruten (@james-bruten-mo), but it is very useful to have them as separate macros.
Rose stem tests with npft=9 with ncpft=4
This issue also highlighted the need to be able to identify the surface types present in a configuration when an example upgrade macro was tested so users had an example to follow to write upgrade macros after this issue was resolved. This is documented on the related issue #136, which now blocks this one as the affected Rose stem tests should be corrected before jules_pftparm is converted.
Original jules_pftparm method
Before this change the way that jules_pftparm items were read into JULES is illustrated here using the standalone method for a_wl_io as an example:
src/initialisation/standalone/params/init_pftparm.inc
SUBROUTINE init_pftparm_jules
USE pftparm_io, ONLY: jules_pftparm, init_pftparm_allocated
READ(namelist_unit, NML = jules_pftparm, IOSTAT = ERROR, IOMSG = iomessage)
CALL init_pftparm_allocated()
END SUBROUTINE init_pftparm_jules
src/science/params/pftparm_io_mod.F90
MODULE pftparm_io
REAL(KIND=real_jlslsm) :: a_wl_io(npft_max) = rmdi
NAMELIST / jules_pftparm/ a_wl_io
CONTAINS
SUBROUTINE init_pftparm_allocated()
USE pftparm, ONLY: a_wl
a_wl(:) = a_wl_io(1:npft)
END SUBROUTINE init_pftparm_allocated
src/science/params/pftparm_mod.F90
REAL(KIND=real_jlslsm), ALLOCATABLE :: a_wl(:)
ALLOCATE( a_wl(npft))
a_wl(:) = rmdi
Where USE pftparm, ONLY: a_wl is the value used in the JULES science code. All JULES tile namelist inputs pretty much follow this design.
Multiple instance jules_pftparm method
There are now multiple instances of jules_pftparm which are looped over when the namelist is read in by read_nml_jules_pftparm (JULES & UM versions both call the same routine). The members of jules_pftparm are now scalars rather than arrays. When each instance is read in, the instance is mapped to the correct position in the pftparm allocated arrays (pftparm_mod). It is therefore the pftparm_mod arrays that must be broadcast in the UM rather than jules_pftparm namelist when it is read. This means that the broadcasting does not happen in the same routine as the reading which breaks the UM Rose stem test that checks for namelist broadcasting.
ERROR: ./jules/src/science/params/pftparm_io_mod.F90 (read_nml_jules_pftparm)
Namelist "jules_pftparm" is read, but has no corresponding broadcast
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Checks completed with 1 failure %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ERROR: Failed files:
* ./jules/src/science/params/pftparm_io_mod.F90
src/initialisation/standalone/params/init_pftparm.inc
SUBROUTINE init_pftparm_jules
USE pftparm_io, ONLY: read_nml_jules_pftparm
CALL read_nml_jules_pftparm (nml_dir)
END SUBROUTINE init_pftparm_jules
src/science/params/pftparm_io_mod.F90
MODULE pftparm_io
REAL(KIND=real_jlslsm) :: a_wl_io = rmdi
NAMELIST / jules_pftparm/ a_wl_io
CONTAINS
SUBROUTINE read_nml_jules_pftparm(unitnumber)
< Different wrapper depending on UM or JULES >
CALL read_nml_jules_pftparm_instances(unitnumber)
< UM version - Now the allocated arrays are filled, broadcast these to other processors >
END SUBROUTINE read_nml_jules_pftparm
SUBROUTINE read_nml_jules_pftparm_instances(unitnumber)
n = 0
DO ! loop over jules_pftparm instances
READ (UNIT = unitnumber, NML = jules_pftparm, IOSTAT = errorstatus, &
IOMSG = iomessage)
IF (errorstatus == IOSTAT_END) THEN
EXIT
ELSE IF (errorstatus == 0) THEN
! Map jules_pftparm instance to correct position in allocated array
CALL init_pftparm_allocated()
END IF
END DO
END SUBROUTINE read_nml_jules_pftparm_instances
SUBROUTINE init_pftparm_allocated()
USE pftparm, ONLY: a_wl
USE jules_surface_types_mod, ONLY: map_nml_instance_to_tile_number
i = map_nml_instance_to_tile_number ( 'jules_pftparm', pft_name_io )
a_wl(i) = a_wl_io
END SUBROUTINE init_pftparm_allocated
[FATAL ERROR] READ_NML_JULES_PFTPARM_INSTANCES:
Error reading namelist JULES_PFTPARM
IoMsg: Cannot match namelist object name a_wl_io
Please check input list against code.
[FATAL ERROR] READ_NML_JULES_PFTPARM_INSTANCES: Number of instances of jules_pftparm does not equal npft.
Migrate
jules_pftparmmetadata to jules-shared #41 left an unresolved feature resulting from the implementation of the duplicate namelist functionality in LFRic apps, but not in JULES standalone. The presence of length keyword in the metadata causes the configurator tool to declare the variable as an array, which causes problems when trying to assign the value fromconfig%jules_pftparmtojules_pftparm. For nowlength=:resides in jules-um & jules-standalone rather than jules-shared. This required an amendment in the parent metadata, for each item for example:jules-um & jules-standalone
And also amendments in jules-lfric
but this was unsatisfactory and a long term solution was required. After discussion, the best solution was to treat the
jules_pftparmnamelist in the same way as LFRic apps i.e. one per PFT, allowing the metadata to be as fully shared as possible. JULES standalone and the UM would also benefit from vastly improved management of the namelist inputs for different surface configurations. See the JULES wiki Redesigning JULES tile input which documents the issues. This issue explores this implementation in JULES standalone.The upgrade macro has been made more complicated as a result of the need to correct many
jules_pftparmitems entries that are trigger ignored, before applying the macro required for this ticket. This reinforces the need for better management of this namelist. The reasons for these errors and how they have been rectified in this macro are:npft = [5, 9, 13]and have not included a default e.g. setting them all to missing data, which would be picked up by the validator macro or the checking routines in JULES at runtime.fire_mort_io(vn5.3_t872), INFERNO (vn4.4_t136), radiation parameters for scaling against observations (no macro)[x]*npft, the upgrade macro was robust, an upgrade macro didn't exist or the value was different from the upgrade macro and there weren't too may apps affected in Rose stem, I took a pragmatic approach and corrected these by hand e.g. rose-stem/app/loobos_jules_es_1p0*; vn5.5_t864, vn5.3_t766, vn4.8_t541The upgrade macro in this issue has been split into two. The first part of the macro (vn8.2_t115a) corrects the
jules_pftparmnamelist and the second (vn8.2_t115) converts the corrected namelist into one namelist per PFT. This is useful as the corrections to the namelist can easily be seen before they are split into separate namelists. These may need to be combined before it is merged to main and is a question for James Bruten (@james-bruten-mo), but it is very useful to have them as separate macros.Rose stem tests with
npft=9withncpft=4This issue also highlighted the need to be able to identify the surface types present in a configuration when an example upgrade macro was tested so users had an example to follow to write upgrade macros after this issue was resolved. This is documented on the related issue #136, which now blocks this one as the affected Rose stem tests should be corrected before
jules_pftparmis converted.Original
jules_pftparmmethodBefore this change the way that
jules_pftparmitems were read into JULES is illustrated here using the standalone method fora_wl_ioas an example:src/initialisation/standalone/params/init_pftparm.inc
src/science/params/pftparm_io_mod.F90
src/science/params/pftparm_mod.F90
Where
USE pftparm, ONLY: a_wlis the value used in the JULES science code. All JULES tile namelist inputs pretty much follow this design.Multiple instance
jules_pftparmmethodThere are now multiple instances of
jules_pftparmwhich are looped over when the namelist is read in byread_nml_jules_pftparm(JULES & UM versions both call the same routine). The members ofjules_pftparmare now scalars rather than arrays. When each instance is read in, the instance is mapped to the correct position in the pftparm allocated arrays (pftparm_mod). It is therefore thepftparm_modarrays that must be broadcast in the UM rather thanjules_pftparmnamelist when it is read. This means that the broadcasting does not happen in the same routine as the reading which breaks the UM Rose stem test that checks for namelist broadcasting.src/initialisation/standalone/params/init_pftparm.inc
src/science/params/pftparm_io_mod.F90