diff --git a/CMakeLists.txt b/CMakeLists.txt index 9618bd2ea..93ebd1337 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,7 +268,6 @@ else() src/util/cable_common.F90 src/shared/casa_offline_inout.F90 src/shared/casa_ncdf.F90 - src/offline/cable_io_decomp.F90 src/offline/cable_iovars.F90 src/offline/cable_surface_types.F90 src/offline/cable_define_types.F90 @@ -278,6 +277,8 @@ else() src/offline/cable_abort.F90 src/offline/cable_checks.F90 src/offline/cable_cru_TRENDY.F90 + src/offline/cable_diagnostics_casa.F90 + src/offline/cable_diagnostics_core.F90 src/offline/cable_driver_common.F90 src/offline/cable_initialise.F90 src/offline/cable_input.F90 @@ -299,14 +300,24 @@ else() src/offline/cbl_model_driver_offline.F90 src/offline/landuse_inout.F90 src/offline/spincasacnp.F90 + src/util/aggregator.F90 src/util/cable_climate_type_mod.F90 src/util/masks_cbl.F90 src/util/cable_array_utils.F90 + src/util/cable_enum.F90 + src/util/cable_grid_reductions.F90 + src/util/cable_timing_utils.F90 src/util/netcdf/cable_netcdf_decomp_util.F90 src/util/netcdf/cable_netcdf.F90 src/util/netcdf/cable_netcdf_internal.F90 src/util/netcdf/cable_netcdf_stub_types.F90 src/util/netcdf/nf90/cable_netcdf_nf90.F90 + src/util/io/output/cable_output_core.F90 + src/util/io/output/cable_output_decomp.F90 + src/util/io/output/cable_output_reduction_buffers.F90 + src/util/io/output/cable_output_types.F90 + src/util/io/output/cable_output_utils.F90 + src/util/io/output/cable_output.F90 ) target_link_libraries(cable_common PRIVATE PkgConfig::NETCDF) diff --git a/documentation/docs/user_guide/constants/physical_constants.md b/documentation/docs/user_guide/constants/physical_constants.md index b4344b993..256b272a0 100644 --- a/documentation/docs/user_guide/constants/physical_constants.md +++ b/documentation/docs/user_guide/constants/physical_constants.md @@ -20,4 +20,4 @@ | cswat | 4.218E3 | \( J \cdot kg^{-1} \cdot K^{-1} \) | Specific heat for water at \( 0^{\circ}C \) | | density_liq | 1000.0 | \( kg \cdot m^{-3} \) | Density of liquid water | | density_ice | 921.0 | \( kg \cdot m^{-3} \) | Density of ice | - +| c_molar_mass | 1.201E-5 | \( \micro g / mol \) | Molar mass of carbon | diff --git a/src/offline/cable_define_types.F90 b/src/offline/cable_define_types.F90 index df411ca31..bf8580998 100644 --- a/src/offline/cable_define_types.F90 +++ b/src/offline/cable_define_types.F90 @@ -24,7 +24,8 @@ !#define UM_BUILD yes MODULE cable_def_types_mod -USE cable_climate_type_mod, ONLY: climate_type + USE cable_climate_type_mod, ONLY: climate_type + USE aggregator_mod, ONLY: aggregator_real32_1d_t, new_aggregator ! Contains all variables which are not subroutine-internal @@ -264,6 +265,7 @@ MODULE cable_def_types_mod qssrf, & ! sublimation snage, & ! snow age snowd, & ! snow depth (liquid water) + totsdepth, & ! total snow depth (m) smelt, & ! snow melt ssdnn, & ! average snow density tss, & ! surface temperature (weighted soil, snow) @@ -453,12 +455,18 @@ MODULE cable_def_types_mod frpw, & ! plant respiration (woody component) (g C m-2 s-1) frpr, & ! plant respiration (root component) (g C m-2 s-1) frs, & ! soil respiration (g C m-2 s-1) + fra, & ! autotrophic respiration (g C m-2 s-1) fnee, & ! net carbon flux (g C m-2 s-1) frday, & ! daytime leaf resp fnv, & ! net rad. avail. to canopy (W/m2) fev, & ! latent hf from canopy (W/m2) epot, & ! total potential evaporation + et, & ! total evapotranspiration (kg/m2/s) + eint, & ! interception evaporation from wet canopy (kg/m2/s) + tveg, & ! vegation transpiration (kg/m2/s) + esoil, & ! soil evaporation (kg/m2/s) fnpp, & ! npp flux + fgpp, & ! gpp flux fevw_pot,& ! potential lat heat from canopy gswx_T, & ! ! stom cond for water cdtq, & ! drag coefficient for momentum @@ -474,6 +482,7 @@ MODULE cable_def_types_mod ghflux, & ! ground heat flux (W/m2) ??? precis, & ! throughfall to soil, after snow (mm) qscrn, & ! specific humudity at screen height (g/g) + qmom, & ! surface momentum flux rnet, & ! net radiation absorbed by surface (W/m2) rniso, & !isothermal net radiation absorbed by surface (W/m2) segg, & ! latent heatfl from soil mm @@ -531,6 +540,8 @@ MODULE cable_def_types_mod ! vh_js ! !litter thermal conductivity (Wm-2K-1) and vapour diffusivity (m2s-1) REAL(r_2), DIMENSION(:), POINTER :: kthLitt, DvLitt + type(aggregator_real32_1d_t), allocatable :: tscrn_max_daily + type(aggregator_real32_1d_t), allocatable :: tscrn_min_daily END TYPE canopy_type @@ -553,6 +564,9 @@ MODULE cable_def_types_mod latitude,& ! latitude lwabv, & ! long wave absorbed by vegetation qssabs, & ! absorbed short-wave radiation for soil + swnet, & ! net shortwave radiation absorbed by surface (W/m^2) + lwnet, & ! net longwave radiation absorbed by surface (W/m^2) + rnet, & ! net radiation absorbed by surface (W/m^2) transd, & ! frac SW diffuse transmitted through canopy trad, & ! radiative temperature (soil and veg) otrad ! radiative temperature on previous timestep (ACCESS) @@ -917,6 +931,7 @@ SUBROUTINE alloc_soil_snow_type(var, mp) ALLOCATE( var% smass(mp,msn) ) ALLOCATE( var% snage(mp) ) ALLOCATE( var% snowd(mp) ) + ALLOCATE( var% totsdepth(mp) ) ALLOCATE( var% smelt(mp) ) ALLOCATE( var% ssdn(mp,msn) ) ALLOCATE( var% ssdnn(mp) ) @@ -1122,6 +1137,7 @@ SUBROUTINE alloc_canopy_type(var, mp) ALLOCATE( var% frpw(mp) ) ALLOCATE( var% frpr(mp) ) ALLOCATE( var% frs(mp) ) + ALLOCATE( var% fra(mp) ) ALLOCATE( var% fnee(mp) ) ALLOCATE( var% frday(mp) ) ALLOCATE( var% fnv(mp) ) @@ -1135,6 +1151,7 @@ SUBROUTINE alloc_canopy_type(var, mp) ALLOCATE( var% ghflux(mp) ) ALLOCATE( var% precis(mp) ) ALLOCATE( var% qscrn(mp) ) + ALLOCATE( var% qmom(mp) ) ALLOCATE( var% rnet(mp) ) ALLOCATE( var% rniso(mp) ) ALLOCATE( var% segg(mp) ) @@ -1154,7 +1171,12 @@ SUBROUTINE alloc_canopy_type(var, mp) ALLOCATE( var% ga_cor(mp) ) !REV_CORR variable ALLOCATE ( var % evapfbl(mp,ms) ) ALLOCATE( var% epot(mp) ) + ALLOCATE( var% et(mp) ) + ALLOCATE( var% eint(mp) ) + ALLOCATE( var% tveg(mp) ) + ALLOCATE( var% esoil(mp) ) ALLOCATE( var% fnpp(mp) ) + ALLOCATE( var% fgpp(mp) ) ALLOCATE( var% fevw_pot(mp) ) ALLOCATE( var% gswx_T(mp) ) ALLOCATE( var% cdtq(mp) ) @@ -1186,6 +1208,9 @@ SUBROUTINE alloc_canopy_type(var, mp) ALLOCATE (var % kthLitt(mp)) ALLOCATE (var % DvLitt(mp)) + var%tscrn_max_daily = new_aggregator(source_data=var%tscrn); CALL var%tscrn_max_daily%init(method="max") + var%tscrn_min_daily = new_aggregator(source_data=var%tscrn); CALL var%tscrn_min_daily%init(method="min") + END SUBROUTINE alloc_canopy_type ! ------------------------------------------------------------------------------ @@ -1205,6 +1230,9 @@ SUBROUTINE alloc_radiation_type(var, mp) ALLOCATE( var% lwabv(mp) ) ALLOCATE( var% qcan(mp,mf,nrb) ) ALLOCATE( var% qssabs(mp) ) + ALLOCATE( var% swnet(mp) ) + ALLOCATE( var% lwnet(mp) ) + ALLOCATE( var% rnet(mp) ) ALLOCATE( var% rhocdf(mp,nrb) ) ALLOCATE( var% rniso(mp,mf) ) ALLOCATE( var% scalex(mp,mf) ) @@ -1565,6 +1593,7 @@ SUBROUTINE dealloc_soil_snow_type(var) DEALLOCATE( var% smass ) DEALLOCATE( var% snage ) DEALLOCATE( var% snowd ) + DEALLOCATE( var% totsdepth ) DEALLOCATE( var% smelt ) DEALLOCATE( var% ssdn ) DEALLOCATE( var% ssdnn ) @@ -1756,6 +1785,7 @@ SUBROUTINE dealloc_canopy_type(var) DEALLOCATE( var% frpw ) DEALLOCATE( var% frpr ) DEALLOCATE( var% frs ) + DEALLOCATE( var% fra ) DEALLOCATE( var% fnee ) DEALLOCATE( var% frday ) DEALLOCATE( var% fnv ) @@ -1769,6 +1799,7 @@ SUBROUTINE dealloc_canopy_type(var) DEALLOCATE( var% ghflux ) DEALLOCATE( var% precis ) DEALLOCATE( var% qscrn ) + DEALLOCATE( var% qmom ) DEALLOCATE( var% rnet ) DEALLOCATE( var% rniso ) DEALLOCATE( var% segg ) @@ -1788,7 +1819,12 @@ SUBROUTINE dealloc_canopy_type(var) DEALLOCATE( var% ga_cor ) !REV_CORR variable DEALLOCATE ( var % evapfbl ) DEALLOCATE( var% epot ) + DEALLOCATE( var% et ) + DEALLOCATE( var% eint ) + DEALLOCATE( var% tveg ) + DEALLOCATE( var% esoil ) DEALLOCATE( var% fnpp ) + DEALLOCATE( var% fgpp ) DEALLOCATE( var% fevw_pot ) DEALLOCATE( var% gswx_T ) DEALLOCATE( var% cdtq ) @@ -1811,6 +1847,9 @@ SUBROUTINE dealloc_canopy_type(var) DEALLOCATE (var % kthLitt) DEALLOCATE (var % DvLitt) + DEALLOCATE(var%tscrn_max_daily) + DEALLOCATE(var%tscrn_min_daily) + END SUBROUTINE dealloc_canopy_type ! ------------------------------------------------------------------------------ @@ -1829,6 +1868,9 @@ SUBROUTINE dealloc_radiation_type(var) DEALLOCATE( var% lwabv ) DEALLOCATE( var% qcan ) DEALLOCATE( var% qssabs ) + DEALLOCATE( var% swnet ) + DEALLOCATE( var% lwnet ) + DEALLOCATE( var% rnet ) DEALLOCATE( var% rhocdf ) DEALLOCATE( var% rniso ) DEALLOCATE( var% scalex ) diff --git a/src/offline/cable_diagnostics_casa.F90 b/src/offline/cable_diagnostics_casa.F90 new file mode 100644 index 000000000..72937d685 --- /dev/null +++ b/src/offline/cable_diagnostics_casa.F90 @@ -0,0 +1,485 @@ +module cable_diagnostics_casa_mod + use casavariable, only: casa_flux + use casavariable, only: casa_pool + use casavariable, only: casa_met + + use casaparm, only: LEAF + use casaparm, only: WOOD + use casaparm, only: FROOT + + use casaparm, only: MIC + use casaparm, only: SLOW + use casaparm, only: PASS + + use casaparm, only: METB + use casaparm, only: STR + use casaparm, only: CWD + + use cable_timing_utils_mod, only: seconds_per_day + + use cable_phys_constants_mod, only: c_molar_mass + + use cable_common_module, only: l_casacnp + + use cable_common_module, only: cable_user + + use cable_io_vars_module, only: output, patchout + + use cable_output_prototype_v2_mod, only: cable_output_variable_t + use cable_output_prototype_v2_mod, only: attribute => cable_output_attribute_t + use cable_output_prototype_v2_mod, only: DIM_PATCH => CABLE_OUTPUT_DIM_PATCH + + use cable_netcdf_mod, only: CABLE_NETCDF_FLOAT + + use aggregator_mod, only: new_aggregator + + use cable_checks_module, only: ranges + + implicit none + private + + public :: cable_diagnostics_casa + +contains + + function cable_diagnostics_casa(casaflux, casapool, casamet) result(casa_output_variables) + type(casa_flux), intent(in) :: casaflux + type(casa_pool), intent(in) :: casapool + type(casa_met), intent(in) :: casamet + type(cable_output_variable_t), allocatable :: casa_output_variables(:) + + if (.not. l_casacnp) then + allocate(casa_output_variables(0)) + return + end if + + casa_output_variables = [ & + cable_output_variable_t( & + field_name="crmplant_froot", & + netcdf_name="RootResp", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%AutoResp, & + active=output%carbon .or. output%casa, & + patchout=output%patch .or. patchout%casa, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%crmplant(:, FROOT)), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Fine Root Autotrophic respiration") & + ] & + ), & + cable_output_variable_t( & + field_name="crmplant_wood", & + netcdf_name="StemResp", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%AutoResp, & + active=output%carbon .or. output%casa, & + patchout=output%patch .or. patchout%casa, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%crmplant(:, WOOD)), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "StemWood Autotrophic respiration") & + ] & + ), & + cable_output_variable_t( & + field_name="cnbp", & + netcdf_name="NBP", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%NBP, & + patchout=output%patch .or. patchout%NBP, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%cnbp), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Net Biosphere Production") & + ] & + ), & + cable_output_variable_t( & + field_name="dCdt", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%dCdt, & + patchout=output%patch .or. patchout%dCdt, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%dCdt), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Carbon accumulation rate (uptake +ve)") & + ] & + ), & + cable_output_variable_t( & + field_name="csoiltot", & + netcdf_name="TotSoilCarb", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotSoilCarb, & + active=output%casa .or. output%TotSoilCarb, & + patchout=output%patch .or. patchout%TotSoilCarb, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%csoiltot), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Total Soil and Litter Carbon") & + ] & + ), & + cable_output_variable_t( & + field_name="clittertot", & + netcdf_name="TotLittCarb", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%TotLittCarb, & + patchout=output%patch .or. patchout%TotLittCarb, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%clittertot), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Total Litter Carbon") & + ] & + ), & + cable_output_variable_t( & + field_name="csoil_mic", & + netcdf_name="SoilCarbFast", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%SoilCarbFast, & + patchout=output%patch .or. patchout%SoilCarbFast, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%csoil(:, MIC)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Soil Carbon: Fast Turnover") & + ] & + ), & + cable_output_variable_t( & + field_name="csoil_slow", & + netcdf_name="SoilCarbSlow", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotSoilCarb, & + active=output%casa .or. output%SoilCarbSlow, & + patchout=output%patch .or. patchout%SoilCarbSlow, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%csoil(:, SLOW)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Soil Carbon: Slow Turnover") & + ] & + ), & + cable_output_variable_t( & + field_name="csoil_pass", & + netcdf_name="SoilCarbPassive", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotSoilCarb, & + active=output%casa .or. output%SoilCarbPassive, & + patchout=output%patch .or. patchout%SoilCarbPassive, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%csoil(:, PASS)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Soil Carbon: Passive") & + ] & + ), & + cable_output_variable_t( & + field_name="clitter_metb", & + netcdf_name="LittCarbMetabolic", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%LittCarbMetabolic, & + patchout=output%patch .or. patchout%LittCarbMetabolic, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%clitter(:, METB)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Litter Carbon: metabolic") & + ] & + ), & + cable_output_variable_t( & + field_name="clitter_str", & + netcdf_name="LittCarbStructural", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%LittCarbStructural, & + patchout=output%patch .or. patchout%LittCarbStructural, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%clitter(:, STR)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Litter Carbon: structural") & + ] & + ), & + cable_output_variable_t( & + field_name="clitter_cwd", & + netcdf_name="LittCarbCWD", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%LittCarbCWD, & + patchout=output%patch .or. patchout%LittCarbCWD, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%clitter(:, CWD)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Litter Carbon: CWD") & + ] & + ), & + cable_output_variable_t( & + field_name="cplant_leaf", & + netcdf_name="PlantCarbLeaf", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%PlantCarbLeaf, & + patchout=output%patch .or. patchout%PlantCarbLeaf, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%cplant(:, LEAF)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Plant Carbon: leaf") & + ] & + ), & + cable_output_variable_t( & + field_name="cplant_wood", & + netcdf_name="PlantCarbWood", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%PlantCarbWood, & + patchout=output%patch .or. patchout%PlantCarbWood, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%cplant(:, WOOD)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Plant Carbon: wood (above- and below-ground)") & + ] & + ), & + cable_output_variable_t( & + field_name="cplant_froot", & + netcdf_name="PlantCarbFineRoot", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLittCarb, & + active=output%casa .or. output%PlantCarbFineRoot, & + patchout=output%patch .or. patchout%PlantCarbFineRoot, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%cplant(:, FROOT)), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Plant Carbon: Fine roots") & + ] & + ), & + cable_output_variable_t( & + field_name="cplanttot", & + netcdf_name="TotLivBiomass", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TotLivBiomass, & + active=output%casa .or. output%TotLivBiomass, & + patchout=output%patch .or. patchout%TotLivBiomass, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casapool%cplanttot), & + scale=(1.0 / 1000.0), & + metadata=[ & + attribute("units", "kg C/m^2"), & + attribute("long_name", "Total Biomass") & + ] & + ), & + cable_output_variable_t( & + field_name="cplant_turnover_tot", & + netcdf_name="PlantTurnover", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%PlantTurnover, & + patchout=output%patch .or. patchout%PlantTurnover, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%cplant_turnover_tot), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Total Biomass Turnover") & + ] & + ), & + cable_output_variable_t( & + field_name="Cplant_turnover_leaf", & + netcdf_name="PlantTurnoverLeaf", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%PlantTurnoverLeaf, & + patchout=output%patch .or. patchout%PlantTurnoverLeaf, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%Cplant_turnover(:, LEAF)), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Leaf Biomass Turnover") & + ] & + ), & + cable_output_variable_t( & + field_name="Cplant_turnover_wood", & + netcdf_name="PlantTurnoverWood", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%PlantTurnoverWood, & + patchout=output%patch .or. patchout%PlantTurnoverWood, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%Cplant_turnover(:, WOOD)), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Woody Biomass Turnover") & + ] & + ), & + cable_output_variable_t( & + field_name="Cplant_turnover_froot", & + netcdf_name="PlantTurnoverFineRoot", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%PlantTurnoverFineRoot, & + patchout=output%patch .or. patchout%PlantTurnoverFineRoot, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%Cplant_turnover(:, FROOT)), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "FineRoot Biomass Turnover") & + ] & + ), & + cable_output_variable_t( & + field_name="Cplant_turnover_disturbance", & + netcdf_name="PlantTurnoverWoodDist", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%PlantTurnoverWoodDist, & + patchout=output%patch .or. patchout%PlantTurnoverWoodDist, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%Cplant_turnover_disturbance), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Woody Biomass Turnover (disturbance)") & + ] & + ), & + cable_output_variable_t( & + field_name="Cplant_turnover_crowding", & + netcdf_name="PlantTurnoverWoodCrowding", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%PlantTurnoverWoodCrowding, & + patchout=output%patch .or. patchout%PlantTurnoverWoodCrowding, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%Cplant_turnover_crowding), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Woody Biomass Turnover (crowding)") & + ] & + ), & + cable_output_variable_t( & + field_name="Cplant_turnover_resource_limitation", & + netcdf_name="PlantTurnoverWoodResourceLim", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%casa .or. output%PlantTurnoverWoodResourceLim, & + patchout=output%patch .or. patchout%PlantTurnoverWoodResourceLim, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%Cplant_turnover_resource_limitation), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Woody Biomass Turnover (Resource Limitation)") & + ] & + ), & + cable_output_variable_t( & + field_name="areacell", & + netcdf_name="Area", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Area, & + active=output%casa .or. output%Area, & + patchout=output%patch .or. patchout%Area, & + reduction_method="grid_cell_average", & + aggregation_method="point", & + aggregator=new_aggregator(casamet%areacell), & + scale=1e-6, & + metadata=[ & + attribute("units", "km2"), & + attribute("long_name", "Patch Area") & + ] & + ), & + cable_output_variable_t( & + field_name="FluxCtoLUC", & + netcdf_name="LandUseFlux", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=cable_user%POPLUC .or. output%LandUseFlux, & + patchout=output%patch .or. patchout%LandUseFlux, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(casaflux%FluxCtoLUC), & + scale=(1.0 / seconds_per_day / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Sum of wood harvest and clearing fluxes") & + ] & + ) & + ] + + end function cable_diagnostics_casa + +end module diff --git a/src/offline/cable_diagnostics_core.F90 b/src/offline/cable_diagnostics_core.F90 new file mode 100644 index 000000000..040a9c129 --- /dev/null +++ b/src/offline/cable_diagnostics_core.F90 @@ -0,0 +1,2191 @@ +module cable_diagnostics_core_mod + + use cable_def_types_mod, only: met_type + use cable_def_types_mod, only: canopy_type + use cable_def_types_mod, only: soil_parameter_type + use cable_def_types_mod, only: soil_snow_type + use cable_def_types_mod, only: radiation_type + use cable_def_types_mod, only: veg_parameter_type + use cable_def_types_mod, only: balances_type + use cable_def_types_mod, only: roughness_type + use cable_def_types_mod, only: bgc_pool_type + use cable_def_types_mod, only: mvtype, mstype + + use cable_phys_constants_mod, only: c_molar_mass + + use cable_netcdf_mod, only: CABLE_NETCDF_INT + use cable_netcdf_mod, only: CABLE_NETCDF_FLOAT + + use aggregator_mod, only: new_aggregator + + use cable_common_module, only: cable_user + use cable_common_module, only: gw_params + + use cable_io_vars_module, only: output, patchout + use cable_io_vars_module, only: landpt_global + use cable_io_vars_module, only: patch + + use cable_output_prototype_v2_mod, only: cable_output_variable_t + use cable_output_prototype_v2_mod, only: attribute => cable_output_attribute_t + use cable_output_prototype_v2_mod, only: DIM_PATCH => CABLE_OUTPUT_DIM_PATCH + use cable_output_prototype_v2_mod, only: DIM_SOIL => CABLE_OUTPUT_DIM_SOIL + use cable_output_prototype_v2_mod, only: DIM_RAD => CABLE_OUTPUT_DIM_RAD + use cable_output_prototype_v2_mod, only: DIM_SNOW => CABLE_OUTPUT_DIM_SNOW + use cable_output_prototype_v2_mod, only: DIM_PLANTCARBON => CABLE_OUTPUT_DIM_PLANTCARBON + use cable_output_prototype_v2_mod, only: DIM_SOILCARBON => CABLE_OUTPUT_DIM_SOILCARBON + use cable_output_prototype_v2_mod, only: DIM_LAND_GLOBAL => CABLE_OUTPUT_DIM_LAND_GLOBAL + + use cable_checks_module, only: ranges + + implicit none + private + + public :: cable_diagnostics_core + +contains + + function cable_diagnostics_core(met, canopy, soil, ssnow, rad, veg, bal, rough, bgc, dels) result(output_variables) + type(met_type), intent(inout) :: met + type(canopy_type), intent(inout) :: canopy + type(soil_parameter_type), intent(inout) :: soil + type(soil_snow_type), intent(inout) :: ssnow + type(radiation_type), intent(inout) :: rad + type(veg_parameter_type), intent(inout) :: veg + type(balances_type), intent(inout) :: bal + type(roughness_type), intent(inout) :: rough + type(bgc_pool_type), intent(inout) :: bgc + real, intent(in) :: dels + + type(cable_output_variable_t), allocatable :: output_variables(:) + + output_variables = [ & + cable_output_variable_t( & + field_name="fsd", & + netcdf_name="SWdown", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SWdown, & + active=output%met .or. output%SWdown, & + patchout=output%patch .or. patchout%SWdown, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%ofsd), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Downward shortwave radiation") & + ] & + ), & + cable_output_variable_t( & + field_name="fld", & + netcdf_name="LWdown", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%LWdown, & + active=output%met .or. output%LWdown, & + patchout=output%patch .or. patchout%LWdown, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%fld), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Downward longwave radiation") & + ] & + ), & + cable_output_variable_t( & + field_name="precip", & + netcdf_name="Rainf", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Rainf, & + active=output%met .or. output%Rainf, & + patchout=output%patch .or. patchout%Rainf, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%precip), & + scale=(1.0 / dels), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Rainfall+snowfall") & + ] & + ), & + cable_output_variable_t( & + field_name="precip_sn", & + netcdf_name="Snowf", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Snowf, & + active=output%met .or. output%Snowf, & + patchout=output%patch .or. patchout%Snowf, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%precip_sn), & + scale=(1.0 / dels), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Snowfall") & + ] & + ), & + cable_output_variable_t( & + field_name="pmb", & + netcdf_name="PSurf", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%PSurf, & + active=output%met .or. output%PSurf, & + patchout=output%patch .or. patchout%PSurf, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%pmb), & + metadata=[ & + attribute("units", "hPa"), & + attribute("long_name", "Surface air pressure") & + ] & + ), & + cable_output_variable_t( & + field_name="tk", & + netcdf_name="Tair", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Tair, & + active=output%met .or. output%Tair, & + patchout=output%patch .or. patchout%Tair, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%tk), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Surface air temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="qv", & + netcdf_name="Qair", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qair, & + active=output%met .or. output%Qair, & + patchout=output%patch .or. patchout%Qair, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%qv), & + metadata=[ & + attribute("units", "kg/kg"), & + attribute("long_name", "Surface specific humidity") & + ] & + ), & + cable_output_variable_t( & + field_name="ua", & + netcdf_name="Wind", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Wind, & + active=output%met .or. output%Wind, & + patchout=output%patch .or. patchout%Wind, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%ua), & + metadata=[ & + attribute("units", "m/s"), & + attribute("long_name", "Scalar surface wind speed") & + ] & + ), & + cable_output_variable_t( & + field_name="ca", & + netcdf_name="CO2air", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%CO2air, & + active=output%met .or. output%CO2air, & + patchout=output%patch .or. patchout%CO2air, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + scale=1e6, & ! Convert to ppmv + aggregator=new_aggregator(met%ca), & + metadata=[ & + attribute("units", "ppmv"), & + attribute("long_name", "Surface air CO2 concentration") & + ] & + ), & + cable_output_variable_t( & + field_name="qmom", & + netcdf_name="Qmom", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qmom, & + active=output%flux .or. output%Qmom, & + patchout=output%patch .or. patchout%Qmom, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%qmom), & + metadata=[ & + attribute("units", "kg/m/s2"), & + attribute("long_name", "Surface momentum flux") & + ] & + ), & + cable_output_variable_t( & + field_name="fe", & + netcdf_name="Qle", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qle, & + active=output%flux .or. output%Qle, & + patchout=output%patch .or. patchout%Qle, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fe), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Surface latent heat flux") & + ] & + ), & + cable_output_variable_t( & + field_name="fh", & + netcdf_name="Qh", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qh, & + active=output%flux .or. output%Qh, & + patchout=output%patch .or. patchout%Qh, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fh), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Surface sensible heat flux") & + ] & + ), & + cable_output_variable_t( & + field_name="ga", & + netcdf_name="Qg", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qg, & + active=output%flux .or. output%Qg, & + patchout=output%patch .or. patchout%Qg, & + restart=.true., & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%ga), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Surface ground heat flux") & + ] & + ), & + cable_output_variable_t( & + field_name="rnof1", & + netcdf_name="Qs", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qs, & + active=output%flux .or. output%Qs, & + patchout=output%patch .or. patchout%Qs, & + restart=.true., & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%rnof1), & + scale=(1.0 / dels), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Surface runoff") & + ] & + ), & + cable_output_variable_t( & + field_name="rnof2", & + netcdf_name="Qsb", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qsb, & + active=output%flux .or. output%Qsb, & + patchout=output%patch .or. patchout%Qsb, & + restart=.true., & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%rnof2), & + scale=(1.0 / dels), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Subsurface runoff") & + ] & + ), & + cable_output_variable_t( & + field_name="et", & + netcdf_name="Evap", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Evap, & + active=output%flux .or. output%Evap, & + patchout=output%patch .or. patchout%Evap, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%et), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Total evapotranspiration") & + ] & + ), & + cable_output_variable_t( & + field_name="epot", & + netcdf_name="PotEvap", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%PotEvap, & + active=output%flux .or. output%PotEvap, & + patchout=output%patch .or. patchout%PotEvap, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%epot), & + scale=(1.0 / dels), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Potential evaporation") & + ] & + ), & + cable_output_variable_t( & + field_name="eint", & + netcdf_name="ECanop", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%ECanop, & + active=output%flux .or. output%ECanop, & + patchout=output%patch .or. patchout%ECanop, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%eint), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Wet canopy evaporation") & + ] & + ), & + cable_output_variable_t( & + field_name="tveg", & + netcdf_name="TVeg", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%TVeg, & + active=output%flux .or. output%TVeg, & + patchout=output%patch .or. patchout%TVeg, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%tveg), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Vegetation transpiration") & + ] & + ), & + cable_output_variable_t( & + field_name="esoil", & + netcdf_name="ESoil", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%ESoil, & + active=output%flux .or. output%ESoil, & + patchout=output%patch .or. patchout%ESoil, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%esoil), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Evaporation from soil") & + ] & + ), & + cable_output_variable_t( & + field_name="fhv", & + netcdf_name="HVeg", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%HVeg, & + active=output%flux .or. output%HVeg, & + patchout=output%patch .or. patchout%HVeg, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fhv), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Sensible heat from vegetation") & + ] & + ), & + cable_output_variable_t( & + field_name="fhs", & + netcdf_name="HSoil", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%HSoil, & + active=output%flux .or. output%HSoil, & + patchout=output%patch .or. patchout%HSoil, & + restart=.true., & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fhs), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Sensible heat from soil") & + ] & + ), & + cable_output_variable_t( & + field_name="fns", & + netcdf_name="RnetSoil", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%HSoil, & + active=output%flux .or. output%RnetSoil, & + patchout=output%patch .or. patchout%RnetSoil, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fns), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Net radiation absorbed by ground") & + ] & + ), & + cable_output_variable_t( & + field_name="wb", & + netcdf_name="SoilMoist", & + data_shape=[DIM_PATCH, DIM_SOIL], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SoilMoist, & + active=output%soil .or. output%SoilMoist, & + patchout=output%patch .or. patchout%SoilMoist, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%wb), & + restart=.true., & + metadata=[ & + attribute("units", "m^3/m^3"), & + attribute("long_name", "Average layer soil moisture") & + ] & + ), & + cable_output_variable_t( & + field_name="wbice", & + netcdf_name="SoilMoistIce", & + data_shape=[DIM_PATCH, DIM_SOIL], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SoilMoist, & + active=output%soil .or. output%SoilMoistIce, & + patchout=output%patch .or. patchout%SoilMoistIce, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%wbice), & + restart=.true., & + metadata=[ & + attribute("units", "m^3/m^3"), & + attribute("long_name", "Average layer frozen soil moisture") & + ] & + ), & + cable_output_variable_t( & + field_name="tgg", & + netcdf_name="SoilTemp", & + data_shape=[DIM_PATCH, DIM_SOIL], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SoilTemp, & + active=output%soil .or. output%SoilTemp, & + patchout=output%patch .or. patchout%SoilTemp, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%tgg), & + restart=.true., & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Average layer soil temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="gammzz", & + data_shape=[DIM_PATCH, DIM_SOIL], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + aggregation_method="mean", & + restart=.true., & + aggregator=new_aggregator(ssnow%gammzz), & + metadata=[ & + attribute("units", "J/kg/C"), & + attribute("long_name", "Heat capacity for each soil layer") & + ] & + ), & + cable_output_variable_t( & + field_name="ssdn", & + data_shape=[DIM_PATCH, DIM_SNOW], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + aggregation_method="mean", & + restart=.true., & + aggregator=new_aggregator(ssnow%ssdn), & + metadata=[ & + attribute("units", "kg/m^3"), & + attribute("long_name", "Average layer snow density") & + ] & + ), & + cable_output_variable_t( & + field_name="smass", & + data_shape=[DIM_PATCH, DIM_SNOW], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + aggregation_method="mean", & + restart=.true., & + aggregator=new_aggregator(ssnow%smass), & + metadata=[ & + attribute("units", "kg/m^2"), & + attribute("long_name", "Average layer snow mass") & + ] & + ), & + cable_output_variable_t( & + field_name="tgg1", & + netcdf_name="BaresoilT", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%BaresoilT, & + active=output%soil .or. output%BaresoilT, & + patchout=output%patch .or. patchout%BaresoilT, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%tgg(:, 1)), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Bare soil temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="snowd", & + netcdf_name="SWE", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SWE, & + active=output%snow .or. output%SWE, & + patchout=output%patch .or. patchout%SWE, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%snowd), & + restart=.true., & + metadata=[ & + attribute("units", "kg/m^2"), & + attribute("long_name", "Snow water equivalent") & + ] & + ), & + cable_output_variable_t( & + field_name="smelt", & + netcdf_name="SnowMelt", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SnowMelt, & + active=output%snow .or. output%SnowMelt, & + patchout=output%patch .or. patchout%SnowMelt, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%smelt), & + scale=(1.0 / dels), & + metadata=[ & + attribute("units", "kg/m^2/s"), & + attribute("long_name", "Snow Melt Rate") & + ] & + ), & + cable_output_variable_t( & + field_name="tggsn", & + data_shape=[DIM_PATCH, DIM_SNOW], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + aggregation_method="mean", & + restart=.true., & + aggregator=new_aggregator(ssnow%tggsn), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Average layer snow temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="tggsn1", & + netcdf_name="SnowT", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SnowT, & + active=output%snow .or. output%SnowT, & + patchout=output%patch .or. patchout%SnowT, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%tggsn(:, 1)), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Snow surface temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="sdepth", & + data_shape=[DIM_PATCH, DIM_SNOW], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SnowDepth, & + active=.false., & + aggregation_method="mean", & + restart=.true., & + aggregator=new_aggregator(ssnow%sdepth), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Snow layer depth") & + ] & + ), & + cable_output_variable_t( & + field_name="totsdepth", & + netcdf_name="SnowDepth", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SnowDepth, & + active=output%snow .or. output%SnowDepth, & + patchout=output%patch .or. patchout%SnowDepth, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%totsdepth), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Snow depth") & + ] & + ), & + cable_output_variable_t( & + field_name="swnet", & + netcdf_name="SWnet", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SWnet, & + active=output%radiation .or. output%SWnet, & + patchout=output%patch .or. patchout%SWnet, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(rad%swnet), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Net shortwave radiation absorbed by surface") & + ] & + ), & + cable_output_variable_t( & + field_name="lwnet", & + netcdf_name="LWnet", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%LWnet, & + active=output%radiation .or. output%LWnet, & + patchout=output%patch .or. patchout%LWnet, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(rad%lwnet), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Net longwave radiation absorbed by surface") & + ] & + ), & + cable_output_variable_t( & + field_name="rnet", & + netcdf_name="Rnet", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Rnet, & + active=output%radiation .or. output%Rnet, & + patchout=output%patch .or. patchout%Rnet, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(rad%rnet), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Net radiation absorbed by surface") & + ] & + ), & + cable_output_variable_t( & + field_name="albedo_T", & + netcdf_name="Albedo", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Albedo, & + active=output%radiation .or. output%Albedo, & + patchout=output%patch .or. patchout%Albedo, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(rad%albedo_T), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Surface albedo") & + ] & + ), & + cable_output_variable_t( & + field_name="albedo_vis", & + netcdf_name="visAlbedo", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%visAlbedo, & + active=output%radiation .or. output%visAlbedo, & + patchout=output%patch .or. patchout%visAlbedo, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(rad%albedo(:, 1)), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Surface vis albedo") & + ] & + ), & + cable_output_variable_t( & + field_name="albedo_nir", & + netcdf_name="nirAlbedo", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%nirAlbedo, & + active=output%radiation .or. output%nirAlbedo, & + patchout=output%patch .or. patchout%nirAlbedo, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(rad%albedo(:, 2)), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Surface nir albedo") & + ] & + ), & + cable_output_variable_t( & + field_name="trad", & + netcdf_name="RadT", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%RadT, & + active=output%radiation .or. output%RadT, & + patchout=output%patch .or. patchout%RadT, & + restart=.true., & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(rad%trad), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Radiative surface temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="tscrn", & + netcdf_name="Tscrn", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Tscrn, & + active=output%veg .or. output%Tscrn, & + patchout=output%patch .or. patchout%Tscrn, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%tscrn), & + metadata=[ & + attribute("units", "oC"), & + attribute("long_name", "screen level air temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="tscrn_max", & + netcdf_name="Txx", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Tscrn, & + active=output%veg .or. output%Tex, & + patchout=output%patch .or. patchout%Tex, & + reduction_method="grid_cell_average", & + aggregation_method="max", & + aggregator=new_aggregator(canopy%tscrn), & + metadata=[ & + attribute("units", "oC"), & + attribute("long_name", "max screen-level T in reporting period") & + ] & + ), & + cable_output_variable_t( & + field_name="tscrn_min", & + netcdf_name="Tnn", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Tscrn, & + active=output%veg .or. output%Tex, & + patchout=output%patch .or. patchout%Tex, & + reduction_method="grid_cell_average", & + aggregation_method="min", & + aggregator=new_aggregator(canopy%tscrn), & + metadata=[ & + attribute("units", "oC"), & + attribute("long_name", "min screen-level T in reporting period") & + ] & + ), & + cable_output_variable_t( & + field_name="tscrn_max_daily", & + netcdf_name="Tmx", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=(output%veg .or. output%Tex) .and. output%averaging == "monthly", & + patchout=output%patch .or. patchout%Tex, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + range=ranges%Tscrn, & + accumulation_frequency="daily", & + aggregator=new_aggregator(canopy%tscrn_max_daily%aggregated_data), & + metadata=[ & + attribute("units", "oC"), & + attribute("long_name", "averaged daily maximum screen-level T") & + ] & + ), & + cable_output_variable_t( & + field_name="tscrn_min_daily", & + netcdf_name="Tmn", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=(output%veg .or. output%Tex) .and. output%averaging == "monthly", & + patchout=output%patch .or. patchout%Tex, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + range=ranges%Tscrn, & + accumulation_frequency="daily", & + aggregator=new_aggregator(canopy%tscrn_min_daily%aggregated_data), & + metadata=[ & + attribute("units", "oC"), & + attribute("long_name", "averaged daily minimum screen-level T") & + ] & + ), & + cable_output_variable_t( & + field_name="qscrn", & + netcdf_name="Qscrn", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qscrn, & + active=output%veg .or. output%Qscrn, & + patchout=output%patch .or. patchout%Qscrn, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%qscrn), & + metadata=[ & + attribute("units", "kg/kg"), & + attribute("long_name", "screen level specific humidity") & + ] & + ), & + cable_output_variable_t( & + field_name="tv", & + netcdf_name="VegT", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%VegT, & + active=output%veg .or. output%VegT, & + patchout=output%patch .or. patchout%VegT, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%tv), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Average vegetation temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="tvair", & + netcdf_name="CanT", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%CanT, & + active=output%veg .or. output%CanT, & + patchout=output%patch .or. patchout%CanT, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(met%tvair), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Within-canopy temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="fwsoil", & + netcdf_name="Fwsoil", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Fwsoil, & + active=output%veg .or. output%Fwsoil, & + patchout=output%patch .or. patchout%Fwsoil, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fwsoil), & + metadata=[ & + attribute("units", "[-]"), & + attribute("long_name", "soil moisture modifier to stomatal conductance") & + ] & + ), & + cable_output_variable_t( & + field_name="cansto", & + netcdf_name="CanopInt", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%CanopInt, & + active=output%veg .or. output%CanopInt, & + patchout=output%patch .or. patchout%CanopInt, & + restart=.true., & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%cansto), & + metadata=[ & + attribute("units", "kg/m^2"), & + attribute("long_name", "Canopy intercepted water storage") & + ] & + ), & + cable_output_variable_t( & + field_name="vlai", & + netcdf_name="LAI", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%LAI, & + active=output%veg .or. output%LAI, & + patchout=output%patch .or. patchout%LAI, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(veg%vlai), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Leaf area index") & + ] & + ), & + cable_output_variable_t( & + field_name="ebal_tot", & + netcdf_name="Ebal", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Ebal, & + active=output%balances .or. output%Ebal, & + patchout=output%patch .or. patchout%Ebal, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(bal%ebal_tot), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Cumulative energy imbalance") & + ] & + ), & + cable_output_variable_t( & + field_name="wbal_tot", & + netcdf_name="Wbal", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Wbal, & + active=output%balances .or. output%Wbal, & + patchout=output%patch .or. patchout%Wbal, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(bal%wbal_tot), & + metadata=[ & + attribute("units", "kg/m^2"), & + attribute("long_name", "Cumulative water imbalance") & + ] & + ), & + cable_output_variable_t( & + field_name="wbtot0", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(bal%wbtot0), & + metadata=[ & + attribute("units", "mm"), & + attribute("long_name", "Initial time step soil water total") & + ] & + ), & + cable_output_variable_t( & + field_name="osnowd0", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(bal%osnowd0), & + metadata=[ & + attribute("units", "mm"), & + attribute("long_name", "Initial time step snow water total") & + ] & + ), & + cable_output_variable_t( & + field_name="frday", & + netcdf_name="LeafResp", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%AutoResp, & + active=output%carbon .or. output%LeafResp, & + patchout=output%patch .or. patchout%LeafResp, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%frday), & + scale=(1.0 / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Leaf respiration") & + ] & + ), & + cable_output_variable_t( & + field_name="frs", & + netcdf_name="HeteroResp", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%HeteroResp, & + active=output%carbon .or. output%HeteroResp, & + patchout=output%patch .or. patchout%HeteroResp, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%frs), & + scale=(1.0 / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Heterotrophic respiration") & + ] & + ), & + cable_output_variable_t( & + field_name="fgpp", & + netcdf_name="GPP", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%GPP, & + active=output%carbon .or. output%GPP, & + patchout=output%patch .or. patchout%GPP, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fgpp), & + scale=(1.0 / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Gross primary production") & + ] & + ), & + cable_output_variable_t( & + field_name="fnpp", & + netcdf_name="NPP", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NPP, & + active=output%carbon .or. output%NPP, & + patchout=output%patch .or. patchout%NPP, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fnpp), & + scale=(1.0 / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Net primary production") & + ] & + ), & + cable_output_variable_t( & + field_name="fra", & + netcdf_name="AutoResp", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%AutoResp, & + active=output%carbon .or. output%AutoResp, & + patchout=output%patch .or. patchout%AutoResp, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fra), & + scale=(1.0 / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Autotrophic respiration") & + ] & + ), & + cable_output_variable_t( & + field_name="fnee", & + netcdf_name="NEE", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%NEE, & + active=output%flux .or. output%NEE, & + patchout=output%patch .or. patchout%NEE, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(canopy%fnee), & + scale=(1.0 / c_molar_mass), & + metadata=[ & + attribute("units", "umol/m^2/s"), & + attribute("long_name", "Net ecosystem exchange of CO2") & + ] & + ), & + cable_output_variable_t( & + field_name="wtd", & + netcdf_name="WatTable", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%WatTable, & + active=output%soil .or. output%WatTable, & + patchout=output%patch .or. patchout%WatTable, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%wtd), & + scale=1e-3, & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Water Table Depth") & + ] & + ), & + cable_output_variable_t( & + field_name="GWwb", & + netcdf_name="GWMoist", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%GWwb, & + active=output%soil .or. output%GWMoist, & + patchout=output%patch .or. patchout%GWMoist, & + restart=.true., & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%GWwb), & + metadata=[ & + attribute("units", "mm3/mm3"), & + attribute("long_name", "Aquifer moisture content") & + ] & + ), & + cable_output_variable_t( & + field_name="satfrac", & + netcdf_name="SatFrac", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%SatFrac, & + active=output%soil .or. output%SatFrac, & + patchout=output%patch .or. patchout%SatFrac, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%satfrac), & + metadata=[ & + attribute("units", "unitless"), & + attribute("long_name", "Saturated fraction of grid cell") & + ] & + ), & + cable_output_variable_t( & + field_name="Qrecharge", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%Qrecharge, & + active=output%soil .or. output%Qrecharge, & + patchout=output%patch .or. patchout%Qrecharge, & + reduction_method="grid_cell_average", & + aggregation_method="mean", & + aggregator=new_aggregator(ssnow%Qrecharge), & + metadata=[ & + attribute("units", "mm/s"), & + attribute("long_name", "Recharge to or from Aquifer") & + ] & + ), & + cable_output_variable_t( & + field_name="tss", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(ssnow%tss), & + metadata=[ & + attribute("units", "K"), & + attribute("long_name", "Combined soil/snow temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="rtsoil", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(ssnow%rtsoil), & + metadata=[ & + attribute("units", "??"), & + attribute("long_name", "Turbulent resistance for soil") & + ] & + ), & + cable_output_variable_t( & + field_name="runoff", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(ssnow%runoff), & + metadata=[ & + attribute("units", "mm/timestep"), & + attribute("long_name", "Total runoff") & + ] & + ), & + cable_output_variable_t( & + field_name="ssdnn", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(ssnow%ssdnn), & + metadata=[ & + attribute("units", "kg/m^3"), & + attribute("long_name", "Average snow density") & + ] & + ), & + cable_output_variable_t( & + field_name="snage", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(ssnow%snage), & + metadata=[ & + attribute("units", "??"), & + attribute("long_name", "Snow age") & + ] & + ), & + cable_output_variable_t( & + field_name="osnowd", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(ssnow%osnowd), & + metadata=[ & + attribute("units", "mm"), & + attribute("long_name", "Previous time step snow depth in water equivalent") & + ] & + ), & + cable_output_variable_t( & + field_name="albsoilsn", & + data_shape=[DIM_PATCH, DIM_RAD], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%albsoiln, & + active=.false., & + aggregation_method="mean", & + restart=.true., & + aggregator=new_aggregator(ssnow%albsoilsn), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Combined soil/snow albedo") & + ] & + ), & + cable_output_variable_t( & + field_name="isflag", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_INT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(ssnow%isflag), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Snow layer scheme flag") & + ] & + ), & + cable_output_variable_t( & + field_name="ghflux", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(canopy%ghflux), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "????") & + ] & + ), & + cable_output_variable_t( & + field_name="sghflux", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(canopy%sghflux), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "????") & + ] & + ), & + cable_output_variable_t( & + field_name="dgdtg", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(canopy%dgdtg), & + metadata=[ & + attribute("units", "W/m^2/K"), & + attribute("long_name", "Derivative of ground heat flux wrt soil temperature") & + ] & + ), & + cable_output_variable_t( & + field_name="fev", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(canopy%fev), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Latent heat flux from vegetation") & + ] & + ), & + cable_output_variable_t( & + field_name="fes", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(canopy%fes), & + metadata=[ & + attribute("units", "W/m^2"), & + attribute("long_name", "Latent heat flux from soil") & + ] & + ), & + cable_output_variable_t( & + field_name="albedo", & + data_shape=[DIM_PATCH, DIM_RAD], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(rad%albedo), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Albedo for shortwave and NIR radiation") & + ] & + ), & + cable_output_variable_t( & + field_name="iveg", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_INT, & + range=ranges%iveg, & + active=output%params .or. output%iveg, & + patchout=output%patch .or. patchout%iveg, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + restart=.true., & + aggregator=new_aggregator(veg%iveg), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Vegetation type") & + ] & + ), & + cable_output_variable_t( & + field_name="patchfrac", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%patchfrac, & + active=(output%params .or. output%patchfrac) .and. (output%patch .or. patchout%patchfrac), & + patchout=output%patch .or. patchout%patchfrac, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + restart=.true., & + aggregator=new_aggregator(patch(:)%frac), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fractional cover of vegetation patches") & + ] & + ), & + cable_output_variable_t( & + field_name="isoil", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_INT, & + range=ranges%isoil, & + active=output%params .or. output%isoil, & + patchout=output%patch .or. patchout%isoil, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + restart=.true., & + aggregator=new_aggregator(soil%isoilm), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Soil type") & + ] & + ), & + cable_output_variable_t( & + field_name="bch", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%bch, & + active=output%params .or. output%bch, & + patchout=output%patch .or. patchout%bch, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%bch), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Parameter b, Campbell eqn 1985") & + ] & + ), & + cable_output_variable_t( & + field_name="clay", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%clay, & + active=output%params .or. output%clay, & + patchout=output%patch .or. patchout%clay, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%clay), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of soil which is clay") & + ] & + ), & + cable_output_variable_t( & + field_name="sand", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%sand, & + active=output%params .or. output%sand, & + patchout=output%patch .or. patchout%sand, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%sand), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of soil which is sand") & + ] & + ), & + cable_output_variable_t( & + field_name="silt", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%silt, & + active=output%params .or. output%silt, & + patchout=output%patch .or. patchout%silt, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%silt), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of soil which is silt") & + ] & + ), & + cable_output_variable_t( & + field_name="ssat", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%ssat, & + active=output%params .or. output%ssat, & + patchout=output%patch .or. patchout%ssat, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%ssat), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of soil volume which is water @ saturation") & + ] & + ), & + cable_output_variable_t( & + field_name="sfc", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%sfc, & + active=output%params .or. output%sfc, & + patchout=output%patch .or. patchout%sfc, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%sfc), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of soil volume which is water @ field capacity") & + ] & + ), & + cable_output_variable_t( & + field_name="swilt", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%swilt, & + active=output%params .or. output%swilt, & + patchout=output%patch .or. patchout%swilt, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%swilt), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of soil volume which is water @ wilting point") & + ] & + ), & + cable_output_variable_t( & + field_name="hyds", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%hyds, & + active=output%params .or. output%hyds, & + patchout=output%patch .or. patchout%hyds, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%hyds), & + metadata=[ & + attribute("units", "m/s"), & + attribute("long_name", "Hydraulic conductivity @ saturation") & + ] & + ), & + cable_output_variable_t( & + field_name="sucs", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%sucs, & + active=output%params .or. output%sucs, & + patchout=output%patch .or. patchout%sucs, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%sucs), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Suction @ saturation") & + ] & + ), & + cable_output_variable_t( & + field_name="css", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%css, & + active=output%params .or. output%css, & + patchout=output%patch .or. patchout%css, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%css), & + metadata=[ & + attribute("units", "J/kg/C"), & + attribute("long_name", "Heat capacity of soil minerals") & + ] & + ), & + cable_output_variable_t( & + field_name="rhosoil", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%rhosoil, & + active=output%params .or. output%rhosoil, & + patchout=output%patch .or. patchout%rhosoil, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%rhosoil), & + metadata=[ & + attribute("units", "kg/m^3"), & + attribute("long_name", "Density of soil minerals") & + ] & + ), & + cable_output_variable_t( & + field_name="rs20", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%rs20, & + active=output%params .or. output%rs20, & + patchout=output%patch .or. patchout%rs20, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%rs20), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Soil respiration coefficient at 20C") & + ] & + ), & + cable_output_variable_t( & + field_name="albsoil", & + data_shape=[DIM_PATCH, DIM_RAD], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%albsoil, & + active=output%params .or. output%albsoil, & + patchout=output%patch .or. patchout%albsoil, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + restart=.true., & + aggregator=new_aggregator(soil%albsoil), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Snow free shortwave soil reflectance fraction") & + ] & + ), & + cable_output_variable_t( & + field_name="hc", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%hc, & + active=output%params .or. output%hc, & + patchout=output%patch .or. patchout%hc, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%hc), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Height of canopy") & + ] & + ), & + cable_output_variable_t( & + field_name="canst1", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%canst1, & + active=output%params .or. output%canst1, & + patchout=output%patch .or. patchout%canst1, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%canst1), & + metadata=[ & + attribute("units", "mm/LAI"), & + attribute("long_name", "Max water intercepted by canopy") & + ] & + ), & + cable_output_variable_t( & + field_name="dleaf", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%dleaf, & + active=output%params .or. output%dleaf, & + patchout=output%patch .or. patchout%dleaf, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%dleaf), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Characteristic length of leaf") & + ] & + ), & + cable_output_variable_t( & + field_name="frac4", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%frac4, & + active=output%params .or. output%frac4, & + patchout=output%patch .or. patchout%frac4, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%frac4), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of plants which are C4") & + ] & + ), & + cable_output_variable_t( & + field_name="ejmax", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%ejmax, & + active=output%params .or. output%ejmax, & + patchout=output%patch .or. patchout%ejmax, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%ejmax), & + metadata=[ & + attribute("units", "mol/m^2/s"), & + attribute("long_name", "Max potential electron transport rate top leaf") & + ] & + ), & + cable_output_variable_t( & + field_name="vcmax", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%vcmax, & + active=output%params .or. output%vcmax, & + patchout=output%patch .or. patchout%vcmax, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%vcmax), & + metadata=[ & + attribute("units", "mol/m^2/s"), & + attribute("long_name", "Maximum RuBP carboxylation rate top leaf") & + ] & + ), & + cable_output_variable_t( & + field_name="rp20", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%rp20, & + active=output%params .or. output%rp20, & + patchout=output%patch .or. patchout%rp20, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%rp20), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Plant respiration coefficient at 20C") & + ] & + ), & + cable_output_variable_t( & + field_name="g0", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%g0, & + active=output%params .or. output%g0, & + patchout=output%patch .or. patchout%g0, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%g0), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "g0 term in Medlyn Stom Cond. Param") & + ] & + ), & + cable_output_variable_t( & + field_name="g1", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%g1, & + active=output%params .or. output%g1, & + patchout=output%patch .or. patchout%g1, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%g1), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "g1 term in Medlyn Stom Cond. Param") & + ] & + ), & + cable_output_variable_t( & + field_name="rpcoef", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%rpcoef, & + active=output%params .or. output%rpcoef, & + patchout=output%patch .or. patchout%rpcoef, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%rpcoef), & + metadata=[ & + attribute("units", "1/C"), & + attribute("long_name", "Temperature coef nonleaf plant respiration") & + ] & + ), & + cable_output_variable_t( & + field_name="shelrb", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%shelrb, & + active=output%params .or. output%shelrb, & + patchout=output%patch .or. patchout%shelrb, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%shelrb), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Sheltering factor") & + ] & + ), & + cable_output_variable_t( & + field_name="xfang", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%xfang, & + active=output%params .or. output%xfang, & + patchout=output%patch .or. patchout%xfang, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%xfang), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Leaf angle parameter") & + ] & + ), & + cable_output_variable_t( & + field_name="wai", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%wai, & + active=output%params .or. output%wai, & + patchout=output%patch .or. patchout%wai, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%wai), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Wood area index") & + ] & + ), & + cable_output_variable_t( & + field_name="vegcf", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%vegcf, & + active=output%params .or. output%vegcf, & + patchout=output%patch .or. patchout%vegcf, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%vegcf), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "vegcf") & + ] & + ), & + cable_output_variable_t( & + field_name="extkn", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%extkn, & + active=output%params .or. output%extkn, & + patchout=output%patch .or. patchout%extkn, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%extkn), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Nitrogen extinction coef for vert. canopy profile") & + ] & + ), & + cable_output_variable_t( & + field_name="tminvj", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%tminvj, & + active=output%params .or. output%tminvj, & + patchout=output%patch .or. patchout%tminvj, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%tminvj), & + metadata=[ & + attribute("units", "C"), & + attribute("long_name", "Min temperature for the start of photosynthesis") & + ] & + ), & + cable_output_variable_t( & + field_name="tmaxvj", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%tmaxvj, & + active=output%params .or. output%tmaxvj, & + patchout=output%patch .or. patchout%tmaxvj, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%tmaxvj), & + metadata=[ & + attribute("units", "C"), & + attribute("long_name", "Max temperature for photosynthesis") & + ] & + ), & + cable_output_variable_t( & + field_name="vbeta", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%vbeta, & + active=output%params .or. output%vbeta, & + patchout=output%patch .or. patchout%vbeta, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%vbeta), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Stomatal sensitivity to soil water") & + ] & + ), & + cable_output_variable_t( & + field_name="xalbnir", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%xalbnir, & + active=output%params .or. output%xalbnir, & + patchout=output%patch .or. patchout%xalbnir, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%xalbnir), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Modifier for albedo in near ir band") & + ] & + ), & + cable_output_variable_t( & + field_name="meth", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%meth, & + active=output%params .or. output%meth, & + patchout=output%patch .or. patchout%meth, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%meth), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Canopy turbulence parameterisation choice") & + ] & + ), & + cable_output_variable_t( & + field_name="za_uv", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%za, & + active=output%params .or. output%za, & + patchout=output%patch .or. patchout%za, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(rough%za_uv), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Reference height (lowest atm. model layer) for momentum") & + ] & + ), & + cable_output_variable_t( & + field_name="za_tq", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%za, & + active=output%params .or. output%za, & + patchout=output%patch .or. patchout%za, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(rough%za_tq), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Reference height (lowest atm. model layer) for scalars") & + ] & + ), & + cable_output_variable_t( & + field_name="ratecp", & + data_shape=[DIM_PLANTCARBON], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%ratecp, & + active=output%params .or. output%ratecp, & + distributed=.false., & + parameter=.true., & + aggregator=new_aggregator(bgc%ratecp), & + metadata=[ & + attribute("units", "1/year"), & + attribute("long_name", "Plant carbon rate constant") & + ] & + ), & + cable_output_variable_t( & + field_name="ratecs", & + data_shape=[DIM_SOILCARBON], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%ratecs, & + active=output%params .or. output%ratecs, & + distributed=.false., & + parameter=.true., & + aggregator=new_aggregator(bgc%ratecs), & + metadata=[ & + attribute("units", "1/year"), & + attribute("long_name", "Soil carbon rate constant") & + ] & + ), & + cable_output_variable_t( & + field_name="cplant", & + data_shape=[DIM_PATCH, DIM_PLANTCARBON], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(bgc%cplant), & + metadata=[ & + attribute("units", "gC/m^2"), & + attribute("long_name", "Plant carbon stores") & + ] & + ), & + cable_output_variable_t( & + field_name="csoil", & + data_shape=[DIM_PATCH, DIM_SOILCARBON], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + aggregator=new_aggregator(bgc%csoil), & + metadata=[ & + attribute("units", "gC/m^2"), & + attribute("long_name", "Soil carbon stores") & + ] & + ), & + cable_output_variable_t( & + field_name="zse", & + data_shape=[DIM_SOIL], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%zse, & + active=output%params .or. output%zse, & + distributed=.false., & + parameter=.true., & + restart=.true., & + aggregator=new_aggregator(soil%zse), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Depth of each soil layer") & + ] & + ), & + cable_output_variable_t( & + field_name="froot", & + data_shape=[DIM_PATCH, DIM_SOIL], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%froot, & + active=output%params .or. output%froot, & + patchout=output%patch .or. patchout%froot, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(veg%froot), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Fraction of roots in each soil layer") & + ] & + ), & + cable_output_variable_t( & + field_name="slope", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%slope, & + active=output%params .or. output%slope, & + patchout=output%patch .or. patchout%slope, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%slope), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Mean subgrid topographic slope") & + ] & + ), & + cable_output_variable_t( & + field_name="slope_std", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%slope_std, & + active=output%params .or. output%slope_std, & + patchout=output%patch .or. patchout%slope_std, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%slope_std), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Mean subgrid topographic slope_std") & + ] & + ), & + cable_output_variable_t( & + field_name="GWdz", & + data_shape=[DIM_PATCH], & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%GWdz, & + active=output%params .AND. cable_user%gw_model, & + patchout=output%patch .OR. patchout%GWdz, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(soil%GWdz), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Mean aquifer layer thickness") & + ] & + ), & + cable_output_variable_t( & + field_name="MaxHorzDrainRate", & + netcdf_name="Qhmax", & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%gw_default, & + active=output%params .AND. cable_user%gw_model, & + patchout=output%patch .OR. patchout%Qhmax, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(gw_params%MaxHorzDrainRate), & + metadata=[ & + attribute("units", "mm/s"), & + attribute("long_name", "Maximum subsurface drainage") & + ] & + ), & + cable_output_variable_t( & + field_name="EfoldHorzDrainRate", & + netcdf_name="QhmaxEfold", & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%gw_default, & + active=output%params .AND. cable_user%gw_model, & + patchout=output%patch .OR. patchout%QhmaxEfold, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(gw_params%EfoldHorzDrainRate), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Maximum subsurface drainage decay rate") & + ] & + ), & + cable_output_variable_t( & + field_name="MaxSatFraction", & + netcdf_name="SatFracmax", & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%gw_default, & + active=output%params .AND. cable_user%gw_model, & + patchout=output%patch .OR. patchout%SatFracmax, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(gw_params%MaxSatFraction), & + metadata=[ & + attribute("units", "-"), & + attribute("long_name", "Controls max saturated fraction") & + ] & + ), & + cable_output_variable_t( & + field_name="hkrz", & + netcdf_name="HKefold", & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%gw_default, & + active=output%params .AND. cable_user%gw_model, & + patchout=output%patch .OR. patchout%HKefold, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(gw_params%hkrz), & + metadata=[ & + attribute("units", "1/m"), & + attribute("long_name", "Rate HK decays with depth") & + ] & + ), & + cable_output_variable_t( & + field_name="zdepth", & + netcdf_name="HKdepth", & + var_type=CABLE_NETCDF_FLOAT, & + range=ranges%gw_default, & + active=output%params .AND. cable_user%gw_model, & + patchout=output%patch .OR. patchout%HKdepth, & + reduction_method="first_patch_in_grid_cell", & + aggregation_method="point", & + parameter=.true., & + aggregator=new_aggregator(gw_params%zdepth), & + metadata=[ & + attribute("units", "m"), & + attribute("long_name", "Depth at which HKsat(z) is HKsat(0)") & + ] & + ), & + cable_output_variable_t( & + field_name="nap", & + data_shape=[DIM_LAND_GLOBAL], & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + distributed=.false., & + aggregation_method="point", & + aggregator=new_aggregator(landpt_global(:)%nap), & + metadata=[ & + attribute("units", ""), & + attribute("long_name", "") & + ] & + ), & + cable_output_variable_t( & + field_name="mvtype", & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + distributed=.false., & + aggregation_method="point", & + aggregator=new_aggregator(mvtype), & + metadata=[ & + attribute("units", ""), & + attribute("long_name", "Number of vegetation types") & + ] & + ), & + cable_output_variable_t( & + field_name="mstype", & + var_type=CABLE_NETCDF_FLOAT, & + active=.false., & + restart=.true., & + distributed=.false., & + aggregation_method="point", & + aggregator=new_aggregator(mstype), & + metadata=[ & + attribute("units", ""), & + attribute("long_name", "Number of soil types") & + ] & + ) & + ] + + end function cable_diagnostics_core + +end module diff --git a/src/offline/cable_driver_common.F90 b/src/offline/cable_driver_common.F90 index 93cffc798..d94dd0ef1 100644 --- a/src/offline/cable_driver_common.F90 +++ b/src/offline/cable_driver_common.F90 @@ -13,6 +13,10 @@ MODULE cable_driver_common_mod snmin, & cable_user, & gw_params, & + l_casacnp, & + l_landuse, & + l_laiFeedbk, & + l_vcmaxFeedbk, & cable_runtime USE cable_IO_vars_module, ONLY : & soilparmnew, & @@ -56,10 +60,6 @@ MODULE cable_driver_common_mod LOGICAL, SAVE, PUBLIC :: spinup = .FALSE. ! model spinup to soil state equilibrium? LOGICAL, SAVE, PUBLIC :: spincasa = .FALSE. ! TRUE: CASA-CNP Will spin mloop times, FALSE: no spin up LOGICAL, SAVE, PUBLIC :: CASAONLY = .FALSE. ! ONLY Run CASA-CNP - LOGICAL, SAVE, PUBLIC :: l_casacnp = .FALSE. ! using CASA-CNP with CABLE - LOGICAL, SAVE, PUBLIC :: l_landuse = .FALSE. ! using CASA-CNP with CABLE - LOGICAL, SAVE, PUBLIC :: l_laiFeedbk = .FALSE. ! using prognostic LAI - LOGICAL, SAVE, PUBLIC :: l_vcmaxFeedbk = .FALSE. ! using prognostic Vcmax REAL, SAVE, PUBLIC :: delsoilM ! allowed variation in soil moisture for spin up REAL, SAVE, PUBLIC :: delsoilT ! allowed variation in soil temperature for spin up @@ -263,6 +263,7 @@ SUBROUTINE cable_driver_init_site(site) END SUBROUTINE cable_driver_init_site SUBROUTINE cable_driver_init_default(dels, koffset, kend) + USE cable_io_vars_module, ONLY : syear !! Model initialisation routine (default met specific). REAL, INTENT(OUT) :: dels !! Time step size in seconds INTEGER, INTENT(OUT) :: koffset !! Timestep to start at @@ -277,6 +278,10 @@ SUBROUTINE cable_driver_init_default(dels, koffset, kend) STOP 991 END IF + ncciy = syear + cable_user%YearStart = syear + cable_user%YearEnd = syear + END SUBROUTINE cable_driver_init_default SUBROUTINE cable_driver_init_plume(dels, koffset, PLUME) diff --git a/src/offline/cable_io_decomp.F90 b/src/offline/cable_io_decomp.F90 deleted file mode 100644 index 4da99efe6..000000000 --- a/src/offline/cable_io_decomp.F90 +++ /dev/null @@ -1,328 +0,0 @@ -module cable_io_decomp_mod - use cable_def_types_mod, only: mp, mp_global - use cable_def_types_mod, only: mland, mland_global - use cable_def_types_mod, only: ms - use cable_def_types_mod, only: msn - use cable_def_types_mod, only: nrb - use cable_def_types_mod, only: ncp - use cable_def_types_mod, only: ncs - - use cable_io_vars_module, only: xdimsize, ydimsize - use cable_io_vars_module, only: land_x, land_y - use cable_io_vars_module, only: landpt - use cable_io_vars_module, only: max_vegpatches - use cable_io_vars_module, only: land_decomp_start - use cable_io_vars_module, only: patch_decomp_start - use cable_io_vars_module, only: output - use cable_io_vars_module, only: metGrid - - use cable_netcdf_decomp_util_mod, only: dim_spec_t - use cable_netcdf_decomp_util_mod, only: io_decomp_land_to_x_y - use cable_netcdf_decomp_util_mod, only: io_decomp_patch_to_x_y_patch - use cable_netcdf_decomp_util_mod, only: io_decomp_land_to_land - use cable_netcdf_decomp_util_mod, only: io_decomp_patch_to_land_patch - use cable_netcdf_decomp_util_mod, only: io_decomp_patch_to_patch - - use cable_netcdf_mod, only: cable_netcdf_decomp_t - use cable_netcdf_mod, only: CABLE_NETCDF_INT - use cable_netcdf_mod, only: CABLE_NETCDF_FLOAT - use cable_netcdf_mod, only: CABLE_NETCDF_DOUBLE - - implicit none - private - - public :: & - io_decomp_t, & - cable_io_decomp_init - - type io_decomp_t - class(cable_netcdf_decomp_t), allocatable :: patch_to_x_y_patch_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_to_x_y_patch_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_to_x_y_patch_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_x_y_patch_soil_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_x_y_patch_soil_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_x_y_patch_soil_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_x_y_patch_snow_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_x_y_patch_snow_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_x_y_patch_snow_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_x_y_patch_rad_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_x_y_patch_rad_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_x_y_patch_rad_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_x_y_patch_plantcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_x_y_patch_plantcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_x_y_patch_plantcarbon_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_x_y_patch_soilcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_x_y_patch_soilcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_x_y_patch_soilcarbon_real64 - - class(cable_netcdf_decomp_t), allocatable :: patch_to_land_patch_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_to_land_patch_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_to_land_patch_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_land_patch_soil_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_land_patch_soil_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_land_patch_soil_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_land_patch_snow_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_land_patch_snow_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_land_patch_snow_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_land_patch_rad_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_land_patch_rad_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_land_patch_rad_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_land_patch_plantcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_land_patch_plantcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_land_patch_plantcarbon_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_land_patch_soilcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_land_patch_soilcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_land_patch_soilcarbon_real64 - - class(cable_netcdf_decomp_t), allocatable :: patch_to_patch_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_to_patch_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_to_patch_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_patch_soil_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_patch_soil_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_soil_to_patch_soil_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_patch_snow_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_patch_snow_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_snow_to_patch_snow_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_patch_rad_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_patch_rad_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_rad_to_patch_rad_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_patch_plantcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_patch_plantcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_to_patch_plantcarbon_real64 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_patch_soilcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_patch_soilcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_to_patch_soilcarbon_real64 - - class(cable_netcdf_decomp_t), allocatable :: land_to_x_y_int32 - class(cable_netcdf_decomp_t), allocatable :: land_to_x_y_real32 - class(cable_netcdf_decomp_t), allocatable :: land_to_x_y_real64 - class(cable_netcdf_decomp_t), allocatable :: land_soil_to_x_y_soil_int32 - class(cable_netcdf_decomp_t), allocatable :: land_soil_to_x_y_soil_real32 - class(cable_netcdf_decomp_t), allocatable :: land_soil_to_x_y_soil_real64 - class(cable_netcdf_decomp_t), allocatable :: land_snow_to_x_y_snow_int32 - class(cable_netcdf_decomp_t), allocatable :: land_snow_to_x_y_snow_real32 - class(cable_netcdf_decomp_t), allocatable :: land_snow_to_x_y_snow_real64 - class(cable_netcdf_decomp_t), allocatable :: land_rad_to_x_y_rad_int32 - class(cable_netcdf_decomp_t), allocatable :: land_rad_to_x_y_rad_real32 - class(cable_netcdf_decomp_t), allocatable :: land_rad_to_x_y_rad_real64 - class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_to_x_y_plantcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_to_x_y_plantcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_to_x_y_plantcarbon_real64 - class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_to_x_y_soilcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_to_x_y_soilcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_to_x_y_soilcarbon_real64 - - class(cable_netcdf_decomp_t), allocatable :: land_to_land_int32 - class(cable_netcdf_decomp_t), allocatable :: land_to_land_real32 - class(cable_netcdf_decomp_t), allocatable :: land_to_land_real64 - class(cable_netcdf_decomp_t), allocatable :: land_soil_to_land_soil_int32 - class(cable_netcdf_decomp_t), allocatable :: land_soil_to_land_soil_real32 - class(cable_netcdf_decomp_t), allocatable :: land_soil_to_land_soil_real64 - class(cable_netcdf_decomp_t), allocatable :: land_snow_to_land_snow_int32 - class(cable_netcdf_decomp_t), allocatable :: land_snow_to_land_snow_real32 - class(cable_netcdf_decomp_t), allocatable :: land_snow_to_land_snow_real64 - class(cable_netcdf_decomp_t), allocatable :: land_rad_to_land_rad_int32 - class(cable_netcdf_decomp_t), allocatable :: land_rad_to_land_rad_real32 - class(cable_netcdf_decomp_t), allocatable :: land_rad_to_land_rad_real64 - class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_to_land_plantcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_to_land_plantcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_to_land_plantcarbon_real64 - class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_to_land_soilcarbon_int32 - class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_to_land_soilcarbon_real32 - class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_to_land_soilcarbon_real64 - - end type io_decomp_t - -contains - - subroutine cable_io_decomp_init(io_decomp) - type(io_decomp_t), intent(out), target :: io_decomp - - type(dim_spec_t), allocatable :: mem_shape_land(:) - type(dim_spec_t), allocatable :: mem_shape_land_soil(:) - type(dim_spec_t), allocatable :: mem_shape_land_snow(:) - type(dim_spec_t), allocatable :: mem_shape_land_rad(:) - type(dim_spec_t), allocatable :: mem_shape_land_plantcarbon(:) - type(dim_spec_t), allocatable :: mem_shape_land_soilcarbon(:) - type(dim_spec_t), allocatable :: mem_shape_patch(:) - type(dim_spec_t), allocatable :: mem_shape_patch_soil(:) - type(dim_spec_t), allocatable :: mem_shape_patch_snow(:) - type(dim_spec_t), allocatable :: mem_shape_patch_rad(:) - type(dim_spec_t), allocatable :: mem_shape_patch_plantcarbon(:) - type(dim_spec_t), allocatable :: mem_shape_patch_soilcarbon(:) - - type(dim_spec_t), allocatable :: var_shape_x_y(:) - type(dim_spec_t), allocatable :: var_shape_x_y_soil(:) - type(dim_spec_t), allocatable :: var_shape_x_y_snow(:) - type(dim_spec_t), allocatable :: var_shape_x_y_rad(:) - type(dim_spec_t), allocatable :: var_shape_x_y_plantcarbon(:) - type(dim_spec_t), allocatable :: var_shape_x_y_soilcarbon(:) - type(dim_spec_t), allocatable :: var_shape_x_y_patch(:) - type(dim_spec_t), allocatable :: var_shape_x_y_patch_soil(:) - type(dim_spec_t), allocatable :: var_shape_x_y_patch_snow(:) - type(dim_spec_t), allocatable :: var_shape_x_y_patch_rad(:) - type(dim_spec_t), allocatable :: var_shape_x_y_patch_plantcarbon(:) - type(dim_spec_t), allocatable :: var_shape_x_y_patch_soilcarbon(:) - type(dim_spec_t), allocatable :: var_shape_land(:) - type(dim_spec_t), allocatable :: var_shape_land_soil(:) - type(dim_spec_t), allocatable :: var_shape_land_snow(:) - type(dim_spec_t), allocatable :: var_shape_land_rad(:) - type(dim_spec_t), allocatable :: var_shape_land_plantcarbon(:) - type(dim_spec_t), allocatable :: var_shape_land_soilcarbon(:) - type(dim_spec_t), allocatable :: var_shape_land_patch(:) - type(dim_spec_t), allocatable :: var_shape_land_patch_soil(:) - type(dim_spec_t), allocatable :: var_shape_land_patch_snow(:) - type(dim_spec_t), allocatable :: var_shape_land_patch_rad(:) - type(dim_spec_t), allocatable :: var_shape_land_patch_plantcarbon(:) - type(dim_spec_t), allocatable :: var_shape_land_patch_soilcarbon(:) - type(dim_spec_t), allocatable :: var_shape_patch(:) - type(dim_spec_t), allocatable :: var_shape_patch_soil(:) - type(dim_spec_t), allocatable :: var_shape_patch_snow(:) - type(dim_spec_t), allocatable :: var_shape_patch_rad(:) - type(dim_spec_t), allocatable :: var_shape_patch_plantcarbon(:) - type(dim_spec_t), allocatable :: var_shape_patch_soilcarbon(:) - - logical :: requires_land_output_grid, requires_x_y_output_grid - - mem_shape_land = [dim_spec_t('land', mland)] - mem_shape_land_soil = [dim_spec_t('land', mland), dim_spec_t('soil', ms)] - mem_shape_land_snow = [dim_spec_t('land', mland), dim_spec_t('snow', msn)] - mem_shape_land_rad = [dim_spec_t('land', mland), dim_spec_t('rad', nrb)] - mem_shape_land_plantcarbon = [dim_spec_t('land', mland), dim_spec_t('plantcarbon', ncp)] - mem_shape_land_soilcarbon = [dim_spec_t('land', mland), dim_spec_t('soilcarbon', ncs)] - mem_shape_patch = [dim_spec_t('patch', mp)] - mem_shape_patch_soil = [dim_spec_t('patch', mp), dim_spec_t('soil', ms)] - mem_shape_patch_snow = [dim_spec_t('patch', mp), dim_spec_t('snow', msn)] - mem_shape_patch_rad = [dim_spec_t('patch', mp), dim_spec_t('rad', nrb)] - mem_shape_patch_plantcarbon = [dim_spec_t('patch', mp), dim_spec_t('plantcarbon', ncp)] - mem_shape_patch_soilcarbon = [dim_spec_t('patch', mp), dim_spec_t('soilcarbon', ncs)] - - var_shape_x_y = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize)] - var_shape_x_y_soil = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('soil', ms)] - var_shape_x_y_snow = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('snow', msn)] - var_shape_x_y_rad = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('rad', nrb)] - var_shape_x_y_plantcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('plantcarbon', ncp)] - var_shape_x_y_soilcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('soilcarbon', ncs)] - var_shape_x_y_patch = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches)] - var_shape_x_y_patch_soil = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('soil', ms)] - var_shape_x_y_patch_snow = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('snow', msn)] - var_shape_x_y_patch_rad = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('rad', nrb)] - var_shape_x_y_patch_plantcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('plantcarbon', ncp)] - var_shape_x_y_patch_soilcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('soilcarbon', ncs)] - var_shape_land = [dim_spec_t('land', mland_global)] - var_shape_land_soil = [dim_spec_t('land', mland_global), dim_spec_t('soil', ms)] - var_shape_land_snow = [dim_spec_t('land', mland_global), dim_spec_t('snow', msn)] - var_shape_land_rad = [dim_spec_t('land', mland_global), dim_spec_t('rad', nrb)] - var_shape_land_plantcarbon = [dim_spec_t('land', mland_global), dim_spec_t('plantcarbon', ncp)] - var_shape_land_soilcarbon = [dim_spec_t('land', mland_global), dim_spec_t('soilcarbon', ncs)] - var_shape_land_patch = [dim_spec_t('land', mland_global)] - var_shape_land_patch_soil = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('soil', ms)] - var_shape_land_patch_snow = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('snow', msn)] - var_shape_land_patch_rad = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('rad', nrb)] - var_shape_land_patch_plantcarbon = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('plantcarbon', ncp)] - var_shape_land_patch_soilcarbon = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('soilcarbon', ncs)] - var_shape_patch = [dim_spec_t('patch', mp_global)] - var_shape_patch_soil = [dim_spec_t('patch', mp_global), dim_spec_t('soil', ms)] - var_shape_patch_snow = [dim_spec_t('patch', mp_global), dim_spec_t('snow', msn)] - var_shape_patch_rad = [dim_spec_t('patch', mp_global), dim_spec_t('rad', nrb)] - var_shape_patch_plantcarbon = [dim_spec_t('patch', mp_global), dim_spec_t('plantcarbon', ncp)] - var_shape_patch_soilcarbon = [dim_spec_t('patch', mp_global), dim_spec_t('soilcarbon', ncs)] - - io_decomp%land_to_x_y_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land, var_shape_x_y, CABLE_NETCDF_INT) - io_decomp%land_to_x_y_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land, var_shape_x_y, CABLE_NETCDF_FLOAT) - io_decomp%land_to_x_y_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land, var_shape_x_y, CABLE_NETCDF_DOUBLE) - io_decomp%land_soil_to_x_y_soil_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soil, var_shape_x_y_soil, CABLE_NETCDF_INT) - io_decomp%land_soil_to_x_y_soil_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soil, var_shape_x_y_soil, CABLE_NETCDF_FLOAT) - io_decomp%land_soil_to_x_y_soil_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soil, var_shape_x_y_soil, CABLE_NETCDF_DOUBLE) - io_decomp%land_snow_to_x_y_snow_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_snow, var_shape_x_y_snow, CABLE_NETCDF_INT) - io_decomp%land_snow_to_x_y_snow_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_snow, var_shape_x_y_snow, CABLE_NETCDF_FLOAT) - io_decomp%land_snow_to_x_y_snow_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_snow, var_shape_x_y_snow, CABLE_NETCDF_DOUBLE) - io_decomp%land_rad_to_x_y_rad_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_rad, var_shape_x_y_rad, CABLE_NETCDF_INT) - io_decomp%land_rad_to_x_y_rad_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_rad, var_shape_x_y_rad, CABLE_NETCDF_FLOAT) - io_decomp%land_rad_to_x_y_rad_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_rad, var_shape_x_y_rad, CABLE_NETCDF_DOUBLE) - io_decomp%land_plantcarbon_to_x_y_plantcarbon_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_plantcarbon, var_shape_x_y_plantcarbon, CABLE_NETCDF_INT) - io_decomp%land_plantcarbon_to_x_y_plantcarbon_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_plantcarbon, var_shape_x_y_plantcarbon, CABLE_NETCDF_FLOAT) - io_decomp%land_plantcarbon_to_x_y_plantcarbon_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_plantcarbon, var_shape_x_y_plantcarbon, CABLE_NETCDF_DOUBLE) - io_decomp%land_soilcarbon_to_x_y_soilcarbon_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soilcarbon, var_shape_x_y_soilcarbon, CABLE_NETCDF_INT) - io_decomp%land_soilcarbon_to_x_y_soilcarbon_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soilcarbon, var_shape_x_y_soilcarbon, CABLE_NETCDF_FLOAT) - io_decomp%land_soilcarbon_to_x_y_soilcarbon_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soilcarbon, var_shape_x_y_soilcarbon, CABLE_NETCDF_DOUBLE) - - io_decomp%land_to_land_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land, var_shape_land, CABLE_NETCDF_INT) - io_decomp%land_to_land_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land, var_shape_land, CABLE_NETCDF_FLOAT) - io_decomp%land_to_land_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land, var_shape_land, CABLE_NETCDF_DOUBLE) - io_decomp%land_soil_to_land_soil_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soil, var_shape_land_soil, CABLE_NETCDF_INT) - io_decomp%land_soil_to_land_soil_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soil, var_shape_land_soil, CABLE_NETCDF_FLOAT) - io_decomp%land_soil_to_land_soil_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soil, var_shape_land_soil, CABLE_NETCDF_DOUBLE) - io_decomp%land_snow_to_land_snow_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_snow, var_shape_land_snow, CABLE_NETCDF_INT) - io_decomp%land_snow_to_land_snow_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_snow, var_shape_land_snow, CABLE_NETCDF_FLOAT) - io_decomp%land_snow_to_land_snow_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_snow, var_shape_land_snow, CABLE_NETCDF_DOUBLE) - io_decomp%land_rad_to_land_rad_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_rad, var_shape_land_rad, CABLE_NETCDF_INT) - io_decomp%land_rad_to_land_rad_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_rad, var_shape_land_rad, CABLE_NETCDF_FLOAT) - io_decomp%land_rad_to_land_rad_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_rad, var_shape_land_rad, CABLE_NETCDF_DOUBLE) - io_decomp%land_plantcarbon_to_land_plantcarbon_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_plantcarbon, var_shape_land_plantcarbon, CABLE_NETCDF_INT) - io_decomp%land_plantcarbon_to_land_plantcarbon_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_plantcarbon, var_shape_land_plantcarbon, CABLE_NETCDF_FLOAT) - io_decomp%land_plantcarbon_to_land_plantcarbon_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_plantcarbon, var_shape_land_plantcarbon, CABLE_NETCDF_DOUBLE) - io_decomp%land_soilcarbon_to_land_soilcarbon_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soilcarbon, var_shape_land_soilcarbon, CABLE_NETCDF_INT) - io_decomp%land_soilcarbon_to_land_soilcarbon_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soilcarbon, var_shape_land_soilcarbon, CABLE_NETCDF_FLOAT) - io_decomp%land_soilcarbon_to_land_soilcarbon_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soilcarbon, var_shape_land_soilcarbon, CABLE_NETCDF_DOUBLE) - - io_decomp%patch_to_x_y_patch_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_x_y_patch, CABLE_NETCDF_INT) - io_decomp%patch_to_x_y_patch_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_x_y_patch, CABLE_NETCDF_FLOAT) - io_decomp%patch_to_x_y_patch_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_x_y_patch, CABLE_NETCDF_DOUBLE) - io_decomp%patch_soil_to_x_y_patch_soil_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_x_y_patch_soil, CABLE_NETCDF_INT) - io_decomp%patch_soil_to_x_y_patch_soil_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_x_y_patch_soil, CABLE_NETCDF_FLOAT) - io_decomp%patch_soil_to_x_y_patch_soil_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_x_y_patch_soil, CABLE_NETCDF_DOUBLE) - io_decomp%patch_snow_to_x_y_patch_snow_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_x_y_patch_snow, CABLE_NETCDF_INT) - io_decomp%patch_snow_to_x_y_patch_snow_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_x_y_patch_snow, CABLE_NETCDF_FLOAT) - io_decomp%patch_snow_to_x_y_patch_snow_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_x_y_patch_snow, CABLE_NETCDF_DOUBLE) - io_decomp%patch_rad_to_x_y_patch_rad_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_x_y_patch_rad, CABLE_NETCDF_INT) - io_decomp%patch_rad_to_x_y_patch_rad_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_x_y_patch_rad, CABLE_NETCDF_FLOAT) - io_decomp%patch_rad_to_x_y_patch_rad_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_x_y_patch_rad, CABLE_NETCDF_DOUBLE) - io_decomp%patch_plantcarbon_to_x_y_patch_plantcarbon_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_x_y_patch_plantcarbon, CABLE_NETCDF_INT) - io_decomp%patch_plantcarbon_to_x_y_patch_plantcarbon_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_x_y_patch_plantcarbon, CABLE_NETCDF_FLOAT) - io_decomp%patch_plantcarbon_to_x_y_patch_plantcarbon_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_x_y_patch_plantcarbon, CABLE_NETCDF_DOUBLE) - io_decomp%patch_soilcarbon_to_x_y_patch_soilcarbon_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_x_y_patch_soilcarbon, CABLE_NETCDF_INT) - io_decomp%patch_soilcarbon_to_x_y_patch_soilcarbon_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_x_y_patch_soilcarbon, CABLE_NETCDF_FLOAT) - io_decomp%patch_soilcarbon_to_x_y_patch_soilcarbon_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_x_y_patch_soilcarbon, CABLE_NETCDF_DOUBLE) - - io_decomp%patch_to_land_patch_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_land_patch, CABLE_NETCDF_INT) - io_decomp%patch_to_land_patch_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_land_patch, CABLE_NETCDF_FLOAT) - io_decomp%patch_to_land_patch_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_land_patch, CABLE_NETCDF_DOUBLE) - io_decomp%patch_soil_to_land_patch_soil_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_land_patch_soil, CABLE_NETCDF_INT) - io_decomp%patch_soil_to_land_patch_soil_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_land_patch_soil, CABLE_NETCDF_FLOAT) - io_decomp%patch_soil_to_land_patch_soil_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_land_patch_soil, CABLE_NETCDF_DOUBLE) - io_decomp%patch_snow_to_land_patch_snow_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_land_patch_snow, CABLE_NETCDF_INT) - io_decomp%patch_snow_to_land_patch_snow_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_land_patch_snow, CABLE_NETCDF_FLOAT) - io_decomp%patch_snow_to_land_patch_snow_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_land_patch_snow, CABLE_NETCDF_DOUBLE) - io_decomp%patch_rad_to_land_patch_rad_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_land_patch_rad, CABLE_NETCDF_INT) - io_decomp%patch_rad_to_land_patch_rad_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_land_patch_rad, CABLE_NETCDF_FLOAT) - io_decomp%patch_rad_to_land_patch_rad_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_land_patch_rad, CABLE_NETCDF_DOUBLE) - io_decomp%patch_plantcarbon_to_land_patch_plantcarbon_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_land_patch_plantcarbon, CABLE_NETCDF_INT) - io_decomp%patch_plantcarbon_to_land_patch_plantcarbon_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_land_patch_plantcarbon, CABLE_NETCDF_FLOAT) - io_decomp%patch_plantcarbon_to_land_patch_plantcarbon_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_land_patch_plantcarbon, CABLE_NETCDF_DOUBLE) - io_decomp%patch_soilcarbon_to_land_patch_soilcarbon_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_land_patch_soilcarbon, CABLE_NETCDF_INT) - io_decomp%patch_soilcarbon_to_land_patch_soilcarbon_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_land_patch_soilcarbon, CABLE_NETCDF_FLOAT) - io_decomp%patch_soilcarbon_to_land_patch_soilcarbon_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_land_patch_soilcarbon, CABLE_NETCDF_DOUBLE) - - io_decomp%patch_to_patch_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch, var_shape_patch, CABLE_NETCDF_INT) - io_decomp%patch_to_patch_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch, var_shape_patch, CABLE_NETCDF_FLOAT) - io_decomp%patch_to_patch_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch, var_shape_patch, CABLE_NETCDF_DOUBLE) - io_decomp%patch_soil_to_patch_soil_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soil, var_shape_patch_soil, CABLE_NETCDF_INT) - io_decomp%patch_soil_to_patch_soil_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soil, var_shape_patch_soil, CABLE_NETCDF_FLOAT) - io_decomp%patch_soil_to_patch_soil_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soil, var_shape_patch_soil, CABLE_NETCDF_DOUBLE) - io_decomp%patch_snow_to_patch_snow_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_snow, var_shape_patch_snow, CABLE_NETCDF_INT) - io_decomp%patch_snow_to_patch_snow_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_snow, var_shape_patch_snow, CABLE_NETCDF_FLOAT) - io_decomp%patch_snow_to_patch_snow_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_snow, var_shape_patch_snow, CABLE_NETCDF_DOUBLE) - io_decomp%patch_rad_to_patch_rad_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_rad, var_shape_patch_rad, CABLE_NETCDF_INT) - io_decomp%patch_rad_to_patch_rad_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_rad, var_shape_patch_rad, CABLE_NETCDF_FLOAT) - io_decomp%patch_rad_to_patch_rad_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_rad, var_shape_patch_rad, CABLE_NETCDF_DOUBLE) - io_decomp%patch_plantcarbon_to_patch_plantcarbon_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_plantcarbon, var_shape_patch_plantcarbon, CABLE_NETCDF_INT) - io_decomp%patch_plantcarbon_to_patch_plantcarbon_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_plantcarbon, var_shape_patch_plantcarbon, CABLE_NETCDF_FLOAT) - io_decomp%patch_plantcarbon_to_patch_plantcarbon_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_plantcarbon, var_shape_patch_plantcarbon, CABLE_NETCDF_DOUBLE) - io_decomp%patch_soilcarbon_to_patch_soilcarbon_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soilcarbon, var_shape_patch_soilcarbon, CABLE_NETCDF_INT) - io_decomp%patch_soilcarbon_to_patch_soilcarbon_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soilcarbon, var_shape_patch_soilcarbon, CABLE_NETCDF_FLOAT) - io_decomp%patch_soilcarbon_to_patch_soilcarbon_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soilcarbon, var_shape_patch_soilcarbon, CABLE_NETCDF_DOUBLE) - - end subroutine - -end module diff --git a/src/offline/cable_mpimaster.F90 b/src/offline/cable_mpimaster.F90 index cccdcedea..8e29b7b17 100644 --- a/src/offline/cable_mpimaster.F90 +++ b/src/offline/cable_mpimaster.F90 @@ -80,7 +80,6 @@ MODULE cable_mpimaster spinup, & spincasa, & CASAONLY, & - l_landuse, & delsoilM, & delsoilT, & delgwM, & @@ -91,11 +90,22 @@ MODULE cable_mpimaster compare_consistency_check_values USE cable_mpicommon USE cable_IO_vars_module, ONLY : NO_CHECK - USE cable_io_decomp_mod, ONLY: io_decomp_t, cable_io_decomp_init + use cable_io_vars_module, only: patch USE casa_cable USE casa_inout_module USE cable_checks_module, ONLY: constant_check_range USE cable_mpi_mod, ONLY: mpi_grp_t + use cable_output_prototype_v2_mod, only: cable_output_mod_init + use cable_output_prototype_v2_mod, only: cable_output_mod_end + use cable_output_prototype_v2_mod, only: cable_output_register_output_variables + use cable_output_prototype_v2_mod, only: cable_output_profiles_init + use cable_output_prototype_v2_mod, only: cable_output_update + use cable_output_prototype_v2_mod, only: cable_output_write + use cable_output_prototype_v2_mod, only: cable_output_write_parameters + use cable_output_prototype_v2_mod, only: cable_output_write_restart + use cable_diagnostics_core_mod, only: cable_diagnostics_core + use cable_diagnostics_casa_mod, only: cable_diagnostics_casa + use cable_netcdf_mod, only: cable_netcdf_mod_init, cable_netcdf_mod_end IMPLICIT NONE @@ -181,6 +191,7 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) USE cable_common_module, ONLY: ktau_gl, kend_gl, knode_gl, cable_user, & cable_runtime, fileName, & CurYear, & + l_landuse, & IS_LEAPYEAR, calcsoilalbedo, & kwidth_gl USE casa_ncdf_module, ONLY: is_casa_time @@ -332,7 +343,7 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) integer, dimension(:), allocatable, save :: cstart,cend,nap real(r_2), dimension(:,:,:), allocatable, save :: patchfrac_new - type(io_decomp_t) :: io_decomp + call cable_netcdf_mod_init(mpi_grp_master) ! END header @@ -442,6 +453,15 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) ENDIF CALL nullify_write() ! nullify pointers CALL open_output_file( dels, soil, veg, bgc, rough, met) + + call cable_output_mod_init() + call cable_output_register_output_variables([ & + cable_diagnostics_core(met, canopy, soil, ssnow, rad, veg, bal, rough, bgc, dels=dels), & + cable_diagnostics_casa(casaflux, casapool, casamet) & + ]) + call cable_output_profiles_init() + call cable_output_write_parameters(kstart, patch, landpt, met) + ENDIF ssnow%otss_0 = ssnow%tgg(:,1) @@ -632,7 +652,6 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) ktau = 0 ENDIF - call cable_io_decomp_init(io_decomp) ! MPI: mostly original serial code follows... ENDIF ! CALL1 @@ -769,7 +788,6 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) !$ CALL POPLUC_set_patchfrac(POPLUC,LUC_EXPT) !$ ENDIF - IF ( .NOT. CASAONLY ) THEN IF ( icycle > 0 ) THEN @@ -820,6 +838,9 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) ENDIF ENDIF + call canopy%tscrn_max_daily%accumulate() + call canopy%tscrn_min_daily%accumulate() + ELSE IF ( MOD((ktau-kstart+1+koffset),ktauday)==0 ) THEN CALL master_send_input (icomm, casa_dump_ts, iktau ) @@ -862,11 +883,14 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) casamet,ssnow, & rad, bal, air, soil, veg, CSBOLTZ, & CEMLEAF, CEMSOIL ) + call cable_output_update(ktau_tot, dels, leaps, cable_user%yearstart, met) + call cable_output_write(ktau_tot, dels, leaps, cable_user%yearstart, met, patch, landpt) CASE DEFAULT CALL write_output( dels, ktau, met, canopy, casaflux, casapool, & casamet, ssnow, & rad, bal, air, soil, veg, CSBOLTZ, CEMLEAF, CEMSOIL ) - + call cable_output_update(ktau, dels, leaps, cable_user%yearstart, met) + call cable_output_write(ktau, dels, leaps, cable_user%yearstart, met, patch, landpt) END SELECT END IF ENDIF @@ -1053,13 +1077,22 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) CASE ('plum', 'cru', 'gswp', 'gswp3') CALL write_output( dels, ktau_tot, met, canopy, casaflux, casapool, casamet, & ssnow, rad, bal, air, soil, veg, CSBOLTZ, CEMLEAF, CEMSOIL ) + call cable_output_update(ktau_tot, dels, leaps, cable_user%yearstart, met) + call cable_output_write(ktau_tot, dels, leaps, cable_user%yearstart, met, patch, landpt) CASE DEFAULT CALL write_output( dels, ktau, met, canopy, casaflux, casapool, casamet, & ssnow, rad, bal, air, soil, veg, CSBOLTZ, CEMLEAF, CEMSOIL ) - + call cable_output_update(ktau, dels, leaps, cable_user%yearstart, met) + call cable_output_write(ktau, dels, leaps, cable_user%yearstart, met, patch, landpt) END SELECT END IF + IF (.not. casaonly .and. ktau > kstart .and. mod(ktau - kstart + 1, ktauday) == 0) THEN + ! Reset daily aggregators if previous time step was the end of day + CALL canopy%tscrn_max_daily%reset() + CALL canopy%tscrn_min_daily%reset() + END IF + IF(cable_user%consistency_check) THEN count_bal = count_bal +1; @@ -1258,6 +1291,7 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) if(.not.l_landuse) then CALL create_restart( logn, dels, ktau, soil, veg, ssnow, & canopy, rough, rad, bgc, bal, met ) + call cable_output_write_restart(current_time=ktau * dels) endif IF (cable_user%CALL_climate) THEN @@ -1321,7 +1355,9 @@ SUBROUTINE mpidrv_master (comm, dels, koffset, kend, PLUME, CRU, mpi_grp_master) call landuse_deallocate_mp(cend(mland),ms,msn,nrb,mplant,mlitter,msoil,mwood,lucmp) ENDIF + if (.not. casaonly) call cable_output_mod_end() + call cable_netcdf_mod_end() ! Close met data input file: IF ( TRIM(cable_user%MetType) .NE. "gswp" .AND. & diff --git a/src/offline/cable_mpiworker.F90 b/src/offline/cable_mpiworker.F90 index 030f62af1..405573f24 100644 --- a/src/offline/cable_mpiworker.F90 +++ b/src/offline/cable_mpiworker.F90 @@ -70,13 +70,11 @@ MODULE cable_mpiworker spinup, & spincasa, & CASAONLY, & - l_laiFeedbk, & - l_vcmaxFeedbk, & delsoilM, & delsoilT, & LALLOC USE cable_mpicommon - USE cable_common_module, ONLY: cable_user + USE cable_common_module, ONLY: cable_user, l_laiFeedbk, l_vcmaxFeedbk USE casa_inout_module USE casa_cable USE bgcdriver_mod, ONLY : bgcdriver diff --git a/src/offline/cable_serial.F90 b/src/offline/cable_serial.F90 index 14aa29449..1f070ce57 100644 --- a/src/offline/cable_serial.F90 +++ b/src/offline/cable_serial.F90 @@ -66,10 +66,6 @@ MODULE cable_serial spinup, & spincasa, & CASAONLY, & - l_casacnp, & - l_landuse, & - l_laiFeedbk, & - l_vcmaxFeedbk, & delsoilM, & delsoilT, & delgwM, & @@ -85,13 +81,15 @@ MODULE cable_serial patch_type,landpt,& defaultLAI, sdoy, smoy, syear, timeunits, calendar, & NO_CHECK - USE cable_io_decomp_mod, ONLY: io_decomp_t - USE cable_io_decomp_mod, ONLY: cable_io_decomp_init + use cable_io_vars_module, only: patch USE casa_ncdf_module, ONLY: is_casa_time USE cable_common_module, ONLY: ktau_gl, kend_gl, knode_gl, cable_user, & filename, myhome, & CurYear, & IS_LEAPYEAR, & + l_landuse, & + l_laiFeedbk, & + l_vcmaxFeedbk, & kwidth_gl ! physical constants @@ -112,6 +110,17 @@ MODULE cable_serial ncid_wd,ncid_mask USE cable_output_module, ONLY: create_restart,open_output_file, & write_output,close_output_file + use cable_output_prototype_v2_mod, only: cable_output_mod_init + use cable_output_prototype_v2_mod, only: cable_output_mod_end + use cable_output_prototype_v2_mod, only: cable_output_register_output_variables + use cable_output_prototype_v2_mod, only: cable_output_profiles_init + use cable_output_prototype_v2_mod, only: cable_output_update + use cable_output_prototype_v2_mod, only: cable_output_write + use cable_output_prototype_v2_mod, only: cable_output_write_parameters + use cable_output_prototype_v2_mod, only: cable_output_write_restart + use cable_diagnostics_core_mod, only: cable_diagnostics_core + use cable_diagnostics_casa_mod, only: cable_diagnostics_casa + use cable_netcdf_mod, only: cable_netcdf_mod_init, cable_netcdf_mod_end USE cable_checks_module, ONLY: constant_check_range USE cable_write_module, ONLY: nullify_write USE cable_IO_vars_module, ONLY: timeunits,calendar @@ -271,12 +280,11 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi integer, dimension(:,:), allocatable, save :: landmask integer, dimension(:), allocatable, save :: cstart,cend,nap real(r_2), dimension(:,:,:), allocatable, save :: patchfrac_new - - type(io_decomp_t) :: io_decomp ! END header ! INISTUFF + call cable_netcdf_mod_init(mpi_grp) ! outer loop - spinup loop no. ktau_tot : ktau = 0 @@ -423,6 +431,15 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi ENDIF CALL nullify_write() ! nullify pointers CALL open_output_file( dels, soil, veg, bgc, rough, met) + + call cable_output_mod_init() + call cable_output_register_output_variables([ & + cable_diagnostics_core(met, canopy, soil, ssnow, rad, veg, bal, rough, bgc, dels=dels), & + cable_diagnostics_casa(casaflux, casapool, casamet) & + ]) + call cable_output_profiles_init() + call cable_output_write_parameters(kstart, patch, landpt, met) + ENDIF ssnow%otss_0 = ssnow%tgg(:,1) @@ -460,8 +477,6 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi ENDIF - call cable_io_decomp_init(io_decomp) - ENDIF ! CALL 1 ! globally (WRT code) accessible kend through USE cable_common_module @@ -581,6 +596,7 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi IF (l_laiFeedbk.AND.icycle>0) veg%vlai(:) = casamet%glai(:) IF (.NOT. allocated(c1)) ALLOCATE( c1(mp,nrb), rhoch(mp,nrb), xk(mp,nrb) ) + ! Call land surface scheme for this timestep, all grid points: CALL cbm( ktau, dels, air, bgc, canopy, met, bal, & rad, rough, soil, ssnow, sum_flux, veg, climate, xk, c1, rhoch ) @@ -595,9 +611,8 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi ssnow%rnof2 = ssnow%rnof2*dels ssnow%runoff = ssnow%runoff*dels - - - + call canopy%tscrn_max_daily%accumulate() + call canopy%tscrn_min_daily%accumulate() ELSE IF ( IS_CASA_TIME("dread", yyyy, ktau, kstart, & koffset, kend, ktauday, logn) ) THEN ! CLN READ FROM FILE INSTEAD ! @@ -718,12 +733,22 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi CASE ('plum', 'cru', 'bios', 'gswp', 'gswp3', 'site') CALL write_output( dels, ktau_tot, met, canopy, casaflux, casapool, casamet, & ssnow, rad, bal, air, soil, veg, CSBOLTZ, CEMLEAF, CEMSOIL ) + call cable_output_update(ktau_tot, dels, leaps, cable_user%yearstart, met) + call cable_output_write(ktau_tot, dels, leaps, cable_user%yearstart, met, patch, landpt) CASE DEFAULT CALL write_output( dels, ktau, met, canopy, casaflux, casapool, casamet, & ssnow, rad, bal, air, soil, veg, CSBOLTZ, CEMLEAF, CEMSOIL ) + call cable_output_update(ktau, dels, leaps, cable_user%yearstart, met) + call cable_output_write(ktau, dels, leaps, cable_user%yearstart, met, patch, landpt) END SELECT ENDIF + IF (.not. casaonly .and. ktau > kstart .and. mod(ktau - kstart + 1, ktauday) == 0) THEN + ! Reset daily aggregators if it is the end of day + CALL canopy%tscrn_max_daily%reset() + CALL canopy%tscrn_min_daily%reset() + END IF + ! Check triggered by cable_user%consistency_check = .TRUE. in cable.nml IF(cable_user%consistency_check) THEN @@ -1004,9 +1029,11 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi IF ( .NOT. CASAONLY.and. .not. l_landuse ) THEN ! Write restart file if requested: - IF(output%restart) & + IF(output%restart) then CALL create_restart( logn, dels, ktau, soil, veg, ssnow, & canopy, rough, rad, bgc, bal, met ) + call cable_output_write_restart(current_time=ktau * dels) + end if !mpidiff IF (cable_user%CALL_climate) & CALL WRITE_CLIMATE_RESTART_NC ( climate, ktauday ) @@ -1014,7 +1041,9 @@ SUBROUTINE serialdrv(NRRRR, dels, koffset, kend, GSWP_MID, PLUME, CRU, site, mpi !--- LN ------------------------------------------[ ENDIF + if (.not. casaonly) call cable_output_mod_end() + call cable_netcdf_mod_end() IF ( TRIM(cable_user%MetType) .NE. "gswp" .AND. & TRIM(cable_user%MetType) .NE. "gswp3" .AND. & diff --git a/src/offline/casa_cable.F90 b/src/offline/casa_cable.F90 index b85c0ea1c..2498df01b 100644 --- a/src/offline/casa_cable.F90 +++ b/src/offline/casa_cable.F90 @@ -540,7 +540,8 @@ SUBROUTINE sumcflux(ktau, kstart, kend, dels, bgc, canopy, & sum_flux%sumrs = sum_flux%sumrs+canopy%frs*dels endif ! Set net ecosystem exchange after adjustments to frs: - canopy%fnpp = -1.0* canopy%fpn - canopy%frp + canopy%fnpp = casaflux%cnpp / 86400.0 + canopy%fra = canopy%frp + canopy%frday IF (icycle <= 1) THEN canopy%fnee = canopy%fpn + canopy%frs + canopy%frp ELSE diff --git a/src/offline/cbl_model_driver_offline.F90 b/src/offline/cbl_model_driver_offline.F90 index 763e68075..751b85b07 100644 --- a/src/offline/cbl_model_driver_offline.F90 +++ b/src/offline/cbl_model_driver_offline.F90 @@ -180,6 +180,8 @@ SUBROUTINE cbm( ktau,dels, air, bgc, canopy, met, rad%reffbm, rad%reffdf & ) !EffSurfRefl_beam, EffSurfRefldif_ +rad%albedo_T = (rad%albedo(:, 1) + rad%albedo(:, 2)) * 0.5 + ssnow%otss_0 = ssnow%otss ! vh should be before call to canopy? ssnow%otss = ssnow%tss @@ -219,11 +221,13 @@ SUBROUTINE cbm( ktau,dels, air, bgc, canopy, met, CALL carbon_pl(dels, soil, ssnow, veg, canopy, bgc) - canopy%fnpp = -1.0* canopy%fpn - canopy%frp + canopy%fnpp = -1.0 * canopy%fpn - canopy%frp canopy%fnee = canopy%fpn + canopy%frs + canopy%frp + canopy%fra = canopy%frp + canopy%frday ENDIF + canopy%fgpp = -1.0 * canopy%fpn + canopy%frday END SUBROUTINE cbm diff --git a/src/params/cable_phys_constants_mod.F90 b/src/params/cable_phys_constants_mod.F90 index 09138981b..99af05651 100644 --- a/src/params/cable_phys_constants_mod.F90 +++ b/src/params/cable_phys_constants_mod.F90 @@ -42,6 +42,7 @@ MODULE cable_phys_constants_mod REAL, PARAMETER :: cswat = 4.218e3 ! specific heat for water at 0°C (J/kg/K) REAL, PARAMETER :: density_liq = 1000.0 ! density of liquid water REAL, PARAMETER :: density_ice = 921.0 ! density of ice +REAL, PARAMETER :: c_molar_mass = 1.201e-5 ! molar mass of carbon (ug/mol) ! Teten coefficients REAL, PARAMETER :: tetena = 6.106 ! Magnus Tetans (Murray 1967) diff --git a/src/science/canopy/cable_canopy.F90 b/src/science/canopy/cable_canopy.F90 index 96073e6dc..2be20df78 100644 --- a/src/science/canopy/cable_canopy.F90 +++ b/src/science/canopy/cable_canopy.F90 @@ -654,6 +654,14 @@ SUBROUTINE define_canopy(bal,rad,rough,air,met,dels,ssnow,soil,veg, canopy,clima !CABLE3 #335 - AM3 #250 - removing the transd weighting canopy%epot = (canopy%fevw_pot + ssnow%potev/ssnow%cls) * dels/air%rlam + canopy%et = canopy%fe / air%rlam + + canopy%eint = canopy%fevw / air%rlam + + canopy%tveg = canopy%fevc / air%rlam + + canopy%esoil = canopy%fes / air%rlam + rlower_limit = canopy%epot * air%rlam / dels WHERE (rlower_limit == 0 ) rlower_limit = 1.e-7 !prevent from 0. by adding 1.e-7 (W/m2) @@ -840,6 +848,8 @@ SUBROUTINE define_canopy(bal,rad,rough,air,met,dels,ssnow,soil,veg, canopy,clima qsurf(j) = 0.1*rsts(j)*ssnow%wetfac(j) + 0.9*met%qv(j) ENDIF + canopy%qmom(j) = air%rho(j) * canopy%us(j) ** 2.0 + canopy%qscrn(j) = met%qv(j) - qstar(j) * ftemp(j) IF( canopy%vlaiw(j) >CLAI_THRESH .AND. rough%hruff(j) > 0.01) THEN @@ -1031,6 +1041,10 @@ SUBROUTINE define_canopy(bal,rad,rough,air,met,dels,ssnow,soil,veg, canopy,clima + CCAPP*Crmair * (tlfy-met%tk) * sum_rad_gradis * & canopy%fwet ! YP nov2009 +rad%swnet = sum(rad%qcan(:, :, 1), 2) + SUM(rad%qcan(:, :, 2), 2) + rad%qssabs +rad%lwnet = met%fld - CSboltz * Cemleaf * canopy%tv**4 * (1 - rad%transd) - rad%flws * rad%transd +rad%rnet = rad%swnet + rad%lwnet + DEALLOCATE(cansat,gbhu) DEALLOCATE(dsx, fwsoil, tlfx, tlfy) DEALLOCATE(ecy, hcy, rny) diff --git a/src/science/casa-cnp/biogeochem_casa.F90 b/src/science/casa-cnp/biogeochem_casa.F90 index ab0f4ebb1..78f9834e2 100644 --- a/src/science/casa-cnp/biogeochem_casa.F90 +++ b/src/science/casa-cnp/biogeochem_casa.F90 @@ -171,6 +171,12 @@ SUBROUTINE biogeochem(ktau,dels,idoY,LALLOC,veg,soil,casabiome,casapool,casaflux casapool%Psoillab = max(casapool%Psoillab,0.1) ENDIF +casaflux%cnbp = casaflux%cnpp + casapool%dClabiledt - casaflux%Crsoil + +casaflux%cplant_turnover_tot = sum(casaflux%Cplant_turnover, 2) + +casapool%dCdt = casapool%ctot - casapool%ctot_0 + END SUBROUTINE biogeochem END MODULE biogeochem_mod diff --git a/src/science/casa-cnp/casa_cnp.F90 b/src/science/casa-cnp/casa_cnp.F90 index 685b248e3..326b4d8b8 100644 --- a/src/science/casa-cnp/casa_cnp.F90 +++ b/src/science/casa-cnp/casa_cnp.F90 @@ -2181,13 +2181,13 @@ SUBROUTINE casa_cnpbal(veg,casamet,casapool,casaflux,casabal) ENDIF ENDDO - - + casapool%cplanttot = sum(casapool%cplant, wood) + casapool%clittertot = sum(casapool%clitter, str) + casapool%csoiltot = sum(casapool%csoil, slow) + casapool%clittertot casapool%ctot_0 = SUM(casabal%cplantlast,2)+SUM(casabal%clitterlast,2) & + SUM(casabal%csoillast,2)+ casabal%clabilelast - casapool%ctot = SUM(casapool%cplant,2)+SUM(casapool%clitter,2) & - + SUM(casapool%csoil,2)+ casapool%clabile + casapool%ctot = casapool%cplanttot + casapool%csoiltot + casapool%clabile casabal%sumcbal = casabal%sumcbal + casabal%cbalance diff --git a/src/science/casa-cnp/casa_readbiome.F90 b/src/science/casa-cnp/casa_readbiome.F90 index fc9c88355..fdba821e2 100644 --- a/src/science/casa-cnp/casa_readbiome.F90 +++ b/src/science/casa-cnp/casa_readbiome.F90 @@ -408,6 +408,9 @@ SUBROUTINE casa_readbiome(veg,soil,casabiome,casapool,casaflux,casamet,phen) /(casaflux%kmlabp(:)+casapool%psoillab(:)) ENDIF + casapool%clittertot = sum(casapool%clitter, str) + casapool%cplanttot = sum(casapool%cplant, wood) + casapool%csoiltot = sum(casapool%csoil, slow) + casapool%clittertot END SUBROUTINE casa_readbiome diff --git a/src/science/casa-cnp/casa_sumcflux.F90 b/src/science/casa-cnp/casa_sumcflux.F90 index 6257c0794..9406fbe60 100644 --- a/src/science/casa-cnp/casa_sumcflux.F90 +++ b/src/science/casa-cnp/casa_sumcflux.F90 @@ -88,7 +88,8 @@ SUBROUTINE sumcflux(ktau, kstart, kend, dels, bgc, canopy, & sum_flux%sumrs = sum_flux%sumrs+canopy%frs*dels endif ! Set net ecosystem exchange after adjustments to frs: - canopy%fnpp = -1.0* canopy%fpn - canopy%frp + canopy%fnpp = casaflux%cnpp / 86400.0 + canopy%fra = canopy%frp + canopy%frday IF (icycle <= 1) THEN canopy%fnee = canopy%fpn + canopy%frs + canopy%frp ELSE diff --git a/src/science/casa-cnp/casa_variable.F90 b/src/science/casa-cnp/casa_variable.F90 index 2937f2f93..c1f4def45 100644 --- a/src/science/casa-cnp/casa_variable.F90 +++ b/src/science/casa-cnp/casa_variable.F90 @@ -84,6 +84,10 @@ MODULE casavariable TYPE casa_pool REAL(r_2), DIMENSION(:),POINTER :: Clabile, & dClabiledt, & + dCdt , & + Cplanttot, & + Clittertot, & + Csoiltot, & Ctot , & ! vh_js ! Ctot_0 REAL(r_2), DIMENSION(:,:),POINTER :: Cplant, & @@ -132,6 +136,7 @@ MODULE casavariable TYPE casa_flux REAL(r_2), DIMENSION(:),POINTER :: Cgpp, & Cnpp, & + Cnbp, & Crp, & Crgplant, & Nminfix, & @@ -142,6 +147,7 @@ MODULE casavariable ! vh_js ! the 3 variables below are needed for POP coupling to CASA stemnpp, & frac_sapwood, & + Cplant_turnover_tot, & sapwood_area REAL(r_2), DIMENSION(:,:),POINTER :: fracCalloc, & fracNalloc, & @@ -203,6 +209,7 @@ MODULE casavariable REAL(r_2), DIMENSION(:),POINTER :: FluxNtoclear REAL(r_2), DIMENSION(:),POINTER :: FluxPtoclear REAL(r_2), DIMENSION(:),POINTER :: CtransferLUC + REAL(r_2), DIMENSION(:),POINTER :: FluxCtoLUC REAL(r_2), DIMENSION(:),POINTER :: meangpp REAL(r_2), DIMENSION(:),POINTER :: meanrleaf END TYPE casa_flux @@ -364,6 +371,10 @@ SUBROUTINE alloc_casavariable(casabiome,casapool,casaflux, & ALLOCATE(casapool%Clabile(arraysize), & casapool%dClabiledt(arraysize), & + casapool%dCdt(arraysize), & + casapool%Cplanttot(arraysize), & + casapool%Clittertot(arraysize), & + casapool%Csoiltot(arraysize), & casapool%Cplant(arraysize,mplant), & casapool%Nplant(arraysize,mplant), & casapool%Pplant(arraysize,mplant), & @@ -412,6 +423,7 @@ SUBROUTINE alloc_casavariable(casabiome,casapool,casaflux, & ALLOCATE(casaflux%Cgpp(arraysize), & casaflux%Cnpp(arraysize), & + casaflux%Cnbp(arraysize), & casaflux%Crp(arraysize), & casaflux%Crgplant(arraysize), & casaflux%Nminfix(arraysize), & @@ -460,6 +472,7 @@ SUBROUTINE alloc_casavariable(casabiome,casapool,casaflux, & casaflux%fromStoCO2(arraysize,msoil), & casaflux%stemnpp(arraysize), & casaflux%frac_sapwood(arraysize), & + casaflux%Cplant_turnover_tot(arraysize), & casaflux%sapwood_area(arraysize), & casaflux%Cplant_turnover(arraysize,mplant) , & casaflux%Cplant_turnover_disturbance(arraysize) , & @@ -493,6 +506,7 @@ SUBROUTINE alloc_casavariable(casabiome,casapool,casaflux, & ) ALLOCATE(casaflux%CtransferLUC(arraysize), SOURCE=0.0_r_2) + ALLOCATE(casaflux%FluxCtoLUC(arraysize), SOURCE=0.0_r_2) ALLOCATE(casaflux%FluxCtoco2(arraysize), SOURCE=0.0_r_2) diff --git a/src/science/pop/POPLUC.F90 b/src/science/pop/POPLUC.F90 index 579551967..08686f73f 100644 --- a/src/science/pop/POPLUC.F90 +++ b/src/science/pop/POPLUC.F90 @@ -1037,6 +1037,8 @@ SUBROUTINE POP_LUC_CASA_transfer(POPLUC,POP,LUC_EXPT,casapool,casabal,casaflux,k 991 FORMAT(1166(e14.7,2x)) + casaflux%FluxCtoLUC = casaflux%FluxCtohwp + casaflux%FluxCtoclear + ! update total carbon pools and "last" pool values for use in carbon balance checks. casapool%ctot = SUM(casapool%cplant,2)+SUM(casapool%clitter,2)+ & SUM(casapool%csoil,2)+casapool%clabile diff --git a/src/science/soilsnow/cbl_soilsnow_main.F90 b/src/science/soilsnow/cbl_soilsnow_main.F90 index d630abf5c..587cb903d 100644 --- a/src/science/soilsnow/cbl_soilsnow_main.F90 +++ b/src/science/soilsnow/cbl_soilsnow_main.F90 @@ -193,6 +193,8 @@ SUBROUTINE soil_snow(dels, soil, ssnow, canopy, met, bal, veg) ssnow%wbliq = ssnow%wb - ssnow%wbice + ssnow%totsdepth = sum(ssnow%sdepth, dim=2) + ssnow%wbtot = 0.0 DO k = 1, ms ! tot moisture this timestep diff --git a/src/util/aggregator.F90 b/src/util/aggregator.F90 new file mode 100644 index 000000000..3152aed58 --- /dev/null +++ b/src/util/aggregator.F90 @@ -0,0 +1,715 @@ +module aggregator_mod + + use iso_fortran_env, only: int32, real32, real64 + use cable_abort_module, only: cable_abort + + implicit none + private + + public :: aggregator_t + public :: aggregator_int32_0d_t + public :: aggregator_int32_1d_t + public :: aggregator_int32_2d_t + public :: aggregator_int32_3d_t + public :: aggregator_real32_0d_t + public :: aggregator_real32_1d_t + public :: aggregator_real32_2d_t + public :: aggregator_real32_3d_t + public :: aggregator_real64_0d_t + public :: aggregator_real64_1d_t + public :: aggregator_real64_2d_t + public :: aggregator_real64_3d_t + public :: new_aggregator + + type, abstract :: aggregator_t + integer :: counter = 0 + procedure(accumulate_data), pointer :: accumulate + procedure(reset_data), pointer :: reset + contains + procedure :: init => aggregator_init + procedure :: set_method => aggregator_set_method + procedure :: type => aggregator_type + procedure :: rank => aggregator_rank + procedure :: shape => aggregator_shape + procedure :: scale => aggregator_scale + procedure :: offset => aggregator_offset + end type aggregator_t + + abstract interface + subroutine accumulate_data(this) + import aggregator_t + class(aggregator_t), intent(inout) :: this + end subroutine accumulate_data + subroutine reset_data(this) + import aggregator_t + class(aggregator_t), intent(inout) :: this + end subroutine reset_data + end interface + + type, extends(aggregator_t) :: aggregator_int32_0d_t + integer(kind=int32), allocatable :: aggregated_data + integer(kind=int32), pointer :: source_data => null() + end type aggregator_int32_0d_t + + type, extends(aggregator_t) :: aggregator_int32_1d_t + integer(kind=int32), dimension(:), allocatable :: aggregated_data + integer(kind=int32), dimension(:), pointer :: source_data => null() + end type aggregator_int32_1d_t + + type, extends(aggregator_t) :: aggregator_int32_2d_t + integer(kind=int32), dimension(:,:), allocatable :: aggregated_data + integer(kind=int32), dimension(:,:), pointer :: source_data => null() + end type aggregator_int32_2d_t + + type, extends(aggregator_t) :: aggregator_int32_3d_t + integer(kind=int32), dimension(:,:,:), allocatable :: aggregated_data + integer(kind=int32), dimension(:,:,:), pointer :: source_data => null() + end type aggregator_int32_3d_t + + type, extends(aggregator_t) :: aggregator_real32_0d_t + real(kind=real32), allocatable :: aggregated_data + real(kind=real32), pointer :: source_data => null() + end type aggregator_real32_0d_t + + type, extends(aggregator_t) :: aggregator_real32_1d_t + real(kind=real32), dimension(:), allocatable :: aggregated_data + real(kind=real32), dimension(:), pointer :: source_data => null() + end type aggregator_real32_1d_t + + type, extends(aggregator_t) :: aggregator_real32_2d_t + real(kind=real32), dimension(:,:), allocatable :: aggregated_data + real(kind=real32), dimension(:,:), pointer :: source_data => null() + end type aggregator_real32_2d_t + + type, extends(aggregator_t) :: aggregator_real32_3d_t + real(kind=real32), dimension(:,:,:), allocatable :: aggregated_data + real(kind=real32), dimension(:,:,:), pointer :: source_data => null() + end type aggregator_real32_3d_t + + type, extends(aggregator_t) :: aggregator_real64_0d_t + real(kind=real64), allocatable :: aggregated_data + real(kind=real64), pointer :: source_data => null() + end type aggregator_real64_0d_t + + type, extends(aggregator_t) :: aggregator_real64_1d_t + real(kind=real64), dimension(:), allocatable :: aggregated_data + real(kind=real64), dimension(:), pointer :: source_data => null() + end type aggregator_real64_1d_t + + type, extends(aggregator_t) :: aggregator_real64_2d_t + real(kind=real64), dimension(:,:), allocatable :: aggregated_data + real(kind=real64), dimension(:,:), pointer :: source_data => null() + end type aggregator_real64_2d_t + + type, extends(aggregator_t) :: aggregator_real64_3d_t + real(kind=real64), dimension(:,:,:), allocatable :: aggregated_data + real(kind=real64), dimension(:,:,:), pointer :: source_data => null() + end type aggregator_real64_3d_t + + interface new_aggregator + module procedure new_aggregator_int32_0d_t + module procedure new_aggregator_int32_1d_t + module procedure new_aggregator_int32_2d_t + module procedure new_aggregator_int32_3d_t + module procedure new_aggregator_real32_0d + module procedure new_aggregator_real32_1d + module procedure new_aggregator_real32_2d + module procedure new_aggregator_real32_3d + module procedure new_aggregator_real64_0d + module procedure new_aggregator_real64_1d + module procedure new_aggregator_real64_2d + module procedure new_aggregator_real64_3d + end interface + +contains + + subroutine aggregator_init(this, method) + class(aggregator_t), intent(inout) :: this + character(len=*), intent(in) :: method + + select type (this) + type is (aggregator_int32_0d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_int32_1d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_int32_2d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_int32_3d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real32_0d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real32_1d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real32_2d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real32_3d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real64_0d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real64_1d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real64_2d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + type is (aggregator_real64_3d_t) + if (.not. allocated(this%aggregated_data)) allocate(this%aggregated_data, mold=this%source_data) + end select + + call this%set_method(method) + + call this%reset() + + end subroutine aggregator_init + + subroutine aggregator_set_method(this, method) + class(aggregator_t), intent(inout) :: this + character(len=*), intent(in) :: method + + if (method == "mean") then + this%accumulate => mean_accumulate + this%reset => other_reset + elseif (method == "sum") then + this%accumulate => sum_accumulate + this%reset => other_reset + elseif (method == "point") then + this%accumulate => point_accumulate + this%reset => point_reset + elseif (method == "min") then + this%accumulate => min_accumulate + this%reset => min_reset + elseif (method == "max") then + this%accumulate => max_accumulate + this%reset => max_reset + else + call cable_abort("Aggregation method "//method//" is invalid.") + endif + + end subroutine aggregator_set_method + + character(16) function aggregator_type(this) + class(aggregator_t), intent(in) :: this + + select type (this) + type is (aggregator_int32_0d_t) + aggregator_type = "int32" + type is (aggregator_int32_1d_t) + aggregator_type = "int32" + type is (aggregator_int32_2d_t) + aggregator_type = "int32" + type is (aggregator_int32_3d_t) + aggregator_type = "int32" + type is (aggregator_real32_0d_t) + aggregator_type = "real32" + type is (aggregator_real32_1d_t) + aggregator_type = "real32" + type is (aggregator_real32_2d_t) + aggregator_type = "real32" + type is (aggregator_real32_3d_t) + aggregator_type = "real32" + type is (aggregator_real64_0d_t) + aggregator_type = "real64" + type is (aggregator_real64_1d_t) + aggregator_type = "real64" + type is (aggregator_real64_2d_t) + aggregator_type = "real64" + type is (aggregator_real64_3d_t) + aggregator_type = "real64" + end select + + end function aggregator_type + + integer function aggregator_rank(this) + class(aggregator_t), intent(in) :: this + + select type (this) + type is (aggregator_int32_0d_t) + aggregator_rank = 0 + type is (aggregator_int32_1d_t) + aggregator_rank = 1 + type is (aggregator_int32_2d_t) + aggregator_rank = 2 + type is (aggregator_int32_3d_t) + aggregator_rank = 3 + type is (aggregator_real32_0d_t) + aggregator_rank = 0 + type is (aggregator_real32_1d_t) + aggregator_rank = 1 + type is (aggregator_real32_2d_t) + aggregator_rank = 2 + type is (aggregator_real32_3d_t) + aggregator_rank = 3 + type is (aggregator_real64_0d_t) + aggregator_rank = 0 + type is (aggregator_real64_1d_t) + aggregator_rank = 1 + type is (aggregator_real64_2d_t) + aggregator_rank = 2 + type is (aggregator_real64_3d_t) + aggregator_rank = 3 + end select + + end function aggregator_rank + + function aggregator_shape(this) result(agg_shape) + class(aggregator_t), intent(in) :: this + integer, allocatable :: agg_shape(:) + + select type (this) + type is (aggregator_int32_0d_t) + agg_shape = shape(this%source_data) + type is (aggregator_int32_1d_t) + agg_shape = shape(this%source_data) + type is (aggregator_int32_2d_t) + agg_shape = shape(this%source_data) + type is (aggregator_int32_3d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real32_0d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real32_1d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real32_2d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real32_3d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real64_0d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real64_1d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real64_2d_t) + agg_shape = shape(this%source_data) + type is (aggregator_real64_3d_t) + agg_shape = shape(this%source_data) + end select + + end function aggregator_shape + + subroutine aggregator_scale(this, scale) + class(aggregator_t), intent(inout) :: this + real, intent(in) :: scale + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_int32_1d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_int32_2d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_int32_3d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real32_0d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real32_1d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real32_2d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real32_3d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real64_0d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real64_1d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real64_2d_t) + this%aggregated_data = this%aggregated_data * scale + type is (aggregator_real64_3d_t) + this%aggregated_data = this%aggregated_data * scale + end select + + end subroutine aggregator_scale + + subroutine aggregator_offset(this, offset) + class(aggregator_t), intent(inout) :: this + real, intent(in) :: offset + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_int32_1d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_int32_2d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_int32_3d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real32_0d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real32_1d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real32_2d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real32_3d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real64_0d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real64_1d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real64_2d_t) + this%aggregated_data = this%aggregated_data + offset + type is (aggregator_real64_3d_t) + this%aggregated_data = this%aggregated_data + offset + end select + + end subroutine aggregator_offset + + subroutine mean_accumulate(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_real32_0d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + type is (aggregator_real32_1d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + type is (aggregator_real32_2d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + type is (aggregator_real32_3d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + type is (aggregator_real64_0d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + type is (aggregator_real64_1d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + type is (aggregator_real64_2d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + type is (aggregator_real64_3d_t) + this%aggregated_data = this%aggregated_data + (this%source_data - this%aggregated_data) / (this%counter + 1) + end select + + this%counter = this%counter + 1 + + end subroutine mean_accumulate + + subroutine sum_accumulate(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_int32_1d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_int32_2d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_int32_3d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real32_0d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real32_1d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real32_2d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real32_3d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real64_0d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real64_1d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real64_2d_t) + this%aggregated_data = this%aggregated_data + this%source_data + type is (aggregator_real64_3d_t) + this%aggregated_data = this%aggregated_data + this%source_data + end select + + this%counter = this%counter + 1 + + end subroutine sum_accumulate + + subroutine point_accumulate(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = this%source_data + type is (aggregator_int32_1d_t) + this%aggregated_data = this%source_data + type is (aggregator_int32_2d_t) + this%aggregated_data = this%source_data + type is (aggregator_int32_3d_t) + this%aggregated_data = this%source_data + type is (aggregator_real32_0d_t) + this%aggregated_data = this%source_data + type is (aggregator_real32_1d_t) + this%aggregated_data = this%source_data + type is (aggregator_real32_2d_t) + this%aggregated_data = this%source_data + type is (aggregator_real32_3d_t) + this%aggregated_data = this%source_data + type is (aggregator_real64_0d_t) + this%aggregated_data = this%source_data + type is (aggregator_real64_1d_t) + this%aggregated_data = this%source_data + type is (aggregator_real64_2d_t) + this%aggregated_data = this%source_data + type is (aggregator_real64_3d_t) + this%aggregated_data = this%source_data + end select + + this%counter = this%counter + 1 + + end subroutine point_accumulate + + subroutine min_accumulate(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_int32_1d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_int32_2d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_int32_3d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real32_0d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real32_1d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real32_2d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real32_3d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real64_0d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real64_1d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real64_2d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + type is (aggregator_real64_3d_t) + this%aggregated_data = min(this%aggregated_data, this%source_data) + end select + + this%counter = this%counter + 1 + + end subroutine min_accumulate + + subroutine max_accumulate(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_int32_1d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_int32_2d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_int32_3d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real32_0d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real32_1d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real32_2d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real32_3d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real64_0d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real64_1d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real64_2d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + type is (aggregator_real64_3d_t) + this%aggregated_data = max(this%aggregated_data, this%source_data) + end select + + this%counter = this%counter + 1 + + end subroutine max_accumulate + + subroutine point_reset(this) + class(aggregator_t), intent(inout) :: this + end subroutine point_reset + + subroutine min_reset(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = huge(int(0_int32)) + type is (aggregator_int32_1d_t) + this%aggregated_data = huge(int(0_int32)) + type is (aggregator_int32_2d_t) + this%aggregated_data = huge(int(0_int32)) + type is (aggregator_int32_3d_t) + this%aggregated_data = huge(int(0_int32)) + type is (aggregator_real32_0d_t) + this%aggregated_data = huge(real(0.0_real32)) + type is (aggregator_real32_1d_t) + this%aggregated_data = huge(real(0.0_real32)) + type is (aggregator_real32_2d_t) + this%aggregated_data = huge(real(0.0_real32)) + type is (aggregator_real32_3d_t) + this%aggregated_data = huge(real(0.0_real32)) + type is (aggregator_real64_0d_t) + this%aggregated_data = huge(real(0.0_real64)) + type is (aggregator_real64_1d_t) + this%aggregated_data = huge(real(0.0_real64)) + type is (aggregator_real64_2d_t) + this%aggregated_data = huge(real(0.0_real64)) + type is (aggregator_real64_3d_t) + this%aggregated_data = huge(real(0.0_real64)) + end select + + this%counter = 0 + + end subroutine min_reset + + subroutine max_reset(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = -huge(int(0_int32)) + type is (aggregator_int32_1d_t) + this%aggregated_data = -huge(int(0_int32)) + type is (aggregator_int32_2d_t) + this%aggregated_data = -huge(int(0_int32)) + type is (aggregator_int32_3d_t) + this%aggregated_data = -huge(int(0_int32)) + type is (aggregator_real32_0d_t) + this%aggregated_data = -huge(real(0.0_real32)) + type is (aggregator_real32_1d_t) + this%aggregated_data = -huge(real(0.0_real32)) + type is (aggregator_real32_2d_t) + this%aggregated_data = -huge(real(0.0_real32)) + type is (aggregator_real32_3d_t) + this%aggregated_data = -huge(real(0.0_real32)) + type is (aggregator_real64_0d_t) + this%aggregated_data = -huge(real(0.0_real64)) + type is (aggregator_real64_1d_t) + this%aggregated_data = -huge(real(0.0_real64)) + type is (aggregator_real64_2d_t) + this%aggregated_data = -huge(real(0.0_real64)) + type is (aggregator_real64_3d_t) + this%aggregated_data = -huge(real(0.0_real64)) + end select + + this%counter = 0 + + end subroutine max_reset + + subroutine other_reset(this) + class(aggregator_t), intent(inout) :: this + + select type (this) + type is (aggregator_int32_0d_t) + this%aggregated_data = 0_int32 + type is (aggregator_int32_1d_t) + this%aggregated_data = 0_int32 + type is (aggregator_int32_2d_t) + this%aggregated_data = 0_int32 + type is (aggregator_int32_3d_t) + this%aggregated_data = 0_int32 + type is (aggregator_real32_0d_t) + this%aggregated_data = 0.0_real32 + type is (aggregator_real32_1d_t) + this%aggregated_data = 0.0_real32 + type is (aggregator_real32_2d_t) + this%aggregated_data = 0.0_real32 + type is (aggregator_real32_3d_t) + this%aggregated_data = 0.0_real32 + type is (aggregator_real64_0d_t) + this%aggregated_data = 0.0_real64 + type is (aggregator_real64_1d_t) + this%aggregated_data = 0.0_real64 + type is (aggregator_real64_2d_t) + this%aggregated_data = 0.0_real64 + type is (aggregator_real64_3d_t) + this%aggregated_data = 0.0_real64 + end select + + this%counter = 0 + + end subroutine other_reset + + function new_aggregator_int32_0d_t(source_data) result(agg) + integer(kind=int32), intent(inout), target :: source_data + type(aggregator_int32_0d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_int32_0d_t + + function new_aggregator_int32_1d_t(source_data) result(agg) + integer(kind=int32), dimension(:), intent(inout), target :: source_data + type(aggregator_int32_1d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_int32_1d_t + + function new_aggregator_int32_2d_t(source_data) result(agg) + integer(kind=int32), dimension(:,:), intent(inout), target :: source_data + type(aggregator_int32_2d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_int32_2d_t + + function new_aggregator_int32_3d_t(source_data) result(agg) + integer(kind=int32), dimension(:,:,:), intent(inout), target :: source_data + type(aggregator_int32_3d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_int32_3d_t + + function new_aggregator_real32_0d(source_data) result(agg) + real(kind=real32), intent(inout), target :: source_data + type(aggregator_real32_0d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real32_0d + + function new_aggregator_real32_1d(source_data) result(agg) + real(kind=real32), dimension(:), intent(inout), target :: source_data + type(aggregator_real32_1d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real32_1d + + function new_aggregator_real32_2d(source_data) result(agg) + real(kind=real32), dimension(:,:), intent(inout), target :: source_data + type(aggregator_real32_2d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real32_2d + + function new_aggregator_real32_3d(source_data) result(agg) + real(kind=real32), dimension(:,:,:), intent(inout), target :: source_data + type(aggregator_real32_3d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real32_3d + + function new_aggregator_real64_0d(source_data) result(agg) + real(kind=real64), intent(inout), target :: source_data + type(aggregator_real64_0d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real64_0d + + function new_aggregator_real64_1d(source_data) result(agg) + real(kind=real64), dimension(:), intent(inout), target :: source_data + type(aggregator_real64_1d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real64_1d + + function new_aggregator_real64_2d(source_data) result(agg) + real(kind=real64), dimension(:,:), intent(inout), target :: source_data + type(aggregator_real64_2d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real64_2d + + function new_aggregator_real64_3d(source_data) result(agg) + real(kind=real64), dimension(:,:,:), intent(inout), target :: source_data + type(aggregator_real64_3d_t) :: agg + + agg%source_data => source_data + + end function new_aggregator_real64_3d + +end module diff --git a/src/util/cable_common.F90 b/src/util/cable_common.F90 index 20106ae42..553cfc2cd 100644 --- a/src/util/cable_common.F90 +++ b/src/util/cable_common.F90 @@ -46,10 +46,12 @@ MODULE cable_common_module LOGICAL :: calcsoilalbedo = .FALSE. !---Lestevens Sept2012 !---CASACNP switches and cycle index - LOGICAL, SAVE :: l_casacnp,l_laiFeedbk,l_vcmaxFeedbk - LOGICAL :: l_luc = .FALSE. - LOGICAL :: l_thinforest = .FALSE. - LOGICAL :: l_landuse = .FALSE. + LOGICAL :: l_casacnp = .FALSE. + LOGICAL :: l_laiFeedbk = .FALSE. + LOGICAL :: l_vcmaxFeedbk = .FALSE. + LOGICAL :: l_luc = .FALSE. + LOGICAL :: l_thinforest = .FALSE. + LOGICAL :: l_landuse = .FALSE. !---CABLE runtime switches def in this type TYPE kbl_internal_switches diff --git a/src/util/cable_enum.F90 b/src/util/cable_enum.F90 new file mode 100644 index 000000000..7bbb3c18d --- /dev/null +++ b/src/util/cable_enum.F90 @@ -0,0 +1,25 @@ +module cable_enum_mod + implicit none + + type :: cable_enum_t + integer :: value + contains + procedure, private :: cable_enum_eq + generic :: operator(==) => cable_enum_eq + procedure, private :: cable_enum_ne + generic :: operator(/=) => cable_enum_ne + end type + +contains + + elemental logical function cable_enum_eq(this, other) + class(cable_enum_t), intent(in) :: this, other + cable_enum_eq = (this%value == other%value) + end function + + elemental logical function cable_enum_ne(this, other) + class(cable_enum_t), intent(in) :: this, other + cable_enum_ne = (this%value /= other%value) + end function + +end module diff --git a/src/util/cable_grid_reductions.F90 b/src/util/cable_grid_reductions.F90 new file mode 100644 index 000000000..44ae1d6f9 --- /dev/null +++ b/src/util/cable_grid_reductions.F90 @@ -0,0 +1,282 @@ +module cable_grid_reductions_mod + + use iso_fortran_env, only: int32, real32, real64 + + use cable_io_vars_module, only: patch_type, land_type + + implicit none + private + + public :: grid_cell_average + public :: first_patch_in_grid_cell + + interface first_patch_in_grid_cell + module procedure first_patch_in_grid_cell_int32_1d + module procedure first_patch_in_grid_cell_int32_2d + module procedure first_patch_in_grid_cell_int32_3d + module procedure first_patch_in_grid_cell_real32_1d + module procedure first_patch_in_grid_cell_real32_2d + module procedure first_patch_in_grid_cell_real32_3d + module procedure first_patch_in_grid_cell_real64_1d + module procedure first_patch_in_grid_cell_real64_2d + module procedure first_patch_in_grid_cell_real64_3d + end interface + + interface grid_cell_average + module procedure grid_cell_average_real32_1d + module procedure grid_cell_average_real32_2d + module procedure grid_cell_average_real32_3d + module procedure grid_cell_average_real64_1d + module procedure grid_cell_average_real64_2d + module procedure grid_cell_average_real64_3d + end interface + +contains + + subroutine grid_cell_average_real32_1d(input_array, output_array, patch, landpt) + real(kind=real32), intent(in) :: input_array(:) + real(kind=real32), intent(out) :: output_array(:) + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, patch_index + + do land_index = 1, size(output_array) + output_array(land_index) = 0.0_real32 + do patch_index = landpt(land_index)%cstart, landpt(land_index)%cend + output_array(land_index) = output_array(land_index) + & + input_array(patch_index) * patch(patch_index)%frac + end do + end do + + end subroutine + + subroutine grid_cell_average_real32_2d(input_array, output_array, patch, landpt) + real(kind=real32), intent(in) :: input_array(:, :) + real(kind=real32), intent(out) :: output_array(:, :) + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, patch_index, j + + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j) = 0.0_real32 + do patch_index = landpt(land_index)%cstart, landpt(land_index)%cend + output_array(land_index, j) = ( & + output_array(land_index, j) + input_array(patch_index, j) * patch(patch_index)%frac & + ) + end do + end do + end do + + end subroutine + + subroutine grid_cell_average_real32_3d(input_array, output_array, patch, landpt) + real(kind=real32), intent(in) :: input_array(:, :, :) + real(kind=real32), intent(out) :: output_array(:, :, :) + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, patch_index, j, k + + do k = 1, size(output_array, 3) + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j, k) = 0.0_real32 + do patch_index = landpt(land_index)%cstart, landpt(land_index)%cend + output_array(land_index, j, k) = ( & + output_array(land_index, j, k) + & + input_array(patch_index, j, k) * patch(patch_index)%frac & + ) + end do + end do + end do + end do + + end subroutine + + subroutine grid_cell_average_real64_1d(input_array, output_array, patch, landpt) + real(kind=real64), intent(in) :: input_array(:) + real(kind=real64), intent(out) :: output_array(:) + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, patch_index + + do land_index = 1, size(output_array) + output_array(land_index) = 0.0_real64 + do patch_index = landpt(land_index)%cstart, landpt(land_index)%cend + output_array(land_index) = output_array(land_index) + & + input_array(patch_index) * patch(patch_index)%frac + end do + end do + + end subroutine + + subroutine grid_cell_average_real64_2d(input_array, output_array, patch, landpt) + real(kind=real64), intent(in) :: input_array(:, :) + real(kind=real64), intent(out) :: output_array(:, :) + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, patch_index, j + + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j) = 0.0_real64 + do patch_index = landpt(land_index)%cstart, landpt(land_index)%cend + output_array(land_index, j) = ( & + output_array(land_index, j) + input_array(patch_index, j) * patch(patch_index)%frac & + ) + end do + end do + end do + + end subroutine + + subroutine grid_cell_average_real64_3d(input_array, output_array, patch, landpt) + real(kind=real64), intent(in) :: input_array(:, :, :) + real(kind=real64), intent(out) :: output_array(:, :, :) + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, patch_index, j, k + + do k = 1, size(output_array, 3) + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j, k) = 0.0_real64 + do patch_index = landpt(land_index)%cstart, landpt(land_index)%cend + output_array(land_index, j, k) = ( & + output_array(land_index, j, k) + & + input_array(patch_index, j, k) * patch(patch_index)%frac & + ) + end do + end do + end do + end do + + end subroutine + + subroutine first_patch_in_grid_cell_int32_1d(input_array, output_array, landpt) + integer(kind=int32), intent(in) :: input_array(:) + integer(kind=int32), intent(out) :: output_array(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index + + do land_index = 1, size(output_array) + output_array(land_index) = input_array(landpt(land_index)%cstart) + end do + + end subroutine + + subroutine first_patch_in_grid_cell_int32_2d(input_array, output_array, landpt) + integer(kind=int32), intent(in) :: input_array(:, :) + integer(kind=int32), intent(out) :: output_array(:, :) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, j + + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j) = input_array(landpt(land_index)%cstart, j) + end do + end do + + end subroutine + + subroutine first_patch_in_grid_cell_int32_3d(input_array, output_array, landpt) + integer(kind=int32), intent(in) :: input_array(:, :, :) + integer(kind=int32), intent(out) :: output_array(:, :, :) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, j, k + + do k = 1, size(output_array, 3) + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j, k) = input_array(landpt(land_index)%cstart, j, k) + end do + end do + end do + + end subroutine + + subroutine first_patch_in_grid_cell_real32_1d(input_array, output_array, landpt) + real(kind=real32), intent(in) :: input_array(:) + real(kind=real32), intent(out) :: output_array(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index + + do land_index = 1, size(output_array) + output_array(land_index) = input_array(landpt(land_index)%cstart) + end do + + end subroutine + + subroutine first_patch_in_grid_cell_real32_2d(input_array, output_array, landpt) + real(kind=real32), intent(in) :: input_array(:, :) + real(kind=real32), intent(out) :: output_array(:, :) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, j + + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j) = input_array(landpt(land_index)%cstart, j) + end do + end do + + end subroutine + + subroutine first_patch_in_grid_cell_real32_3d(input_array, output_array, landpt) + real(kind=real32), intent(in) :: input_array(:, :, :) + real(kind=real32), intent(out) :: output_array(:, :, :) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, j, k + + do k = 1, size(output_array, 3) + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j, k) = input_array(landpt(land_index)%cstart, j, k) + end do + end do + end do + + end subroutine + + subroutine first_patch_in_grid_cell_real64_1d(input_array, output_array, landpt) + real(kind=real64), intent(in) :: input_array(:) + real(kind=real64), intent(out) :: output_array(:) + type(land_type), intent(in) :: landpt(:) + integer :: land_index + + do land_index = 1, size(output_array) + output_array(land_index) = input_array(landpt(land_index)%cstart) + end do + + end subroutine + + subroutine first_patch_in_grid_cell_real64_2d(input_array, output_array, landpt) + real(kind=real64), intent(in) :: input_array(:, :) + real(kind=real64), intent(out) :: output_array(:, :) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, j + + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j) = input_array(landpt(land_index)%cstart, j) + end do + end do + + end subroutine + + subroutine first_patch_in_grid_cell_real64_3d(input_array, output_array, landpt) + real(kind=real64), intent(in) :: input_array(:, :, :) + real(kind=real64), intent(out) :: output_array(:, :, :) + type(land_type), intent(in) :: landpt(:) + integer :: land_index, j, k + + do k = 1, size(output_array, 3) + do j = 1, size(output_array, 2) + do land_index = 1, size(output_array, 1) + output_array(land_index, j, k) = input_array(landpt(land_index)%cstart, j, k) + end do + end do + end do + + end subroutine + +end module diff --git a/src/util/cable_timing_utils.F90 b/src/util/cable_timing_utils.F90 new file mode 100644 index 000000000..80827cbb2 --- /dev/null +++ b/src/util/cable_timing_utils.F90 @@ -0,0 +1,68 @@ +module cable_timing_utils_mod + use cable_abort_module, only: cable_abort + use cable_common_module, only: is_leapyear, current_year => CurYear + implicit none + private + + public :: time_step_matches + public :: seconds_per_hour + public :: hours_per_day + public :: seconds_per_day + + integer, parameter :: seconds_per_hour = 3600 + integer, parameter :: hours_per_day = 24 + integer, parameter :: seconds_per_day = 86400 + integer, parameter :: months_in_year = 12 + integer, parameter, dimension(months_in_year) :: & + daysm = [31,28,31,30,31,30,31,31,30,31,30,31], & + daysml = [31,29,31,30,31,30,31,31,30,31,30,31], & + lastday = [31,59,90,120,151,181,212,243,273,304,334,365], & + lastdayl = [31,60,91,121,152,182,213,244,274,305,335,366] + +contains + + function time_step_matches(dels, ktau, frequency, leaps, start_year) result(match) + real, intent(in) :: dels !! Model time step in seconds + integer, intent(in) :: ktau !! Current time step index + character(len=*), intent(in) :: frequency !! Frequency string: 'all', 'daily', 'monthly' + logical, intent(in) :: leaps !! Are we using leap years? + integer, intent(in) :: start_year !! Start year of the simulation + logical :: match + integer :: i + integer :: time_steps_per_interval + integer :: interval_in_hours + integer :: last_day_of_month_in_accumulated_days(months_in_year) ! TODO(Sean): better variable name? + + select case (frequency) + case ('user') + read(frequency(5:7), *) interval_in_hours + time_steps_per_interval = seconds_per_hour * interval_in_hours / int(dels) + match = mod(ktau, time_steps_per_interval) == 0 + case ('all') + match = .true. + case ('daily') + time_steps_per_interval = seconds_per_hour * hours_per_day / int(dels) + match = mod(ktau, time_steps_per_interval) == 0 + case ('monthly') + ! TODO(Sean): is there a better algorithm for monthly matching that doesn't involve looping over years? + last_day_of_month_in_accumulated_days = 0 + do i = start_year, current_year - 1 + if (leaps .and. is_leapyear(i)) then + last_day_of_month_in_accumulated_days = last_day_of_month_in_accumulated_days + 366 + else + last_day_of_month_in_accumulated_days = last_day_of_month_in_accumulated_days + 365 + end if + end do + if (leaps .and. is_leapyear(current_year)) then + last_day_of_month_in_accumulated_days = last_day_of_month_in_accumulated_days + lastdayl + else + last_day_of_month_in_accumulated_days = last_day_of_month_in_accumulated_days + lastday + end if + match = any(int(real(last_day_of_month_in_accumulated_days) * seconds_per_day / dels) == ktau) + case default + call cable_abort('Error: unknown frequency "' // trim(adjustl(frequency)) // '"', __FILE__, __LINE__) + end select + + end function + +end module diff --git a/src/util/io/output/cable_output.F90 b/src/util/io/output/cable_output.F90 new file mode 100644 index 000000000..d7e250ebd --- /dev/null +++ b/src/util/io/output/cable_output.F90 @@ -0,0 +1,26 @@ +module cable_output_prototype_v2_mod ! TODO(Sean): rename to cable_output_mod + + use cable_output_core_mod, only: cable_output_mod_init + use cable_output_core_mod, only: cable_output_mod_end + use cable_output_core_mod, only: cable_output_register_output_variables + use cable_output_core_mod, only: cable_output_profiles_init + use cable_output_core_mod, only: cable_output_update + use cable_output_core_mod, only: cable_output_write + use cable_output_core_mod, only: cable_output_write_parameters + use cable_output_core_mod, only: cable_output_write_restart + + use cable_output_types_mod, only: cable_output_attribute_t + use cable_output_types_mod, only: cable_output_variable_t + + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PATCH + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOIL + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SNOW + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_RAD + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PLANTCARBON + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOILCARBON + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_LAND_GLOBAL + + implicit none + public + +end module diff --git a/src/util/io/output/cable_output_core.F90 b/src/util/io/output/cable_output_core.F90 new file mode 100644 index 000000000..67d4bc70a --- /dev/null +++ b/src/util/io/output/cable_output_core.F90 @@ -0,0 +1,833 @@ +module cable_output_core_mod + + use iso_fortran_env, only: int32, real32, real64 + + use cable_def_types_mod, only: met_type + + use cable_io_vars_module, only: patch_type + use cable_io_vars_module, only: land_type + use cable_io_vars_module, only: metgrid + use cable_io_vars_module, only: output + use cable_io_vars_module, only: check + use cable_io_vars_module, only: ON_TIMESTEP + use cable_io_vars_module, only: ON_WRITE + + use aggregator_mod, only: aggregator_int32_0d_t + use aggregator_mod, only: aggregator_int32_1d_t + use aggregator_mod, only: aggregator_int32_2d_t + use aggregator_mod, only: aggregator_int32_3d_t + use aggregator_mod, only: aggregator_real32_0d_t + use aggregator_mod, only: aggregator_real32_1d_t + use aggregator_mod, only: aggregator_real32_2d_t + use aggregator_mod, only: aggregator_real32_3d_t + use aggregator_mod, only: aggregator_real64_0d_t + use aggregator_mod, only: aggregator_real64_1d_t + use aggregator_mod, only: aggregator_real64_2d_t + use aggregator_mod, only: aggregator_real64_3d_t + + use cable_netcdf_mod, only: cable_netcdf_decomp_t + use cable_netcdf_mod, only: cable_netcdf_file_t + use cable_netcdf_mod, only: cable_netcdf_create_file + use cable_netcdf_mod, only: CABLE_NETCDF_INT + use cable_netcdf_mod, only: CABLE_NETCDF_FLOAT + use cable_netcdf_mod, only: CABLE_NETCDF_DOUBLE + use cable_netcdf_mod, only: CABLE_NETCDF_IOTYPE_CLASSIC + + use cable_abort_module, only: cable_abort + + use cable_checks_module, only: check_range + + use cable_timing_utils_mod, only: time_step_matches + + use cable_grid_reductions_mod, only: grid_cell_average + use cable_grid_reductions_mod, only: first_patch_in_grid_cell + + use cable_output_types_mod, only: cable_output_variable_t + use cable_output_types_mod, only: cable_output_profile_t + use cable_output_types_mod, only: FILL_VALUE_INT32 + use cable_output_types_mod, only: FILL_VALUE_REAL32 + use cable_output_types_mod, only: FILL_VALUE_REAL64 + use cable_output_types_mod, only: CABLE_OUTPUT_VAR_TYPE_UNDEFINED + + use cable_output_reduction_buffers_mod, only: allocate_grid_reduction_buffers + use cable_output_reduction_buffers_mod, only: deallocate_grid_reduction_buffers + use cable_output_reduction_buffers_mod, only: associate_temp_buffer_int32 + use cable_output_reduction_buffers_mod, only: associate_temp_buffer_real32 + use cable_output_reduction_buffers_mod, only: associate_temp_buffer_real64 + + use cable_output_decomp_mod, only: allocate_decompositions + use cable_output_decomp_mod, only: deallocate_decompositions + use cable_output_decomp_mod, only: associate_decomp_int32 + use cable_output_decomp_mod, only: associate_decomp_real32 + use cable_output_decomp_mod, only: associate_decomp_real64 + + use cable_output_utils_mod, only: check_duplicate_variable_names + use cable_output_utils_mod, only: check_sampling_frequency + use cable_output_utils_mod, only: var_name + use cable_output_utils_mod, only: dim_size + use cable_output_utils_mod, only: define_variables + use cable_output_utils_mod, only: set_global_attributes + use cable_output_utils_mod, only: coordinate_variables + + implicit none + private + + public :: cable_output_mod_init + public :: cable_output_mod_end + public :: cable_output_register_output_variables + public :: cable_output_profiles_init + public :: cable_output_update + public :: cable_output_write + public :: cable_output_write_parameters + public :: cable_output_write_restart + + type(cable_output_profile_t), allocatable :: global_profile + + type(cable_output_variable_t), allocatable :: registered_output_variables(:) + +contains + + subroutine cable_output_mod_init() + class(cable_netcdf_file_t), allocatable :: output_file + + call allocate_decompositions() + call allocate_grid_reduction_buffers() + + end subroutine + + subroutine cable_output_mod_end() + + if (allocated(global_profile%output_file)) call global_profile%output_file%close() + + deallocate(global_profile) + + call deallocate_grid_reduction_buffers() + call deallocate_decompositions() + + end subroutine + + subroutine cable_output_register_output_variables(output_variables) + type(cable_output_variable_t), dimension(:), intent(in) :: output_variables + integer :: i + + do i = 1, size(output_variables) + associate(output_var => output_variables(i)) + if (count(output_var%field_name == output_variables(:)%field_name) > 1) then + call cable_abort("Duplicate field_name found: " // trim(output_var%field_name), __FILE__, __LINE__) + end if + if (all(output_var%reduction_method /= [character(32) :: "none", "grid_cell_average", "first_patch_in_grid_cell"])) then + call cable_abort("Invalid reduction method for variable " // trim(output_var%field_name), __FILE__, __LINE__) + end if + if (all(output_var%aggregation_method /= [character(32) :: "point", "mean", "max", "min", "sum"])) then + call cable_abort("Invalid aggregation method for variable " // trim(output_var%field_name), __FILE__, __LINE__) + end if + if (all(output_var%var_type /= [CABLE_OUTPUT_VAR_TYPE_UNDEFINED, CABLE_NETCDF_INT, CABLE_NETCDF_FLOAT, CABLE_NETCDF_DOUBLE])) then + call cable_abort("Invalid variable type for variable " // trim(output_var%field_name), __FILE__, __LINE__) + end if + if (.not. allocated(output_var%aggregator)) then + call cable_abort("Undefined aggregator for variable " // trim(output_var%field_name), __FILE__, __LINE__) + end if + if (( & + .not. allocated(output_var%data_shape) .and. output_var%aggregator%rank() /= 0 & + ) .or. ( & + allocated(output_var%data_shape) .and. ( & + size(output_var%data_shape) /= size(output_var%aggregator%shape()) .or. & + any(dim_size(output_var%data_shape) /= output_var%aggregator%shape()) & + ) & + )) then + call cable_abort("Data shape does not match aggregator shape for variable " // trim(output_var%field_name), __FILE__, __LINE__) + end if + if (output_var%reduction_method /= "none" .and. .not. output_var%distributed) then + call cable_abort("Grid cell reductions require distributed output for variable " // trim(output_var%field_name), __FILE__, __LINE__) + end if + end associate + end do + + registered_output_variables = output_variables + + end subroutine cable_output_register_output_variables + + subroutine cable_output_profiles_init() + class(cable_netcdf_file_t), allocatable :: output_file + integer :: i + + character(32) :: grid_type + + if (output%grid == "land" .OR. (output%grid == "default" .AND. metgrid == "land")) then + grid_type = "land" + else if (( & + output%grid == "default" .AND. metgrid == "mask" & + ) .OR. ( & + output%grid == "mask" .OR. output%grid == "ALMA" & + )) then + grid_type = "mask" + else + call cable_abort("Unable to determine output grid type.", __FILE__, __LINE__) + end if + + global_profile = cable_output_profile_t( & + sampling_frequency=output%averaging, & + grid_type=grid_type, & + file_name="test_output.nc", & ! TODO(Sean): use filename from namelist + output_file=cable_netcdf_create_file("test_output.nc", iotype=CABLE_NETCDF_IOTYPE_CLASSIC), & ! TODO(Sean): use filename from namelist + coordinate_variables=coordinate_variables(grid_type), & + output_variables=pack(registered_output_variables, registered_output_variables(:)%active) & + ) + + do i = 1, size(global_profile%output_variables) + associate(output_var => global_profile%output_variables(i)) + if (output_var%patchout) output_var%reduction_method = "none" + if (global_profile%sampling_frequency == "all") output_var%aggregation_method = "point" + end associate + end do + + call check_duplicate_variable_names(global_profile) + + call check_sampling_frequency(global_profile) + + call define_variables(global_profile) + + call set_global_attributes(global_profile) + + call global_profile%output_file%end_def() + + do i = 1, size(global_profile%coordinate_variables) + associate(coordinate_variable => global_profile%coordinate_variables(i)) + call coordinate_variable%aggregator%init(method="point") + call coordinate_variable%aggregator%accumulate() + call write_variable(global_profile, coordinate_variable) + call coordinate_variable%aggregator%reset() + end associate + end do + + do i = 1, size(global_profile%output_variables) + associate(output_variable => global_profile%output_variables(i)) + call output_variable%aggregator%init(method=output_variable%aggregation_method) + end associate + end do + + end subroutine + + subroutine cable_output_write_parameters(time_index, patch, landpt, met) + integer, intent(in) :: time_index + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + type(met_type), intent(in) :: met + + integer :: i + + do i = 1, size(global_profile%output_variables) + associate(output_variable => global_profile%output_variables(i)) + if (.not. output_variable%parameter) cycle + call check_variable_range(output_variable, time_index, met) + call output_variable%aggregator%accumulate() + call write_variable(global_profile, output_variable, patch, landpt) + call output_variable%aggregator%reset() + end associate + end do + + end subroutine cable_output_write_parameters + + subroutine cable_output_update(time_index, dels, leaps, start_year, met) + integer, intent(in) :: time_index + real, intent(in) :: dels + logical, intent(in) :: leaps + integer, intent(in) :: start_year + type(met_type), intent(in) :: met + + real :: current_time + integer :: i + + if (check%ranges == ON_TIMESTEP) then + do i = 1, size(global_profile%output_variables) + call check_variable_range(global_profile%output_variables(i), time_index, met) + end do + end if + + do i = 1, size(global_profile%output_variables) + associate(output_variable => global_profile%output_variables(i)) + if (time_step_matches(dels, time_index, output_variable%accumulation_frequency, leaps, start_year)) then + call output_variable%aggregator%accumulate() + end if + end associate + end do + + end subroutine cable_output_update + + subroutine cable_output_write(time_index, dels, leaps, start_year, met, patch, landpt) + integer, intent(in) :: time_index + real, intent(in) :: dels + logical, intent(in) :: leaps + integer, intent(in) :: start_year + type(met_type), intent(in) :: met + type(patch_type), intent(in) :: patch(:) + type(land_type), intent(in) :: landpt(:) + + real :: current_time + integer :: i + + if (time_step_matches(dels, time_index, global_profile%sampling_frequency, leaps, start_year)) then + + do i = 1, size(global_profile%output_variables) + associate(output_variable => global_profile%output_variables(i)) + if (output_variable%parameter) cycle + if (check%ranges == ON_WRITE) call check_variable_range(output_variable, time_index, met) + if (allocated(output_variable%scale)) call output_variable%aggregator%scale(output_variable%scale) + if (allocated(output_variable%offset)) call output_variable%aggregator%offset(output_variable%offset) + call write_variable(global_profile, output_variable, patch, landpt, frame=global_profile%frame + 1) + call output_variable%aggregator%reset() + end associate + end do + + current_time = time_index * dels + + if (global_profile%sampling_frequency == "all") then + call global_profile%output_file%put_var("time", current_time, start=[global_profile%frame + 1]) + else + call global_profile%output_file%put_var("time", (current_time + global_profile%previous_write_time) / 2.0, start=[global_profile%frame + 1]) + end if + + call global_profile%output_file%put_var("time_bnds", [global_profile%previous_write_time, current_time], start=[1, global_profile%frame + 1]) + + global_profile%previous_write_time = current_time + global_profile%frame = global_profile%frame + 1 + + end if + + end subroutine cable_output_write + + subroutine cable_output_write_restart(current_time) + real, intent(in) :: current_time !! Current simulation time + + type(cable_output_profile_t), allocatable :: restart_output_profile + integer :: i + + restart_output_profile = cable_output_profile_t( & + sampling_frequency="none", & + grid_type="restart", & + file_name="test_restart.nc", & ! TODO(Sean): use filename from namelist + output_file=cable_netcdf_create_file("test_restart.nc", iotype=CABLE_NETCDF_IOTYPE_CLASSIC), & ! TODO(Sean): use filename from namelist + coordinate_variables=coordinate_variables(grid_type="restart"), & + output_variables=pack(registered_output_variables, registered_output_variables(:)%restart) & + ) + + call define_variables(restart_output_profile, restart=.true.) + + call restart_output_profile%output_file%end_def() + + call restart_output_profile%output_file%put_var("time", [current_time]) + + do i = 1, size(restart_output_profile%coordinate_variables) + call write_variable(restart_output_profile, restart_output_profile%coordinate_variables(i), restart=.true.) + end do + + do i = 1, size(restart_output_profile%output_variables) + call write_variable(restart_output_profile, restart_output_profile%output_variables(i), restart=.true.) + end do + + call restart_output_profile%output_file%close() + + end subroutine cable_output_write_restart + + subroutine check_variable_range(output_variable, time_index, met) + type(cable_output_variable_t), intent(in) :: output_variable + integer, intent(in) :: time_index + type(met_type), intent(in) :: met + + select type (aggregator => output_variable%aggregator) + type is (aggregator_int32_0d_t) + ! TODO(Sean): implement range checking for integer types + type is (aggregator_int32_1d_t) + ! TODO(Sean): implement range checking for integer types + type is (aggregator_int32_2d_t) + ! TODO(Sean): implement range checking for integer types + type is (aggregator_int32_3d_t) + ! TODO(Sean): implement range checking for integer types + type is (aggregator_real32_0d_t) + ! TODO(Sean): implement range checking for scalars + type is (aggregator_real32_1d_t) + call check_range(output_variable%field_name, aggregator%source_data, output_variable%range, time_index, met) + type is (aggregator_real32_2d_t) + call check_range(output_variable%field_name, aggregator%source_data, output_variable%range, time_index, met) + type is (aggregator_real32_3d_t) + call check_range(output_variable%field_name, aggregator%source_data, output_variable%range, time_index, met) + type is (aggregator_real64_0d_t) + ! TODO(Sean): implement range checking for double precision types + type is (aggregator_real64_1d_t) + ! TODO(Sean): implement range checking for double precision types + type is (aggregator_real64_2d_t) + ! TODO(Sean): implement range checking for double precision types + type is (aggregator_real64_3d_t) + ! TODO(Sean): implement range checking for double precision types + class default + call cable_abort("Unexpected aggregator type", __FILE__, __LINE__) + end select + + end subroutine check_variable_range + + subroutine write_variable(output_profile, output_variable, patch, landpt, frame, restart) + type(cable_output_profile_t), intent(inout) :: output_profile + type(cable_output_variable_t), intent(inout), target :: output_variable + type(patch_type), intent(in), optional :: patch(:) + type(land_type), intent(in), optional :: landpt(:) + integer, intent(in), optional :: frame + logical, intent(in), optional :: restart + + class(cable_netcdf_decomp_t), pointer :: decomp + integer :: i, ndims + logical :: restart_local + character(128) :: variable_name + + integer(kind=int32), pointer :: write_buffer_int32_0d + integer(kind=int32), pointer :: write_buffer_int32_1d(:) + integer(kind=int32), pointer :: write_buffer_int32_2d(:, :) + integer(kind=int32), pointer :: write_buffer_int32_3d(:, :, :) + real(kind=real32), pointer :: write_buffer_real32_0d + real(kind=real32), pointer :: write_buffer_real32_1d(:) + real(kind=real32), pointer :: write_buffer_real32_2d(:, :) + real(kind=real32), pointer :: write_buffer_real32_3d(:, :, :) + real(kind=real64), pointer :: write_buffer_real64_0d + real(kind=real64), pointer :: write_buffer_real64_1d(:) + real(kind=real64), pointer :: write_buffer_real64_2d(:, :) + real(kind=real64), pointer :: write_buffer_real64_3d(:, :, :) + + decomp => null() + + write_buffer_int32_0d => null() + write_buffer_int32_1d => null() + write_buffer_int32_2d => null() + write_buffer_int32_3d => null() + write_buffer_real32_0d => null() + write_buffer_real32_1d => null() + write_buffer_real32_2d => null() + write_buffer_real32_3d => null() + write_buffer_real64_0d => null() + write_buffer_real64_1d => null() + write_buffer_real64_2d => null() + write_buffer_real64_3d => null() + + restart_local = .false. + if (present(restart)) restart_local = restart + + if (.not. restart_local .and. output_variable%reduction_method /= "none") then + if (.not. present(patch) .or. .not. present(landpt)) then + call cable_abort("Optional arguments patch and landpt must be present for grid reductions", __FILE__, __LINE__) + end if + end if + + variable_name = var_name(output_variable) + if (restart_local) variable_name = output_variable%field_name + + select type (aggregator => output_variable%aggregator) + type is (aggregator_int32_0d_t) + if (output_variable%reduction_method /= "none") then + call cable_abort("Grid cell reductions are not supported for scalar variables", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call cable_abort("Distributed writes are not supported for scalar variables", __FILE__, __LINE__) + end if + write_buffer_int32_0d => aggregator%aggregated_data + if (restart_local) write_buffer_int32_0d => aggregator%source_data + if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_0d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_0d) + end if + type is (aggregator_int32_1d_t) + if (restart_local) then + write_buffer_int32_1d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_int32_1d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call cable_abort("Reduction method grid_cell_average is not supported for integer variables", __FILE__, __LINE__) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_int32(output_variable, temp_buffer_int32_1d=write_buffer_int32_1d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_int32_1d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_int32(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_int32_1d, & + decomp=decomp, & + fill_value=FILL_VALUE_INT32, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_1d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_1d) + end if + type is (aggregator_int32_2d_t) + if (restart_local) then + write_buffer_int32_2d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_int32_2d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call cable_abort("Reduction method grid_cell_average is not supported for integer variables", __FILE__, __LINE__) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_int32(output_variable, temp_buffer_int32_2d=write_buffer_int32_2d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_int32_2d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_int32(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_int32_2d, & + decomp=decomp, & + fill_value=FILL_VALUE_INT32, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_2d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_2d) + end if + type is (aggregator_int32_3d_t) + if (restart_local) then + write_buffer_int32_3d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_int32_3d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call cable_abort("Reduction method grid_cell_average is not supported for integer variables", __FILE__, __LINE__) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_int32(output_variable, temp_buffer_int32_3d=write_buffer_int32_3d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_int32_3d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_int32(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_int32_3d, & + decomp=decomp, & + fill_value=FILL_VALUE_INT32, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_3d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_int32_3d) + end if + type is (aggregator_real32_0d_t) + if (output_variable%reduction_method /= "none") then + call cable_abort("Grid cell reductions are not supported for scalar variables", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call cable_abort("Distributed writes are not supported for scalar variables", __FILE__, __LINE__) + end if + write_buffer_real32_0d => aggregator%aggregated_data + if (restart_local) write_buffer_real32_0d => aggregator%source_data + if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_0d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_0d) + end if + type is (aggregator_real32_1d_t) + if (restart_local) then + write_buffer_real32_1d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_real32_1d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call associate_temp_buffer_real32(output_variable, temp_buffer_real32_1d=write_buffer_real32_1d) + call grid_cell_average( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real32_1d, & + landpt=landpt, & + patch=patch) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_real32(output_variable, temp_buffer_real32_1d=write_buffer_real32_1d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real32_1d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_real32(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_real32_1d, & + decomp=decomp, & + fill_value=FILL_VALUE_REAL32, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_1d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_1d) + end if + type is (aggregator_real32_2d_t) + if (restart_local) then + write_buffer_real32_2d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_real32_2d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call associate_temp_buffer_real32(output_variable, temp_buffer_real32_2d=write_buffer_real32_2d) + call grid_cell_average( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real32_2d, & + landpt=landpt, & + patch=patch) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_real32(output_variable, temp_buffer_real32_2d=write_buffer_real32_2d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real32_2d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_real32(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_real32_2d, & + decomp=decomp, & + fill_value=FILL_VALUE_REAL32, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_2d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_2d) + end if + type is (aggregator_real32_3d_t) + if (restart_local) then + write_buffer_real32_3d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_real32_3d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call associate_temp_buffer_real32(output_variable, temp_buffer_real32_3d=write_buffer_real32_3d) + call grid_cell_average( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real32_3d, & + landpt=landpt, & + patch=patch) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_real32(output_variable, temp_buffer_real32_3d=write_buffer_real32_3d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real32_3d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_real32(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_real32_3d, & + decomp=decomp, & + fill_value=FILL_VALUE_REAL32, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_3d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real32_3d) + end if + type is (aggregator_real64_0d_t) + if (output_variable%reduction_method /= "none") then + call cable_abort("Grid cell reductions are not supported for scalar variables", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call cable_abort("Distributed writes are not supported for scalar variables", __FILE__, __LINE__) + end if + write_buffer_real64_0d => aggregator%aggregated_data + if (restart_local) write_buffer_real64_0d => aggregator%source_data + if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_0d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_0d) + end if + type is (aggregator_real64_1d_t) + if (restart_local) then + write_buffer_real64_1d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_real64_1d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call associate_temp_buffer_real64(output_variable, temp_buffer_real64_1d=write_buffer_real64_1d) + call grid_cell_average( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real64_1d, & + landpt=landpt, & + patch=patch) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_real64(output_variable, temp_buffer_real64_1d=write_buffer_real64_1d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real64_1d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_real64(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_real64_1d, & + decomp=decomp, & + fill_value=FILL_VALUE_REAL64, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_1d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_1d) + end if + type is (aggregator_real64_2d_t) + if (restart_local) then + write_buffer_real64_2d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_real64_2d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call associate_temp_buffer_real64(output_variable, temp_buffer_real64_2d=write_buffer_real64_2d) + call grid_cell_average( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real64_2d, & + landpt=landpt, & + patch=patch) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_real64(output_variable, temp_buffer_real64_2d=write_buffer_real64_2d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real64_2d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_real64(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_real64_2d, & + decomp=decomp, & + fill_value=FILL_VALUE_REAL64, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_2d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_2d) + end if + type is (aggregator_real64_3d_t) + if (restart_local) then + write_buffer_real64_3d => aggregator%source_data + else if (output_variable%reduction_method == "none") then + write_buffer_real64_3d => aggregator%aggregated_data + else if (output_variable%reduction_method == "grid_cell_average") then + call associate_temp_buffer_real64(output_variable, temp_buffer_real64_3d=write_buffer_real64_3d) + call grid_cell_average( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real64_3d, & + landpt=landpt, & + patch=patch) + else if (output_variable%reduction_method == "first_patch_in_grid_cell") then + call associate_temp_buffer_real64(output_variable, temp_buffer_real64_3d=write_buffer_real64_3d) + call first_patch_in_grid_cell( & + input_array=aggregator%aggregated_data, & + output_array=write_buffer_real64_3d, & + landpt=landpt) + else + call cable_abort("Invalid reduction method", __FILE__, __LINE__) + end if + if (output_variable%distributed) then + call associate_decomp_real64(output_profile, output_variable, decomp) + call output_profile%output_file%write_darray( & + var_name=variable_name, & + values=write_buffer_real64_3d, & + decomp=decomp, & + fill_value=FILL_VALUE_REAL64, & + frame=frame) + else if (present(frame)) then + call output_profile%output_file%inq_var_ndims(variable_name, ndims) + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_3d, & + start=[(1, i = 1, ndims - 1), frame]) + else + call output_profile%output_file%put_var( & + var_name=variable_name, & + values=write_buffer_real64_3d) + end if + class default + call cable_abort("Unexpected aggregator type", __FILE__, __LINE__) + end select + + end subroutine write_variable + +end module diff --git a/src/util/io/output/cable_output_decomp.F90 b/src/util/io/output/cable_output_decomp.F90 new file mode 100644 index 000000000..d3d7d0a78 --- /dev/null +++ b/src/util/io/output/cable_output_decomp.F90 @@ -0,0 +1,633 @@ +module cable_output_decomp_mod + + use cable_abort_module, only: cable_abort + + use cable_def_types_mod, only: mp + use cable_def_types_mod, only: mp_global + use cable_def_types_mod, only: mland + use cable_def_types_mod, only: mland_global + use cable_def_types_mod, only: ms + use cable_def_types_mod, only: msn + use cable_def_types_mod, only: nrb + use cable_def_types_mod, only: ncs + use cable_def_types_mod, only: ncp + + use cable_io_vars_module, only: xdimsize + use cable_io_vars_module, only: ydimsize + use cable_io_vars_module, only: max_vegpatches + use cable_io_vars_module, only: land_x, land_y + use cable_io_vars_module, only: landpt + use cable_io_vars_module, only: land_decomp_start + use cable_io_vars_module, only: patch_decomp_start + + use cable_netcdf_mod, only: cable_netcdf_decomp_t + use cable_netcdf_mod, only: CABLE_NETCDF_INT + use cable_netcdf_mod, only: CABLE_NETCDF_FLOAT + use cable_netcdf_mod, only: CABLE_NETCDF_DOUBLE + + use cable_netcdf_decomp_util_mod, only: dim_spec_t + use cable_netcdf_decomp_util_mod, only: io_decomp_land_to_x_y + use cable_netcdf_decomp_util_mod, only: io_decomp_patch_to_x_y_patch + use cable_netcdf_decomp_util_mod, only: io_decomp_land_to_land + use cable_netcdf_decomp_util_mod, only: io_decomp_patch_to_land_patch + use cable_netcdf_decomp_util_mod, only: io_decomp_patch_to_patch + + use cable_output_types_mod, only: cable_output_variable_t + use cable_output_types_mod, only: cable_output_profile_t + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PATCH + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOIL + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SNOW + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_RAD + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PLANTCARBON + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOILCARBON + + use cable_output_utils_mod, only: data_shape_eq + + implicit none + private + + public :: allocate_decompositions + public :: deallocate_decompositions + public :: associate_decomp_int32 + public :: associate_decomp_real32 + public :: associate_decomp_real64 + + type :: cable_output_decomp_t + class(cable_netcdf_decomp_t), allocatable :: land_int32 + class(cable_netcdf_decomp_t), allocatable :: land_real32 + class(cable_netcdf_decomp_t), allocatable :: land_real64 + class(cable_netcdf_decomp_t), allocatable :: land_soil_int32 + class(cable_netcdf_decomp_t), allocatable :: land_soil_real32 + class(cable_netcdf_decomp_t), allocatable :: land_soil_real64 + class(cable_netcdf_decomp_t), allocatable :: land_snow_int32 + class(cable_netcdf_decomp_t), allocatable :: land_snow_real32 + class(cable_netcdf_decomp_t), allocatable :: land_snow_real64 + class(cable_netcdf_decomp_t), allocatable :: land_rad_int32 + class(cable_netcdf_decomp_t), allocatable :: land_rad_real32 + class(cable_netcdf_decomp_t), allocatable :: land_rad_real64 + class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_int32 + class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_real32 + class(cable_netcdf_decomp_t), allocatable :: land_plantcarbon_real64 + class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_int32 + class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_real32 + class(cable_netcdf_decomp_t), allocatable :: land_soilcarbon_real64 + class(cable_netcdf_decomp_t), allocatable :: patch_int32 + class(cable_netcdf_decomp_t), allocatable :: patch_real32 + class(cable_netcdf_decomp_t), allocatable :: patch_real64 + class(cable_netcdf_decomp_t), allocatable :: patch_soil_int32 + class(cable_netcdf_decomp_t), allocatable :: patch_soil_real32 + class(cable_netcdf_decomp_t), allocatable :: patch_soil_real64 + class(cable_netcdf_decomp_t), allocatable :: patch_snow_int32 + class(cable_netcdf_decomp_t), allocatable :: patch_snow_real32 + class(cable_netcdf_decomp_t), allocatable :: patch_snow_real64 + class(cable_netcdf_decomp_t), allocatable :: patch_rad_int32 + class(cable_netcdf_decomp_t), allocatable :: patch_rad_real32 + class(cable_netcdf_decomp_t), allocatable :: patch_rad_real64 + class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_int32 + class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_real32 + class(cable_netcdf_decomp_t), allocatable :: patch_plantcarbon_real64 + class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_int32 + class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_real32 + class(cable_netcdf_decomp_t), allocatable :: patch_soilcarbon_real64 + end type + + type(cable_output_decomp_t), target :: decomp_grid_x_y + type(cable_output_decomp_t), target :: decomp_grid_land + type(cable_output_decomp_t), target :: decomp_grid_restart + +contains + + subroutine allocate_decompositions() + + type(dim_spec_t), allocatable :: mem_shape_land(:) + type(dim_spec_t), allocatable :: mem_shape_land_soil(:) + type(dim_spec_t), allocatable :: mem_shape_land_snow(:) + type(dim_spec_t), allocatable :: mem_shape_land_rad(:) + type(dim_spec_t), allocatable :: mem_shape_land_plantcarbon(:) + type(dim_spec_t), allocatable :: mem_shape_land_soilcarbon(:) + type(dim_spec_t), allocatable :: mem_shape_patch(:) + type(dim_spec_t), allocatable :: mem_shape_patch_soil(:) + type(dim_spec_t), allocatable :: mem_shape_patch_snow(:) + type(dim_spec_t), allocatable :: mem_shape_patch_rad(:) + type(dim_spec_t), allocatable :: mem_shape_patch_plantcarbon(:) + type(dim_spec_t), allocatable :: mem_shape_patch_soilcarbon(:) + + type(dim_spec_t), allocatable :: var_shape_x_y(:) + type(dim_spec_t), allocatable :: var_shape_x_y_soil(:) + type(dim_spec_t), allocatable :: var_shape_x_y_snow(:) + type(dim_spec_t), allocatable :: var_shape_x_y_rad(:) + type(dim_spec_t), allocatable :: var_shape_x_y_plantcarbon(:) + type(dim_spec_t), allocatable :: var_shape_x_y_soilcarbon(:) + type(dim_spec_t), allocatable :: var_shape_x_y_patch(:) + type(dim_spec_t), allocatable :: var_shape_x_y_patch_soil(:) + type(dim_spec_t), allocatable :: var_shape_x_y_patch_snow(:) + type(dim_spec_t), allocatable :: var_shape_x_y_patch_rad(:) + type(dim_spec_t), allocatable :: var_shape_x_y_patch_plantcarbon(:) + type(dim_spec_t), allocatable :: var_shape_x_y_patch_soilcarbon(:) + + type(dim_spec_t), allocatable :: var_shape_land(:) + type(dim_spec_t), allocatable :: var_shape_land_soil(:) + type(dim_spec_t), allocatable :: var_shape_land_snow(:) + type(dim_spec_t), allocatable :: var_shape_land_rad(:) + type(dim_spec_t), allocatable :: var_shape_land_plantcarbon(:) + type(dim_spec_t), allocatable :: var_shape_land_soilcarbon(:) + type(dim_spec_t), allocatable :: var_shape_land_patch(:) + type(dim_spec_t), allocatable :: var_shape_land_patch_soil(:) + type(dim_spec_t), allocatable :: var_shape_land_patch_snow(:) + type(dim_spec_t), allocatable :: var_shape_land_patch_rad(:) + type(dim_spec_t), allocatable :: var_shape_land_patch_plantcarbon(:) + type(dim_spec_t), allocatable :: var_shape_land_patch_soilcarbon(:) + + type(dim_spec_t), allocatable :: var_shape_patch(:) + type(dim_spec_t), allocatable :: var_shape_patch_soil(:) + type(dim_spec_t), allocatable :: var_shape_patch_snow(:) + type(dim_spec_t), allocatable :: var_shape_patch_rad(:) + type(dim_spec_t), allocatable :: var_shape_patch_plantcarbon(:) + type(dim_spec_t), allocatable :: var_shape_patch_soilcarbon(:) + + mem_shape_land = [dim_spec_t('land', mland)] + mem_shape_land_soil = [dim_spec_t('land', mland), dim_spec_t('soil', ms)] + mem_shape_land_snow = [dim_spec_t('land', mland), dim_spec_t('snow', msn)] + mem_shape_land_rad = [dim_spec_t('land', mland), dim_spec_t('rad', nrb)] + mem_shape_land_plantcarbon = [dim_spec_t('land', mland), dim_spec_t('plantcarbon', ncp)] + mem_shape_land_soilcarbon = [dim_spec_t('land', mland), dim_spec_t('soilcarbon', ncs)] + mem_shape_patch = [dim_spec_t('patch', mp)] + mem_shape_patch_soil = [dim_spec_t('patch', mp), dim_spec_t('soil', ms)] + mem_shape_patch_snow = [dim_spec_t('patch', mp), dim_spec_t('snow', msn)] + mem_shape_patch_rad = [dim_spec_t('patch', mp), dim_spec_t('rad', nrb)] + mem_shape_patch_plantcarbon = [dim_spec_t('patch', mp), dim_spec_t('plantcarbon', ncp)] + mem_shape_patch_soilcarbon = [dim_spec_t('patch', mp), dim_spec_t('soilcarbon', ncs)] + + var_shape_x_y = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize)] + var_shape_x_y_soil = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('soil', ms)] + var_shape_x_y_snow = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('snow', msn)] + var_shape_x_y_rad = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('rad', nrb)] + var_shape_x_y_plantcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('plantcarbon', ncp)] + var_shape_x_y_soilcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('soilcarbon', ncs)] + var_shape_x_y_patch = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches)] + var_shape_x_y_patch_soil = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('soil', ms)] + var_shape_x_y_patch_snow = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('snow', msn)] + var_shape_x_y_patch_rad = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('rad', nrb)] + var_shape_x_y_patch_plantcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('plantcarbon', ncp)] + var_shape_x_y_patch_soilcarbon = [dim_spec_t('x', xdimsize), dim_spec_t('y', ydimsize), dim_spec_t('patch', max_vegpatches), dim_spec_t('soilcarbon', ncs)] + + var_shape_land = [dim_spec_t('land', mland_global)] + var_shape_land_soil = [dim_spec_t('land', mland_global), dim_spec_t('soil', ms)] + var_shape_land_snow = [dim_spec_t('land', mland_global), dim_spec_t('snow', msn)] + var_shape_land_rad = [dim_spec_t('land', mland_global), dim_spec_t('rad', nrb)] + var_shape_land_plantcarbon = [dim_spec_t('land', mland_global), dim_spec_t('plantcarbon', ncp)] + var_shape_land_soilcarbon = [dim_spec_t('land', mland_global), dim_spec_t('soilcarbon', ncs)] + var_shape_land_patch = [dim_spec_t('land', mland_global)] + var_shape_land_patch_soil = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('soil', ms)] + var_shape_land_patch_snow = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('snow', msn)] + var_shape_land_patch_rad = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('rad', nrb)] + var_shape_land_patch_plantcarbon = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('plantcarbon', ncp)] + var_shape_land_patch_soilcarbon = [dim_spec_t('land', mland_global), dim_spec_t('patch', max_vegpatches), dim_spec_t('soilcarbon', ncs)] + + var_shape_patch = [dim_spec_t('patch', mp_global)] + var_shape_patch_soil = [dim_spec_t('patch', mp_global), dim_spec_t('soil', ms)] + var_shape_patch_snow = [dim_spec_t('patch', mp_global), dim_spec_t('snow', msn)] + var_shape_patch_rad = [dim_spec_t('patch', mp_global), dim_spec_t('rad', nrb)] + var_shape_patch_plantcarbon = [dim_spec_t('patch', mp_global), dim_spec_t('plantcarbon', ncp)] + var_shape_patch_soilcarbon = [dim_spec_t('patch', mp_global), dim_spec_t('soilcarbon', ncs)] + + decomp_grid_x_y%land_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land, var_shape_x_y, CABLE_NETCDF_INT) + decomp_grid_x_y%land_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land, var_shape_x_y, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%land_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land, var_shape_x_y, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%land_soil_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soil, var_shape_x_y_soil, CABLE_NETCDF_INT) + decomp_grid_x_y%land_soil_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soil, var_shape_x_y_soil, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%land_soil_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soil, var_shape_x_y_soil, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%land_snow_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_snow, var_shape_x_y_snow, CABLE_NETCDF_INT) + decomp_grid_x_y%land_snow_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_snow, var_shape_x_y_snow, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%land_snow_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_snow, var_shape_x_y_snow, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%land_rad_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_rad, var_shape_x_y_rad, CABLE_NETCDF_INT) + decomp_grid_x_y%land_rad_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_rad, var_shape_x_y_rad, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%land_rad_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_rad, var_shape_x_y_rad, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%land_plantcarbon_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_plantcarbon, var_shape_x_y_plantcarbon, CABLE_NETCDF_INT) + decomp_grid_x_y%land_plantcarbon_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_plantcarbon, var_shape_x_y_plantcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%land_plantcarbon_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_plantcarbon, var_shape_x_y_plantcarbon, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%land_soilcarbon_int32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soilcarbon, var_shape_x_y_soilcarbon, CABLE_NETCDF_INT) + decomp_grid_x_y%land_soilcarbon_real32 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soilcarbon, var_shape_x_y_soilcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%land_soilcarbon_real64 = io_decomp_land_to_x_y(land_x, land_y, mem_shape_land_soilcarbon, var_shape_x_y_soilcarbon, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%patch_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_x_y_patch, CABLE_NETCDF_INT) + decomp_grid_x_y%patch_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_x_y_patch, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%patch_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_x_y_patch, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%patch_soil_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_x_y_patch_soil, CABLE_NETCDF_INT) + decomp_grid_x_y%patch_soil_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_x_y_patch_soil, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%patch_soil_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_x_y_patch_soil, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%patch_snow_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_x_y_patch_snow, CABLE_NETCDF_INT) + decomp_grid_x_y%patch_snow_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_x_y_patch_snow, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%patch_snow_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_x_y_patch_snow, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%patch_rad_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_x_y_patch_rad, CABLE_NETCDF_INT) + decomp_grid_x_y%patch_rad_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_x_y_patch_rad, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%patch_rad_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_x_y_patch_rad, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%patch_plantcarbon_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_x_y_patch_plantcarbon, CABLE_NETCDF_INT) + decomp_grid_x_y%patch_plantcarbon_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_x_y_patch_plantcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%patch_plantcarbon_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_x_y_patch_plantcarbon, CABLE_NETCDF_DOUBLE) + decomp_grid_x_y%patch_soilcarbon_int32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_x_y_patch_soilcarbon, CABLE_NETCDF_INT) + decomp_grid_x_y%patch_soilcarbon_real32 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_x_y_patch_soilcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_x_y%patch_soilcarbon_real64 = io_decomp_patch_to_x_y_patch(land_x, land_y, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_x_y_patch_soilcarbon, CABLE_NETCDF_DOUBLE) + + decomp_grid_land%land_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land, var_shape_land, CABLE_NETCDF_INT) + decomp_grid_land%land_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land, var_shape_land, CABLE_NETCDF_FLOAT) + decomp_grid_land%land_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land, var_shape_land, CABLE_NETCDF_DOUBLE) + decomp_grid_land%land_soil_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soil, var_shape_land_soil, CABLE_NETCDF_INT) + decomp_grid_land%land_soil_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soil, var_shape_land_soil, CABLE_NETCDF_FLOAT) + decomp_grid_land%land_soil_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soil, var_shape_land_soil, CABLE_NETCDF_DOUBLE) + decomp_grid_land%land_snow_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_snow, var_shape_land_snow, CABLE_NETCDF_INT) + decomp_grid_land%land_snow_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_snow, var_shape_land_snow, CABLE_NETCDF_FLOAT) + decomp_grid_land%land_snow_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_snow, var_shape_land_snow, CABLE_NETCDF_DOUBLE) + decomp_grid_land%land_rad_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_rad, var_shape_land_rad, CABLE_NETCDF_INT) + decomp_grid_land%land_rad_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_rad, var_shape_land_rad, CABLE_NETCDF_FLOAT) + decomp_grid_land%land_rad_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_rad, var_shape_land_rad, CABLE_NETCDF_DOUBLE) + decomp_grid_land%land_plantcarbon_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_plantcarbon, var_shape_land_plantcarbon, CABLE_NETCDF_INT) + decomp_grid_land%land_plantcarbon_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_plantcarbon, var_shape_land_plantcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_land%land_plantcarbon_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_plantcarbon, var_shape_land_plantcarbon, CABLE_NETCDF_DOUBLE) + decomp_grid_land%land_soilcarbon_int32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soilcarbon, var_shape_land_soilcarbon, CABLE_NETCDF_INT) + decomp_grid_land%land_soilcarbon_real32 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soilcarbon, var_shape_land_soilcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_land%land_soilcarbon_real64 = io_decomp_land_to_land(land_decomp_start, mem_shape_land_soilcarbon, var_shape_land_soilcarbon, CABLE_NETCDF_DOUBLE) + decomp_grid_land%patch_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_land_patch, CABLE_NETCDF_INT) + decomp_grid_land%patch_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_land_patch, CABLE_NETCDF_FLOAT) + decomp_grid_land%patch_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch, var_shape_land_patch, CABLE_NETCDF_DOUBLE) + decomp_grid_land%patch_soil_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_land_patch_soil, CABLE_NETCDF_INT) + decomp_grid_land%patch_soil_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_land_patch_soil, CABLE_NETCDF_FLOAT) + decomp_grid_land%patch_soil_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soil, var_shape_land_patch_soil, CABLE_NETCDF_DOUBLE) + decomp_grid_land%patch_snow_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_land_patch_snow, CABLE_NETCDF_INT) + decomp_grid_land%patch_snow_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_land_patch_snow, CABLE_NETCDF_FLOAT) + decomp_grid_land%patch_snow_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_snow, var_shape_land_patch_snow, CABLE_NETCDF_DOUBLE) + decomp_grid_land%patch_rad_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_land_patch_rad, CABLE_NETCDF_INT) + decomp_grid_land%patch_rad_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_land_patch_rad, CABLE_NETCDF_FLOAT) + decomp_grid_land%patch_rad_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_rad, var_shape_land_patch_rad, CABLE_NETCDF_DOUBLE) + decomp_grid_land%patch_plantcarbon_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_land_patch_plantcarbon, CABLE_NETCDF_INT) + decomp_grid_land%patch_plantcarbon_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_land_patch_plantcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_land%patch_plantcarbon_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_plantcarbon, var_shape_land_patch_plantcarbon, CABLE_NETCDF_DOUBLE) + decomp_grid_land%patch_soilcarbon_int32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_land_patch_soilcarbon, CABLE_NETCDF_INT) + decomp_grid_land%patch_soilcarbon_real32 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_land_patch_soilcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_land%patch_soilcarbon_real64 = io_decomp_patch_to_land_patch(land_decomp_start, landpt(:)%cstart, landpt(:)%nap, mem_shape_patch_soilcarbon, var_shape_land_patch_soilcarbon, CABLE_NETCDF_DOUBLE) + + decomp_grid_restart%patch_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch, var_shape_patch, CABLE_NETCDF_INT) + decomp_grid_restart%patch_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch, var_shape_patch, CABLE_NETCDF_FLOAT) + decomp_grid_restart%patch_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch, var_shape_patch, CABLE_NETCDF_DOUBLE) + decomp_grid_restart%patch_soil_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soil, var_shape_patch_soil, CABLE_NETCDF_INT) + decomp_grid_restart%patch_soil_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soil, var_shape_patch_soil, CABLE_NETCDF_FLOAT) + decomp_grid_restart%patch_soil_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soil, var_shape_patch_soil, CABLE_NETCDF_DOUBLE) + decomp_grid_restart%patch_snow_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_snow, var_shape_patch_snow, CABLE_NETCDF_INT) + decomp_grid_restart%patch_snow_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_snow, var_shape_patch_snow, CABLE_NETCDF_FLOAT) + decomp_grid_restart%patch_snow_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_snow, var_shape_patch_snow, CABLE_NETCDF_DOUBLE) + decomp_grid_restart%patch_rad_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_rad, var_shape_patch_rad, CABLE_NETCDF_INT) + decomp_grid_restart%patch_rad_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_rad, var_shape_patch_rad, CABLE_NETCDF_FLOAT) + decomp_grid_restart%patch_rad_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_rad, var_shape_patch_rad, CABLE_NETCDF_DOUBLE) + decomp_grid_restart%patch_plantcarbon_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_plantcarbon, var_shape_patch_plantcarbon, CABLE_NETCDF_INT) + decomp_grid_restart%patch_plantcarbon_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_plantcarbon, var_shape_patch_plantcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_restart%patch_plantcarbon_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_plantcarbon, var_shape_patch_plantcarbon, CABLE_NETCDF_DOUBLE) + decomp_grid_restart%patch_soilcarbon_int32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soilcarbon, var_shape_patch_soilcarbon, CABLE_NETCDF_INT) + decomp_grid_restart%patch_soilcarbon_real32 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soilcarbon, var_shape_patch_soilcarbon, CABLE_NETCDF_FLOAT) + decomp_grid_restart%patch_soilcarbon_real64 = io_decomp_patch_to_patch(patch_decomp_start, mem_shape_patch_soilcarbon, var_shape_patch_soilcarbon, CABLE_NETCDF_DOUBLE) + + end subroutine + + subroutine deallocate_decompositions() + + deallocate(decomp_grid_x_y%land_int32) + deallocate(decomp_grid_x_y%land_real32) + deallocate(decomp_grid_x_y%land_real64) + deallocate(decomp_grid_x_y%land_soil_int32) + deallocate(decomp_grid_x_y%land_soil_real32) + deallocate(decomp_grid_x_y%land_soil_real64) + deallocate(decomp_grid_x_y%land_snow_int32) + deallocate(decomp_grid_x_y%land_snow_real32) + deallocate(decomp_grid_x_y%land_snow_real64) + deallocate(decomp_grid_x_y%land_rad_int32) + deallocate(decomp_grid_x_y%land_rad_real32) + deallocate(decomp_grid_x_y%land_rad_real64) + deallocate(decomp_grid_x_y%land_plantcarbon_int32) + deallocate(decomp_grid_x_y%land_plantcarbon_real32) + deallocate(decomp_grid_x_y%land_plantcarbon_real64) + deallocate(decomp_grid_x_y%land_soilcarbon_int32) + deallocate(decomp_grid_x_y%land_soilcarbon_real32) + deallocate(decomp_grid_x_y%land_soilcarbon_real64) + deallocate(decomp_grid_x_y%patch_int32) + deallocate(decomp_grid_x_y%patch_real32) + deallocate(decomp_grid_x_y%patch_real64) + deallocate(decomp_grid_x_y%patch_soil_int32) + deallocate(decomp_grid_x_y%patch_soil_real32) + deallocate(decomp_grid_x_y%patch_soil_real64) + deallocate(decomp_grid_x_y%patch_snow_int32) + deallocate(decomp_grid_x_y%patch_snow_real32) + deallocate(decomp_grid_x_y%patch_snow_real64) + deallocate(decomp_grid_x_y%patch_rad_int32) + deallocate(decomp_grid_x_y%patch_rad_real32) + deallocate(decomp_grid_x_y%patch_rad_real64) + deallocate(decomp_grid_x_y%patch_plantcarbon_int32) + deallocate(decomp_grid_x_y%patch_plantcarbon_real32) + deallocate(decomp_grid_x_y%patch_plantcarbon_real64) + deallocate(decomp_grid_x_y%patch_soilcarbon_int32) + deallocate(decomp_grid_x_y%patch_soilcarbon_real32) + deallocate(decomp_grid_x_y%patch_soilcarbon_real64) + + deallocate(decomp_grid_land%land_int32) + deallocate(decomp_grid_land%land_real32) + deallocate(decomp_grid_land%land_real64) + deallocate(decomp_grid_land%land_soil_int32) + deallocate(decomp_grid_land%land_soil_real32) + deallocate(decomp_grid_land%land_soil_real64) + deallocate(decomp_grid_land%land_snow_int32) + deallocate(decomp_grid_land%land_snow_real32) + deallocate(decomp_grid_land%land_snow_real64) + deallocate(decomp_grid_land%land_rad_int32) + deallocate(decomp_grid_land%land_rad_real32) + deallocate(decomp_grid_land%land_rad_real64) + deallocate(decomp_grid_land%land_plantcarbon_int32) + deallocate(decomp_grid_land%land_plantcarbon_real32) + deallocate(decomp_grid_land%land_plantcarbon_real64) + deallocate(decomp_grid_land%land_soilcarbon_int32) + deallocate(decomp_grid_land%land_soilcarbon_real32) + deallocate(decomp_grid_land%land_soilcarbon_real64) + deallocate(decomp_grid_land%patch_int32) + deallocate(decomp_grid_land%patch_real32) + deallocate(decomp_grid_land%patch_real64) + deallocate(decomp_grid_land%patch_soil_int32) + deallocate(decomp_grid_land%patch_soil_real32) + deallocate(decomp_grid_land%patch_soil_real64) + deallocate(decomp_grid_land%patch_snow_int32) + deallocate(decomp_grid_land%patch_snow_real32) + deallocate(decomp_grid_land%patch_snow_real64) + deallocate(decomp_grid_land%patch_rad_int32) + deallocate(decomp_grid_land%patch_rad_real32) + deallocate(decomp_grid_land%patch_rad_real64) + deallocate(decomp_grid_land%patch_plantcarbon_int32) + deallocate(decomp_grid_land%patch_plantcarbon_real32) + deallocate(decomp_grid_land%patch_plantcarbon_real64) + deallocate(decomp_grid_land%patch_soilcarbon_int32) + deallocate(decomp_grid_land%patch_soilcarbon_real32) + deallocate(decomp_grid_land%patch_soilcarbon_real64) + + deallocate(decomp_grid_restart%patch_int32) + deallocate(decomp_grid_restart%patch_real32) + deallocate(decomp_grid_restart%patch_real64) + deallocate(decomp_grid_restart%patch_soil_int32) + deallocate(decomp_grid_restart%patch_soil_real32) + deallocate(decomp_grid_restart%patch_soil_real64) + deallocate(decomp_grid_restart%patch_snow_int32) + deallocate(decomp_grid_restart%patch_snow_real32) + deallocate(decomp_grid_restart%patch_snow_real64) + deallocate(decomp_grid_restart%patch_rad_int32) + deallocate(decomp_grid_restart%patch_rad_real32) + deallocate(decomp_grid_restart%patch_rad_real64) + deallocate(decomp_grid_restart%patch_plantcarbon_int32) + deallocate(decomp_grid_restart%patch_plantcarbon_real32) + deallocate(decomp_grid_restart%patch_plantcarbon_real64) + deallocate(decomp_grid_restart%patch_soilcarbon_int32) + deallocate(decomp_grid_restart%patch_soilcarbon_real32) + deallocate(decomp_grid_restart%patch_soilcarbon_real64) + + end subroutine + + subroutine associate_decomp_int32(output_profile, output_var, decomp) + type(cable_output_profile_t), intent(in) :: output_profile + type(cable_output_variable_t), intent(in) :: output_var + class(cable_netcdf_decomp_t), pointer, intent(inout) :: decomp + type(cable_output_decomp_t), pointer :: output_decomp + + select case (output_profile%grid_type) + case ("restart") + call associate_decomp_restart_int32(output_var, decomp) + return + case ("mask") + output_decomp => decomp_grid_x_y + case ("land") + output_decomp => decomp_grid_land + case default + call cable_abort("Unsupported grid type for output profile " // output_profile%file_name, __FILE__, __LINE__) + end select + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_int32 + else + decomp => output_decomp%land_int32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_soil_int32 + else + decomp => output_decomp%land_soil_int32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_snow_int32 + else + decomp => output_decomp%land_snow_int32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_rad_int32 + else + decomp => output_decomp%land_rad_int32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_plantcarbon_int32 + else + decomp => output_decomp%land_plantcarbon_int32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_soilcarbon_int32 + else + decomp => output_decomp%land_soilcarbon_int32 + end if + else + call cable_abort("Unsupported data shape for output variable " // output_var%field_name, __FILE__, __LINE__) + end if + + end subroutine associate_decomp_int32 + + subroutine associate_decomp_real32(output_profile, output_var, decomp) + type(cable_output_profile_t), intent(in) :: output_profile + type(cable_output_variable_t), intent(in) :: output_var + class(cable_netcdf_decomp_t), pointer, intent(inout) :: decomp + type(cable_output_decomp_t), pointer :: output_decomp + + select case (output_profile%grid_type) + case ("restart") + call associate_decomp_restart_real32(output_var, decomp) + return + case ("mask") + output_decomp => decomp_grid_x_y + case ("land") + output_decomp => decomp_grid_land + case default + call cable_abort("Unsupported grid type for output profile " // output_profile%file_name, __FILE__, __LINE__) + end select + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_real32 + else + decomp => output_decomp%land_real32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_soil_real32 + else + decomp => output_decomp%land_soil_real32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_snow_real32 + else + decomp => output_decomp%land_snow_real32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_rad_real32 + else + decomp => output_decomp%land_rad_real32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_plantcarbon_real32 + else + decomp => output_decomp%land_plantcarbon_real32 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_soilcarbon_real32 + else + decomp => output_decomp%land_soilcarbon_real32 + end if + else + call cable_abort("Unsupported data shape for output variable " // output_var%field_name, __FILE__, __LINE__) + end if + + end subroutine associate_decomp_real32 + + subroutine associate_decomp_real64(output_profile, output_var, decomp) + type(cable_output_profile_t), intent(in) :: output_profile + type(cable_output_variable_t), intent(in) :: output_var + class(cable_netcdf_decomp_t), pointer, intent(inout) :: decomp + type(cable_output_decomp_t), pointer :: output_decomp + + select case (output_profile%grid_type) + case ("restart") + call associate_decomp_restart_real64(output_var, decomp) + return + case ("mask") + output_decomp => decomp_grid_x_y + case ("land") + output_decomp => decomp_grid_land + case default + call cable_abort("Unsupported grid type for output profile " // output_profile%file_name, __FILE__, __LINE__) + end select + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_real64 + else + decomp => output_decomp%land_real64 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_soil_real64 + else + decomp => output_decomp%land_soil_real64 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_snow_real64 + else + decomp => output_decomp%land_snow_real64 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_rad_real64 + else + decomp => output_decomp%land_rad_real64 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_plantcarbon_real64 + else + decomp => output_decomp%land_plantcarbon_real64 + end if + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + if (output_var%reduction_method == "none") then + decomp => output_decomp%patch_soilcarbon_real64 + else + decomp => output_decomp%land_soilcarbon_real64 + end if + else + call cable_abort("Unsupported data shape for output variable " // output_var%field_name, __FILE__, __LINE__) + end if + + end subroutine associate_decomp_real64 + + subroutine associate_decomp_restart_int32(output_var, decomp) + type(cable_output_variable_t), intent(in) :: output_var + class(cable_netcdf_decomp_t), pointer, intent(inout) :: decomp + type(cable_output_decomp_t), pointer :: output_decomp + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + decomp => decomp_grid_restart%patch_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + decomp => decomp_grid_restart%patch_soil_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + decomp => decomp_grid_restart%patch_snow_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + decomp => decomp_grid_restart%patch_rad_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + decomp => decomp_grid_restart%patch_plantcarbon_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + decomp => decomp_grid_restart%patch_soilcarbon_int32 + else + call cable_abort("Unsupported data shape for output variable " // output_var%field_name, __FILE__, __LINE__) + end if + + end subroutine associate_decomp_restart_int32 + + subroutine associate_decomp_restart_real32(output_var, decomp) + type(cable_output_variable_t), intent(in) :: output_var + class(cable_netcdf_decomp_t), pointer, intent(inout) :: decomp + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + decomp => decomp_grid_restart%patch_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + decomp => decomp_grid_restart%patch_soil_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + decomp => decomp_grid_restart%patch_snow_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + decomp => decomp_grid_restart%patch_rad_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + decomp => decomp_grid_restart%patch_plantcarbon_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + decomp => decomp_grid_restart%patch_soilcarbon_real32 + else + call cable_abort("Unsupported data shape for output variable " // output_var%field_name, __FILE__, __LINE__) + end if + + end subroutine associate_decomp_restart_real32 + + subroutine associate_decomp_restart_real64(output_var, decomp) + type(cable_output_variable_t), intent(in) :: output_var + class(cable_netcdf_decomp_t), pointer, intent(inout) :: decomp + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + decomp => decomp_grid_restart%patch_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + decomp => decomp_grid_restart%patch_soil_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + decomp => decomp_grid_restart%patch_snow_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + decomp => decomp_grid_restart%patch_rad_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + decomp => decomp_grid_restart%patch_plantcarbon_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + decomp => decomp_grid_restart%patch_soilcarbon_real64 + else + call cable_abort("Unsupported data shape for output variable " // output_var%field_name, __FILE__, __LINE__) + end if + + end subroutine associate_decomp_restart_real64 + +end module diff --git a/src/util/io/output/cable_output_reduction_buffers.F90 b/src/util/io/output/cable_output_reduction_buffers.F90 new file mode 100644 index 000000000..1fc9d4bb4 --- /dev/null +++ b/src/util/io/output/cable_output_reduction_buffers.F90 @@ -0,0 +1,220 @@ +module cable_output_reduction_buffers_mod + + use cable_abort_module, only: cable_abort + + use iso_fortran_env, only: int32, real32, real64 + + use cable_def_types_mod, only: mland + use cable_def_types_mod, only: ms + use cable_def_types_mod, only: msn + use cable_def_types_mod, only: nrb + use cable_def_types_mod, only: ncs + use cable_def_types_mod, only: ncp + + use cable_output_types_mod, only: cable_output_variable_t + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PATCH + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOIL + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SNOW + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_RAD + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PLANTCARBON + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOILCARBON + + use cable_output_utils_mod, only: data_shape_eq + + implicit none + private + + public :: allocate_grid_reduction_buffers + public :: deallocate_grid_reduction_buffers + public :: associate_temp_buffer_int32 + public :: associate_temp_buffer_real32 + public :: associate_temp_buffer_real64 + + integer(kind=int32), allocatable, target :: temp_buffer_land_int32(:) + real(kind=real32), allocatable, target :: temp_buffer_land_real32(:) + real(kind=real64), allocatable, target :: temp_buffer_land_real64(:) + integer(kind=int32), allocatable, target :: temp_buffer_land_soil_int32(:, :) + real(kind=real32), allocatable, target :: temp_buffer_land_soil_real32(:, :) + real(kind=real64), allocatable, target :: temp_buffer_land_soil_real64(:, :) + integer(kind=int32), allocatable, target :: temp_buffer_land_snow_int32(:, :) + real(kind=real32), allocatable, target :: temp_buffer_land_snow_real32(:, :) + real(kind=real64), allocatable, target :: temp_buffer_land_snow_real64(:, :) + integer(kind=int32), allocatable, target :: temp_buffer_land_rad_int32(:, :) + real(kind=real32), allocatable, target :: temp_buffer_land_rad_real32(:, :) + real(kind=real64), allocatable, target :: temp_buffer_land_rad_real64(:, :) + integer(kind=int32), allocatable, target :: temp_buffer_land_plantcarbon_int32(:, :) + real(kind=real32), allocatable, target :: temp_buffer_land_plantcarbon_real32(:, :) + real(kind=real64), allocatable, target :: temp_buffer_land_plantcarbon_real64(:, :) + integer(kind=int32), allocatable, target :: temp_buffer_land_soilcarbon_int32(:, :) + real(kind=real32), allocatable, target :: temp_buffer_land_soilcarbon_real32(:, :) + real(kind=real64), allocatable, target :: temp_buffer_land_soilcarbon_real64(:, :) + +contains + + subroutine allocate_grid_reduction_buffers() + + allocate(temp_buffer_land_int32(mland)) + allocate(temp_buffer_land_real32(mland)) + allocate(temp_buffer_land_real64(mland)) + allocate(temp_buffer_land_soil_int32(mland, ms)) + allocate(temp_buffer_land_soil_real32(mland, ms)) + allocate(temp_buffer_land_soil_real64(mland, ms)) + allocate(temp_buffer_land_snow_int32(mland, msn)) + allocate(temp_buffer_land_snow_real32(mland, msn)) + allocate(temp_buffer_land_snow_real64(mland, msn)) + allocate(temp_buffer_land_rad_int32(mland, nrb)) + allocate(temp_buffer_land_rad_real32(mland, nrb)) + allocate(temp_buffer_land_rad_real64(mland, nrb)) + allocate(temp_buffer_land_plantcarbon_int32(mland, ncp)) + allocate(temp_buffer_land_plantcarbon_real32(mland, ncp)) + allocate(temp_buffer_land_plantcarbon_real64(mland, ncp)) + allocate(temp_buffer_land_soilcarbon_int32(mland, ncs)) + allocate(temp_buffer_land_soilcarbon_real32(mland, ncs)) + allocate(temp_buffer_land_soilcarbon_real64(mland, ncs)) + + end subroutine + + subroutine deallocate_grid_reduction_buffers() + + deallocate(temp_buffer_land_int32) + deallocate(temp_buffer_land_real32) + deallocate(temp_buffer_land_real64) + deallocate(temp_buffer_land_soil_int32) + deallocate(temp_buffer_land_soil_real32) + deallocate(temp_buffer_land_soil_real64) + deallocate(temp_buffer_land_snow_int32) + deallocate(temp_buffer_land_snow_real32) + deallocate(temp_buffer_land_snow_real64) + deallocate(temp_buffer_land_rad_int32) + deallocate(temp_buffer_land_rad_real32) + deallocate(temp_buffer_land_rad_real64) + deallocate(temp_buffer_land_plantcarbon_int32) + deallocate(temp_buffer_land_plantcarbon_real32) + deallocate(temp_buffer_land_plantcarbon_real64) + deallocate(temp_buffer_land_soilcarbon_int32) + deallocate(temp_buffer_land_soilcarbon_real32) + deallocate(temp_buffer_land_soilcarbon_real64) + + end subroutine + + subroutine associate_temp_buffer_int32(output_var, temp_buffer_int32_1d, temp_buffer_int32_2d, temp_buffer_int32_3d) + type(cable_output_variable_t), intent(inout) :: output_var + integer(kind=int32), pointer, intent(inout), optional :: temp_buffer_int32_1d(:) + integer(kind=int32), pointer, intent(inout), optional :: temp_buffer_int32_2d(:,:) + integer(kind=int32), pointer, intent(inout), optional :: temp_buffer_int32_3d(:,:,:) + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + if (.not. present(temp_buffer_int32_1d)) call cable_abort( & + "temp_buffer_int32_1d must be provided for 1D data shape", __FILE__, __LINE__) + temp_buffer_int32_1d => temp_buffer_land_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + if (.not. present(temp_buffer_int32_2d)) call cable_abort( & + "temp_buffer_int32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_int32_2d => temp_buffer_land_soil_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (.not. present(temp_buffer_int32_2d)) call cable_abort( & + "temp_buffer_int32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_int32_2d => temp_buffer_land_rad_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + if (.not. present(temp_buffer_int32_2d)) call cable_abort( & + "temp_buffer_int32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_int32_2d => temp_buffer_land_snow_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (.not. present(temp_buffer_int32_2d)) call cable_abort( & + "temp_buffer_int32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_int32_2d => temp_buffer_land_rad_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + if (.not. present(temp_buffer_int32_2d)) call cable_abort( & + "temp_buffer_int32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_int32_2d => temp_buffer_land_plantcarbon_int32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + if (.not. present(temp_buffer_int32_2d)) call cable_abort( & + "temp_buffer_int32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_int32_2d => temp_buffer_land_soilcarbon_int32 + else + call cable_abort("Unexpected source data shape for grid reduction", __FILE__, __LINE__) + end if + + end subroutine associate_temp_buffer_int32 + + subroutine associate_temp_buffer_real32(output_var, temp_buffer_real32_1d, temp_buffer_real32_2d, temp_buffer_real32_3d) + type(cable_output_variable_t), intent(inout) :: output_var + real(kind=real32), pointer, intent(inout), optional :: temp_buffer_real32_1d(:) + real(kind=real32), pointer, intent(inout), optional :: temp_buffer_real32_2d(:,:) + real(kind=real32), pointer, intent(inout), optional :: temp_buffer_real32_3d(:,:,:) + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + if (.not. present(temp_buffer_real32_1d)) call cable_abort( & + "temp_buffer_real32_1d must be provided for 1D data shape", __FILE__, __LINE__) + temp_buffer_real32_1d => temp_buffer_land_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + if (.not. present(temp_buffer_real32_2d)) call cable_abort( & + "temp_buffer_real32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real32_2d => temp_buffer_land_soil_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (.not. present(temp_buffer_real32_2d)) call cable_abort( & + "temp_buffer_real32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real32_2d => temp_buffer_land_rad_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + if (.not. present(temp_buffer_real32_2d)) call cable_abort( & + "temp_buffer_real32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real32_2d => temp_buffer_land_snow_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (.not. present(temp_buffer_real32_2d)) call cable_abort( & + "temp_buffer_real32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real32_2d => temp_buffer_land_rad_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + if (.not. present(temp_buffer_real32_2d)) call cable_abort( & + "temp_buffer_real32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real32_2d => temp_buffer_land_plantcarbon_real32 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + if (.not. present(temp_buffer_real32_2d)) call cable_abort( & + "temp_buffer_real32_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real32_2d => temp_buffer_land_soilcarbon_real32 + else + call cable_abort("Unexpected source data shape for grid reduction", __FILE__, __LINE__) + end if + + end subroutine associate_temp_buffer_real32 + + subroutine associate_temp_buffer_real64(output_var, temp_buffer_real64_1d, temp_buffer_real64_2d, temp_buffer_real64_3d) + type(cable_output_variable_t), intent(inout) :: output_var + real(kind=real64), pointer, intent(inout), optional :: temp_buffer_real64_1d(:) + real(kind=real64), pointer, intent(inout), optional :: temp_buffer_real64_2d(:,:) + real(kind=real64), pointer, intent(inout), optional :: temp_buffer_real64_3d(:,:,:) + + if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH])) then + if (.not. present(temp_buffer_real64_1d)) call cable_abort( & + "temp_buffer_real64_1d must be provided for 1D data shape", __FILE__, __LINE__) + temp_buffer_real64_1d => temp_buffer_land_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOIL])) then + if (.not. present(temp_buffer_real64_2d)) call cable_abort( & + "temp_buffer_real64_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real64_2d => temp_buffer_land_soil_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (.not. present(temp_buffer_real64_2d)) call cable_abort( & + "temp_buffer_real64_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real64_2d => temp_buffer_land_rad_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SNOW])) then + if (.not. present(temp_buffer_real64_2d)) call cable_abort( & + "temp_buffer_real64_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real64_2d => temp_buffer_land_snow_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_RAD])) then + if (.not. present(temp_buffer_real64_2d)) call cable_abort( & + "temp_buffer_real64_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real64_2d => temp_buffer_land_rad_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_PLANTCARBON])) then + if (.not. present(temp_buffer_real64_2d)) call cable_abort( & + "temp_buffer_real64_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real64_2d => temp_buffer_land_plantcarbon_real64 + else if (data_shape_eq(output_var%data_shape, [CABLE_OUTPUT_DIM_PATCH, CABLE_OUTPUT_DIM_SOILCARBON])) then + if (.not. present(temp_buffer_real64_2d)) call cable_abort( & + "temp_buffer_real64_2d must be provided for 2D data shape", __FILE__, __LINE__) + temp_buffer_real64_2d => temp_buffer_land_soilcarbon_real64 + else + call cable_abort("Unexpected source data shape for grid reduction", __FILE__, __LINE__) + end if + + end subroutine associate_temp_buffer_real64 + +end module diff --git a/src/util/io/output/cable_output_types.F90 b/src/util/io/output/cable_output_types.F90 new file mode 100644 index 000000000..d6297fb52 --- /dev/null +++ b/src/util/io/output/cable_output_types.F90 @@ -0,0 +1,71 @@ +module cable_output_types_mod + + use iso_fortran_env, only: int32, real32, real64 + + use aggregator_mod, only: aggregator_t + + use cable_netcdf_mod, only: cable_netcdf_file_t + + use cable_enum_mod, only: cable_enum_t + + implicit none + private + + integer, parameter, public :: CABLE_OUTPUT_VAR_TYPE_UNDEFINED = -1 + + type, extends(cable_enum_t), public :: cable_output_dim_t + end type + + type, public :: cable_output_attribute_t + character(len=64) :: name + character(len=256) :: value + end type + + type, public :: cable_output_variable_t + character(len=64) :: field_name + character(len=64) :: netcdf_name = "" + character(len=64) :: accumulation_frequency = "all" + character(len=64) :: reduction_method = "none" + character(len=64) :: aggregation_method = "point" + logical :: active = .true. + logical :: parameter = .false. + logical :: distributed = .true. + logical :: restart = .false. + logical :: patchout = .false. + integer :: var_type = CABLE_OUTPUT_VAR_TYPE_UNDEFINED + real, dimension(2) :: range = [-huge(0.0), huge(0.0)] + real, allocatable :: scale + real, allocatable :: offset + type(cable_output_dim_t), allocatable :: data_shape(:) + class(aggregator_t), allocatable :: aggregator + type(cable_output_attribute_t), allocatable :: metadata(:) + end type + + type, public :: cable_output_profile_t + real :: previous_write_time = 0.0 + integer :: frame = 0 + character(len=64) :: sampling_frequency + character(len=64) :: grid_type + character(len=256) :: file_name + class(cable_netcdf_file_t), allocatable :: output_file + type(cable_output_variable_t), allocatable :: coordinate_variables(:) + type(cable_output_variable_t), allocatable :: output_variables(:) + type(cable_output_attribute_t), allocatable :: metadata(:) + end type + + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_PATCH = cable_output_dim_t(0) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_SOIL = cable_output_dim_t(1) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_SNOW = cable_output_dim_t(2) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_RAD = cable_output_dim_t(3) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_PLANTCARBON = cable_output_dim_t(4) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_SOILCARBON = cable_output_dim_t(5) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_LAND = cable_output_dim_t(6) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_LAND_GLOBAL = cable_output_dim_t(7) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_X = cable_output_dim_t(8) + type(cable_output_dim_t), parameter, public :: CABLE_OUTPUT_DIM_Y = cable_output_dim_t(9) + + integer(kind=int32), parameter, public :: FILL_VALUE_INT32 = -9999999_int32 + real(kind=real32), parameter, public :: FILL_VALUE_REAL32 = -1.0e+33_real32 + real(kind=real64), parameter, public :: FILL_VALUE_REAL64 = -1.0e+33_real64 + +end module diff --git a/src/util/io/output/cable_output_utils.F90 b/src/util/io/output/cable_output_utils.F90 new file mode 100644 index 000000000..e9c43dcdb --- /dev/null +++ b/src/util/io/output/cable_output_utils.F90 @@ -0,0 +1,606 @@ +module cable_output_utils_mod + + use cable_common_module, only: filename + + use cable_def_types_mod, only: mp + use cable_def_types_mod, only: mp_global + use cable_def_types_mod, only: mland + use cable_def_types_mod, only: mland_global + use cable_def_types_mod, only: ms + use cable_def_types_mod, only: msn + use cable_def_types_mod, only: nrb + use cable_def_types_mod, only: ncs + use cable_def_types_mod, only: ncp + + use cable_io_vars_module, only: xdimsize + use cable_io_vars_module, only: ydimsize + use cable_io_vars_module, only: max_vegpatches + use cable_io_vars_module, only: timeunits + use cable_io_vars_module, only: time_coord + use cable_io_vars_module, only: calendar + use cable_io_vars_module, only: lat_all, lon_all + use cable_io_vars_module, only: latitude, longitude + + use cable_abort_module, only: cable_abort + + use cable_netcdf_mod, only: MAX_LEN_DIM => CABLE_NETCDF_MAX_STR_LEN_DIM + use cable_netcdf_mod, only: CABLE_NETCDF_UNLIMITED + use cable_netcdf_mod, only: CABLE_NETCDF_INT + use cable_netcdf_mod, only: CABLE_NETCDF_FLOAT + use cable_netcdf_mod, only: CABLE_NETCDF_DOUBLE + + use cable_output_types_mod, only: cable_output_dim_t + use cable_output_types_mod, only: cable_output_variable_t + use cable_output_types_mod, only: cable_output_profile_t + use cable_output_types_mod, only: attribute => cable_output_attribute_t + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PATCH + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOIL + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SNOW + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_RAD + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_PLANTCARBON + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_SOILCARBON + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_LAND + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_LAND_GLOBAL + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_X + use cable_output_types_mod, only: CABLE_OUTPUT_DIM_Y + use cable_output_types_mod, only: FILL_VALUE_INT32 + use cable_output_types_mod, only: FILL_VALUE_REAL32 + use cable_output_types_mod, only: FILL_VALUE_REAL64 + use cable_output_types_mod, only: CABLE_OUTPUT_VAR_TYPE_UNDEFINED + + use aggregator_mod, only: new_aggregator + + implicit none + private + + public :: coordinate_variables + public :: check_duplicate_variable_names + public :: check_sampling_frequency + public :: dim_size + public :: var_name + public :: infer_dim_names + public :: define_variables + public :: set_global_attributes + public :: data_shape_eq + +contains + + function coordinate_variables(grid_type) result(coord_variables) + character(len=*), intent(in) :: grid_type + + type(cable_output_variable_t), allocatable :: coord_variables(:) + + select case (grid_type) + case ("restart") + coord_variables = [ & + cable_output_variable_t( & + field_name="latitude", & + data_shape=[CABLE_OUTPUT_DIM_LAND_GLOBAL], & + distributed=.false., & + aggregator=new_aggregator(latitude), & + metadata=[attribute("units", "degrees_north")] & + ), & + cable_output_variable_t( & + field_name="longitude", & + data_shape=[CABLE_OUTPUT_DIM_LAND_GLOBAL], & + distributed=.false., & + aggregator=new_aggregator(longitude), & + metadata=[attribute("units", "degrees_east")] & + ) & + ] + case ("mask") + coord_variables = [ & + cable_output_variable_t( & + field_name="lat_all", & + netcdf_name="latitude", & + data_shape=[CABLE_OUTPUT_DIM_X, CABLE_OUTPUT_DIM_Y], & + var_type=CABLE_NETCDF_FLOAT, & + parameter=.true., & + distributed=.false., & + aggregator=new_aggregator(lat_all), & + metadata=[attribute("units", "degrees_north")] & + ), & + cable_output_variable_t( & + field_name="lon_all", & + netcdf_name="longitude", & + data_shape=[CABLE_OUTPUT_DIM_X, CABLE_OUTPUT_DIM_Y], & + parameter=.true., & + distributed=.false., & + aggregator=new_aggregator(lon_all), & + metadata=[attribute("units", "degrees_east")] & + ), & + cable_output_variable_t( & + field_name="x", & + data_shape=[CABLE_OUTPUT_DIM_X], & + parameter=.true., & + distributed=.false., & + aggregator=new_aggregator(lon_all(:, 1)), & + metadata=[ & + attribute("units", "degrees_east"), & + attribute("comment", "x coordinate variable for GrADS compatibility") & + ] & + ), & + cable_output_variable_t( & + field_name="y", & + data_shape=[CABLE_OUTPUT_DIM_Y], & + parameter=.true., & + distributed=.false., & + aggregator=new_aggregator(lat_all(1, :)), & + metadata=[ & + attribute("units", "degrees_north"), & + attribute("comment", "y coordinate variable for GrADS compatibility") & + ] & + ) & + ] + case ("land") + coord_variables = [ & + cable_output_variable_t( & + field_name="local_lat", & + data_shape=[CABLE_OUTPUT_DIM_LAND_GLOBAL], & + parameter=.true., & + distributed=.false., & + aggregator=new_aggregator(latitude), & + metadata=[attribute("units", "degrees_north")] & + ), & + cable_output_variable_t( & + field_name="local_lon", & + data_shape=[CABLE_OUTPUT_DIM_LAND_GLOBAL], & + parameter=.true., & + distributed=.false., & + aggregator=new_aggregator(longitude), & + metadata=[attribute("units", "degrees_east")] & + ) & + ] + case default + call cable_abort("Unexpected grid type '" // grid_type // "'", __FILE__, __LINE__) + end select + + end function coordinate_variables + + logical function data_shape_eq(shape1, shape2) + type(cable_output_dim_t), dimension(:), intent(in) :: shape1, shape2 + data_shape_eq = size(shape1) == size(shape2) .and. all(shape1 == shape2) + end function + + function dim_size(dims) + type(cable_output_dim_t), intent(in) :: dims(:) + integer, allocatable :: dim_size(:) + integer :: i + + allocate(dim_size(size(dims))) + do i = 1, size(dims) + select case (dims(i)%value) + case (CABLE_OUTPUT_DIM_PATCH%value) + dim_size(i) = mp + case (CABLE_OUTPUT_DIM_SOIL%value) + dim_size(i) = ms + case (CABLE_OUTPUT_DIM_SNOW%value) + dim_size(i) = msn + case (CABLE_OUTPUT_DIM_RAD%value) + dim_size(i) = nrb + case (CABLE_OUTPUT_DIM_PLANTCARBON%value) + dim_size(i) = ncp + case (CABLE_OUTPUT_DIM_SOILCARBON%value) + dim_size(i) = ncs + case (CABLE_OUTPUT_DIM_LAND%value) + dim_size(i) = mland + case (CABLE_OUTPUT_DIM_LAND_GLOBAL%value) + dim_size(i) = mland_global + case (CABLE_OUTPUT_DIM_X%value) + dim_size(i) = xdimsize + case (CABLE_OUTPUT_DIM_Y%value) + dim_size(i) = ydimsize + case default + call cable_abort("Unexpected dimension type", __FILE__, __LINE__) + end select + end do + + end function + + integer function netcdf_var_type(output_variable) + type(cable_output_variable_t), intent(in) :: output_variable + + if (output_variable%var_type /= CABLE_OUTPUT_VAR_TYPE_UNDEFINED) then + netcdf_var_type = output_variable%var_type + return + end if + + select case (output_variable%aggregator%type()) + case ("int32") + netcdf_var_type = CABLE_NETCDF_INT + case ("real32") + netcdf_var_type = CABLE_NETCDF_FLOAT + case ("real64") + netcdf_var_type = CABLE_NETCDF_DOUBLE + case default + call cable_abort("Unable to infer variable type for variable " // trim(output_variable%field_name), __FILE__, __LINE__) + end select + + end function + + elemental function var_name(output_variable) + type(cable_output_variable_t), intent(in) :: output_variable + character(len=128) :: var_name + + if (len_trim(output_variable%netcdf_name) > 0) then + var_name = output_variable%netcdf_name + else + var_name = output_variable%field_name + end if + + end function var_name + + subroutine check_duplicate_variable_names(output_profile) + type(cable_output_profile_t), intent(in) :: output_profile + integer :: i + + do i = 1, size(output_profile%output_variables) + associate(output_var => output_profile%output_variables(i)) + if (count(var_name(output_var) == var_name(output_profile%output_variables(:))) > 1) then + call cable_abort("Duplicate variable name found: " // trim(var_name(output_var)), __FILE__, __LINE__) + end if + end associate + end do + + end subroutine + + subroutine check_sampling_frequency(output_profile) + type(cable_output_profile_t), intent(in) :: output_profile + + integer :: i, sampling_period_in_hours, accumulation_period_in_hours + + character(len=256) :: err_message + + do i = 1, size(output_profile%output_variables) + associate(output_var => output_profile%output_variables(i)) + err_message = ( & + "Invalid combination of sampling frequency '" // output_profile%sampling_frequency // & + "' with accumulation frequency '" // output_var%accumulation_frequency // "' for variable '" // & + output_var%field_name // "' in file '" // output_profile%file_name // "'" & + ) + select case (output_profile%sampling_frequency) + case ("all") + if (output_var%accumulation_frequency /= "all") call cable_abort(err_message, __FILE__, __LINE__) + case ("user") + read(output_profile%sampling_frequency(5:7), *) sampling_period_in_hours + if (output_var%accumulation_frequency == "user") then + read(output_var%accumulation_frequency(5:7), *) accumulation_period_in_hours + if (sampling_period_in_hours < accumulation_period_in_hours) then + call cable_abort(err_message, __FILE__, __LINE__) + end if + else if (output_var%accumulation_frequency /= "all") then + call cable_abort(err_message, __FILE__, __LINE__) + end if + case ("daily") + if (.not. any(output_var%accumulation_frequency == ["all ", "daily", "user "])) then + call cable_abort(err_message, __FILE__, __LINE__) + end if + case ("monthly") + if (.not. any(output_var%accumulation_frequency == ["all ", "daily ", "user ", "monthly"])) then + call cable_abort(err_message, __FILE__, __LINE__) + end if + case default + call cable_abort("Invalid sampling frequency '" // output_profile%sampling_frequency // & + "' for variable '" // output_var%field_name // "' in file '" // output_profile%file_name // "'", __FILE__, __LINE__) + end select + end associate + end do + + end subroutine check_sampling_frequency + + function infer_dim_names(output_profile, output_variable, time_axis) result(dim_names) + type(cable_output_profile_t), intent(in) :: output_profile + type(cable_output_variable_t), intent(in) :: output_variable + logical, intent(in), optional :: time_axis + + character(MAX_LEN_DIM), allocatable :: dim_names(:) + integer :: j + + allocate(dim_names(0)) + if (allocated(output_variable%data_shape)) then + do j = 1, size(output_variable%data_shape) + select case (output_variable%data_shape(j)%value) + case (CABLE_OUTPUT_DIM_PATCH%value) + select case (output_profile%grid_type) + case ("restart") + dim_names = [dim_names, "mp"] + case ("land") + if (output_variable%reduction_method == "none") then + dim_names = [dim_names, "land", "patch"] + else + dim_names = [dim_names, "land"] + end if + case ("mask") + if (output_variable%reduction_method == "none") then + dim_names = [dim_names, "x", "y", "patch"] + else + dim_names = [dim_names, "x", "y"] + end if + case default + call cable_abort("Unexpected grid type '" // output_profile%grid_type // & + "' for variable '" // output_variable%field_name // "'", __FILE__, __LINE__) + end select + case (CABLE_OUTPUT_DIM_LAND%value) + select case (output_profile%grid_type) + case ("restart") + dim_names = [dim_names, "mland"] + case ("land") + dim_names = [dim_names, "land"] + case ("mask") + dim_names = [dim_names, "x", "y"] + case default + call cable_abort("Unexpected grid type '" // output_profile%grid_type // & + "' for variable '" // output_variable%field_name // "'", __FILE__, __LINE__) + end select + case (CABLE_OUTPUT_DIM_LAND_GLOBAL%value) + if (output_profile%grid_type == "restart") then + dim_names = [dim_names, "mland"] + else + dim_names = [dim_names, "land"] + end if + case (CABLE_OUTPUT_DIM_SOIL%value) + dim_names = [dim_names, "soil"] + case (CABLE_OUTPUT_DIM_SNOW%value) + dim_names = [dim_names, "snow"] + case (CABLE_OUTPUT_DIM_RAD%value) + dim_names = [dim_names, "rad"] + case (CABLE_OUTPUT_DIM_PLANTCARBON%value) + if (output_profile%grid_type == "restart") then + dim_names = [dim_names, "plant_carbon_pools"] + else + dim_names = [dim_names, "plantcarbon"] + end if + case (CABLE_OUTPUT_DIM_SOILCARBON%value) + if (output_profile%grid_type == "restart") then + dim_names = [dim_names, "soil_carbon_pools"] + else + dim_names = [dim_names, "soilcarbon"] + end if + case (CABLE_OUTPUT_DIM_X%value) + dim_names = [dim_names, "x"] + case (CABLE_OUTPUT_DIM_Y%value) + dim_names = [dim_names, "y"] + case default + call cable_abort("Unexpected data shape for variable " // output_variable%field_name, __FILE__, __LINE__) + end select + end do + end if + + if (present(time_axis)) then; if (time_axis) then + dim_names = [dim_names, "time"] + end if; end if + + end function + + function infer_cell_methods(output_variable) result(cell_methods) + type(cable_output_variable_t), intent(in) :: output_variable + character(len=256) :: cell_methods + character(len=256) :: cell_methods_time, cell_methods_area + + if (.not. output_variable%parameter) then + select case (output_variable%aggregation_method) + case ("point") + cell_methods_time = "time: point" + case ("mean") + cell_methods_time = "time: mean" + case ("sum") + cell_methods_time = "time: sum" + case ("min") + cell_methods_time = "time: minimum" + case ("max") + cell_methods_time = "time: maximum" + case default + call cable_abort("Unexpected aggregation method '" // output_variable%aggregation_method // & + "' for variable '" // output_variable%field_name // "'", __FILE__, __LINE__) + end select + else + cell_methods_time = "" + end if + + select case (output_variable%reduction_method) + case ("none") + ! TODO(Sean): the cell_method for this case should be `area: point where + ! pft` where `pft` is a string-valued auxiliary coordinate variable + ! describing the labels for all patches: + cell_methods_area = "" + case ("first_patch_in_grid_cell") + ! TODO(Sean): the cell_method for this case should be `area: point where + ! ` where `` is the area type of the first patch in + ! the grid cell: + cell_methods_area = "" + case ("grid_cell_average") + cell_methods_area = "area: mean where land" + case default + call cable_abort("Unexpected reduction method '" // output_variable%reduction_method // & + "' for variable '" // output_variable%field_name // "'", __FILE__, __LINE__) + end select + + cell_methods = adjustl(trim(cell_methods_time) // " " // trim(cell_methods_area)) + + end function + + subroutine define_variables(output_profile, restart) + type(cable_output_profile_t), intent(inout) :: output_profile + logical, intent(in), optional :: restart + + logical :: restart_local + integer :: i, j + + character(MAX_LEN_DIM), allocatable :: required_dimensions(:), dim_names(:) + character(len=128) :: variable_name + + type(cable_output_variable_t), allocatable :: all_output_variables(:) + + restart_local = .false. + if (present(restart)) restart_local = restart + + all_output_variables = [ & + output_profile%coordinate_variables, & + output_profile%output_variables & + ] + + do i = 1, size(all_output_variables) + associate(output_var => all_output_variables(i)) + if (.not. allocated(output_var%data_shape)) cycle + dim_names = infer_dim_names( & + output_profile, & + output_var, & + time_axis=(.not. (restart_local .or. output_var%parameter)) & + ) + if (.not. allocated(required_dimensions)) then + required_dimensions = dim_names + else + required_dimensions = [ & + required_dimensions, & + pack(dim_names, [( & + all(dim_names(j) /= required_dimensions), & + j = 1, & + size(dim_names) & + )]) & + ] + end if + end associate + end do + + do i = 1, size(required_dimensions) + select case (required_dimensions(i)) + case ("mp") + call output_profile%output_file%def_dims(["mp"], [mp_global]) + case ("mland") + call output_profile%output_file%def_dims(["mland"], [mland_global]) + case ("land") + call output_profile%output_file%def_dims(["land"], [mland_global]) + case ("x") + call output_profile%output_file%def_dims(["x"], [xdimsize]) + case ("y") + call output_profile%output_file%def_dims(["y"], [ydimsize]) + case ("patch") + call output_profile%output_file%def_dims(["patch"], [max_vegpatches]) + case ("soil") + call output_profile%output_file%def_dims(["soil"], [ms]) + case ("snow") + call output_profile%output_file%def_dims(["snow"], [msn]) + case ("rad") + call output_profile%output_file%def_dims(["rad"], [nrb]) + case ("soil_carbon_pools") + call output_profile%output_file%def_dims(["soil_carbon_pools"], [ncs]) + case ("soilcarbon") + call output_profile%output_file%def_dims(["soilcarbon"], [ncs]) + case ("plant_carbon_pools") + call output_profile%output_file%def_dims(["plant_carbon_pools"], [ncp]) + case ("plantcarbon") + call output_profile%output_file%def_dims(["plantcarbon"], [ncp]) + case ("time") + ! time dimension defined separately below + case default + call cable_abort("Unexpected dimension name '" // required_dimensions(i) // "'", __FILE__, __LINE__) + end select + end do + + if (output_profile%grid_type == "restart") then + call output_profile%output_file%def_dims(["time"], [1]) + else + call output_profile%output_file%def_dims(["time"], [CABLE_NETCDF_UNLIMITED]) + end if + + call output_profile%output_file%def_var("time", ["time"], CABLE_NETCDF_DOUBLE) + call output_profile%output_file%put_att("time", "units", timeunits) + call output_profile%output_file%put_att("time", "coordinate", time_coord) + call output_profile%output_file%put_att("time", "calendar", calendar) + + if (output_profile%grid_type /= "restart") then + call output_profile%output_file%def_dims(["nv"], [2]) + call output_profile%output_file%def_var("time_bnds", ["nv ", "time"], CABLE_NETCDF_DOUBLE) + call output_profile%output_file%put_att("time", "bounds", "time_bnds") + end if + + do i = 1, size(output_profile%coordinate_variables) + associate(coord_var => output_profile%coordinate_variables(i)) + variable_name = var_name(coord_var) + call output_profile%output_file%def_var( & + var_name=variable_name, & + dim_names=infer_dim_names(output_profile, coord_var), & + type=netcdf_var_type(coord_var) & + ) + if (allocated(coord_var%metadata)) then + do j = 1, size(coord_var%metadata) + call output_profile%output_file%put_att(variable_name, coord_var%metadata(j)%name, coord_var%metadata(j)%value) + end do + end if + end associate + end do + + do i = 1, size(output_profile%output_variables) + associate(output_var => output_profile%output_variables(i)) + variable_name = var_name(output_var) + if (restart_local) variable_name = output_var%field_name + dim_names = infer_dim_names( & + output_profile, & + output_var, & + time_axis=(.not. (restart_local .or. output_var%parameter)) & + ) + call output_profile%output_file%def_var( & + var_name=variable_name, & + dim_names=dim_names, & + type=netcdf_var_type(output_var) & + ) + if (allocated(output_var%metadata)) then + do j = 1, size(output_var%metadata) + call output_profile%output_file%put_att(variable_name, output_var%metadata(j)%name, output_var%metadata(j)%value) + end do + end if + select case (netcdf_var_type(output_var)) + case (CABLE_NETCDF_INT) + call output_profile%output_file%put_att(variable_name, "_FillValue", FILL_VALUE_INT32) + call output_profile%output_file%put_att(variable_name, "missing_value", FILL_VALUE_INT32) + case (CABLE_NETCDF_FLOAT) + call output_profile%output_file%put_att(variable_name, "_FillValue", FILL_VALUE_REAL32) + call output_profile%output_file%put_att(variable_name, "missing_value", FILL_VALUE_REAL32) + case (CABLE_NETCDF_DOUBLE) + call output_profile%output_file%put_att(variable_name, "_FillValue", FILL_VALUE_REAL64) + call output_profile%output_file%put_att(variable_name, "missing_value", FILL_VALUE_REAL64) + end select + call output_profile%output_file%put_att(variable_name, "cell_methods", infer_cell_methods(output_var)) + end associate + end do + + end subroutine define_variables + + subroutine set_global_attributes(output_profile) + type(cable_output_profile_t), intent(inout) :: output_profile + + character(32) :: todaydate, nowtime + integer :: i + + if (allocated(output_profile%metadata)) then + do i = 1, size(output_profile%metadata) + call output_profile%output_file%put_att( & + att_name=output_profile%metadata(i)%name, & + att_value=output_profile%metadata(i)%value & + ) + end do + end if + + call date_and_time(todaydate, nowtime) + todaydate = todaydate(1:4) // "/" // todaydate(5:6) // "/" // todaydate(7:8) + nowtime = nowtime(1:2) // ":" // nowtime(3:4) // ":" // nowtime(5:6) + call output_profile%output_file%put_att("Production", trim(todaydate) // " at " // trim(nowtime)) + call output_profile%output_file%put_att("Source", "CABLE LSM output file") + call output_profile%output_file%put_att("CABLE_input_file", trim(filename%met)) + + select case (output_profile%sampling_frequency) + case ("user") + call output_profile%output_file%put_att("Output_averaging", TRIM(output_profile%sampling_frequency(5:7)) // "-hourly output") + case ("all") + call output_profile%output_file%put_att("Output_averaging", "all timesteps recorded") + case ("daily") + call output_profile%output_file%put_att("Output_averaging", "daily") + case ("monthly") + call output_profile%output_file%put_att("Output_averaging", "monthly") + case default + call cable_abort("Invalid sampling frequency '" // output_profile%sampling_frequency // "'", __FILE__, __LINE__) + end select + + end subroutine set_global_attributes + +end module