From 2ceba835d7b0c44354380a9613101a11dbfd9b19 Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Sun, 4 Jan 2026 07:30:51 +1300 Subject: [PATCH 01/11] Refactor: split types into FUSE_SRC/types and move shared module storage to FUSE_SRC/share --- build/FUSE_SRC/dshare/model_defn.f90 | 74 ------- build/FUSE_SRC/dshare/multiforce.f90 | 160 --------------- build/FUSE_SRC/dshare/multiroute.f90 | 13 -- build/FUSE_SRC/dshare/multistate.f90 | 53 ----- build/FUSE_SRC/prelim/bucketsize.f90 | 1 + build/FUSE_SRC/prelim/init_state.f90 | 1 + .../FUSE_SRC/{dshare => share}/globaldata.f90 | 0 build/FUSE_SRC/share/model_defn_data.f90 | 56 ++++++ .../{dshare => share}/model_defnames.f90 | 0 .../{dshare => share}/model_numerix.f90 | 0 build/FUSE_SRC/share/multi_flux_data.f90 | 22 +++ build/FUSE_SRC/share/multibands_data.f90 | 30 +++ .../FUSE_SRC/{dshare => share}/multiconst.f90 | 0 build/FUSE_SRC/share/multiforce_data.f90 | 185 ++++++++++++++++++ build/FUSE_SRC/share/multiparam_data.f90 | 37 ++++ build/FUSE_SRC/share/multiroute_data.f90 | 20 ++ build/FUSE_SRC/share/multistate_data.f90 | 44 +++++ build/FUSE_SRC/share/multistats_data.f90 | 16 ++ build/FUSE_SRC/types/model_defn_types.f90 | 48 +++++ .../multi_flux_types.f90} | 19 +- .../multibands_types.f90} | 29 +-- build/FUSE_SRC/types/multiforce_types.f90 | 52 +++++ .../multiparam_types.f90} | 44 +++-- build/FUSE_SRC/types/multiroute_types.f90 | 16 ++ build/FUSE_SRC/types/multistate_types.f90 | 37 ++++ .../multistats_types.f90} | 26 ++- build/Makefile | 56 ++++-- build/generated/fuseversion.inc | 6 +- 28 files changed, 673 insertions(+), 372 deletions(-) delete mode 100644 build/FUSE_SRC/dshare/model_defn.f90 delete mode 100644 build/FUSE_SRC/dshare/multiforce.f90 delete mode 100644 build/FUSE_SRC/dshare/multiroute.f90 delete mode 100644 build/FUSE_SRC/dshare/multistate.f90 rename build/FUSE_SRC/{dshare => share}/globaldata.f90 (100%) create mode 100644 build/FUSE_SRC/share/model_defn_data.f90 rename build/FUSE_SRC/{dshare => share}/model_defnames.f90 (100%) rename build/FUSE_SRC/{dshare => share}/model_numerix.f90 (100%) create mode 100644 build/FUSE_SRC/share/multi_flux_data.f90 create mode 100644 build/FUSE_SRC/share/multibands_data.f90 rename build/FUSE_SRC/{dshare => share}/multiconst.f90 (100%) create mode 100644 build/FUSE_SRC/share/multiforce_data.f90 create mode 100644 build/FUSE_SRC/share/multiparam_data.f90 create mode 100644 build/FUSE_SRC/share/multiroute_data.f90 create mode 100644 build/FUSE_SRC/share/multistate_data.f90 create mode 100644 build/FUSE_SRC/share/multistats_data.f90 create mode 100644 build/FUSE_SRC/types/model_defn_types.f90 rename build/FUSE_SRC/{dshare/multi_flux.f90 => types/multi_flux_types.f90} (82%) rename build/FUSE_SRC/{dshare/multibands.f90 => types/multibands_types.f90} (59%) create mode 100644 build/FUSE_SRC/types/multiforce_types.f90 rename build/FUSE_SRC/{dshare/multiparam.f90 => types/multiparam_types.f90} (90%) create mode 100644 build/FUSE_SRC/types/multiroute_types.f90 create mode 100644 build/FUSE_SRC/types/multistate_types.f90 rename build/FUSE_SRC/{dshare/multistats.f90 => types/multistats_types.f90} (85%) diff --git a/build/FUSE_SRC/dshare/model_defn.f90 b/build/FUSE_SRC/dshare/model_defn.f90 deleted file mode 100644 index 9a0c80a..0000000 --- a/build/FUSE_SRC/dshare/model_defn.f90 +++ /dev/null @@ -1,74 +0,0 @@ -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark -! Modified by Brian Henn to include snow model, 6/2013 -! --------------------------------------------------------------------------------------- -MODULE model_defn - USE nrtype - ! FUSE version - character(*),parameter::FUSE_version="FUSE 1.0" - logical,parameter::FUSE_enabled=.true. - ! list of combinations in each model component - INTEGER, PARAMETER :: NDEC = 9 ! number of model decisions - TYPE DESC - CHARACTER(LEN=16) :: MCOMPONENT ! description of model component - END TYPE DESC - TYPE(DESC), DIMENSION(2) :: LIST_RFERR ! rainfall error - TYPE(DESC), DIMENSION(3) :: LIST_ARCH1 ! upper-layer architecture - TYPE(DESC), DIMENSION(4) :: LIST_ARCH2 ! lower-layer architecture - TYPE(DESC), DIMENSION(3) :: LIST_QSURF ! surface runoff - TYPE(DESC), DIMENSION(3) :: LIST_QPERC ! percolation - TYPE(DESC), DIMENSION(2) :: LIST_ESOIL ! evaporation - TYPE(DESC), DIMENSION(2) :: LIST_QINTF ! interflow - TYPE(DESC), DIMENSION(2) :: LIST_Q_TDH ! time delay in runoff - TYPE(DESC), DIMENSION(2) :: LIST_SNOWM ! snow model - ! structure that holds (x) unique combinations - TYPE UMODEL - INTEGER(I4B) :: MODIX ! model index - CHARACTER(LEN=256) :: MNAME ! model name -! CHARACTER(LEN=16) :: RFERR ! rainfall error - INTEGER(I4B) :: iRFERR -! CHARACTER(LEN=16) :: ARCH1 ! upper-layer architecture - INTEGER(I4B) :: iARCH1 -! CHARACTER(LEN=16) :: ARCH2 ! lower-layer architecture - INTEGER(I4B) :: iARCH2 -! CHARACTER(LEN=16) :: QSURF ! surface runoff - INTEGER(I4B) :: iQSURF -! CHARACTER(LEN=16) :: QPERC ! percolation - INTEGER(I4B) :: iQPERC -! CHARACTER(LEN=16) :: ESOIL ! evaporation - INTEGER(I4B) :: iESOIL -! CHARACTER(LEN=16) :: QINTF ! interflow - INTEGER(I4B) :: iQINTF -! CHARACTER(LEN=16) :: Q_TDH ! time delay in runoff - INTEGER(I4B) :: iQ_TDH - INTEGER(I4B) :: iSNOWM ! snow - END TYPE UMODEL - ! structure to hold model state names - TYPE SNAMES -! CHARACTER(LEN=8) :: SNAME ! state name - INTEGER(I4B) :: iSNAME ! integer value of state name - END TYPE SNAMES - ! structure to hold model flux names - TYPE FNAMES - CHARACTER(LEN=16) :: FNAME ! state name - END TYPE FNAMES -! max steps in routing function - INTEGER(I4B),PARAMETER::NTDH_MAX=500 -! model definitions - CHARACTER(LEN=256) :: FNAME_NETCDF_RUNS ! NETCDF output filename for model runs - CHARACTER(LEN=256) :: FNAME_NETCDF_PARA ! NETCDF output filename for model parameters - CHARACTER(LEN=256) :: FNAME_NETCDF_PARA_SCE ! NETCDF output filename for model parameters produced by SCE - CHARACTER(LEN=256) :: FNAME_NETCDF_PARA_PRE ! NETCDF filename for pre-defined model parameters set - CHARACTER(LEN=256) :: FNAME_PREFIX ! prefix for desired output files - CHARACTER(LEN=256) :: FNAME_TEMPRY ! prefix for temporary output files - CHARACTER(LEN=256) :: FNAME_ASCII ! ASCII output filename - TYPE(UMODEL),DIMENSION(5000) :: AMODL ! (model definition -- all) - TYPE(UMODEL) :: SMODL ! (model definition -- single model) - TYPE(SNAMES),DIMENSION(7) :: CSTATE ! (list of model states for SMODL) - INTEGER(I4B) :: NSTATE=0 ! number of model states - TYPE(FNAMES),DIMENSION(50) :: C_FLUX ! (list of model fluxes for SMODL) - INTEGER(I4B) :: N_FLUX=0 ! number of model fluxes - ! -------------------------------------------------------------------------------------- -END MODULE model_defn diff --git a/build/FUSE_SRC/dshare/multiforce.f90 b/build/FUSE_SRC/dshare/multiforce.f90 deleted file mode 100644 index 90d6ec6..0000000 --- a/build/FUSE_SRC/dshare/multiforce.f90 +++ /dev/null @@ -1,160 +0,0 @@ -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark -! Modified by Brian Henn to include snow model, 6/2013 -! Modified by Nans Addor to enable distributed modeling, 9/2016 -! Modified by Cyril Thébault to allow different metrics as objective function, 2024 -! --------------------------------------------------------------------------------------- -MODULE multiforce - USE nrtype - SAVE - ! -------------------------------------------------------------------------------------- - ! the time data structure (will have no spatial dimension) - TYPE TDATA - INTEGER(I4B) :: IY ! year - INTEGER(I4B) :: IM ! month - INTEGER(I4B) :: ID ! day - INTEGER(I4B) :: IH ! hour - INTEGER(I4B) :: IMIN ! minute - REAL(SP) :: DSEC ! second - REAL(SP) :: DTIME ! time in seconds since year dot - ENDTYPE TDATA - ! the response structure (will not have a spatial dimension) - TYPE VDATA - REAL(SP) :: OBSQ ! observed runoff (mm day-1) - END TYPE VDATA - ! ancillary forcing variables used to compute ET (will have a spatial dimension) - TYPE ADATA - REAL(SP) :: AIRTEMP ! air temperature (K) - REAL(SP) :: SPECHUM ! specific humidity (g/g) - REAL(SP) :: AIRPRES ! air pressure (Pa) - REAL(SP) :: SWDOWN ! downward sw radiation (W m-2) - REAL(SP) :: NETRAD ! net radiation (W m-2) - END TYPE ADATA - ! the forcing data structure (will have a spatial dimension) - TYPE FDATA - REAL(SP) :: PPT ! water input: rain + melt (mm day-1) - REAL(SP) :: TEMP ! temperature for snow model (deg.C) - REAL(SP) :: PET ! energy input: potential ET (mm day-1) - ENDTYPE FDATA - ! -------------------------------------------------------------------------------------- - ! general - INTEGER(I4B),PARAMETER :: STRLEN=256 ! length of the character string - ! time data structures - TYPE(tData) :: timDat ! model time structure - ! response data structures - TYPE(vData) :: valDat ! validation structure - TYPE(vData), DIMENSION(:,:,:), POINTER :: aValid ! all model validation data - ! forcing data structures - TYPE(FDATA), DIMENSION(:), POINTER :: CFORCE ! COPY of model forcing data - TYPE(FDATA), DIMENSION(:), POINTER :: AFORCE ! all model forcing data - TYPE(FDATA) :: MFORCE ! model forcing data for a single time step - TYPE(fData), DIMENSION(:,:), POINTER :: gForce ! model forcing data for a 2-d grid - TYPE(aData), DIMENSION(:,:), POINTER :: ancilF ! ancillary forcing data for the 2-d grid - TYPE(fData), DIMENSION(:,:,:), POINTER :: gForce_3d ! model forcing data for a 3-d grid (time as 3rd dimension) - TYPE(aData), DIMENSION(:,:,:), POINTER :: ancilF_3d ! ancillary forcing data for the 3-d grid - - ! timing information - note that numtim_in >= numtim_sim >= numtim_sub - CHARACTER(len=20) :: date_start_input ! date start input time series - CHARACTER(len=20) :: date_end_input ! date end input time series - - INTEGER(i4b) :: numtim_in=-1 ! number of time steps of input (atmospheric forcing) - INTEGER(i4b) :: numtim_sim=-1 ! number of time steps of FUSE simulations (including spin-up) - INTEGER(i4b) :: numtim_sub=-1 ! number of time steps of subperiod (will be kept in memory) - INTEGER(i4b) :: numtim_sub_cur=-1 ! number of time steps of current subperiod (allows for the last subperiod to be shorter) - INTEGER(i4b) :: itim_in=-1 ! indice within numtim_in - INTEGER(i4b) :: itim_sim=-1 ! indice within numtim_sim - INTEGER(i4b) :: itim_sub=-1 ! indice within numtim_sub - - INTEGER(i4b) :: sim_beg=-1 ! index for the start of the simulation in fuse_metric - INTEGER(i4b) :: sim_end=-1 ! index for the end of the simulation in fuse_metric - INTEGER(i4b) :: eval_beg=-1 ! index for the start of evaluation period - INTEGER(i4b) :: eval_end=-1 ! index for the end of the inference period - - INTEGER(i4b) :: istart=-1 ! index for start of inference period (in reduced array) - REAL(sp) :: jdayRef ! reference time (days) - REAL(sp) :: deltim=-1._dp ! length of time step (days) - - LOGICAL(LGT) :: SUB_PERIODS_FLAG ! .true. if subperiods are used to run FUSE - - ! dimension information - INTEGER(i4b) :: startSpat2=-1 ! number of points in 1st spatial dimension - INTEGER(i4b) :: nSpat1=-1 ! number of points in 1st spatial dimension - INTEGER(i4b) :: nSpat2=-1 ! number of points in 2nd spatial dimension - LOGICAL(LGT) :: GRID_FLAG ! spatial flag .true. if grid - REAL(sp) :: xlon ! longitude (degrees) for PET computation - REAL(sp) :: ylat ! latitude (degrees) for PET computation - REAL(sp),dimension(:),allocatable :: latitude ! latitude (degrees) - REAL(sp),dimension(:),allocatable :: longitude ! longitude (degrees) - CHARACTER(len=strLen),dimension(:),allocatable :: name_psets ! name of parameter sets - INTEGER(I4B) :: NUMPSET ! number of parameter sets - REAL(sp),dimension(:),allocatable :: time_steps ! time steps (days) - REAL(sp),dimension(:),allocatable :: julian_day_input ! time steps (julian days) - CHARACTER(len=strLen) :: latUnits ! units string for latitude - CHARACTER(len=strLen) :: lonUnits ! units string for longitude - CHARACTER(len=strLen) :: timeUnits ! units string for time - - ! filename - CHARACTER(len=StrLen) :: forcefile='undefined' ! name of forcing file - - ! name of time variables - CHARACTER(len=StrLen) :: vname_iy ='undefined' ! name of variable for year - CHARACTER(len=StrLen) :: vname_im ='undefined' ! name of variable for month - CHARACTER(len=StrLen) :: vname_id ='undefined' ! name of variable for day - CHARACTER(len=StrLen) :: vname_ih ='undefined' ! name of variable for hour - CHARACTER(len=StrLen) :: vname_imin ='undefined' ! name of variable for minute - CHARACTER(len=StrLen) :: vname_dsec ='undefined' ! name of variable for second - CHARACTER(len=StrLen) :: vname_dtime='undefined' ! name of variable for time - - ! number of forcing variables - INTEGER(i4b), PARAMETER :: nForce=7 ! see lines below - INTEGER(i4b) :: nInput=3 ! number of variable to retrieve from input file - - ! forcing variable names - CHARACTER(len=StrLen) :: vname_aprecip='undefined' ! variable name: precipitation - CHARACTER(len=StrLen) :: vname_potevap='undefined' ! variable name: potential ET - CHARACTER(len=StrLen) :: vname_airtemp='undefined' ! variable name: temperature - CHARACTER(len=StrLen) :: vname_q ='undefined' ! variable name: observed runoff - CHARACTER(len=StrLen) :: vname_spechum='undefined' ! variable name: specific humidity - CHARACTER(len=StrLen) :: vname_airpres='undefined' ! variable name: surface pressure - CHARACTER(len=StrLen) :: vname_swdown ='undefined' ! variable name: downward shortwave radiation - - ! indices for forcing variables - INTEGER(i4b),PARAMETER :: ilook_aprecip=1 ! named element in lCheck - INTEGER(i4b),PARAMETER :: ilook_potevap=2 ! named element in lCheck - INTEGER(i4b),PARAMETER :: ilook_airtemp=3 ! named element in lCheck - INTEGER(i4b),PARAMETER :: ilook_q=4 ! named element in lCheck - INTEGER(i4b),PARAMETER :: ilook_spechum=5 ! named element in lCheck - INTEGER(i4b),PARAMETER :: ilook_airpres=6 ! named element in lCheck - INTEGER(i4b),PARAMETER :: ilook_swdown =7 ! named element in lCheck - - ! NetCDF - INTEGER(i4b) :: ncid_forc=-1 ! NetCDF forcing file ID - INTEGER(i4b),DIMENSION(nForce) :: ncid_var ! NetCDF forcing variable ID - - ! indices for time data (only used in ASCII files) - INTEGER(i4b) :: ivarid_iy=-1 ! variable ID for year - INTEGER(i4b) :: ivarid_im=-1 ! variable ID for month - INTEGER(i4b) :: ivarid_id=-1 ! variable ID for day - INTEGER(i4b) :: ivarid_ih=-1 ! variable ID for hour - INTEGER(i4b) :: ivarid_imin=-1 ! variable ID for minute - INTEGER(i4b) :: ivarid_dsec=-1 ! variable ID for second - - ! indices for variables - INTEGER(i4b) :: ivarid_ppt=-1 ! variable ID for precipitation - INTEGER(i4b) :: ivarid_temp=-1 ! variable ID for temperature - INTEGER(i4b) :: ivarid_pet=-1 ! variable ID for potential ET - INTEGER(i4b) :: ivarid_q=-1 ! variable ID for runoff - - ! multipliers for variables to convert fluxes to mm/day - REAL(sp) :: amult_ppt=-1._dp ! convert precipitation to mm/day - REAL(sp) :: amult_pet=-1._dp ! convert potential ET to mm/day - REAL(sp) :: amult_q=-1._dp ! convert runoff to mm/day - - ! missing values - INTEGER(I4B),PARAMETER :: NA_VALUE=-9999 ! integer designating missing values - TODO: retrieve from NetCDF file - REAL(SP),PARAMETER :: NA_VALUE_SP=-9999 ! integer designating missing values - TODO: retrieve from NetCDF file - - ! -------------------------------------------------------------------------------------- -END MODULE multiforce diff --git a/build/FUSE_SRC/dshare/multiroute.f90 b/build/FUSE_SRC/dshare/multiroute.f90 deleted file mode 100644 index f9d046b..0000000 --- a/build/FUSE_SRC/dshare/multiroute.f90 +++ /dev/null @@ -1,13 +0,0 @@ -MODULE multiroute - USE nrtype - USE model_defn,ONLY:NTDH_MAX - TYPE RUNOFF - REAL(SP) :: Q_INSTNT ! instantaneous runoff - REAL(SP) :: Q_ROUTED ! routed runoff - REAL(SP) :: Q_ACCURATE ! "accurate" runoff estimate (mm day-1) - END TYPE RUNOFF - REAL(SP), DIMENSION(NTDH_MAX) :: FUTURE ! runoff placed in future time steps - TYPE(RUNOFF), DIMENSION(:), POINTER :: AROUTE ! runoff for all time steps - TYPE(RUNOFF),dimension(:,:,:), allocatable :: AROUTE_3d ! runoff for all time steps on a grid - TYPE(RUNOFF) :: MROUTE ! runoff for one time step -END MODULE multiroute diff --git a/build/FUSE_SRC/dshare/multistate.f90 b/build/FUSE_SRC/dshare/multistate.f90 deleted file mode 100644 index 51c563c..0000000 --- a/build/FUSE_SRC/dshare/multistate.f90 +++ /dev/null @@ -1,53 +0,0 @@ -MODULE multistate - USE nrtype - ! -------------------------------------------------------------------------------------- - ! model state structure - ! -------------------------------------------------------------------------------------- - TYPE STATEV - ! snow layer - REAL(SP) :: SWE_TOT ! total storage as snow (mm) - ! upper layer - REAL(SP) :: WATR_1 ! total storage in layer1 (mm) - REAL(SP) :: TENS_1 ! tension storage in layer1 (mm) - REAL(SP) :: FREE_1 ! free storage in layer 1 (mm) - REAL(SP) :: TENS_1A ! storage in the recharge zone (mm) - REAL(SP) :: TENS_1B ! storage in the lower zone (mm) - ! lower layer - REAL(SP) :: WATR_2 ! total storage in layer2 (mm) - REAL(SP) :: TENS_2 ! tension storage in layer2 (mm) - REAL(SP) :: FREE_2 ! free storage in layer2 (mm) - REAL(SP) :: FREE_2A ! storage in the primary resvr (mm) - REAL(SP) :: FREE_2B ! storage in the secondary resvr (mm) - END TYPE STATEV - ! -------------------------------------------------------------------------------------- - ! model time structure - ! -------------------------------------------------------------------------------------- - TYPE M_TIME - REAL(SP) :: STEP ! (time interval to advance model states) - END TYPE M_TIME - ! -------------------------------------------------------------------------------------- - ! variable definitions - ! -------------------------------------------------------------------------------------- - type(statev),dimension(:,:),pointer :: gState ! (grid of model states) - type(statev),dimension(:,:,:),pointer :: gState_3d ! (grid of model states with a time dimension) - TYPE(STATEV) :: ASTATE ! (model states at the start of full timestep) - TYPE(STATEV) :: FSTATE ! (model states at start of sub-timestep) - TYPE(STATEV) :: MSTATE ! (model states at start/middle of sub-timestep) - TYPE(STATEV) :: TSTATE ! (temporary copy of model states) - TYPE(STATEV) :: BSTATE ! (temporary copy of model states) - TYPE(STATEV) :: ESTATE ! (temporary copy of model states) - TYPE(STATEV) :: DSTATE ! (default model states) - TYPE(STATEV) :: DYDT_0 ! (derivative of model states at start of sub-step) - TYPE(STATEV) :: DYDT_1 ! (derivative of model states at end of sub-step) - TYPE(STATEV) :: DY_DT ! (derivative of model states) - TYPE(STATEV) :: DYDT_OLD ! (derivative of model states for final solution) - TYPE(M_TIME) :: HSTATE ! (time interval to advance model states) - ! -------------------------------------------------------------------------------------- - - ! NetCDF - integer(i4b) :: ncid_out=-1 ! NetCDF output file ID - - ! initial store fraction (initialization) - real(sp),parameter::fracState0=0.25_sp - -END MODULE multistate diff --git a/build/FUSE_SRC/prelim/bucketsize.f90 b/build/FUSE_SRC/prelim/bucketsize.f90 index cfcb526..0afbd0e 100644 --- a/build/FUSE_SRC/prelim/bucketsize.f90 +++ b/build/FUSE_SRC/prelim/bucketsize.f90 @@ -12,6 +12,7 @@ SUBROUTINE BUCKETSIZE() ! ----------------- ! MODULE multiparam -- bucket sizes stored in MODULE multiparam ! --------------------------------------------------------------------------------------- +USE nrtype USE multiparam ! model parameters IMPLICIT NONE ! --------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/prelim/init_state.f90 b/build/FUSE_SRC/prelim/init_state.f90 index ea88d82..c5a4f41 100644 --- a/build/FUSE_SRC/prelim/init_state.f90 +++ b/build/FUSE_SRC/prelim/init_state.f90 @@ -13,6 +13,7 @@ SUBROUTINE INIT_STATE(FRAC) ! ----------------- ! Model states in MODULE multistate ! --------------------------------------------------------------------------------------- +USE nrtype USE multiparam ! model parameters USE multistate ! model states USE multibands ! model snow bands diff --git a/build/FUSE_SRC/dshare/globaldata.f90 b/build/FUSE_SRC/share/globaldata.f90 similarity index 100% rename from build/FUSE_SRC/dshare/globaldata.f90 rename to build/FUSE_SRC/share/globaldata.f90 diff --git a/build/FUSE_SRC/share/model_defn_data.f90 b/build/FUSE_SRC/share/model_defn_data.f90 new file mode 100644 index 0000000..3b85981 --- /dev/null +++ b/build/FUSE_SRC/share/model_defn_data.f90 @@ -0,0 +1,56 @@ +MODULE model_defn + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Martyn Clark to separate type definitions from data storage, 01/2026 + ! --------------------------------------------------------------------------------------- + + USE nrtype + USE model_defn_types, only: DESC, UMODEL, SNAMES, FNAMES + + USE globaldata, only: FUSE_VERSION + + implicit none + private + + public :: NDEC, NTDH_MAX, NSTATE, N_FLUX + public :: LIST_RFERR, LIST_ARCH1, LIST_ARCH2, LIST_QSURF, LIST_QPERC, LIST_ESOIL, LIST_QINTF, LIST_Q_TDH, LIST_SNOWM + public :: FNAME_PREFIX, FNAME_TEMPRY, FNAME_ASCII + public :: FNAME_NETCDF_RUNS, FNAME_NETCDF_PARA, FNAME_NETCDF_PARA_SCE, FNAME_NETCDF_PARA_PRE + public :: AMODL, SMODL, CSTATE, C_FLUX + + ! list of combinations in each model component + INTEGER, PARAMETER :: NDEC = 9 ! number of model decisions + TYPE(DESC), DIMENSION(2) :: LIST_RFERR ! rainfall error + TYPE(DESC), DIMENSION(3) :: LIST_ARCH1 ! upper-layer architecture + TYPE(DESC), DIMENSION(4) :: LIST_ARCH2 ! lower-layer architecture + TYPE(DESC), DIMENSION(3) :: LIST_QSURF ! surface runoff + TYPE(DESC), DIMENSION(3) :: LIST_QPERC ! percolation + TYPE(DESC), DIMENSION(2) :: LIST_ESOIL ! evaporation + TYPE(DESC), DIMENSION(2) :: LIST_QINTF ! interflow + TYPE(DESC), DIMENSION(2) :: LIST_Q_TDH ! time delay in runoff + TYPE(DESC), DIMENSION(2) :: LIST_SNOWM ! snow model + + ! max steps in routing function + INTEGER(I4B),PARAMETER::NTDH_MAX=500 + + ! model definitions + CHARACTER(LEN=256) :: FNAME_NETCDF_RUNS ! NETCDF output filename for model runs + CHARACTER(LEN=256) :: FNAME_NETCDF_PARA ! NETCDF output filename for model parameters + CHARACTER(LEN=256) :: FNAME_NETCDF_PARA_SCE ! NETCDF output filename for model parameters produced by SCE + CHARACTER(LEN=256) :: FNAME_NETCDF_PARA_PRE ! NETCDF filename for pre-defined model parameters set + CHARACTER(LEN=256) :: FNAME_PREFIX ! prefix for desired output files + CHARACTER(LEN=256) :: FNAME_TEMPRY ! prefix for temporary output files + CHARACTER(LEN=256) :: FNAME_ASCII ! ASCII output filename + TYPE(UMODEL),DIMENSION(5000) :: AMODL ! (model definition -- all) + TYPE(UMODEL) :: SMODL ! (model definition -- single model) + TYPE(SNAMES),DIMENSION(7) :: CSTATE ! (list of model states for SMODL) + TYPE(FNAMES),DIMENSION(50) :: C_FLUX ! (list of model fluxes for SMODL) + INTEGER(I4B) :: NSTATE=0 ! number of model states + INTEGER(I4B) :: N_FLUX=0 ! number of model fluxes + ! -------------------------------------------------------------------------------------- + +END MODULE model_defn diff --git a/build/FUSE_SRC/dshare/model_defnames.f90 b/build/FUSE_SRC/share/model_defnames.f90 similarity index 100% rename from build/FUSE_SRC/dshare/model_defnames.f90 rename to build/FUSE_SRC/share/model_defnames.f90 diff --git a/build/FUSE_SRC/dshare/model_numerix.f90 b/build/FUSE_SRC/share/model_numerix.f90 similarity index 100% rename from build/FUSE_SRC/dshare/model_numerix.f90 rename to build/FUSE_SRC/share/model_numerix.f90 diff --git a/build/FUSE_SRC/share/multi_flux_data.f90 b/build/FUSE_SRC/share/multi_flux_data.f90 new file mode 100644 index 0000000..9673397 --- /dev/null +++ b/build/FUSE_SRC/share/multi_flux_data.f90 @@ -0,0 +1,22 @@ +MODULE multi_flux + + USE nrtype + + USE multi_flux_types, only: FLUXES + + implicit none + private + + public :: M_FLUX, FLUX_0, FLUX_1, FDFLUX, W_FLUX, W_FLUX_3d + public :: CURRENT_DT + + TYPE(FLUXES) :: M_FLUX ! model fluxes + TYPE(FLUXES) :: FLUX_0 ! model fluxes at start of step + TYPE(FLUXES) :: FLUX_1 ! model fluxes at end of step + TYPE(FLUXES), DIMENSION(:), POINTER :: FDFLUX=>NULL() ! finite difference fluxes + TYPE(FLUXES) :: W_FLUX ! weighted sum of model fluxes over a time step + TYPE(FLUXES), dimension(:,:,:), allocatable :: W_FLUX_3d ! weighted sum of model fluxes over a time step for several time steps + + REAL(SP) :: CURRENT_DT ! current time step (days) + +END MODULE multi_flux diff --git a/build/FUSE_SRC/share/multibands_data.f90 b/build/FUSE_SRC/share/multibands_data.f90 new file mode 100644 index 0000000..7fa4406 --- /dev/null +++ b/build/FUSE_SRC/share/multibands_data.f90 @@ -0,0 +1,30 @@ +MODULE multibands + + ! Created by Brian Henn to allow multi-band snow modeling, 6/2013 + ! Based on module MULTIFORCE by Martyn Clark + + ! Modified by Martyn Clark to separate type definitions from data storage, 01/2026 + + USE nrtype + + USE multibands_types, only: BANDS, BANDS_INFO, BANDS_VAR + + implicit none + private + + public :: N_BANDS + public :: MBANDS, MBANDS_INFO_3d, MBANDS_VAR_4d + public :: Z_FORCING, Z_FORCING_grid, elev_mask + + ! -------------------------------------------------------------------------------------- + TYPE(BANDS),DIMENSION(:),ALLOCATABLE :: MBANDS ! basin band information + type(BANDS_INFO),dimension(:,:,:),ALLOCATABLE :: MBANDS_INFO_3d ! basin band information in space + type(BANDS_VAR),dimension(:,:,:,:),ALLOCATABLE :: MBANDS_VAR_4d ! basin band information in space plus time + + INTEGER(I4B) :: N_BANDS=0 ! number of bands, initialize to zero + REAL(SP) :: Z_FORCING ! elevation of forcing data (m) + REAL(SP),DIMENSION(:,:),ALLOCATABLE :: Z_FORCING_grid ! elevation of forcing data (m) for the 2D domain + LOGICAL(LGT),DIMENSION(:,:),ALLOCATABLE :: elev_mask ! mask domain - TRUE means the cell must be masked, i.e. not run + ! -------------------------------------------------------------------------------------- + +END MODULE multibands diff --git a/build/FUSE_SRC/dshare/multiconst.f90 b/build/FUSE_SRC/share/multiconst.f90 similarity index 100% rename from build/FUSE_SRC/dshare/multiconst.f90 rename to build/FUSE_SRC/share/multiconst.f90 diff --git a/build/FUSE_SRC/share/multiforce_data.f90 b/build/FUSE_SRC/share/multiforce_data.f90 new file mode 100644 index 0000000..cd077b2 --- /dev/null +++ b/build/FUSE_SRC/share/multiforce_data.f90 @@ -0,0 +1,185 @@ +MODULE multiforce + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Nans Addor to enable distributed modeling, 9/2016 + ! Modified by Cyril Thébault to allow different metrics as objective function, 2024 + ! Modified by Martyn Clark to separate type definitions from data storage, 01/2026 + ! --------------------------------------------------------------------------------------- + + USE nrtype + + USE multiforce_types, only: TDATA, VDATA, ADATA, FDATA + + implicit none + private + + public :: forcefile + + public :: ncid_forc, ncid_var + + public :: nForce, nInput + + public :: timDat, valDat, aValid + public :: AFORCE, CFORCE, MFORCE + public :: ancilF, ancilF_3d + public :: gForce, gForce_3d + + public :: date_start_input, date_end_input + public :: numtim_in, numtim_sim, numtim_sub, numtim_sub_cur + public :: itim_in, itim_sim, itim_sub + public :: sim_beg, sim_end, eval_beg, eval_end + public :: istart, jdayRef + public :: deltim + + public :: SUB_PERIODS_FLAG, GRID_FLAG + + public :: startSpat2, nSpat1, nSpat2 + public :: xlon, ylat, latitude, longitude + public :: latUnits, lonUnits, timeUnits + + public :: time_steps, julian_day_input + + public :: NUMPSET, name_psets + + public :: vname_iy, vname_im, vname_id, vname_ih, vname_imin, vname_dsec, vname_dtime + + public :: vname_aprecip, vname_potevap, vname_airtemp, vname_q, vname_spechum, vname_airpres, vname_swdown + public :: ilook_aprecip, ilook_potevap, ilook_airtemp, ilook_q, ilook_spechum, ilook_airpres, ilook_swdown + + public :: ivarid_iy, ivarid_im, ivarid_id, ivarid_ih, ivarid_imin, ivarid_dsec + public :: ivarid_ppt, ivarid_temp, ivarid_pet, ivarid_q + + public :: amult_ppt, amult_pet, amult_q + + public :: NA_VALUE, NA_VALUE_SP + + SAVE + + ! general + INTEGER(I4B),PARAMETER :: STRLEN=256 ! length of the character string + + ! time data structures + TYPE(tData) :: timDat ! model time structure + + ! response data structures + TYPE(vData) :: valDat ! validation structure + TYPE(vData), DIMENSION(:,:,:), POINTER :: aValid ! all model validation data + + ! forcing data structures + TYPE(FDATA), DIMENSION(:), POINTER :: AFORCE ! all model forcing data + TYPE(FDATA), DIMENSION(:), POINTER :: CFORCE ! COPY of model forcing data + TYPE(FDATA) :: MFORCE ! model forcing data for a single time step + TYPE(aData), DIMENSION(:,:), POINTER :: ancilF ! ancillary forcing data for the 2-d grid + TYPE(fData), DIMENSION(:,:), POINTER :: gForce ! model forcing data for a 2-d grid + TYPE(fData), DIMENSION(:,:,:), POINTER :: gForce_3d ! model forcing data for a 3-d grid (time as 3rd dimension) + TYPE(aData), DIMENSION(:,:,:), POINTER :: ancilF_3d ! ancillary forcing data for the 3-d grid + + ! NetCDF + + CHARACTER(len=StrLen) :: forcefile = 'undefined' ! name of forcing file + + INTEGER(i4b), PARAMETER :: nForce = 7 ! number of forcing variables + INTEGER(i4b) :: nInput = 3 ! number of variable to retrieve from input file + + INTEGER(i4b) :: ncid_forc = -1 ! NetCDF forcing file ID + INTEGER(i4b), DIMENSION(nForce) :: ncid_var ! NetCDF forcing variable ID + + ! timing information - note that numtim_in >= numtim_sim >= numtim_sub + + CHARACTER(len=20) :: date_start_input ! date start input time series + CHARACTER(len=20) :: date_end_input ! date end input time series + + INTEGER(i4b) :: numtim_in = -1 ! number of time steps of input (atmospheric forcing) + INTEGER(i4b) :: numtim_sim = -1 ! number of time steps of FUSE simulations (including spin-up) + INTEGER(i4b) :: numtim_sub = -1 ! number of time steps of subperiod (will be kept in memory) + INTEGER(i4b) :: numtim_sub_cur = -1 ! number of time steps of current subperiod (allows for the last subperiod to be shorter) + INTEGER(i4b) :: itim_in = -1 ! indice within numtim_in + INTEGER(i4b) :: itim_sim = -1 ! indice within numtim_sim + INTEGER(i4b) :: itim_sub = -1 ! indice within numtim_sub + + INTEGER(i4b) :: sim_beg = -1 ! index for the start of the simulation in fuse_metric + INTEGER(i4b) :: sim_end = -1 ! index for the end of the simulation in fuse_metric + INTEGER(i4b) :: eval_beg = -1 ! index for the start of evaluation period + INTEGER(i4b) :: eval_end = -1 ! index for the end of the inference period + + INTEGER(i4b) :: istart = -1 ! index for start of inference period (in reduced array) + REAL(sp) :: jdayRef ! reference time (days) + REAL(sp) :: deltim = -1._dp ! length of time step (days) + + LOGICAL(LGT) :: SUB_PERIODS_FLAG ! .true. if subperiods are used to run FUSE + LOGICAL(LGT) :: GRID_FLAG ! spatial flag .true. if grid + + ! dimension information + + INTEGER(i4b) :: startSpat2 = -1 ! number of points in 1st spatial dimension + INTEGER(i4b) :: nSpat1 = -1 ! number of points in 1st spatial dimension + INTEGER(i4b) :: nSpat2 = -1 ! number of points in 2nd spatial dimension + REAL(sp) :: xlon ! longitude (degrees) for PET computation + REAL(sp) :: ylat ! latitude (degrees) for PET computation + REAL(sp),dimension(:),allocatable :: latitude ! latitude (degrees) + REAL(sp),dimension(:),allocatable :: longitude ! longitude (degrees) + CHARACTER(len=strLen) :: latUnits ! units string for latitude + CHARACTER(len=strLen) :: lonUnits ! units string for longitude + CHARACTER(len=strLen) :: timeUnits ! units string for time + + REAL(sp),dimension(:),allocatable :: time_steps ! time steps (days) + REAL(sp),dimension(:),allocatable :: julian_day_input ! time steps (julian days) + + INTEGER(I4B) :: NUMPSET ! number of parameter sets + CHARACTER(len=strLen),dimension(:),allocatable :: name_psets ! name of parameter sets + + ! name of time variables + CHARACTER(len=StrLen) :: vname_iy = 'undefined' ! name of variable for year + CHARACTER(len=StrLen) :: vname_im = 'undefined' ! name of variable for month + CHARACTER(len=StrLen) :: vname_id = 'undefined' ! name of variable for day + CHARACTER(len=StrLen) :: vname_ih = 'undefined' ! name of variable for hour + CHARACTER(len=StrLen) :: vname_imin = 'undefined' ! name of variable for minute + CHARACTER(len=StrLen) :: vname_dsec = 'undefined' ! name of variable for second + CHARACTER(len=StrLen) :: vname_dtime = 'undefined' ! name of variable for time + + ! forcing variable names + CHARACTER(len=StrLen) :: vname_aprecip = 'undefined' ! variable name: precipitation + CHARACTER(len=StrLen) :: vname_potevap = 'undefined' ! variable name: potential ET + CHARACTER(len=StrLen) :: vname_airtemp = 'undefined' ! variable name: temperature + CHARACTER(len=StrLen) :: vname_q = 'undefined' ! variable name: observed runoff + CHARACTER(len=StrLen) :: vname_spechum = 'undefined' ! variable name: specific humidity + CHARACTER(len=StrLen) :: vname_airpres = 'undefined' ! variable name: surface pressure + CHARACTER(len=StrLen) :: vname_swdown = 'undefined' ! variable name: downward shortwave radiation + + ! indices for forcing variables + INTEGER(i4b),PARAMETER :: ilook_aprecip = 1 ! named element in lCheck + INTEGER(i4b),PARAMETER :: ilook_potevap = 2 ! named element in lCheck + INTEGER(i4b),PARAMETER :: ilook_airtemp = 3 ! named element in lCheck + INTEGER(i4b),PARAMETER :: ilook_q = 4 ! named element in lCheck + INTEGER(i4b),PARAMETER :: ilook_spechum = 5 ! named element in lCheck + INTEGER(i4b),PARAMETER :: ilook_airpres = 6 ! named element in lCheck + INTEGER(i4b),PARAMETER :: ilook_swdown = 7 ! named element in lCheck + + ! indices for time data (only used in ASCII files) + INTEGER(i4b) :: ivarid_iy = -1 ! variable ID for year + INTEGER(i4b) :: ivarid_im = -1 ! variable ID for month + INTEGER(i4b) :: ivarid_id = -1 ! variable ID for day + INTEGER(i4b) :: ivarid_ih = -1 ! variable ID for hour + INTEGER(i4b) :: ivarid_imin = -1 ! variable ID for minute + INTEGER(i4b) :: ivarid_dsec = -1 ! variable ID for second + + ! indices for variables + INTEGER(i4b) :: ivarid_ppt = -1 ! variable ID for precipitation + INTEGER(i4b) :: ivarid_temp = -1 ! variable ID for temperature + INTEGER(i4b) :: ivarid_pet = -1 ! variable ID for potential ET + INTEGER(i4b) :: ivarid_q = -1 ! variable ID for runoff + + ! multipliers for variables to convert fluxes to mm/day + REAL(sp) :: amult_ppt = -1._dp ! convert precipitation to mm/day + REAL(sp) :: amult_pet = -1._dp ! convert potential ET to mm/day + REAL(sp) :: amult_q = -1._dp ! convert runoff to mm/day + + ! missing values + INTEGER(I4B),PARAMETER :: NA_VALUE = -9999 ! integer designating missing values - TODO: retrieve from NetCDF file + REAL(SP),PARAMETER :: NA_VALUE_SP = -9999._sp ! integer designating missing values - TODO: retrieve from NetCDF file + +END MODULE multiforce diff --git a/build/FUSE_SRC/share/multiparam_data.f90 b/build/FUSE_SRC/share/multiparam_data.f90 new file mode 100644 index 0000000..2fc8071 --- /dev/null +++ b/build/FUSE_SRC/share/multiparam_data.f90 @@ -0,0 +1,37 @@ +MODULE multiparam + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Martyn Clark to separate type definitions from data storage, 01/2026 + ! --------------------------------------------------------------------------------------- + + USE nrtype + USE multiparam_types, only: PARATT ! included for legacy for routines that USE multiparam + USE multiparam_types, only: PARADJ, PARDVD, PARINFO, PAR_ID + + implicit none + private + + public :: PARATT, PARADJ, PARDVD, PARINFO, PAR_ID + + public :: MAXPAR, NUMPAR + public :: APARAM, MPARAM, DPARAM + public :: PARMETA, LPARAM + public :: SOBOL_INDX + + INTEGER(I4B), PARAMETER :: MAXPAR=50 ! maximum number of parameters for a single model + INTEGER(I4B) :: NUMPAR ! number of model parameters for current model + + TYPE(PARADJ), DIMENSION(:), POINTER :: APARAM=>null() ! all model parameter sets; DK/2008/10/21: explicit null + TYPE(PARADJ) :: MPARAM ! single model parameter set + TYPE(PARDVD) :: DPARAM ! derived model parameters + + TYPE(PARINFO) :: PARMETA ! parameter metadata (all parameters) + TYPE(PAR_ID), DIMENSION(MAXPAR) :: LPARAM ! list of model parameter names (need to modify to 16 for SCE) + + INTEGER(I4B) :: SOBOL_INDX ! code to re-assemble Sobol parameters + +END MODULE multiparam diff --git a/build/FUSE_SRC/share/multiroute_data.f90 b/build/FUSE_SRC/share/multiroute_data.f90 new file mode 100644 index 0000000..e1f3111 --- /dev/null +++ b/build/FUSE_SRC/share/multiroute_data.f90 @@ -0,0 +1,20 @@ +MODULE multiroute + + USE nrtype + USE model_defn,ONLY:NTDH_MAX + USE multiroute_types, only: RUNOFF + + implicit none + private + + public :: FUTURE + public :: AROUTE, AROUTE_3d + public :: MROUTE + + REAL(SP), DIMENSION(NTDH_MAX) :: FUTURE ! runoff placed in future time steps + + TYPE(RUNOFF), DIMENSION(:), POINTER :: AROUTE ! runoff for all time steps + TYPE(RUNOFF),dimension(:,:,:), allocatable :: AROUTE_3d ! runoff for all time steps on a grid + TYPE(RUNOFF) :: MROUTE ! runoff for one time step + +END MODULE multiroute diff --git a/build/FUSE_SRC/share/multistate_data.f90 b/build/FUSE_SRC/share/multistate_data.f90 new file mode 100644 index 0000000..ce1c1ec --- /dev/null +++ b/build/FUSE_SRC/share/multistate_data.f90 @@ -0,0 +1,44 @@ +MODULE multistate + + USE nrtype + USE multistate_types, only: STATEV, M_TIME + + implicit none + private + + public :: STATEV, M_TIME + + public :: gState, gState_3d + + public :: ASTATE, FSTATE, MSTATE, TSTATE, BSTATE, ESTATE, DSTATE + public :: DYDT_0, DYDT_1, DY_DT, DYDT_OLD + public :: HSTATE + + public :: ncid_out + public :: fracState0 + + ! variable definitions (grid) + type(statev),dimension(:,:),pointer :: gState ! (grid of model states) + type(statev),dimension(:,:,:),pointer :: gState_3d ! (grid of model states with a time dimension) + + ! variable definitions (one cell) + TYPE(STATEV) :: ASTATE ! (model states at the start of full timestep) + TYPE(STATEV) :: FSTATE ! (model states at start of sub-timestep) + TYPE(STATEV) :: MSTATE ! (model states at start/middle of sub-timestep) + TYPE(STATEV) :: TSTATE ! (temporary copy of model states) + TYPE(STATEV) :: BSTATE ! (temporary copy of model states) + TYPE(STATEV) :: ESTATE ! (temporary copy of model states) + TYPE(STATEV) :: DSTATE ! (default model states) + TYPE(STATEV) :: DYDT_0 ! (derivative of model states at start of sub-step) + TYPE(STATEV) :: DYDT_1 ! (derivative of model states at end of sub-step) + TYPE(STATEV) :: DY_DT ! (derivative of model states) + TYPE(STATEV) :: DYDT_OLD ! (derivative of model states for final solution) + TYPE(M_TIME) :: HSTATE ! (time interval to advance model states) + + ! NetCDF + integer(i4b) :: ncid_out = -1 ! NetCDF output file ID + + ! initial store fraction (initialization) + real(sp), parameter :: fracState0 = 0.25_sp + +END MODULE multistate diff --git a/build/FUSE_SRC/share/multistats_data.f90 b/build/FUSE_SRC/share/multistats_data.f90 new file mode 100644 index 0000000..4008e09 --- /dev/null +++ b/build/FUSE_SRC/share/multistats_data.f90 @@ -0,0 +1,16 @@ +MODULE multistats + + USE nrtype + USE multistats_types, only: SUMMARY + + implicit none + private + + public :: MSTATS, MOD_IX, PCOUNT, FCOUNT + + TYPE(SUMMARY) :: MSTATS ! (model summary statistics) + INTEGER(I4B) :: MOD_IX = 1 ! (model index) + INTEGER(I4B) :: PCOUNT ! (number of parameter sets in model output files) + INTEGER(I4B) :: FCOUNT ! (number of model simulations) + +END MODULE multistats diff --git a/build/FUSE_SRC/types/model_defn_types.f90 b/build/FUSE_SRC/types/model_defn_types.f90 new file mode 100644 index 0000000..a22acf9 --- /dev/null +++ b/build/FUSE_SRC/types/model_defn_types.f90 @@ -0,0 +1,48 @@ +MODULE model_defn_types + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Martyn Clark to separate data tyoes from data store, 01/2026 + ! --------------------------------------------------------------------------------------- + + USE nrtype + + implicit none + private + + public :: DESC, UMODEL, SNAMES, FNAMES + + ! description of model component + TYPE DESC + CHARACTER(LEN=16) :: MCOMPONENT ! description of model component + END TYPE DESC + + ! structure that holds (x) unique combinations + TYPE UMODEL + INTEGER(I4B) :: MODIX ! model index + CHARACTER(LEN=256) :: MNAME ! model name + INTEGER(I4B) :: iRFERR + INTEGER(I4B) :: iARCH1 + INTEGER(I4B) :: iARCH2 + INTEGER(I4B) :: iQSURF + INTEGER(I4B) :: iQPERC + INTEGER(I4B) :: iESOIL + INTEGER(I4B) :: iQINTF + INTEGER(I4B) :: iQ_TDH + INTEGER(I4B) :: iSNOWM ! snow + END TYPE UMODEL + + ! structure to hold model state names + TYPE SNAMES + INTEGER(I4B) :: iSNAME ! integer value of state name + END TYPE SNAMES + + ! structure to hold model flux names + TYPE FNAMES + CHARACTER(LEN=16) :: FNAME ! state name + END TYPE FNAMES + +END MODULE model_defn_types diff --git a/build/FUSE_SRC/dshare/multi_flux.f90 b/build/FUSE_SRC/types/multi_flux_types.f90 similarity index 82% rename from build/FUSE_SRC/dshare/multi_flux.f90 rename to build/FUSE_SRC/types/multi_flux_types.f90 index b3c884f..c4411f4 100644 --- a/build/FUSE_SRC/dshare/multi_flux.f90 +++ b/build/FUSE_SRC/types/multi_flux_types.f90 @@ -1,5 +1,12 @@ -MODULE multi_flux +MODULE multi_flux_types + USE nrtype + + implicit none + private + + public :: FLUXES + TYPE FLUXES REAL(SP) :: EFF_PPT ! effective precipitation (mm day-1) REAL(SP) :: SATAREA ! saturated area (-) @@ -32,11 +39,5 @@ MODULE multi_flux REAL(SP) :: ERR_FREE_2B ! excessive extrapolation: storage in the secondary resvr (mm day-1) REAL(SP) :: CHK_TIME ! time elapsed during time step (days) ENDTYPE FLUXES - TYPE(FLUXES) :: M_FLUX ! model fluxes - TYPE(FLUXES) :: FLUX_0 ! model fluxes at start of step - TYPE(FLUXES) :: FLUX_1 ! model fluxes at end of step - TYPE(FLUXES), DIMENSION(:), POINTER :: FDFLUX=>NULL() ! finite difference fluxes - TYPE(FLUXES) :: W_FLUX ! weighted sum of model fluxes over a time step - TYPE(FLUXES), dimension(:,:,:), allocatable :: W_FLUX_3d ! weighted sum of model fluxes over a time step for several time steps - REAL(SP) :: CURRENT_DT ! current time step (days) -END MODULE multi_flux + +END MODULE multi_flux_types diff --git a/build/FUSE_SRC/dshare/multibands.f90 b/build/FUSE_SRC/types/multibands_types.f90 similarity index 59% rename from build/FUSE_SRC/dshare/multibands.f90 rename to build/FUSE_SRC/types/multibands_types.f90 index 101928d..e045eec 100644 --- a/build/FUSE_SRC/dshare/multibands.f90 +++ b/build/FUSE_SRC/types/multibands_types.f90 @@ -1,7 +1,18 @@ -! Created by Brian Henn to allow multi-band snow modeling, 6/2013 -! Based on module MULTIFORCE by Martyn Clark -MODULE multibands +MODULE multibands_types + + ! Created by Brian Henn to allow multi-band snow modeling, 6/2013 + ! Based on module MULTIFORCE by Martyn Clark + + ! Modified by Martyn Clark to separate type definitions from data storage, 01/2026 + USE nrtype + + implicit none + private + + public :: BANDS, BANDS_INFO, BANDS_VAR + + TYPE BANDS ! for catchment scale modeling INTEGER(I4B) :: NUM ! band number (-) REAL(SP) :: Z_MID ! band mid-point elevation (m) @@ -26,14 +37,4 @@ MODULE multibands REAL(SP) :: DSWE_DT ! rate of change of band SWE (mm day-1) ENDTYPE BANDS_VAR - ! -------------------------------------------------------------------------------------- - TYPE(BANDS),DIMENSION(:),ALLOCATABLE :: MBANDS ! basin band information - type(BANDS_INFO),dimension(:,:,:),ALLOCATABLE :: MBANDS_INFO_3d ! basin band information in space - type(BANDS_VAR),dimension(:,:,:,:),ALLOCATABLE :: MBANDS_VAR_4d ! basin band information in space plus time - - INTEGER(I4B) :: N_BANDS=0 ! number of bands, initialize to zero - REAL(SP) :: Z_FORCING ! elevation of forcing data (m) - REAL(SP),DIMENSION(:,:),ALLOCATABLE :: Z_FORCING_grid ! elevation of forcing data (m) for the 2D domain - LOGICAL(LGT),DIMENSION(:,:),ALLOCATABLE :: elev_mask ! mask domain - TRUE means the cell must be masked, i.e. not run - ! -------------------------------------------------------------------------------------- -END MODULE multibands +END MODULE multibands_types diff --git a/build/FUSE_SRC/types/multiforce_types.f90 b/build/FUSE_SRC/types/multiforce_types.f90 new file mode 100644 index 0000000..8a40f9b --- /dev/null +++ b/build/FUSE_SRC/types/multiforce_types.f90 @@ -0,0 +1,52 @@ +MODULE multiforce_types + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Nans Addor to enable distributed modeling, 9/2016 + ! Modified by Cyril Thébault to allow different metrics as objective function, 2024 + ! Modified by Martyn Clark to separate type definitions from data storage, 01/2026 + ! --------------------------------------------------------------------------------------- + + USE nrtype + + implicit none + private + + public :: TDATA, VDATA, ADATA, FDATA + + ! the time data structure (will have no spatial dimension) + TYPE TDATA + INTEGER(I4B) :: IY ! year + INTEGER(I4B) :: IM ! month + INTEGER(I4B) :: ID ! day + INTEGER(I4B) :: IH ! hour + INTEGER(I4B) :: IMIN ! minute + REAL(SP) :: DSEC ! second + REAL(SP) :: DTIME ! time in seconds since year dot + ENDTYPE TDATA + + ! the response structure (will not have a spatial dimension) + TYPE VDATA + REAL(SP) :: OBSQ ! observed runoff (mm day-1) + END TYPE VDATA + + ! ancillary forcing variables used to compute ET (will have a spatial dimension) + TYPE ADATA + REAL(SP) :: AIRTEMP ! air temperature (K) + REAL(SP) :: SPECHUM ! specific humidity (g/g) + REAL(SP) :: AIRPRES ! air pressure (Pa) + REAL(SP) :: SWDOWN ! downward sw radiation (W m-2) + REAL(SP) :: NETRAD ! net radiation (W m-2) + END TYPE ADATA + + ! the forcing data structure (will have a spatial dimension) + TYPE FDATA + REAL(SP) :: PPT ! water input: rain + melt (mm day-1) + REAL(SP) :: TEMP ! temperature for snow model (deg.C) + REAL(SP) :: PET ! energy input: potential ET (mm day-1) + ENDTYPE FDATA + +END MODULE multiforce_types diff --git a/build/FUSE_SRC/dshare/multiparam.f90 b/build/FUSE_SRC/types/multiparam_types.f90 similarity index 90% rename from build/FUSE_SRC/dshare/multiparam.f90 rename to build/FUSE_SRC/types/multiparam_types.f90 index dd1188e..6062732 100644 --- a/build/FUSE_SRC/dshare/multiparam.f90 +++ b/build/FUSE_SRC/types/multiparam_types.f90 @@ -1,12 +1,21 @@ -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark -! Modified by Brian Henn to include snow model, 6/2013 -! --------------------------------------------------------------------------------------- -MODULE multiparam +MODULE multiparam_types + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Martyn Clark to separate type definitions from data storage, 01/2026 + ! --------------------------------------------------------------------------------------- + USE nrtype - USE model_defn,ONLY:NTDH_MAX + USE model_defn, ONLY: NTDH_MAX + + implicit none + private + + public :: PARATT, PARINFO, PARADJ, PARDVD, PAR_ID + ! -------------------------------------------------------------------------------------- ! (1) PARAMETER METADATA ! -------------------------------------------------------------------------------------- @@ -29,6 +38,7 @@ MODULE multiparam CHARACTER(LEN=256) :: CHILD1 ! name of 1st parameter child CHARACTER(LEN=256) :: CHILD2 ! name of 2nd parameter child END TYPE PARATT + ! data structure to hold metadata for each parameter TYPE PARINFO ! rainfall error parameters (adjustable) @@ -78,6 +88,7 @@ MODULE multiparam TYPE(PARATT) :: OPG ! precipitation gradient (-) TYPE(PARATT) :: LAPSE ! temperature gradient (deg. C) ENDTYPE PARINFO + ! -------------------------------------------------------------------------------------- ! (2) ADJUSTABLE PARAMETERS ! -------------------------------------------------------------------------------------- @@ -129,6 +140,7 @@ MODULE multiparam REAL(SP) :: OPG ! precipitation gradient (-) REAL(SP) :: LAPSE ! temperature gradient (deg. C) END TYPE PARADJ + ! -------------------------------------------------------------------------------------- ! (3) DERIVED PARAMETERS ! -------------------------------------------------------------------------------------- @@ -153,22 +165,12 @@ MODULE multiparam REAL(SP), DIMENSION(NTDH_MAX) :: FRAC_FUTURE ! fraction of runoff in future time steps INTEGER(I4B) :: NTDH_NEED ! number of time-steps with non-zero routing contribution END TYPE PARDVD + ! -------------------------------------------------------------------------------------- ! (4) LIST OF PARAMETERS FOR A GIVEN MODEL ! -------------------------------------------------------------------------------------- TYPE PAR_ID CHARACTER(LEN=9) :: PARNAME ! list of parameter names ENDTYPE PAR_ID - ! -------------------------------------------------------------------------------------- - ! (5) FINAL DATA STRUCTURES - ! -------------------------------------------------------------------------------------- - INTEGER(I4B), PARAMETER :: MAXPAR=50 ! maximum number of parameters for a single model - TYPE(PARADJ), DIMENSION(:), POINTER :: APARAM=>null() ! all model parameter sets; DK/2008/10/21: explicit null - TYPE(PARADJ) :: MPARAM ! single model parameter set - TYPE(PARDVD) :: DPARAM ! derived model parameters - TYPE(PARINFO) :: PARMETA ! parameter metadata (all parameters) - TYPE(PAR_ID), DIMENSION(MAXPAR) :: LPARAM ! list of model parameter names (need to modify to 16 for SCE) - INTEGER(I4B) :: NUMPAR ! number of model parameters for current model - INTEGER(I4B) :: SOBOL_INDX ! code to re-assemble Sobol parameters - ! -------------------------------------------------------------------------------------- -END MODULE multiparam + +END MODULE multiparam_types diff --git a/build/FUSE_SRC/types/multiroute_types.f90 b/build/FUSE_SRC/types/multiroute_types.f90 new file mode 100644 index 0000000..3b98045 --- /dev/null +++ b/build/FUSE_SRC/types/multiroute_types.f90 @@ -0,0 +1,16 @@ +MODULE multiroute_types + + USE nrtype + + implicit none + private + + public :: RUNOFF + + TYPE RUNOFF + REAL(SP) :: Q_INSTNT ! instantaneous runoff + REAL(SP) :: Q_ROUTED ! routed runoff + REAL(SP) :: Q_ACCURATE ! "accurate" runoff estimate (mm day-1) + END TYPE RUNOFF + +END MODULE multiroute_types diff --git a/build/FUSE_SRC/types/multistate_types.f90 b/build/FUSE_SRC/types/multistate_types.f90 new file mode 100644 index 0000000..e40f59d --- /dev/null +++ b/build/FUSE_SRC/types/multistate_types.f90 @@ -0,0 +1,37 @@ +MODULE multistate_types + + USE nrtype + + implicit none + private + + public :: STATEV, M_TIME + + ! -------------------------------------------------------------------------------------- + ! model state structure + ! -------------------------------------------------------------------------------------- + TYPE STATEV + ! snow layer + REAL(SP) :: SWE_TOT ! total storage as snow (mm) + ! upper layer + REAL(SP) :: WATR_1 ! total storage in layer1 (mm) + REAL(SP) :: TENS_1 ! tension storage in layer1 (mm) + REAL(SP) :: FREE_1 ! free storage in layer 1 (mm) + REAL(SP) :: TENS_1A ! storage in the recharge zone (mm) + REAL(SP) :: TENS_1B ! storage in the lower zone (mm) + ! lower layer + REAL(SP) :: WATR_2 ! total storage in layer2 (mm) + REAL(SP) :: TENS_2 ! tension storage in layer2 (mm) + REAL(SP) :: FREE_2 ! free storage in layer2 (mm) + REAL(SP) :: FREE_2A ! storage in the primary resvr (mm) + REAL(SP) :: FREE_2B ! storage in the secondary resvr (mm) + END TYPE STATEV + + ! -------------------------------------------------------------------------------------- + ! model time structure + ! -------------------------------------------------------------------------------------- + TYPE M_TIME + REAL(SP) :: STEP ! (time interval to advance model states) + END TYPE M_TIME + +END MODULE multistate_types diff --git a/build/FUSE_SRC/dshare/multistats.f90 b/build/FUSE_SRC/types/multistats_types.f90 similarity index 85% rename from build/FUSE_SRC/dshare/multistats.f90 rename to build/FUSE_SRC/types/multistats_types.f90 index d950cd9..f3f4ffd 100644 --- a/build/FUSE_SRC/dshare/multistats.f90 +++ b/build/FUSE_SRC/types/multistats_types.f90 @@ -1,10 +1,21 @@ -MODULE multistats +MODULE multistats_types + USE nrtype + + implicit none + private + + public :: SUMMARY + + ! -------------------------------------------------------------------------------------- + TYPE SUMMARY - ! DMSL diagnostix + + ! DMSL diagnostix REAL(SP) :: VAR_RESIDUL ! variance of the model residuals REAL(SP) :: LOGP_SIMULN ! log density of the model simulation REAL(SP) :: JUMP_TAKEN ! defines a jump in the MCMC production run + ! comparisons between model output and observations REAL(SP) :: QOBS_MEAN ! mean observed runoff (mm day-1) REAL(SP) :: QSIM_MEAN ! mean simulated runoff (mm day-1) @@ -19,6 +30,7 @@ MODULE multistats REAL(SP) :: KGEP ! Kling-Gupta Efficiency' score REAL(SP) :: MAE ! Mean absolute error REAL(SP) :: METRIC_VAL ! value of the metric chosen as objective function + ! attributes of model output REAL(SP) :: NUM_RMSE ! error of the approximate solution REAL(SP) :: NUM_FUNCS ! number of function calls @@ -28,12 +40,10 @@ MODULE multistats REAL(SP) :: NUMSUB_NOCONV ! number of sub-steps tried that did not converge INTEGER(I4B) :: MAXNUM_ITERNS ! maximum number of iterations in implicit scheme REAL(SP), DIMENSION(20) :: NUMSUB_PROB ! probability distribution for number of sub-steps + ! error checking CHARACTER(LEN=1024) :: ERR_MESSAGE ! error message + ENDTYPE SUMMARY - ! final data structures - TYPE(SUMMARY) :: MSTATS ! (model summary statistics) - INTEGER(I4B) :: MOD_IX=1 ! (model index) - INTEGER(I4B) :: PCOUNT ! (number of parameter sets in model output files) - INTEGER(I4B) :: FCOUNT ! (number of model simulations) -END MODULE multistats + +END MODULE multistats_types diff --git a/build/Makefile b/build/Makefile index 5a41660..3310710 100755 --- a/build/Makefile +++ b/build/Makefile @@ -124,7 +124,8 @@ NUMREC_DIR = $(FUSE_SOURCE_DIR)numrec HOOKUP_DIR = $(FUSE_SOURCE_DIR)hookup DRIVER_DIR = $(FUSE_SOURCE_DIR)driver NETCDF_DIR = $(FUSE_SOURCE_DIR)netcdf -DSHARE_DIR = $(FUSE_SOURCE_DIR)dshare +SHARE_DIR = $(FUSE_SOURCE_DIR)share +TYPES_DIR = $(FUSE_SOURCE_DIR)types PRELIM_DIR = $(FUSE_SOURCE_DIR)prelim RUNTIME_DIR = $(FUSE_SOURCE_DIR)runtime PHYSICS_DIR = $(FUSE_SOURCE_DIR)physics @@ -158,22 +159,43 @@ FUSE_NRUTIL += nrtype.f90 FUSE_NRUTIL += nr.f90 nrutil.f90 NRUTIL = $(patsubst %, $(NUMREC_DIR)/%, $(FUSE_NRUTIL)) -# Data modules -FUSE_DATAMS = -FUSE_DATAMS += model_defn.f90 -#FUSE_DATAMS += data_types.f90 -FUSE_DATAMS += model_defnames.f90 -FUSE_DATAMS += globaldata.f90 -FUSE_DATAMS += multiconst.f90 -FUSE_DATAMS += multiforce.f90 -FUSE_DATAMS += multibands.f90 -FUSE_DATAMS += multiparam.f90 -FUSE_DATAMS += multistate.f90 -FUSE_DATAMS += multi_flux.f90 -FUSE_DATAMS += multiroute.f90 -FUSE_DATAMS += multistats.f90 -FUSE_DATAMS += model_numerix.f90 -DATAMS = $(patsubst %, $(DSHARE_DIR)/%, $(FUSE_DATAMS)) +# Global data (needs to be defined before model_defn) +G_DATA = $(SHARE_DIR)/globaldata.f90 + +# Model definition +FUSE_MODDEF = +FUSE_MODDEF += $(TYPES_DIR)/model_defn_types.f90 +FUSE_MODDEF += $(SHARE_DIR)/model_defn_data.f90 +MODDEF = $(FUSE_MODDEF) # no patetrn substitution needed + +# Data types +FUSE_TYPES = +FUSE_TYPES += multiforce_types.f90 +FUSE_TYPES += multibands_types.f90 +FUSE_TYPES += multiparam_types.f90 +FUSE_TYPES += multistate_types.f90 +FUSE_TYPES += multi_flux_types.f90 +FUSE_TYPES += multiroute_types.f90 +FUSE_TYPES += multistats_types.f90 +#FUSE_TYPES += data_types.f90 +TYPES = $(patsubst %, $(TYPES_DIR)/%, $(FUSE_TYPES)) + +# combined type+data (mimic legacy code) +FUSE_SHARE = +FUSE_SHARE += multiconst.f90 +FUSE_SHARE += model_defnames.f90 +FUSE_SHARE += model_numerix.f90 +FUSE_SHARE += multiforce_data.f90 +FUSE_SHARE += multibands_data.f90 +FUSE_SHARE += multiparam_data.f90 +FUSE_SHARE += multistate_data.f90 +FUSE_SHARE += multi_flux_data.f90 +FUSE_SHARE += multiroute_data.f90 +FUSE_SHARE += multistats_data.f90 +SHARE = $(patsubst %, $(SHARE_DIR)/%, $(FUSE_SHARE)) + +# combine data modules together +DATAMS = $(G_DATA) $(MODDEF) $(TYPES) $(SHARE) # Time I/O modules FUSE_TIMEMS = diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index 841a0c5..f746158 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-01-03T03:28:59Z' -character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/baseline' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'e90e6ea52e9956032bfe114e712398d58db3e9df' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-01-03T18:16:33Z' +character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/separate-data-types-from-storage' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '4bb2fc3879f4acb512fb464781d8422a92e35c89' From fa0612d2409778bdcf26825084d4f3ac2b51f873 Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Tue, 6 Jan 2026 20:55:59 +1300 Subject: [PATCH 02/11] initialize with common random seed --- build/FUSE_SRC/driver/fuse_driver.f90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index 32b4cee..6be2133 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -452,6 +452,9 @@ PROGRAM DISTRIBUTED_DRIVER print *, 'Creating SCE output file:', trim(FNAME_ASCII) ISCE = 96; OPEN(ISCE,FILE=TRIM(FNAME_ASCII)) + ! set random seed + ISEED = 1 + ! optimize (returns A and AF) ! note that SCE requires the kind of APAR, BL, BU to be MSP CALL SCEUA(APAR_MSP,AF_MSP,BL_MSP,BU_MSP,NOPT,MAXN,KSTOP,PCENTO,ISEED,& From 711131f5718d2de448d03ae629c66762d1166dea Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Tue, 6 Jan 2026 21:33:14 +1300 Subject: [PATCH 03/11] build: record git version --- build/generated/fuseversion.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index f746158..ac6d752 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-01-03T18:16:33Z' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-01-06T08:03:49Z' character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/separate-data-types-from-storage' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '4bb2fc3879f4acb512fb464781d8422a92e35c89' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'fa0612d2409778bdcf26825084d4f3ac2b51f873' From e3718ed797ed957828ee0138d2ee8d3c815388be Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Tue, 17 Feb 2026 16:41:34 -0700 Subject: [PATCH 04/11] initial refactor for the differentiable model --- build/FUSE_SRC/driver/fuse_driver.f90 | 3 +- build/FUSE_SRC/driver/fuse_metric.f90 | 222 +++++-- build/FUSE_SRC/netcdf/def_output.f90 | 198 +++--- build/FUSE_SRC/netcdf/put_output.f90 | 302 +++++---- build/FUSE_SRC/netcdf/put_params.f90 | 163 ++--- build/FUSE_SRC/physics/conserve_clamp.f90 | 303 +++++++++ build/FUSE_SRC/physics/evap_lower_diff.f90 | 94 +++ build/FUSE_SRC/physics/evap_upper_diff.f90 | 139 ++++ build/FUSE_SRC/physics/fix_ovshoot.f90 | 161 +++++ build/FUSE_SRC/physics/get_bundle.f90 | 44 ++ build/FUSE_SRC/physics/implicit_solve.f90 | 360 ++++++++++ build/FUSE_SRC/physics/mod_derivs_diff.f90 | 65 ++ build/FUSE_SRC/physics/mstate_rhs_diff.f90 | 115 ++++ build/FUSE_SRC/physics/q_baseflow_diff.f90 | 109 +++ build/FUSE_SRC/physics/q_misscell_diff.f90 | 125 ++++ build/FUSE_SRC/physics/qinterflow_diff.f90 | 59 ++ build/FUSE_SRC/physics/qpercolate_diff.f90 | 117 ++++ build/FUSE_SRC/physics/qsatexcess_diff.f90 | 157 +++++ build/FUSE_SRC/physics/smoothers.f90 | 307 +++++++++ build/FUSE_SRC/physics/update_swe_diff.f90 | 337 ++++++++++ build/FUSE_SRC/physics_orig/update_swe.f90 | 51 +- build/FUSE_SRC/prelim/init_state.f90 | 2 +- build/FUSE_SRC/runtime/initfluxes.f90 | 4 +- build/FUSE_SRC/runtime/set_all.f90 | 14 +- build/FUSE_SRC/share/model_numerix.f90 | 3 + build/FUSE_SRC/types/data_types.f90 | 70 ++ build/FUSE_SRC/types/info_types.f90 | 182 +++++ build/FUSE_SRC/types/multibands_types.f90 | 21 +- build/FUSE_SRC/types/work_types.f90 | 60 ++ build/FUSE_SRC/util/metaoutput.f90 | 214 +++--- build/FUSE_SRC/util/metaparams.f90 | 223 ++++--- build/FUSE_SRC/util/parextract.f90 | 362 ++++------ build/FUSE_SRC/util/varextract.f90 | 739 +++++++-------------- build/Makefile | 8 +- build/generated/fuseversion.inc | 6 +- 35 files changed, 3973 insertions(+), 1366 deletions(-) create mode 100644 build/FUSE_SRC/physics/conserve_clamp.f90 create mode 100644 build/FUSE_SRC/physics/evap_lower_diff.f90 create mode 100644 build/FUSE_SRC/physics/evap_upper_diff.f90 create mode 100644 build/FUSE_SRC/physics/fix_ovshoot.f90 create mode 100644 build/FUSE_SRC/physics/get_bundle.f90 create mode 100644 build/FUSE_SRC/physics/implicit_solve.f90 create mode 100644 build/FUSE_SRC/physics/mod_derivs_diff.f90 create mode 100644 build/FUSE_SRC/physics/mstate_rhs_diff.f90 create mode 100644 build/FUSE_SRC/physics/q_baseflow_diff.f90 create mode 100644 build/FUSE_SRC/physics/q_misscell_diff.f90 create mode 100644 build/FUSE_SRC/physics/qinterflow_diff.f90 create mode 100644 build/FUSE_SRC/physics/qpercolate_diff.f90 create mode 100644 build/FUSE_SRC/physics/qsatexcess_diff.f90 create mode 100644 build/FUSE_SRC/physics/smoothers.f90 create mode 100644 build/FUSE_SRC/physics/update_swe_diff.f90 create mode 100644 build/FUSE_SRC/types/data_types.f90 create mode 100644 build/FUSE_SRC/types/info_types.f90 create mode 100644 build/FUSE_SRC/types/work_types.f90 diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index 6be2133..f4ac3a4 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -59,6 +59,7 @@ PROGRAM DISTRIBUTED_DRIVER USE getpar_str_module ! extracts parameter metadata USE par_insert_module ! inserts model parameters USE force_info_module,only:force_info ! get forcing info for NetCDF files +USE def_output_module,only:def_output ! define NetCDF output file USE get_gforce_module,only:read_ginfo ! get dimension lengths from the NetCDF file USE get_gforce_module,only:get_varid ! get netCDF ID for forcing variables USE get_gforce_module,only:get_gforce_3d ! get forcing @@ -386,7 +387,7 @@ PROGRAM DISTRIBUTED_DRIVER CALL DEF_PARAMS(NUMPSET) ! define model parameters (initial CREATE) CALL DEF_SSTATS() ! define summary statistics (REDEF) -CALL DEF_OUTPUT(nSpat1,nSpat2,NUMPSET,numtim_sim) ! define model output time series (REDEF) +CALL DEF_OUTPUT(nSpat1,nSpat2,N_BANDS,NUMPSET,numtim_sim) ! define model output time series (REDEF) ! --------------------------------------------------------------------------------------- ! RUN FUSE IN DESIRED MODE diff --git a/build/FUSE_SRC/driver/fuse_metric.f90 b/build/FUSE_SRC/driver/fuse_metric.f90 index c22a43b..d7ec781 100644 --- a/build/FUSE_SRC/driver/fuse_metric.f90 +++ b/build/FUSE_SRC/driver/fuse_metric.f90 @@ -10,6 +10,7 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA ! Modified by Brian Henn to include snow model, 6/2013 ! Modified by Nans Addor to enable grid-based modeling, 9/2016 ! Modified by Cyril Thébault to allow different metrics as objective function, 2024 + ! Modified by Martyn Clark to call differentiable modeling routines, 12/2025 ! --------------------------------------------------------------------------------------- ! Purpose: ! -------- @@ -21,8 +22,13 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA USE nrtype ! variable types, etc. ! data modules + USE globaldata, ONLY:NPAR_SNOW ! number of snow parameters USE model_defn, ONLY:NSTATE,SMODL ! number of state variables USE model_defnames ! integer model definitions + USE globaldata, ONLY: isPrint ! flag for printing progress to screen + USE globaldata, only: nFUSE_eval ! number of fuse evaluations + USE globaldata, ONLY: fracstate0 ! fraction of initial state (used for initialization) + USE globaldata, ONLY: NA_VALUE, NA_VALUE_SP ! NA_VALUE for the forcing USE multiparam, ONLY: LPARAM,NUMPAR,MPARAM ! list of model parameters USE multiforce, ONLY: MFORCE,AFORCE,DELTIM,ISTART ! model forcing data USE multiforce, ONLY: numtim_in, itim_in ! length of input time series and associated index @@ -31,28 +37,36 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA USE multiforce, ONLY: numtim_sub_cur ! length of current subperiod USE multiforce, ONLY: sim_beg,sim_end ! timestep indices USE multiforce, ONLY: eval_beg,eval_end ! timestep indices + USE multiforce, ONLY: timdat ! time structure USE multiforce, ONLY:nspat1,nspat2 ! spatial dimensions USE multiforce, ONLY:ncid_var ! NetCDF ID for forcing variables USE multiforce, ONLY:gForce,gForce_3d ! gridded forcing data - USE multistate, ONLY:fracstate0,TSTATE,MSTATE,FSTATE,& ! model states - HSTATE ! model states (continued) - USE multiforce, ONLY:NA_VALUE, NA_VALUE_SP ! NA_VALUE for the forcing + USE multistate, ONLY:TSTATE,MSTATE,FSTATE,HSTATE ! model state variables USE multistate, ONLY:gState,gState_3d ! gridded state variables USE multiroute, ONLY:MROUTE,AROUTE,AROUTE_3d ! routed runoff USE multistats, ONLY:MSTATS,PCOUNT,MOD_IX ! access model statistics; counter for param set USE multi_flux ! model fluxes - USE multibands ! elevation bands for snow modeling + USE multibands ! NOTE: include N_BANDS ! elevation bands for snow modeling USE set_all_module ! code modules USE time_io, ONLY:get_modtim ! get model time for a given time step - USE get_gforce_module, ONLY:get_gforce_3d ! get gridded forcing data for a range of time steps - USE getPETgrid_module, ONLY:getPETgrid ! get gridded PET + USE get_gforce_module, ONLY: get_gforce_3d ! get gridded forcing data for a range of time steps + USE getPETgrid_module, ONLY: getPETgrid ! get gridded PET + USE put_params_module, ONLY: put_params ! write parameters + USE put_output_module, ONLY: put_goutput_3d ! write gridded output + !USE PAR_DERIVE_module, ONLY: PAR_DERIVE USE par_insert_module ! insert parameters into data structures USE str_2_xtry_module ! provide access to the routine str_2_xtry USE xtry_2_str_module ! provide access to the routine xtry_2_str + ! differentiable model + use work_types, only: fuse_work ! bundles "everything" required to run fuse for a single cell + use get_bundle_module, only: get_bundle ! populate the fuse_work data structure + use implicit_solve_module, only:implicit_solve ! simple implicit solve for differnetiable ODE + use update_swe_diff_module, only:update_swe_diff ! differentiable snow model + ! interface blocks USE interfaceb, ONLY:ode_int,fuse_solve ! provide access to FUSE_SOLVE through ODE_INT @@ -71,7 +85,7 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA LOGICAL(LGT), INTENT(IN), OPTIONAL :: MPARAM_FLAG ! .FALSE. (used to turn off writing statistics) ! output - REAL(SP),INTENT(OUT) :: METRIC_VAL ! value of the metric chosen as objective function + REAL(SP),INTENT(OUT) :: METRIC_VAL ! metric ! internal LOGICAL(lgt),PARAMETER :: computePET=.FALSE. ! flag to compute PET @@ -94,10 +108,28 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA CHARACTER(LEN=CLEN) :: CMESSAGE ! error message of downwind routine INTEGER(I4B),PARAMETER::UNT=6 !1701 ! 6 + ! differentiable model + type(fuse_work) :: fuseStruct ! fuse work structure + ! --------------------------------------------------------------------------------------- ! allocate state vectors ALLOCATE(STATE0(NSTATE),STATE1(NSTATE),STAT=IERR) - IF (IERR.NE.0) STOP ' problem allocating space for state vectors in fuse_metric ' + IF (IERR.NE.0) STOP ' problem allocating space for state vectors in fuse_metric' + + ! allocate flux derivative vectors + allocate(fuseStruct%df_dS(nState), fuseStruct%df_dPar(NUMPAR), fuseStruct%dL_dPar(NUMPAR), stat=ierr) + if(ierr/=0) STOP ' problem allocating space for the flux derivative vectors' + + ! allocate elevation bands (for the snow model) + allocate(fuseStruct%sbands(n_bands), stat=ierr) + if(ierr/=0) STOP ' problem allocating space for the elevation bands' + + ! allocate parameter derivative for each elevation band + do iBands=1,n_bands + allocate(fuseStruct%sbands(iBands)%var%dSWE_dParam(NPAR_SNOW), stat=ierr) + if(ierr/=0) STOP ' problem allocating space for the parameter derivatives' + fuseStruct%sbands(iBands)%var%dSWE_dparam(:) = 0._sp + end do ! increment parameter counter for model output IF (.NOT.PRESENT(MPARAM_FLAG)) THEN @@ -108,38 +140,57 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA ! add parameter set to the data structure CALL PUT_PARSET(XPAR) - PRINT *, 'Parameter set added to data structure:' - PRINT *, XPAR + if(isPrint) PRINT *, 'Parameter set added to data structure:' + if(isPrint) PRINT *, XPAR ! compute derived model parameters (bucket sizes, etc.) CALL PAR_DERIVE(ERR,MESSAGE) IF (ERR.NE.0) WRITE(*,*) TRIM(MESSAGE); IF (ERR.GT.0) STOP + ! get elevation bands (if catchment) + if(SMODL%iSNOWM == iopt_temp_index .and. .not.GRID_FLAG)then + Z_FORCING = Z_FORCING_grid(1,1) ! elevation of forcing data (m) + MBANDS(:)%info = MBANDS_INFO_3d(1,1,:) ! info structure, %AF, %Z_MID + endif + + if(isPrint) PRINT *, 'Writing parameter values...' + CALL PUT_PARAMS(PCOUNT) + ! initialize model states over the 2D gridded domain (1x1 domain in catchment mode) DO iSpat2=1,nSpat2 DO iSpat1=1,nSpat1 CALL INIT_STATE(fracState0) ! define FSTATE using fracState0 + CALL STR_2_XTRY(FSTATE,STATE0) ! set state at the start of the time step (STATE0) using FSTATE + CALL XTRY_2_STR(STATE0,FSTATE) ! update structure, including derived state variables gState_3d(iSpat1,iSpat2,1) = FSTATE ! put the state into first time step of 3D structure END DO END DO - PRINT *, 'Model states initialized over the 2D gridded domain' + if(isPrint) PRINT *, 'Model states initialized over the 2D gridded domain' ! initialize elevations bands if snow module is on - PRINT *, 'N_BANDS =', N_BANDS - + if(isPrint) PRINT *, 'N_BANDS =', N_BANDS IF (SMODL%iSNOWM.EQ.iopt_temp_index) THEN + + ! initialize the per-band template once + ! (dSWE_dParam allocated & initialized earlier) + fuseStruct%sbands(:)%var%SWE = 0._sp ! band snowpack water equivalent (mm) + fuseStruct%sbands(:)%var%SNOWACCMLTN = 0._sp ! new snow accumulation in band (mm day-1) + fuseStruct%sbands(:)%var%SNOWMELT = 0._sp ! snowmelt in band (mm day-1) + fuseStruct%sbands(:)%var%DSWE_DT = 0._sp ! rate of change of band SWE (mm day-1) + + ! copy to every grid cell + ! NOTE: %bands_var only copies the var components (OK because MBANDS_VAR_4d is legacy structure) DO iSpat2=1,nSpat2 DO iSpat1=1,nSpat1 - DO IBANDS=1,N_BANDS - MBANDS_VAR_4d(iSpat1,iSpat2,IBANDS,1)%SWE=0.0_sp ! band snowpack water equivalent (mm) - MBANDS_VAR_4d(iSpat1,iSpat2,IBANDS,1)%SNOWACCMLTN=0.0_sp ! new snow accumulation in band (mm day-1) - MBANDS_VAR_4d(iSpat1,iSpat2,IBANDS,1)%SNOWMELT=0.0_sp ! snowmelt in band (mm day-1) - MBANDS_VAR_4d(iSpat1,iSpat2,IBANDS,1)%DSWE_DT=0.0_sp ! rate of change of band SWE (mm day-1) - END DO - END DO - END DO - PRINT *, 'Snow states initiatlized over the 2D gridded domain ' - ENDIF + do iBands=1,n_bands + MBANDS_VAR_4d(iSpat1,iSpat2,iBands,1) = fuseStruct%sbands(iBands)%var%bands_var + end do ! elevation bands + end do ! 1st spatial dimension + end do ! 2nd spatial dimension + + if(isPrint) PRINT *, 'Snow states initiatlized over the 2D gridded domain ' + + ENDIF ! if snow model is on ! allocate 3d data structure for fluxes ALLOCATE(W_FLUX_3d(nspat1,nspat2,numtim_sub)) @@ -153,7 +204,8 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA CALL CPU_TIME(T1) ! This version of FUSE enables the user to load slices of the forcing - ! - FUSE1 used to access the input file at each time step, slowing operations + ! + ! FUSE1 used to access the input file at each time step, slowing operations ! down over large domains on systems with slow I/O. The number of timesteps ! of the slices is defined by the user in the filemanager. The default is ! that the whole time period needed for the simulation is loaded, but @@ -178,16 +230,17 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA numtim_sub_cur=MIN(numtim_sub,numtim_sim-itim_sim+1) ! load forcing for desired period into gForce_3d - PRINT *, 'New subperiod: loading forcing for ',numtim_sub_cur,' time steps' + if(isPrint) PRINT *, 'New subperiod: loading forcing for ',numtim_sub_cur,' time steps' CALL get_gforce_3d(itim_in,numtim_sub_cur,ncid_forc,err,message) IF(err/=0)THEN; WRITE(*,*) 'Error while extracting 3d forcing'; STOP; ENDIF - PRINT *, 'Forcing loaded. Running FUSE...' + if(isPrint) PRINT *, 'Forcing loaded. Running FUSE...' ENDIF ! get the model time CALL get_modtim(itim_in,ncid_forc,ierr,message) IF(ierr/=0)THEN; PRINT*, TRIM(cmessage); STOP; ENDIF + !print*, timdat ! compute potential ET IF(computePET) CALL getPETgrid(ierr,cmessage) @@ -223,35 +276,68 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA ! initialize model fluxes CALL INITFLUXES() ! set weighted sum of fluxes to zero + ! populate fuse work structure + if(diff_mode==differentiable) call get_bundle(fuseStruct) + ! if snow model is on, call UPDATE_SWE to calculate snow fluxes and update snow bands ! using explicit Euler approach; if not, call QRAINERROR SELECT CASE(SMODL%iSNOWM) CASE(iopt_temp_index) ! load data from multidimensional arrays - Z_FORCING = Z_FORCING_grid(iSpat1,iSpat2) ! elevation of forcing data (m) - MBANDS%Z_MID = MBANDS_INFO_3d(iSpat1,iSpat2,:)%Z_MID ! band mid-point elevation (m) - MBANDS%AF = MBANDS_INFO_3d(iSpat1,iSpat2,:)%AF ! fraction of basin area in band (-) - MBANDS%SWE = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub)%SWE ! band snowpack water equivalent (mm) - MBANDS%SNOWACCMLTN = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub)%SNOWACCMLTN ! new snow accumulation in band (mm day-1) - MBANDS%SNOWMELT = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub)%SNOWMELT ! snowmelt in band (mm day-1) - MBANDS%DSWE_DT = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub)%DSWE_DT ! rate of change of band SWE (mm day-1) - - CALL UPDATE_SWE(DELTIM) + Z_FORCING = Z_FORCING_grid(iSpat1,iSpat2) ! elevation of forcing data (m) + mbands(:)%info = MBANDS_INFO_3d(iSpat1,iSpat2,:) ! info structure + mbands(:)%var = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub) ! var structure + + ! put data into the FUSE structure + ! NOTE: only copy the "var" variables + if(diff_mode == differentiable)then + fuseStruct%z_forcing = Z_FORCING + fuseStruct%sbands(:)%info = MBANDS(:)%info + fuseStruct%sbands(:)%var%bands_var = MBANDS(:)%var + endif ! if diff_mode == differentiable + + ! run the snow model + select case(diff_mode) + case(original); CALL UPDATE_SWE(DELTIM) + case(differentiable); CALL UPDATE_SWE_DIFF(fuseStruct,DELTIM) + CASE DEFAULT; stop "fuse_metric: cannot identify diff_mode" + end select CASE(iopt_no_snowmod) CALL QRAINERROR() CASE DEFAULT - message="f-fuse_metric/SMODL%iSNOWM must be either iopt_temp_index or iopt_no_snowmod" - RETURN + message="fuse_metric/SMODL%iSNOWM must be either iopt_temp_index or iopt_no_snowmod" + print*, trim(message); stop 1 END SELECT - ! temporally integrate the ordinary differential equations - CALL ODE_INT(FUSE_SOLVE,STATE0,STATE1,DT_SUB,DT_FULL,IERR,MESSAGE) - IF (IERR.NE.0) THEN - PRINT *, TRIM(MESSAGE) - !PAUSE - ENDIF + ! ----- start of soil physics code ------------------------------------------------------------ + + ! temporally integrate the ordinary differential equations + select case(diff_mode) + + ! original code + case(original) + CALL ODE_INT(FUSE_SOLVE,STATE0,STATE1,DT_SUB,DT_FULL,IERR,MESSAGE) + IF (IERR.NE.0) THEN; PRINT *, TRIM(MESSAGE); STOP 1; ENDIF + + ! differentiable code + case(differentiable) + + ! solve differentiable ODEs + call implicit_solve(fuseStruct, state0, state1, nState, ierr, cmessage) + + ! save fluxes + W_FLUX = fuseStruct%flux + + ! check options + case default; print*, "fuse_metric: Cannot identify diff_mode"; stop 1 + end select + + !print*, ITIM_IN, w_flux%eff_ppt + !if(ITIM_IN > 100) stop "check" + + ! ----- end of soil physics code -------------------------------------------------------------- ! perform overland flow routing CALL Q_OVERLAND() @@ -273,14 +359,18 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA IF (SMODL%iSNOWM.EQ.iopt_temp_index) THEN + ! extract data from the FUSE structure + if(diff_mode == differentiable)then + Z_FORCING = fuseStruct%z_forcing + MBANDS%info = fuseStruct%sbands%info + MBANDS%var = fuseStruct%sbands%var%bands_var + endif ! if diff_mode == differentiable + ! SWE TOT: weighted average of SWE over all the elevation bands - gState_3d(iSpat1,iSpat2,itim_sub+1)%SWE_TOT = SUM(MBANDS%SWE*MBANDS_INFO_3d(iSpat1,iSpat2,:)%AF) + gState_3d(iSpat1,iSpat2,itim_sub+1)%SWE_TOT = SUM(MBANDS(:)%var%SWE * MBANDS(:)%info%AF) ! update MBANDS_VAR_4D - MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1)%SWE = MBANDS%SWE - MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1)%SNOWACCMLTN = MBANDS%SNOWACCMLTN - MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1)%SNOWMELT = MBANDS%SNOWMELT - MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1)%DSWE_DT = MBANDS%DSWE_DT + MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1) = MBANDS(:)%var END IF @@ -311,25 +401,22 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA ! if end of subperiod: write to output file and save states IF(itim_sub.EQ.numtim_sub_cur)THEN - PRINT *, 'End of subperiod reached:' + if(isPrint) PRINT *, 'End of subperiod reached:' ! write model output IF (OUTPUT_FLAG) THEN - PRINT *, 'Write output for ',numtim_sub_cur,' time steps starting at indice', itim_sim-numtim_sub_cur+1 - CALL PUT_GOUTPUT_3D(itim_sim-numtim_sub_cur+1,itim_in-numtim_sub_cur+1,numtim_sub_cur,IPSET) - PRINT *, 'Done writing output' + if(isPrint) PRINT *, 'Write output for ',numtim_sub_cur,' time steps starting at indices', itim_sim-numtim_sub_cur+1 + CALL PUT_GOUTPUT_3D(itim_sim-numtim_sub_cur+1, itim_in-numtim_sub_cur+1, numtim_sub_cur) + if(isPrint) PRINT *, 'Done writing output' ELSE - PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' + if(isPrint) PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' END IF ! TODO: set gState_3d and MBANDS_VAR_4d to NA ! reinitialize states for next subperiod using last time step - gState_3d(:,:,1) = gState_3d(:,:,itim_sub+1) - MBANDS_VAR_4d(:,:,:,1)%SWE = MBANDS_VAR_4d(:,:,:,itim_sub+1)%SWE - MBANDS_VAR_4d(:,:,:,1)%SNOWACCMLTN = MBANDS_VAR_4d(:,:,:,itim_sub+1)%SNOWACCMLTN - MBANDS_VAR_4d(:,:,:,1)%SNOWMELT = MBANDS_VAR_4d(:,:,:,itim_sub+1)%SNOWMELT - MBANDS_VAR_4d(:,:,:,1)%DSWE_DT = MBANDS_VAR_4d(:,:,:,itim_sub+1)%DSWE_DT + gState_3d(:,:,1) = gState_3d(:,:,itim_sub+1) + MBANDS_VAR_4d(:,:,:,1) = MBANDS_VAR_4d(:,:,:,itim_sub+1) ! reset itim_sub itim_sub=1 @@ -348,25 +435,34 @@ SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPA ! get timing information CALL CPU_TIME(T2) - WRITE(*,*) "TIME ELAPSED = ", t2-t1 + if(isPrint) WRITE(*,*) "TIME ELAPSED = ", t2-t1 ! calculate mean summary statistics IF(.NOT.GRID_FLAG)THEN - PRINT *, 'Calculating performance metrics...' + if(isPrint) PRINT *, 'Calculating performance metrics...' CALL MEAN_STATS() METRIC_VAL = MSTATS%METRIC_VAL + write(*,'(i6,1x,a6,1x,f12.6,1x,a20,1x,f12.6)') nFUSE_eval, "NSE = ", MSTATS%NASH_SUTT, "; TIME ELAPSED = ", t2-t1 + !if(nFUSE_eval > 10) stop "checking results" + ENDIF - PRINT *, 'Writing parameter values...' - CALL PUT_PARAMS(PCOUNT) - PRINT *, 'Writing model statistics...' + if(isPrint) PRINT *, 'Writing model statistics...' CALL PUT_SSTATS(PCOUNT) + ! deallocate parameter derivative vectors + do iBands=1,n_bands + deallocate(fuseStruct%sbands(iBands)%var%dSWE_dParam, stat=ierr) + if(ierr/=0) STOP ' problem deallocating space for the parameter derivatives' + end do + ! deallocate vectors DEALLOCATE(W_FLUX_3d); IF (IERR.NE.0) STOP ' problem deallocating W_FLUX_3d in fuse_metric ' DEALLOCATE(STATE0,STATE1,STAT=IERR); IF (IERR.NE.0) STOP ' problem deallocating state vectors in fuse_metric' + deallocate(fuseStruct%df_dS, fuseStruct%df_dPar, fuseStruct%dL_dPar, stat=ierr); if(ierr/=0) STOP ' problem deallocating space for the flux derivative vectors' + deallocate(fuseStruct%sbands, stat=ierr); if(ierr/=0) STOP ' problem deallocating space for the elevation bands' END SUBROUTINE FUSE_METRIC END MODULE FUSE_METRIC_MODULE diff --git a/build/FUSE_SRC/netcdf/def_output.f90 b/build/FUSE_SRC/netcdf/def_output.f90 index b323020..e93e41f 100644 --- a/build/FUSE_SRC/netcdf/def_output.f90 +++ b/build/FUSE_SRC/netcdf/def_output.f90 @@ -1,38 +1,57 @@ -SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,NPSET,NTIM) +MODULE DEF_OUTPUT_MODULE + + USE nrtype ! variable types, etc. + + implicit none + + private + public :: DEF_OUTPUT + + contains + + SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR,NTIM) ! --------------------------------------------------------------------------------------- ! Creator: ! -------- ! Martyn Clark, 2007 + ! Modified by Martyn Clark to include elevation bands, 12/2025 ! --------------------------------------------------------------------------------------- ! Purpose: ! -------- ! Define NetCDF output files -- time-varying model output ! --------------------------------------------------------------------------------------- - USE nrtype ! variable types, etc. + ! subroutines + USE metaoutput, only: VARDESCRIBE ! define metadata for model variables + + ! data modules + USE globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH + USE metaoutput, only: NOUTVAR ! number of output variables + USE metaoutput, only: VNAME, LNAME, VUNIT ! metadata for all model variables + USE metaoutput, only: isBand, isFlux ! logical flag to define vars with band/flux dimension USE model_defn, only: FNAME_NETCDF_RUNS ! model definition (includes filename) - USE metaoutput ! metadata for all model variables - USE fuse_fileManager,only: Q_ONLY ! only write streamflow to output file? - USE multiforce, only: GRID_FLAG ! .true. if distributed + USE fuse_fileManager, only: Q_ONLY ! only write streamflow to output file? + USE multiforce, only: GRID_FLAG ! .true. if distributed USE multiforce, only: latitude,longitude ! dimension arrays USE multiforce, only: name_psets,time_steps ! dimension arrays - USE multiforce, only: latUnits,lonUnits ! units string - USE multiforce, only: timeUnits ! units string - USE multistate, only: ncid_out ! NetCDF output file ID - USE globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH - + USE multiforce, only: latUnits,lonUnits ! lat/lon units string + USE multiforce, only: timeUnits ! time units string + USE globaldata, only: ncid_out ! NetCDF output file ID IMPLICIT NONE ! input INTEGER(I4B), INTENT(IN) :: NTIM ! number of time steps INTEGER(I4B), INTENT(IN) :: nSpat1,nSpat2 ! length of spatial dimensions - INTEGER(I4B), INTENT(IN) :: NPSET ! number of parameter sets + INTEGER(I4B), INTENT(IN) :: n_bands ! number of elevation bands + INTEGER(I4B), INTENT(IN) :: NUMPAR ! number of model parameters ! internal - REAL(MSP),DIMENSION(nspat1) :: longitude_msp ! desired variable (SINGLE PRECISION) - REAL(MSP),DIMENSION(nspat2) :: latitude_msp ! desired variable (SINGLE PRECISION) + integer(i4b), dimension(n_bands) :: band_i ! coordinate variable + integer(i4b), dimension(NUMPAR) :: param_i ! coordinate variable + REAL(MSP),DIMENSION(nspat1) :: longitude_msp ! coordinate variable (SINGLE PRECISION) + REAL(MSP),DIMENSION(nspat2) :: latitude_msp ! coordinate variable (SINGLE PRECISION) REAL(SP),parameter :: NA_VALUE_OUT= -9999. ! NA_VALUE for output file REAL(MSP) :: NA_VALUE_OUT_MSP ! NA_VALUE for output file @@ -41,62 +60,39 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,NPSET,NTIM) INTEGER(I4B) :: NTIM_DIM ! time INTEGER(I4B) :: lon_dim ! 1st spatial dimension INTEGER(I4B) :: lat_dim ! 2nd spatial dimension - INTEGER(I4B) :: param_dim ! parameter set dimension - INTEGER(I4B) :: NMOD_DIM ! number of models - INTEGER(I4B), DIMENSION(:), ALLOCATABLE :: TVAR ! all dimensions + INTEGER(I4B) :: par_dim ! parameter dimension + INTEGER(I4B) :: band_dim ! band dimension + INTEGER(I4B), DIMENSION(3) :: TVAR ! dimension list: exclude band, param + INTEGER(I4B), DIMENSION(4) :: EVAR ! dimension list: include band + INTEGER(I4B), DIMENSION(4) :: PVAR ! dimension list: include param + integer(i4b) :: ib ! loop through bands + integer(i4b) :: ip ! loop through parameters INTEGER(I4B) :: IVAR ! loop through variables INTEGER(I4B) :: IVAR_ID ! variable ID - INTEGER(I4B) :: CHID ! char position dimension id - INTEGER(I4B),parameter :: TDIMS=2 ! char position dimension id - INTEGER(I4B) :: TXDIMS(TDIMS) ! variable shape - INTEGER(I4B) :: TSTART(TDIMS), TCOUNT(TDIMS) - include 'netcdf.inc' ! use netCDF libraries ! --------------------------------------------------------------------------------------- CALL VARDESCRIBE() ! get list of variable descriptions ! --------------------------------------------------------------------------------------- -! put file in define mode + + ! put file in define mode print *, 'Create NetCDF file for runs:' PRINT *, FNAME_NETCDF_RUNS IERR = NF_CREATE(TRIM(FNAME_NETCDF_RUNS),NF_CLOBBER,ncid_out); CALL HANDLE_ERR(IERR) - !IERR = NF_OPEN(TRIM(FNAME_NETCDF_RUNS),NF_WRITE,ncid_out); CALL HANDLE_ERR(IERR) - !IERR = NF_REDEF(ncid_out); CALL HANDLE_ERR(IERR) ! define dimensions - IERR = NF_DEF_DIM(ncid_out,'time',NF_UNLIMITED,NTIM_DIM); CALL HANDLE_ERR(IERR) !record dimension (unlimited length) - IERR = NF_DEF_DIM(ncid_out,'longitude',nSpat1,lon_dim); CALL HANDLE_ERR(IERR) - IERR = NF_DEF_DIM(ncid_out,'latitude',nSpat2,lat_dim); CALL HANDLE_ERR(IERR) - IF(.NOT.GRID_FLAG)THEN - IERR = NF_DEF_DIM(ncid_out,'param_set',NPSET,param_dim); CALL HANDLE_ERR(IERR) - ENDIF - - - ! define character-position dimension for strings of max length 40 - !IERR = NF_DEF_DIM(ncid_out, "chid", 40, CHID); CALL HANDLE_ERR(IERR) - - ! define a character-string variable - ! TXDIMS(1) = CHID ! character-position dimension first - ! TXDIMS(2) = NTIM_DIM ! record dimension ID - ! IERR = NF_DEF_VAR(ncid_out, 'param_set',NF_CHAR, TDIMS, TXDIMS, param_dim); CALL HANDLE_ERR(IERR) - - ! retrieve ID for the model and parameter dimensions - !IERR = NF_INQ_DIMID(ncid_out,'par',NPAR_DIM); CALL HANDLE_ERR(IERR) - !IERR = NF_INQ_DIMID(ncid_out,'mod',NMOD_DIM); CALL HANDLE_ERR(IERR) - - ! assign dimensions to indices: for efficiency reasons, param_dim should be - ! last, because it varies the slowest, but the NetCDF standard imposes - ! the unlimited dimension to be last. - - IF(.NOT.GRID_FLAG)THEN - allocate(TVAR(4)) - TVAR = (/lon_dim,lat_dim,param_dim,NTIM_DIM/) - ELSE - allocate(TVAR(3)) - TVAR = (/lon_dim,lat_dim,NTIM_DIM/) ! no parameter dimension in grid mode - ENDIF + IERR = NF_DEF_DIM(ncid_out, 'time', NF_UNLIMITED, NTIM_DIM); CALL HANDLE_ERR(IERR) !record dimension (unlimited length) + IERR = NF_DEF_DIM(ncid_out, 'band', n_bands, band_dim); CALL HANDLE_ERR(IERR) + IERR = NF_DEF_DIM(ncid_out, 'param', NUMPAR, par_dim); CALL HANDLE_ERR(IERR) + IERR = NF_DEF_DIM(ncid_out, 'longitude', nSpat1, lon_dim); CALL HANDLE_ERR(IERR) + IERR = NF_DEF_DIM(ncid_out, 'latitude', nSpat2, lat_dim); CALL HANDLE_ERR(IERR) + + ! define dimension vector + TVAR = (/lon_dim, lat_dim, NTIM_DIM/) + PVAR = (/lon_dim, lat_dim, par_dim, NTIM_DIM/) + EVAR = (/lon_dim, lat_dim, band_dim, NTIM_DIM/) ! define time-varying output variables DO IVAR=1,NOUTVAR @@ -105,40 +101,31 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,NPSET,NTIM) ! uncomment variables that should be written to output file IF (Q_ONLY) THEN WRITE_VAR=.FALSE. - !IF (TRIM(VNAME(IVAR)).EQ.'ppt') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'pet') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'obsq') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'evap_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'evap_2') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. + IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'watr_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'watr_2') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'swe_tot') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'qsurf') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'oflow_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'qintf_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'oflow_2') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'qbase_2') WRITE_VAR=.TRUE. IF (.NOT.WRITE_VAR) CYCLE ! start new iteration of do loop, i.e. skip writting variable ENDIF ! write the variable - IF(.NOT.GRID_FLAG)THEN - IERR = NF_DEF_VAR(ncid_out,TRIM(VNAME(IVAR)),NF_REAL,4,TVAR,IVAR_ID); CALL HANDLE_ERR(IERR) + if(isBand(iVar))then + IERR = NF_DEF_VAR(ncid_out,TRIM(VNAME(IVAR)),NF_REAL,4,EVAR,IVAR_ID); CALL HANDLE_ERR(IERR) ELSE IERR = NF_DEF_VAR(ncid_out,TRIM(VNAME(IVAR)),NF_REAL,3,TVAR,IVAR_ID); CALL HANDLE_ERR(IERR) ENDIF - - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',LEN_TRIM(LNAME(IVAR)),TRIM(LNAME(IVAR))) - CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',LEN_TRIM(VUNIT(IVAR)),TRIM(VUNIT(IVAR))) - CALL HANDLE_ERR(IERR) - !IERR = NF_DEF_VAR_FILL(ncid_out,IVAR_ID,0,NA_VALUE) ! define _FillValue for NetCDF4 files only + ! define missing value NA_VALUE_OUT_MSP=NA_VALUE_OUT - IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_FLOAT,1,NA_VALUE_OUT_MSP) - CALL HANDLE_ERR(IERR) + + ! write metadata + IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',LEN_TRIM(LNAME(IVAR)),TRIM(LNAME(IVAR))); CALL HANDLE_ERR(IERR) + IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',LEN_TRIM(VUNIT(IVAR)),TRIM(VUNIT(IVAR))); CALL HANDLE_ERR(IERR) + IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_FLOAT,1,NA_VALUE_OUT_MSP); CALL HANDLE_ERR(IERR) + + ! define the parameter sensitivity for each flux: extra variable + if(isFlux(iVar))then + IERR = NF_DEF_VAR(ncid_out,TRIM(VNAME(IVAR))//'__dFlux_dParam',NF_REAL,4,PVAR,IVAR_ID); CALL HANDLE_ERR(IERR) + IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_FLOAT,1,NA_VALUE_OUT_MSP); CALL HANDLE_ERR(IERR) + endif END DO ! ivar @@ -157,23 +144,24 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,NPSET,NTIM) ierr = nf_put_att_text(ncid_out,ivar_id,'units',8,'degreesE'); call handle_err(ierr) ierr = nf_put_att_text(ncid_out,ivar_id,'axis',1,'X'); call handle_err(ierr) - IF(.NOT.GRID_FLAG)THEN - ! define the param_set variable - ierr = nf_def_var(ncid_out,'param_set',nf_char,1,(/param_dim/),ivar_id); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'units',1,'-'); call handle_err(ierr) - ENDIF + ! define the parameter set variable + ierr = nf_def_var(ncid_out,'param',nf_int,1,(/par_dim/),ivar_id); call handle_err(ierr) + ierr = nf_put_att_text(ncid_out,ivar_id,'units',1,'-'); call handle_err(ierr) - ! add global attributes - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "software", len("FUSE"), "FUSE"); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_version", len_trim(FUSE_VERSION), trim(FUSE_VERSION)); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_build_time", len_trim(FUSE_BUILDTIME), trim(FUSE_BUILDTIME)); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_branch", len_trim(FUSE_GITBRANCH), trim(FUSE_GITBRANCH)); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_hash", len_trim(FUSE_GITHASH), trim(FUSE_GITHASH)); call HANDLE_ERR(ierr) + ! define the band variable + ierr = nf_def_var(ncid_out,'band',nf_int,1,(/band_dim/),ivar_id); call handle_err(ierr) + ierr = nf_put_att_text(ncid_out,ivar_id,'units',1,'-'); call handle_err(ierr) + + ! add global attributes + ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "software", len("FUSE"), "FUSE"); call HANDLE_ERR(ierr) + ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_version", len_trim(FUSE_VERSION), trim(FUSE_VERSION)); call HANDLE_ERR(ierr) + ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_build_time", len_trim(FUSE_BUILDTIME), trim(FUSE_BUILDTIME)); call HANDLE_ERR(ierr) + ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_branch", len_trim(FUSE_GITBRANCH), trim(FUSE_GITBRANCH)); call HANDLE_ERR(ierr) + ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_hash", len_trim(FUSE_GITHASH), trim(FUSE_GITHASH)); call HANDLE_ERR(ierr) ! end definitions IERR = NF_ENDDEF(ncid_out); call handle_err(ierr) - !IERR = NF_OPEN(TRIM(FNAME_NETCDF),NF_WRITE,ncid_out); CALL HANDLE_ERR(IERR) latitude_msp=latitude ! convert to actual single precision IERR = NF_INQ_VARID(ncid_out,'latitude',IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID IERR = NF_PUT_VARA_REAL(ncid_out,IVAR_ID,1,nspat2,latitude_msp); CALL HANDLE_ERR(IERR) ! write data @@ -182,26 +170,20 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,NPSET,NTIM) IERR = NF_INQ_VARID(ncid_out,'longitude',IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID IERR = NF_PUT_VARA_REAL(ncid_out,IVAR_ID,1,nspat1,longitude_msp); CALL HANDLE_ERR(IERR) ! write data - !TSTART(1) = 1 ! start at beginning of variable - !TSTART(2) = 1 ! record number to write - !TCOUNT(1) = 20 ! number of chars to write - !TCOUNT(2) = 1 ! only write one record - - !IERR = NF_INQ_VARID(ncid_out,'param_set',IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID - !IERR = NF_PUT_VARA_TEXT(ncid_out,IVAR_ID,1,NPSET,name_psets); CALL HANDLE_ERR(IERR) ! write data - !IERR = NF_PUT_VARA_TEXT(ncid_out,IVAR_ID,TSTART,TCOUNT,name_psets); CALL HANDLE_ERR(IERR) ! write data + band_i = [(ib, ib=1,n_bands)] ! 1..n_bands + ierr = NF_INQ_VARID(ncid_out, 'band', ivar_id); call HANDLE_ERR(ierr) + ierr = NF_PUT_VARA_INT(ncid_out, ivar_id, (/1/), (/n_bands/), band_i); call HANDLE_ERR(ierr) - IF(.NOT.GRID_FLAG)THEN - PRINT *, 'NetCDF file for model runs defined with dimensions', nSpat1 , nSpat2, NPSET, NTIM - ELSE - PRINT *, 'NetCDF file for model runs defined with dimensions', nSpat1 , nSpat2, NTIM - ENDIF + param_i = [(ip, ip=1,NUMPAR)] ! 1..NUMPAR + ierr = NF_INQ_VARID(ncid_out, 'param', ivar_id); call HANDLE_ERR(ierr) + ierr = NF_PUT_VARA_INT(ncid_out, ivar_id, (/1/), (/NUMPAR/), param_i); call HANDLE_ERR(ierr) + PRINT *, 'NetCDF file for model runs defined with dimensions', nSpat1 , nSpat2, n_bands, NUMPAR, NTIM - IERR = NF_ENDDEF(ncid_out) + ! close output file IERR = NF_CLOSE(ncid_out) - deallocate(TVAR) + ! --------------------------------------------------------------------------------------- + END SUBROUTINE DEF_OUTPUT -! --------------------------------------------------------------------------------------- -END SUBROUTINE DEF_OUTPUT +END MODULE DEF_OUTPUT_MODULE diff --git a/build/FUSE_SRC/netcdf/put_output.f90 b/build/FUSE_SRC/netcdf/put_output.f90 index ed8bae8..aaedb82 100644 --- a/build/FUSE_SRC/netcdf/put_output.f90 +++ b/build/FUSE_SRC/netcdf/put_output.f90 @@ -1,190 +1,234 @@ -SUBROUTINE PUT_OUTPUT(iSpat1,iSpat2,ITIM,IMOD,IPAR) +MODULE PUT_OUTPUT_MODULE + USE nrtype ! variable types, etc. + + implicit none + + private + public :: PUT_GOUTPUT_3D + + contains + + SUBROUTINE PUT_GOUTPUT_3D(istart_sim,istart_in,numtim) ! --------------------------------------------------------------------------------------- ! Creator: ! -------- - ! Martyn Clark, 2007 + ! Nans Addor, based on Martyn Clark's 2007 PUT_OUTPUT + ! Modified by Marytn Clark to use the elevation band dimension and add parameter derivatives, 12/2025 ! --------------------------------------------------------------------------------------- ! Purpose: ! -------- - ! write NetCDF output files + ! write a 3D (or 4D) data structure to the NetCDF output file ! --------------------------------------------------------------------------------------- - USE nrtype ! variable types, etc. - USE model_defn ! model definition (includes filename) - USE metaoutput ! metadata for time-varying model output - USE varextract_module ! interface for the function to extract variables - USE fuse_fileManager,only: Q_ONLY ! only write streamflow to output file? - USE multiforce,ONLY: timDat ! time data - USE multistate, only: ncid_out ! NetCDF output file ID + + ! subroutines + USE varextract_module, only: VAREXTRACT_3d ! interface for the function to extract variables + + ! data + USE model_defn, only: FNAME_NETCDF_RUNS ! model definition (includes filename) + USE metaoutput, only: NOUTVAR ! number of output variables + USE metaoutput, only: VNAME, LNAME, VUNIT ! metadata for all model variables + USE metaoutput, only: isBand ! logical flag to define vars with elevation dimension + USE multiparam, only: NUMPAR ! variables for parameters + USE multibands, only: MBANDS_VAR_4d, N_BANDS ! variables for elevation bands + USE multiforce, only: timDat,time_steps ! time data + USE multiforce, only: nspat1,nspat2,startSpat2 ! spatial dimensions + USE multiforce, only: gForce_3d ! test only + USE multiforce, only: GRID_FLAG ! .true. if distributed + USE globaldata, only: ncid_out ! NetCDF output file ID + USE fuse_fileManager, only: Q_ONLY ! only write streamflow to output file? IMPLICIT NONE + ! input - INTEGER(I4B), INTENT(IN) :: iSpat1 ! index of 1st spatial dimension - INTEGER(I4B), INTENT(IN) :: iSpat2 ! index of 2nd spatial dimension - INTEGER(I4B), INTENT(IN) :: ITIM ! time step index - INTEGER(I4B), INTENT(IN) :: IMOD ! model index - INTEGER(I4B), INTENT(IN) :: IPAR ! parameter set index + INTEGER(I4B), INTENT(IN) :: istart_sim ! index start time step relative to numtim_sim + INTEGER(I4B), INTENT(IN) :: istart_in ! index start time step relative to numtim_in - for time dimension + INTEGER(I4B), INTENT(IN) :: numtim ! number of time steps to write + ! internal - LOGICAL(LGT) :: WRITE_VAR ! used to denote if the variable is written - INTEGER(I4B) :: IERR ! error code - !INTEGER(I4B), DIMENSION(5) :: INDX ! indices for time series write - INTEGER(I4B), DIMENSION(3) :: INDX ! indices for time series write - INTEGER(I4B) :: IVAR ! loop through variables - REAL(SP) :: XVAR ! desired variable (SP NOT NECESSARILY SP) - REAL(MSP) :: AVAR ! desired variable (SINGLE PRECISION) - REAL(MSP) :: tDat ! time data - INTEGER(I4B) :: IVAR_ID ! variable ID - INCLUDE 'netcdf.inc' ! use netCDF libraries - ! --------------------------------------------------------------------------------------- - ! open file - IERR = NF_OPEN(TRIM(FNAME_NETCDF_RUNS),NF_WRITE,ncid_out); CALL HANDLE_ERR(IERR) + LOGICAL(LGT) :: WRITE_VAR ! used to denote if the variable is written + INTEGER(I4B) :: IERR ! error code + integer(i4b), dimension(3) :: start3 ! start indices: exclude elevation bands and parameters + integer(i4b), dimension(3) :: count3 ! count indices: exclude elevation bands and parameters + integer(i4b), dimension(4) :: start4_band ! start indices: include elevation bands + integer(i4b), dimension(4) :: count4_band ! count indices: include elevation bands + integer(i4b), dimension(4) :: start4_param ! start indices: include parameters + integer(i4b), dimension(4) :: count4_param ! count indices: include parameters + INTEGER(I4B) :: IVAR ! loop through variables + REAL(SP) :: XVAR ! desired variable (SP NOT NECESSARILY SP) + REAL(MSP) :: AVAR ! desired variable (SINGLE PRECISION) + REAL(SP), DIMENSION(nspat1,nspat2,numtim) :: XVAR_3d ! desired 3-d variable (SINGLE PRECISION) + REAL(MSP), DIMENSION(nspat1,nspat2,numtim) :: AVAR_3d ! desired 3-d variable (SINGLE PRECISION) + REAL(SP), DIMENSION(nspat1,nspat2,n_bands,numtim) :: XVAR_4d_band ! desired 4-d variable (SINGLE PRECISION) + REAL(MSP), DIMENSION(nspat1,nspat2,n_bands,numtim) :: AVAR_4d_band ! desired 4-d variable (SINGLE PRECISION) + REAL(SP), DIMENSION(nspat1,nspat2,NUMPAR,numtim) :: XVAR_4d_param ! desired 4-d variable (SINGLE PRECISION) + REAL(MSP), DIMENSION(nspat1,nspat2,NUMPAR,numtim) :: AVAR_4d_param ! desired 4-d variable (SINGLE PRECISION) + REAL(MSP), DIMENSION(numtim) :: tDat ! time data + REAL(SP), DIMENSION(numtim) :: time_steps_sub ! time data + INTEGER(I4B) :: IVAR_ID ! variable ID + + INCLUDE 'netcdf.inc' ! use netCDF libraries + + + ! define dimension list (exclude elevation bands) + ! NOTE: if enabling parallel output you need 1,startSpat2 instead of 1,1 below + start3 = (/1,1,istart_sim/) + count3 = (/nspat1,nspat2,numtim/) + + ! define dimension list (include elevation bands) + start4_band = (/1,1,1,istart_sim/) + count4_band = (/nspat1,nspat2,n_bands,numtim/) + + ! define dimension list (include parameter derivatives) + start4_param = (/1,1,1,istart_sim/) + count4_param = (/nspat1,nspat2,n_bands,numtim/) - ! define indices for model output - INDX = (/iSpat1,iSpat2,ITIM/) + ! open file + IERR = NF_OPEN(TRIM(FNAME_NETCDF_RUNS),NF_WRITE,ncid_out) + CALL HANDLE_ERR(IERR) - ! loop through time-varying model output + ! loop through variables with time-varying model output DO IVAR=1,NOUTVAR - ! check if there is a need to write the variable - see also def_output - IF (Q_ONLY) THEN - WRITE_VAR=.FALSE. - !IF (TRIM(VNAME(IVAR)).EQ.'ppt') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'pet') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'obsq') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'evap_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'evap_2') WRITE_VAR=.TRUE. - IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'watr_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'watr_2') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'swe_tot') WRITE_VAR=.TRUE. - IF (.NOT.WRITE_VAR) CYCLE - ENDIF + ! check if there is a need to write the variable - see also def_output + IF (Q_ONLY) THEN + WRITE_VAR=.FALSE. + IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. + IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. + IF (.NOT.WRITE_VAR) CYCLE ! start new iteration of do loop, i.e. skip writting variable + ENDIF - ! write the variable - XVAR = VAREXTRACT(VNAME(IVAR)); AVAR=XVAR ! get variable ivar - IERR = NF_INQ_VARID(ncid_out,TRIM(VNAME(IVAR)),IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID - IERR = NF_PUT_VAR1_REAL(ncid_out,IVAR_ID,INDX,AVAR); CALL HANDLE_ERR(IERR) ! write data + ! get variable ID + IERR = NF_INQ_VARID(ncid_out,TRIM(VNAME(IVAR)),IVAR_ID) + CALL HANDLE_ERR(IERR) + + ! 3-d variables + if(.not.isBand(iVar))then + + ! write 3-d matrix + XVAR_3d = VAREXTRACT_3d(VNAME(IVAR), nspat1, nspat2, numtim); AVAR_3d = XVAR_3d ! get variable and convert format + IERR = NF_PUT_VARA_REAL(ncid_out, IVAR_ID, start3, count3, AVAR_3d) ! write data + CALL HANDLE_ERR(IERR) + + ! 4-d variables + else + + ! extract variable from 4-D elevation band matrix + select case (trim(VNAME(IVAR))) + case ('swe_z' ); AVAR_4d_band = MBANDS_VAR_4d(:,:,:,1:numtim)%SWE + case ('snwacml_z'); AVAR_4d_band = MBANDS_VAR_4d(:,:,:,1:numtim)%SNOWACCMLTN + case ('snwmelt_z'); AVAR_4d_band = MBANDS_VAR_4d(:,:,:,1:numtim)%SNOWMELT + case default; stop "put_output.f90: cannot identify elevation band variable: "//trim(VNAME(IVAR)) + end select + + ! write 4-d matrix for elevation bands + IERR = NF_PUT_VARA_REAL(ncid_out, IVAR_ID, START4_band, COUNT4_band, AVAR_4d_band) + call HANDLE_ERR(IERR) + + endif ! (switch between 3-d and 4-d variables) + + ! ! write the parameter sensitivity for each flux: extra variable + ! if(isFlux(iVar))then + ! AVAR_4d_param = fuseStruct%df_dPar(:) + ! endif END DO ! (ivar) ! write the time - tDat = timDat%dtime ! convert to actual single precision - ierr = nf_inq_varid(ncid_out,'time',ivar_id); CALL handle_err(ierr) ! get variable ID for time - ierr = nf_put_var1_real(ncid_out,ivar_id,(/itim/),tDat); CALL handle_err(ierr) ! write time variable + time_steps_sub = time_steps(istart_in:(istart_in+numtim-1)) ! extract time for subperiod + tDat = time_steps_sub ! convert to actual single precision + ierr = nf_inq_varid(ncid_out,'time',ivar_id); CALL handle_err(ierr) ! get variable ID for time + ierr = nf_put_vara_real(ncid_out,ivar_id,(/istart_sim/),(/numtim/),tDat); CALL handle_err(ierr) ! write time variable ! close NetCDF file IERR = NF_CLOSE(ncid_out) -END SUBROUTINE PUT_OUTPUT + END SUBROUTINE PUT_GOUTPUT_3D + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + SUBROUTINE PUT_OUTPUT(iSpat1, iSpat2, ITIM) -SUBROUTINE PUT_GOUTPUT_3D(istart_sim,istart_in,numtim,IPSET) ! --------------------------------------------------------------------------------------- ! Creator: ! -------- - ! Nans Addor, based on Martyn Clark's 2007 PUT_OUTPUT + ! Martyn Clark, 2007 ! --------------------------------------------------------------------------------------- ! Purpose: ! -------- - ! write a 3D data structure to the NetCDF output file + ! write NetCDF output files ! --------------------------------------------------------------------------------------- - USE nrtype ! variable types, etc. - USE model_defn ! model definition (includes filename) - USE metaoutput ! metadata for time-varying model output - USE varextract_module ! interface for the function to extract variables - USE fuse_fileManager,only: Q_ONLY ! only write streamflow to output file? - - USE multiforce, ONLY: timDat,time_steps ! time data - USE multistate, only: ncid_out ! NetCDF output file ID - USE multiforce, ONLY: nspat1,nspat2,startSpat2 ! spatial dimensions - USE multiforce, ONLY: gForce_3d ! test only - USE multiforce, only: GRID_FLAG ! .true. if distributed - IMPLICIT NONE + ! subroutines + USE varextract_module, only: VAREXTRACT ! interface for the function to extract variables + + ! data + USE model_defn, only: FNAME_NETCDF_RUNS ! model definition (includes filename) + USE metaoutput, only: NOUTVAR ! number of output variables + USE metaoutput, only: VNAME, LNAME, VUNIT ! metadata for all model variables + USE metaoutput, only: isBand ! logical flag to define vars with elevation dimension + USE multibands, only: MBANDS, N_BANDS ! variables for elevation bands + USE multiforce, only: timDat,time_steps ! time data + USE multiforce, only: nspat1,nspat2,startSpat2 ! spatial dimensions + USE multiforce, only: gForce_3d ! test only + USE multiforce, only: GRID_FLAG ! .true. if distributed + USE globaldata, only: ncid_out ! NetCDF output file ID + USE fuse_fileManager, only: Q_ONLY ! only write streamflow to output file? + IMPLICIT NONE ! input - INTEGER(I4B), INTENT(IN) :: istart_sim ! index start time step relative to numtim_sim - INTEGER(I4B), INTENT(IN) :: istart_in ! index start time step relative to numtim_in - for time dimension - INTEGER(I4B), INTENT(IN) :: numtim ! number of time steps to write - INTEGER(I4B), INTENT(IN) :: IPSET ! parameter set index - + INTEGER(I4B), INTENT(IN) :: iSpat1 ! index of 1st spatial dimension + INTEGER(I4B), INTENT(IN) :: iSpat2 ! index of 2nd spatial dimension + INTEGER(I4B), INTENT(IN) :: ITIM ! time step index ! internal LOGICAL(LGT) :: WRITE_VAR ! used to denote if the variable is written INTEGER(I4B) :: IERR ! error code - INTEGER(I4B), DIMENSION(:), ALLOCATABLE :: IND_START ! start indices - INTEGER(I4B), DIMENSION(:), ALLOCATABLE :: IND_COUNT ! count indices + !INTEGER(I4B), DIMENSION(5) :: INDX ! indices for time series write + INTEGER(I4B), DIMENSION(3) :: INDX ! indices for time series write INTEGER(I4B) :: IVAR ! loop through variables REAL(SP) :: XVAR ! desired variable (SP NOT NECESSARILY SP) REAL(MSP) :: AVAR ! desired variable (SINGLE PRECISION) - REAL(SP), DIMENSION(nspat1,nspat2,numtim) :: XVAR_3d ! desired variable (SINGLE PRECISION) - REAL(MSP), DIMENSION(nspat1,nspat2,numtim) :: AVAR_3d ! desired variable (SINGLE PRECISION) - REAL(MSP), DIMENSION(:), ALLOCATABLE :: tDat ! time data - REAL(SP), DIMENSION(:), ALLOCATABLE :: time_steps_sub ! time data + REAL(MSP) :: tDat ! time data INTEGER(I4B) :: IVAR_ID ! variable ID INCLUDE 'netcdf.inc' ! use netCDF libraries - + ! --------------------------------------------------------------------------------------- + ! open file IERR = NF_OPEN(TRIM(FNAME_NETCDF_RUNS),NF_WRITE,ncid_out); CALL HANDLE_ERR(IERR) ! define indices for model output - ! if enabling parallel output you need 1,startSpat2 instead of 1,1 below - - IF(.NOT.GRID_FLAG)THEN - allocate(IND_START(4),IND_COUNT(4)) - IND_START = (/1,1,IPSET,istart_sim/) ! the indices start at 1, i.e. first element in (1, 1, ..., 1) - IND_COUNT = (/nspat1,nspat2,1,numtim/) ! third element is 1 because we only write results for one parameter set at a time - ELSE - allocate(IND_START(3),IND_COUNT(3)) - IND_START = (/1,1,istart_sim/) ! no parameter dimension in grid mode - IND_COUNT = (/nspat1,nspat2,numtim/) - ENDIF - - PRINT *, 'IND_START=', IND_START - PRINT *, 'IND_COUNT=', IND_COUNT + INDX = (/iSpat1, iSpat2, ITIM/) ! loop through time-varying model output DO IVAR=1,NOUTVAR - ! check if there is a need to write the variable - see also def_output - IF (Q_ONLY) THEN - WRITE_VAR=.FALSE. - !IF (TRIM(VNAME(IVAR)).EQ.'ppt') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'pet') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'obsq') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'evap_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'evap_2') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. - IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'watr_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'watr_2') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'swe_tot') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'qsurf') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'oflow_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'qintf_1') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'oflow_2') WRITE_VAR=.TRUE. - !IF (TRIM(VNAME(IVAR)).EQ.'qbase_2') WRITE_VAR=.TRUE. - IF (.NOT.WRITE_VAR) CYCLE ! start new iteration of do loop, i.e. skip writting variable - ENDIF + ! check if there is a need to write the variable - see also def_output + IF (Q_ONLY) THEN + WRITE_VAR=.FALSE. + IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. + IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. + IF (.NOT.WRITE_VAR) CYCLE + ENDIF - ! write the variable - XVAR_3d = VAREXTRACT_3d(VNAME(IVAR),numtim) ! get variable - AVAR_3d = XVAR_3d ! convert format - IERR = NF_INQ_VARID(ncid_out,TRIM(VNAME(IVAR)),IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID - IERR = NF_PUT_VARA_REAL(ncid_out,IVAR_ID,IND_START,IND_COUNT,AVAR_3d); CALL HANDLE_ERR(IERR) ! write data + ! write the variable + XVAR = VAREXTRACT(VNAME(IVAR)); AVAR=XVAR ! get variable ivar + IERR = NF_INQ_VARID(ncid_out,TRIM(VNAME(IVAR)),IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID + IERR = NF_PUT_VAR1_REAL(ncid_out,IVAR_ID,INDX,AVAR); CALL HANDLE_ERR(IERR) ! write data END DO ! (ivar) ! write the time - allocate(tDat(numtim),time_steps_sub(numtim)) - - time_steps_sub = time_steps(istart_in:(istart_in+numtim-1)) ! extract time for subperiod - tDat = time_steps_sub ! convert to actual single precision - ierr = nf_inq_varid(ncid_out,'time',ivar_id); CALL handle_err(ierr) ! get variable ID for time - ierr = nf_put_vara_real(ncid_out,ivar_id,(/istart_sim/),(/numtim/),tDat); CALL handle_err(ierr) ! write time variable + tDat = timDat%dtime ! convert to actual single precision + ierr = nf_inq_varid(ncid_out,'time',ivar_id); CALL handle_err(ierr) ! get variable ID for time + ierr = nf_put_var1_real(ncid_out,ivar_id,(/itim/),tDat); CALL handle_err(ierr) ! write time variable ! close NetCDF file IERR = NF_CLOSE(ncid_out) - deallocate(tDat,time_steps_sub,IND_START,IND_COUNT) - -END SUBROUTINE PUT_GOUTPUT_3D + END SUBROUTINE PUT_OUTPUT + +END MODULE PUT_OUTPUT_MODULE diff --git a/build/FUSE_SRC/netcdf/put_params.f90 b/build/FUSE_SRC/netcdf/put_params.f90 index 46430b9..2c4401c 100644 --- a/build/FUSE_SRC/netcdf/put_params.f90 +++ b/build/FUSE_SRC/netcdf/put_params.f90 @@ -1,80 +1,95 @@ -SUBROUTINE PUT_PARAMS(IPAR) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007 -! Modified by Nans Addor to include snow module -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! write NetCDF output files -- model parameters -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -USE model_defn ! model definition structures (includes filename) -USE model_defnames ! define variable names -USE metaparams ! metadata for model parameters -USE multistats, ONLY:MSTATS ! provide access to error message -USE parextract_module ! extract parameters -IMPLICIT NONE -! input -INTEGER(I4B), INTENT(IN) :: IPAR ! parameter set index -! internal -INTEGER(I4B) :: IERR,NCID ! error code; NetCDF ID -INTEGER(I4B), DIMENSION(1) :: INDX ! indices for parameter write -INTEGER(I4B) :: IVAR ! loop through parameters -REAL(SP) :: XPAR ! desired parameter -REAL(MSP) :: APAR ! convert to SP (need for SP write) -INTEGER(I4B) :: IVAR_ID ! variable ID -INTEGER(I4B), PARAMETER :: NDESC=9 ! number of model descriptors - TODO: THIS SHOULDN'T BE HARD-CODED -INTEGER(I4B), PARAMETER :: NCHAR=10 ! length of model descriptors - TODO: THIS SHOULDN'T BE HARD-CODED -INTEGER(I4B), DIMENSION(3) :: ISTART ! starting position for array write -INTEGER(I4B), DIMENSION(3) :: ICOUNT ! count for array write -CHARACTER(LEN=10) :: TXTVEC ! single model descriptor -include 'netcdf.inc' ! use netCDF libraries -! --------------------------------------------------------------------------------------- +MODULE PUT_PARAMS_MODULE -! open file -IERR = NF_OPEN(TRIM(FNAME_NETCDF_PARA),NF_WRITE,NCID); CALL HANDLE_ERR(IERR) + USE nrtype ! variable types, etc. - ! define indices for model output - INDX = (/IPAR/) + implicit none - ! loop through model parameters - DO IVAR=1,NOUTPAR ! NOUTPAR is stored in module metaparams + private + public :: PUT_PARAMS - XPAR = PAREXTRACT(PNAME(IVAR)); APAR=XPAR ! get parameter PNAME(IVAR) - IERR = NF_INQ_VARID(NCID,TRIM(PNAME(IVAR)),IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID - IERR = NF_PUT_VAR1_REAL(NCID,IVAR_ID,INDX,APAR); CALL HANDLE_ERR(IERR) ! write data + contains - END DO ! (ivar) + SUBROUTINE PUT_PARAMS(IPAR) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Nans Addor to include snow module + ! Modified by Martyn Clark to write snow bands as a vector, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! write NetCDF output files -- model parameters + ! --------------------------------------------------------------------------------------- + USE model_defn, only: FNAME_NETCDF_PARA ! model definition structures (includes filename) + USE metaparams, only: NOUTPAR ! number of model parameters + USE metaparams, only: PNAME, PDESC, PUNIT ! metadata for all model parameters + USE metaparams, only: isBand ! logical flag to define vars with elevation dimension + USE multibands, only: MBANDS, N_BANDS ! information for elevation bands + USE parextract_module ! extract parameters + IMPLICIT NONE + ! input + INTEGER(I4B), INTENT(IN) :: IPAR ! parameter set index + ! internal + INTEGER(I4B) :: IERR,NCID ! error code; NetCDF ID + INTEGER(I4B), DIMENSION(1) :: INDX ! indices for parameter write + integer(i4b), dimension(2) :: start2 ! 2-d start vector + integer(i4b), dimension(2) :: count2 ! 2-d count vector + INTEGER(I4B) :: IVAR ! loop through parameters + REAL(SP) :: XPAR ! desired parameter + REAL(MSP) :: APAR ! convert to SP (need for SP write) + integer(i4b) :: ib ! index of elevation bands + REAL(SP) , DIMENSION(N_BANDS) :: XVEC ! desired vector + REAL(MSP) , DIMENSION(N_BANDS) :: AVEC ! convert to SP (need for SP write) + INTEGER(I4B) :: IVAR_ID ! variable ID + include 'netcdf.inc' ! use netCDF libraries + ! --------------------------------------------------------------------------------------- + + ! open file + IERR = NF_OPEN(TRIM(FNAME_NETCDF_PARA),NF_WRITE,NCID) + CALL HANDLE_ERR(IERR) + + ! define indices for model output + INDX = (/IPAR/) + + ! loop through model parameters + DO IVAR=1,NOUTPAR ! NOUTPAR is stored in module metaparams + + ! get variable ID + IERR = NF_INQ_VARID(NCID,TRIM(PNAME(IVAR)),IVAR_ID) + CALL HANDLE_ERR(IERR) + + ! standard scalar parameters + if(.not.isBand(iVar))then + + ! extract parameter and write data + XPAR = PAREXTRACT(PNAME(IVAR)); APAR=XPAR ! get parameter PNAME(IVAR) + IERR = NF_PUT_VAR1_REAL(NCID, IVAR_ID, INDX, APAR); CALL HANDLE_ERR(IERR) ! write data + + ! elevation band parameters + else + + ! extract vector + select case (trim(PNAME(IVAR))) + case ('AF') ; xVec(1:n_bands) = [ (MBANDS(ib)%info%AF, ib=1,n_bands) ] + case ('Z_MID'); xVec(1:n_bands) = [ (MBANDS(ib)%info%Z_MID, ib=1,n_bands) ] + case default; stop "put_params.f90: cannot identify elevation band variable" + end select + aVec = xVec ! use MSP to write single precision + + ! write row at par=IPAR + start2 = (/ IPAR, 1 /) + count2 = (/ 1, n_bands /) + IERR = NF_PUT_VARA_REAL(NCID, IVAR_ID, start2, count2, aVec(1:n_bands)) + CALL HANDLE_ERR(IERR) + + endif ! elevation band switch + + END DO ! (ivar) + + ! close NetCDF file + IERR = NF_CLOSE(NCID) + ! --------------------------------------------------------------------------------------- + END SUBROUTINE PUT_PARAMS - ! put model description - !IERR = NF_INQ_VARID(NCID,'model_description',IVAR_ID); CALL HANDLE_ERR(IERR) - - ! print *, 'Writing model decisions to this NetCDF file:', TRIM(FNAME_NETCDF) - ! - ! DO IVAR=1,NDESC - ! ! extract text string - ! IF (IVAR.EQ.1) TXTVEC = desc_int2str(SMODL%iRFERR) - ! IF (IVAR.EQ.2) TXTVEC = desc_int2str(SMODL%iARCH1) - ! IF (IVAR.EQ.3) TXTVEC = desc_int2str(SMODL%iARCH2) - ! IF (IVAR.EQ.4) TXTVEC = desc_int2str(SMODL%iQSURF) - ! IF (IVAR.EQ.5) TXTVEC = desc_int2str(SMODL%iQPERC) - ! IF (IVAR.EQ.6) TXTVEC = desc_int2str(SMODL%iESOIL) - ! IF (IVAR.EQ.7) TXTVEC = desc_int2str(SMODL%iQINTF) - ! IF (IVAR.EQ.8) TXTVEC = desc_int2str(SMODL%iQ_TDH) - ! IF (IVAR.EQ.9) TXTVEC = desc_int2str(SMODL%iSNOWM) - ! - ! ISTART = (/ 1,IVAR,IMOD/) ! starting position of array - ! ICOUNT = (/NCHAR, 1, 1/) ! number of array elements (one descriptor, one model) - ! IERR = NF_PUT_VARA_TEXT(NCID,IVAR_ID,ISTART,ICOUNT,TXTVEC); CALL HANDLE_ERR(IERR) - ! END DO - ! put error message - !ISTART = (/ 1,IMOD,IPAR/) ! starting position of array - !ICOUNT = (/LEN(MSTATS%ERR_MESSAGE), 1, 1/) ! number of array elements (one descriptor, one model) - !IERR = NF_INQ_VARID(NCID,'error_message',IVAR_ID); CALL HANDLE_ERR(IERR) - !IERR = NF_PUT_VARA_TEXT(NCID,IVAR_ID,ISTART,ICOUNT,MSTATS%ERR_MESSAGE); CALL HANDLE_ERR(IERR) -! close NetCDF file -IERR = NF_CLOSE(NCID) -! --------------------------------------------------------------------------------------- -END SUBROUTINE PUT_PARAMS +END MODULE PUT_PARAMS_MODULE diff --git a/build/FUSE_SRC/physics/conserve_clamp.f90 b/build/FUSE_SRC/physics/conserve_clamp.f90 new file mode 100644 index 0000000..3c119ad --- /dev/null +++ b/build/FUSE_SRC/physics/conserve_clamp.f90 @@ -0,0 +1,303 @@ +module conserve_clamp_module + + ! data types + use nrtype ! variable types, etc. + use work_types, only: fuse_work ! fuse work structure + USE model_defn ! model definition structure + USE model_defnames + USE model_numerix + + implicit none + + private + public :: conserve_clamp + + contains + + SUBROUTINE conserve_clamp(fuseStruct,DT,ERROR_FLAG) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2009 + ! Modified by Martyn Clark to pass fuse work data structure, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Ensure states are within bounds, and disaggregate fluxes if necessary + ! - This routine handles the very rare case (less than one-in-a-million) where + ! the implicit Euler solver fails to converge + ! --------------------------------------------------------------------------------------- + IMPLICIT NONE + ! input/output + type(fuse_work) , intent(inout) :: fuseStruct ! fuse work structure + REAL(SP), INTENT(IN) :: DT ! time step + LOGICAL(LGT), INTENT(OUT) :: ERROR_FLAG ! .TRUE. if extrapolation error + ! internal + REAL(SP) :: XMIN ! very small number + INTEGER(I4B) :: ISTT ! loop through model states + REAL(SP) :: ERROR_LOSS ! error (L/T) + REAL(SP) :: TOTAL_LOSS ! total loss (L/T) + ! --------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + M_FLUX => fuseStruct%flux , & ! fluxes + BSTATE => fuseStruct%state0 , & ! state variables (start of step) + ESTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! --------------------------------------------------------------------------------------- + ERROR_FLAG=.FALSE. ! initialize with no extrapolation error + ! --------------------------------------------------------------------------------------- + XMIN = FRACSTATE_MIN ! used to avoid zero derivatives + ! --------------------------------------------------------------------------------------- + DO ISTT=1,NSTATE + if (M_FLUX%QSURF.LT.0._sp) print *, 'start ', desc_int2str(cstate(istt)%isname), M_FLUX%QSURF + ERROR_LOSS = 0._SP ! initialize state error + SELECT CASE(CSTATE(ISTT)%iSNAME) + ! --------------------------------------------------------------------------------------- + ! (1) FIX STATES IN THE UPPER LAYER + ! ------------------------------------------------------------------------------------- + CASE (iopt_TENS1A) + IF (ESTATE%TENS_1A.LT.XMIN*DPARAM%MAXTENS_1A) THEN ! too much drainage + ERROR_LOSS = (ESTATE%TENS_1A - XMIN*DPARAM%MAXTENS_1A)/DT ! error (L/T) + TOTAL_LOSS = M_FLUX%QSURF + M_FLUX%EVAP_1A ! total loss (L/T) + M_FLUX%QSURF = M_FLUX%QSURF + (M_FLUX%QSURF /TOTAL_LOSS)*ERROR_LOSS + M_FLUX%EVAP_1A = M_FLUX%EVAP_1A + (M_FLUX%EVAP_1A/TOTAL_LOSS)*ERROR_LOSS + ESTATE%TENS_1A = XMIN*DPARAM%MAXTENS_1A ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%TENS_1A.GT.DPARAM%MAXTENS_1A) THEN ! too much input + ERROR_LOSS = (ESTATE%TENS_1A - DPARAM%MAXTENS_1A)/DT + M_FLUX%RCHR2EXCS = M_FLUX%RCHR2EXCS + ERROR_LOSS + ESTATE%TENS_1A = DPARAM%MAXTENS_1A ! (correct state) + ESTATE%TENS_1B = BSTATE%TENS_1B + & ! (correct subsequent states) + (M_FLUX%RCHR2EXCS - M_FLUX%EVAP_1B - M_FLUX%TENS2FREE_1)*DT + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_TENS_1A = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + CASE (iopt_TENS1B) + IF (ESTATE%TENS_1B.LT.XMIN*DPARAM%MAXTENS_1B) THEN ! too much drainage + ERROR_LOSS = (ESTATE%TENS_1B - XMIN*DPARAM%MAXTENS_1B)/DT + M_FLUX%EVAP_1B = M_FLUX%EVAP_1B + ERROR_LOSS + ESTATE%TENS_1B = XMIN*DPARAM%MAXTENS_1B ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%TENS_1B.GT.DPARAM%MAXTENS_1B) THEN ! too much input + ERROR_LOSS = (ESTATE%TENS_1B - DPARAM%MAXTENS_1B)/DT + M_FLUX%TENS2FREE_1 = M_FLUX%TENS2FREE_1 + ERROR_LOSS + ESTATE%TENS_1B = DPARAM%MAXTENS_1B ! (correct state) + ESTATE%FREE_1 = BSTATE%FREE_1 + & ! (correct subsequent states) + (M_FLUX%TENS2FREE_1 - M_FLUX%QPERC_12 - M_FLUX%QINTF_1 - M_FLUX%OFLOW_1)*DT + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_TENS_1B = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + CASE (iopt_TENS_1) + IF (ESTATE%TENS_1.LT.XMIN*DPARAM%MAXTENS_1) THEN ! too much drainage + ERROR_LOSS = (ESTATE%TENS_1 - XMIN*DPARAM%MAXTENS_1)/DT ! error (L/T) + TOTAL_LOSS = M_FLUX%QSURF + M_FLUX%EVAP_1 ! total loss (L/T) + M_FLUX%QSURF = M_FLUX%QSURF + (M_FLUX%QSURF /TOTAL_LOSS)*ERROR_LOSS + M_FLUX%EVAP_1 = M_FLUX%EVAP_1 + (M_FLUX%EVAP_1/TOTAL_LOSS)*ERROR_LOSS + ESTATE%TENS_1 = XMIN*DPARAM%MAXTENS_1 ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%TENS_1.GT.DPARAM%MAXTENS_1) THEN ! too much input + ERROR_LOSS = (ESTATE%TENS_1 - DPARAM%MAXTENS_1)/DT + M_FLUX%TENS2FREE_1 = M_FLUX%TENS2FREE_1 + (ESTATE%TENS_1 - DPARAM%MAXTENS_1)/DT + ESTATE%TENS_1 = DPARAM%MAXTENS_1 ! (correct state) + ESTATE%FREE_1 = BSTATE%FREE_1 + & ! (correct subsequent states) + (M_FLUX%TENS2FREE_1 - M_FLUX%QPERC_12 - M_FLUX%QINTF_1 - M_FLUX%OFLOW_1)*DT + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_TENS_1 = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + CASE (iopt_FREE_1) + IF (ESTATE%FREE_1.LT.XMIN*DPARAM%MAXFREE_1) THEN ! too much drainage + ERROR_LOSS = (ESTATE%FREE_1 - XMIN*DPARAM%MAXFREE_1)/DT ! error (L/T) + TOTAL_LOSS = M_FLUX%QPERC_12 + M_FLUX%QINTF_1 ! total loss (L/T) + M_FLUX%QPERC_12 = M_FLUX%QPERC_12 + (M_FLUX%QPERC_12/TOTAL_LOSS)*ERROR_LOSS + M_FLUX%QINTF_1 = M_FLUX%QINTF_1 + (M_FLUX%QINTF_1 /TOTAL_LOSS)*ERROR_LOSS + ESTATE%FREE_1 = XMIN*DPARAM%MAXFREE_1 ! (correct state) + ! correct subsequent states (deal appropriately with percolation) + ! NOTE: do this here because only necessary to make corrections if M_FLUX%QPERC_12 changes + SELECT CASE(SMODL%iARCH2) + CASE(iopt_tens2pll_2) ! tension reservoir plus two parallel tanks + ! fix overflow fluxes + M_FLUX%TENS2FREE_2 = MAX(0._SP, M_FLUX%QPERC_12*(1._SP-MPARAM%PERCFRAC) - (DPARAM%MAXTENS_2 - BSTATE%TENS_2 )/DT) + M_FLUX%OFLOW_2A = MAX(0._SP, (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) & + - (DPARAM%MAXFREE_2A - BSTATE%FREE_2A)/DT) + M_FLUX%OFLOW_2B = MAX(0._SP, (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) & + - (DPARAM%MAXFREE_2B - BSTATE%FREE_2B)/DT) + M_FLUX%OFLOW_2 = M_FLUX%OFLOW_2A + M_FLUX%OFLOW_2B + ! fix states + ESTATE%TENS_2 = BSTATE%TENS_2 + & + (M_FLUX%QPERC_12*(1._SP-MPARAM%PERCFRAC) - M_FLUX%EVAP_2 - M_FLUX%TENS2FREE_2)*DT + ESTATE%FREE_2A = BSTATE%FREE_2A + & + (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP - M_FLUX%QBASE_2A & + - M_FLUX%OFLOW_2A)*DT + ESTATE%FREE_2B = BSTATE%FREE_2B + & + (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP - M_FLUX%QBASE_2B & + - M_FLUX%OFLOW_2B)*DT + CASE(iopt_unlimfrc_2,iopt_unlimpow_2,iopt_fixedsiz_2) ! single state + ! NOTE: M_FLUX%OFLOW_2 and M_FLUX%EVAP_2 only calculated for 'fixedsiz_2' + ! fix overflow + IF (SMODL%iARCH2.EQ.iopt_fixedsiz_2) & + M_FLUX%OFLOW_2 = MAX(0._SP, M_FLUX%QPERC_12 - (MPARAM%MAXWATR_2 - BSTATE%WATR_2)/DT) + ! fix states + ESTATE%WATR_2 = BSTATE%WATR_2 + & + (M_FLUX%QPERC_12 - M_FLUX%EVAP_2 - M_FLUX%QBASE_2 - M_FLUX%OFLOW_2)*DT + CASE DEFAULT; stop ' SMODL%iARCH2 must be iopt_tens2pll_2, iopt_unlimfrc_2, iopt_unlimpow_2 or iopt_fixedsiz_2 ' + END SELECT ! deal with modified percolation of water to the lower layer + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%FREE_1.GT.DPARAM%MAXFREE_1) THEN ! too much input + ERROR_LOSS = (ESTATE%FREE_1 - DPARAM%MAXFREE_1)/DT + M_FLUX%OFLOW_1 = M_FLUX%OFLOW_1 + ERROR_LOSS + ESTATE%FREE_1 = DPARAM%MAXFREE_1 ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_FREE_1 = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + CASE (iopt_WATR_1) + IF (ESTATE%WATR_1.LT.XMIN*MPARAM%MAXWATR_1) THEN ! too much drainage + ERROR_LOSS = (ESTATE%WATR_1 - XMIN*MPARAM%MAXWATR_1)/DT ! error (L/T) + TOTAL_LOSS = M_FLUX%QSURF + M_FLUX%EVAP_1 + M_FLUX%QPERC_12 + M_FLUX%QINTF_1 + M_FLUX%QSURF = M_FLUX%QSURF + (M_FLUX%QSURF /TOTAL_LOSS)*ERROR_LOSS + M_FLUX%EVAP_1 = M_FLUX%EVAP_1 + (M_FLUX%EVAP_1 /TOTAL_LOSS)*ERROR_LOSS + M_FLUX%QINTF_1 = M_FLUX%QINTF_1 + (M_FLUX%QINTF_1 /TOTAL_LOSS)*ERROR_LOSS + M_FLUX%QPERC_12 = M_FLUX%QPERC_12 + (M_FLUX%QPERC_12/TOTAL_LOSS)*ERROR_LOSS + ESTATE%WATR_1 = XMIN*MPARAM%MAXWATR_1 ! (correct state) + ! correct subsequent states (deal appropriately with percolation) + ! NOTE: do this here because only necessary to make corrections if M_FLUX%QPERC_12 changes + SELECT CASE(SMODL%iARCH2) + CASE(iopt_tens2pll_2) ! tension reservoir plus two parallel tanks + ! fix overflow fluxes + M_FLUX%TENS2FREE_2 = MAX(0._SP, M_FLUX%QPERC_12*(1._SP-MPARAM%PERCFRAC) - (DPARAM%MAXTENS_2 - BSTATE%TENS_2 )/DT) + M_FLUX%OFLOW_2A = MAX(0._SP, (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) & + - (DPARAM%MAXFREE_2A - BSTATE%FREE_2A)/DT) + M_FLUX%OFLOW_2B = MAX(0._SP, (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) & + - (DPARAM%MAXFREE_2B - BSTATE%FREE_2B)/DT) + M_FLUX%OFLOW_2 = M_FLUX%OFLOW_2A + M_FLUX%OFLOW_2B + ! fix states + ESTATE%TENS_2 = BSTATE%TENS_2 + & + (M_FLUX%QPERC_12*(1._SP-MPARAM%PERCFRAC) - M_FLUX%EVAP_2 - M_FLUX%TENS2FREE_2)*DT + ESTATE%FREE_2A = BSTATE%FREE_2A + & + (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP - M_FLUX%QBASE_2A & + - M_FLUX%OFLOW_2A)*DT + ESTATE%FREE_2B = BSTATE%FREE_2B + & + (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP - M_FLUX%QBASE_2B & + - M_FLUX%OFLOW_2B)*DT + CASE(iopt_unlimfrc_2,iopt_unlimpow_2,iopt_fixedsiz_2) ! single state + ! NOTE: M_FLUX%OFLOW_2 and M_FLUX%EVAP_2 only calculated for 'fixedsiz_2' + ! fix overflow + IF (SMODL%iARCH2.EQ.iopt_fixedsiz_2) & + M_FLUX%OFLOW_2 = MAX(0._SP, M_FLUX%QPERC_12 - (MPARAM%MAXWATR_2 - BSTATE%WATR_2)/DT) + ! fix states + ESTATE%WATR_2 = BSTATE%WATR_2 + & + (M_FLUX%QPERC_12 - M_FLUX%EVAP_2 - M_FLUX%QBASE_2 - M_FLUX%OFLOW_2)*DT + CASE DEFAULT; stop ' SMODL%iARCH2 must be iopt_tens2pll_2, iopt_unlimfrc_2, iopt_unlimpow_2 or iopt_fixedsiz_2 ' + END SELECT ! deal with modified percolation of water to the lower layer + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%WATR_1.GT.MPARAM%MAXWATR_1) THEN ! too much input + ERROR_LOSS = (ESTATE%WATR_1 - MPARAM%MAXWATR_1)/DT + M_FLUX%OFLOW_1 = M_FLUX%OFLOW_1 + ERROR_LOSS + ESTATE%WATR_1 = MPARAM%MAXWATR_1 ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_WATR_1 = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + ! (2) FIX STATES IN THE LOWER LAYER + ! ------------------------------------------------------------------------------------- + CASE (iopt_TENS_2) + IF (ESTATE%TENS_2.LT.XMIN*DPARAM%MAXTENS_2) THEN ! too much drainage + ERROR_LOSS = (ESTATE%TENS_2 - XMIN*DPARAM%MAXTENS_2)/DT + M_FLUX%EVAP_2 = M_FLUX%EVAP_2 + ERROR_LOSS + ESTATE%TENS_2 = XMIN*DPARAM%MAXTENS_2 ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%TENS_2.GT.DPARAM%MAXTENS_2) THEN ! too much input + ERROR_LOSS = (ESTATE%TENS_2 - DPARAM%MAXTENS_2)/DT + M_FLUX%TENS2FREE_2 = M_FLUX%TENS2FREE_2 + ERROR_LOSS + ESTATE%TENS_2 = DPARAM%MAXTENS_2 ! (correct state) + ! ** correct subsequent states (NOTE: 2 parallel tanks always coupled with a tension store) + ! fix overflow fluxes + M_FLUX%OFLOW_2A = MAX(0._SP, (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) & + - (DPARAM%MAXFREE_2A - BSTATE%FREE_2A)/DT) + M_FLUX%OFLOW_2B = MAX(0._SP, (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) & + - (DPARAM%MAXFREE_2B - BSTATE%FREE_2B)/DT) + M_FLUX%OFLOW_2 = M_FLUX%OFLOW_2A + M_FLUX%OFLOW_2B + ! fix states + ESTATE%FREE_2A = BSTATE%FREE_2A + & + (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP & + - M_FLUX%QBASE_2A - M_FLUX%OFLOW_2A)*DT + ESTATE%FREE_2B = BSTATE%FREE_2B + & + (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP & + - M_FLUX%QBASE_2B - M_FLUX%OFLOW_2B)*DT + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_TENS_2 = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + CASE (iopt_FREE2A) + IF (ESTATE%FREE_2A.LT.XMIN*DPARAM%MAXFREE_2A) THEN ! too much drainage + ERROR_LOSS = (ESTATE%FREE_2A - XMIN*DPARAM%MAXFREE_2A)/DT + M_FLUX%QBASE_2A = M_FLUX%QBASE_2A + ERROR_LOSS + ESTATE%FREE_2A = XMIN*DPARAM%MAXFREE_2A ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%FREE_2A.GT.DPARAM%MAXFREE_2A) THEN ! too much input + ERROR_LOSS = (ESTATE%FREE_2A - DPARAM%MAXFREE_2A)/DT + M_FLUX%OFLOW_2A = M_FLUX%OFLOW_2A + ERROR_LOSS + ESTATE%FREE_2A = DPARAM%MAXFREE_2A ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_FREE_2A = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + CASE (iopt_FREE2B) + IF (ESTATE%FREE_2B.LT.XMIN*DPARAM%MAXFREE_2B) THEN ! too much drainage + ERROR_LOSS = (ESTATE%FREE_2B - XMIN*DPARAM%MAXFREE_2B)/DT + M_FLUX%QBASE_2B = M_FLUX%QBASE_2B + ERROR_LOSS + ESTATE%FREE_2B = XMIN*DPARAM%MAXFREE_2B ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%FREE_2B.GT.DPARAM%MAXFREE_2B) THEN ! too much input + ERROR_LOSS = (ESTATE%FREE_2B - DPARAM%MAXFREE_2B)/DT + M_FLUX%OFLOW_2B = M_FLUX%OFLOW_2B + ERROR_LOSS + ESTATE%FREE_2B = DPARAM%MAXFREE_2B ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_FREE_2B = ERROR_LOSS + ! ------------------------------------------------------------------------------------- + CASE (iopt_WATR_2) + IF (ESTATE%WATR_2.LT.XMIN*MPARAM%MAXWATR_2) THEN ! too much drainage + ERROR_LOSS = (ESTATE%WATR_2 - XMIN*MPARAM%MAXWATR_2)/DT ! error (L/T) + TOTAL_LOSS = M_FLUX%EVAP_2 + M_FLUX%QBASE_2 + M_FLUX%EVAP_2 = M_FLUX%EVAP_2 + (M_FLUX%EVAP_2 /TOTAL_LOSS)*ERROR_LOSS + M_FLUX%QBASE_2 = M_FLUX%QBASE_2 + (M_FLUX%QBASE_2/TOTAL_LOSS)*ERROR_LOSS + ESTATE%WATR_2 = XMIN*MPARAM%MAXWATR_2 ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + IF (ESTATE%WATR_2.GT.MPARAM%MAXWATR_2) THEN + ERROR_LOSS = (ESTATE%WATR_2 - MPARAM%MAXWATR_2)/DT + M_FLUX%OFLOW_2 = M_FLUX%OFLOW_2 + ERROR_LOSS + ESTATE%WATR_2 = MPARAM%MAXWATR_2 ! (correct state) + ERROR_FLAG = .TRUE. + ENDIF + M_FLUX%ERR_WATR_2 = ERROR_LOSS + CASE DEFAULT; STOP ' cannot find state in fix_states() ' + END SELECT ! select state variable for processing + if (M_FLUX%QSURF.LT.0._sp) print *, 'end ', desc_int2str(cstate(istt)%isname), M_FLUX%QSURF + END DO ! loop through state variables + ! --------------------------------------------------------------------------------------- + ! compute derived fluxes, if necessary + IF (SMODL%iARCH2.EQ.iopt_tens2pll_2) THEN ! tension reservoir plus two parallel tanks + M_FLUX%QBASE_2 = M_FLUX%QBASE_2A + M_FLUX%QBASE_2B + M_FLUX%OFLOW_2 = M_FLUX%OFLOW_2A + M_FLUX%OFLOW_2B + ENDIF + ! --------------------------------------------------------------------------------------- + end associate ! end association with variables in the data structures + END SUBROUTINE conserve_clamp + +end module conserve_clamp_module diff --git a/build/FUSE_SRC/physics/evap_lower_diff.f90 b/build/FUSE_SRC/physics/evap_lower_diff.f90 new file mode 100644 index 0000000..f8e0c78 --- /dev/null +++ b/build/FUSE_SRC/physics/evap_lower_diff.f90 @@ -0,0 +1,94 @@ +module EVAP_LOWER_DIFF_MODULE + + implicit none + + private + public :: EVAP_LOWER_DIFF + +contains + + SUBROUTINE EVAP_LOWER_DIFF(fuseStruct, want_dflux) + ! ------------------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! ------------------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes evaporation from the lower soil layer + ! ------------------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work data type + USE model_defn ! model definition structure + USE model_defnames + IMPLICIT NONE + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + logical(lgt), intent(in), optional :: want_dflux ! if we want flux derivatives + ! internal + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + ! ------------------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + MFORCE => fuseStruct%force , & ! model forcing data + M_FLUX => fuseStruct%flux , & ! fluxes + TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! ------------------------------------------------------------------------------------------------- + + ! check the need to compute flux derivatives + comp_dflux = .false.; if(present(want_dflux)) comp_dflux = want_dflux + + ! --------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iARCH2) ! lower layer architecture + CASE(iopt_tens2pll_2,iopt_fixedsiz_2) + + ! ------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iARCH1) + ! ------------------------------------------------------------------------------------ + CASE(iopt_tension1_1,iopt_onestate_1) ! lower-layer evap is valid + + ! ------------------------------------------------------------------------------------ + ! use different evaporation schemes for the lower layer + ! ----------------------------------------------------- + SELECT CASE(SMODL%iESOIL) + CASE(iopt_sequential) + M_FLUX%EVAP_2 = (MFORCE%PET-M_FLUX%EVAP_1) * (TSTATE%TENS_2/DPARAM%MAXTENS_2) + CASE(iopt_rootweight) + M_FLUX%EVAP_2 = MFORCE%PET * DPARAM%RTFRAC2 * (TSTATE%TENS_2/DPARAM%MAXTENS_2) + CASE DEFAULT + print *, "SMODL%iESOIL must be either iopt_sequential or iopt_rootweight" + END SELECT ! (evaporation schemes) + + ! ------------------------------------------------------------------------------------ + CASE(iopt_tension2_1) ! lower-layer evap is zero + M_FLUX%EVAP_2 = 0._sp + + ! ------------------------------------------------------------------------------------ + CASE DEFAULT + print *, "SMODL%iARCH1 must be iopt_tension2_1, iopt_tension1_1, or iopt_onestate_1" + STOP + + ! ------------------------------------------------------------------------------------ + END SELECT ! (upper-layer architechure) + + ! -------------------------------------------------------------------------------------- + CASE(iopt_unlimfrc_2,iopt_unlimpow_2,iopt_topmdexp_2) + M_FLUX%EVAP_2 = 0._sp + + ! -------------------------------------------------------------------------------------- + CASE DEFAULT + print *, "SMODL%iARCH2 must be iopt_tens2pll_2, iopt_unlimfrc_2, iopt_unlimpow_2" + print *, " iopt_topmdexp_2, or iopt_fixedsiz_2" + STOP + + END SELECT + ! --------------------------------------------------------------------------------------- + + end associate ! end association with variables in the data structures + END SUBROUTINE EVAP_LOWER_DIFF + +end module EVAP_LOWER_DIFF_module diff --git a/build/FUSE_SRC/physics/evap_upper_diff.f90 b/build/FUSE_SRC/physics/evap_upper_diff.f90 new file mode 100644 index 0000000..ac69b01 --- /dev/null +++ b/build/FUSE_SRC/physics/evap_upper_diff.f90 @@ -0,0 +1,139 @@ +module EVAP_UPPER_DIFF_module + + implicit none + + private + public :: EVAP_UPPER_DIFF + +contains + + SUBROUTINE EVAP_UPPER_DIFF(fuseStruct, want_dflux) + ! ------------------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! ------------------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes evaporation from the upper soil layer + ! ------------------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work type + USE model_defn ! model definition structure + USE model_defnames ! model definition names + use smoothers, only : sfrac, dsfrac ! smoothed fraction, derivative + IMPLICIT NONE + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + logical(lgt), intent(in), optional :: want_dflux ! if we want flux derivatives + ! local variables + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + integer(i4b) :: iState ! state index + real(sp) :: phi ! smoothed fraction of total tension storage (0,1] + real(sp) :: phi_1a ! smoothed fraction of primary tension storage (0,1] + real(sp) :: phi_1b ! smoothed fraction of secondary tension storage (0,1] + real(sp) :: maxRate ! maximum forcing + real(sp) :: maxRate_1a ! maximum forcing for the primary tension tank + real(sp) :: maxRate_1b ! maximum forcing for the secondary tension tank + real(sp) :: dphi_dx ! derivative in fraction w.r.t. storage + real(sp) :: devap_dx ! derivative in evaporation w.r.t. storage + real(sp), parameter :: ms=1.e-4_sp ! smoothing in sfrac(smax) function + ! ------------------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + MFORCE => fuseStruct%force , & ! model forcing data + M_FLUX => fuseStruct%flux , & ! fluxes + dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states + TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! ------------------------------------------------------------------------------------------------- + + ! check the need to compute flux derivatives + comp_dflux = .false.; if(present(want_dflux)) comp_dflux = want_dflux + + ! --------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iARCH1) ! upper layer architecture + + ! -------------------------------------------------------------------------------------- + CASE(iopt_tension2_1) ! tension storage sub-divided into recharge and excess + ! -------------------------------------------------------------------------------------- + + ! calculate the smoothed fraction of tension storage (NOTE: use WATR_1) + phi_1a = sfrac(TSTATE%TENS_1A, DPARAM%MAXTENS_1A, ms) + phi_1b = sfrac(TSTATE%TENS_1B, DPARAM%MAXTENS_1B, ms) + + ! calculate the maximum evap rate for the storage + SELECT CASE(SMODL%iESOIL) + CASE(iopt_sequential) + maxrate_1a = MFORCE%PET + maxrate_1b = MFORCE%PET - MFORCE%PET*phi_1a + CASE(iopt_rootweight) + maxrate_1a = MFORCE%PET * MPARAM%RTFRAC1 + maxrate_1b = MFORCE%PET * DPARAM%RTFRAC2 + CASE DEFAULT; stop "evap_upper: SMODL%iESOIL must be either iopt_sequential or iopt_rootweight" + END SELECT + + ! ----- compute flux ---------------------------------------------------------------- + M_FLUX%EVAP_1A = maxrate_1a*phi_1a + M_FLUX%EVAP_1B = maxrate_1b*phi_1b + M_FLUX%EVAP_1 = M_FLUX%EVAP_1A + M_FLUX%EVAP_1B + + ! ----- compute derivatives --------------------------------------------------------------------- + if(comp_dflux) stop "evap_upper: derivatives for iopt_tension2_1 not implemented yet" + + ! -------------------------------------------------------------------------------------- + CASE(iopt_tension1_1,iopt_onestate_1) ! single tension store or single state + ! -------------------------------------------------------------------------------------- + + ! zero fluxes not used + M_FLUX%EVAP_1A = 0._sp + M_FLUX%EVAP_1B = 0._sp + + select case(SMODL%iARCH1) + case(iopt_tension1_1); phi = sfrac(TSTATE%TENS_1, DPARAM%MAXTENS_1, ms) + case(iopt_onestate_1); phi = sfrac(TSTATE%WATR_1, DPARAM%MAXTENS_1, ms) ! NOTE: use WATR_1 + end select ! no need for default because checked above + + ! calculate the maximum evap rate for the upper layer + SELECT CASE(SMODL%iESOIL) + CASE(iopt_sequential); maxRate = MFORCE%PET + CASE(iopt_rootweight); maxRate = MFORCE%PET*MPARAM%RTFRAC1 + CASE DEFAULT; stop "evap_upper: SMODL%iESOIL must be either iopt_sequential or iopt_rootweight" + END SELECT ! (evaporation schemes) + + ! ----- compute flux ---------------------------------------------------------------- + M_FLUX%EVAP_1 = maxRate*phi + + ! ----- compute derivatives --------------------------------------------------------- + if(comp_dflux)then + + ! calculate the derivative in the smoothed fraction of tension storage + select case(SMODL%iARCH1) + case(iopt_tension1_1); dphi_dx = dsfrac(TSTATE%TENS_1, DPARAM%MAXTENS_1, ms) + case(iopt_onestate_1); dphi_dx = dsfrac(TSTATE%WATR_1, DPARAM%MAXTENS_1, ms) ! NOTE: use WATR_1 + end select ! no need for default because checked above + + ! calculate the derivative in the maximum rate + devap_dx = maxRate*dphi_dx + + ! populate derivative vector + do iState=1,nState + select case(cState(iState)%iSNAME) + case (iopt_TENS_1); dfx_dS(iState)%EVAP_1 = devap_dx ! exists if one tension tank + case (iopt_WATR_1); dfx_dS(iState)%EVAP_1 = devap_dx ! exists if one state in the upper layer + end select ! no default needed + end do ! looping through states + + endif ! if computing derivatives + + CASE DEFAULT; stop "evap_upper: SMODL%iARCH1 must be iopt_tension2_1, iopt_tension1_1, or iopt_onestate_1" + END SELECT ! (upper-layer architecture) + + + end associate ! end association with variables in the data structures + END SUBROUTINE EVAP_UPPER_DIFF + +end module EVAP_UPPER_DIFF_module diff --git a/build/FUSE_SRC/physics/fix_ovshoot.f90 b/build/FUSE_SRC/physics/fix_ovshoot.f90 new file mode 100644 index 0000000..5467980 --- /dev/null +++ b/build/FUSE_SRC/physics/fix_ovshoot.f90 @@ -0,0 +1,161 @@ +module overshoot_module + + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work data type + USE model_defn, only: CSTATE,NSTATE,SMODL ! model definition structures + USE model_defnames + implicit none + + private + public :: get_bounds + public :: fix_ovshoot + public :: sigmoid + +contains + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! Numerically-stable softplus with sharpness alpha + pure real(sp) function softplus(x, alpha) result(y) + implicit none + real(sp), intent(in) :: x, alpha + real(sp) :: ax + ax = alpha * x + if (ax > 0.0_sp) then + y = (ax + log(1.0_sp + exp(-ax))) / alpha + else + y = log(1.0_sp + exp(ax)) / alpha + end if + end function softplus + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! Sigmoid + pure real(sp) function sigmoid(z) result(s) + real(sp), intent(in) :: z + if (z >= 0._sp) then + s = 1._sp / (1._sp + exp(-z)) + else + s = exp(z) / (1._sp + exp(z)) + end if + end function sigmoid + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + SUBROUTINE fix_ovshoot(X_TRY, lower, upper, dclamp) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Apply soft constraints to model state variables + ! --------------------------------------------------------------------------------------- + ! input/output + REAL(SP), DIMENSION(:), INTENT(INOUT) :: X_TRY ! vector of model states + real(sp), dimension(:), intent(in) :: lower ! lower bound + real(sp), dimension(:), intent(in) :: upper ! upper bound + real(sp), dimension(:), intent(out) :: dclamp ! derivative + ! internal + integer(i4b) :: i ! index of model state variable + real(sp), parameter :: alpha=10_sp ! controls sharpness in smoothing + + do i=1,NSTATE + + ! hard constraints + x_try(i) = max( min(x_try(i), upper(i)), lower(i) ) + dclamp(i) = 1._sp + + ! ! apply soft constraint to model states + ! x_try(i) = lower(i) + softplus(x_try(i)-lower(i), alpha) - softplus(x_try(i)-upper(i), alpha) + ! + ! ! compute derivative in clamp + ! dclamp(i) = sigmoid( (x_try(i) - lower(i)) * alpha ) - sigmoid( (x_try(i) - upper(i)) * alpha ) + + end do ! looping through model state variables + + end subroutine fix_ovshoot + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + SUBROUTINE get_bounds(fuseStruct, lower, upper) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified to return lower and upper bounds by Martyn Clark, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Identify lower and upper bounds for the vector of model states + ! --------------------------------------------------------------------------------------- + USE model_numerix ! model numerix + IMPLICIT NONE + ! input/output + type(fuse_work), intent(in) :: fuseStruct ! fuse work structure + real(sp), dimension(:), intent(out) :: lower ! lower bound for states + real(sp), dimension(:), intent(out) :: upper ! upper bound for states + ! internal + REAL(SP) :: XMIN ! very small number + INTEGER(I4B) :: ISTT ! loop through model states + ! --------------------------------------------------------------------------------------- + associate(MPARAM => fuseStruct%param_adjust, & ! adjuustable model parameters + DPARAM => fuseStruct%param_derive) ! derived model parameters + ! --------------------------------------------------------------------------------------- + XMIN=FRACSTATE_MIN ! used to avoid zero derivatives + ! --------------------------------------------------------------------------------------- + ! loop through model states + DO ISTT=1,NSTATE + SELECT CASE(CSTATE(ISTT)%iSNAME) + ! upper tanks + CASE (iopt_TENS1A) + lower(ISTT) = XMIN*DPARAM%MAXTENS_1A + upper(ISTT) = DPARAM%MAXTENS_1A + CASE (iopt_TENS1B) + lower(ISTT) = XMIN*DPARAM%MAXTENS_1B + upper(ISTT) = DPARAM%MAXTENS_1B + CASE (iopt_TENS_1) + lower(ISTT) = XMIN*DPARAM%MAXTENS_1 + upper(ISTT) = DPARAM%MAXTENS_1 + CASE (iopt_FREE_1) + lower(ISTT) = XMIN*DPARAM%MAXFREE_1 + upper(ISTT) = DPARAM%MAXFREE_1 + CASE (iopt_WATR_1) + lower(ISTT) = XMIN*MPARAM%MAXWATR_1 + upper(ISTT) = MPARAM%MAXWATR_1 + ! lower tanks + CASE (iopt_TENS_2) + lower(ISTT) = XMIN*DPARAM%MAXTENS_2 + upper(ISTT) = DPARAM%MAXTENS_2 + CASE (iopt_FREE2A) + lower(ISTT) = XMIN*DPARAM%MAXFREE_2A + upper(ISTT) = DPARAM%MAXFREE_2A + CASE (iopt_FREE2B) + lower(ISTT) = XMIN*DPARAM%MAXFREE_2B + upper(ISTT) = DPARAM%MAXFREE_2B + CASE (iopt_WATR_2) + ! *** SET LOWER LIMITS *** + IF (SMODL%iARCH2.NE.iopt_topmdexp_2) THEN + ! enforce lower limit + lower(ISTT) = XMIN*MPARAM%MAXWATR_2 + ELSE + ! MPARAM%MAXWATR_2 is just a scaling parameter, but don't allow stupid values + lower(ISTT) = -MPARAM%MAXWATR_2*10._sp + ENDIF + ! *** SET UPPER LIMITS *** + IF (SMODL%iARCH2.EQ.iopt_tens2pll_2 .OR. SMODL%iARCH2.EQ.iopt_fixedsiz_2) THEN + ! cannot exceed capacity + upper(ISTT) = MPARAM%MAXWATR_2 + ELSE + ! unlimited storage, but make sure the values are still sensible + upper(ISTT) = MPARAM%MAXWATR_2*1000._sp + ENDIF + END SELECT + END DO ! (loop through states) + end associate ! end association with variables in the data structures + ! --------------------------------------------------------------------------------------- + END SUBROUTINE get_bounds + +END MODULE overshoot_module diff --git a/build/FUSE_SRC/physics/get_bundle.f90 b/build/FUSE_SRC/physics/get_bundle.f90 new file mode 100644 index 0000000..5432157 --- /dev/null +++ b/build/FUSE_SRC/physics/get_bundle.f90 @@ -0,0 +1,44 @@ +module get_bundle_module + use nrtype + use work_types, only: fuse_work + USE model_defn, ONLY: NSTATE ! TODO: update to new structures + USE multiparam, ONLY: NUMPAR ! TODO: update to new structures + implicit none + +contains + + subroutine get_bundle(fuseStruct) + use multiforce, only: timDat + use multiforce, only: mForce + use multistate, only: mState + use multi_flux, only: m_flux + use multiparam, only: parMeta,mParam,dParam + implicit none + type(fuse_work), intent(inout) :: fuseStruct + integer(i4b) :: iState + integer(i4b) :: iParam + + ! populate fuse work structures + fuseStruct%time = timdat + fuseStruct%force = mForce + fuseStruct%state0 = mState + fuseStruct%state1 = mState + fuseStruct%flux = m_flux ! initialized at zero + fuseStruct%param_meta = parMeta + fuseStruct%param_adjust = mParam + fuseStruct%param_derive = dParam + + ! initialize flux derivatives + do iState=1,nState + fuseStruct%df_dS(iState) = m_flux ! initialized at zero + end do + + ! initialize parameter derivatives + do iParam=1,NUMPAR + fuseStruct%df_dPar(iParam) = m_flux ! initialized at zero + end do + + end subroutine get_bundle + + +end module get_bundle_module diff --git a/build/FUSE_SRC/physics/implicit_solve.f90 b/build/FUSE_SRC/physics/implicit_solve.f90 new file mode 100644 index 0000000..0849013 --- /dev/null +++ b/build/FUSE_SRC/physics/implicit_solve.f90 @@ -0,0 +1,360 @@ +module implicit_solve_module + + ! data types + use nrtype ! variable types, etc. + use work_types, only: fuse_work ! fuse work structure + + ! modules + use xtry_2_str_module ! puts state vector into FUSE state structure + use str_2_xtry_module ! puts FUSE state structure into state vector + + ! global data + use model_defn, only: nState ! number of state variables + use multiforce, only: dt => deltim ! time step + use globaldata, only: isDebug ! print flag + + use model_numerix, only: NUM_FUNCS ! number of function calls + use model_numerix, only: NUM_JACOBIAN ! number of times Jacobian is calculated + + implicit none + + private + public :: implicit_solve + + contains + + ! ----- calculate dx/dt=g(x) ----------------------------------------------------------- + subroutine dx_dt(fuseStruct, x_try, g_x, J_g) + use MOD_DERIVS_DIFF_module, only: MOD_DERIVS_DIFF ! compute dx/dt + implicit none + ! input + type(fuse_work) , intent(inout) :: fuseStruct ! fuse work structure + real(sp) , intent(in) :: x_try(:) ! trial state vector + ! output + real(sp) , intent(out) :: g_x(:) ! dx/dt=g(x) + real(sp) , intent(out) , optional :: J_g(:,:) ! flux Jacobian matrix + ! internal + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + ! -------------------------------------------------------------------------------------- + + comp_dflux = present(J_g) + + ! put data in structure + call XTRY_2_STR(x_try, fuseStruct%state1) + + ! run the fuse physics + if (present(J_g)) then + call mod_derivs_diff(fuseStruct, g_x, J_g) + else + call mod_derivs_diff(fuseStruct, g_x) + end if + + ! track the total number of function calls + NUM_FUNCS = NUM_FUNCS + 1 + + end subroutine dx_dt + + ! ----- calculate the Jacobian of g(x) ------------------------------------------------- + SUBROUTINE jac_flux(fuseStruct, x_try, g_x, lower, upper, Jac) + IMPLICIT NONE + ! input-output + type(fuse_work) , intent(in) :: fuseStruct ! fuse work structure + REAL(SP), DIMENSION(:), INTENT(IN) :: g_x, lower, upper + REAL(SP), DIMENSION(:), INTENT(IN) :: x_try + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: Jac + ! locals + type(fuse_work) :: fuseStruct_local + real(sp), parameter :: eps_rel = 1e-4_sp + real(sp), parameter :: eps_abs = 1e-6_sp ! or smaller, but NOT 1e-9 scale + real(sp), parameter :: h_min = 1e-8_sp + INTEGER(I4B) :: j,n + REAL(SP), DIMENSION(size(x_try)) :: x, xsav, g_ph + real(sp) :: h_try, h_act + + ! preliminaries + n = size(x) + fuseStruct_local = fuseStruct + x = x_try + xsav = x + + ! loop through columns + do j=1,n + + ! propose one-sided step (NOTE: negative) + h_try = -max(eps_rel*abs(xsav(j)), eps_abs) + + ! flip sign if necessary + if(xsav(j) + h_try < lower(j)) h_try = -h_try + + ! compute function from the perturbed vector + x(j) = xsav(j) + h_try + call dx_dt(fuseStruct_local, x, g_ph) + h_act = x(j) - xsav(j) + + ! compute column in the Jacobian + Jac(:,j) = (g_ph - g_x) / h_act + + ! safety: save full vector and data structure + fuseStruct_local = fuseStruct ! restores consistency after finite differencing + x = xsav + + end do ! looping through Jacobian columns + + NUM_JACOBIAN = NUM_JACOBIAN + 1 ! keep track of the number of iterations + end SUBROUTINE jac_flux + + ! ----- simple implicit solve for differentiable model -------------------------- + + subroutine implicit_solve(fuseStruct, x0, x1, nx, ierr, message, isVerbose) + USE nr, ONLY : lubksb,ludcmp + USE overshoot_module, only : get_bounds ! get state bounds + USE overshoot_module, only : fix_ovshoot ! fix overshoot (soft clamp) + USE conserve_clamp_module, only: conserve_clamp ! fix overshoot and disaggregate fluxes to conserve mass + USE model_numerix, only: ERR_ITER_FUNC ! Iteration convergence tolerance for function values + USE model_numerix, only: ERR_ITER_DX ! Iteration convergence tolerance for dx + implicit none + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + real(sp) , intent(in) :: x0(:) ! state vector at start of step + real(sp) , intent(out) :: x1(:) ! state vector at end of step + integer(i4b) , intent(in) :: nx ! number of state variables + ! error cont ,ol + integer(i4b) , intent(out) :: ierr ! error code + character(*) , intent(out) :: message ! error message + logical(lgt) , intent(in), optional :: isVerbose ! flag for printing (subroutine argument) + logical(lgt) :: isPrint ! flag for printing (local flag) + ! internal: newton iterations + real(sp) :: x_old(nx) ! old trial state vector + real(sp) :: x_try(nx) ! trial state vector + real(sp) :: g_x(nx) ! dx/dt=g(x) + real(sp) :: res(nx) ! residual vector + real(sp) :: Ja(nx,nx) ! Jacobian matrix (flux) + real(sp) :: Jg(nx,nx) ! Jacobian matrix (flux) + real(sp) :: Jac(nx,nx) ! Jacobian matrix (full) + real(sp) :: dx(nx) ! state update + real(sp) :: phi ! half squared residual norm + real(sp) :: d ! determinant sign tracker + integer(i4b) :: indx(nx) ! LU pivot indices (row-swap bookkeeping) + integer(i4b) :: i ! index of state + integer(i4b) :: it ! index of newton iteration + integer(i4b), parameter :: maxit=100 ! maximum number of iterations + logical(lgt) :: converged ! flag for convergence + ! internal: backtracking line search w/ overshoot reject + real(sp) :: xnorm ! norm used in maximum step + real(sp) :: dxnorm ! norm used to evaluate step size + real(sp) :: stpmax ! the maximum step + real(sp) :: dxScale ! used to scale dx if dxnorm > stpmax + real(sp) :: gpsi(nx) ! function gradient: func = 0.5*sum(res*res) + real(sp) :: slope ! direction of decrease + real(sp) :: lambda ! backtrack length multiplier (lambda*dx) + real(sp) :: alamin ! minimum lambda + real(sp) :: lam_i ! maximum lambda for the i-th state + real(sp) :: lam_max ! maximum lambda + real(sp) :: lower(nx) ! lower bound + real(sp) :: upper(nx) ! lower bound + real(sp) :: dclamp(nx) ! derivative in the clamp + real(sp) :: x_trial(nx) ! state vector for backtrack + real(sp) :: g_trial(nx) ! dx/dt=g(x) for backtrack + real(sp) :: res_trial(nx) ! residual for backtrack + real(sp) :: phi_new ! half squared residual norm + integer(i4b) :: ls_it ! index of line search iteration + logical(lgt) :: ovshoot ! flag for overshoot + logical(lgt) :: accepted ! flag for accepting newton step + real(sp) :: phi_best ! best function evaluation + real(sp) :: x_best(nx) ! best state vector + real(sp) :: g_best(nx) ! dx/dt = g(x_best) + logical(lgt) :: have_best ! check if found a state vector + logical(lgt) :: isClamped ! check if fallback is clamped + ! algorithmic control parameters (most passed through MODULE model_numerix) + REAL(SP), PARAMETER :: TOLMIN=1.0e-10_sp ! check for spurious minima + REAL(SP), PARAMETER :: STPMX=100.0_sp ! maximum step in lnsrch + real(sp), parameter :: shrink = 0.5_sp + real(sp), parameter :: dampen = 0.1_sp + real(sp), parameter :: phi_rel_tol = 1e-5_sp ! 0.001% + real(sp), parameter :: phi_abs_tol = 1e-6_sp + real(sp), parameter :: epsb = 1.e-10_sp ! small safety margin + integer(i4b), parameter :: ls_max = 5 + ! ----- procedure starts here -------------------------------------------------------------------- + ! initialize error control + ierr=0; message='implicit_solve/' + + ! check dimension size + if (nx /= nState) stop "implicit_solve: nx /= nState" + + ! initialize check for best function evaluation + phi_best = huge(1._sp); have_best=.false. + + ! initialize number of calls + NUM_FUNCS = 0 ! number of function calls + NUM_JACOBIAN = 0 ! number of times Jacobian is calculated + + ! get the flag for printing + isPrint = .false.; if (present(isVerbose)) isPrint = isVerbose + + ! get the bounds for the state variables + ! NOTE: This can be done outside of the time and iteration loops (keeping here for now) + call get_bounds(fuseStruct, lower, upper) + + ! put state vector into the fuse data structure + call XTRY_2_STR(x0, fuseStruct%state0) + + ! intialize state vector (and soft clamp) + x_try = x0 + x_old = x_try + dclamp = 1._sp + + ! fix overshoot (only if necessary) + if(any(x_try < lower) .or. any(x_try > upper)) & + call fix_ovshoot(x_try, lower, upper, dclamp) + + ! define maximum step + xnorm = sqrt( sum(x_try*x_try) ) + stpmax = STPMX * max( xnorm, real(nx, sp) ) + + ! initialize flags + accepted = .false. + converged = .false. + + ! --- F(x), J(x), and objective phi + call dx_dt(fuseStruct, x_try, g_x, Jg) ! compute analytical Jacobian + res = x_try - (x0 + g_x*dt) + phi = 0.5_sp * dot_product(res, res) + + ! iterate + do it = 1, maxit + + ! save x + x_old = x_try + + ! check convergence + if (phi < ERR_ITER_FUNC) then + converged = .true. + exit ! exit iteration loop + end if + + ! --- compute residual Jacobian J(x) from flux Jacobian Jg(x) ---- + !call jac_flux(fuseStruct, x_try, g_x, lower, upper, Jg) + do i=1,nx + Jac(:,i) = -dt*Jg(:,i) + Jac(i,i) = Jac(i,i) + 1.0_sp + end do + + ! --- function gradient: before Jac is modified in ludcmp + gpsi = matmul(transpose(Jac), res) ! assumes func = 0.5_sp * sum(res*res) + + ! --- Solve J dx = -F (Newton step) + dx = -res + call ludcmp(Jac, indx, d) ! J overwritten with LU + call lubksb(Jac, indx, dx) ! dx becomes solution + + ! --- Modify dx + + ! modify dx if norm > stpmax + dxnorm = sqrt( sum(dx*dx) ) + if (dxnorm > stpmax) then + dxScale = stpmax / dxnorm + dx = dxScale * dx + end if + + ! modify dx if Newton step not descending for psi + slope = dot_product(gpsi, dx) + if (slope >= 0._sp) dx = -gpsi ! fallback + + ! implement active-set methods + do i=1,nx + if (x_try(i) <= lower(i)+epsb .and. dx(i) < 0._sp) dx(i)=0._sp + if (x_try(i) >= upper(i)-epsb .and. dx(i) > 0._sp) dx(i)=0._sp + end do + + ! ---- backtracking line search -------------- + + ! line search control + accepted = .false. ! flag to check if line search is accepted + alamin = ERR_ITER_DX / maxval( abs(dx) / max(abs(x_try), 1.0_sp) ) + + lambda = 1.0_sp + do ls_it = 1, ls_max + + ! update x + x_trial = x_try + lambda*dx + + ! shrink lambda until find a value in the feasible space + if(any(x_trial < lower) .or. any(x_trial > upper))then + lambda = lambda * shrink + cycle + endif + + ! compute function and function eval -- no need for the Jacobian here + call dx_dt(fuseStruct, x_trial, g_trial) + res_trial = x_trial - (x0 + dt*g_trial) + phi_new = 0.5_sp * dot_product(res_trial, res_trial) + + ! save best function evaluation + if (phi_new < phi_best) then + phi_best = phi_new + x_best = x_trial + g_best = g_trial + have_best = .true. + endif + + if (phi_new <= phi + phi_abs_tol) then + accepted = .true.; exit + endif + + ! update lambda + lambda = lambda * shrink + if (lambda < alamin) exit ! give up shrinking + + end do ! line search + + ! ----- fallback: try a small step ----- + if(.not. accepted)then + x_trial = x_try + dampen*dx + if(any(x_trial < lower) .or. any(x_trial > upper)) & + call fix_ovshoot(x_trial, lower, upper, dclamp) + end if ! (if accepted) + + ! recompute dx_dt because we need the Jacobian + x_try = x_trial + call dx_dt(fuseStruct, x_try, g_x, Jg) ! compute analytical Jacobian + res = x_try - (x0 + g_x*dt) + phi = 0.5_sp * dot_product(res, res) + + ! save best function evaluation + if (phi < phi_best) then + phi_best = phi + x_best = x_try + g_best = g_x + have_best = .true. + endif + + ! tiny-step convergence + if (maxval( abs(x_try - x_old) / max(abs(x_try), 1._sp) ) < ERR_ITER_DX) then + converged = .true. + exit ! exit iteration loop + end if + + end do ! loop through iterations + + ! ----- handle the extremely rare case of non-convergence ----- + if( .not. converged)then + + ! use explicit Euler if did not find anything + if( .not. have_best) call dx_dt(fuseStruct, x0, g_best) + + ! use dx/dt = g(x_best) + x_try = x0 + dt*g_best + + ! test bounds violations: if bounds exceeded, then clamp and disaggregate fluxes (conserve mass) + call XTRY_2_STR(x_try, fuseStruct%state1) + call conserve_clamp(fuseStruct, dt, isClamped) + print*, 'WARNING: '//trim(message)//"failed to converge: use best function evaluation. Clamp = ", isClamped + + endif ! if not converged + + ! save final state + x1 = x_try + + end subroutine implicit_solve + +end module implicit_solve_module diff --git a/build/FUSE_SRC/physics/mod_derivs_diff.f90 b/build/FUSE_SRC/physics/mod_derivs_diff.f90 new file mode 100644 index 0000000..fd0bb00 --- /dev/null +++ b/build/FUSE_SRC/physics/mod_derivs_diff.f90 @@ -0,0 +1,65 @@ +module MOD_DERIVS_DIFF_module + + USE nrtype + USE work_types, only: fuse_work + USE multistate_types, only: STATEV + USE qsatexcess_diff_module, only: qsatexcess_diff + USE evap_upper_diff_module, only: evap_upper_diff + USE evap_lower_diff_module, only: evap_lower_diff + USE qinterflow_diff_module, only: qinterflow_diff + USE qpercolate_diff_module, only: qpercolate_diff + USE q_baseflow_diff_module, only: q_baseflow_diff + USE q_misscell_diff_module, only: q_misscell_diff + USE mstate_rhs_diff_module, only: mstate_rhs_diff + + implicit none + + private + public :: MOD_DERIVS_DIFF + +contains + + SUBROUTINE MOD_DERIVS_DIFF(fuseStruct, g_x, J_g) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified to include snow model by Brian Henn, 6/2013 + ! Modified to include analytical derivatives by Martyn Clark, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! compute the time derivative (dx/dt) of all model states (x) + ! -------------------------------------------------------------------------------------- + implicit none + ! input + type(fuse_work) , intent(inout) :: fuseStruct ! fuse work structure + ! output + real(sp) , intent(out) :: g_x(:) ! dx/dt=g(x) + real(sp) , intent(out) , optional :: J_g(:,:) ! flux Jacobian matrix + ! internal + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + ! -------------------------------------------------------------------------------------- + + ! check if Jacobian is desired + comp_dflux = present(J_g) + + ! compute fluxes + call qsatexcess_diff(fuseStruct, comp_dflux) ! compute the saturated area and surface runoff + call evap_upper_diff(fuseStruct, comp_dflux) ! compute evaporation from the upper layer + call evap_lower_diff(fuseStruct, comp_dflux) ! compute evaporation from the lower layer + call qinterflow_diff(fuseStruct, comp_dflux) ! compute interflow from free water in the upper layer + call qpercolate_diff(fuseStruct, comp_dflux) ! compute percolation from the upper to lower soil layers + call q_baseflow_diff(fuseStruct, comp_dflux) ! compute baseflow from the lower soil layer + call q_misscell_diff(fuseStruct, comp_dflux) ! compute miscellaneous fluxes (NOTE: need sat area, evap, and perc) + + ! compute the time derivative (dx/dt) of all model states (x) + if(comp_dflux)then + call mstate_rhs_diff(fuseStruct, g_x, J_g) + else + call mstate_rhs_diff(fuseStruct, g_x) + endif + + END SUBROUTINE MOD_DERIVS_DIFF + +end module MOD_DERIVS_DIFF_module diff --git a/build/FUSE_SRC/physics/mstate_rhs_diff.f90 b/build/FUSE_SRC/physics/mstate_rhs_diff.f90 new file mode 100644 index 0000000..68ae410 --- /dev/null +++ b/build/FUSE_SRC/physics/mstate_rhs_diff.f90 @@ -0,0 +1,115 @@ +module MSTATE_RHS_DIFF_module + + use globaldata, only: isDebug ! print flag + + implicit none + + private + public :: MSTATE_RHS_DIFF + +contains + + SUBROUTINE MSTATE_RHS_DIFF(fuseStruct, g_x, J_g) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes time derivatives of all states for all model combinations + ! --------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work data type + USE model_defn ! model definition structure + USE model_defnames ! model names + use str_2_xtry_module ! puts FUSE state structure into state vector + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + ! output + real(sp) , intent(out) :: g_x(:) ! dx/dt=g(x) + real(sp) , intent(out) , optional :: J_g(:,:) ! flux Jacobian matrix + ! internal + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + ! ------------------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + M_FLUX => fuseStruct%flux , & ! fluxes + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DX_DT => fuseStruct%dx_dt & ! time derivative in states + ) ! (associate) + ! ------------------------------------------------------------------------------------------------- + + ! check if Jacobian is desired + comp_dflux = present(J_g) + + ! --------------------------------------------------------------------------------------- + ! (1) UPPER LAYER + ! --------------------------------------------------------------------------------------- + + ! compute time derivatives + SELECT CASE(SMODL%iARCH1) + CASE(iopt_tension2_1) ! tension storage sub-divided into recharge and excess + DX_DT%TENS_1A = M_FLUX%EFF_PPT - M_FLUX%QSURF - M_FLUX%EVAP_1A - M_FLUX%RCHR2EXCS + DX_DT%TENS_1B = M_FLUX%RCHR2EXCS - M_FLUX%EVAP_1B - M_FLUX%TENS2FREE_1 + DX_DT%FREE_1 = M_FLUX%TENS2FREE_1 - M_FLUX%QPERC_12 - M_FLUX%QINTF_1 - M_FLUX%OFLOW_1 + CASE(iopt_tension1_1) ! upper layer broken up into tension and free storage + DX_DT%TENS_1 = M_FLUX%EFF_PPT - M_FLUX%QSURF - M_FLUX%EVAP_1 - M_FLUX%TENS2FREE_1 + DX_DT%FREE_1 = M_FLUX%TENS2FREE_1 - M_FLUX%QPERC_12 - M_FLUX%QINTF_1 - M_FLUX%OFLOW_1 + CASE(iopt_onestate_1) ! upper layer defined by a single state variable + DX_DT%WATR_1 = M_FLUX%EFF_PPT - M_FLUX%QSURF - M_FLUX%EVAP_1 - M_FLUX%QPERC_12 - M_FLUX%QINTF_1 & + - M_FLUX%OFLOW_1 + CASE DEFAULT + print *, "SMODL%iARCH1 must be iopt_tension2_1, iopt_tension1_1, or iopt_onestate_1" + STOP + END SELECT ! (upper layer architecture) + + ! compute Jacobian + if(comp_dflux)then + if(SMODL%iARCH1 /= iopt_onestate_1) stop "mstate_rhs: only iopt_onestate_1 currently implemented" + J_g(1,:) = -M_FLUX%EFF_PPT*fuseStruct%df_dS%SATAREA - fuseStruct%df_dS%EVAP_1 - fuseStruct%df_dS%QPERC_12 + endif + + ! --------------------------------------------------------------------------------------- + ! (2) LOWER LAYER + ! --------------------------------------------------------------------------------------- + + ! compute time derivatives + SELECT CASE(SMODL%iARCH2) + CASE(iopt_tens2pll_2) ! tension reservoir plus two parallel tanks + DX_DT%TENS_2 = M_FLUX%QPERC_12*(1._SP-MPARAM%PERCFRAC) - M_FLUX%EVAP_2 - M_FLUX%TENS2FREE_2 + DX_DT%FREE_2A = M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP - M_FLUX%QBASE_2A & + - M_FLUX%OFLOW_2A + DX_DT%FREE_2B = M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP - M_FLUX%QBASE_2B & + - M_FLUX%OFLOW_2B + CASE(iopt_unlimfrc_2,iopt_unlimpow_2,iopt_topmdexp_2,iopt_fixedsiz_2) ! single state + ! (NOTE: M_FLUX%OFLOW_2=0 for 'unlimfrc_2','unlimpow_2','topmdexp_2') + DX_DT%WATR_2 = M_FLUX%QPERC_12 - M_FLUX%EVAP_2 - M_FLUX%QBASE_2 - M_FLUX%OFLOW_2 + CASE DEFAULT + print *, "SMODL%iARCH2 must be iopt_tens2pll_2, iopt_unlimfrc_2, iopt_unlimpow_2" + print *, " iopt_topmdexp_2, or iopt_fixedsiz_2" + STOP + END SELECT + + ! compute Jacobian + ! NOTE: assume M_FLUX%EVAP_2=0 and M_FLUX%OFLOW_2=0 + if(comp_dflux)then + if(SMODL%iARCH2 == iopt_tens2pll_2) stop "mstate_rhs: iopt_tens2pll_2 not currently implemented" + J_g(2,:) = fuseStruct%df_dS%QPERC_12 - fuseStruct%df_dS%QBASE_2 + endif + + ! --------------------------------------------------------------------------------------- + + ! --------------------------------------------------------------------------------------- + ! (3) FINALIZE + ! --------------------------------------------------------------------------------------- + + ! extract dx_dt from fuse structure + call STR_2_XTRY(fuseStruct%dx_dt, g_x) + ! --------------------------------------------------------------------------------------- + + end associate ! end association with variables in the data structures + END SUBROUTINE MSTATE_RHS_DIFF + +end module MSTATE_RHS_DIFF_module diff --git a/build/FUSE_SRC/physics/q_baseflow_diff.f90 b/build/FUSE_SRC/physics/q_baseflow_diff.f90 new file mode 100644 index 0000000..5dd2813 --- /dev/null +++ b/build/FUSE_SRC/physics/q_baseflow_diff.f90 @@ -0,0 +1,109 @@ +module Q_BASEFLOW_DIFF_module + + implicit none + + private + public :: Q_BASEFLOW_DIFF + +contains + + + SUBROUTINE Q_BASEFLOW_DIFF(fuseStruct, want_dflux) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes the baseflow from the lower soil layer + ! --------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work type + USE model_defn ! model definition structure + USE model_defnames + IMPLICIT NONE + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + logical(lgt), intent(in), optional :: want_dflux ! if we want flux derivatives + ! derivatives + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + integer(i4b) :: iState ! state index + real(sp) :: phi ! scaled water storage, phi=w/ws + real(sp) :: dqb_dw ! derivative in baseflow flux w.r.t. water store + ! ------------------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + M_FLUX => fuseStruct%flux , & ! fluxes + dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states + TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + + ! check the need to compute flux derivatives + comp_dflux = .false.; if(present(want_dflux)) comp_dflux = want_dflux + + ! --------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iARCH2) + + ! -------------------------------------------------------------------------------------- + CASE(iopt_tens2pll_2) ! tension reservoir plus two parallel tanks + M_FLUX%QBASE_2A = MPARAM%QBRATE_2A * TSTATE%FREE_2A ! qbrate_2a is a fraction (T-1) + M_FLUX%QBASE_2B = MPARAM%QBRATE_2B * TSTATE%FREE_2B ! qbrate_2b is a fraction (T-1) + M_FLUX%QBASE_2 = M_FLUX%QBASE_2A + M_FLUX%QBASE_2B ! total baseflow + if(comp_dflux) stop "q_baseflow: derivative not implemented yet for iopt_tens2pll_2" + + ! -------------------------------------------------------------------------------------- + CASE(iopt_unlimfrc_2) ! baseflow resvr of unlimited size (0-HUGE), frac rate + M_FLUX%QBASE_2 = MPARAM%QB_PRMS * TSTATE%WATR_2 ! qb_prms is a fraction (T-1) + if(comp_dflux) stop "q_baseflow: derivative not implemented yet for iopt_unlimfrc_2" + + ! -------------------------------------------------------------------------------------- + CASE(iopt_unlimpow_2) ! baseflow resvr of unlimited size (0-HUGE), power recession + + associate(qbsat=>DPARAM%QBSAT, w=>TSTATE%WATR_2, ws=>MPARAM%MAXWATR_2, p=>MPARAM%QB_POWR) + + ! ----- compute flux ------------------------------------------------------------------ + phi = w/ws + M_FLUX%QBASE_2 = qbsat*phi**p + + ! ----- compute derivative ------------------------------------------------------------ + if(comp_dflux) dqb_dw = (qbsat*p/ws)*phi**(p - 1._sp) + + end associate + + ! -------------------------------------------------------------------------------------- + CASE(iopt_topmdexp_2) ! topmodel exponential reservoir (-HUGE to HUGE) + M_FLUX%QBASE_2 = DPARAM%QBSAT * EXP( -(1. - TSTATE%WATR_2/MPARAM%MAXWATR_2) ) + if(comp_dflux) stop "q_baseflow: derivative not implemented yet for iopt_topmdexp_2" + + ! -------------------------------------------------------------------------------------- + CASE(iopt_fixedsiz_2) ! baseflow reservoir of fixed size + M_FLUX%QBASE_2 = MPARAM%BASERTE * (TSTATE%WATR_2/MPARAM%MAXWATR_2)**MPARAM%QB_POWR + if(comp_dflux) stop "q_baseflow: derivative not implemented yet for iopt_fixedsiz_2" + + ! -------------------------------------------------------------------------------------- + CASE DEFAULT + print *, "SMODL%iARCH2 must be iopt_tens2pll_2, iopt_unlimfrc_2, iopt_unlimpow_2" + print *, " iopt_topmdexp_2, or iopt_fixedsiz_2" + STOP + ! -------------------------------------------------------------------------------------- + + END SELECT + ! --------------------------------------------------------------------------------------- + + ! populate derivative vector + if(comp_dflux)then + do iState=1,nState + select case(cState(iState)%iSNAME) + case (iopt_WATR_2); dfx_dS(iState)%QBASE_2 = dqb_dw ! exists if one state in the upper layer + end select ! no default needed + end do ! looping through states + endif + + end associate ! end association with variables in the data structures + END SUBROUTINE Q_BASEFLOW_DIFF + +end module Q_BASEFLOW_DIFF_module diff --git a/build/FUSE_SRC/physics/q_misscell_diff.f90 b/build/FUSE_SRC/physics/q_misscell_diff.f90 new file mode 100644 index 0000000..ae56313 --- /dev/null +++ b/build/FUSE_SRC/physics/q_misscell_diff.f90 @@ -0,0 +1,125 @@ +module Q_MISSCELL_DIFF_module + + implicit none + + private + public :: Q_MISSCELL_DIFF + +contains + + SUBROUTINE Q_MISSCELL_DIFF(fuseStruct, want_dflux) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes miscellaneous fluxes: + ! RCHR2EXCS = flow from recharge to excess (mm day-1) + ! TENS2FREE_1 = flow from tension storage to free storage in the upper layer (mm day-1) + ! TENS2FREE_2 = flow from tension storage to free storage in the lower layer (mm day-1) + ! OFLOW_1 = overflow from the upper soil layer (mm day-1) + ! OFLOW_2 = overflow from the lower soil layer (mm day-1) + ! --------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work type + USE model_defn ! model definition structure + USE model_defnames + USE smoothers, only: smoother ! smoothing function + IMPLICIT NONE + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + logical(lgt), intent(in), optional :: want_dflux ! if we want flux derivatives + ! internal + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + REAL(SP), PARAMETER :: PSMOOTH=0.05_SP ! smoothing parameter + REAL(SP) :: W_FUNC ! result from smoother + ! ------------------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + M_FLUX => fuseStruct%flux , & ! fluxes + TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! --------------------------------------------------------------------------------------- + + ! check the need to compute flux derivatives + comp_dflux = .false.; if(present(want_dflux)) comp_dflux = want_dflux + + ! --------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iARCH1) + CASE(iopt_tension2_1) ! tension storage sub-divided into recharge and excess + ! compute flow from recharge to excess (mm s-1) + W_FUNC = SMOOTHER(TSTATE%TENS_1A,DPARAM%MAXTENS_1A,PSMOOTH) + M_FLUX%RCHR2EXCS = W_FUNC * (M_FLUX%EFF_PPT - M_FLUX%QSURF) + ! compute flow from tension storage to free storage (mm s-1) + W_FUNC = SMOOTHER(TSTATE%TENS_1B,DPARAM%MAXTENS_1B,PSMOOTH) + M_FLUX%TENS2FREE_1 = W_FUNC * M_FLUX%RCHR2EXCS + ! compute over-flow of free water + W_FUNC = SMOOTHER(TSTATE%FREE_1,DPARAM%MAXFREE_1,PSMOOTH) + M_FLUX%OFLOW_1 = W_FUNC * M_FLUX%TENS2FREE_1 + CASE(iopt_tension1_1) ! upper layer broken up into tension and free storage + ! no separate recharge zone (flux should never be used) + M_FLUX%RCHR2EXCS = 0._SP + ! compute flow from tension storage to free storage (mm s-1) + W_FUNC = SMOOTHER(TSTATE%TENS_1,DPARAM%MAXTENS_1,PSMOOTH) + M_FLUX%TENS2FREE_1 = W_FUNC * (M_FLUX%EFF_PPT - M_FLUX%QSURF) + ! compute over-flow of free water + W_FUNC = SMOOTHER(TSTATE%FREE_1,DPARAM%MAXFREE_1,PSMOOTH) + M_FLUX%OFLOW_1 = W_FUNC * M_FLUX%TENS2FREE_1 + CASE(iopt_onestate_1) ! upper layer defined by a single state variable + ! no tension stores + M_FLUX%RCHR2EXCS = 0._SP + M_FLUX%TENS2FREE_1 = 0._SP + ! compute over-flow of free water + if(SMODL%iQSURF == iopt_arno_x_vic)then + M_FLUX%OFLOW_1 = 0._sp ! no need for overflow since the vic parmaeterization is smoothed now + else + W_FUNC = SMOOTHER(TSTATE%WATR_1,MPARAM%MAXWATR_1,PSMOOTH) + M_FLUX%OFLOW_1 = W_FUNC * (M_FLUX%EFF_PPT - M_FLUX%QSURF) + endif + CASE DEFAULT + print *, "SMODL%iARCH1 must be iopt_tension2_1, iopt_tension1_1, or iopt_onestate_1" + STOP + END SELECT + + ! --------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iARCH2) + CASE(iopt_tens2pll_2) ! tension reservoir plus two parallel tanks + ! compute flow from tension storage to free storage (mm s-1) + W_FUNC = SMOOTHER(TSTATE%TENS_2,DPARAM%MAXTENS_2,PSMOOTH) + M_FLUX%TENS2FREE_2 = W_FUNC * M_FLUX%QPERC_12*(1._SP-MPARAM%PERCFRAC) + ! compute over-flow of free water in the primary reservoir + W_FUNC = SMOOTHER(TSTATE%FREE_2A,DPARAM%MAXFREE_2A,PSMOOTH) + M_FLUX%OFLOW_2A = W_FUNC * (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) + ! compute over-flow of free water in the secondary reservoir + W_FUNC = SMOOTHER(TSTATE%FREE_2B,DPARAM%MAXFREE_2B,PSMOOTH) + M_FLUX%OFLOW_2B = W_FUNC * (M_FLUX%QPERC_12*(MPARAM%PERCFRAC/2._SP) + M_FLUX%TENS2FREE_2/2._SP) + ! compute total overflow + M_FLUX%OFLOW_2 = M_FLUX%OFLOW_2A + M_FLUX%OFLOW_2B + CASE(iopt_fixedsiz_2) + ! no tension store + M_FLUX%TENS2FREE_2 = 0._SP + M_FLUX%OFLOW_2A = 0._SP + M_FLUX%OFLOW_2B = 0._SP + ! compute over-flow of free water + W_FUNC = SMOOTHER(TSTATE%WATR_2,MPARAM%MAXWATR_2,PSMOOTH) + M_FLUX%OFLOW_2 = W_FUNC * M_FLUX%QPERC_12 + CASE(iopt_unlimfrc_2,iopt_unlimpow_2,iopt_topmdexp_2) ! unlimited size + M_FLUX%TENS2FREE_2 = 0._SP + M_FLUX%OFLOW_2 = 0._SP + M_FLUX%OFLOW_2A = 0._SP + M_FLUX%OFLOW_2B = 0._SP + CASE DEFAULT + print *, "SMODL%iARCH2 must be iopt_tens2pll_2, iopt_unlimfrc_2, iopt_unlimpow_2" + print *, " iopt_topmdexp_2, or iopt_fixedsiz_2" + STOP + END SELECT + + end associate ! end association with variables in the data structures + END SUBROUTINE Q_MISSCELL_DIFF + +end module Q_MISSCELL_DIFF_module diff --git a/build/FUSE_SRC/physics/qinterflow_diff.f90 b/build/FUSE_SRC/physics/qinterflow_diff.f90 new file mode 100644 index 0000000..d2aaf84 --- /dev/null +++ b/build/FUSE_SRC/physics/qinterflow_diff.f90 @@ -0,0 +1,59 @@ +module QINTERFLOW_DIFF_module + + implicit none + + private + public :: QINTERFLOW_DIFF + +contains + + SUBROUTINE QINTERFLOW_DIFF(fuseStruct, want_dflux) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes the interflow from free water in the upper soil layer + ! --------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work type + USE model_defn ! model definition structure + USE model_defnames + IMPLICIT NONE + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + logical(lgt), intent(in), optional :: want_dflux ! if we want flux derivatives + ! internal + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + ! ------------------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + M_FLUX => fuseStruct%flux , & ! fluxes + TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! ------------------------------------------------------------------------------------------------- + + ! check the need to compute flux derivatives + comp_dflux = .false.; if(present(want_dflux)) comp_dflux = want_dflux + + ! --------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iQINTF) + CASE(iopt_intflwsome) ! interflow + M_FLUX%QINTF_1 = MPARAM%IFLWRTE * (TSTATE%FREE_1/DPARAM%MAXFREE_1) + CASE(iopt_intflwnone) ! no interflow + M_FLUX%QINTF_1 = 0. + CASE DEFAULT ! check for errors + print *, "SMODL%iQINTF must be either iopt_intflwsome or iopt_intflwnone" + STOP + END SELECT + ! --------------------------------------------------------------------------------------- + + end associate ! end association with variables in the data structures + END SUBROUTINE QINTERFLOW_DIFF + +end module QINTERFLOW_DIFF_module diff --git a/build/FUSE_SRC/physics/qpercolate_diff.f90 b/build/FUSE_SRC/physics/qpercolate_diff.f90 new file mode 100644 index 0000000..28a6b45 --- /dev/null +++ b/build/FUSE_SRC/physics/qpercolate_diff.f90 @@ -0,0 +1,117 @@ +module QPERCOLATE_DIFF_module + + implicit none + + private + public :: QPERCOLATE_DIFF + +contains + + SUBROUTINE QPERCOLATE_DIFF(fuseStruct, want_dflux) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes the percolation from the upper soil layer to the lower soil layer + ! --------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work type + USE model_defn ! model definition structure + USE model_defnames ! model definition names + use smoothers, only : sfrac, dsfrac ! smoothed fraction, derivative + IMPLICIT NONE + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + logical(lgt), intent(in), optional :: want_dflux ! if we want flux derivatives + ! internal + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + integer(i4b) :: iState ! state index + real(sp) :: phi ! smoothed fraction of free water + real(sp) :: dphi_dx ! derivative in smoothed fraction of free water + real(sp) :: df_dpsi ! derivative of flux w.r.t. fraction + real(sp) :: dqperc_dx ! derivative of percolation fux w.r.t. water state + REAL(SP) :: LZ_PD ! lower zone percolation demand + real(sp), parameter :: ms=1.e-4_sp ! smoothing in sfrac(smax) function + ! --------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + M_FLUX => fuseStruct%flux , & ! fluxes + dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states + TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! --------------------------------------------------------------------------------------- + + ! check the need to compute flux derivatives + comp_dflux = .false.; if(present(want_dflux)) comp_dflux = want_dflux + + ! --------------------------------------------------------------------------------------- + SELECT CASE(SMODL%iQPERC) + + ! -------------------------------------------------------------------------------------- + ! upper zone control + ! -------------------------------------------------------------------------------------- + CASE(iopt_perc_w2sat, iopt_perc_f2sat) + + ! short-cuts + associate(k=>MPARAM%PERCRTE, c=>MPARAM%PERCEXP) + + ! compute fractions + select case(SMODL%iQPERC) + case(iopt_perc_w2sat); phi = sfrac(TSTATE%WATR_1, MPARAM%MAXWATR_1, ms) + case(iopt_perc_f2sat); phi = sfrac(TSTATE%FREE_1, DPARAM%MAXFREE_1, ms) + end select ! no need for default since already in block + + ! ----- compute flux ---------------------------------------------------------------- + M_FLUX%QPERC_12 = k*phi**c + + ! ----- compute derivative ---------------------------------------------------------- + if(comp_dflux)then + + ! compute derivative in the fractions + select case(SMODL%iQPERC) + case(iopt_perc_w2sat); dphi_dx = dsfrac(TSTATE%WATR_1, MPARAM%MAXWATR_1, ms) + case(iopt_perc_f2sat); dphi_dx = dsfrac(TSTATE%FREE_1, DPARAM%MAXFREE_1, ms) + end select ! no need for default since already in block + + ! compute derivatives in the percolation flux + df_dpsi = k*c*phi**(c - 1._sp) ! derivative of flux w.r.t. fraction + dqperc_dx = df_dpsi*dphi_dx + + ! populate derivative vector + do iState=1,nState + select case(cState(iState)%iSNAME) + case (iopt_FREE_1); dfx_dS(iState)%QPERC_12 = dqperc_dx ! exists if separate free tank + case (iopt_WATR_1); dfx_dS(iState)%QPERC_12 = dqperc_dx ! exists if one state in the upper layer + end select ! no default needed + end do ! looping through states + + endif ! if computing derivatives + + end associate + + ! -------------------------------------------------------------------------------------- + ! lower zone control + ! -------------------------------------------------------------------------------------- + CASE(iopt_perc_lower) ! perc defined by moisture content in lower layer (SAC) + + ! ----- compute flux ---------------------------------------------------------------- + LZ_PD = 1._SP + MPARAM%SACPMLT*(1._SP - TSTATE%WATR_2/MPARAM%MAXWATR_2)**MPARAM%SACPEXP + M_FLUX%QPERC_12 = DPARAM%QBSAT*LZ_PD * (TSTATE%FREE_1/DPARAM%MAXFREE_1) + + ! ----- compute derivatives --------------------------------------------------------------------- + if(comp_dflux) stop "qpercolate: derivatives for iopt_perc_lower not implemented yet" + + CASE DEFAULT; stop "qpercolate: SMODL%iQPERC must be iopt_perc_f2sat, iopt_perc_w2sat, or iopt_perc_lower" + END SELECT + ! -------------------------------------------------------------------------------------- + + end associate ! end association with variables in the data structures + END SUBROUTINE QPERCOLATE_DIFF + +end module QPERCOLATE_DIFF_module diff --git a/build/FUSE_SRC/physics/qsatexcess_diff.f90 b/build/FUSE_SRC/physics/qsatexcess_diff.f90 new file mode 100644 index 0000000..901c0eb --- /dev/null +++ b/build/FUSE_SRC/physics/qsatexcess_diff.f90 @@ -0,0 +1,157 @@ +module QSATEXCESS_DIFF_MODULE + + implicit none + + private + public :: QSATEXCESS_DIFF + +contains + + SUBROUTINE QSATEXCESS_DIFF(fuseStruct, want_dflux) + ! ------------------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to create a differentiable model, 12/25 + ! ------------------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes the saturated area and surface runoff + ! ------------------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE work_types, only: fuse_work ! fuse work type + USE model_defn ! model definition structure + USE model_defnames + USE nr, ONLY : gammp ! interface for the incomplete gamma function + USE smoothers, only : smax,dsmax ! smoothed max function, derivative + IMPLICIT NONE + ! input-output + type(fuse_work), intent(inout) :: fuseStruct ! fuse work structure + logical(lgt), intent(in), optional :: want_dflux ! if we want flux derivatives + ! internal variables -- vic + real(sp) :: u,xp ! temporary variables + real(sp) :: ds_dx ! derivative of saturated area w.r.t. x + real(sp) :: dx_du ! derivative of smooth max(u,0) w.r.t. u + real(sp) :: du_dw ! derivative of u w.r.t. w + real(sp) :: ds_dw ! derivative of saturated area w.r.t. w + ! internal variables -- topmodel + REAL(SP) :: TI_SAT ! topographic index where saturated + REAL(SP) :: TI_LOG ! critical value of topo index in log space + REAL(SP) :: TI_OFF ! offset in the Gamma distribution + REAL(SP) :: TI_SHP ! shape of the Gamma distribution + REAL(SP) :: TI_CHI ! CHI, see Sivapalan et al., 1987 + REAL(SP) :: TI_ARG ! argument of the Gamma function + REAL(SP) :: NO_ZERO=1.E-8 ! avoid divide by zero + ! derivatives + logical(lgt) :: comp_dflux ! flag to compute flux derivatives + integer(i4b) :: iState ! state index + real(sp), parameter :: ms=1.e-4_sp ! smoothing in smax function + ! ------------------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + M_FLUX => fuseStruct%flux , & ! fluxes + dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states + TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! ------------------------------------------------------------------------------------------------- + + ! check the need to compute flux derivatives + comp_dflux = .false.; if(present(want_dflux)) comp_dflux = want_dflux + + ! saturated area method + SELECT CASE(SMODL%iQSURF) + + ! ------------------------------------------------------------------------------------------------ + ! ----- ARNO/Xzang/VIC parameterization (upper zone control) ------------------------------------- + ! ------------------------------------------------------------------------------------------------ + CASE(iopt_arno_x_vic) + + ! define variables + associate(w=>TSTATE%WATR_1, wmax=>MPARAM%MAXWATR_1, b=>MPARAM%AXV_BEXP) + + ! ----- compute flux ---------------------------------------------------------------------------- + u = 1._sp - w/wmax + xp = smax(u, 0._sp, ms) ! smooth version of max(u,0) + M_FLUX%SATAREA = 1._sp - xp**b + + ! ----- compute derivatives --------------------------------------------------------------------- + if(comp_dflux)then + + ! compute derivative w.r.t. saturated area + ds_dx = -b*xp**(b - 1._sp) ! derivative of saturated area w.r.t. xp + dx_du = dsmax(u, 0._sp, ms) ! derivative of smooth max(u,0) w.r.t. u + du_dw = -1._sp/wmax ! derivative of u w.r.t. w + ds_dw = du_dw*dx_du*ds_dx ! derivative of saturated area w.r.t. w + + ! since WATR_1 is the sum of individual state variables (e.g., WATR_1=TENS_1+FREE_1) simply copy derivative + do iState=1,nState + select case(cState(iState)%iSNAME) + case (iopt_TENS1A); dfx_dS(iState)%SATAREA = ds_dw ! exists if two tension tanks + case (iopt_TENS1B); dfx_dS(iState)%SATAREA = ds_dw ! exists if two tension tanks + case (iopt_TENS_1); dfx_dS(iState)%SATAREA = ds_dw ! exists if one tension tank + case (iopt_FREE_1); dfx_dS(iState)%SATAREA = ds_dw ! exists if separate free storage + case (iopt_WATR_1); dfx_dS(iState)%SATAREA = ds_dw ! exists if one state in the upper layer + end select ! no default needed + end do ! looping through states + + endif ! if want derivatives + + end associate + + ! ------------------------------------------------------------------------------------------------ + ! ----- PRMS variant (fraction of upper tension storage) ----------------------------------------- + ! ------------------------------------------------------------------------------------------------ + CASE(iopt_prms_varnt) + + ! ----- compute flux ---------------------------------------------------------------------------- + M_FLUX%SATAREA = MIN(TSTATE%TENS_1/DPARAM%MAXTENS_1, 1._sp) * MPARAM%SAREAMAX + + ! ----- compute derivatives --------------------------------------------------------------------- + if(comp_dflux) stop "qsatexcess: derivatives for iopt_prms_varnt not implemented yet" + + ! ------------------------------------------------------------------------------------------------ + ! ----- TOPMODEL parameterization (only valid for TOPMODEL qb) ----------------------------------- + ! ------------------------------------------------------------------------------------------------ + CASE(iopt_tmdl_param) + + ! ----- compute flux ---------------------------------------------------------------------------- + + ! compute the minimum value of the topographic index where the basin is saturated + ! (this is correct, as MPARAM%MAXWATR_2 is m*n -- units are meters**(1/n) + TI_SAT = DPARAM%POWLAMB / (TSTATE%WATR_2/MPARAM%MAXWATR_2 + NO_ZERO) + ! compute the saturated area + IF (TI_SAT.GT.DPARAM%MAXPOW) THEN + M_FLUX%SATAREA = 0. + ELSE + ! convert the topographic index to log space + TI_LOG = LOG( TI_SAT**MPARAM%QB_POWR ) + ! compute the saturated area (NOTE: critical value of the topographic index is in log space) + TI_OFF = 3._sp ! offset in the Gamma distribution (the "3rd" parameter) + TI_SHP = MPARAM%TISHAPE ! shape of the Gamma distribution (the "2nd" parameter) + TI_CHI = (MPARAM%LOGLAMB - TI_OFF) / MPARAM%TISHAPE ! Chi -- loglamb is the first parameter (mean) + TI_ARG = MAX(0._sp, TI_LOG - TI_OFF) / TI_CHI ! argument to the incomplete Gamma function + M_FLUX%SATAREA = 1._sp - GAMMP(TI_SHP, TI_ARG) ! GAMMP is the incomplete Gamma function + ENDIF + + ! ----- compute derivatives --------------------------------------------------------------------- + if(comp_dflux) stop "qsatexcess: derivatives for iopt_tmdl_param not implemented yet" + + ! ------------------------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------------------------ + ! check processed surface runoff selection + CASE DEFAULT + print *, "SMODL%iQSURF must be iopt_arno_x_vic, iopt_prms_varnt, or iopt_tmdl_param" + STOP + + END SELECT ! (different surface runoff options) + + ! ...and, compute surface runoff + ! ------------------------------ + M_FLUX%QSURF = M_FLUX%EFF_PPT * M_FLUX%SATAREA + + end associate ! end association with variables in the data structures + END SUBROUTINE QSATEXCESS_DIFF + +end module QSATEXCESS_DIFF_MODULE diff --git a/build/FUSE_SRC/physics/smoothers.f90 b/build/FUSE_SRC/physics/smoothers.f90 new file mode 100644 index 0000000..7ed972d --- /dev/null +++ b/build/FUSE_SRC/physics/smoothers.f90 @@ -0,0 +1,307 @@ +module smoothers + + implicit none + + private + public:: sigmoid,dsigmoid + public:: LOGISMOOTH + public:: smoother + public:: smax,dsmax + public:: smin,dsmin + public:: sfrac,dsfrac + public:: sclamp,dsclamp + +contains + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + PURE FUNCTION sfrac(x,xmax,ms) result(xf) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Use smoothed min function to compute smooth fraction + ! --------------------------------------------------------------------------------------- + USE nrtype + implicit none + real(sp), intent(in) :: x ! x value + real(sp), intent(in) :: xmax ! maximum value + real(sp), intent(in) :: ms ! smoothing parameter + real(sp) :: xp ! smooth min(x,xmax) + real(sp) :: xf ! smooth fraction x/xmax + xp = xmax - smax(xmax - x, 0._sp, ms) ! smooth version of min(x, xmax) + xf = max(0._sp, xp) / xmax ! use max(0._sp, xp) to account for small neg values at zero + end function sfrac + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + PURE FUNCTION dsfrac(x,xmax,ms) result(dxf_dx) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Get derivative of the smooth fraction + ! --------------------------------------------------------------------------------------- + USE nrtype + implicit none + real(sp), intent(in) :: x ! x value + real(sp), intent(in) :: xmax ! maximum value + real(sp), intent(in) :: ms ! smoothing parameter + real(sp) :: dxp_dx ! derivative of the max smoother + real(sp) :: dxf_dx ! derivative of the smoothed fraction + ! NOTE: ignore the hard clamp at zero (very small differences and not worth the extra expense) + dxp_dx = dsmax(xmax - x, 0._sp, ms) ! note signs cancel out + dxf_dx = dxp_dx / xmax + end function dsfrac + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + PURE FUNCTION smax(x,xmin,ms) result(xp) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Compute smoothed max function following Kavetski and Kuczera (2007) + ! + ! Kavetski, D. and Kuczera, G., 2007. Model smoothing strategies to remove microscale + ! discontinuities and spurious secondary optima in objective functions in hydrological + ! calibration. Water Resources Research, 43(3). + ! --------------------------------------------------------------------------------------- + USE nrtype + implicit none + real(sp), intent(in) :: x ! x value + real(sp), intent(in) :: xmin ! minimum value + real(sp), intent(in) :: ms ! smoothing parameter + real(sp) :: srt ! sqrt(x*x + ms) + real(sp) :: xp ! smooth max(x,xmin) + srt = sqrt((x-xmin)**2 + ms) + xp = 0.5_sp*(x + xmin + srt) ! smooth max(x,xmin) + end function smax + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + PURE FUNCTION dsmax(x,xmin,ms) result(dxp) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Compute derivative of smoothed max function of Kavetski and Kuczera (2007) + ! + ! Kavetski, D. and Kuczera, G., 2007. Model smoothing strategies to remove microscale + ! discontinuities and spurious secondary optima in objective functions in hydrological + ! calibration. Water Resources Research, 43(3). + ! --------------------------------------------------------------------------------------- + USE nrtype + implicit none + real(sp), intent(in) :: x ! x value + real(sp), intent(in) :: xmin ! minimum value + real(sp), intent(in) :: ms ! smoothing parameter + real(sp) :: u ! x-xmin + real(sp) :: srt ! sqrt(x*x + ms) + real(sp) :: dxp ! derivative of smooth max(x,xmin) + u = x-xmin + srt = sqrt(u*u + ms) + dxp = 0.5_sp*(1._sp + u/srt) ! derivative of smooth max(x,xmin) + end function dsmax + + ! --------------------------------------------------------------------------------------- + ! Extra helper functions + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! compute smin, sclamp, and derivatives + ! --------------------------------------------------------------------------------------- + + pure function smin(x, xmax, ms) result(xp) + use nrtype + implicit none + real(sp), intent(in) :: x, xmax, ms + real(sp) :: xp + xp = xmax - smax(xmax - x, 0._sp, ms) + end function smin + + pure function dsmin(x, xmax, ms) result(dxp) + use nrtype + implicit none + real(sp), intent(in) :: x, xmax, ms + real(sp) :: dxp + dxp = dsmax(xmax - x, 0._sp, ms) + end function dsmin + + pure function sclamp(x, xmin, xmax, ms) result(xp) + use nrtype + implicit none + real(sp), intent(in) :: x, xmin, xmax, ms + real(sp) :: xp + xp = smax( smin(x, xmax, ms), xmin, ms ) + end function sclamp + + pure function dsclamp(x, xmin, xmax, ms) result(dxp) + use nrtype + implicit none + real(sp), intent(in) :: x, xmin, xmax, ms + real(sp) :: v + real(sp) :: dxp + v = smin(x, xmax, ms) + dxp = dsmax(v, xmin, ms) * dsmin(x, xmax, ms) + end function dsclamp + + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + pure real(sp) function sigmoid(z, beta) result(s) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! A simple sigmoid smoother centered on zero + ! --------------------------------------------------------------------------------------- + use nrtype + implicit none + real(sp), intent(in) :: z, beta + real(sp) :: zb + + zb = z/beta + + if (zb >= 0._sp) then + s = 1._sp / (1._sp + exp(-zb)) + else + s = exp(zb) / (1._sp + exp(zb)) + end if + + end function sigmoid + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + pure real(sp) function dsigmoid(s, beta) result(ds_dz) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Derivative in the sigmoid w.r.t. z given already have the sigmoid + ! --------------------------------------------------------------------------------------- + use nrtype + implicit none + real(sp), intent(in) :: s, beta + ds_dz = (s/beta) * (1._sp - s) + end function dsigmoid + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + + PURE FUNCTION smoother(STATE,STATE_MAX,PSMOOTH) result(w_func) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Provides the option of different smoothers + ! --------------------------------------------------------------------------------------- + USE nrtype + IMPLICIT NONE + REAL(SP), INTENT(IN) :: STATE ! model state + REAL(SP), INTENT(IN) :: STATE_MAX ! maximum model state + REAL(SP), INTENT(IN) :: PSMOOTH ! smoothing parameter (fraction of state) + real(sp) :: w_func ! smoothed threshold + real(sp) :: delta ! scale factor + + ! logistic smoothing (original) + w_func = LOGISMOOTH(STATE,STATE_MAX,PSMOOTH) + + ! qintic smoother (plays better with Newton) + !delta = MAX(PSMOOTH*STATE_MAX, 1.0e-6_SP*STATE_MAX) + !w_func = SMOOTHSTEP5_W(STATE,STATE_MAX,delta) + + end function smoother + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + PURE FUNCTION LOGISMOOTH(STATE,STATE_MAX,PSMOOTH) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Uses a logistic function to smooth the threshold at the top of a bucket + ! --------------------------------------------------------------------------------------- + USE nrtype + IMPLICIT NONE + REAL(SP), INTENT(IN) :: STATE ! model state + REAL(SP), INTENT(IN) :: STATE_MAX ! maximum model state + REAL(SP), INTENT(IN) :: PSMOOTH ! smoothing parameter (fraction of state) + real(sp) :: arg ! clamp argument + REAL(SP) :: ASMOOTH ! actual smoothing + REAL(SP) :: LOGISMOOTH ! FUNCTION name + ! --------------------------------------------------------------------------------------- + ASMOOTH = PSMOOTH*STATE_MAX ! actual smoothing + arg = -(STATE - (STATE_MAX - 5*ASMOOTH))/ASMOOTH ! argument + !arg = max(min(arg, 50._SP), -50._SP) ! clamp + LOGISMOOTH = 1._SP / ( 1._SP + EXP(arg) ) + ! --------------------------------------------------------------------------------------- + END FUNCTION LOGISMOOTH + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + PURE FUNCTION SMOOTHSTEP5_W(STATE, STATE_MAX, DELTA) RESULT(W) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Uses a qintic function to smooth the threshold at the top of a bucket + ! --------------------------------------------------------------------------------------- + USE nrtype + IMPLICIT NONE + REAL(SP), INTENT(IN) :: STATE, STATE_MAX, DELTA + REAL(SP) :: W, x + + x = (STATE - (STATE_MAX - DELTA)) / DELTA + IF (x <= 0._SP) THEN + W = 0._SP + ELSEIF (x >= 1._SP) THEN + W = 1._SP + ELSE + W = x*x*x*(10._SP + x*(-15._SP + 6._SP*x)) + END IF + END FUNCTION + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + PURE FUNCTION SMOOTHSTEP5_DWDS(STATE, STATE_MAX, DELTA) RESULT(DWDS) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Compute the derivative of the qintic function + ! --------------------------------------------------------------------------------------- + USE nrtype + IMPLICIT NONE + REAL(SP), INTENT(IN) :: STATE, STATE_MAX, DELTA + REAL(SP) :: DWDS, x + + IF (DELTA <= 0._SP) THEN + DWDS = 0._SP + RETURN + END IF + + x = (STATE - (STATE_MAX - DELTA)) / DELTA + IF (x <= 0._SP .OR. x >= 1._SP) THEN + DWDS = 0._SP + ELSE + DWDS = (30._SP * x*x * (1._SP - x)*(1._SP - x)) / DELTA + END IF + END FUNCTION + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + +end module smoothers diff --git a/build/FUSE_SRC/physics/update_swe_diff.f90 b/build/FUSE_SRC/physics/update_swe_diff.f90 new file mode 100644 index 0000000..5ea26b4 --- /dev/null +++ b/build/FUSE_SRC/physics/update_swe_diff.f90 @@ -0,0 +1,337 @@ +module update_swe_DIFF_MODULE + + USE model_defn ! model definition structure + USE model_defnames ! integer model definitions + USE globaldata, only : NA_VALUE_SP ! missing vale + + implicit none + + private + public :: update_swe_diff + +contains + + ! --------------------------------------------------------------------------------------- + pure logical function is_leap_year(y) + integer, intent(in) :: y + is_leap_year = (mod(y,4) == 0 .and. (mod(y,100) /= 0 .or. mod(y,400) == 0)) + end function is_leap_year + ! --------------------------------------------------------------------------------------- + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + SUBROUTINE UPDATE_SWE_DIFF(fuseStruct, DT, want_dparam) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Brian Henn, as part of FUSE snow model implementation, 6/2013 + ! Based on subroutines QSATEXCESS and UPDATSTATE, by Martyn Clark + ! + ! Modified by Nans Addor to enable distributed modeling, 9/2016 + ! + ! Modified by Martyn Clark to extend to a differentiable model, 12/2025 + ! + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Computes the snow accumulation and melt from forcing data + ! Then updates the SWE band states based on the fluxes + ! --------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. (includes PI) + USE work_types, only: fuse_work ! fuse work type + use smoothers, only: smax, dsmax ! max smoothers + use smoothers, only: smin, dsmin ! min smoothers (based on smax, dsmax) + use smoothers, only: sigmoid, dsigmoid ! sigmoid smoothers + USE globaldata, only: NP => NPAR_SNOW ! number of snow parameters + USE globaldata, only: iMBASE, iMFMAX, iMFMIN, iPXTEMP, iOPG, iLAPSE, & ! indices in vectors + iPERR ! not a snow parameter but used in the snow model + USE multibands, only: N_BANDS ! number of elevation bands + IMPLICIT NONE + ! input + type(fuse_work) , intent(inout) :: fuseStruct ! fuse work structure + REAL(SP), INTENT(IN) :: DT ! length of the time step + logical(lgt), intent(in), optional :: want_dparam ! if we want parameter derivatives + ! ----- internal variables ----------------------------------------------------------------------------- + ! general + INTEGER(I4B) :: ISNW ! loop through snow model bands + REAL(SP) :: DZ ! vert. distance from forcing + real(sp) :: SWE_prev ! SWE at start of band update (mm) + ! melt factor + LOGICAL(LGT) :: LEAP ! leap year flag + REAL(SP) :: JDAY ! Julian day of year + integer(i4b) :: days_in_year ! number of days in year (365 or 366) + integer(i4b) :: phase_shift ! shift in sine curve in days (80 or 81) + real(sp) :: season01 ! seasonal cycle scaled to [0,1] + REAL(SP) :: MF ! melt factor (mm/deg.C-6hr) -- NOTE: check units + ! adjusted precipitation (after precipitation multiplier) + real(sp), parameter :: ms_mult=1.e-4_sp ! smoothing in smax function (additive precip error) + real(sp) :: precip_adj ! adjusted precipitation (after multiplicative/additive error) + ! temperature lapse (simple) + real(sp) :: xLapse ! scaled temperature lapse rate + REAL(SP) :: TEMP_Z ! band temperature at timestep + ! orographic precipitation multiplier (OPG) + real(sp) :: xOPG ! DZ * MPARAM%OPG/1000 -- scaled OPG (dimensionless) + real(sp) :: gate ! hard [0,1] gate on DZ + real(sp) :: fpos ! positive-side formula: 1 + x + real(sp) :: fneg ! megative-side formula: 1/(1-x) + real(sp) :: inv ! 1-x: demominator in negative-side formula: 1/(1-x) + real(sp) :: inv_safe ! safe denominator: max(1-x, eps_inv) + real(sp), parameter :: eps_inv=1.e-6_sp ! denominator floor: dimensionless + real(sp) :: OPG_mult ! final OPG multiplier + REAL(SP) :: PRECIP_Z ! band precipitation at timestep + ! partition rain from snow + real(sp) :: fsnow ! fraction of precip falling as snow (0–1) + real(sp) :: snow ! snowfall rate (mm/day) for this band + real(sp) :: rain ! rainfall rate (mm/day) for this band + real(sp), parameter :: beta_px=0.01_sp ! sigmoid width for snow/rain partition (degC) + ! snowmelt + real(sp), parameter :: ms_temp=1.e-4_sp ! smoothing in smax function (temperature) + real(sp) :: posTemp ! positive-part temperature term used for melt (degC), smoothed + real(sp) :: potMelt ! potential melt rate before capping (mm/day) + real(sp) :: meltCap ! maximum feasible melt rate from availability (mm/day) + real(sp) :: snowmelt ! final (capped) melt rate (mm/day) + real(sp) :: swe_eps=1.e-12_sp ! small value for the derivative switch in u_swe clamp + real(sp) :: u_swe ! pre-clamp SWE update + integer(i4b), parameter :: cumdays0(12) = [ & ! cumulative days before the start of each month + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ] + integer(i4b) :: cumdays(12) ! cumulative days adjust for leap year + ! internal variables: paraneter derivatives + logical(lgt) :: comp_dparam ! flag to compute parameter derivatives + real(sp) :: df_dz ! precip partitioning + real(sp) :: active, dfpos_dOPG, dinv_dOPG, dfneg_dOPG, dmult_dOPG ! OPG + real(sp) :: dMF(NP), dPadj(NP), dPrecZ(NP), dTempZ(NP) ! derivative vectors + real(sp) :: dfsnow(NP), dsnow(NP), drain(NP) ! derivative vectors + real(sp) :: g_pos, dposTemp(NP), dpotMelt(NP), dsnowmelt(NP) ! derivative vectors + real(sp) :: g_u, dSWE(NP), dSWE_new(NP) ! persist dSWE between timesteps for each band + ! --------------------------------------------------------------------------------------- + ! associate variables with elements of data structure + associate(& + TIMDAT => fuseStruct%time , & ! time information + MFORCE => fuseStruct%force , & ! forcing data + Z_FORC => fuseStruct%z_forcing , & ! elevation of the forcing data + M_FLUX => fuseStruct%flux , & ! fluxes + MBANDS => fuseStruct%sbands , & ! elevation band variables: MBANDS(i)%var, MBANDS(i)info + MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%param_derive & ! derived model parameters + ) ! (associate) + ! --------------------------------------------------------------------------------------- + ! snow accumulation and melt calculations for each band + ! also calculates effective precipitation + ! --------------------------------------------------------------------------------------- + + ! check the need to compute flux derivatives + comp_dparam = .false.; if(present(want_dparam)) comp_dparam = want_dparam + + ! zero derivatives for fluxes constant over elevation bands + if(comp_dparam)then + dMF(:) = 0._sp; dPadj(:) = 0._sp + endif + + ! ----- compute the melt factor --------------------------------------------------------- + + ! adjust cumulative days for leap year + leap = is_leap_year(timDat%IY) + cumdays = cumdays0; if (leap) cumdays(3:12) = cumdays(3:12) + 1 + + ! calculate day of year for melt factor calculation + jday = cumdays(timDat%IM) + timDat%ID + + ! seasonal cycle scaled to [0,1] + days_in_year = merge(366, 365, leap) + phase_shift = merge(81, 80, leap) ! keeps peak timing aligned across leap/non-leap + season01 = 0.5_sp * ( sin( (real(jday - phase_shift, sp) * 2._sp * PI) / real(days_in_year, sp) ) + 1._sp ) + + ! melt factor calculations + mf = MPARAM%MFMIN + season01*(MPARAM%MFMAX - MPARAM%MFMIN) + + ! compute derivatives + if(comp_dparam)then + + ! NOTE: MF = (1−season01)*MFMIN + season01*MFMAX + + dMF(iMFMIN) = 1._sp - season01 + dMF(iMFMAX) = season01 + + endif ! computing derivatives + + ! ----- add error to the precipiation --------------------------------------------------- + + SELECT CASE(SMODL%iRFERR) + CASE(iopt_additive_e); precip_adj = smax(MFORCE%PPT + MPARAM%RFERR_ADD, 0._sp, ms_mult) ! additive error + CASE(iopt_multiplc_e); precip_adj = MFORCE%PPT*MPARAM%RFERR_MLT ! multiplicative error + CASE DEFAULT; stop "swe_update_diff: unable to identify precip error model" + END SELECT + + ! compute derivatives + if(comp_dparam)then + + ! NOTE: parameter vector interprets theta(iPERR) as either RFERR_ADD or RFERR_MLT depending on SMODL%iRFERR + + SELECT CASE(SMODL%iRFERR) + CASE(iopt_additive_e); dPadj(iPERR) = dsmax(MFORCE%PPT + MPARAM%RFERR_ADD, 0._sp, ms_mult) ! additive error + CASE(iopt_multiplc_e); dPadj(iPERR) = MFORCE%PPT ! multiplicative error + CASE DEFAULT; stop "swe_update_diff: unable to identify precip error model" + END SELECT + + endif ! computing derivatives + + ! ----- check OPG ----------------------------------------------------------------------- + + if (MPARAM%OPG < 0._sp) then + stop "swe_update_diff: OPG < 0 not allowed with hard-gate OPG scheme" + end if + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + ! initialize effective precip + M_FLUX%EFF_PPT = 0._sp + + ! check band rea fractions sum to 1 + if (abs(sum(MBANDS(:)%info%AF) - 1._sp) > 1.e-6_sp) stop "Band area fractions do not sum to 1" + + ! loop through model bands + DO ISNW=1,N_BANDS + + ! save SWE + SWE_prev = MBANDS(ISNW)%var%SWE + + ! zero derivatives for elevation band fluxes + if(comp_dparam)then + dPrecZ(:) = 0._sp; dTempZ(:) = 0._sp + dfsnow(:) = 0._sp; dsnow(:) = 0._sp; drain(:) = 0._sp + dposTemp(:)=0._sp; dpotMelt(:)=0._sp; dsnowmelt(:)=0._sp + endif + + ! copy the stored sensitivity of SWE from the previous timestep to propagate it forward + if (comp_dparam) dSWE(:) = MBANDS(ISNW)%var%dSWE_dparam(:) + + ! --- use the Orographic Precipitation Gradient (OPG) to adjust precip for elevation --- + + ! dimensionless OPG + DZ = MBANDS(ISNW)%info%Z_MID - Z_FORC + xOPG = DZ * MPARAM%OPG / 1000._sp + + ! hard [0,1] gate by DZ sign (no smoothing): preserves original code from Henn et al. + gate = merge(1._sp, 0._sp, DZ >= 0._sp) ! gate = 1 if DZ >= 0 + + ! positive-side formula: 1 + x + fpos = 1._sp + xOPG + + ! negative-side formula: 1/(1-x), but with hard floor on denominator + inv = 1._sp - xOPG + inv_safe = max(inv, eps_inv) ! hard floor + fneg = 1._sp / inv_safe + + ! blended multiplier and band precip + OPG_mult = gate * fpos + (1._sp - gate) * fneg + PRECIP_Z = precip_adj * OPG_mult + + ! compute derivatives + if(comp_dparam)then + + ! derivative of fpos wrt OPG + dfpos_dOPG = DZ / 1000._sp + + ! derivative of fneg wrt OPG + active = merge(1._sp, 0._sp, inv >= eps_inv) ! deriv is zero if inv is clamped at eps_inv + dinv_dOPG = -(DZ / 1000._sp) ! inv = 1 - xOPG, xOPG = DZ*OPG/1000 + dfneg_dOPG = -(1._sp/(inv_safe*inv_safe)) * (active * dinv_dOPG) + + ! derivative of OPG_mult (ignore derivative of the hard gate) + dmult_dOPG = gate*dfpos_dOPG + (1._sp-gate)*dfneg_dOPG + + ! final derivatives + dPrecZ(:) = dPadj(:) * OPG_mult + dPrecZ(iOPG) = dPrecZ(iOPG) + precip_adj*dmult_dOPG + + endif ! computing derivatives + + ! ----- use the temperature lapse rate to adjust temperature for elevation ------------- + + xLapse = MPARAM%LAPSE/1000._sp ! scaled temperature lapse rate + TEMP_Z = MFORCE%TEMP + DZ*xLapse ! adjust for elevation using lapse rate + + ! compute derivatives + if(comp_dparam) dTempZ(iLAPSE) = DZ/1000._sp + + ! ----- calculate the (smoothed) snow accumulation ------------------------------------- + + ! snowfall and rainfall fluxes + fsnow = sigmoid(MPARAM%PXTEMP - TEMP_Z, beta_px) ! beta_px is the width, set small because originally a step function + snow = PRECIP_Z*fsnow + rain = PRECIP_Z*(1._sp - fsnow) + + MBANDS(ISNW)%var%SNOWACCMLTN = snow + + ! compute derivatives + if(comp_dparam)then + + df_dz = dsigmoid(fsnow, beta_px) ! d(fsnow)/d(z), z=PXTEMP - TEMP_Z + + dfsnow(iPXTEMP) = df_dz + dfsnow(:) = dfsnow(:) - df_dz * dTempZ(:) ! minus because z depends on -TEMP_Z + + dsnow(:) = dPrecZ(:)*fsnow + PRECIP_Z*dfsnow(:) + drain(:) = dPrecZ(:)*(1._sp - fsnow) - PRECIP_Z*dfsnow(:) + + endif ! computing derivatives + + ! ----- calculate the (smoothed) snow melt --------------------------------------------- + + ! potenital melt + posTemp = smax(TEMP_Z - MPARAM%MBASE, 0._sp, ms_temp) ! smoothed max(TEMP_Z - MPARAM%MBASE, 0) + potMelt = MF*posTemp ! mm day-1 + + ! cap snowmelt + meltCap = SWE_prev/DT + snowmelt = min(potMelt, meltCap) ! hard clamp: allow a kink at SWE=0 to avoid "ghost snow" + MBANDS(ISNW)%var%SNOWMELT = snowmelt + + ! compute derivatives + if(comp_dparam)then + + ! positive temperature: smoothed max(TEMP_Z - MPARAM%MBASE, 0) + g_pos = dsmax(TEMP_Z - MPARAM%MBASE, 0._sp, ms_temp) + dposTemp(:) = g_pos * dTempZ(:) + dposTemp(iMBASE) = dposTemp(iMBASE) - g_pos + + ! potential melt + dpotMelt(:) = dMF(:)*posTemp + MF*dposTemp(:) + + ! melt cap + dsnowmelt(:) = merge(dpotMelt(:), dSWE(:)/DT, potMelt <= meltcap) + + endif ! computing derivatives + + ! ----- update SWE --------------------------------------------------------------------- + + u_swe = SWE_prev + DT*(snow - snowmelt) + MBANDS(ISNW)%var%SWE = max(u_swe, 0._sp) ! hard clamp just removes numerical noise + + if(comp_dparam)then + g_u = merge(1._sp, 0._sp, u_swe > swe_eps) ! sensitivities zero in snow free periods + dSWE_new(:) = g_u * ( dSWE(:) + DT*(dsnow(:) - dsnowmelt(:)) ) + MBANDS(ISNW)%var%dSWE_dparam(:) = dSWE_new(:) + endif + + ! ----- calculate effective precip (rain + melt) --------------------------------------- + + M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + MBANDS(ISNW)%info%AF * (rain + snowmelt) + + if(comp_dparam)then + fuseStruct%df_dPar(1:NP)%EFF_PPT = fuseStruct%df_dPar(1:NP)%EFF_PPT + & + MBANDS(ISNW)%info%AF * (drain(:) + dsnowmelt(:)) + endif + + END DO ! looping through elevation bands + + end associate + + ! TEMPORARY: save the derivative as a "fake" loss function + fuseStruct%dL_dPar(:) = NA_VALUE_SP + fuseStruct%dL_dPar(1:NP) = fuseStruct%df_dPar(1:NP)%EFF_PPT + + END SUBROUTINE UPDATE_SWE_DIFF + +end module update_swe_DIFF_MODULE diff --git a/build/FUSE_SRC/physics_orig/update_swe.f90 b/build/FUSE_SRC/physics_orig/update_swe.f90 index 646f73f..90e8751 100644 --- a/build/FUSE_SRC/physics_orig/update_swe.f90 +++ b/build/FUSE_SRC/physics_orig/update_swe.f90 @@ -5,6 +5,7 @@ SUBROUTINE UPDATE_SWE(DT) ! Brian Henn, as part of FUSE snow model implementation, 6/2013 ! Based on subroutines QSATEXCESS and UPDATSTATE, by Martyn Clark ! Modified by Nans Addor to enable distributed modeling, 9/2016 +! Modified by Martyn Clark to enable the split info/var structure, 01/2026 ! --------------------------------------------------------------------------------------- ! Purpose: ! -------- @@ -59,60 +60,72 @@ SUBROUTINE UPDATE_SWE(DT) ! loop through model bands DO ISNW=1,N_BANDS - ! calculate forcing data for each band - DZ = MBANDS(ISNW)%Z_MID - Z_FORCING + ! --------------------------------------------------------------------------------------- + associate( & ! link to the info and var sub-structures in MBANDS (less invasive / more readable in code below) + z_mid => mbands(isnw)%info%z_mid, & + af => mbands(isnw)%info%af, & + swe => mbands(isnw)%var%swe, & + snowaccmltn => mbands(isnw)%var%snowaccmltn, & + snowmelt => mbands(isnw)%var%snowmelt, & + dswe_dt => mbands(isnw)%var%dswe_dt ) + + ! calculate forcing data for each band + DZ = Z_MID - Z_FORCING TEMP_Z = MFORCE%TEMP + DZ*MPARAM%LAPSE/1000._sp ! adjust for elevation using lapse rate IF (DZ.GT.0._sp) THEN ! adjust for elevation using OPG PRECIP_Z = MFORCE%PPT * (1._sp + DZ*MPARAM%OPG/1000._sp) ELSE PRECIP_Z = MFORCE%PPT / (1._sp - DZ*MPARAM%OPG/1000._sp) ENDIF - IF ((MBANDS(ISNW)%SWE.GT.0._sp).AND.(TEMP_Z.GT.MPARAM%MBASE)) THEN + IF ((SWE.GT.0._sp).AND.(TEMP_Z.GT.MPARAM%MBASE)) THEN ! calculate the initial snowmelt rate from the melt factor and the temperature - MBANDS(ISNW)%SNOWMELT = MF*(TEMP_Z - MPARAM%MBASE) ! MBANDS%SNOWMELT has units of mm day-1 + SNOWMELT = MF*(TEMP_Z - MPARAM%MBASE) ! MBANDS%SNOWMELT has units of mm day-1 ELSE - MBANDS(ISNW)%SNOWMELT = 0.0_sp + SNOWMELT = 0.0_sp ENDIF ! calculate the accumulation rate from the forcing data IF (TEMP_Z.LT.MPARAM%PXTEMP) THEN SELECT CASE(SMODL%iRFERR) CASE(iopt_additive_e) ! additive rainfall error - MBANDS(ISNW)%SNOWACCMLTN = MAX(0.0_sp, PRECIP_Z + MPARAM%RFERR_ADD) + SNOWACCMLTN = MAX(0.0_sp, PRECIP_Z + MPARAM%RFERR_ADD) CASE(iopt_multiplc_e) ! multiplicative rainfall error - MBANDS(ISNW)%SNOWACCMLTN = PRECIP_Z * MPARAM%RFERR_MLT + SNOWACCMLTN = PRECIP_Z * MPARAM%RFERR_MLT CASE DEFAULT ! check for errors print *, "SMODL%iRFERR must be either iopt_additive_e or iopt_multiplc_e" STOP END SELECT ELSE - MBANDS(ISNW)%SNOWACCMLTN = 0.0_sp + SNOWACCMLTN = 0.0_sp ENDIF ! update SWE, and check to ensure non-negative values - MBANDS(ISNW)%DSWE_DT = MBANDS(ISNW)%SNOWACCMLTN - MBANDS(ISNW)%SNOWMELT - IF ((MBANDS(ISNW)%SWE + MBANDS(ISNW)%DSWE_DT*DT).GE.0._sp) THEN - MBANDS(ISNW)%SWE = MBANDS(ISNW)%SWE + MBANDS(ISNW)%DSWE_DT*DT + DSWE_DT = SNOWACCMLTN - SNOWMELT + IF ((SWE + DSWE_DT*DT).GE.0._sp) THEN + SWE = SWE + DSWE_DT*DT ELSE ! reduce melt rate in case of negative SWE - MBANDS(ISNW)%SNOWMELT = MBANDS(ISNW)%SWE/DT + MBANDS(ISNW)%SNOWACCMLTN - MBANDS(ISNW)%SWE = 0.0_sp + SNOWMELT = SWE/DT + SNOWACCMLTN + SWE = 0.0_sp ENDIF ! calculate rainfall plus snowmelt IF (TEMP_Z.GT.MPARAM%PXTEMP) THEN SELECT CASE(SMODL%iRFERR) CASE(iopt_additive_e) ! additive rainfall error - M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + MBANDS(ISNW)%AF * & - (MAX(0.0_sp, PRECIP_Z + MPARAM%RFERR_ADD) + MBANDS(ISNW)%SNOWMELT) + M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + AF * & + (MAX(0.0_sp, PRECIP_Z + MPARAM%RFERR_ADD) + SNOWMELT) CASE(iopt_multiplc_e) ! multiplicative rainfall error - M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + MBANDS(ISNW)%AF * & - (PRECIP_Z * MPARAM%RFERR_MLT + MBANDS(ISNW)%SNOWMELT) + M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + AF * & + (PRECIP_Z * MPARAM%RFERR_MLT + SNOWMELT) CASE DEFAULT ! check for errors print *, "SMODL%iRFERR must be either iopt_additive_e or iopt_multiplc_e" STOP END SELECT ELSE - M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + MBANDS(ISNW)%AF * MBANDS(ISNW)%SNOWMELT + M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + AF * SNOWMELT ENDIF -END DO + + end associate + +END DO ! looping through bands END SUBROUTINE UPDATE_SWE diff --git a/build/FUSE_SRC/prelim/init_state.f90 b/build/FUSE_SRC/prelim/init_state.f90 index c5a4f41..1358d3c 100644 --- a/build/FUSE_SRC/prelim/init_state.f90 +++ b/build/FUSE_SRC/prelim/init_state.f90 @@ -36,7 +36,7 @@ SUBROUTINE INIT_STATE(FRAC) FSTATE%WATR_2 = MPARAM%MAXWATR_2 * FRAC ! snow model, assume no snow at start DO ISNW=1,N_BANDS - MBANDS(ISNW)%SWE = 0.0_sp + MBANDS(ISNW)%VAR%SWE = 0.0_sp END DO ! (routed runoff) FUTURE = 0._sp diff --git a/build/FUSE_SRC/runtime/initfluxes.f90 b/build/FUSE_SRC/runtime/initfluxes.f90 index 230781d..dd41bab 100644 --- a/build/FUSE_SRC/runtime/initfluxes.f90 +++ b/build/FUSE_SRC/runtime/initfluxes.f90 @@ -42,8 +42,8 @@ SUBROUTINE INITFLUXES() M_FLUX%OFLOW_2B = 0._sp; W_FLUX%OFLOW_2B = 0._sp IF(SMODL%iSNOWM.EQ.iopt_temp_index) THEN !loop through snow model bands DO ISNW=1,N_BANDS - MBANDS(ISNW)%SNOWACCMLTN = 0._sp - MBANDS(ISNW)%SNOWMELT = 0._sp + MBANDS(ISNW)%var%SNOWACCMLTN = 0._sp + MBANDS(ISNW)%var%SNOWMELT = 0._sp END DO ENDIF M_FLUX%ERR_WATR_1 = 0._sp; W_FLUX%ERR_WATR_1 = 0._sp diff --git a/build/FUSE_SRC/runtime/set_all.f90 b/build/FUSE_SRC/runtime/set_all.f90 index ed3d0e7..071dc0e 100644 --- a/build/FUSE_SRC/runtime/set_all.f90 +++ b/build/FUSE_SRC/runtime/set_all.f90 @@ -39,7 +39,7 @@ SUBROUTINE SET_STATE(VAL) ! snow model DO ISNW=1,N_BANDS - MBANDS(ISNW)%SWE = VAL + MBANDS(ISNW)%var%SWE = VAL END DO FSTATE%SWE_TOT = VAL @@ -88,8 +88,8 @@ SUBROUTINE SET_FLUXES(VAL) M_FLUX%OFLOW_2B = VAL; W_FLUX%OFLOW_2B = VAL IF(SMODL%iSNOWM.EQ.iopt_temp_index) THEN !loop through snow model bands DO ISNW=1,N_BANDS - MBANDS(ISNW)%SNOWACCMLTN = VAL - MBANDS(ISNW)%SNOWMELT = VAL + MBANDS(ISNW)%var%SNOWACCMLTN = VAL + MBANDS(ISNW)%var%SNOWMELT = VAL END DO ENDIF M_FLUX%ERR_WATR_1 = VAL; W_FLUX%ERR_WATR_1 = VAL @@ -153,10 +153,10 @@ SUBROUTINE SET_SNOW(VAL) ! --------------------------------------------------------------------------------------- DO IBANDS=1,N_BANDS - MBANDS(IBANDS)%SWE=VAL ! band snowpack water equivalent (mm) - MBANDS(IBANDS)%SNOWACCMLTN=VAL ! new snow accumulation in band (mm day-1) - MBANDS(IBANDS)%SNOWMELT=VAL ! snowmelt in band (mm day-1) - MBANDS(IBANDS)%DSWE_DT=VAL ! rate of change of band SWE (mm day-1) + MBANDS(IBANDS)%var%SWE=VAL ! band snowpack water equivalent (mm) + MBANDS(IBANDS)%var%SNOWACCMLTN=VAL ! new snow accumulation in band (mm day-1) + MBANDS(IBANDS)%var%SNOWMELT=VAL ! snowmelt in band (mm day-1) + MBANDS(IBANDS)%var%DSWE_DT=VAL ! rate of change of band SWE (mm day-1) END DO ! --------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/share/model_numerix.f90 b/build/FUSE_SRC/share/model_numerix.f90 index 8aefa42..030073e 100644 --- a/build/FUSE_SRC/share/model_numerix.f90 +++ b/build/FUSE_SRC/share/model_numerix.f90 @@ -30,6 +30,9 @@ MODULE model_numerix ! 6. Method used to process the small interval at the end of a time step INTEGER(I4B), PARAMETER :: STEP_TRUNC=0, LOOK_AHEAD=1, STEP_ABSORB=2 INTEGER(I4B) :: SMALL_ENDSTEP +! 7. Flag for differentiable model +integer(i4b), parameter :: original=0, differentiable=1 +integer(i4b) :: diff_mode ! --------------------------------------------------------------------------------------- ! (B) PARAMETERS ! --------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/types/data_types.f90 b/build/FUSE_SRC/types/data_types.f90 new file mode 100644 index 0000000..46771e4 --- /dev/null +++ b/build/FUSE_SRC/types/data_types.f90 @@ -0,0 +1,70 @@ +module data_types + + use nrtype + + use multiforce_types, only: ADATA, FDATA, VDATA + use multibands_types, only: BANDS_VAR + use multistate_types, only: STATEV + use multi_flux_types, only: FLUXES + use multiroute_types, only: RUNOFF + + private + public :: coord_data, domain_data + + ! ------------------------------------------------------------------------------------- + + type :: coord_data + + logical(lgt) :: is_curvilinear = .false. ! true if lat/lon are 2D + logical(lgt) :: is_point_list = .false. ! true if nx=1 and lat/lon are 1D over ny + + ! 2D rectilinear OR point-list + real(sp), allocatable :: lon_1d(:) ! nx or ny depending on layout + real(sp), allocatable :: lat_1d(:) + + ! 2D curvilinear + real(sp), allocatable :: lon_2d(:,:) ! (nx_local, ny_local) + real(sp), allocatable :: lat_2d(:,:) + + ! optional IDs (int is usually safest) + integer(i4b), allocatable :: cell_id(:,:) ! always stored locally as (nx_local, ny_local) + + end type coord_data + + ! ------------------------------------------------------------------------------------- + + type :: domain_data + + ! coordinate information + type(coord_data) :: coords + + ! 2D ancillary forcing (optional, for PET etc.) + type(ADATA), allocatable :: ancil(:,:) ! (nx_local, ny_local) + + ! 3D forcing window (nx_local, ny_local, numtim_sub) + type(FDATA), allocatable :: force(:,:,:) ! force_3d + + ! 3D state window (nx_local, ny_local, numtim_sub+1) + type(STATEV), allocatable :: state(:,:,:) ! state_3d + + ! 3D flux window (nx_local, ny_local, numtim_sub) + type(FLUXES), allocatable :: flux(:,:,:) ! flux_3d + + ! 3D routing window (nx_local, ny_local, numtim_sub) + type(RUNOFF), allocatable :: route(:,:,:) ! route_3d + + ! 4D snow-band state window (nx_local, ny_local, n_bands, numtim_sub+1) + type(BANDS_VAR), allocatable :: bands(:,:,:,:) ! bands_var_4d + + ! 3D observed discharge / validity (optional) + type(VDATA), allocatable :: valid(:,:,:) ! (nx_local, ny_local, numtim_sub) + + ! basin-average time series for output convenience + type(FDATA), allocatable :: aForce(:) ! (numtim_sub) + type(RUNOFF), allocatable :: aRoute(:) ! (numtim_sub) + + end type domain_data + + ! ------------------------------------------------------------------------------------- + +end module data_types diff --git a/build/FUSE_SRC/types/info_types.f90 b/build/FUSE_SRC/types/info_types.f90 new file mode 100644 index 0000000..8721942 --- /dev/null +++ b/build/FUSE_SRC/types/info_types.f90 @@ -0,0 +1,182 @@ +module info_types + + use nrtype + + use multiparam_types, only: par_id + + private + public :: cli_options + public :: fuse_info + + ! -------------------------------------------------------------------------------------- + + type :: mpi_info + logical(lgt) :: enabled = .false. + integer(i4b) :: rank = 0 + integer(i4b) :: nproc = 1 + end type mpi_info + + ! ------------------------------------------------------------------------------------- + + ! options for the command-line interface + + type :: cli_options + character(len=:), allocatable :: tag ! string to add to output file + character(len=:), allocatable :: control_file + character(len=:), allocatable :: domain_id + character(len=:), allocatable :: runmode ! def/idx/opt/sce + character(len=:), allocatable :: sets_file ! for idx,opt + integer(i4b) :: indx = -1 ! for idx + character(len=:), allocatable :: restart_freq ! y/m/d/e/never + logical(lgt) :: show_version = .false. + logical(lgt) :: show_help = .false. + character(len=:), allocatable :: param_name(:) ! list of parameter names + real(sp), allocatable :: param_value(:) ! list of parameter values + end type cli_options + + ! ------------------------------------------------------------------------------------- + + type :: space_info + + ! global dimensions (full forcing file) + integer(i4b) :: nx_global = 1 + integer(i4b) :: ny_global = 1 + + ! local dimensions (after MPI split) + integer(i4b) :: nx_local = 1 + integer(i4b) :: ny_local = 1 + + ! decomposition along y dimension + integer(i4b) :: y_start_global = 1 + integer(i4b) :: y_end_global = 1 + + ! mode flag + logical(lgt) :: grid_flag = .false. + + end type space_info + + ! ------------------------------------------------------------------------------------- + + type :: time_info + + ! forcing axis (global) + integer(i4b) :: nt_global = 0 + + ! simulation & evaluation indices into forcing time axis + integer(i4b) :: sim_beg = 1 + integer(i4b) :: sim_end = 1 + integer(i4b) :: eval_beg = 1 + integer(i4b) :: eval_end = 1 + + ! derived lengths + integer(i4b) :: nt_sim = 0 + + ! subperiod / windowing + logical(lgt) :: use_subperiods = .false. + integer(i4b) :: nt_window = 0 ! (= numtim_sub) + integer(i4b) :: nt_window_cur = 0 ! runtime: current window length + + ! bookkeeping for time axis + character(len=:), allocatable :: units + real(sp) :: jdate_ref = 0._sp + real(sp), allocatable :: jdate(:) ! julian day for each forcing record + + end type time_info + + ! ------------------------------------------------------------------------------------- + + type :: snow_info + integer(i4b) :: n_bands = 0 + end type snow_info + + ! ------------------------------------------------------------------------------------- + + type :: file_info + + ! directories + character(len=512) :: setngs_path = "" + character(len=512) :: input_path = "" + character(len=512) :: output_path = "" + + ! settings filenames (relative or absolute) + character(len=512) :: forcinginfo = "" + character(len=512) :: constraints = "" + character(len=512) :: mod_numerix = "" + character(len=512) :: m_decisions = "" + + ! domain-derived input suffixes + character(len=512) :: suffix_forcing = "" + character(len=512) :: suffix_elev_bands = "" + + ! actual input filenames for this domain (derived once dom_id known) + character(len=512) :: forcing_file = "" ! dom_id//suffix_forcing + character(len=512) :: elevbands_file = "" ! dom_id//suffix_elev_bands + + ! output base name + concrete outputs + character(len=512) :: fname_tempry = "" + character(len=512) :: fname_netcdf_runs = "" + character(len=512) :: fname_netcdf_para = "" + + end type file_info + + ! ------------------------------------------------------------------------------------- + + type :: run_config + + ! provenance + character(len=512) :: file_manager_file = "" + + ! CLI options + type(cli_options) :: cli_opts + + ! model selection + character(len=64) :: fmodel_id = "" + + ! model information + integer(i4b) :: nState = -9999 + integer(i4b) :: nParam = -9999 + + ! list of model parameters + type(par_id), allocatable :: listParam(:) + + ! run flags + logical(lgt) :: q_only = .false. + + ! requested time windows (strings as read from filemanager) + character(len=20) :: date_start_sim = "" + character(len=20) :: date_end_sim = "" + character(len=20) :: date_start_eval = "" + character(len=20) :: date_end_eval = "" + character(len=20) :: numtim_sub_str = "" + + ! parsed / derived values (optional convenience) + integer(i4b) :: numtim_sub = -9999 ! parsed from numtim_sub_str + + ! output dimension for number of parameter sets + integer(i4b) :: nSets + + ! SCE settings (store as numeric types) + integer(i4b) :: maxn = -9999 + integer(i4b) :: kstop = -9999 + real(sp) :: pcento = -9999._sp + + ! store raw strings too if you care about provenance + character(len=20) :: maxn_str = "" + character(len=20) :: kstop_str = "" + character(len=20) :: pcento_str = "" + + end type run_config + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + type :: fuse_info + type(mpi_info) :: mpi + type(space_info) :: space + type(time_info) :: time + type(snow_info) :: snow + type(file_info) :: files + type(run_config) :: config + end type fuse_info + +end module info_types diff --git a/build/FUSE_SRC/types/multibands_types.f90 b/build/FUSE_SRC/types/multibands_types.f90 index e045eec..8691c67 100644 --- a/build/FUSE_SRC/types/multibands_types.f90 +++ b/build/FUSE_SRC/types/multibands_types.f90 @@ -12,20 +12,10 @@ MODULE multibands_types public :: BANDS, BANDS_INFO, BANDS_VAR - - TYPE BANDS ! for catchment scale modeling - INTEGER(I4B) :: NUM ! band number (-) - REAL(SP) :: Z_MID ! band mid-point elevation (m) - REAL(SP) :: AF ! fraction of basin area in band (-) - REAL(SP) :: SWE ! band snowpack water equivalent (mm) - REAL(SP) :: SNOWACCMLTN ! new snow accumulation in band (mm day-1) - REAL(SP) :: SNOWMELT ! snowmelt in band (mm day-1) - REAL(SP) :: DSWE_DT ! rate of change of band SWE (mm day-1) - ENDTYPE BANDS - - ! for distributed modeling MBANDS is split between time-independent and time-dependent charactertistics + ! MBANDS is split between time-independent and time-dependent charactertistics TYPE BANDS_INFO ! invariant characteristics + INTEGER(I4B) :: NUM ! band number (-) REAL(SP) :: Z_MID ! band mid-point elevation (m) REAL(SP) :: AF ! fraction of basin area in band (-) ENDTYPE BANDS_INFO @@ -37,4 +27,11 @@ MODULE multibands_types REAL(SP) :: DSWE_DT ! rate of change of band SWE (mm day-1) ENDTYPE BANDS_VAR + ! Combined structure + + TYPE BANDS + type(BANDS_INFO) :: info + type(BANDS_VAR) :: var + ENDTYPE BANDS + END MODULE multibands_types diff --git a/build/FUSE_SRC/types/work_types.f90 b/build/FUSE_SRC/types/work_types.f90 new file mode 100644 index 0000000..2c1ee0f --- /dev/null +++ b/build/FUSE_SRC/types/work_types.f90 @@ -0,0 +1,60 @@ +module work_types + + ! data types + + use nrtype + + use multiforce_types, only: TDATA, VDATA, ADATA, FDATA + use multibands_types, only: BANDS, BANDS_INFO, BANDS_VAR + use multiparam_types, only: PARATT, PARINFO, PARADJ, PARDVD, PAR_ID + use multistate_types, only: STATEV, M_TIME + use multi_flux_types, only: FLUXES + use multiroute_types, only: RUNOFF + + use multistats_types, only: SUMMARY + + private + + public :: bands_var_diff, ebands + public :: fuse_work + + ! -------------------------------------------------------------------------------------- + + ! dSWE/dParam for each elevation band + + type, extends(bands_var) :: bands_var_diff + real(sp), allocatable :: dSWE_dParam(:) + end type bands_var_diff + + ! extended bands structure + type ebands + type(bands_info) :: info + type(bands_var_diff) :: var + end type ebands + + ! -------------------------------------------------------------------------------------- + + ! omnibus structure that bundles "everything" required to run fuse for a single cell + + type fuse_work + type(tdata) :: time ! time data + type(fdata) :: force ! model forcing data + type(ebands) , allocatable :: sbands(:) ! info/variables for elevation bands (snow model) + type(statev) :: state0 ! state variables (start of step) + type(statev) :: state1 ! state variables (end of step) + type(statev) :: dx_dt ! time derivative in state variables + type(fluxes) :: flux ! fluxes + type(fluxes), allocatable :: df_dS(:) ! derivative in fluxes w.r.t. states + type(fluxes), allocatable :: df_dPar(:) ! derivative in fluxes w.r.t. parameters + real(sp), allocatable :: dL_dPar(:) ! derivative in loss function w.r.t. parameters + type(runoff) :: route ! hillslope routing + type(par_id) :: param_name ! parameter names + type(parinfo) :: param_meta ! metadata on model parameters + type(paradj) :: param_adjust ! adjustable model parametrs + type(pardvd) :: param_derive ! derived model parameters + type(summary) :: sim_stats ! simulation statistics + real(sp) :: z_forcing ! elevation of forcing data (m) + logical(lgt) :: is_initialized = .false. + end type fuse_work + +end module work_types diff --git a/build/FUSE_SRC/util/metaoutput.f90 b/build/FUSE_SRC/util/metaoutput.f90 index 66765a1..77801b0 100644 --- a/build/FUSE_SRC/util/metaoutput.f90 +++ b/build/FUSE_SRC/util/metaoutput.f90 @@ -1,113 +1,121 @@ MODULE metaoutput -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007 -! Modified by Brian Henn to include snow model, 6/2013 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Describe all variables used in the model (used to define NetCDF output files, etc.) -! --------------------------------------------------------------------------------------- -! variable definitions -USE nrtype -USE multibands,ONLY:N_BANDS -USE model_defn,ONLY:SMODL -USE model_defnames -IMPLICIT NONE -CHARACTER(LEN=11), DIMENSION(200) :: VNAME ! variable names -CHARACTER(LEN=52), DIMENSION(200) :: LNAME ! variable long names (descrition of variable) -CHARACTER(LEN=13), DIMENSION(200) :: VUNIT ! variable units -INTEGER(I4B) :: I ! loop through variables -INTEGER(I4B) :: NOUTVAR ! number of output variables -INTEGER(I4B) :: ISNW ! loop through SWE states -CHARACTER(LEN=2) :: TXT_ISNW ! band index as a character -CONTAINS -! --------------------------------------------------------------------------------------- -SUBROUTINE VARDESCRIBE() -I=0 ! initialize counter -! model forcing -I=I+1; VNAME(I)='ppt '; LNAME(I)='precipitation rate '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='pet '; LNAME(I)='potential evapotranspiration rate '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='temp '; LNAME(I)='mean air temperature '; VUNIT(I)='deg.C ' -I=I+1; VNAME(I)='obsq '; LNAME(I)='observed runoff '; VUNIT(I)='mm timestep-1' -! model states -I=I+1; VNAME(I)='tens_1 '; LNAME(I)='tension storage in the upper layer '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='tens_1a '; LNAME(I)='tension storage in the soil excess zone '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='tens_1b '; LNAME(I)='tension storage in the soil recharge zone '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='free_1 '; LNAME(I)='free storage in the upper layer '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='watr_1 '; LNAME(I)='total storage in the upper layer '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='tens_2 '; LNAME(I)='tension storage in the lower layer '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='free_2 '; LNAME(I)='free storage in the lower layer '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='free_2a '; LNAME(I)='free storage in the primary baseflow reservoir '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='free_2b '; LNAME(I)='free storage in the secondary baseflow reservoir '; VUNIT(I)='mm ' -I=I+1; VNAME(I)='watr_2 '; LNAME(I)='total storage in the lower layer '; VUNIT(I)='mm ' -IF(SMODL%iSNOWM.EQ.iopt_temp_index) THEN !loop through snow model bands + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Martyn Clark to use an elevation band dimension, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Describe all variables used in the model (used to define NetCDF output files, etc.) + ! --------------------------------------------------------------------------------------- + ! variable definitions - print *, 'Creating variables for the snow model for ', N_BANDS ,'elevation bands' + USE nrtype - I=I+1; VNAME(I)='swe_tot '; LNAME(I)='total storage as snow '; VUNIT(I)='mm ' + IMPLICIT NONE - DO ISNW=1,N_BANDS ! output each for each snow model band - WRITE(TXT_ISNW,'(I2)') ISNW ! convert band no. to text - IF (ISNW.LT.10) TXT_ISNW(1:1) = '0' ! pad with zeros - I=I+1; VNAME(I)='swe_z'//TXT_ISNW//' '! first create SWE band series - LNAME(I)='elevation band snow water equivalent '; VUNIT(I)='mm ' - I=I+1; VNAME(I)='snwacml_z'//TXT_ISNW ! then the accumulation series - LNAME(I)='new band snowpack accumulation, in water equivalent'; VUNIT(I)='mm timestep-1' - I=I+1; VNAME(I)='snwmelt_z'//TXT_ISNW ! then the melt series - LNAME(I)='band snowpack melt, in water equivalent '; VUNIT(I)='mm timestep-1' - END DO + private + public :: VARDESCRIBE ! subroutine + public :: VNAME, LNAME, VUNIT ! metadata + public :: isBand, isFlux ! flags + public :: NOUTVAR -ENDIF + CHARACTER(LEN=11), DIMENSION(200) :: VNAME ! variable names + CHARACTER(LEN=52), DIMENSION(200) :: LNAME ! variable long names (descrition of variable) + CHARACTER(LEN=13), DIMENSION(200) :: VUNIT ! variable units + logical(lgt), DIMENSION(200) :: isBand ! flag to denote variable for elevation band + logical(lgt), DIMENSION(200) :: isFlux ! flag to denote variable for model fluxes + INTEGER(I4B) :: NOUTVAR ! number of output variables -! model fluxes -I=I+1; VNAME(I)='eff_ppt '; LNAME(I)='effective precipitation rate '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='satarea '; LNAME(I)='saturated area '; VUNIT(I)='- ' -I=I+1; VNAME(I)='qsurf '; LNAME(I)='surface runoff '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='evap_1a '; LNAME(I)='evaporation from soil excess zone '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='evap_1b '; LNAME(I)='evaporation from soil recharge zone '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='evap_1 '; LNAME(I)='evaporation from the upper soil layer '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='evap_2 '; LNAME(I)='evaporation from the lower soil layer '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='rchr2excs '; LNAME(I)='flow from recharge zone to excess zone '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='tens2free_1'; LNAME(I)='flow from tension to free storage, lower layer '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='oflow_1 '; LNAME(I)='bucket overflow from upper soil layer '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='tens2free_2'; LNAME(I)='flow from tension to free storage, lower layer '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='qintf_1 '; LNAME(I)='interflow '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='qperc_12 '; LNAME(I)='percolation from upper to lower soil layer '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='qbase_2 '; LNAME(I)='baseflow '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='qbase_2a '; LNAME(I)='baseflow from primary baseflow reservoir '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='qbase_2b '; LNAME(I)='baseflow from secondary baseflow reservoir '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='oflow_2 '; LNAME(I)='bucket overflow from lower soil layer '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='oflow_2a '; LNAME(I)='bucket overflow from primary baseflow reservoir '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='oflow_2b '; LNAME(I)='bucket overflow from secondary baseflow reservoir '; VUNIT(I)='mm timestep-1' -! errors in model states (due to excessive extrapolation) -I=I+1; VNAME(I)='err_tens_1 '; LNAME(I)='excessive extrapolation: upper tension storage '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_tens_1a'; LNAME(I)='excessive extrapolation: upper excs tension storage'; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_tens_1b'; LNAME(I)='excessive extrapolation: upper rech tension storage'; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_free_1 '; LNAME(I)='excessive extrapolation: upper free storage '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_watr_1 '; LNAME(I)='excessive extrapolation: upper total storage '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_tens_2 '; LNAME(I)='excessive extrapolation: lower tension storage '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_free_2 '; LNAME(I)='excessive extrapolation: lower free storage '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_free_2a'; LNAME(I)='excessive extrapolation: 1st baseflow reservoir '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_free_2b'; LNAME(I)='excessive extrapolation: 2nd baseflow reservoir '; VUNIT(I)='mm day-1 ' -I=I+1; VNAME(I)='err_watr_2 '; LNAME(I)='excessive extrapolation: lower total storage '; VUNIT(I)='mm day-1 ' -! time check -I=I+1; VNAME(I)='chk_time '; LNAME(I)='length of time step included in weighted average '; VUNIT(I)='days ' -! model numerix -I=I+1; VNAME(I)='num_funcs '; LNAME(I)='number of function calls '; VUNIT(I)='- ' -I=I+1; VNAME(I)='numjacobian'; LNAME(I)='number of times the Jacobian is calculated '; VUNIT(I)='- ' -I=I+1; VNAME(I)='sub_accept' ; LNAME(I)='number of sub-steps accepted (taken) '; VUNIT(I)='- ' -I=I+1; VNAME(I)='sub_reject' ; LNAME(I)='number of sub-steps tried but rejected '; VUNIT(I)='- ' -I=I+1; VNAME(I)='sub_noconv' ; LNAME(I)='number of sub-steps tried that did not converge '; VUNIT(I)='- ' -I=I+1; VNAME(I)='max_iterns' ; LNAME(I)='maximum number of iterations in implicit euler '; VUNIT(I)='- ' -! model runoff (for BATEA, assumed to be last) -I=I+1; VNAME(I)='q_instnt '; LNAME(I)='instantaneous runoff '; VUNIT(I)='mm timestep-1' -I=I+1; VNAME(I)='q_routed '; LNAME(I)='routed runoff '; VUNIT(I)='mm timestep-1' + CONTAINS + ! --------------------------------------------------------------------------------------- -print *, 'Setting NOUTVAR (number of forcing, state and flux variables) to', I -NOUTVAR=I + SUBROUTINE VARDESCRIBE() + implicit none + INTEGER(I4B) :: I ! loop through variables + + I=0 ! initialize counter + + ! model forcing + I=I+1; VNAME(I)='ppt '; LNAME(I)='precipitation rate '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='pet '; LNAME(I)='potential evapotranspiration rate '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='temp '; LNAME(I)='mean air temperature '; VUNIT(I)='deg.C '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='obsq '; LNAME(I)='observed runoff '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.false. + + ! model states + I=I+1; VNAME(I)='tens_1 '; LNAME(I)='tension storage in the upper layer '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='tens_1a '; LNAME(I)='tension storage in the soil excess zone '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='tens_1b '; LNAME(I)='tension storage in the soil recharge zone '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='free_1 '; LNAME(I)='free storage in the upper layer '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='watr_1 '; LNAME(I)='total storage in the upper layer '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='tens_2 '; LNAME(I)='tension storage in the lower layer '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='free_2 '; LNAME(I)='free storage in the lower layer '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='free_2a '; LNAME(I)='free storage in the primary baseflow reservoir '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='free_2b '; LNAME(I)='free storage in the secondary baseflow reservoir '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='watr_2 '; LNAME(I)='total storage in the lower layer '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + + ! snow states + I=I+1; VNAME(I)='swe_tot '; LNAME(I)='total storage as snow '; VUNIT(I)='mm '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='swe_z '; LNAME(I)='elevation band snow water equivalent '; VUNIT(I)='mm '; isBand(i)=.true. ; isFlux(i)=.false. + + ! snow fluxes + I=I+1; VNAME(I)='snwacml_z '; LNAME(I)='new band snowpack accumulation, in water equivalent'; VUNIT(I)='mm timestep-1'; isBand(i)=.true. ; isFlux(i)=.false. + I=I+1; VNAME(I)='snwmelt_z '; LNAME(I)='band snowpack melt, in water equivalent '; VUNIT(I)='mm timestep-1'; isBand(i)=.true. ; isFlux(i)=.false. + + ! model fluxes + I=I+1; VNAME(I)='eff_ppt '; LNAME(I)='effective precipitation rate '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='satarea '; LNAME(I)='saturated area '; VUNIT(I)='- '; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='qsurf '; LNAME(I)='surface runoff '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='evap_1a '; LNAME(I)='evaporation from soil excess zone '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='evap_1b '; LNAME(I)='evaporation from soil recharge zone '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='evap_1 '; LNAME(I)='evaporation from the upper soil layer '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='evap_2 '; LNAME(I)='evaporation from the lower soil layer '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='rchr2excs '; LNAME(I)='flow from recharge zone to excess zone '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='tens2free_1'; LNAME(I)='flow from tension to free storage, lower layer '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='oflow_1 '; LNAME(I)='bucket overflow from upper soil layer '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='tens2free_2'; LNAME(I)='flow from tension to free storage, lower layer '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='qintf_1 '; LNAME(I)='interflow '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='qperc_12 '; LNAME(I)='percolation from upper to lower soil layer '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='qbase_2 '; LNAME(I)='baseflow '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='qbase_2a '; LNAME(I)='baseflow from primary baseflow reservoir '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='qbase_2b '; LNAME(I)='baseflow from secondary baseflow reservoir '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='oflow_2 '; LNAME(I)='bucket overflow from lower soil layer '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='oflow_2a '; LNAME(I)='bucket overflow from primary baseflow reservoir '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + I=I+1; VNAME(I)='oflow_2b '; LNAME(I)='bucket overflow from secondary baseflow reservoir '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.true. + + ! errors in model states (due to excessive extrapolation) + I=I+1; VNAME(I)='err_tens_1 '; LNAME(I)='excessive extrapolation: upper tension storage '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_tens_1a'; LNAME(I)='excessive extrapolation: upper excs tension storage'; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_tens_1b'; LNAME(I)='excessive extrapolation: upper rech tension storage'; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_free_1 '; LNAME(I)='excessive extrapolation: upper free storage '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_watr_1 '; LNAME(I)='excessive extrapolation: upper total storage '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_tens_2 '; LNAME(I)='excessive extrapolation: lower tension storage '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_free_2 '; LNAME(I)='excessive extrapolation: lower free storage '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_free_2a'; LNAME(I)='excessive extrapolation: 1st baseflow reservoir '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_free_2b'; LNAME(I)='excessive extrapolation: 2nd baseflow reservoir '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='err_watr_2 '; LNAME(I)='excessive extrapolation: lower total storage '; VUNIT(I)='mm day-1 '; isBand(i)=.false.; isFlux(i)=.false. + + ! time check + I=I+1; VNAME(I)='chk_time '; LNAME(I)='length of time step included in weighted average '; VUNIT(I)='days '; isBand(i)=.false.; isFlux(i)=.false. + + ! model numerix + I=I+1; VNAME(I)='num_funcs '; LNAME(I)='number of function calls '; VUNIT(I)='- '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='numjacobian'; LNAME(I)='number of times the Jacobian is calculated '; VUNIT(I)='- '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='sub_accept' ; LNAME(I)='number of sub-steps accepted (taken) '; VUNIT(I)='- '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='sub_reject' ; LNAME(I)='number of sub-steps tried but rejected '; VUNIT(I)='- '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='sub_noconv' ; LNAME(I)='number of sub-steps tried that did not converge '; VUNIT(I)='- '; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='max_iterns' ; LNAME(I)='maximum number of iterations in implicit euler '; VUNIT(I)='- '; isBand(i)=.false.; isFlux(i)=.false. + + ! model runoff (for BATEA, assumed to be last) + I=I+1; VNAME(I)='q_instnt '; LNAME(I)='instantaneous runoff '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.false. + I=I+1; VNAME(I)='q_routed '; LNAME(I)='routed runoff '; VUNIT(I)='mm timestep-1'; isBand(i)=.false.; isFlux(i)=.false. + + print *, 'Setting NOUTVAR (number of forcing, state and flux variables) to', I + NOUTVAR=I + + END SUBROUTINE VARDESCRIBE -END SUBROUTINE VARDESCRIBE END MODULE metaoutput diff --git a/build/FUSE_SRC/util/metaparams.f90 b/build/FUSE_SRC/util/metaparams.f90 index 34d313e..41cc6dd 100644 --- a/build/FUSE_SRC/util/metaparams.f90 +++ b/build/FUSE_SRC/util/metaparams.f90 @@ -1,108 +1,119 @@ MODULE metaparams -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007 -! Modified by Brian Henn to include snow model, 6/2013 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Describe all parameters used in the model (used to define NetCDF output files, etc.) -! --------------------------------------------------------------------------------------- -! variable definitions -USE nrtype -USE multibands -USE model_defn,ONLY:SMODL -USE model_defnames -IMPLICIT NONE -CHARACTER(LEN=11), DIMENSION(200) :: PNAME ! parameter names -CHARACTER(LEN=52), DIMENSION(200) :: PDESC ! parameter long names (description of variable) -CHARACTER(LEN= 8), DIMENSION(200) :: PUNIT ! parameter units -INTEGER(I4B) :: I ! loop through parameter sets -INTEGER(I4B) :: IBAND ! loop through bands -CHARACTER(LEN=2) :: TXT_IBAND ! band index as a character -INTEGER(I4B) :: NOUTPAR ! number of model parameters for output -CONTAINS -! --------------------------------------------------------------------------------------- -SUBROUTINE PARDESCRIBE() -I=0 ! initialize counter -! adjustable model parameters -I=I+1; PNAME(I)='RFERR_ADD '; PDESC(I)='additive rainfall error '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='RFERR_MLT '; PDESC(I)='multiplicative rainfall error '; PUNIT(I)='- ' -I=I+1; PNAME(I)='MAXWATR_1 '; PDESC(I)='maximum total storage in the upper layer '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXWATR_2 '; PDESC(I)='maximum total storage in the lower layer '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='FRACTEN '; PDESC(I)='fraction total storage as tension storage '; PUNIT(I)='- ' -I=I+1; PNAME(I)='FRCHZNE '; PDESC(I)='fraction tension storage in recharge zone '; PUNIT(I)='- ' -I=I+1; PNAME(I)='FPRIMQB '; PDESC(I)='fraction of baseflow in primary reservoir '; PUNIT(I)='- ' -I=I+1; PNAME(I)='RTFRAC1 '; PDESC(I)='fraction of roots in the upper layer '; PUNIT(I)='- ' -I=I+1; PNAME(I)='PERCRTE '; PDESC(I)='percolation rate '; PUNIT(I)='mm day-1' -I=I+1; PNAME(I)='PERCEXP '; PDESC(I)='percolation exponent '; PUNIT(I)='- ' -I=I+1; PNAME(I)='SACPMLT '; PDESC(I)='percolation multiplier in the SAC model '; PUNIT(I)='- ' -I=I+1; PNAME(I)='SACPEXP '; PDESC(I)='percolation exponent in the SAC model '; PUNIT(I)='- ' -I=I+1; PNAME(I)='PERCFRAC '; PDESC(I)='fraction of percolation to tension storage '; PUNIT(I)='- ' -I=I+1; PNAME(I)='FRACLOWZ '; PDESC(I)='fraction of soil excess to lower zone '; PUNIT(I)='- ' -I=I+1; PNAME(I)='IFLWRTE '; PDESC(I)='interflow rate '; PUNIT(I)='mm day-1' -I=I+1; PNAME(I)='BASERTE '; PDESC(I)='baseflow rate '; PUNIT(I)='mm day-1' -I=I+1; PNAME(I)='QB_POWR '; PDESC(I)='baseflow exponent '; PUNIT(I)='- ' -I=I+1; PNAME(I)='QB_PRMS '; PDESC(I)='baseflow depletion rate '; PUNIT(I)='- ' -I=I+1; PNAME(I)='QBRATE_2A '; PDESC(I)='baseflow depletion rate for primary reservoir '; PUNIT(I)='day-1 ' -I=I+1; PNAME(I)='QBRATE_2B '; PDESC(I)='baseflow depletion rate for secondary reservoir '; PUNIT(I)='day-1 ' -I=I+1; PNAME(I)='SAREAMAX '; PDESC(I)='maximum saturated area '; PUNIT(I)='- ' -I=I+1; PNAME(I)='AXV_BEXP '; PDESC(I)='ARNO/VIC b exponent '; PUNIT(I)='- ' -I=I+1; PNAME(I)='LOGLAMB '; PDESC(I)='mean value of the log-transformed topographic index'; PUNIT(I)='log m ' -I=I+1; PNAME(I)='TISHAPE '; PDESC(I)='shape parameter for the topo index Gamma distribtn '; PUNIT(I)='- ' -I=I+1; PNAME(I)='TIMEDELAY '; PDESC(I)='time delay in runoff (routing) '; PUNIT(I)='day ' -I=I+1; PNAME(I)='MBASE '; PDESC(I)='snow model base melt temperature '; PUNIT(I)='deg.C ' -I=I+1; PNAME(I)='MFMAX '; PDESC(I)='snow model maximum melt factor '; PUNIT(I)='mm/(C-d)' -I=I+1; PNAME(I)='MFMIN '; PDESC(I)='snow model minimum melt factor '; PUNIT(I)='mm/(C-d)' -I=I+1; PNAME(I)='PXTEMP '; PDESC(I)='rain-snow partition temperature '; PUNIT(I)='deg.C ' -I=I+1; PNAME(I)='OPG '; PDESC(I)='maximum relative precip difference across the bands'; PUNIT(I)='- ' -I=I+1; PNAME(I)='LAPSE '; PDESC(I)='maximum temperature difference across the bands '; PUNIT(I)='deg.C ' -! derived model parameters -I=I+1; PNAME(I)='MAXTENS_1 '; PDESC(I)='maximum tension storage in the upper layer '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXTENS_1A '; PDESC(I)='maximum storage in the recharge zone '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXTENS_1B '; PDESC(I)='maximum storage in the lower zone '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXFREE_1 '; PDESC(I)='maximum free storage in the upper layer '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXTENS_2 '; PDESC(I)='maximum tension storage in the lower layer '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXFREE_2 '; PDESC(I)='maximum free storage in the lower layer '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXFREE_2A '; PDESC(I)='maximum storage in the primary baseflow reservoir '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='MAXFREE_2B '; PDESC(I)='maximum storage in the secondary baseflow reservoir'; PUNIT(I)='mm ' -I=I+1; PNAME(I)='RTFRAC2 '; PDESC(I)='fraction of roots in the lower layer '; PUNIT(I)='- ' -I=I+1; PNAME(I)='QBSAT '; PDESC(I)='baseflow at saturation (derived parameter) '; PUNIT(I)='mm day-1' -I=I+1; PNAME(I)='POWLAMB '; PDESC(I)='mean value of power-transformed topographic index '; PUNIT(I)='m**(1/n)' -I=I+1; PNAME(I)='MAXPOW '; PDESC(I)='max value of power-transformed topographic index '; PUNIT(I)='m**(1/n)' -! model bands parameters -IF(SMODL%iSNOWM.EQ.iopt_temp_index) THEN !loop through snow model bands - I=I+1; PNAME(I)='N_BANDS '; PDESC(I)='number of basin bands in model '; PUNIT(I)='= ' - I=I+1; PNAME(I)='Z_FORCING '; PDESC(I)='elevation of model forcing data '; PUNIT(I)='m ' - DO IBAND=1,N_BANDS - WRITE(TXT_IBAND,'(I2)') IBAND ! convert band no. to text - IF (IBAND.LT.10) TXT_IBAND(1:1) = '0' ! pad with zeros - I=I+1; PNAME(I)='Z_MID'//TXT_IBAND//' '; PDESC(I)='basin band mid-point elevation '; PUNIT(I)='m ' - I=I+1; PNAME(I)='AF'//TXT_IBAND//' '; PDESC(I)='basin band area fraction '; PUNIT(I)='- ' - END DO -ENDIF -! numerical solution parameters -I=I+1; PNAME(I)='SOLUTION '; PDESC(I)='0=explicit euler; 1=implicit euler '; PUNIT(I)='- ' -I=I+1; PNAME(I)='TIMSTEP_TYP'; PDESC(I)='0=fixed time steps; 1=adaptive time steps '; PUNIT(I)='- ' -I=I+1; PNAME(I)='INITL_GUESS'; PDESC(I)='0=old state; 1=explicit half-step; 2=expl full-step'; PUNIT(I)='- ' -I=I+1; PNAME(I)='JAC_RECOMPT'; PDESC(I)='0=variable; 1=constant sub-step; 2=const full step '; PUNIT(I)='- ' -I=I+1; PNAME(I)='CK_OVRSHOOT'; PDESC(I)='0=always take full newton step; 1=line search '; PUNIT(I)='- ' -I=I+1; PNAME(I)='SMALL_ESTEP'; PDESC(I)='0=step truncation; 1=look-ahead; 2=step absorption '; PUNIT(I)='- ' -I=I+1; PNAME(I)='ERRTRUNCABS'; PDESC(I)='absolute temporal truncation error tolerance '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='ERRTRUNCREL'; PDESC(I)='relative temporal truncation error tolerance '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='ERRITERFUNC'; PDESC(I)='iteration convergence tolerance for function values'; PUNIT(I)='mm ' -I=I+1; PNAME(I)='ERR_ITER_DX'; PDESC(I)='iteration convergence tolerance for dx '; PUNIT(I)='- ' -I=I+1; PNAME(I)='THRESH_FRZE'; PDESC(I)='threshold for freezing the Jacobian '; PUNIT(I)='mm ' -I=I+1; PNAME(I)='FSTATE_MIN '; PDESC(I)='fractional minimum value of state '; PUNIT(I)='- ' -I=I+1; PNAME(I)='STEP_SAFETY'; PDESC(I)='safety factor in step-size equation '; PUNIT(I)='- ' -I=I+1; PNAME(I)='RMIN '; PDESC(I)='minimum step size multiplier '; PUNIT(I)='- ' -I=I+1; PNAME(I)='RMAX '; PDESC(I)='maximum step size multiplier '; PUNIT(I)='- ' -I=I+1; PNAME(I)='NITER_TOTAL'; PDESC(I)='maximum number of iterations in the implicit scheme'; PUNIT(I)='- ' -I=I+1; PNAME(I)='MIN_TSTEP '; PDESC(I)='minimum time step length '; PUNIT(I)='day ' -I=I+1; PNAME(I)='MAX_TSTEP '; PDESC(I)='maximum time step length '; PUNIT(I)='day ' -! parameter identifier -I=I+1; PNAME(I)='SOBOL_INDX '; PDESC(I)='indentifier for Sobol parameter set '; PUNIT(I)='- ' -NOUTPAR=I -END SUBROUTINE PARDESCRIBE + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Martyn Clark to avoid per-band parameters, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Describe all parameters used in the model (used to define NetCDF output files, etc.) + ! --------------------------------------------------------------------------------------- + + ! variable definitions + USE nrtype + + IMPLICIT NONE + + private + public :: PARDESCRIBE ! make subroutine public + public :: PNAME, PDESC, PUNIT, isBand ! make metadata variables public + public :: NOUTPAR ! make number of output parameters public + + CHARACTER(LEN=11), DIMENSION(200) :: PNAME ! parameter names + CHARACTER(LEN=52), DIMENSION(200) :: PDESC ! parameter long names (description of variable) + CHARACTER(LEN= 8), DIMENSION(200) :: PUNIT ! parameter units + logical(lgt) , DIMENSION(200) :: isBand ! flag for the parameter dimension + INTEGER(I4B) :: NOUTPAR ! number of model parameters for output + + CONTAINS + ! --------------------------------------------------------------------------------------- + + SUBROUTINE PARDESCRIBE() + implicit none + INTEGER(I4B) :: I ! loop through parameter sets + + I=0 ! initialize counter + + ! adjustable model parameters + I=I+1; PNAME(I)='RFERR_ADD '; PDESC(I)='additive rainfall error '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='RFERR_MLT '; PDESC(I)='multiplicative rainfall error '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXWATR_1 '; PDESC(I)='maximum total storage in the upper layer '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXWATR_2 '; PDESC(I)='maximum total storage in the lower layer '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='FRACTEN '; PDESC(I)='fraction total storage as tension storage '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='FRCHZNE '; PDESC(I)='fraction tension storage in recharge zone '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='FPRIMQB '; PDESC(I)='fraction of baseflow in primary reservoir '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='RTFRAC1 '; PDESC(I)='fraction of roots in the upper layer '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='PERCRTE '; PDESC(I)='percolation rate '; PUNIT(I)='mm day-1'; isBand(i)=.false. + I=I+1; PNAME(I)='PERCEXP '; PDESC(I)='percolation exponent '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='SACPMLT '; PDESC(I)='percolation multiplier in the SAC model '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='SACPEXP '; PDESC(I)='percolation exponent in the SAC model '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='PERCFRAC '; PDESC(I)='fraction of percolation to tension storage '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='FRACLOWZ '; PDESC(I)='fraction of soil excess to lower zone '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='IFLWRTE '; PDESC(I)='interflow rate '; PUNIT(I)='mm day-1'; isBand(i)=.false. + I=I+1; PNAME(I)='BASERTE '; PDESC(I)='baseflow rate '; PUNIT(I)='mm day-1'; isBand(i)=.false. + I=I+1; PNAME(I)='QB_POWR '; PDESC(I)='baseflow exponent '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='QB_PRMS '; PDESC(I)='baseflow depletion rate '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='QBRATE_2A '; PDESC(I)='baseflow depletion rate for primary reservoir '; PUNIT(I)='day-1 '; isBand(i)=.false. + I=I+1; PNAME(I)='QBRATE_2B '; PDESC(I)='baseflow depletion rate for secondary reservoir '; PUNIT(I)='day-1 '; isBand(i)=.false. + I=I+1; PNAME(I)='SAREAMAX '; PDESC(I)='maximum saturated area '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='AXV_BEXP '; PDESC(I)='ARNO/VIC b exponent '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='LOGLAMB '; PDESC(I)='mean value of the log-transformed topographic index'; PUNIT(I)='log m '; isBand(i)=.false. + I=I+1; PNAME(I)='TISHAPE '; PDESC(I)='shape parameter for the topo index Gamma distribtn '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='TIMEDELAY '; PDESC(I)='time delay in runoff (routing) '; PUNIT(I)='day '; isBand(i)=.false. + I=I+1; PNAME(I)='MBASE '; PDESC(I)='snow model base melt temperature '; PUNIT(I)='deg.C '; isBand(i)=.false. + I=I+1; PNAME(I)='MFMAX '; PDESC(I)='snow model maximum melt factor '; PUNIT(I)='mm/(C-d)'; isBand(i)=.false. + I=I+1; PNAME(I)='MFMIN '; PDESC(I)='snow model minimum melt factor '; PUNIT(I)='mm/(C-d)'; isBand(i)=.false. + I=I+1; PNAME(I)='PXTEMP '; PDESC(I)='rain-snow partition temperature '; PUNIT(I)='deg.C '; isBand(i)=.false. + I=I+1; PNAME(I)='OPG '; PDESC(I)='maximum relative precip difference across the bands'; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='LAPSE '; PDESC(I)='maximum temperature difference across the bands '; PUNIT(I)='deg.C '; isBand(i)=.false. + + ! derived model parameters + I=I+1; PNAME(I)='MAXTENS_1 '; PDESC(I)='maximum tension storage in the upper layer '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXTENS_1A '; PDESC(I)='maximum storage in the recharge zone '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXTENS_1B '; PDESC(I)='maximum storage in the lower zone '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXFREE_1 '; PDESC(I)='maximum free storage in the upper layer '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXTENS_2 '; PDESC(I)='maximum tension storage in the lower layer '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXFREE_2 '; PDESC(I)='maximum free storage in the lower layer '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXFREE_2A '; PDESC(I)='maximum storage in the primary baseflow reservoir '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='MAXFREE_2B '; PDESC(I)='maximum storage in the secondary baseflow reservoir'; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='RTFRAC2 '; PDESC(I)='fraction of roots in the lower layer '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='QBSAT '; PDESC(I)='baseflow at saturation (derived parameter) '; PUNIT(I)='mm day-1'; isBand(i)=.false. + I=I+1; PNAME(I)='POWLAMB '; PDESC(I)='mean value of power-transformed topographic index '; PUNIT(I)='m**(1/n)'; isBand(i)=.false. + I=I+1; PNAME(I)='MAXPOW '; PDESC(I)='max value of power-transformed topographic index '; PUNIT(I)='m**(1/n)'; isBand(i)=.false. + + ! model bands parameters + I=I+1; PNAME(I)='N_BANDS '; PDESC(I)='number of basin bands in model '; PUNIT(I)='= '; isBand(i)=.false. + I=I+1; PNAME(I)='Z_FORCING '; PDESC(I)='elevation of model forcing data '; PUNIT(I)='m '; isBand(i)=.false. + I=I+1; PNAME(I)='Z_MID '; PDESC(I)='basin band mid-point elevation (bands) '; PUNIT(I)='m '; isBand(i)=.true. + I=I+1; PNAME(I)='AF '; PDESC(I)='basin band area fraction (bands) '; PUNIT(I)='- '; isBand(i)=.true. + + ! numerical solution parameters + I=I+1; PNAME(I)='SOLUTION '; PDESC(I)='0=explicit euler; 1=implicit euler '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='TIMSTEP_TYP'; PDESC(I)='0=fixed time steps; 1=adaptive time steps '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='INITL_GUESS'; PDESC(I)='0=old state; 1=explicit half-step; 2=expl full-step'; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='JAC_RECOMPT'; PDESC(I)='0=variable; 1=constant sub-step; 2=const full step '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='CK_OVRSHOOT'; PDESC(I)='0=always take full newton step; 1=line search '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='SMALL_ESTEP'; PDESC(I)='0=step truncation; 1=look-ahead; 2=step absorption '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='ERRTRUNCABS'; PDESC(I)='absolute temporal truncation error tolerance '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='ERRTRUNCREL'; PDESC(I)='relative temporal truncation error tolerance '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='ERRITERFUNC'; PDESC(I)='iteration convergence tolerance for function values'; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='ERR_ITER_DX'; PDESC(I)='iteration convergence tolerance for dx '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='THRESH_FRZE'; PDESC(I)='threshold for freezing the Jacobian '; PUNIT(I)='mm '; isBand(i)=.false. + I=I+1; PNAME(I)='FSTATE_MIN '; PDESC(I)='fractional minimum value of state '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='STEP_SAFETY'; PDESC(I)='safety factor in step-size equation '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='RMIN '; PDESC(I)='minimum step size multiplier '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='RMAX '; PDESC(I)='maximum step size multiplier '; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='NITER_TOTAL'; PDESC(I)='maximum number of iterations in the implicit scheme'; PUNIT(I)='- '; isBand(i)=.false. + I=I+1; PNAME(I)='MIN_TSTEP '; PDESC(I)='minimum time step length '; PUNIT(I)='day '; isBand(i)=.false. + I=I+1; PNAME(I)='MAX_TSTEP '; PDESC(I)='maximum time step length '; PUNIT(I)='day '; isBand(i)=.false. + + ! parameter identifier + I=I+1; PNAME(I)='SOBOL_INDX '; PDESC(I)='indentifier for Sobol parameter set '; PUNIT(I)='- '; isBand(i)=.false. + + NOUTPAR=I + + END SUBROUTINE PARDESCRIBE END MODULE metaparams diff --git a/build/FUSE_SRC/util/parextract.f90 b/build/FUSE_SRC/util/parextract.f90 index e9499d6..7eba011 100644 --- a/build/FUSE_SRC/util/parextract.f90 +++ b/build/FUSE_SRC/util/parextract.f90 @@ -1,237 +1,129 @@ MODULE PAREXTRACT_MODULE -IMPLICIT NONE -CONTAINS -! --------------------------------------------------------------------------------------- -! --------------------------------------------------------------------------------------- -SUBROUTINE GET_PARSET(PARSET) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2008 -! Modified by Brian Henn to include snow model, 6/2013 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Extracts an entire parameter set from a data structure, based on the list of parameters -! in LPARAM -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -USE multiparam ! model parameters -IMPLICIT NONE -! output -REAL(SP), INTENT(INOUT), DIMENSION(:) :: PARSET ! parameter set -! local -INTEGER(I4B) :: IPAR ! looping -! --------------------------------------------------------------------------------------- -DO IPAR=1,NUMPAR ! NUMPAR is stored in module multiparam - PARSET(IPAR) = PAREXTRACT(LPARAM(IPAR)%PARNAME) -END DO -! --------------------------------------------------------------------------------------- -END SUBROUTINE GET_PARSET -! --------------------------------------------------------------------------------------- -! --------------------------------------------------------------------------------------- -! --------------------------------------------------------------------------------------- -PURE FUNCTION PAREXTRACT(PARNAME) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Extracts parameter from data structures -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -USE multiparam ! model parameters -USE model_numerix ! model numerix parameters -USE multibands ! model basin band data -IMPLICIT NONE -! input -CHARACTER(*), INTENT(IN) :: PARNAME ! parameter name -! internal -REAL(SP) :: XVAR ! variable -! output -REAL(SP) :: PAREXTRACT ! FUNCTION name -! --------------------------------------------------------------------------------------- -SELECT CASE (TRIM(PARNAME)) - ! model parameters - CASE ('RFERR_ADD') ; XVAR = MPARAM%RFERR_ADD - CASE ('RFERR_MLT') ; XVAR = MPARAM%RFERR_MLT - CASE ('RFH1_MEAN') ; XVAR = MPARAM%RFH1_MEAN - CASE ('RFH2_SDEV') ; XVAR = MPARAM%RFH2_SDEV - CASE ('RH1P_MEAN') ; XVAR = MPARAM%RH1P_MEAN - CASE ('RH1P_SDEV') ; XVAR = MPARAM%RH1P_SDEV - CASE ('RH2P_MEAN') ; XVAR = MPARAM%RH2P_MEAN - CASE ('RH2P_SDEV') ; XVAR = MPARAM%RH2P_SDEV - CASE ('MAXWATR_1') ; XVAR = MPARAM%MAXWATR_1 - CASE ('MAXWATR_2') ; XVAR = MPARAM%MAXWATR_2 - CASE ('FRACTEN') ; XVAR = MPARAM%FRACTEN - CASE ('FRCHZNE') ; XVAR = MPARAM%FRCHZNE - CASE ('FPRIMQB') ; XVAR = MPARAM%FPRIMQB - CASE ('RTFRAC1') ; XVAR = MPARAM%RTFRAC1 - CASE ('PERCRTE') ; XVAR = MPARAM%PERCRTE - CASE ('PERCEXP') ; XVAR = MPARAM%PERCEXP - CASE ('SACPMLT') ; XVAR = MPARAM%SACPMLT - CASE ('SACPEXP') ; XVAR = MPARAM%SACPEXP - CASE ('PERCFRAC') ; XVAR = MPARAM%PERCFRAC - CASE ('FRACLOWZ') ; XVAR = MPARAM%FRACLOWZ - CASE ('IFLWRTE') ; XVAR = MPARAM%IFLWRTE - CASE ('BASERTE') ; XVAR = MPARAM%BASERTE - CASE ('QB_POWR') ; XVAR = MPARAM%QB_POWR - CASE ('QB_PRMS') ; XVAR = MPARAM%QB_PRMS - CASE ('QBRATE_2A') ; XVAR = MPARAM%QBRATE_2A - CASE ('QBRATE_2B') ; XVAR = MPARAM%QBRATE_2B - CASE ('SAREAMAX') ; XVAR = MPARAM%SAREAMAX - CASE ('AXV_BEXP') ; XVAR = MPARAM%AXV_BEXP - CASE ('LOGLAMB') ; XVAR = MPARAM%LOGLAMB - CASE ('TISHAPE') ; XVAR = MPARAM%TISHAPE - CASE ('TIMEDELAY') ; XVAR = MPARAM%TIMEDELAY - CASE ('MBASE') ; XVAR = MPARAM%MBASE - CASE ('MFMAX') ; XVAR = MPARAM%MFMAX - CASE ('MFMIN') ; XVAR = MPARAM%MFMIN - CASE ('PXTEMP') ; XVAR = MPARAM%PXTEMP - CASE ('OPG') ; XVAR = MPARAM%OPG - CASE ('LAPSE') ; XVAR = MPARAM%LAPSE - ! derived parameters - CASE ('MAXTENS_1') ; XVAR = DPARAM%MAXTENS_1 - CASE ('MAXTENS_1A') ; XVAR = DPARAM%MAXTENS_1A - CASE ('MAXTENS_1B') ; XVAR = DPARAM%MAXTENS_1B - CASE ('MAXFREE_1') ; XVAR = DPARAM%MAXFREE_1 - CASE ('MAXTENS_2') ; XVAR = DPARAM%MAXTENS_2 - CASE ('MAXFREE_2') ; XVAR = DPARAM%MAXFREE_2 - CASE ('MAXFREE_2A') ; XVAR = DPARAM%MAXFREE_2A - CASE ('MAXFREE_2B') ; XVAR = DPARAM%MAXFREE_2B - CASE ('QBSAT') ; XVAR = DPARAM%QBSAT - CASE ('RTFRAC2') ; XVAR = DPARAM%RTFRAC2 - CASE ('POWLAMB') ; XVAR = DPARAM%POWLAMB - CASE ('MAXPOW') ; XVAR = DPARAM%MAXPOW - ! basin band data - CASE ('Z_MID01') ; XVAR = MBANDS(1)%Z_MID - CASE ('AF01') ; XVAR = MBANDS(1)%AF - CASE ('Z_MID02') ; XVAR = MBANDS(2)%Z_MID - CASE ('AF02') ; XVAR = MBANDS(2)%AF - CASE ('Z_MID03') ; XVAR = MBANDS(3)%Z_MID - CASE ('AF03') ; XVAR = MBANDS(3)%AF - CASE ('Z_MID04') ; XVAR = MBANDS(4)%Z_MID - CASE ('AF04') ; XVAR = MBANDS(4)%AF - CASE ('Z_MID05') ; XVAR = MBANDS(5)%Z_MID - CASE ('AF05') ; XVAR = MBANDS(5)%AF - CASE ('Z_MID06') ; XVAR = MBANDS(6)%Z_MID - CASE ('AF06') ; XVAR = MBANDS(6)%AF - CASE ('Z_MID07') ; XVAR = MBANDS(7)%Z_MID - CASE ('AF07') ; XVAR = MBANDS(7)%AF - CASE ('Z_MID08') ; XVAR = MBANDS(8)%Z_MID - CASE ('AF08') ; XVAR = MBANDS(8)%AF - CASE ('Z_MID09') ; XVAR = MBANDS(9)%Z_MID - CASE ('AF09') ; XVAR = MBANDS(9)%AF - CASE ('Z_MID10') ; XVAR = MBANDS(10)%Z_MID - CASE ('AF10') ; XVAR = MBANDS(10)%AF - CASE ('Z_MID11') ; XVAR = MBANDS(11)%Z_MID - CASE ('AF11') ; XVAR = MBANDS(11)%AF - CASE ('Z_MID12') ; XVAR = MBANDS(12)%Z_MID - CASE ('AF12') ; XVAR = MBANDS(12)%AF - CASE ('Z_MID13') ; XVAR = MBANDS(13)%Z_MID - CASE ('AF13') ; XVAR = MBANDS(13)%AF - CASE ('Z_MID14') ; XVAR = MBANDS(14)%Z_MID - CASE ('AF14') ; XVAR = MBANDS(14)%AF - CASE ('Z_MID15') ; XVAR = MBANDS(15)%Z_MID - CASE ('AF15') ; XVAR = MBANDS(15)%AF - CASE ('Z_MID16') ; XVAR = MBANDS(16)%Z_MID - CASE ('AF16') ; XVAR = MBANDS(16)%AF - CASE ('Z_MID17') ; XVAR = MBANDS(17)%Z_MID - CASE ('AF17') ; XVAR = MBANDS(17)%AF - CASE ('Z_MID18') ; XVAR = MBANDS(18)%Z_MID - CASE ('AF18') ; XVAR = MBANDS(18)%AF - CASE ('Z_MID19') ; XVAR = MBANDS(19)%Z_MID - CASE ('AF19') ; XVAR = MBANDS(19)%AF - CASE ('Z_MID20') ; XVAR = MBANDS(20)%Z_MID - CASE ('AF20') ; XVAR = MBANDS(20)%AF - CASE ('Z_MID21') ; XVAR = MBANDS(21)%Z_MID - CASE ('AF21') ; XVAR = MBANDS(21)%AF - CASE ('Z_MID22') ; XVAR = MBANDS(22)%Z_MID - CASE ('AF22') ; XVAR = MBANDS(22)%AF - CASE ('Z_MID23') ; XVAR = MBANDS(23)%Z_MID - CASE ('AF23') ; XVAR = MBANDS(23)%AF - CASE ('Z_MID24') ; XVAR = MBANDS(24)%Z_MID - CASE ('AF24') ; XVAR = MBANDS(24)%AF - CASE ('Z_MID25') ; XVAR = MBANDS(25)%Z_MID - CASE ('AF25') ; XVAR = MBANDS(25)%AF - CASE ('Z_MID26') ; XVAR = MBANDS(26)%Z_MID - CASE ('AF26') ; XVAR = MBANDS(26)%AF - CASE ('Z_MID27') ; XVAR = MBANDS(27)%Z_MID - CASE ('AF27') ; XVAR = MBANDS(27)%AF - CASE ('Z_MID28') ; XVAR = MBANDS(28)%Z_MID - CASE ('AF28') ; XVAR = MBANDS(28)%AF - CASE ('Z_MID29') ; XVAR = MBANDS(29)%Z_MID - CASE ('AF29') ; XVAR = MBANDS(29)%AF - CASE ('Z_MID30') ; XVAR = MBANDS(30)%Z_MID - CASE ('AF30') ; XVAR = MBANDS(30)%AF - CASE ('Z_MID31') ; XVAR = MBANDS(31)%Z_MID - CASE ('AF31') ; XVAR = MBANDS(31)%AF - CASE ('Z_MID32') ; XVAR = MBANDS(32)%Z_MID - CASE ('AF32') ; XVAR = MBANDS(32)%AF - CASE ('Z_MID33') ; XVAR = MBANDS(33)%Z_MID - CASE ('AF33') ; XVAR = MBANDS(33)%AF - CASE ('Z_MID34') ; XVAR = MBANDS(34)%Z_MID - CASE ('AF34') ; XVAR = MBANDS(34)%AF - CASE ('Z_MID35') ; XVAR = MBANDS(35)%Z_MID - CASE ('AF35') ; XVAR = MBANDS(35)%AF - CASE ('Z_MID36') ; XVAR = MBANDS(36)%Z_MID - CASE ('AF36') ; XVAR = MBANDS(36)%AF - CASE ('Z_MID37') ; XVAR = MBANDS(37)%Z_MID - CASE ('AF37') ; XVAR = MBANDS(37)%AF - CASE ('Z_MID38') ; XVAR = MBANDS(38)%Z_MID - CASE ('AF38') ; XVAR = MBANDS(38)%AF - CASE ('Z_MID39') ; XVAR = MBANDS(39)%Z_MID - CASE ('AF39') ; XVAR = MBANDS(39)%AF - CASE ('Z_MID40') ; XVAR = MBANDS(40)%Z_MID - CASE ('AF40') ; XVAR = MBANDS(40)%AF - CASE ('Z_MID41') ; XVAR = MBANDS(41)%Z_MID - CASE ('AF41') ; XVAR = MBANDS(41)%AF - CASE ('Z_MID42') ; XVAR = MBANDS(42)%Z_MID - CASE ('AF42') ; XVAR = MBANDS(42)%AF - CASE ('Z_MID43') ; XVAR = MBANDS(43)%Z_MID - CASE ('AF43') ; XVAR = MBANDS(43)%AF - CASE ('Z_MID44') ; XVAR = MBANDS(44)%Z_MID - CASE ('AF44') ; XVAR = MBANDS(44)%AF - CASE ('Z_MID45') ; XVAR = MBANDS(45)%Z_MID - CASE ('AF45') ; XVAR = MBANDS(45)%AF - CASE ('Z_MID46') ; XVAR = MBANDS(46)%Z_MID - CASE ('AF46') ; XVAR = MBANDS(46)%AF - CASE ('Z_MID47') ; XVAR = MBANDS(47)%Z_MID - CASE ('AF47') ; XVAR = MBANDS(47)%AF - CASE ('Z_MID48') ; XVAR = MBANDS(48)%Z_MID - CASE ('AF48') ; XVAR = MBANDS(48)%AF - CASE ('Z_MID49') ; XVAR = MBANDS(49)%Z_MID - CASE ('AF49') ; XVAR = MBANDS(49)%AF - CASE ('Z_MID50') ; XVAR = MBANDS(50)%Z_MID - CASE ('AF50') ; XVAR = MBANDS(50)%AF - CASE('N_BANDS') ; XVAR = N_BANDS - CASE('Z_FORCING') ; XVAR = Z_FORCING - ! numerical solution parameters - CASE ('SOLUTION') ; XVAR = REAL(SOLUTION_METHOD, KIND(SP)) - CASE ('TIMSTEP_TYP'); XVAR = REAL(TEMPORAL_ERROR_CONTROL, KIND(SP)) - CASE ('INITL_GUESS'); XVAR = REAL(INITIAL_NEWTON, KIND(SP)) - CASE ('JAC_RECOMPT'); XVAR = REAL(JAC_RECOMPUTE, KIND(SP)) - CASE ('CK_OVRSHOOT'); XVAR = REAL(CHECK_OVERSHOOT, KIND(SP)) - CASE ('SMALL_ESTEP'); XVAR = REAL(SMALL_ENDSTEP, KIND(SP)) - CASE ('ERRTRUNCABS'); XVAR = ERR_TRUNC_ABS - CASE ('ERRTRUNCREL'); XVAR = ERR_TRUNC_REL - CASE ('ERRITERFUNC'); XVAR = ERR_ITER_FUNC - CASE ('ERR_ITER_DX'); XVAR = ERR_ITER_DX - CASE ('THRESH_FRZE'); XVAR = THRESH_FRZE - CASE ('FSTATE_MIN') ; XVAR = FRACSTATE_MIN - CASE ('STEP_SAFETY'); XVAR = SAFETY - CASE ('RMIN') ; XVAR = RMIN - CASE ('RMAX') ; XVAR = RMAX - CASE ('NITER_TOTAL'); XVAR = REAL(NITER_TOTAL, KIND(SP)) - CASE ('MIN_TSTEP') ; XVAR = MIN_TSTEP - CASE ('MAX_TSTEP') ; XVAR = MAX_TSTEP - ! Sobol identifier - CASE ('SOBOL_INDX') ; XVAR = REAL(SOBOL_INDX, KIND(SP)) -END SELECT -! and, save the output -PAREXTRACT = XVAR -! --------------------------------------------------------------------------------------- -END FUNCTION PAREXTRACT + + USE nrtype ! variable types, etc. + + IMPLICIT NONE + + private + public :: PAREXTRACT ! make function public + + CONTAINS + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + PURE FUNCTION PAREXTRACT(PARNAME) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Martyn Clark to remove elevation band parameters (handled separately) + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Extracts parameter from data structures + ! --------------------------------------------------------------------------------------- + USE model_numerix ! model numerix parameters + USE globaldata, only: NA_VALUE_SP ! missing value + USE multiparam, only: MPARAM, DPARAM, SOBOL_INDX ! model parameters + USE multibands, only: Z_FORCING ! scalar variables from elevation bands + IMPLICIT NONE + ! input + CHARACTER(*), INTENT(IN) :: PARNAME ! parameter name + ! internal + REAL(SP) :: XVAR ! variable + ! output + REAL(SP) :: PAREXTRACT ! FUNCTION name + ! --------------------------------------------------------------------------------------- + SELECT CASE (TRIM(PARNAME)) + + ! model parameters + CASE ('RFERR_ADD') ; XVAR = MPARAM%RFERR_ADD + CASE ('RFERR_MLT') ; XVAR = MPARAM%RFERR_MLT + CASE ('RFH1_MEAN') ; XVAR = MPARAM%RFH1_MEAN + CASE ('RFH2_SDEV') ; XVAR = MPARAM%RFH2_SDEV + CASE ('RH1P_MEAN') ; XVAR = MPARAM%RH1P_MEAN + CASE ('RH1P_SDEV') ; XVAR = MPARAM%RH1P_SDEV + CASE ('RH2P_MEAN') ; XVAR = MPARAM%RH2P_MEAN + CASE ('RH2P_SDEV') ; XVAR = MPARAM%RH2P_SDEV + CASE ('MAXWATR_1') ; XVAR = MPARAM%MAXWATR_1 + CASE ('MAXWATR_2') ; XVAR = MPARAM%MAXWATR_2 + CASE ('FRACTEN') ; XVAR = MPARAM%FRACTEN + CASE ('FRCHZNE') ; XVAR = MPARAM%FRCHZNE + CASE ('FPRIMQB') ; XVAR = MPARAM%FPRIMQB + CASE ('RTFRAC1') ; XVAR = MPARAM%RTFRAC1 + CASE ('PERCRTE') ; XVAR = MPARAM%PERCRTE + CASE ('PERCEXP') ; XVAR = MPARAM%PERCEXP + CASE ('SACPMLT') ; XVAR = MPARAM%SACPMLT + CASE ('SACPEXP') ; XVAR = MPARAM%SACPEXP + CASE ('PERCFRAC') ; XVAR = MPARAM%PERCFRAC + CASE ('FRACLOWZ') ; XVAR = MPARAM%FRACLOWZ + CASE ('IFLWRTE') ; XVAR = MPARAM%IFLWRTE + CASE ('BASERTE') ; XVAR = MPARAM%BASERTE + CASE ('QB_POWR') ; XVAR = MPARAM%QB_POWR + CASE ('QB_PRMS') ; XVAR = MPARAM%QB_PRMS + CASE ('QBRATE_2A') ; XVAR = MPARAM%QBRATE_2A + CASE ('QBRATE_2B') ; XVAR = MPARAM%QBRATE_2B + CASE ('SAREAMAX') ; XVAR = MPARAM%SAREAMAX + CASE ('AXV_BEXP') ; XVAR = MPARAM%AXV_BEXP + CASE ('LOGLAMB') ; XVAR = MPARAM%LOGLAMB + CASE ('TISHAPE') ; XVAR = MPARAM%TISHAPE + CASE ('TIMEDELAY') ; XVAR = MPARAM%TIMEDELAY + CASE ('MBASE') ; XVAR = MPARAM%MBASE + CASE ('MFMAX') ; XVAR = MPARAM%MFMAX + CASE ('MFMIN') ; XVAR = MPARAM%MFMIN + CASE ('PXTEMP') ; XVAR = MPARAM%PXTEMP + CASE ('OPG') ; XVAR = MPARAM%OPG + CASE ('LAPSE') ; XVAR = MPARAM%LAPSE + + ! derived parameters + CASE ('MAXTENS_1') ; XVAR = DPARAM%MAXTENS_1 + CASE ('MAXTENS_1A') ; XVAR = DPARAM%MAXTENS_1A + CASE ('MAXTENS_1B') ; XVAR = DPARAM%MAXTENS_1B + CASE ('MAXFREE_1') ; XVAR = DPARAM%MAXFREE_1 + CASE ('MAXTENS_2') ; XVAR = DPARAM%MAXTENS_2 + CASE ('MAXFREE_2') ; XVAR = DPARAM%MAXFREE_2 + CASE ('MAXFREE_2A') ; XVAR = DPARAM%MAXFREE_2A + CASE ('MAXFREE_2B') ; XVAR = DPARAM%MAXFREE_2B + CASE ('QBSAT') ; XVAR = DPARAM%QBSAT + CASE ('RTFRAC2') ; XVAR = DPARAM%RTFRAC2 + CASE ('POWLAMB') ; XVAR = DPARAM%POWLAMB + CASE ('MAXPOW') ; XVAR = DPARAM%MAXPOW + + ! scalar elevation bands information + CASE ('Z_FORCING') ; XVAR = Z_FORCING + + ! numerical solution parameters + CASE ('SOLUTION') ; XVAR = REAL(SOLUTION_METHOD, KIND(SP)) + CASE ('TIMSTEP_TYP'); XVAR = REAL(TEMPORAL_ERROR_CONTROL, KIND(SP)) + CASE ('INITL_GUESS'); XVAR = REAL(INITIAL_NEWTON, KIND(SP)) + CASE ('JAC_RECOMPT'); XVAR = REAL(JAC_RECOMPUTE, KIND(SP)) + CASE ('CK_OVRSHOOT'); XVAR = REAL(CHECK_OVERSHOOT, KIND(SP)) + CASE ('SMALL_ESTEP'); XVAR = REAL(SMALL_ENDSTEP, KIND(SP)) + CASE ('ERRTRUNCABS'); XVAR = ERR_TRUNC_ABS + CASE ('ERRTRUNCREL'); XVAR = ERR_TRUNC_REL + CASE ('ERRITERFUNC'); XVAR = ERR_ITER_FUNC + CASE ('ERR_ITER_DX'); XVAR = ERR_ITER_DX + CASE ('THRESH_FRZE'); XVAR = THRESH_FRZE + CASE ('FSTATE_MIN') ; XVAR = FRACSTATE_MIN + CASE ('STEP_SAFETY'); XVAR = SAFETY + CASE ('RMIN') ; XVAR = RMIN + CASE ('RMAX') ; XVAR = RMAX + CASE ('NITER_TOTAL'); XVAR = REAL(NITER_TOTAL, KIND(SP)) + CASE ('MIN_TSTEP') ; XVAR = MIN_TSTEP + CASE ('MAX_TSTEP') ; XVAR = MAX_TSTEP + + ! Sobol identifier + CASE ('SOBOL_INDX') ; XVAR = REAL(SOBOL_INDX, KIND(SP)) + + ! Set to missing if not found + case default; XVAR = NA_VALUE_SP + + END SELECT + + ! and, save the output + PAREXTRACT = XVAR + ! --------------------------------------------------------------------------------------- + END FUNCTION PAREXTRACT + END MODULE PAREXTRACT_MODULE diff --git a/build/FUSE_SRC/util/varextract.f90 b/build/FUSE_SRC/util/varextract.f90 index f73f766..dbb1767 100644 --- a/build/FUSE_SRC/util/varextract.f90 +++ b/build/FUSE_SRC/util/varextract.f90 @@ -1,508 +1,247 @@ MODULE VAREXTRACT_MODULE -IMPLICIT NONE -CONTAINS -! --------------------------------------------------------------------------------------- -PURE FUNCTION VAREXTRACT(VARNAME) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007 -! Modified by Brian Henn to include snow model, 6/2013 -! Modified by Nans Addor to enable distributed modeling, 9/2016 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Extracts variable "VARNAME" from relevant data structures -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -USE metaoutput ! metadata for all model variables -USE multiforce ! model forcing data -USE multistate ! model states -USE multi_flux ! model fluxes -USE multibands ! model snow bands -USE multiroute ! routed runoff -USE model_numerix ! model numerix parameters -IMPLICIT NONE -! input -CHARACTER(*), INTENT(IN) :: VARNAME ! variable name -! internal -REAL(SP) :: XVAR ! variable -! output -REAL(SP) :: VAREXTRACT ! FUNCTION name -! --------------------------------------------------------------------------------------- -! initialize XVAR -XVAR=-9999._sp -SELECT CASE (TRIM(VARNAME)) - ! extract forcing data - CASE ('ppt') ; XVAR = MFORCE%PPT - CASE ('temp') ; XVAR = MFORCE%TEMP - CASE ('pet') ; XVAR = MFORCE%PET - ! extract response data - CASE ('obsq') ; XVAR = valDat%OBSQ - ! extract model states - CASE ('tens_1') ; XVAR = FSTATE%TENS_1 - CASE ('tens_1a') ; XVAR = FSTATE%TENS_1A - CASE ('tens_1b') ; XVAR = FSTATE%TENS_1B - CASE ('free_1') ; XVAR = FSTATE%FREE_1 - CASE ('watr_1') ; XVAR = FSTATE%WATR_1 - CASE ('tens_2') ; XVAR = FSTATE%TENS_2 - CASE ('free_2') ; XVAR = FSTATE%FREE_2 - CASE ('free_2a') ; XVAR = FSTATE%FREE_2A - CASE ('free_2b') ; XVAR = FSTATE%FREE_2B - CASE ('watr_2') ; XVAR = FSTATE%WATR_2 - CASE ('swe_z01') ; XVAR = MBANDS(1)%SWE - CASE ('swe_z02') ; XVAR = MBANDS(2)%SWE - CASE ('swe_z03') ; XVAR = MBANDS(3)%SWE - CASE ('swe_z04') ; XVAR = MBANDS(4)%SWE - CASE ('swe_z05') ; XVAR = MBANDS(5)%SWE - CASE ('swe_z06') ; XVAR = MBANDS(6)%SWE - CASE ('swe_z07') ; XVAR = MBANDS(7)%SWE - CASE ('swe_z08') ; XVAR = MBANDS(8)%SWE - CASE ('swe_z09') ; XVAR = MBANDS(9)%SWE - CASE ('swe_z10') ; XVAR = MBANDS(10)%SWE - CASE ('swe_z11') ; XVAR = MBANDS(11)%SWE - CASE ('swe_z12') ; XVAR = MBANDS(12)%SWE - CASE ('swe_z13') ; XVAR = MBANDS(13)%SWE - CASE ('swe_z14') ; XVAR = MBANDS(14)%SWE - CASE ('swe_z15') ; XVAR = MBANDS(15)%SWE - CASE ('swe_z16') ; XVAR = MBANDS(16)%SWE - CASE ('swe_z17') ; XVAR = MBANDS(17)%SWE - CASE ('swe_z18') ; XVAR = MBANDS(18)%SWE - CASE ('swe_z19') ; XVAR = MBANDS(19)%SWE - CASE ('swe_z20') ; XVAR = MBANDS(20)%SWE - CASE ('swe_z21') ; XVAR = MBANDS(21)%SWE - CASE ('swe_z22') ; XVAR = MBANDS(22)%SWE - CASE ('swe_z23') ; XVAR = MBANDS(23)%SWE - CASE ('swe_z24') ; XVAR = MBANDS(24)%SWE - CASE ('swe_z25') ; XVAR = MBANDS(25)%SWE - CASE ('swe_z26') ; XVAR = MBANDS(26)%SWE - CASE ('swe_z27') ; XVAR = MBANDS(27)%SWE - CASE ('swe_z28') ; XVAR = MBANDS(28)%SWE - CASE ('swe_z29') ; XVAR = MBANDS(29)%SWE - CASE ('swe_z30') ; XVAR = MBANDS(30)%SWE - CASE ('swe_z31') ; XVAR = MBANDS(31)%SWE - CASE ('swe_z32') ; XVAR = MBANDS(32)%SWE - CASE ('swe_z33') ; XVAR = MBANDS(33)%SWE - CASE ('swe_z34') ; XVAR = MBANDS(34)%SWE - CASE ('swe_z35') ; XVAR = MBANDS(35)%SWE - CASE ('swe_z36') ; XVAR = MBANDS(36)%SWE - CASE ('swe_z37') ; XVAR = MBANDS(37)%SWE - CASE ('swe_z38') ; XVAR = MBANDS(38)%SWE - CASE ('swe_z39') ; XVAR = MBANDS(39)%SWE - CASE ('swe_z40') ; XVAR = MBANDS(40)%SWE - CASE ('swe_z41') ; XVAR = MBANDS(41)%SWE - CASE ('swe_z42') ; XVAR = MBANDS(42)%SWE - CASE ('swe_z43') ; XVAR = MBANDS(43)%SWE - CASE ('swe_z44') ; XVAR = MBANDS(44)%SWE - CASE ('swe_z45') ; XVAR = MBANDS(45)%SWE - CASE ('swe_z46') ; XVAR = MBANDS(46)%SWE - CASE ('swe_z47') ; XVAR = MBANDS(47)%SWE - CASE ('swe_z48') ; XVAR = MBANDS(48)%SWE - CASE ('swe_z49') ; XVAR = MBANDS(49)%SWE - CASE ('swe_z50') ; XVAR = MBANDS(50)%SWE - ! extract model fluxes - CASE ('eff_ppt') ; XVAR = W_FLUX%EFF_PPT - CASE ('satarea') ; XVAR = W_FLUX%SATAREA - CASE ('qsurf') ; XVAR = W_FLUX%QSURF - CASE ('evap_1a') ; XVAR = W_FLUX%EVAP_1A - CASE ('evap_1b') ; XVAR = W_FLUX%EVAP_1B - CASE ('evap_1') ; XVAR = W_FLUX%EVAP_1 - CASE ('evap_2') ; XVAR = W_FLUX%EVAP_2 - CASE ('rchr2excs') ; XVAR = W_FLUX%RCHR2EXCS - CASE ('tens2free_1'); XVAR = W_FLUX%TENS2FREE_1 - CASE ('oflow_1') ; XVAR = W_FLUX%OFLOW_1 - CASE ('tens2free_2'); XVAR = W_FLUX%TENS2FREE_2 - CASE ('qintf_1') ; XVAR = W_FLUX%QINTF_1 - CASE ('qperc_12') ; XVAR = W_FLUX%QPERC_12 - CASE ('qbase_2') ; XVAR = W_FLUX%QBASE_2 - CASE ('qbase_2a') ; XVAR = W_FLUX%QBASE_2A - CASE ('qbase_2b') ; XVAR = W_FLUX%QBASE_2B - CASE ('oflow_2') ; XVAR = W_FLUX%OFLOW_2 - CASE ('oflow_2a') ; XVAR = W_FLUX%OFLOW_2A - CASE ('oflow_2b') ; XVAR = W_FLUX%OFLOW_2B - CASE ('snwacml_z01'); XVAR = MBANDS(1)%SNOWACCMLTN - CASE ('snwacml_z02'); XVAR = MBANDS(2)%SNOWACCMLTN - CASE ('snwacml_z03'); XVAR = MBANDS(3)%SNOWACCMLTN - CASE ('snwacml_z04'); XVAR = MBANDS(4)%SNOWACCMLTN - CASE ('snwacml_z05'); XVAR = MBANDS(5)%SNOWACCMLTN - CASE ('snwacml_z06'); XVAR = MBANDS(6)%SNOWACCMLTN - CASE ('snwacml_z07'); XVAR = MBANDS(7)%SNOWACCMLTN - CASE ('snwacml_z08'); XVAR = MBANDS(8)%SNOWACCMLTN - CASE ('snwacml_z09'); XVAR = MBANDS(9)%SNOWACCMLTN - CASE ('snwacml_z10'); XVAR = MBANDS(10)%SNOWACCMLTN - CASE ('snwacml_z11'); XVAR = MBANDS(11)%SNOWACCMLTN - CASE ('snwacml_z12'); XVAR = MBANDS(12)%SNOWACCMLTN - CASE ('snwacml_z13'); XVAR = MBANDS(13)%SNOWACCMLTN - CASE ('snwacml_z14'); XVAR = MBANDS(14)%SNOWACCMLTN - CASE ('snwacml_z15'); XVAR = MBANDS(15)%SNOWACCMLTN - CASE ('snwacml_z16'); XVAR = MBANDS(16)%SNOWACCMLTN - CASE ('snwacml_z17'); XVAR = MBANDS(17)%SNOWACCMLTN - CASE ('snwacml_z18'); XVAR = MBANDS(18)%SNOWACCMLTN - CASE ('snwacml_z19'); XVAR = MBANDS(19)%SNOWACCMLTN - CASE ('snwacml_z20'); XVAR = MBANDS(20)%SNOWACCMLTN - CASE ('snwacml_z21'); XVAR = MBANDS(21)%SNOWACCMLTN - CASE ('snwacml_z22'); XVAR = MBANDS(22)%SNOWACCMLTN - CASE ('snwacml_z23'); XVAR = MBANDS(23)%SNOWACCMLTN - CASE ('snwacml_z24'); XVAR = MBANDS(24)%SNOWACCMLTN - CASE ('snwacml_z25'); XVAR = MBANDS(25)%SNOWACCMLTN - CASE ('snwacml_z26'); XVAR = MBANDS(26)%SNOWACCMLTN - CASE ('snwacml_z27'); XVAR = MBANDS(27)%SNOWACCMLTN - CASE ('snwacml_z28'); XVAR = MBANDS(28)%SNOWACCMLTN - CASE ('snwacml_z29'); XVAR = MBANDS(29)%SNOWACCMLTN - CASE ('snwacml_z30'); XVAR = MBANDS(30)%SNOWACCMLTN - CASE ('snwacml_z31'); XVAR = MBANDS(31)%SNOWACCMLTN - CASE ('snwacml_z32'); XVAR = MBANDS(32)%SNOWACCMLTN - CASE ('snwacml_z33'); XVAR = MBANDS(33)%SNOWACCMLTN - CASE ('snwacml_z34'); XVAR = MBANDS(34)%SNOWACCMLTN - CASE ('snwacml_z35'); XVAR = MBANDS(35)%SNOWACCMLTN - CASE ('snwacml_z36'); XVAR = MBANDS(36)%SNOWACCMLTN - CASE ('snwacml_z37'); XVAR = MBANDS(37)%SNOWACCMLTN - CASE ('snwacml_z38'); XVAR = MBANDS(38)%SNOWACCMLTN - CASE ('snwacml_z39'); XVAR = MBANDS(39)%SNOWACCMLTN - CASE ('snwacml_z40'); XVAR = MBANDS(40)%SNOWACCMLTN - CASE ('snwacml_z41'); XVAR = MBANDS(41)%SNOWACCMLTN - CASE ('snwacml_z42'); XVAR = MBANDS(42)%SNOWACCMLTN - CASE ('snwacml_z43'); XVAR = MBANDS(43)%SNOWACCMLTN - CASE ('snwacml_z44'); XVAR = MBANDS(44)%SNOWACCMLTN - CASE ('snwacml_z45'); XVAR = MBANDS(45)%SNOWACCMLTN - CASE ('snwacml_z46'); XVAR = MBANDS(46)%SNOWACCMLTN - CASE ('snwacml_z47'); XVAR = MBANDS(47)%SNOWACCMLTN - CASE ('snwacml_z48'); XVAR = MBANDS(48)%SNOWACCMLTN - CASE ('snwacml_z49'); XVAR = MBANDS(49)%SNOWACCMLTN - CASE ('snwacml_z50'); XVAR = MBANDS(50)%SNOWACCMLTN - CASE ('snwmelt_z01'); XVAR = MBANDS(1)%SNOWMELT - CASE ('snwmelt_z02'); XVAR = MBANDS(2)%SNOWMELT - CASE ('snwmelt_z03'); XVAR = MBANDS(3)%SNOWMELT - CASE ('snwmelt_z04'); XVAR = MBANDS(4)%SNOWMELT - CASE ('snwmelt_z05'); XVAR = MBANDS(5)%SNOWMELT - CASE ('snwmelt_z06'); XVAR = MBANDS(6)%SNOWMELT - CASE ('snwmelt_z07'); XVAR = MBANDS(7)%SNOWMELT - CASE ('snwmelt_z08'); XVAR = MBANDS(8)%SNOWMELT - CASE ('snwmelt_z09'); XVAR = MBANDS(9)%SNOWMELT - CASE ('snwmelt_z10'); XVAR = MBANDS(10)%SNOWMELT - CASE ('snwmelt_z11'); XVAR = MBANDS(11)%SNOWMELT - CASE ('snwmelt_z12'); XVAR = MBANDS(12)%SNOWMELT - CASE ('snwmelt_z13'); XVAR = MBANDS(13)%SNOWMELT - CASE ('snwmelt_z14'); XVAR = MBANDS(14)%SNOWMELT - CASE ('snwmelt_z15'); XVAR = MBANDS(15)%SNOWMELT - CASE ('snwmelt_z16'); XVAR = MBANDS(16)%SNOWMELT - CASE ('snwmelt_z17'); XVAR = MBANDS(17)%SNOWMELT - CASE ('snwmelt_z18'); XVAR = MBANDS(18)%SNOWMELT - CASE ('snwmelt_z19'); XVAR = MBANDS(19)%SNOWMELT - CASE ('snwmelt_z20'); XVAR = MBANDS(20)%SNOWMELT - CASE ('snwmelt_z21'); XVAR = MBANDS(21)%SNOWMELT - CASE ('snwmelt_z22'); XVAR = MBANDS(22)%SNOWMELT - CASE ('snwmelt_z23'); XVAR = MBANDS(23)%SNOWMELT - CASE ('snwmelt_z24'); XVAR = MBANDS(24)%SNOWMELT - CASE ('snwmelt_z25'); XVAR = MBANDS(25)%SNOWMELT - CASE ('snwmelt_z26'); XVAR = MBANDS(26)%SNOWMELT - CASE ('snwmelt_z27'); XVAR = MBANDS(27)%SNOWMELT - CASE ('snwmelt_z28'); XVAR = MBANDS(28)%SNOWMELT - CASE ('snwmelt_z29'); XVAR = MBANDS(29)%SNOWMELT - CASE ('snwmelt_z30'); XVAR = MBANDS(30)%SNOWMELT - CASE ('snwmelt_z31'); XVAR = MBANDS(31)%SNOWMELT - CASE ('snwmelt_z32'); XVAR = MBANDS(32)%SNOWMELT - CASE ('snwmelt_z33'); XVAR = MBANDS(33)%SNOWMELT - CASE ('snwmelt_z34'); XVAR = MBANDS(34)%SNOWMELT - CASE ('snwmelt_z35'); XVAR = MBANDS(35)%SNOWMELT - CASE ('snwmelt_z36'); XVAR = MBANDS(36)%SNOWMELT - CASE ('snwmelt_z37'); XVAR = MBANDS(37)%SNOWMELT - CASE ('snwmelt_z38'); XVAR = MBANDS(38)%SNOWMELT - CASE ('snwmelt_z39'); XVAR = MBANDS(39)%SNOWMELT - CASE ('snwmelt_z40'); XVAR = MBANDS(40)%SNOWMELT - CASE ('snwmelt_z41'); XVAR = MBANDS(41)%SNOWMELT - CASE ('snwmelt_z42'); XVAR = MBANDS(42)%SNOWMELT - CASE ('snwmelt_z43'); XVAR = MBANDS(43)%SNOWMELT - CASE ('snwmelt_z44'); XVAR = MBANDS(44)%SNOWMELT - CASE ('snwmelt_z45'); XVAR = MBANDS(45)%SNOWMELT - CASE ('snwmelt_z46'); XVAR = MBANDS(46)%SNOWMELT - CASE ('snwmelt_z47'); XVAR = MBANDS(47)%SNOWMELT - CASE ('snwmelt_z48'); XVAR = MBANDS(48)%SNOWMELT - CASE ('snwmelt_z49'); XVAR = MBANDS(49)%SNOWMELT - CASE ('snwmelt_z50'); XVAR = MBANDS(50)%SNOWMELT - ! extract extrapolation errors - CASE ('err_tens_1') ; XVAR = W_FLUX%ERR_TENS_1 - CASE ('err_tens_1a'); XVAR = W_FLUX%ERR_TENS_1A - CASE ('err_tens_1b'); XVAR = W_FLUX%ERR_TENS_1B - CASE ('err_free_1') ; XVAR = W_FLUX%ERR_FREE_1 - CASE ('err_watr_1') ; XVAR = W_FLUX%ERR_WATR_1 - CASE ('err_tens_2') ; XVAR = W_FLUX%ERR_TENS_2 - CASE ('err_free_2') ; XVAR = W_FLUX%ERR_FREE_2 - CASE ('err_free_2a'); XVAR = W_FLUX%ERR_FREE_2A - CASE ('err_free_2b'); XVAR = W_FLUX%ERR_FREE_2B - CASE ('err_watr_2') ; XVAR = W_FLUX%ERR_WATR_2 - ! time check - CASE ('chk_time') ; XVAR = W_FLUX%CHK_TIME - ! extract model runoff - CASE ('q_instnt') ; XVAR = MROUTE%Q_INSTNT - CASE ('q_routed') ; XVAR = MROUTE%Q_ROUTED - ! extract information on numerical solution (shared in MODULE model_numerix) - CASE ('num_funcs') ; XVAR = NUM_FUNCS - CASE ('numjacobian'); XVAR = NUM_JACOBIAN - CASE ('sub_accept') ; XVAR = NUMSUB_ACCEPT - CASE ('sub_reject') ; XVAR = NUMSUB_REJECT - CASE ('sub_noconv') ; XVAR = NUMSUB_NOCONV - CASE ('max_iterns') ; XVAR = MAXNUM_ITERNS -END SELECT -! and, save the output -VAREXTRACT = XVAR -! --------------------------------------------------------------------------------------- -END FUNCTION VAREXTRACT -! --------------------------------------------------------------------------------------- -! --------------------------------------------------------------------------------------- -PURE FUNCTION VAREXTRACT_3d(VARNAME,numtim) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Nans Addor, based on Martyn Clark's 2007 VAREXTRACT -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Extracts variable "VARNAME" from relevant data structures -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -USE metaoutput ! metadata for all model variables -USE multiforce ! model forcing data -USE multistate ! model states -USE multi_flux ! model fluxes -USE multibands ! model snow bands -USE multiroute ! routed runoff -USE model_numerix ! model numerix parameters -IMPLICIT NONE -! input -CHARACTER(*), INTENT(IN) :: VARNAME ! variable name -INTEGER(i4b), INTENT(IN) :: numtim ! number of time steps -! internal -real(sp),DIMENSION(nspat1,nspat2,numtim):: XVAR_3d ! variable -integer(i4b) :: ierr ! error code -CHARACTER(LEN=1024) :: MESSAGE ! error message -! output -real(sp), DIMENSION(nspat1,nspat2,numtim) :: VAREXTRACT_3d ! FUNCTION name + USE nrtype ! variable types, etc. -! --------------------------------------------------------------------------------------- -! the length of the temporal dimension of the state variables (gState_3d and MBANDS_VAR_4d) -! is greater by one time step, so only keeping first numtim time steps, i.e. not writing -! last value the output file + IMPLICIT NONE -SELECT CASE (TRIM(VARNAME)) - ! extract forcing data - CASE ('ppt') ; XVAR_3d = gForce_3d%PPT - CASE ('temp') ; XVAR_3d = gForce_3d%TEMP - CASE ('pet') ; XVAR_3d = gForce_3d%PET - ! extract response data - CASE ('obsq') ; XVAR_3d = aValid%OBSQ - ! extract model states - CASE ('tens_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1 - CASE ('tens_1a') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1A - CASE ('tens_1b') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1B - CASE ('free_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_1 - CASE ('watr_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%WATR_1 - CASE ('tens_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_2 - CASE ('free_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2 - CASE ('free_2a') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2A - CASE ('free_2b') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2B - CASE ('watr_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%WATR_2 - CASE ('swe_tot') ; XVAR_3d = gState_3d(:,:,1:numtim)%swe_tot - CASE ('swe_z01') ; XVAR_3d = MBANDS_VAR_4d(:,:,1,1:numtim)%SWE - CASE ('swe_z02') ; XVAR_3d = MBANDS_VAR_4d(:,:,2,1:numtim)%SWE - CASE ('swe_z03') ; XVAR_3d = MBANDS_VAR_4d(:,:,3,1:numtim)%SWE - CASE ('swe_z04') ; XVAR_3d = MBANDS_VAR_4d(:,:,4,1:numtim)%SWE - CASE ('swe_z05') ; XVAR_3d = MBANDS_VAR_4d(:,:,5,1:numtim)%SWE - CASE ('swe_z06') ; XVAR_3d = MBANDS_VAR_4d(:,:,6,1:numtim)%SWE - CASE ('swe_z07') ; XVAR_3d = MBANDS_VAR_4d(:,:,7,1:numtim)%SWE - CASE ('swe_z08') ; XVAR_3d = MBANDS_VAR_4d(:,:,8,1:numtim)%SWE - CASE ('swe_z09') ; XVAR_3d = MBANDS_VAR_4d(:,:,9,1:numtim)%SWE - CASE ('swe_z10') ; XVAR_3d = MBANDS_VAR_4d(:,:,10,1:numtim)%SWE - CASE ('swe_z11') ; XVAR_3d = MBANDS_VAR_4d(:,:,11,1:numtim)%SWE - CASE ('swe_z12') ; XVAR_3d = MBANDS_VAR_4d(:,:,12,1:numtim)%SWE - CASE ('swe_z13') ; XVAR_3d = MBANDS_VAR_4d(:,:,13,1:numtim)%SWE - CASE ('swe_z14') ; XVAR_3d = MBANDS_VAR_4d(:,:,14,1:numtim)%SWE - CASE ('swe_z15') ; XVAR_3d = MBANDS_VAR_4d(:,:,15,1:numtim)%SWE - CASE ('swe_z16') ; XVAR_3d = MBANDS_VAR_4d(:,:,16,1:numtim)%SWE - CASE ('swe_z17') ; XVAR_3d = MBANDS_VAR_4d(:,:,17,1:numtim)%SWE - CASE ('swe_z18') ; XVAR_3d = MBANDS_VAR_4d(:,:,18,1:numtim)%SWE - CASE ('swe_z19') ; XVAR_3d = MBANDS_VAR_4d(:,:,19,1:numtim)%SWE - CASE ('swe_z20') ; XVAR_3d = MBANDS_VAR_4d(:,:,20,1:numtim)%SWE - CASE ('swe_z21') ; XVAR_3d = MBANDS_VAR_4d(:,:,21,1:numtim)%SWE - CASE ('swe_z22') ; XVAR_3d = MBANDS_VAR_4d(:,:,22,1:numtim)%SWE - CASE ('swe_z23') ; XVAR_3d = MBANDS_VAR_4d(:,:,23,1:numtim)%SWE - CASE ('swe_z24') ; XVAR_3d = MBANDS_VAR_4d(:,:,24,1:numtim)%SWE - CASE ('swe_z25') ; XVAR_3d = MBANDS_VAR_4d(:,:,25,1:numtim)%SWE - CASE ('swe_z26') ; XVAR_3d = MBANDS_VAR_4d(:,:,26,1:numtim)%SWE - CASE ('swe_z27') ; XVAR_3d = MBANDS_VAR_4d(:,:,27,1:numtim)%SWE - CASE ('swe_z28') ; XVAR_3d = MBANDS_VAR_4d(:,:,28,1:numtim)%SWE - CASE ('swe_z29') ; XVAR_3d = MBANDS_VAR_4d(:,:,29,1:numtim)%SWE - CASE ('swe_z30') ; XVAR_3d = MBANDS_VAR_4d(:,:,30,1:numtim)%SWE - CASE ('swe_z31') ; XVAR_3d = MBANDS_VAR_4d(:,:,31,1:numtim)%SWE - CASE ('swe_z32') ; XVAR_3d = MBANDS_VAR_4d(:,:,32,1:numtim)%SWE - CASE ('swe_z33') ; XVAR_3d = MBANDS_VAR_4d(:,:,33,1:numtim)%SWE - CASE ('swe_z34') ; XVAR_3d = MBANDS_VAR_4d(:,:,34,1:numtim)%SWE - CASE ('swe_z35') ; XVAR_3d = MBANDS_VAR_4d(:,:,35,1:numtim)%SWE - CASE ('swe_z36') ; XVAR_3d = MBANDS_VAR_4d(:,:,36,1:numtim)%SWE - CASE ('swe_z37') ; XVAR_3d = MBANDS_VAR_4d(:,:,37,1:numtim)%SWE - CASE ('swe_z38') ; XVAR_3d = MBANDS_VAR_4d(:,:,38,1:numtim)%SWE - CASE ('swe_z39') ; XVAR_3d = MBANDS_VAR_4d(:,:,39,1:numtim)%SWE - CASE ('swe_z40') ; XVAR_3d = MBANDS_VAR_4d(:,:,40,1:numtim)%SWE - CASE ('swe_z41') ; XVAR_3d = MBANDS_VAR_4d(:,:,41,1:numtim)%SWE - CASE ('swe_z42') ; XVAR_3d = MBANDS_VAR_4d(:,:,42,1:numtim)%SWE - CASE ('swe_z43') ; XVAR_3d = MBANDS_VAR_4d(:,:,43,1:numtim)%SWE - CASE ('swe_z44') ; XVAR_3d = MBANDS_VAR_4d(:,:,44,1:numtim)%SWE - CASE ('swe_z45') ; XVAR_3d = MBANDS_VAR_4d(:,:,45,1:numtim)%SWE - CASE ('swe_z46') ; XVAR_3d = MBANDS_VAR_4d(:,:,46,1:numtim)%SWE - CASE ('swe_z47') ; XVAR_3d = MBANDS_VAR_4d(:,:,47,1:numtim)%SWE - CASE ('swe_z48') ; XVAR_3d = MBANDS_VAR_4d(:,:,48,1:numtim)%SWE - CASE ('swe_z49') ; XVAR_3d = MBANDS_VAR_4d(:,:,49,1:numtim)%SWE - CASE ('swe_z50') ; XVAR_3d = MBANDS_VAR_4d(:,:,50,1:numtim)%SWE - ! extract model fluxes - CASE ('eff_ppt') ; XVAR_3d = W_FLUX_3d%EFF_PPT - CASE ('satarea') ; XVAR_3d = W_FLUX_3d%SATAREA - CASE ('qsurf') ; XVAR_3d = W_FLUX_3d%QSURF - CASE ('evap_1a') ; XVAR_3d = W_FLUX_3d%EVAP_1A - CASE ('evap_1b') ; XVAR_3d = W_FLUX_3d%EVAP_1B - CASE ('evap_1') ; XVAR_3d = W_FLUX_3d%EVAP_1 - CASE ('evap_2') ; XVAR_3d = W_FLUX_3d%EVAP_2 - CASE ('rchr2excs') ; XVAR_3d = W_FLUX_3d%RCHR2EXCS - CASE ('tens2free_1'); XVAR_3d = W_FLUX_3d%TENS2FREE_1 - CASE ('oflow_1') ; XVAR_3d = W_FLUX_3d%OFLOW_1 - CASE ('tens2free_2'); XVAR_3d = W_FLUX_3d%TENS2FREE_2 - CASE ('qintf_1') ; XVAR_3d = W_FLUX_3d%QINTF_1 - CASE ('qperc_12') ; XVAR_3d = W_FLUX_3d%QPERC_12 - CASE ('qbase_2') ; XVAR_3d = W_FLUX_3d%QBASE_2 - CASE ('qbase_2a') ; XVAR_3d = W_FLUX_3d%QBASE_2A - CASE ('qbase_2b') ; XVAR_3d = W_FLUX_3d%QBASE_2B - CASE ('oflow_2') ; XVAR_3d = W_FLUX_3d%OFLOW_2 - CASE ('oflow_2a') ; XVAR_3d = W_FLUX_3d%OFLOW_2A - CASE ('oflow_2b') ; XVAR_3d = W_FLUX_3d%OFLOW_2B - CASE ('snwacml_z01'); XVAR_3d = MBANDS_VAR_4d(:,:,1,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z02'); XVAR_3d = MBANDS_VAR_4d(:,:,2,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z03'); XVAR_3d = MBANDS_VAR_4d(:,:,3,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z04'); XVAR_3d = MBANDS_VAR_4d(:,:,4,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z05'); XVAR_3d = MBANDS_VAR_4d(:,:,5,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z06'); XVAR_3d = MBANDS_VAR_4d(:,:,6,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z07'); XVAR_3d = MBANDS_VAR_4d(:,:,7,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z08'); XVAR_3d = MBANDS_VAR_4d(:,:,8,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z09'); XVAR_3d = MBANDS_VAR_4d(:,:,9,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z10'); XVAR_3d = MBANDS_VAR_4d(:,:,10,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z11'); XVAR_3d = MBANDS_VAR_4d(:,:,11,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z12'); XVAR_3d = MBANDS_VAR_4d(:,:,12,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z13'); XVAR_3d = MBANDS_VAR_4d(:,:,13,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z14'); XVAR_3d = MBANDS_VAR_4d(:,:,14,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z15'); XVAR_3d = MBANDS_VAR_4d(:,:,15,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z16'); XVAR_3d = MBANDS_VAR_4d(:,:,16,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z17'); XVAR_3d = MBANDS_VAR_4d(:,:,17,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z18'); XVAR_3d = MBANDS_VAR_4d(:,:,18,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z19'); XVAR_3d = MBANDS_VAR_4d(:,:,19,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z20'); XVAR_3d = MBANDS_VAR_4d(:,:,20,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z21'); XVAR_3d = MBANDS_VAR_4d(:,:,21,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z22'); XVAR_3d = MBANDS_VAR_4d(:,:,22,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z23'); XVAR_3d = MBANDS_VAR_4d(:,:,23,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z24'); XVAR_3d = MBANDS_VAR_4d(:,:,24,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z25'); XVAR_3d = MBANDS_VAR_4d(:,:,25,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z26'); XVAR_3d = MBANDS_VAR_4d(:,:,26,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z27'); XVAR_3d = MBANDS_VAR_4d(:,:,27,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z28'); XVAR_3d = MBANDS_VAR_4d(:,:,28,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z29'); XVAR_3d = MBANDS_VAR_4d(:,:,29,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z30'); XVAR_3d = MBANDS_VAR_4d(:,:,30,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z31'); XVAR_3d = MBANDS_VAR_4d(:,:,31,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z32'); XVAR_3d = MBANDS_VAR_4d(:,:,32,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z33'); XVAR_3d = MBANDS_VAR_4d(:,:,33,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z34'); XVAR_3d = MBANDS_VAR_4d(:,:,34,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z35'); XVAR_3d = MBANDS_VAR_4d(:,:,35,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z36'); XVAR_3d = MBANDS_VAR_4d(:,:,36,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z37'); XVAR_3d = MBANDS_VAR_4d(:,:,37,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z38'); XVAR_3d = MBANDS_VAR_4d(:,:,38,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z39'); XVAR_3d = MBANDS_VAR_4d(:,:,39,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z40'); XVAR_3d = MBANDS_VAR_4d(:,:,40,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z41'); XVAR_3d = MBANDS_VAR_4d(:,:,41,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z42'); XVAR_3d = MBANDS_VAR_4d(:,:,42,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z43'); XVAR_3d = MBANDS_VAR_4d(:,:,43,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z44'); XVAR_3d = MBANDS_VAR_4d(:,:,44,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z45'); XVAR_3d = MBANDS_VAR_4d(:,:,45,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z46'); XVAR_3d = MBANDS_VAR_4d(:,:,46,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z47'); XVAR_3d = MBANDS_VAR_4d(:,:,47,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z48'); XVAR_3d = MBANDS_VAR_4d(:,:,48,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z49'); XVAR_3d = MBANDS_VAR_4d(:,:,49,1:numtim)%SNOWACCMLTN - CASE ('snwacml_z50'); XVAR_3d = MBANDS_VAR_4d(:,:,50,1:numtim)%SNOWACCMLTN - CASE ('snwmelt_z01'); XVAR_3d = MBANDS_VAR_4d(:,:,1,1:numtim)%SNOWMELT - CASE ('snwmelt_z02'); XVAR_3d = MBANDS_VAR_4d(:,:,2,1:numtim)%SNOWMELT - CASE ('snwmelt_z03'); XVAR_3d = MBANDS_VAR_4d(:,:,3,1:numtim)%SNOWMELT - CASE ('snwmelt_z04'); XVAR_3d = MBANDS_VAR_4d(:,:,4,1:numtim)%SNOWMELT - CASE ('snwmelt_z05'); XVAR_3d = MBANDS_VAR_4d(:,:,5,1:numtim)%SNOWMELT - CASE ('snwmelt_z06'); XVAR_3d = MBANDS_VAR_4d(:,:,6,1:numtim)%SNOWMELT - CASE ('snwmelt_z07'); XVAR_3d = MBANDS_VAR_4d(:,:,7,1:numtim)%SNOWMELT - CASE ('snwmelt_z08'); XVAR_3d = MBANDS_VAR_4d(:,:,8,1:numtim)%SNOWMELT - CASE ('snwmelt_z09'); XVAR_3d = MBANDS_VAR_4d(:,:,9,1:numtim)%SNOWMELT - CASE ('snwmelt_z10'); XVAR_3d = MBANDS_VAR_4d(:,:,10,1:numtim)%SNOWMELT - CASE ('snwmelt_z11'); XVAR_3d = MBANDS_VAR_4d(:,:,11,1:numtim)%SNOWMELT - CASE ('snwmelt_z12'); XVAR_3d = MBANDS_VAR_4d(:,:,12,1:numtim)%SNOWMELT - CASE ('snwmelt_z13'); XVAR_3d = MBANDS_VAR_4d(:,:,13,1:numtim)%SNOWMELT - CASE ('snwmelt_z14'); XVAR_3d = MBANDS_VAR_4d(:,:,14,1:numtim)%SNOWMELT - CASE ('snwmelt_z15'); XVAR_3d = MBANDS_VAR_4d(:,:,15,1:numtim)%SNOWMELT - CASE ('snwmelt_z16'); XVAR_3d = MBANDS_VAR_4d(:,:,16,1:numtim)%SNOWMELT - CASE ('snwmelt_z17'); XVAR_3d = MBANDS_VAR_4d(:,:,17,1:numtim)%SNOWMELT - CASE ('snwmelt_z18'); XVAR_3d = MBANDS_VAR_4d(:,:,18,1:numtim)%SNOWMELT - CASE ('snwmelt_z19'); XVAR_3d = MBANDS_VAR_4d(:,:,19,1:numtim)%SNOWMELT - CASE ('snwmelt_z20'); XVAR_3d = MBANDS_VAR_4d(:,:,20,1:numtim)%SNOWMELT - CASE ('snwmelt_z21'); XVAR_3d = MBANDS_VAR_4d(:,:,21,1:numtim)%SNOWMELT - CASE ('snwmelt_z22'); XVAR_3d = MBANDS_VAR_4d(:,:,22,1:numtim)%SNOWMELT - CASE ('snwmelt_z23'); XVAR_3d = MBANDS_VAR_4d(:,:,23,1:numtim)%SNOWMELT - CASE ('snwmelt_z24'); XVAR_3d = MBANDS_VAR_4d(:,:,24,1:numtim)%SNOWMELT - CASE ('snwmelt_z25'); XVAR_3d = MBANDS_VAR_4d(:,:,25,1:numtim)%SNOWMELT - CASE ('snwmelt_z26'); XVAR_3d = MBANDS_VAR_4d(:,:,26,1:numtim)%SNOWMELT - CASE ('snwmelt_z27'); XVAR_3d = MBANDS_VAR_4d(:,:,27,1:numtim)%SNOWMELT - CASE ('snwmelt_z28'); XVAR_3d = MBANDS_VAR_4d(:,:,28,1:numtim)%SNOWMELT - CASE ('snwmelt_z29'); XVAR_3d = MBANDS_VAR_4d(:,:,29,1:numtim)%SNOWMELT - CASE ('snwmelt_z30'); XVAR_3d = MBANDS_VAR_4d(:,:,30,1:numtim)%SNOWMELT - CASE ('snwmelt_z31'); XVAR_3d = MBANDS_VAR_4d(:,:,31,1:numtim)%SNOWMELT - CASE ('snwmelt_z32'); XVAR_3d = MBANDS_VAR_4d(:,:,32,1:numtim)%SNOWMELT - CASE ('snwmelt_z33'); XVAR_3d = MBANDS_VAR_4d(:,:,33,1:numtim)%SNOWMELT - CASE ('snwmelt_z34'); XVAR_3d = MBANDS_VAR_4d(:,:,34,1:numtim)%SNOWMELT - CASE ('snwmelt_z35'); XVAR_3d = MBANDS_VAR_4d(:,:,35,1:numtim)%SNOWMELT - CASE ('snwmelt_z36'); XVAR_3d = MBANDS_VAR_4d(:,:,36,1:numtim)%SNOWMELT - CASE ('snwmelt_z37'); XVAR_3d = MBANDS_VAR_4d(:,:,37,1:numtim)%SNOWMELT - CASE ('snwmelt_z38'); XVAR_3d = MBANDS_VAR_4d(:,:,38,1:numtim)%SNOWMELT - CASE ('snwmelt_z39'); XVAR_3d = MBANDS_VAR_4d(:,:,39,1:numtim)%SNOWMELT - CASE ('snwmelt_z40'); XVAR_3d = MBANDS_VAR_4d(:,:,40,1:numtim)%SNOWMELT - CASE ('snwmelt_z41'); XVAR_3d = MBANDS_VAR_4d(:,:,41,1:numtim)%SNOWMELT - CASE ('snwmelt_z42'); XVAR_3d = MBANDS_VAR_4d(:,:,42,1:numtim)%SNOWMELT - CASE ('snwmelt_z43'); XVAR_3d = MBANDS_VAR_4d(:,:,43,1:numtim)%SNOWMELT - CASE ('snwmelt_z44'); XVAR_3d = MBANDS_VAR_4d(:,:,44,1:numtim)%SNOWMELT - CASE ('snwmelt_z45'); XVAR_3d = MBANDS_VAR_4d(:,:,45,1:numtim)%SNOWMELT - CASE ('snwmelt_z46'); XVAR_3d = MBANDS_VAR_4d(:,:,46,1:numtim)%SNOWMELT - CASE ('snwmelt_z47'); XVAR_3d = MBANDS_VAR_4d(:,:,47,1:numtim)%SNOWMELT - CASE ('snwmelt_z48'); XVAR_3d = MBANDS_VAR_4d(:,:,48,1:numtim)%SNOWMELT - CASE ('snwmelt_z49'); XVAR_3d = MBANDS_VAR_4d(:,:,49,1:numtim)%SNOWMELT - CASE ('snwmelt_z50'); XVAR_3d = MBANDS_VAR_4d(:,:,50,1:numtim)%SNOWMELT - ! extract extrapolation errors - CASE ('err_tens_1') ; XVAR_3d = W_FLUX_3d%ERR_TENS_1 - CASE ('err_tens_1a'); XVAR_3d = W_FLUX_3d%ERR_TENS_1A - CASE ('err_tens_1b'); XVAR_3d = W_FLUX_3d%ERR_TENS_1B - CASE ('err_free_1') ; XVAR_3d = W_FLUX_3d%ERR_FREE_1 - CASE ('err_watr_1') ; XVAR_3d = W_FLUX_3d%ERR_WATR_1 - CASE ('err_tens_2') ; XVAR_3d = W_FLUX_3d%ERR_TENS_2 - CASE ('err_free_2') ; XVAR_3d = W_FLUX_3d%ERR_FREE_2 - CASE ('err_free_2a'); XVAR_3d = W_FLUX_3d%ERR_FREE_2A - CASE ('err_free_2b'); XVAR_3d = W_FLUX_3d%ERR_FREE_2B - CASE ('err_watr_2') ; XVAR_3d = W_FLUX_3d%ERR_WATR_2 - ! time check - CASE ('chk_time') ; XVAR_3d = W_FLUX_3d%CHK_TIME - ! extract model runoff - CASE ('q_instnt') ; XVAR_3d = AROUTE_3d%Q_INSTNT - CASE ('q_routed') ; XVAR_3d = AROUTE_3d%Q_ROUTED - ! extract information on numerical solution (shared in MODULE model_numerix) - CASE ('num_funcs') ; XVAR_3d = NUM_FUNCS - CASE ('numjacobian'); XVAR_3d = NUM_JACOBIAN - CASE ('sub_accept') ; XVAR_3d = NUMSUB_ACCEPT - CASE ('sub_reject') ; XVAR_3d = NUMSUB_REJECT - CASE ('sub_noconv') ; XVAR_3d = NUMSUB_NOCONV - CASE ('max_iterns') ; XVAR_3d = MAXNUM_ITERNS -END SELECT + private + public :: VAREXTRACT_3d + public :: VAREXTRACT + + CONTAINS + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + PURE FUNCTION VAREXTRACT_3d(VARNAME,nspat1,nspat2,numtim) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Nans Addor, based on Martyn Clark's 2007 VAREXTRACT + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Extracts variable "VARNAME" from relevant data structures + ! --------------------------------------------------------------------------------------- + USE model_numerix ! model numerix parameters + USE globaldata, only: NA_VALUE_SP ! missing value + USE multiforce, only: gForce_3d, aValid ! model forcing data + USE multistate, only: gState_3d ! model states + USE multi_flux, only: w_flux_3d ! model fluxes + USE multiroute, only: aroute_3d ! routed runoff + IMPLICIT NONE + ! input + CHARACTER(*), INTENT(IN) :: VARNAME ! variable name + INTEGER(i4b), INTENT(IN) :: nspat1,nspat2 ! number of elements in spat1, spat2 (lon, lat) + INTEGER(i4b), INTENT(IN) :: numtim ! number of time steps + ! internal + real(sp), DIMENSION(nspat1,nspat2,numtim) :: XVAR_3d ! variable + integer(i4b) :: ierr ! error code + CHARACTER(LEN=1024) :: MESSAGE ! error message + ! output + real(sp), DIMENSION(nspat1,nspat2,numtim) :: VAREXTRACT_3d ! FUNCTION name + + ! --------------------------------------------------------------------------------------- + ! the length of the temporal dimension of the state variables (gState_3d and MBANDS_VAR_4d) + ! is greater by one time step, so only keeping first numtim time steps, i.e. not writing + ! last value the output file + + SELECT CASE (TRIM(VARNAME)) + + ! extract forcing data + CASE ('ppt') ; XVAR_3d = gForce_3d%PPT + CASE ('temp') ; XVAR_3d = gForce_3d%TEMP + CASE ('pet') ; XVAR_3d = gForce_3d%PET + + ! extract response data + CASE ('obsq') ; XVAR_3d = aValid%OBSQ + + ! extract model states + CASE ('tens_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1 + CASE ('tens_1a') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1A + CASE ('tens_1b') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1B + CASE ('free_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_1 + CASE ('watr_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%WATR_1 + CASE ('tens_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_2 + CASE ('free_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2 + CASE ('free_2a') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2A + CASE ('free_2b') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2B + CASE ('watr_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%WATR_2 + CASE ('swe_tot') ; XVAR_3d = gState_3d(:,:,1:numtim)%swe_tot + + ! extract model fluxes + CASE ('eff_ppt') ; XVAR_3d = W_FLUX_3d%EFF_PPT + CASE ('satarea') ; XVAR_3d = W_FLUX_3d%SATAREA + CASE ('qsurf') ; XVAR_3d = W_FLUX_3d%QSURF + CASE ('evap_1a') ; XVAR_3d = W_FLUX_3d%EVAP_1A + CASE ('evap_1b') ; XVAR_3d = W_FLUX_3d%EVAP_1B + CASE ('evap_1') ; XVAR_3d = W_FLUX_3d%EVAP_1 + CASE ('evap_2') ; XVAR_3d = W_FLUX_3d%EVAP_2 + CASE ('rchr2excs') ; XVAR_3d = W_FLUX_3d%RCHR2EXCS + CASE ('tens2free_1'); XVAR_3d = W_FLUX_3d%TENS2FREE_1 + CASE ('oflow_1') ; XVAR_3d = W_FLUX_3d%OFLOW_1 + CASE ('tens2free_2'); XVAR_3d = W_FLUX_3d%TENS2FREE_2 + CASE ('qintf_1') ; XVAR_3d = W_FLUX_3d%QINTF_1 + CASE ('qperc_12') ; XVAR_3d = W_FLUX_3d%QPERC_12 + CASE ('qbase_2') ; XVAR_3d = W_FLUX_3d%QBASE_2 + CASE ('qbase_2a') ; XVAR_3d = W_FLUX_3d%QBASE_2A + CASE ('qbase_2b') ; XVAR_3d = W_FLUX_3d%QBASE_2B + CASE ('oflow_2') ; XVAR_3d = W_FLUX_3d%OFLOW_2 + CASE ('oflow_2a') ; XVAR_3d = W_FLUX_3d%OFLOW_2A + CASE ('oflow_2b') ; XVAR_3d = W_FLUX_3d%OFLOW_2B + + ! extract extrapolation errors + CASE ('err_tens_1') ; XVAR_3d = W_FLUX_3d%ERR_TENS_1 + CASE ('err_tens_1a'); XVAR_3d = W_FLUX_3d%ERR_TENS_1A + CASE ('err_tens_1b'); XVAR_3d = W_FLUX_3d%ERR_TENS_1B + CASE ('err_free_1') ; XVAR_3d = W_FLUX_3d%ERR_FREE_1 + CASE ('err_watr_1') ; XVAR_3d = W_FLUX_3d%ERR_WATR_1 + CASE ('err_tens_2') ; XVAR_3d = W_FLUX_3d%ERR_TENS_2 + CASE ('err_free_2') ; XVAR_3d = W_FLUX_3d%ERR_FREE_2 + CASE ('err_free_2a'); XVAR_3d = W_FLUX_3d%ERR_FREE_2A + CASE ('err_free_2b'); XVAR_3d = W_FLUX_3d%ERR_FREE_2B + CASE ('err_watr_2') ; XVAR_3d = W_FLUX_3d%ERR_WATR_2 + + ! time check + CASE ('chk_time') ; XVAR_3d = W_FLUX_3d%CHK_TIME + + ! extract model runoff + CASE ('q_instnt') ; XVAR_3d = AROUTE_3d%Q_INSTNT + CASE ('q_routed') ; XVAR_3d = AROUTE_3d%Q_ROUTED + + ! extract information on numerical solution (shared in MODULE model_numerix) + CASE ('num_funcs') ; XVAR_3d = NUM_FUNCS + CASE ('numjacobian'); XVAR_3d = NUM_JACOBIAN + CASE ('sub_accept') ; XVAR_3d = NUMSUB_ACCEPT + CASE ('sub_reject') ; XVAR_3d = NUMSUB_REJECT + CASE ('sub_noconv') ; XVAR_3d = NUMSUB_NOCONV + CASE ('max_iterns') ; XVAR_3d = MAXNUM_ITERNS + + ! default + case default; XVAR_3d = NA_VALUE_SP + + END SELECT + + ! save the output + VAREXTRACT_3d = XVAR_3d + + ! --------------------------------------------------------------------------------------- + END FUNCTION VAREXTRACT_3d + + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------- + + ! --------------------------------------------------------------------------------------- + PURE FUNCTION VAREXTRACT(VARNAME) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Nans Addor to enable distributed modeling, 9/2016 + ! Modified by Martyn Clark to use dimension for elevation bands, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Extracts variable "VARNAME" from relevant data structures + ! --------------------------------------------------------------------------------------- + USE model_numerix ! model numerix parameters + USE globaldata, only: NA_VALUE_SP ! missing value + USE multiforce, only: MFORCE, valDat ! model forcing data + USE multistate, only: FSTATE ! model states + USE multi_flux, only: W_FLUX ! model fluxes + USE multiroute, only: MROUTE ! routed runoff + IMPLICIT NONE + ! input + CHARACTER(*), INTENT(IN) :: VARNAME ! variable name + ! internal + REAL(SP) :: XVAR ! variable + ! output + REAL(SP) :: VAREXTRACT ! FUNCTION name + ! --------------------------------------------------------------------------------------- + SELECT CASE (TRIM(VARNAME)) + + ! extract forcing data + CASE ('ppt') ; XVAR = MFORCE%PPT + CASE ('temp') ; XVAR = MFORCE%TEMP + CASE ('pet') ; XVAR = MFORCE%PET + + ! extract response data + CASE ('obsq') ; XVAR = valDat%OBSQ + + ! extract model states + CASE ('tens_1') ; XVAR = FSTATE%TENS_1 + CASE ('tens_1a') ; XVAR = FSTATE%TENS_1A + CASE ('tens_1b') ; XVAR = FSTATE%TENS_1B + CASE ('free_1') ; XVAR = FSTATE%FREE_1 + CASE ('watr_1') ; XVAR = FSTATE%WATR_1 + CASE ('tens_2') ; XVAR = FSTATE%TENS_2 + CASE ('free_2') ; XVAR = FSTATE%FREE_2 + CASE ('free_2a') ; XVAR = FSTATE%FREE_2A + CASE ('free_2b') ; XVAR = FSTATE%FREE_2B + CASE ('watr_2') ; XVAR = FSTATE%WATR_2 + CASE ('swe_tot') ; XVAR = FSTATE%swe_tot + + ! extract model fluxes + CASE ('eff_ppt') ; XVAR = W_FLUX%EFF_PPT + CASE ('satarea') ; XVAR = W_FLUX%SATAREA + CASE ('qsurf') ; XVAR = W_FLUX%QSURF + CASE ('evap_1a') ; XVAR = W_FLUX%EVAP_1A + CASE ('evap_1b') ; XVAR = W_FLUX%EVAP_1B + CASE ('evap_1') ; XVAR = W_FLUX%EVAP_1 + CASE ('evap_2') ; XVAR = W_FLUX%EVAP_2 + CASE ('rchr2excs') ; XVAR = W_FLUX%RCHR2EXCS + CASE ('tens2free_1'); XVAR = W_FLUX%TENS2FREE_1 + CASE ('oflow_1') ; XVAR = W_FLUX%OFLOW_1 + CASE ('tens2free_2'); XVAR = W_FLUX%TENS2FREE_2 + CASE ('qintf_1') ; XVAR = W_FLUX%QINTF_1 + CASE ('qperc_12') ; XVAR = W_FLUX%QPERC_12 + CASE ('qbase_2') ; XVAR = W_FLUX%QBASE_2 + CASE ('qbase_2a') ; XVAR = W_FLUX%QBASE_2A + CASE ('qbase_2b') ; XVAR = W_FLUX%QBASE_2B + CASE ('oflow_2') ; XVAR = W_FLUX%OFLOW_2 + CASE ('oflow_2a') ; XVAR = W_FLUX%OFLOW_2A + CASE ('oflow_2b') ; XVAR = W_FLUX%OFLOW_2B + + ! extract extrapolation errors + CASE ('err_tens_1') ; XVAR = W_FLUX%ERR_TENS_1 + CASE ('err_tens_1a'); XVAR = W_FLUX%ERR_TENS_1A + CASE ('err_tens_1b'); XVAR = W_FLUX%ERR_TENS_1B + CASE ('err_free_1') ; XVAR = W_FLUX%ERR_FREE_1 + CASE ('err_watr_1') ; XVAR = W_FLUX%ERR_WATR_1 + CASE ('err_tens_2') ; XVAR = W_FLUX%ERR_TENS_2 + CASE ('err_free_2') ; XVAR = W_FLUX%ERR_FREE_2 + CASE ('err_free_2a'); XVAR = W_FLUX%ERR_FREE_2A + CASE ('err_free_2b'); XVAR = W_FLUX%ERR_FREE_2B + CASE ('err_watr_2') ; XVAR = W_FLUX%ERR_WATR_2 + + ! time check + CASE ('chk_time') ; XVAR = W_FLUX%CHK_TIME + + ! extract model runoff + CASE ('q_instnt') ; XVAR = MROUTE%Q_INSTNT + CASE ('q_routed') ; XVAR = MROUTE%Q_ROUTED + + ! extract information on numerical solution (shared in MODULE model_numerix) + CASE ('num_funcs') ; XVAR = NUM_FUNCS + CASE ('numjacobian'); XVAR = NUM_JACOBIAN + CASE ('sub_accept') ; XVAR = NUMSUB_ACCEPT + CASE ('sub_reject') ; XVAR = NUMSUB_REJECT + CASE ('sub_noconv') ; XVAR = NUMSUB_NOCONV + CASE ('max_iterns') ; XVAR = MAXNUM_ITERNS + + ! default + case default; XVAR = NA_VALUE_SP + + END SELECT + + ! and, save the output + VAREXTRACT = XVAR + ! --------------------------------------------------------------------------------------- + END FUNCTION VAREXTRACT -! save the output -VAREXTRACT_3d = XVAR_3d -! --------------------------------------------------------------------------------------- -END FUNCTION VAREXTRACT_3d END MODULE VAREXTRACT_MODULE diff --git a/build/Makefile b/build/Makefile index 3310710..8b5fb2e 100755 --- a/build/Makefile +++ b/build/Makefile @@ -177,7 +177,9 @@ FUSE_TYPES += multistate_types.f90 FUSE_TYPES += multi_flux_types.f90 FUSE_TYPES += multiroute_types.f90 FUSE_TYPES += multistats_types.f90 -#FUSE_TYPES += data_types.f90 +FUSE_TYPES += work_types.f90 +FUSE_TYPES += info_types.f90 +FUSE_TYPES += data_types.f90 TYPES = $(patsubst %, $(TYPES_DIR)/%, $(FUSE_TYPES)) # combined type+data (mimic legacy code) @@ -230,7 +232,7 @@ NR_SUB = $(patsubst %, $(NUMREC_DIR)/%, $(FUSE_NR_SUB)) # FUSE physics (differentiable model) FUSE_PHYSICS = FUSE_PHYSICS += smoothers.f90 -FUSE_PHYSICS += get_parent.f90 +FUSE_PHYSICS += get_bundle.f90 FUSE_PHYSICS += update_swe_diff.f90 FUSE_PHYSICS += qsatexcess_diff.f90 FUSE_PHYSICS += evap_upper_diff.f90 @@ -342,7 +344,7 @@ FUSE_ALL += $(DATAMS) FUSE_ALL += $(UTILMS) FUSE_ALL += $(TIMUTILS) FUSE_ALL += $(NR_SUB) -#FUSE_ALL += $(PHYSICS) +FUSE_ALL += $(PHYSICS) FUSE_ALL += $(MODGUT) FUSE_ALL += $(SOLVER) FUSE_ALL += $(PRELIM) diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index ac6d752..40f3245 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-01-06T08:03:49Z' -character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/separate-data-types-from-storage' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'fa0612d2409778bdcf26825084d4f3ac2b51f873' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-17T23:37:32Z' +character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'wip/diffmod-foundation' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '98abe3c8134fda8632549c207fac60bd6b09be1e' From 7ae53258e9c118f5b41b8dc28cccb3c06919e2d6 Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Tue, 17 Feb 2026 22:50:48 -0700 Subject: [PATCH 05/11] Refactor: split fuse_evaluate into helpers (bit-for-bit) --- build/FUSE_SRC/driver/functn.f90 | 4 +- build/FUSE_SRC/driver/fuse_driver.f90 | 8 +- build/FUSE_SRC/driver/fuse_evaluate.f90 | 630 ++++++++++++++++++++++++ build/FUSE_SRC/driver/fuse_metric.f90 | 468 ------------------ build/Makefile | 2 +- build/generated/fuseversion.inc | 6 +- 6 files changed, 640 insertions(+), 478 deletions(-) create mode 100644 build/FUSE_SRC/driver/fuse_evaluate.f90 delete mode 100644 build/FUSE_SRC/driver/fuse_metric.f90 diff --git a/build/FUSE_SRC/driver/functn.f90 b/build/FUSE_SRC/driver/functn.f90 index fa5acf7..14be1ae 100644 --- a/build/FUSE_SRC/driver/functn.f90 +++ b/build/FUSE_SRC/driver/functn.f90 @@ -10,7 +10,7 @@ FUNCTION FUNCTN(NOPT,A) ! Wrapper for SCE (used to compute the objective function) ! --------------------------------------------------------------------------------------- USE nrtype ! variable types, etc. -USE fuse_metric_module ! run model and compute the metric chosen as objective function +USE fuse_evaluate_module, only: fuse_evaluate ! run model and compute the metric chosen as objective function USE multiforce, only: ncid_forc ! NetCDF forcing file ID USE fuse_fileManager,only:METRIC, TRANSFO ! metric and transformation requested in the filemanager USE globaldata, only: nFUSE_eval ! # fuse evaluations @@ -41,7 +41,7 @@ FUNCTION FUNCTN(NOPT,A) OUTPUT_FLAG=.FALSE. ! do not produce *runs.nc files only, param.nc files -CALL FUSE_METRIC(SCE_PAR,.FALSE.,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,1) ! 2nd argument FALSE, always return METRIC value +CALL FUSE_evaluate(SCE_PAR,.FALSE.,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,1) ! 2nd argument FALSE, always return METRIC value ! deallocate parameter set DEALLOCATE(SCE_PAR, STAT=IERR); IF (IERR.NE.0) STOP ' problem deallocating space ' diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index 6874735..58aa2c6 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -74,7 +74,7 @@ PROGRAM DISTRIBUTED_DRIVER USE model_numerix ! defines decisions on model numerix ! access to model simulation modules -USE fuse_metric_module ! run model and compute the metric chosen as objective function +USE fuse_evaluate_module, only: fuse_evaluate ! run model and compute the metric chosen as objective function #ifdef __MPI__ use mpi @@ -389,7 +389,7 @@ PROGRAM DISTRIBUTED_DRIVER OUTPUT_FLAG=.TRUE. print *, 'Running FUSE with default parameter values' - CALL FUSE_METRIC(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,NUMPSET) + CALL FUSE_evaluate(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,NUMPSET) print *, 'Done running FUSE with default parameter values' ELSE IF(fuse_mode == 'run_pre')THEN ! run FUSE with pre-defined parameter values @@ -403,7 +403,7 @@ PROGRAM DISTRIBUTED_DRIVER CALL GET_PRE_PARAM(FNAME_NETCDF_PARA_PRE,IPSET,ONEMOD,NUMPAR,APAR) print *, 'Running FUSE with pre-defined parameter set' - CALL FUSE_METRIC(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,1) ! last argument IPSET=1 + CALL FUSE_evaluate(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,1) ! last argument IPSET=1 print *, 'Done running FUSE with pre-defined parameter set' ELSE IF(fuse_mode == 'calib_sce')THEN ! calibrate FUSE using SCE @@ -459,7 +459,7 @@ PROGRAM DISTRIBUTED_DRIVER CALL GET_SCE_PARAM(FNAME_NETCDF_PARA_SCE,ONEMOD,NUMPAR,APAR) print *, 'Running FUSE with best SCE parameter set' - CALL FUSE_METRIC(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,NUMPSET) + CALL FUSE_evaluate(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,NUMPSET) print *, 'Done running FUSE with best SCE parameter set' ELSE diff --git a/build/FUSE_SRC/driver/fuse_evaluate.f90 b/build/FUSE_SRC/driver/fuse_evaluate.f90 new file mode 100644 index 0000000..bd0efb6 --- /dev/null +++ b/build/FUSE_SRC/driver/fuse_evaluate.f90 @@ -0,0 +1,630 @@ +MODULE fuse_evaluate_module + + use nrtype + use multi_flux_types, only: fluxes + use work_types, only: fuse_work + + IMPLICIT NONE + + ! temporary type: run context + type :: run_ctx + + ! scratch state vectors + real(sp), allocatable :: state0(:), state1(:) + + ! differentiable work struct + type(fuse_work) :: fuseStruct + + end type run_ctx + + CONTAINS + + SUBROUTINE fuse_evaluate(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPARAM_FLAG) + + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2009 + ! Modified by Brian Henn to include snow model, 6/2013 + ! Modified by Nans Addor to enable grid-based modeling, 9/2016 + ! Modified by Cyril Thébault to allow different metrics as objective function, 2024 + ! Modified by Martyn Clark to call differentiable modeling routines, 12/2025 + ! Modified by Martyn Clark to simplify/refactor, 02/2026 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Calculate the metric chosen as objective function for single FUSE model and single parameter set + ! input: model parameter set + ! output: metric chosen as objective function + ! --------------------------------------------------------------------------------------- + + use nrtype + use globaldata,only: NPAR_SNOW, isPrint, nFUSE_eval + use model_defn,only: NSTATE + use multiparam,only: NUMPAR + use multiforce,only: nspat1, nspat2, numtim_sub + use multibands,only: N_BANDS, n_bands + use multistats,only: MSTATS, PCOUNT + use multi_flux,only: W_FLUX_3d + + IMPLICIT NONE + + ! input + REAL(SP),DIMENSION(:),INTENT(IN) :: XPAR ! model parameter set + LOGICAL(LGT), INTENT(IN) :: GRID_FLAG ! .TRUE. if running FUSE on a grid + INTEGER(I4B), INTENT(IN) :: NCID_FORC ! NetCDF ID for the forcing file + LOGICAL(LGT), INTENT(IN) :: OUTPUT_FLAG ! .TRUE. if desire time series output + INTEGER(I4B), INTENT(IN) :: IPSET ! index parameter set + LOGICAL(LGT), INTENT(IN), OPTIONAL :: MPARAM_FLAG ! .FALSE. (used to turn off writing statistics) + + ! output + REAL(SP),INTENT(OUT) :: METRIC_VAL ! metric + + ! run context + type(run_ctx) :: ctx ! container for allocatable structures + + ! error control + integer(i4b) :: err, ierr + character(len=1024) :: message + + ! timing + real(sp) :: t1, t2 + + ! --------------------------------------------------------------------------------------- + ! allocate run-time data structures + call allocate_run(ctx, NSTATE, NUMPAR, N_BANDS, NPAR_SNOW, nspat1, nspat2, numtim_sub, ierr) + if (ierr /= 0) stop "problem allocating run context in fuse_evaluate" + + ! allocate 3d data structure for fluxes + allocate(w_flux_3d(nspat1, nspat2, numtim_sub), stat=ierr) + if (ierr /= 0) stop "problem allocating w_flux_3d in fuse_evaluate" + + ! populate parameter structures and initialize states + call initialize_run(ctx, XPAR, GRID_FLAG, MPARAM_FLAG, ierr, message) + if (ierr /= 0) stop trim(message) + + ! initialize timing + CALL CPU_TIME(T1) + + ! run fuse for the entire time series + call run_time_loop(ctx, GRID_FLAG, NCID_FORC, OUTPUT_FLAG, err, message) + if (err /= 0) stop trim(message) + + ! get timing information + CALL CPU_TIME(T2) + if(isPrint) WRITE(*,*) "TIME ELAPSED = ", t2-t1 + + ! calculate mean summary statistics + IF(.NOT.GRID_FLAG)THEN + + if(isPrint) PRINT *, 'Calculating performance metrics...' + CALL MEAN_STATS() + METRIC_VAL = MSTATS%METRIC_VAL + + write(*,'(i6,1x,a6,1x,f12.6,1x,a20,1x,f12.6)') nFUSE_eval, "NSE = ", MSTATS%NASH_SUTT, "; TIME ELAPSED = ", t2-t1 + !if(nFUSE_eval > 10) stop "checking results" + + ENDIF + + if(isPrint) PRINT *, 'Writing model statistics...' + CALL PUT_SSTATS(PCOUNT) + + ! deallocate run context + call deallocate_run(ctx, n_bands, ierr) + if (ierr /= 0) stop "problem deallocating run context in fuse_evaluate" + + ! deallocate output buffer + DEALLOCATE(W_FLUX_3d); IF (IERR.NE.0) STOP ' problem deallocating W_FLUX_3d in fuse_metric ' + + END SUBROUTINE fuse_evaluate + + ! ------------------------------------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + ! ------------------------------------------------------------------------------------------------------------------- + ! ----- private subroutine allocate_run: allocate run-time variables ------------------------------------------------ + ! ------------------------------------------------------------------------------------------------------------------- + + subroutine allocate_run(ctx, nState, numpar, n_bands, npar_snow, nspat1, nspat2, numtim_sub, ierr) + implicit none + + type(run_ctx), intent(inout) :: ctx + integer(i4b), intent(in) :: nState, numpar, n_bands, npar_snow, nspat1, nspat2, numtim_sub + integer(i4b), intent(out) :: ierr + + integer(i4b) :: iBands + + ierr = 0 + + ! allocate state vectors + allocate(ctx%state0(nState), ctx%state1(nState), stat=ierr) + if (ierr /= 0) return + + ! allocate flux derivative vectors (inside fuseStruct) + allocate(ctx%fuseStruct%df_dS(nState), ctx%fuseStruct%df_dPar(numpar), ctx%fuseStruct%dL_dPar(numpar), stat=ierr) + if (ierr /= 0) return + + ! allocate elevation bands + allocate(ctx%fuseStruct%sbands(n_bands), stat=ierr) + if (ierr /= 0) return + + ! allocate parameter derivative for each elevation band + do iBands = 1, n_bands + + allocate(ctx%fuseStruct%sbands(iBands)%var%dSWE_dParam(npar_snow), stat=ierr) + if (ierr /= 0) return + + ctx%fuseStruct%sbands(iBands)%var%dSWE_dParam(:) = 0._sp + + end do + + end subroutine allocate_run + + ! ------------------------------------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + ! ------------------------------------------------------------------------------------------------------------------- + ! ----- private subroutine deallocate_run: deallocate run-time variables -------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + subroutine deallocate_run(ctx, n_bands, ierr) + implicit none + + type(run_ctx), intent(inout) :: ctx + integer(i4b), intent(in) :: n_bands + integer(i4b), intent(out) :: ierr + integer(i4b) :: iBands + + ierr = 0 + + ! deallocate parameter derivative vectors + do iBands=1,n_bands + deallocate(ctx%fuseStruct%sbands(iBands)%var%dSWE_dParam, stat=ierr) + if (ierr /= 0) return + end do + + ! deallocate state vectors + DEALLOCATE(ctx%STATE0,ctx%STATE1,STAT=IERR) + if (ierr /= 0) return + + ! deallocate flux derivative vectors + deallocate(ctx%fuseStruct%df_dS, ctx%fuseStruct%df_dPar, ctx%fuseStruct%dL_dPar, stat=ierr) + if (ierr /= 0) return + + ! deallocate elevation bands + deallocate(ctx%fuseStruct%sbands, stat=ierr) + if (ierr /= 0) return + + end subroutine deallocate_run + + ! ------------------------------------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + ! ------------------------------------------------------------------------------------------------------------------- + ! ----- private subroutine initialize_run: populate param sets and initialize states ------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) + + use globaldata, only: isPrint, fracstate0 + use model_defn, only: SMODL + use model_defnames + + use multiparam, only: NUMPAR + use multiforce, only: nspat1, nspat2, DELTIM + use multistate, only: FSTATE, gState_3d + use multistats, only: PCOUNT + use multibands + + use par_insert_module + use str_2_xtry_module + use xtry_2_str_module + use put_params_module, only: put_params + implicit none + + type(run_ctx), intent(inout) :: ctx + real(sp), dimension(:), intent(in) :: xpar + logical(lgt), intent(in) :: grid_flag + logical(lgt), intent(in), optional :: mparam_flag + + integer(i4b), intent(out) :: err + character(len=*), intent(out) :: message + + integer(i4b) :: iSpat1, iSpat2, iBands + + err = 0 + message = "" + + ! increment parameter counter for model output + if (.not. present(mparam_flag)) then + PCOUNT = PCOUNT + 1 + else + if (mparam_flag) PCOUNT = PCOUNT + 1 + end if + + ! add parameter set to the data structure + call put_parset(xpar) + if (isPrint) then + print *, 'Parameter set added to data structure:' + print *, xpar + end if + + ! compute derived model parameters (bucket sizes, etc.) + call par_derive(err, message) + if (err /= 0) then + write(*,*) trim(message) + stop + end if + + ! get elevation bands (if catchment) + if (SMODL%iSNOWM == iopt_temp_index .and. .not. grid_flag) then + Z_FORCING = Z_FORCING_grid(1,1) + MBANDS(:)%info = MBANDS_INFO_3d(1,1,:) + end if + + if (isPrint) print *, 'Writing parameter values...' + call put_params(PCOUNT) + + ! initialize model states over the 2D gridded domain (1x1 in catchment mode) + do iSpat2 = 1, nSpat2 + do iSpat1 = 1, nSpat1 + call init_state(fracstate0) + call str_2_xtry(FSTATE, ctx%state0) + call xtry_2_str(ctx%state0, FSTATE) + gState_3d(iSpat1, iSpat2, 1) = FSTATE + end do + end do + if (isPrint) print *, 'Model states initialized over the 2D gridded domain' + + ! initialize elevation bands if snow module is on + if (isPrint) print *, 'N_BANDS =', N_BANDS + if (SMODL%iSNOWM == iopt_temp_index) then + + ! initialize template once + ctx%fuseStruct%sbands(:)%var%SWE = 0._sp + ctx%fuseStruct%sbands(:)%var%SNOWACCMLTN = 0._sp + ctx%fuseStruct%sbands(:)%var%SNOWMELT = 0._sp + ctx%fuseStruct%sbands(:)%var%DSWE_DT = 0._sp + + ! copy to every grid cell (legacy staging) + do iSpat2 = 1, nSpat2 + do iSpat1 = 1, nSpat1 + do iBands = 1, n_bands + MBANDS_VAR_4d(iSpat1, iSpat2, iBands, 1) = ctx%fuseStruct%sbands(iBands)%var%bands_var + end do + end do + end do + + if (isPrint) print *, 'Snow states initialized over the 2D gridded domain' + end if + + ! initialize summary statistics + timer + call init_stats() + + end subroutine initialize_run + + ! ------------------------------------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + ! ------------------------------------------------------------------------------------------------------------------- + ! ----- private subroutine run_time_loop: run fuse for the entire time series -------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, err, message) + + ! switches / options + use globaldata, only: isPrint, NA_VALUE_SP + use model_defn, only: SMODL, NSTATE + use model_defnames + use multiforce, only: & + nspat1, nspat2, DELTIM, & + sim_beg, sim_end, & + numtim_sub, numtim_sim, numtim_sub_cur, & + itim_in, itim_sim, itim_sub, & + gForce_3d, aForce, MFORCE + use multistate, only: gState_3d, FSTATE, MSTATE + use multiroute, only: MROUTE, AROUTE_3d + use multibands + use multi_flux, only: W_FLUX, W_FLUX_3d + + ! modules + use time_io, only: get_modtim + use get_gforce_module, only: get_gforce_3d + use getPETgrid_module, only: getPETgrid + use put_output_module, only: put_goutput_3d + use set_all_module, only: SET_STATE, SET_FLUXES, SET_ROUTE + + ! state vector conversions + use str_2_xtry_module + use xtry_2_str_module + + ! differentiable + use get_bundle_module, only: get_bundle + use implicit_solve_module, only: implicit_solve + use update_swe_diff_module, only: update_swe_diff ! confirm spelling matches your subroutine + + ! original solver interface + use interfaceb, only: ode_int, fuse_solve + + ! model numerix structures + USE model_numerix + USE fuse_deriv_module + USE fdjac_ode_module + + implicit none + + type(run_ctx), intent(inout) :: ctx + logical(lgt), intent(in) :: grid_flag + integer(i4b), intent(in) :: ncid_forc + logical(lgt), intent(in) :: output_flag + + integer(i4b), intent(out) :: err + character(len=*), intent(out):: message + + ! locals + logical(lgt), parameter :: computePET = .false. + real(sp) :: dt_sub, dt_full + integer(i4b) :: iSpat1, iSpat2, iBands + integer(i4b) :: ierr + character(len=1024) :: cmessage + + err = 0 + message = "" + cmessage = "" + ierr = 0 + + ! This version of FUSE enables the user to load slices of the forcing + ! + ! FUSE1 used to access the input file at each time step, slowing operations + ! down over large domains on systems with slow I/O. The number of timesteps + ! of the slices is defined by the user in the filemanager. The default is + ! that the whole time period needed for the simulation is loaded, but + ! this can exceed memory capacity when large domains are processed. + ! To overcome this, a subperiod (slice) of the forcing can be loaded in + ! memory and used to run FUSE. Then, the results are saved to the + ! output file, and the next slice of forcing is loaded. This enables FUSE to + ! run quicker than when forcing is loaded at each time step and grid point, + ! while also controlling memory usage. + + ! initialize model time step + dt_sub = DELTIM + dt_full = DELTIM + + ! initialise time indices for whole simulation and subperiod + itim_sub = 1 + itim_sim = 1 + + ! loop through time steps of the input file (ITIM_IN) + DO ITIM_IN=sim_beg,sim_end + + ! if start of subperiod: load forcing + IF(itim_sub.EQ.1)THEN + + ! determine length of current subperiod + numtim_sub_cur=MIN(numtim_sub,numtim_sim-itim_sim+1) + + ! load forcing for desired period into gForce_3d + if(isPrint) PRINT *, 'New subperiod: loading forcing for ',numtim_sub_cur,' time steps' + CALL get_gforce_3d(itim_in,numtim_sub_cur,ncid_forc,err,message) + IF(err/=0)THEN; WRITE(*,*) 'Error while extracting 3d forcing'; STOP; ENDIF + if(isPrint) PRINT *, 'Forcing loaded. Running FUSE...' + + ENDIF + + ! get the model time + CALL get_modtim(itim_in,ncid_forc,ierr,message) + IF(ierr/=0)THEN; PRINT*, TRIM(cmessage); STOP; ENDIF + !print*, timdat + + ! compute potential ET + IF(computePET) CALL getPETgrid(ierr,cmessage) + IF(ierr/=0)THEN; PRINT*, TRIM(cmessage); STOP; ENDIF + + ! loop through grid points and run the model for one time step + DO iSpat2=1,nSpat2 + DO iSpat1=1,nSpat1 + + ! only run FUSE for grid points within domain defined by elev_mask + IF(.NOT.elev_mask(iSpat1,iSpat2))THEN + + ! FUSE works with MFORCE, MSTATE, MBANDS, W_FLUX, MROUTE, which are all scalars. + ! Here we transfer forcing, state, flux variables from the 3D structures to these + ! variables, run FUSE and then transfer the new values back to the 3D structures. + + ! extract forcing for this grid cell and time step + MFORCE = gForce_3d(iSpat1,iSpat2,itim_sub) + + ! forcing sanity checks + if(MFORCE%PPT.lt.0.0) then; PRINT *, 'Negative precipitation in input file:',iSpat1,iSpat2,MFORCE%PPT; stop; endif + if(MFORCE%PPT.gt.5000.0) then; PRINT *, 'Precipitation greater than 5000 in input file:',iSpat1,iSpat2,MFORCE%PPT; stop; endif + if(MFORCE%PET.lt.0.0) then; PRINT *, 'Negative PET in input file'; stop; endif + if(MFORCE%PET.gt.100.0) then; PRINT *, 'PET greater than 100 in input file'; stop; endif + if(MFORCE%TEMP.lt.-100.0) then; PRINT *, 'Temperature lower than -100 in input file'; stop; endif + if(MFORCE%TEMP.gt.100.0) then; PRINT *, 'Temperature greater than 100 in input file'; stop; endif + + ! extract model states for this grid cell and time step + FSTATE = gState_3d(iSpat1,iSpat2,itim_sub) + MSTATE = FSTATE ! refresh model states + CALL STR_2_XTRY(FSTATE, ctx%STATE0) ! set state at the start of the time step (STATE0) using FSTATE + + ! initialize model fluxes + CALL INITFLUXES() ! set weighted sum of fluxes to zero + + ! populate fuse work structure + if(diff_mode==differentiable) call get_bundle(ctx%fuseStruct) + + ! if snow model is on, call UPDATE_SWE to calculate snow fluxes and update snow bands + ! using explicit Euler approach; if not, call QRAINERROR + SELECT CASE(SMODL%iSNOWM) + CASE(iopt_temp_index) + + ! load data from multidimensional arrays + Z_FORCING = Z_FORCING_grid(iSpat1,iSpat2) ! elevation of forcing data (m) + mbands(:)%info = MBANDS_INFO_3d(iSpat1,iSpat2,:) ! info structure + mbands(:)%var = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub) ! var structure + + ! put data into the FUSE structure + ! NOTE: only copy the "var" variables + if(diff_mode == differentiable)then + ctx%fuseStruct%z_forcing = Z_FORCING + ctx%fuseStruct%sbands(:)%info = MBANDS(:)%info + ctx%fuseStruct%sbands(:)%var%bands_var = MBANDS(:)%var + endif ! if diff_mode == differentiable + + ! run the snow model + select case(diff_mode) + case(original); CALL UPDATE_SWE(DELTIM) + case(differentiable); CALL UPDATE_SWE_DIFF(ctx%fuseStruct,DELTIM) + CASE DEFAULT; stop "fuse_metric: cannot identify diff_mode" + end select + + CASE(iopt_no_snowmod) + CALL QRAINERROR() + CASE DEFAULT + message="fuse_metric/SMODL%iSNOWM must be either iopt_temp_index or iopt_no_snowmod" + print*, trim(message); stop 1 + END SELECT + + ! ----- start of soil physics code ------------------------------------------------------------ + + ! temporally integrate the ordinary differential equations + select case(diff_mode) + + ! original code + case(original) + CALL ODE_INT(FUSE_SOLVE,ctx%STATE0,ctx%STATE1,DT_SUB,DT_FULL,IERR,MESSAGE) + IF (IERR.NE.0) THEN; PRINT *, TRIM(MESSAGE); STOP 1; ENDIF + + ! differentiable code + case(differentiable) + + ! solve differentiable ODEs + call implicit_solve(ctx%fuseStruct, ctx%state0, ctx%state1, nState, ierr, cmessage) + + ! save fluxes + W_FLUX = ctx%fuseStruct%flux + + ! check options + case default; print*, "fuse_metric: Cannot identify diff_mode"; stop 1 + end select + + !print*, ITIM_IN, w_flux%eff_ppt + !if(ITIM_IN > 100) stop "check" + + ! ----- end of soil physics code -------------------------------------------------------------- + + ! perform overland flow routing + CALL Q_OVERLAND() + + ! runoff sanity check + IF (MROUTE%Q_ROUTED.LT.0._sp) STOP 'Q_ROUTED is less than zero' + IF (MROUTE%Q_ROUTED.GT.1000._sp) STOP 'Q_ROUTED is enormous' + + ! transfer simulations to corresponding 3D structures + ! note that the first time step of gState_3d and MBANDS_VAR_4d is defined by initialisation + ! or simulation over previous subperiod, so saving in itim_sub+1 - and hence, the allocated + ! length of the temporal dimension of gState_3d and MBANDS_VAR_4d is numtim_sub+1, + ! but numtim_sub for W_FLUX_3d and AROUTE_3d + + CALL XTRY_2_STR(ctx%STATE1,FSTATE) ! update FSTATE using states at the end of the time step (STATE1) + gState_3d(iSpat1,iSpat2,itim_sub+1) = FSTATE ! transfer FSTATE into the 3-d structure + W_FLUX_3d(iSpat1,iSpat2,itim_sub) = W_FLUX ! fluxes + AROUTE_3d(iSpat1,iSpat2,itim_sub) = MROUTE ! instantaneous and routed runoff + + IF (SMODL%iSNOWM.EQ.iopt_temp_index) THEN + + ! extract data from the FUSE structure + if(diff_mode == differentiable)then + Z_FORCING = ctx%fuseStruct%z_forcing + MBANDS%info = ctx%fuseStruct%sbands%info + MBANDS%var = ctx%fuseStruct%sbands%var%bands_var + endif ! if diff_mode == differentiable + + ! SWE TOT: weighted average of SWE over all the elevation bands + gState_3d(iSpat1,iSpat2,itim_sub+1)%SWE_TOT = SUM(MBANDS(:)%var%SWE * MBANDS(:)%info%AF) + + ! update MBANDS_VAR_4D + MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1) = MBANDS(:)%var + + END IF + + ! save forcing data to export to output file + IF(GRID_FLAG)THEN + aForce(itim_sub)%ppt = SUM(gForce_3d(:,:,itim_sub)%ppt)/REAL(SIZE(gForce_3d(:,:,itim_sub)), KIND(sp)) + aForce(itim_sub)%pet = SUM(gForce_3d(:,:,itim_sub)%pet)/REAL(SIZE(gForce_3d(:,:,itim_sub)), KIND(sp)) + ENDIF + + ! compute summary statistics + CALL COMP_STATS() + + ELSE ! insert NA values if grid point outside of domain or forcing not available + + CALL SET_STATE(NA_VALUE_SP) ! includes FSTATE%SWE_TOT + gState_3d(iSpat1,iSpat2,itim_sub) = FSTATE + + CALL SET_FLUXES(NA_VALUE_SP) + W_FLUX_3d(iSpat1,iSpat2,itim_sub) = W_FLUX + + CALL SET_ROUTE(NA_VALUE_SP) + AROUTE_3d(iSpat1,iSpat2,itim_sub) = MROUTE + + ENDIF ! (is grid cell in mask_elev?) + END DO ! (looping thru 2nd spatial dimension) + END DO ! (looping thru 1st spatial dimension) + + ! if end of subperiod: write to output file and save states + IF(itim_sub.EQ.numtim_sub_cur)THEN + + if(isPrint) PRINT *, 'End of subperiod reached:' + + ! write model output + IF (OUTPUT_FLAG) THEN + if(isPrint) PRINT *, 'Write output for ',numtim_sub_cur,' time steps starting at indices', itim_sim-numtim_sub_cur+1 + CALL PUT_GOUTPUT_3D(itim_sim-numtim_sub_cur+1, itim_in-numtim_sub_cur+1, numtim_sub_cur) + if(isPrint) PRINT *, 'Done writing output' + ELSE + if(isPrint) PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' + END IF + + ! TODO: set gState_3d and MBANDS_VAR_4d to NA + + ! reinitialize states for next subperiod using last time step + gState_3d(:,:,1) = gState_3d(:,:,itim_sub+1) + MBANDS_VAR_4d(:,:,:,1) = MBANDS_VAR_4d(:,:,:,itim_sub+1) + + ! reset itim_sub + itim_sub=1 + + ELSE ! not the end of subperiod + + ! increment itim_sub + itim_sub=itim_sub+1 + + END IF + + ! increment itim_sim + itim_sim=itim_sim+1 + + END DO ! (loop through timesteps) + + end subroutine run_time_loop + + ! ------------------------------------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + ! ------------------------------------------------------------------------------------------------------------------- + ! ----- private subroutine + ! ------------------------------------------------------------------------------------------------------------------- + + + + + + + + + + + + +END MODULE fuse_evaluate_module diff --git a/build/FUSE_SRC/driver/fuse_metric.f90 b/build/FUSE_SRC/driver/fuse_metric.f90 deleted file mode 100644 index d7ec781..0000000 --- a/build/FUSE_SRC/driver/fuse_metric.f90 +++ /dev/null @@ -1,468 +0,0 @@ -MODULE FUSE_METRIC_MODULE - IMPLICIT NONE - CONTAINS - SUBROUTINE FUSE_METRIC(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPARAM_FLAG) - - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2009 - ! Modified by Brian Henn to include snow model, 6/2013 - ! Modified by Nans Addor to enable grid-based modeling, 9/2016 - ! Modified by Cyril Thébault to allow different metrics as objective function, 2024 - ! Modified by Martyn Clark to call differentiable modeling routines, 12/2025 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Calculate the metric chosen as objective function for single FUSE model and single parameter set - ! input: model parameter set - ! output: metric chosen as objective function - ! --------------------------------------------------------------------------------------- - - USE nrtype ! variable types, etc. - - ! data modules - USE globaldata, ONLY:NPAR_SNOW ! number of snow parameters - USE model_defn, ONLY:NSTATE,SMODL ! number of state variables - USE model_defnames ! integer model definitions - USE globaldata, ONLY: isPrint ! flag for printing progress to screen - USE globaldata, only: nFUSE_eval ! number of fuse evaluations - USE globaldata, ONLY: fracstate0 ! fraction of initial state (used for initialization) - USE globaldata, ONLY: NA_VALUE, NA_VALUE_SP ! NA_VALUE for the forcing - USE multiparam, ONLY: LPARAM,NUMPAR,MPARAM ! list of model parameters - USE multiforce, ONLY: MFORCE,AFORCE,DELTIM,ISTART ! model forcing data - USE multiforce, ONLY: numtim_in, itim_in ! length of input time series and associated index - USE multiforce, ONLY: numtim_sim, itim_sim ! length of simulated time series and associated index - USE multiforce, ONLY: numtim_sub, itim_sub ! length of subperiod time series and associated index - USE multiforce, ONLY: numtim_sub_cur ! length of current subperiod - USE multiforce, ONLY: sim_beg,sim_end ! timestep indices - USE multiforce, ONLY: eval_beg,eval_end ! timestep indices - USE multiforce, ONLY: timdat ! time structure - - USE multiforce, ONLY:nspat1,nspat2 ! spatial dimensions - USE multiforce, ONLY:ncid_var ! NetCDF ID for forcing variables - USE multiforce, ONLY:gForce,gForce_3d ! gridded forcing data - USE multistate, ONLY:TSTATE,MSTATE,FSTATE,HSTATE ! model state variables - USE multistate, ONLY:gState,gState_3d ! gridded state variables - USE multiroute, ONLY:MROUTE,AROUTE,AROUTE_3d ! routed runoff - USE multistats, ONLY:MSTATS,PCOUNT,MOD_IX ! access model statistics; counter for param set - USE multi_flux ! model fluxes - USE multibands ! NOTE: include N_BANDS ! elevation bands for snow modeling - USE set_all_module - - ! code modules - USE time_io, ONLY:get_modtim ! get model time for a given time step - USE get_gforce_module, ONLY: get_gforce_3d ! get gridded forcing data for a range of time steps - USE getPETgrid_module, ONLY: getPETgrid ! get gridded PET - USE put_params_module, ONLY: put_params ! write parameters - USE put_output_module, ONLY: put_goutput_3d ! write gridded output - !USE PAR_DERIVE_module, ONLY: PAR_DERIVE - USE par_insert_module ! insert parameters into data structures - USE str_2_xtry_module ! provide access to the routine str_2_xtry - USE xtry_2_str_module ! provide access to the routine xtry_2_str - - ! differentiable model - use work_types, only: fuse_work ! bundles "everything" required to run fuse for a single cell - use get_bundle_module, only: get_bundle ! populate the fuse_work data structure - use implicit_solve_module, only:implicit_solve ! simple implicit solve for differnetiable ODE - use update_swe_diff_module, only:update_swe_diff ! differentiable snow model - - ! interface blocks - USE interfaceb, ONLY:ode_int,fuse_solve ! provide access to FUSE_SOLVE through ODE_INT - - ! model numerix structures - USE model_numerix - USE fuse_deriv_module - USE fdjac_ode_module - IMPLICIT NONE - - ! input - REAL(SP),DIMENSION(:),INTENT(IN) :: XPAR ! model parameter set - LOGICAL(LGT), INTENT(IN) :: GRID_FLAG ! .TRUE. if running FUSE on a grid - INTEGER(I4B), INTENT(IN) :: NCID_FORC ! NetCDF ID for the forcing file - LOGICAL(LGT), INTENT(IN) :: OUTPUT_FLAG ! .TRUE. if desire time series output - INTEGER(I4B), INTENT(IN) :: IPSET ! index parameter set - LOGICAL(LGT), INTENT(IN), OPTIONAL :: MPARAM_FLAG ! .FALSE. (used to turn off writing statistics) - - ! output - REAL(SP),INTENT(OUT) :: METRIC_VAL ! metric - - ! internal - LOGICAL(lgt),PARAMETER :: computePET=.FALSE. ! flag to compute PET - REAL(SP) :: T1,T2 ! CPU time - INTEGER(I4B) :: iSpat1,iSpat2 ! loop through spatial dimensions - INTEGER(I4B) :: ibands ! loop through elevation bands - INTEGER(I4B) :: IPAR ! loop through model parameters - REAL(SP) :: DT_SUB ! length of sub-step - REAL(SP) :: DT_FULL ! length of time step - REAL(SP), DIMENSION(:), ALLOCATABLE :: STATE0 ! vector of model states at the start of the time step - REAL(SP), DIMENSION(:), ALLOCATABLE :: STATE1 ! vector of model states at the end of the time step - REAL(SP), DIMENSION(:,:), ALLOCATABLE :: J ! used to compute the Jacobian (just as a test) - REAL(SP), DIMENSION(:), ALLOCATABLE :: DSDT ! used to compute the ODE (just as a test) - INTEGER(I4B) :: ITEST,JTEST ! used to compute a grid of residuals - REAL(SP) :: TEST_A,TEST_B ! used to compute a grid of residuals - INTEGER(I4B) :: IERR ! error code - INTEGER(I4B), PARAMETER :: CLEN=1024 ! length of character string - INTEGER(I4B) :: ERR ! error code - CHARACTER(LEN=CLEN) :: MESSAGE ! error message - CHARACTER(LEN=CLEN) :: CMESSAGE ! error message of downwind routine - INTEGER(I4B),PARAMETER::UNT=6 !1701 ! 6 - - ! differentiable model - type(fuse_work) :: fuseStruct ! fuse work structure - - ! --------------------------------------------------------------------------------------- - ! allocate state vectors - ALLOCATE(STATE0(NSTATE),STATE1(NSTATE),STAT=IERR) - IF (IERR.NE.0) STOP ' problem allocating space for state vectors in fuse_metric' - - ! allocate flux derivative vectors - allocate(fuseStruct%df_dS(nState), fuseStruct%df_dPar(NUMPAR), fuseStruct%dL_dPar(NUMPAR), stat=ierr) - if(ierr/=0) STOP ' problem allocating space for the flux derivative vectors' - - ! allocate elevation bands (for the snow model) - allocate(fuseStruct%sbands(n_bands), stat=ierr) - if(ierr/=0) STOP ' problem allocating space for the elevation bands' - - ! allocate parameter derivative for each elevation band - do iBands=1,n_bands - allocate(fuseStruct%sbands(iBands)%var%dSWE_dParam(NPAR_SNOW), stat=ierr) - if(ierr/=0) STOP ' problem allocating space for the parameter derivatives' - fuseStruct%sbands(iBands)%var%dSWE_dparam(:) = 0._sp - end do - - ! increment parameter counter for model output - IF (.NOT.PRESENT(MPARAM_FLAG)) THEN - PCOUNT = PCOUNT + 1 - ELSE - IF (MPARAM_FLAG) PCOUNT = PCOUNT + 1 - ENDIF - - ! add parameter set to the data structure - CALL PUT_PARSET(XPAR) - if(isPrint) PRINT *, 'Parameter set added to data structure:' - if(isPrint) PRINT *, XPAR - - ! compute derived model parameters (bucket sizes, etc.) - CALL PAR_DERIVE(ERR,MESSAGE) - IF (ERR.NE.0) WRITE(*,*) TRIM(MESSAGE); IF (ERR.GT.0) STOP - - ! get elevation bands (if catchment) - if(SMODL%iSNOWM == iopt_temp_index .and. .not.GRID_FLAG)then - Z_FORCING = Z_FORCING_grid(1,1) ! elevation of forcing data (m) - MBANDS(:)%info = MBANDS_INFO_3d(1,1,:) ! info structure, %AF, %Z_MID - endif - - if(isPrint) PRINT *, 'Writing parameter values...' - CALL PUT_PARAMS(PCOUNT) - - ! initialize model states over the 2D gridded domain (1x1 domain in catchment mode) - DO iSpat2=1,nSpat2 - DO iSpat1=1,nSpat1 - CALL INIT_STATE(fracState0) ! define FSTATE using fracState0 - CALL STR_2_XTRY(FSTATE,STATE0) ! set state at the start of the time step (STATE0) using FSTATE - CALL XTRY_2_STR(STATE0,FSTATE) ! update structure, including derived state variables - gState_3d(iSpat1,iSpat2,1) = FSTATE ! put the state into first time step of 3D structure - END DO - END DO - if(isPrint) PRINT *, 'Model states initialized over the 2D gridded domain' - - ! initialize elevations bands if snow module is on - if(isPrint) PRINT *, 'N_BANDS =', N_BANDS - IF (SMODL%iSNOWM.EQ.iopt_temp_index) THEN - - ! initialize the per-band template once - ! (dSWE_dParam allocated & initialized earlier) - fuseStruct%sbands(:)%var%SWE = 0._sp ! band snowpack water equivalent (mm) - fuseStruct%sbands(:)%var%SNOWACCMLTN = 0._sp ! new snow accumulation in band (mm day-1) - fuseStruct%sbands(:)%var%SNOWMELT = 0._sp ! snowmelt in band (mm day-1) - fuseStruct%sbands(:)%var%DSWE_DT = 0._sp ! rate of change of band SWE (mm day-1) - - ! copy to every grid cell - ! NOTE: %bands_var only copies the var components (OK because MBANDS_VAR_4d is legacy structure) - DO iSpat2=1,nSpat2 - DO iSpat1=1,nSpat1 - do iBands=1,n_bands - MBANDS_VAR_4d(iSpat1,iSpat2,iBands,1) = fuseStruct%sbands(iBands)%var%bands_var - end do ! elevation bands - end do ! 1st spatial dimension - end do ! 2nd spatial dimension - - if(isPrint) PRINT *, 'Snow states initiatlized over the 2D gridded domain ' - - ENDIF ! if snow model is on - - ! allocate 3d data structure for fluxes - ALLOCATE(W_FLUX_3d(nspat1,nspat2,numtim_sub)) - - ! initialize model time step - DT_SUB = DELTIM ! init stepsize to full step - DT_FULL = DELTIM ! init stepsize to full step - - ! initialize summary statistics - CALL INIT_STATS() - CALL CPU_TIME(T1) - - ! This version of FUSE enables the user to load slices of the forcing - ! - ! FUSE1 used to access the input file at each time step, slowing operations - ! down over large domains on systems with slow I/O. The number of timesteps - ! of the slices is defined by the user in the filemanager. The default is - ! that the whole time period needed for the simulation is loaded, but - ! this can exceed memory capacity when large domains are processed. - ! To overcome this, a subperiod (slice) of the forcing can be loaded in - ! memory and used to run FUSE. Then, the results are saved to the - ! output file, and the next slice of forcing is loaded. This enables FUSE to - ! run quicker than when forcing is loaded at each time step and grid point, - ! while also controlling memory usage. - - ! initialise time indices for whole simulation and subperiod - itim_sub = 1 - itim_sim = 1 - - ! loop through time steps of the input file (ITIM_IN) - DO ITIM_IN=sim_beg,sim_end - - ! if start of subperiod: load forcing - IF(itim_sub.EQ.1)THEN - - ! determine length of current subperiod - numtim_sub_cur=MIN(numtim_sub,numtim_sim-itim_sim+1) - - ! load forcing for desired period into gForce_3d - if(isPrint) PRINT *, 'New subperiod: loading forcing for ',numtim_sub_cur,' time steps' - CALL get_gforce_3d(itim_in,numtim_sub_cur,ncid_forc,err,message) - IF(err/=0)THEN; WRITE(*,*) 'Error while extracting 3d forcing'; STOP; ENDIF - if(isPrint) PRINT *, 'Forcing loaded. Running FUSE...' - - ENDIF - - ! get the model time - CALL get_modtim(itim_in,ncid_forc,ierr,message) - IF(ierr/=0)THEN; PRINT*, TRIM(cmessage); STOP; ENDIF - !print*, timdat - - ! compute potential ET - IF(computePET) CALL getPETgrid(ierr,cmessage) - IF(ierr/=0)THEN; PRINT*, TRIM(cmessage); STOP; ENDIF - - ! loop through grid points and run the model for one time step - DO iSpat2=1,nSpat2 - DO iSpat1=1,nSpat1 - - ! only run FUSE for grid points within domain defined by elev_mask - IF(.NOT.elev_mask(iSpat1,iSpat2))THEN - - ! FUSE works with MFORCE, MSTATE, MBANDS, W_FLUX, MROUTE, which are all scalars. - ! Here we transfer forcing, state, flux variables from the 3D structures to these - ! variables, run FUSE and then transfer the new values back to the 3D structures. - - ! extract forcing for this grid cell and time step - MFORCE = gForce_3d(iSpat1,iSpat2,itim_sub) - - ! forcing sanity checks - if(MFORCE%PPT.lt.0.0) then; PRINT *, 'Negative precipitation in input file:',iSpat1,iSpat2,MFORCE%PPT; stop; endif - if(MFORCE%PPT.gt.5000.0) then; PRINT *, 'Precipitation greater than 5000 in input file:',iSpat1,iSpat2,MFORCE%PPT; stop; endif - if(MFORCE%PET.lt.0.0) then; PRINT *, 'Negative PET in input file'; stop; endif - if(MFORCE%PET.gt.100.0) then; PRINT *, 'PET greater than 100 in input file'; stop; endif - if(MFORCE%TEMP.lt.-100.0) then; PRINT *, 'Temperature lower than -100 in input file'; stop; endif - if(MFORCE%TEMP.gt.100.0) then; PRINT *, 'Temperature greater than 100 in input file'; stop; endif - - ! extract model states for this grid cell and time step - FSTATE = gState_3d(iSpat1,iSpat2,itim_sub) - MSTATE = FSTATE ! refresh model states - CALL STR_2_XTRY(FSTATE,STATE0) ! set state at the start of the time step (STATE0) using FSTATE - - ! initialize model fluxes - CALL INITFLUXES() ! set weighted sum of fluxes to zero - - ! populate fuse work structure - if(diff_mode==differentiable) call get_bundle(fuseStruct) - - ! if snow model is on, call UPDATE_SWE to calculate snow fluxes and update snow bands - ! using explicit Euler approach; if not, call QRAINERROR - SELECT CASE(SMODL%iSNOWM) - CASE(iopt_temp_index) - - ! load data from multidimensional arrays - Z_FORCING = Z_FORCING_grid(iSpat1,iSpat2) ! elevation of forcing data (m) - mbands(:)%info = MBANDS_INFO_3d(iSpat1,iSpat2,:) ! info structure - mbands(:)%var = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub) ! var structure - - ! put data into the FUSE structure - ! NOTE: only copy the "var" variables - if(diff_mode == differentiable)then - fuseStruct%z_forcing = Z_FORCING - fuseStruct%sbands(:)%info = MBANDS(:)%info - fuseStruct%sbands(:)%var%bands_var = MBANDS(:)%var - endif ! if diff_mode == differentiable - - ! run the snow model - select case(diff_mode) - case(original); CALL UPDATE_SWE(DELTIM) - case(differentiable); CALL UPDATE_SWE_DIFF(fuseStruct,DELTIM) - CASE DEFAULT; stop "fuse_metric: cannot identify diff_mode" - end select - - CASE(iopt_no_snowmod) - CALL QRAINERROR() - CASE DEFAULT - message="fuse_metric/SMODL%iSNOWM must be either iopt_temp_index or iopt_no_snowmod" - print*, trim(message); stop 1 - END SELECT - - ! ----- start of soil physics code ------------------------------------------------------------ - - ! temporally integrate the ordinary differential equations - select case(diff_mode) - - ! original code - case(original) - CALL ODE_INT(FUSE_SOLVE,STATE0,STATE1,DT_SUB,DT_FULL,IERR,MESSAGE) - IF (IERR.NE.0) THEN; PRINT *, TRIM(MESSAGE); STOP 1; ENDIF - - ! differentiable code - case(differentiable) - - ! solve differentiable ODEs - call implicit_solve(fuseStruct, state0, state1, nState, ierr, cmessage) - - ! save fluxes - W_FLUX = fuseStruct%flux - - ! check options - case default; print*, "fuse_metric: Cannot identify diff_mode"; stop 1 - end select - - !print*, ITIM_IN, w_flux%eff_ppt - !if(ITIM_IN > 100) stop "check" - - ! ----- end of soil physics code -------------------------------------------------------------- - - ! perform overland flow routing - CALL Q_OVERLAND() - - ! runoff sanity check - IF (MROUTE%Q_ROUTED.LT.0._sp) STOP 'Q_ROUTED is less than zero' - IF (MROUTE%Q_ROUTED.GT.1000._sp) STOP 'Q_ROUTED is enormous' - - ! transfer simulations to corresponding 3D structures - ! note that the first time step of gState_3d and MBANDS_VAR_4d is defined by initialisation - ! or simulation over previous subperiod, so saving in itim_sub+1 - and hence, the allocated - ! length of the temporal dimension of gState_3d and MBANDS_VAR_4d is numtim_sub+1, - ! but numtim_sub for W_FLUX_3d and AROUTE_3d - - CALL XTRY_2_STR(STATE1,FSTATE) ! update FSTATE using states at the end of the time step (STATE1) - gState_3d(iSpat1,iSpat2,itim_sub+1) = FSTATE ! transfer FSTATE into the 3-d structure - W_FLUX_3d(iSpat1,iSpat2,itim_sub) = W_FLUX ! fluxes - AROUTE_3d(iSpat1,iSpat2,itim_sub) = MROUTE ! instantaneous and routed runoff - - IF (SMODL%iSNOWM.EQ.iopt_temp_index) THEN - - ! extract data from the FUSE structure - if(diff_mode == differentiable)then - Z_FORCING = fuseStruct%z_forcing - MBANDS%info = fuseStruct%sbands%info - MBANDS%var = fuseStruct%sbands%var%bands_var - endif ! if diff_mode == differentiable - - ! SWE TOT: weighted average of SWE over all the elevation bands - gState_3d(iSpat1,iSpat2,itim_sub+1)%SWE_TOT = SUM(MBANDS(:)%var%SWE * MBANDS(:)%info%AF) - - ! update MBANDS_VAR_4D - MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1) = MBANDS(:)%var - - END IF - - ! save forcing data to export to output file - IF(GRID_FLAG)THEN - aForce(itim_sub)%ppt = SUM(gForce_3d(:,:,itim_sub)%ppt)/REAL(SIZE(gForce_3d(:,:,itim_sub)), KIND(sp)) - aForce(itim_sub)%pet = SUM(gForce_3d(:,:,itim_sub)%pet)/REAL(SIZE(gForce_3d(:,:,itim_sub)), KIND(sp)) - ENDIF - - ! compute summary statistics - CALL COMP_STATS() - - ELSE ! insert NA values if grid point outside of domain or forcing not available - - CALL SET_STATE(NA_VALUE_SP) ! includes FSTATE%SWE_TOT - gState_3d(iSpat1,iSpat2,itim_sub) = FSTATE - - CALL SET_FLUXES(NA_VALUE_SP) - W_FLUX_3d(iSpat1,iSpat2,itim_sub) = W_FLUX - - CALL SET_ROUTE(NA_VALUE_SP) - AROUTE_3d(iSpat1,iSpat2,itim_sub) = MROUTE - - ENDIF ! (is grid cell in mask_elev?) - END DO ! (looping thru 2nd spatial dimension) - END DO ! (looping thru 1st spatial dimension) - - ! if end of subperiod: write to output file and save states - IF(itim_sub.EQ.numtim_sub_cur)THEN - - if(isPrint) PRINT *, 'End of subperiod reached:' - - ! write model output - IF (OUTPUT_FLAG) THEN - if(isPrint) PRINT *, 'Write output for ',numtim_sub_cur,' time steps starting at indices', itim_sim-numtim_sub_cur+1 - CALL PUT_GOUTPUT_3D(itim_sim-numtim_sub_cur+1, itim_in-numtim_sub_cur+1, numtim_sub_cur) - if(isPrint) PRINT *, 'Done writing output' - ELSE - if(isPrint) PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' - END IF - - ! TODO: set gState_3d and MBANDS_VAR_4d to NA - - ! reinitialize states for next subperiod using last time step - gState_3d(:,:,1) = gState_3d(:,:,itim_sub+1) - MBANDS_VAR_4d(:,:,:,1) = MBANDS_VAR_4d(:,:,:,itim_sub+1) - - ! reset itim_sub - itim_sub=1 - - ELSE ! not the end of subperiod - - ! increment itim_sub - itim_sub=itim_sub+1 - - END IF - - ! increment itim_sim - itim_sim=itim_sim+1 - - END DO ! (loop through timesteps) - - ! get timing information - CALL CPU_TIME(T2) - if(isPrint) WRITE(*,*) "TIME ELAPSED = ", t2-t1 - - ! calculate mean summary statistics - IF(.NOT.GRID_FLAG)THEN - - if(isPrint) PRINT *, 'Calculating performance metrics...' - CALL MEAN_STATS() - METRIC_VAL = MSTATS%METRIC_VAL - - write(*,'(i6,1x,a6,1x,f12.6,1x,a20,1x,f12.6)') nFUSE_eval, "NSE = ", MSTATS%NASH_SUTT, "; TIME ELAPSED = ", t2-t1 - !if(nFUSE_eval > 10) stop "checking results" - - ENDIF - - if(isPrint) PRINT *, 'Writing model statistics...' - CALL PUT_SSTATS(PCOUNT) - - ! deallocate parameter derivative vectors - do iBands=1,n_bands - deallocate(fuseStruct%sbands(iBands)%var%dSWE_dParam, stat=ierr) - if(ierr/=0) STOP ' problem deallocating space for the parameter derivatives' - end do - - ! deallocate vectors - DEALLOCATE(W_FLUX_3d); IF (IERR.NE.0) STOP ' problem deallocating W_FLUX_3d in fuse_metric ' - DEALLOCATE(STATE0,STATE1,STAT=IERR); IF (IERR.NE.0) STOP ' problem deallocating state vectors in fuse_metric' - deallocate(fuseStruct%df_dS, fuseStruct%df_dPar, fuseStruct%dL_dPar, stat=ierr); if(ierr/=0) STOP ' problem deallocating space for the flux derivative vectors' - deallocate(fuseStruct%sbands, stat=ierr); if(ierr/=0) STOP ' problem deallocating space for the elevation bands' - - END SUBROUTINE FUSE_METRIC -END MODULE FUSE_METRIC_MODULE diff --git a/build/Makefile b/build/Makefile index 8b5fb2e..503c9fc 100755 --- a/build/Makefile +++ b/build/Makefile @@ -142,7 +142,7 @@ DRIVER_EX = fuse.exe FUSE_DRIVER = #FUSE_DRIVER += setup_domain.f90 #FUSE_DRIVER += setup_model_definition.f90 -FUSE_DRIVER += fuse_metric.f90 functn.f90 +FUSE_DRIVER += fuse_evaluate.f90 functn.f90 #FUSE_DRIVER += sce_driver.f90 FUSE_DRIVER += fuse_driver.f90 DRIVER = $(patsubst %, $(DRIVER_DIR)/%, $(FUSE_DRIVER)) diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index 40f3245..9320b78 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-17T23:37:32Z' -character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'wip/diffmod-foundation' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '98abe3c8134fda8632549c207fac60bd6b09be1e' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-18T05:46:57Z' +character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/fuse-evaluate' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'd5dab2e1a4b5c9eabbcc6a4b6a0d4fe1a7bd9c68' From b8f2947a48c6572ac6cd4d14a15a9adaedb1afbb Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Wed, 18 Feb 2026 16:06:06 -0700 Subject: [PATCH 06/11] update fuse_work structure --- build/FUSE_SRC/driver/fuse_driver.f90 | 6 +- build/FUSE_SRC/driver/fuse_evaluate.f90 | 555 +++++++++++--------- build/FUSE_SRC/netcdf/put_output.f90 | 2 +- build/FUSE_SRC/physics/conserve_clamp.f90 | 10 +- build/FUSE_SRC/physics/evap_lower_diff.f90 | 10 +- build/FUSE_SRC/physics/evap_upper_diff.f90 | 12 +- build/FUSE_SRC/physics/fix_ovshoot.f90 | 4 +- build/FUSE_SRC/physics/get_bundle.f90 | 21 +- build/FUSE_SRC/physics/implicit_solve.f90 | 6 +- build/FUSE_SRC/physics/mstate_rhs_diff.f90 | 13 +- build/FUSE_SRC/physics/q_baseflow_diff.f90 | 10 +- build/FUSE_SRC/physics/q_misscell_diff.f90 | 8 +- build/FUSE_SRC/physics/qinterflow_diff.f90 | 8 +- build/FUSE_SRC/physics/qpercolate_diff.f90 | 10 +- build/FUSE_SRC/physics/qsatexcess_diff.f90 | 10 +- build/FUSE_SRC/physics/update_swe_diff.f90 | 22 +- build/FUSE_SRC/runtime/get_time_indices.f90 | 17 +- build/FUSE_SRC/share/multiforce_data.f90 | 7 +- build/FUSE_SRC/types/work_types.f90 | 54 +- build/generated/fuseversion.inc | 4 +- 20 files changed, 427 insertions(+), 362 deletions(-) diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index 58aa2c6..61299ca 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -36,9 +36,9 @@ PROGRAM DISTRIBUTED_DRIVER USE multiforce, only: DELTIM USE multiforce, only: ISTART ! index for start of inference USE multiforce, ONLY: timeUnits,time_steps,julian_day_input ! time data -USE multiforce, only: numtim_in, itim_in ! length of input time series and associated index -USE multiforce, only: numtim_sim, itim_sim ! length of simulated time series and associated index -USE multiforce, only: numtim_sub, itim_sub ! length of subperiod time series and associated index +USE multiforce, only: numtim_in ! length of input time series +USE multiforce, only: numtim_sim ! length of simulated time series +USE multiforce, only: numtim_sub ! length of subperiod time series USE multiforce, only: sim_beg,sim_end ! timestep indices USE multiforce, only: eval_beg,eval_end ! timestep indices USE multiforce, only: SUB_PERIODS_FLAG ! .true. if subperiods are used to run FUSE diff --git a/build/FUSE_SRC/driver/fuse_evaluate.f90 b/build/FUSE_SRC/driver/fuse_evaluate.f90 index bd0efb6..2fa091c 100644 --- a/build/FUSE_SRC/driver/fuse_evaluate.f90 +++ b/build/FUSE_SRC/driver/fuse_evaluate.f90 @@ -64,11 +64,11 @@ SUBROUTINE fuse_evaluate(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,M type(run_ctx) :: ctx ! container for allocatable structures ! error control - integer(i4b) :: err, ierr - character(len=1024) :: message + integer(i4b) :: err, ierr + character(len=1024) :: message ! timing - real(sp) :: t1, t2 + real(sp) :: t1, t2 ! --------------------------------------------------------------------------------------- ! allocate run-time data structures @@ -141,20 +141,20 @@ subroutine allocate_run(ctx, nState, numpar, n_bands, npar_snow, nspat1, nspat2, if (ierr /= 0) return ! allocate flux derivative vectors (inside fuseStruct) - allocate(ctx%fuseStruct%df_dS(nState), ctx%fuseStruct%df_dPar(numpar), ctx%fuseStruct%dL_dPar(numpar), stat=ierr) + allocate(ctx%fuseStruct%adj%df_dS(nState), ctx%fuseStruct%adj%df_dPar(numpar), ctx%fuseStruct%adj%dL_dPar(numpar), stat=ierr) if (ierr /= 0) return ! allocate elevation bands - allocate(ctx%fuseStruct%sbands(n_bands), stat=ierr) + allocate(ctx%fuseStruct%snow%sbands(n_bands), stat=ierr) if (ierr /= 0) return ! allocate parameter derivative for each elevation band do iBands = 1, n_bands - allocate(ctx%fuseStruct%sbands(iBands)%var%dSWE_dParam(npar_snow), stat=ierr) + allocate(ctx%fuseStruct%snow%sbands(iBands)%var%dSWE_dParam(npar_snow), stat=ierr) if (ierr /= 0) return - ctx%fuseStruct%sbands(iBands)%var%dSWE_dParam(:) = 0._sp + ctx%fuseStruct%snow%sbands(iBands)%var%dSWE_dParam(:) = 0._sp end do @@ -179,7 +179,7 @@ subroutine deallocate_run(ctx, n_bands, ierr) ! deallocate parameter derivative vectors do iBands=1,n_bands - deallocate(ctx%fuseStruct%sbands(iBands)%var%dSWE_dParam, stat=ierr) + deallocate(ctx%fuseStruct%snow%sbands(iBands)%var%dSWE_dParam, stat=ierr) if (ierr /= 0) return end do @@ -188,11 +188,11 @@ subroutine deallocate_run(ctx, n_bands, ierr) if (ierr /= 0) return ! deallocate flux derivative vectors - deallocate(ctx%fuseStruct%df_dS, ctx%fuseStruct%df_dPar, ctx%fuseStruct%dL_dPar, stat=ierr) + deallocate(ctx%fuseStruct%adj%df_dS, ctx%fuseStruct%adj%df_dPar, ctx%fuseStruct%adj%dL_dPar, stat=ierr) if (ierr /= 0) return ! deallocate elevation bands - deallocate(ctx%fuseStruct%sbands, stat=ierr) + deallocate(ctx%fuseStruct%snow%sbands, stat=ierr) if (ierr /= 0) return end subroutine deallocate_run @@ -281,16 +281,16 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) if (SMODL%iSNOWM == iopt_temp_index) then ! initialize template once - ctx%fuseStruct%sbands(:)%var%SWE = 0._sp - ctx%fuseStruct%sbands(:)%var%SNOWACCMLTN = 0._sp - ctx%fuseStruct%sbands(:)%var%SNOWMELT = 0._sp - ctx%fuseStruct%sbands(:)%var%DSWE_DT = 0._sp + ctx%fuseStruct%snow%sbands(:)%var%SWE = 0._sp + ctx%fuseStruct%snow%sbands(:)%var%SNOWACCMLTN = 0._sp + ctx%fuseStruct%snow%sbands(:)%var%SNOWMELT = 0._sp + ctx%fuseStruct%snow%sbands(:)%var%DSWE_DT = 0._sp ! copy to every grid cell (legacy staging) do iSpat2 = 1, nSpat2 do iSpat1 = 1, nSpat1 do iBands = 1, n_bands - MBANDS_VAR_4d(iSpat1, iSpat2, iBands, 1) = ctx%fuseStruct%sbands(iBands)%var%bands_var + MBANDS_VAR_4d(iSpat1, iSpat2, iBands, 1) = ctx%fuseStruct%snow%sbands(iBands)%var%bands_var end do end do end do @@ -310,46 +310,16 @@ end subroutine initialize_run ! ----- private subroutine run_time_loop: run fuse for the entire time series -------------------------------------- ! ------------------------------------------------------------------------------------------------------------------- - subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, err, message) + subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) - ! switches / options - use globaldata, only: isPrint, NA_VALUE_SP - use model_defn, only: SMODL, NSTATE - use model_defnames - use multiforce, only: & - nspat1, nspat2, DELTIM, & - sim_beg, sim_end, & - numtim_sub, numtim_sim, numtim_sub_cur, & - itim_in, itim_sim, itim_sub, & - gForce_3d, aForce, MFORCE - use multistate, only: gState_3d, FSTATE, MSTATE - use multiroute, only: MROUTE, AROUTE_3d - use multibands - use multi_flux, only: W_FLUX, W_FLUX_3d - - ! modules + use globaldata, only: isPrint + use multiforce, only: nspat1, nspat2, DELTIM, sim_beg, sim_end, numtim_sub + use multistate, only: gState_3d + use multibands, only: MBANDS_VAR_4d use time_io, only: get_modtim - use get_gforce_module, only: get_gforce_3d use getPETgrid_module, only: getPETgrid + use get_gforce_module, only: get_gforce_3d use put_output_module, only: put_goutput_3d - use set_all_module, only: SET_STATE, SET_FLUXES, SET_ROUTE - - ! state vector conversions - use str_2_xtry_module - use xtry_2_str_module - - ! differentiable - use get_bundle_module, only: get_bundle - use implicit_solve_module, only: implicit_solve - use update_swe_diff_module, only: update_swe_diff ! confirm spelling matches your subroutine - - ! original solver interface - use interfaceb, only: ode_int, fuse_solve - - ! model numerix structures - USE model_numerix - USE fuse_deriv_module - USE fdjac_ode_module implicit none @@ -358,20 +328,25 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, err, message) integer(i4b), intent(in) :: ncid_forc logical(lgt), intent(in) :: output_flag - integer(i4b), intent(out) :: err + integer(i4b), intent(out) :: ierr character(len=*), intent(out):: message + ! time management + integer(i4b) :: sim_idx ! index of simulation: 1..numtim_sim + integer(i4b) :: sub_idx ! index of forcing slice: 1..chunk_len + integer(i4b) :: in_idx ! index of input NetCDF time axis: sim_beg..sim_end + integer(i4b) :: remaining ! # remaining data windows in simulation + integer(i4b) :: chunk_len ! # data windows in the sub-period + integer(i4b) :: chunk_start_in ! start-of-chunk index in the input file + integer(i4b) :: chunk_start_sim ! start-of-chunk index in the simulation + ! locals logical(lgt), parameter :: computePET = .false. real(sp) :: dt_sub, dt_full integer(i4b) :: iSpat1, iSpat2, iBands - integer(i4b) :: ierr - character(len=1024) :: cmessage - err = 0 - message = "" - cmessage = "" ierr = 0 + message = "" ! This version of FUSE enables the user to load slices of the forcing ! @@ -380,6 +355,7 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, err, message) ! of the slices is defined by the user in the filemanager. The default is ! that the whole time period needed for the simulation is loaded, but ! this can exceed memory capacity when large domains are processed. + ! To overcome this, a subperiod (slice) of the forcing can be loaded in ! memory and used to run FUSE. Then, the results are saved to the ! output file, and the next slice of forcing is loaded. This enables FUSE to @@ -391,219 +367,91 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, err, message) dt_full = DELTIM ! initialise time indices for whole simulation and subperiod - itim_sub = 1 - itim_sim = 1 - - ! loop through time steps of the input file (ITIM_IN) - DO ITIM_IN=sim_beg,sim_end - - ! if start of subperiod: load forcing - IF(itim_sub.EQ.1)THEN - - ! determine length of current subperiod - numtim_sub_cur=MIN(numtim_sub,numtim_sim-itim_sim+1) - - ! load forcing for desired period into gForce_3d - if(isPrint) PRINT *, 'New subperiod: loading forcing for ',numtim_sub_cur,' time steps' - CALL get_gforce_3d(itim_in,numtim_sub_cur,ncid_forc,err,message) - IF(err/=0)THEN; WRITE(*,*) 'Error while extracting 3d forcing'; STOP; ENDIF - if(isPrint) PRINT *, 'Forcing loaded. Running FUSE...' - - ENDIF - - ! get the model time - CALL get_modtim(itim_in,ncid_forc,ierr,message) - IF(ierr/=0)THEN; PRINT*, TRIM(cmessage); STOP; ENDIF - !print*, timdat - - ! compute potential ET - IF(computePET) CALL getPETgrid(ierr,cmessage) - IF(ierr/=0)THEN; PRINT*, TRIM(cmessage); STOP; ENDIF - - ! loop through grid points and run the model for one time step - DO iSpat2=1,nSpat2 - DO iSpat1=1,nSpat1 - - ! only run FUSE for grid points within domain defined by elev_mask - IF(.NOT.elev_mask(iSpat1,iSpat2))THEN - - ! FUSE works with MFORCE, MSTATE, MBANDS, W_FLUX, MROUTE, which are all scalars. - ! Here we transfer forcing, state, flux variables from the 3D structures to these - ! variables, run FUSE and then transfer the new values back to the 3D structures. - - ! extract forcing for this grid cell and time step - MFORCE = gForce_3d(iSpat1,iSpat2,itim_sub) - - ! forcing sanity checks - if(MFORCE%PPT.lt.0.0) then; PRINT *, 'Negative precipitation in input file:',iSpat1,iSpat2,MFORCE%PPT; stop; endif - if(MFORCE%PPT.gt.5000.0) then; PRINT *, 'Precipitation greater than 5000 in input file:',iSpat1,iSpat2,MFORCE%PPT; stop; endif - if(MFORCE%PET.lt.0.0) then; PRINT *, 'Negative PET in input file'; stop; endif - if(MFORCE%PET.gt.100.0) then; PRINT *, 'PET greater than 100 in input file'; stop; endif - if(MFORCE%TEMP.lt.-100.0) then; PRINT *, 'Temperature lower than -100 in input file'; stop; endif - if(MFORCE%TEMP.gt.100.0) then; PRINT *, 'Temperature greater than 100 in input file'; stop; endif - - ! extract model states for this grid cell and time step - FSTATE = gState_3d(iSpat1,iSpat2,itim_sub) - MSTATE = FSTATE ! refresh model states - CALL STR_2_XTRY(FSTATE, ctx%STATE0) ! set state at the start of the time step (STATE0) using FSTATE - - ! initialize model fluxes - CALL INITFLUXES() ! set weighted sum of fluxes to zero - - ! populate fuse work structure - if(diff_mode==differentiable) call get_bundle(ctx%fuseStruct) - - ! if snow model is on, call UPDATE_SWE to calculate snow fluxes and update snow bands - ! using explicit Euler approach; if not, call QRAINERROR - SELECT CASE(SMODL%iSNOWM) - CASE(iopt_temp_index) - - ! load data from multidimensional arrays - Z_FORCING = Z_FORCING_grid(iSpat1,iSpat2) ! elevation of forcing data (m) - mbands(:)%info = MBANDS_INFO_3d(iSpat1,iSpat2,:) ! info structure - mbands(:)%var = MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub) ! var structure - - ! put data into the FUSE structure - ! NOTE: only copy the "var" variables - if(diff_mode == differentiable)then - ctx%fuseStruct%z_forcing = Z_FORCING - ctx%fuseStruct%sbands(:)%info = MBANDS(:)%info - ctx%fuseStruct%sbands(:)%var%bands_var = MBANDS(:)%var - endif ! if diff_mode == differentiable - - ! run the snow model - select case(diff_mode) - case(original); CALL UPDATE_SWE(DELTIM) - case(differentiable); CALL UPDATE_SWE_DIFF(ctx%fuseStruct,DELTIM) - CASE DEFAULT; stop "fuse_metric: cannot identify diff_mode" - end select - - CASE(iopt_no_snowmod) - CALL QRAINERROR() - CASE DEFAULT - message="fuse_metric/SMODL%iSNOWM must be either iopt_temp_index or iopt_no_snowmod" - print*, trim(message); stop 1 - END SELECT - - ! ----- start of soil physics code ------------------------------------------------------------ - - ! temporally integrate the ordinary differential equations - select case(diff_mode) - - ! original code - case(original) - CALL ODE_INT(FUSE_SOLVE,ctx%STATE0,ctx%STATE1,DT_SUB,DT_FULL,IERR,MESSAGE) - IF (IERR.NE.0) THEN; PRINT *, TRIM(MESSAGE); STOP 1; ENDIF - - ! differentiable code - case(differentiable) - - ! solve differentiable ODEs - call implicit_solve(ctx%fuseStruct, ctx%state0, ctx%state1, nState, ierr, cmessage) - - ! save fluxes - W_FLUX = ctx%fuseStruct%flux - - ! check options - case default; print*, "fuse_metric: Cannot identify diff_mode"; stop 1 - end select - - !print*, ITIM_IN, w_flux%eff_ppt - !if(ITIM_IN > 100) stop "check" - - ! ----- end of soil physics code -------------------------------------------------------------- - - ! perform overland flow routing - CALL Q_OVERLAND() + sub_idx = 1 ! index in data subset - ! runoff sanity check - IF (MROUTE%Q_ROUTED.LT.0._sp) STOP 'Q_ROUTED is less than zero' - IF (MROUTE%Q_ROUTED.GT.1000._sp) STOP 'Q_ROUTED is enormous' + ! ----- loop through chunks of data --------------------------------------------------------------------------------- - ! transfer simulations to corresponding 3D structures - ! note that the first time step of gState_3d and MBANDS_VAR_4d is defined by initialisation - ! or simulation over previous subperiod, so saving in itim_sub+1 - and hence, the allocated - ! length of the temporal dimension of gState_3d and MBANDS_VAR_4d is numtim_sub+1, - ! but numtim_sub for W_FLUX_3d and AROUTE_3d + in_idx = sim_beg + do while (in_idx <= sim_end) - CALL XTRY_2_STR(ctx%STATE1,FSTATE) ! update FSTATE using states at the end of the time step (STATE1) - gState_3d(iSpat1,iSpat2,itim_sub+1) = FSTATE ! transfer FSTATE into the 3-d structure - W_FLUX_3d(iSpat1,iSpat2,itim_sub) = W_FLUX ! fluxes - AROUTE_3d(iSpat1,iSpat2,itim_sub) = MROUTE ! instantaneous and routed runoff + ! get the simulation index + sim_idx = in_idx - sim_beg + 1 - IF (SMODL%iSNOWM.EQ.iopt_temp_index) THEN + ! ----------------------------------------------------------------------------------------------------------------- + ! ----- start of subperiod: load forcing -------------------------------------------------------------------------- - ! extract data from the FUSE structure - if(diff_mode == differentiable)then - Z_FORCING = ctx%fuseStruct%z_forcing - MBANDS%info = ctx%fuseStruct%sbands%info - MBANDS%var = ctx%fuseStruct%sbands%var%bands_var - endif ! if diff_mode == differentiable + ! determine length of current subperiod + remaining = sim_end - in_idx + 1 ! # remaining data windows in simulation + chunk_len = min(numtim_sub, remaining) ! # data windows in the sub-period + + ! save the start of the chunks (avoid arithmetic) + chunk_start_sim = in_idx - sim_beg + 1 ! start of chunk in simulation index space + chunk_start_in = in_idx ! start of chunk in input index space - ! SWE TOT: weighted average of SWE over all the elevation bands - gState_3d(iSpat1,iSpat2,itim_sub+1)%SWE_TOT = SUM(MBANDS(:)%var%SWE * MBANDS(:)%info%AF) - - ! update MBANDS_VAR_4D - MBANDS_VAR_4d(iSpat1,iSpat2,:,itim_sub+1) = MBANDS(:)%var - - END IF - - ! save forcing data to export to output file - IF(GRID_FLAG)THEN - aForce(itim_sub)%ppt = SUM(gForce_3d(:,:,itim_sub)%ppt)/REAL(SIZE(gForce_3d(:,:,itim_sub)), KIND(sp)) - aForce(itim_sub)%pet = SUM(gForce_3d(:,:,itim_sub)%pet)/REAL(SIZE(gForce_3d(:,:,itim_sub)), KIND(sp)) - ENDIF - - ! compute summary statistics - CALL COMP_STATS() - - ELSE ! insert NA values if grid point outside of domain or forcing not available - - CALL SET_STATE(NA_VALUE_SP) ! includes FSTATE%SWE_TOT - gState_3d(iSpat1,iSpat2,itim_sub) = FSTATE - - CALL SET_FLUXES(NA_VALUE_SP) - W_FLUX_3d(iSpat1,iSpat2,itim_sub) = W_FLUX - - CALL SET_ROUTE(NA_VALUE_SP) - AROUTE_3d(iSpat1,iSpat2,itim_sub) = MROUTE - - ENDIF ! (is grid cell in mask_elev?) - END DO ! (looping thru 2nd spatial dimension) - END DO ! (looping thru 1st spatial dimension) - - ! if end of subperiod: write to output file and save states - IF(itim_sub.EQ.numtim_sub_cur)THEN - - if(isPrint) PRINT *, 'End of subperiod reached:' - - ! write model output - IF (OUTPUT_FLAG) THEN - if(isPrint) PRINT *, 'Write output for ',numtim_sub_cur,' time steps starting at indices', itim_sim-numtim_sub_cur+1 - CALL PUT_GOUTPUT_3D(itim_sim-numtim_sub_cur+1, itim_in-numtim_sub_cur+1, numtim_sub_cur) - if(isPrint) PRINT *, 'Done writing output' - ELSE - if(isPrint) PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' - END IF - - ! TODO: set gState_3d and MBANDS_VAR_4d to NA - - ! reinitialize states for next subperiod using last time step - gState_3d(:,:,1) = gState_3d(:,:,itim_sub+1) - MBANDS_VAR_4d(:,:,:,1) = MBANDS_VAR_4d(:,:,:,itim_sub+1) + ! load forcing for desired period into gForce_3d + if(isPrint) PRINT *, 'New subperiod: loading forcing for ',chunk_len,' time steps' + CALL get_gforce_3d(chunk_start_in,chunk_len,ncid_forc,ierr,message) + IF(ierr/=0) stop 'Error while extracting 3d forcing: '//trim(message) + if(isPrint) PRINT *, 'Forcing loaded. Running FUSE...' + + ! ----------------------------------------------------------------------------------------------------------------- + + ! ----------------------------------------------------------------------------------------------------------------- + ! ----- loop through data chunk (sub-period) ---------------------------------------------------------------------- + + do sub_idx = 1, chunk_len + + ! get indices in the input file (in_idx) and the simulation period (sim_idx) + in_idx = chunk_start_in + sub_idx - 1 + sim_idx = chunk_start_sim + sub_idx - 1 + + ! get the model time + CALL get_modtim(in_idx,ncid_forc,ierr,message) + IF(ierr/=0) stop TRIM(message) + + ! compute potential ET + IF(computePET) CALL getPETgrid(ierr,message) + IF(ierr/=0) stop TRIM(message) + + ! loop through grid points and run the model for one time step + DO iSpat2=1,nSpat2 + DO iSpat1=1,nSpat1 + + ! run fuse for one grid cell + call advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_full, ierr, message) + if (ierr /= 0) stop trim(message) + + END DO ! (looping thru 2nd spatial dimension) + END DO ! (looping thru 1st spatial dimension) + + end do ! looping through subperiod + + ! ----------------------------------------------------------------------------------------------------------------- + + ! ----------------------------------------------------------------------------------------------------------------- + ! ----- end of subperiod: write to output file and save states ---------------------------------------------------- + + if(isPrint) PRINT *, 'End of subperiod reached:' + + ! write model output + IF (OUTPUT_FLAG) THEN + if(isPrint) PRINT *, 'Write output for ',chunk_len,' time steps starting at indices', chunk_start_sim + CALL PUT_GOUTPUT_3D(chunk_start_sim, chunk_start_in, chunk_len) + if(isPrint) PRINT *, 'Done writing output' + ELSE + if(isPrint) PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' + END IF - ! reset itim_sub - itim_sub=1 + ! TODO: set gState_3d and MBANDS_VAR_4d to NA - ELSE ! not the end of subperiod + ! reinitialize states for next subperiod using last time step + gState_3d(:,:,1) = gState_3d(:,:,chunk_len+1) + MBANDS_VAR_4d(:,:,:,1) = MBANDS_VAR_4d(:,:,:,chunk_len+1) - ! increment itim_sub - itim_sub=itim_sub+1 + ! ----------------------------------------------------------------------------------------------------------------- - END IF - - ! increment itim_sim - itim_sim=itim_sim+1 + ! update the index in the input file + in_idx = chunk_start_in + chunk_len END DO ! (loop through timesteps) @@ -613,18 +461,203 @@ end subroutine run_time_loop ! ------------------------------------------------------------------------------------------------------------------- ! ------------------------------------------------------------------------------------------------------------------- - ! ----- private subroutine + ! ----- private subroutine advance_one_cell: run fuse for one grid cell --------------------------------------------- ! ------------------------------------------------------------------------------------------------------------------- + subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_full, err, message) + ! switches / options + use globaldata, only: NA_VALUE_SP + use model_defn, only: SMODL, NSTATE + use model_defnames + use multiforce, only: DELTIM, gForce_3d, aForce, MFORCE, nspat1, nspat2 + use multistate, only: gState_3d, FSTATE, MSTATE + use multiroute, only: MROUTE, AROUTE_3d + use multibands + use multi_flux, only: W_FLUX, W_FLUX_3d + use set_all_module, only: SET_STATE, SET_FLUXES, SET_ROUTE + ! state vector conversions + use str_2_xtry_module + use xtry_2_str_module + + ! differentiable + use get_bundle_module, only: get_bundle + use implicit_solve_module, only: implicit_solve + use update_swe_diff_module, only: update_swe_diff ! (only if you actually call it here) + use update_swe_diff_module, only: update_swe_diff ! ok to remove if unused + ! original solver interface + use interfaceb, only: ode_int, fuse_solve + + ! diff-mode flags (make sure these names really live here in your tree) + use model_numerix, only: diff_mode, original, differentiable + + implicit none + + type(run_ctx), intent(inout) :: ctx + logical(lgt), intent(in) :: grid_flag + integer(i4b), intent(in) :: sub_idx, iSpat1, iSpat2 + real(sp), intent(inout) :: dt_sub, dt_full + integer(i4b), intent(out) :: err + character(len=*), intent(out):: message + ! locals + integer(i4b) :: ierr + character(len=1024) :: cmessage + err = 0 + message = "" + ierr = 0 + cmessage = "" + ! --------------------------------------------------------------------------- + ! only run FUSE for grid points within domain defined by elev_mask + ! NOTE: you currently run when elev_mask is FALSE (keep as-is for BFB) + ! --------------------------------------------------------------------------- + if (.not. elev_mask(iSpat1,iSpat2)) then + + ! extract forcing for this grid cell and time step + MFORCE = gForce_3d(iSpat1,iSpat2,sub_idx) + + ! forcing sanity checks (keep behavior; convert STOP -> error return) + if (MFORCE%PPT < 0.0_sp) then + err=1; message='Negative precipitation in input file'; return + end if + if (MFORCE%PPT > 5000.0_sp) then + err=1; message='Precipitation greater than 5000 in input file'; return + end if + if (MFORCE%PET < 0.0_sp) then + err=1; message='Negative PET in input file'; return + end if + if (MFORCE%PET > 100.0_sp) then + err=1; message='PET greater than 100 in input file'; return + end if + if (MFORCE%TEMP < -100.0_sp) then + err=1; message='Temperature lower than -100 in input file'; return + end if + if (MFORCE%TEMP > 100.0_sp) then + err=1; message='Temperature greater than 100 in input file'; return + end if + + ! extract model states for this grid cell and time step + FSTATE = gState_3d(iSpat1,iSpat2,sub_idx) + MSTATE = FSTATE + call STR_2_XTRY(FSTATE, ctx%STATE0) + + ! initialize model fluxes + ! If INITFLUXES lives somewhere else in your tree, swap this line accordingly. + call INITFLUXES() + + ! populate fuse work structure (diff path only) + if (diff_mode == differentiable) call get_bundle(ctx%fuseStruct) + + ! ------------------------- + ! snow module + ! ------------------------- + select case(SMODL%iSNOWM) + + case(iopt_temp_index) + + Z_FORCING = Z_FORCING_grid(iSpat1,iSpat2) + MBANDS(:)%info = MBANDS_INFO_3d(iSpat1,iSpat2,:) + MBANDS(:)%var = MBANDS_VAR_4d(iSpat1,iSpat2,:,sub_idx) + + if (diff_mode == differentiable) then + ctx%fuseStruct%snow%z_forcing = Z_FORCING + ctx%fuseStruct%snow%sbands(:)%info = MBANDS(:)%info + ctx%fuseStruct%snow%sbands(:)%var%bands_var = MBANDS(:)%var + end if + + select case(diff_mode) + case(original) + call UPDATE_SWE(DELTIM) + case(differentiable) + call UPDATE_SWE_DIFF(ctx%fuseStruct, DELTIM) + case default + err=1; message='advance_one_cell: cannot identify diff_mode (snow)'; return + end select + + case(iopt_no_snowmod) + call QRAINERROR() + + case default + err=1; message='advance_one_cell: unknown SMODL%iSNOWM option'; return + + end select + + ! ------------------------- + ! soil physics + ! ------------------------- + select case(diff_mode) + + case(original) + call ODE_INT(FUSE_SOLVE, ctx%STATE0, ctx%STATE1, dt_sub, dt_full, ierr, cmessage) + if (ierr /= 0) then + err=1; message=trim(cmessage); return + end if + + case(differentiable) + call implicit_solve(ctx%fuseStruct, ctx%state0, ctx%state1, nState, ierr, cmessage) + if (ierr /= 0) then + err=1; message=trim(cmessage); return + end if + W_FLUX = ctx%fuseStruct%step%flux + + case default + err=1; message='advance_one_cell: cannot identify diff_mode (soil)'; return + + end select + + ! routing + call Q_OVERLAND() + if (MROUTE%Q_ROUTED < 0._sp) then + err=1; message='Q_ROUTED is less than zero'; return + end if + if (MROUTE%Q_ROUTED > 1000._sp) then + err=1; message='Q_ROUTED is enormous'; return + end if + + ! write back to 3D buffers + call XTRY_2_STR(ctx%STATE1, FSTATE) + gState_3d(iSpat1,iSpat2,sub_idx+1) = FSTATE + W_FLUX_3d(iSpat1,iSpat2,sub_idx) = W_FLUX + AROUTE_3d(iSpat1,iSpat2,sub_idx) = MROUTE + + if (SMODL%iSNOWM == iopt_temp_index) then + + if (diff_mode == differentiable) then + Z_FORCING = ctx%fuseStruct%snow%z_forcing + MBANDS(:)%info = ctx%fuseStruct%snow%sbands(:)%info + MBANDS(:)%var = ctx%fuseStruct%snow%sbands(:)%var%bands_var + end if + + gState_3d(iSpat1,iSpat2,sub_idx+1)%SWE_TOT = sum(MBANDS(:)%var%SWE * MBANDS(:)%info%AF) + MBANDS_VAR_4d(iSpat1,iSpat2,:,sub_idx+1) = MBANDS(:)%var + + end if + + ! forcing diagnostics + if (grid_flag) then + aForce(sub_idx)%ppt = sum(gForce_3d(:,:,sub_idx)%ppt) / real(size(gForce_3d(:,:,sub_idx)), kind=sp) + aForce(sub_idx)%pet = sum(gForce_3d(:,:,sub_idx)%pet) / real(size(gForce_3d(:,:,sub_idx)), kind=sp) + end if + + ! stats + call COMP_STATS() + else + ! outside mask: NA fill + call SET_STATE(NA_VALUE_SP) + gState_3d(iSpat1,iSpat2,sub_idx) = FSTATE + call SET_FLUXES(NA_VALUE_SP) + W_FLUX_3d(iSpat1,iSpat2,sub_idx) = W_FLUX + call SET_ROUTE(NA_VALUE_SP) + AROUTE_3d(iSpat1,iSpat2,sub_idx) = MROUTE + end if + end subroutine advance_one_cell END MODULE fuse_evaluate_module diff --git a/build/FUSE_SRC/netcdf/put_output.f90 b/build/FUSE_SRC/netcdf/put_output.f90 index aaedb82..187e625 100644 --- a/build/FUSE_SRC/netcdf/put_output.f90 +++ b/build/FUSE_SRC/netcdf/put_output.f90 @@ -81,7 +81,7 @@ SUBROUTINE PUT_GOUTPUT_3D(istart_sim,istart_in,numtim) ! define dimension list (include parameter derivatives) start4_param = (/1,1,1,istart_sim/) - count4_param = (/nspat1,nspat2,n_bands,numtim/) + count4_param = (/nspat1,nspat2,NUMPAR,numtim/) ! open file IERR = NF_OPEN(TRIM(FNAME_NETCDF_RUNS),NF_WRITE,ncid_out) diff --git a/build/FUSE_SRC/physics/conserve_clamp.f90 b/build/FUSE_SRC/physics/conserve_clamp.f90 index 3c119ad..374b444 100644 --- a/build/FUSE_SRC/physics/conserve_clamp.f90 +++ b/build/FUSE_SRC/physics/conserve_clamp.f90 @@ -40,11 +40,11 @@ SUBROUTINE conserve_clamp(fuseStruct,DT,ERROR_FLAG) ! --------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - M_FLUX => fuseStruct%flux , & ! fluxes - BSTATE => fuseStruct%state0 , & ! state variables (start of step) - ESTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + M_FLUX => fuseStruct%step%flux , & ! fluxes + BSTATE => fuseStruct%step%state0 , & ! state variables (start of step) + ESTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! --------------------------------------------------------------------------------------- ERROR_FLAG=.FALSE. ! initialize with no extrapolation error diff --git a/build/FUSE_SRC/physics/evap_lower_diff.f90 b/build/FUSE_SRC/physics/evap_lower_diff.f90 index f8e0c78..add3b25 100644 --- a/build/FUSE_SRC/physics/evap_lower_diff.f90 +++ b/build/FUSE_SRC/physics/evap_lower_diff.f90 @@ -31,11 +31,11 @@ SUBROUTINE EVAP_LOWER_DIFF(fuseStruct, want_dflux) ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - MFORCE => fuseStruct%force , & ! model forcing data - M_FLUX => fuseStruct%flux , & ! fluxes - TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + MFORCE => fuseStruct%step%force , & ! model forcing data + M_FLUX => fuseStruct%step%flux , & ! fluxes + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! ------------------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics/evap_upper_diff.f90 b/build/FUSE_SRC/physics/evap_upper_diff.f90 index ac69b01..7a3c8b0 100644 --- a/build/FUSE_SRC/physics/evap_upper_diff.f90 +++ b/build/FUSE_SRC/physics/evap_upper_diff.f90 @@ -42,12 +42,12 @@ SUBROUTINE EVAP_UPPER_DIFF(fuseStruct, want_dflux) ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - MFORCE => fuseStruct%force , & ! model forcing data - M_FLUX => fuseStruct%flux , & ! fluxes - dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states - TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + MFORCE => fuseStruct%step%force , & ! model forcing data + M_FLUX => fuseStruct%step%flux , & ! fluxes + dfx_dS => fuseStruct%adj%df_dS , & ! deriv in fluxes w.r.t. states + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! ------------------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics/fix_ovshoot.f90 b/build/FUSE_SRC/physics/fix_ovshoot.f90 index 5467980..7a314f6 100644 --- a/build/FUSE_SRC/physics/fix_ovshoot.f90 +++ b/build/FUSE_SRC/physics/fix_ovshoot.f90 @@ -101,8 +101,8 @@ SUBROUTINE get_bounds(fuseStruct, lower, upper) REAL(SP) :: XMIN ! very small number INTEGER(I4B) :: ISTT ! loop through model states ! --------------------------------------------------------------------------------------- - associate(MPARAM => fuseStruct%param_adjust, & ! adjuustable model parameters - DPARAM => fuseStruct%param_derive) ! derived model parameters + associate(MPARAM => fuseStruct%par%param_adjust, & ! adjuustable model parameters + DPARAM => fuseStruct%par%param_derive) ! derived model parameters ! --------------------------------------------------------------------------------------- XMIN=FRACSTATE_MIN ! used to avoid zero derivatives ! --------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics/get_bundle.f90 b/build/FUSE_SRC/physics/get_bundle.f90 index 5432157..1d7c9cf 100644 --- a/build/FUSE_SRC/physics/get_bundle.f90 +++ b/build/FUSE_SRC/physics/get_bundle.f90 @@ -19,23 +19,24 @@ subroutine get_bundle(fuseStruct) integer(i4b) :: iParam ! populate fuse work structures - fuseStruct%time = timdat - fuseStruct%force = mForce - fuseStruct%state0 = mState - fuseStruct%state1 = mState - fuseStruct%flux = m_flux ! initialized at zero - fuseStruct%param_meta = parMeta - fuseStruct%param_adjust = mParam - fuseStruct%param_derive = dParam + fuseStruct%step%time = timdat + fuseStruct%step%force = mForce + fuseStruct%step%state0 = mState + fuseStruct%step%state1 = mState + fuseStruct%step%flux = m_flux ! initialized at zero + + fuseStruct%par%param_meta = parMeta + fuseStruct%par%param_adjust = mParam + fuseStruct%par%param_derive = dParam ! initialize flux derivatives do iState=1,nState - fuseStruct%df_dS(iState) = m_flux ! initialized at zero + fuseStruct%adj%df_dS(iState) = m_flux ! initialized at zero end do ! initialize parameter derivatives do iParam=1,NUMPAR - fuseStruct%df_dPar(iParam) = m_flux ! initialized at zero + fuseStruct%adj%df_dPar(iParam) = m_flux ! initialized at zero end do end subroutine get_bundle diff --git a/build/FUSE_SRC/physics/implicit_solve.f90 b/build/FUSE_SRC/physics/implicit_solve.f90 index 0849013..0b4b448 100644 --- a/build/FUSE_SRC/physics/implicit_solve.f90 +++ b/build/FUSE_SRC/physics/implicit_solve.f90 @@ -40,7 +40,7 @@ subroutine dx_dt(fuseStruct, x_try, g_x, J_g) comp_dflux = present(J_g) ! put data in structure - call XTRY_2_STR(x_try, fuseStruct%state1) + call XTRY_2_STR(x_try, fuseStruct%step%state1) ! run the fuse physics if (present(J_g)) then @@ -196,7 +196,7 @@ subroutine implicit_solve(fuseStruct, x0, x1, nx, ierr, message, isVerbose) call get_bounds(fuseStruct, lower, upper) ! put state vector into the fuse data structure - call XTRY_2_STR(x0, fuseStruct%state0) + call XTRY_2_STR(x0, fuseStruct%step%state0) ! intialize state vector (and soft clamp) x_try = x0 @@ -346,7 +346,7 @@ subroutine implicit_solve(fuseStruct, x0, x1, nx, ierr, message, isVerbose) x_try = x0 + dt*g_best ! test bounds violations: if bounds exceeded, then clamp and disaggregate fluxes (conserve mass) - call XTRY_2_STR(x_try, fuseStruct%state1) + call XTRY_2_STR(x_try, fuseStruct%step%state1) call conserve_clamp(fuseStruct, dt, isClamped) print*, 'WARNING: '//trim(message)//"failed to converge: use best function evaluation. Clamp = ", isClamped diff --git a/build/FUSE_SRC/physics/mstate_rhs_diff.f90 b/build/FUSE_SRC/physics/mstate_rhs_diff.f90 index 68ae410..791cde9 100644 --- a/build/FUSE_SRC/physics/mstate_rhs_diff.f90 +++ b/build/FUSE_SRC/physics/mstate_rhs_diff.f90 @@ -35,9 +35,10 @@ SUBROUTINE MSTATE_RHS_DIFF(fuseStruct, g_x, J_g) ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - M_FLUX => fuseStruct%flux , & ! fluxes - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DX_DT => fuseStruct%dx_dt & ! time derivative in states + M_FLUX => fuseStruct%step%flux , & ! fluxes + DX_DT => fuseStruct%step%dx_dt , & ! time derivative in states + df_dS => fuseStruct%adj%df_dS , & ! derivative in fluxes w.r.t. states + MPARAM => fuseStruct%par%param_adjust & ! adjustable model parameters ) ! (associate) ! ------------------------------------------------------------------------------------------------- @@ -68,7 +69,7 @@ SUBROUTINE MSTATE_RHS_DIFF(fuseStruct, g_x, J_g) ! compute Jacobian if(comp_dflux)then if(SMODL%iARCH1 /= iopt_onestate_1) stop "mstate_rhs: only iopt_onestate_1 currently implemented" - J_g(1,:) = -M_FLUX%EFF_PPT*fuseStruct%df_dS%SATAREA - fuseStruct%df_dS%EVAP_1 - fuseStruct%df_dS%QPERC_12 + J_g(1,:) = -M_FLUX%EFF_PPT*df_dS%SATAREA - df_dS%EVAP_1 - df_dS%QPERC_12 endif ! --------------------------------------------------------------------------------------- @@ -96,7 +97,7 @@ SUBROUTINE MSTATE_RHS_DIFF(fuseStruct, g_x, J_g) ! NOTE: assume M_FLUX%EVAP_2=0 and M_FLUX%OFLOW_2=0 if(comp_dflux)then if(SMODL%iARCH2 == iopt_tens2pll_2) stop "mstate_rhs: iopt_tens2pll_2 not currently implemented" - J_g(2,:) = fuseStruct%df_dS%QPERC_12 - fuseStruct%df_dS%QBASE_2 + J_g(2,:) = df_dS%QPERC_12 - df_dS%QBASE_2 endif ! --------------------------------------------------------------------------------------- @@ -106,7 +107,7 @@ SUBROUTINE MSTATE_RHS_DIFF(fuseStruct, g_x, J_g) ! --------------------------------------------------------------------------------------- ! extract dx_dt from fuse structure - call STR_2_XTRY(fuseStruct%dx_dt, g_x) + call STR_2_XTRY(dx_dt, g_x) ! --------------------------------------------------------------------------------------- end associate ! end association with variables in the data structures diff --git a/build/FUSE_SRC/physics/q_baseflow_diff.f90 b/build/FUSE_SRC/physics/q_baseflow_diff.f90 index 5dd2813..5bc7c7e 100644 --- a/build/FUSE_SRC/physics/q_baseflow_diff.f90 +++ b/build/FUSE_SRC/physics/q_baseflow_diff.f90 @@ -35,11 +35,11 @@ SUBROUTINE Q_BASEFLOW_DIFF(fuseStruct, want_dflux) ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - M_FLUX => fuseStruct%flux , & ! fluxes - dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states - TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + M_FLUX => fuseStruct%step%flux , & ! fluxes + dfx_dS => fuseStruct%adj%df_dS , & ! deriv in fluxes w.r.t. states + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! check the need to compute flux derivatives diff --git a/build/FUSE_SRC/physics/q_misscell_diff.f90 b/build/FUSE_SRC/physics/q_misscell_diff.f90 index ae56313..9b232ba 100644 --- a/build/FUSE_SRC/physics/q_misscell_diff.f90 +++ b/build/FUSE_SRC/physics/q_misscell_diff.f90 @@ -39,10 +39,10 @@ SUBROUTINE Q_MISSCELL_DIFF(fuseStruct, want_dflux) ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - M_FLUX => fuseStruct%flux , & ! fluxes - TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + M_FLUX => fuseStruct%step%flux , & ! fluxes + TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! --------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics/qinterflow_diff.f90 b/build/FUSE_SRC/physics/qinterflow_diff.f90 index d2aaf84..4c99eb4 100644 --- a/build/FUSE_SRC/physics/qinterflow_diff.f90 +++ b/build/FUSE_SRC/physics/qinterflow_diff.f90 @@ -31,10 +31,10 @@ SUBROUTINE QINTERFLOW_DIFF(fuseStruct, want_dflux) ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - M_FLUX => fuseStruct%flux , & ! fluxes - TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + M_FLUX => fuseStruct%step%flux , & ! fluxes + TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! ------------------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics/qpercolate_diff.f90 b/build/FUSE_SRC/physics/qpercolate_diff.f90 index 28a6b45..9140a9f 100644 --- a/build/FUSE_SRC/physics/qpercolate_diff.f90 +++ b/build/FUSE_SRC/physics/qpercolate_diff.f90 @@ -39,11 +39,11 @@ SUBROUTINE QPERCOLATE_DIFF(fuseStruct, want_dflux) ! --------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - M_FLUX => fuseStruct%flux , & ! fluxes - dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states - TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + M_FLUX => fuseStruct%step%flux , & ! fluxes + dfx_dS => fuseStruct%adj%df_dS , & ! deriv in fluxes w.r.t. states + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! --------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics/qsatexcess_diff.f90 b/build/FUSE_SRC/physics/qsatexcess_diff.f90 index 901c0eb..b575c31 100644 --- a/build/FUSE_SRC/physics/qsatexcess_diff.f90 +++ b/build/FUSE_SRC/physics/qsatexcess_diff.f90 @@ -49,11 +49,11 @@ SUBROUTINE QSATEXCESS_DIFF(fuseStruct, want_dflux) ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - M_FLUX => fuseStruct%flux , & ! fluxes - dfx_dS => fuseStruct%df_dS , & ! deriv in fluxes w.r.t. states - TSTATE => fuseStruct%state1 , & ! trial state variables (end of step) - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) + M_FLUX => fuseStruct%step%flux , & ! fluxes + dfx_dS => fuseStruct%adj%df_dS , & ! deriv in fluxes w.r.t. states + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! ------------------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics/update_swe_diff.f90 b/build/FUSE_SRC/physics/update_swe_diff.f90 index 5ea26b4..b0a6fd6 100644 --- a/build/FUSE_SRC/physics/update_swe_diff.f90 +++ b/build/FUSE_SRC/physics/update_swe_diff.f90 @@ -106,13 +106,13 @@ SUBROUTINE UPDATE_SWE_DIFF(fuseStruct, DT, want_dparam) ! --------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& - TIMDAT => fuseStruct%time , & ! time information - MFORCE => fuseStruct%force , & ! forcing data - Z_FORC => fuseStruct%z_forcing , & ! elevation of the forcing data - M_FLUX => fuseStruct%flux , & ! fluxes - MBANDS => fuseStruct%sbands , & ! elevation band variables: MBANDS(i)%var, MBANDS(i)info - MPARAM => fuseStruct%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%param_derive & ! derived model parameters + TIMDAT => fuseStruct%step%time , & ! time information + MFORCE => fuseStruct%step%force , & ! forcing data + M_FLUX => fuseStruct%step%flux , & ! fluxes + MBANDS => fuseStruct%snow%sbands , & ! elevation band variables: MBANDS(i)%var, MBANDS(i)info + Z_FORC => fuseStruct%snow%z_forcing , & ! elevation of the forcing data + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! --------------------------------------------------------------------------------------- ! snow accumulation and melt calculations for each band @@ -320,8 +320,8 @@ SUBROUTINE UPDATE_SWE_DIFF(fuseStruct, DT, want_dparam) M_FLUX%EFF_PPT = M_FLUX%EFF_PPT + MBANDS(ISNW)%info%AF * (rain + snowmelt) if(comp_dparam)then - fuseStruct%df_dPar(1:NP)%EFF_PPT = fuseStruct%df_dPar(1:NP)%EFF_PPT + & - MBANDS(ISNW)%info%AF * (drain(:) + dsnowmelt(:)) + fuseStruct%adj%df_dPar(1:NP)%EFF_PPT = fuseStruct%adj%df_dPar(1:NP)%EFF_PPT + & + MBANDS(ISNW)%info%AF * (drain(:) + dsnowmelt(:)) endif END DO ! looping through elevation bands @@ -329,8 +329,8 @@ SUBROUTINE UPDATE_SWE_DIFF(fuseStruct, DT, want_dparam) end associate ! TEMPORARY: save the derivative as a "fake" loss function - fuseStruct%dL_dPar(:) = NA_VALUE_SP - fuseStruct%dL_dPar(1:NP) = fuseStruct%df_dPar(1:NP)%EFF_PPT + fuseStruct%adj%dL_dPar(:) = NA_VALUE_SP + fuseStruct%adj%dL_dPar(1:NP) = fuseStruct%adj%df_dPar(1:NP)%EFF_PPT END SUBROUTINE UPDATE_SWE_DIFF diff --git a/build/FUSE_SRC/runtime/get_time_indices.f90 b/build/FUSE_SRC/runtime/get_time_indices.f90 index e71333e..82c5fbe 100644 --- a/build/FUSE_SRC/runtime/get_time_indices.f90 +++ b/build/FUSE_SRC/runtime/get_time_indices.f90 @@ -12,13 +12,14 @@ SUBROUTINE GET_TIME_INDICES ! convert start and end date of the NetCDF input file to julian day (Julian day is the continuous ! count of days since the beginning of the Julian Period around 4700 BC) - USE multiforce, ONLY: timeUnits,time_steps,julian_day_input ! time data - USE multiforce, only: numtim_in, itim_in, istart ! length of input time series and associated index - USE multiforce, only: numtim_sim, itim_sim ! length of simulated time series and associated index - USE multiforce, only: numtim_sub, itim_sub ! length of subperiod time series and associated index - USE multiforce, only: sim_beg,sim_end ! timestep indices - USE multiforce, only: eval_beg,eval_end ! timestep indices - USE multiforce, only: SUB_PERIODS_FLAG ! .true. if subperiods are used to run FUSE + USE multiforce, ONLY: timeUnits,time_steps,julian_day_input ! time data + USE multiforce, only: numtim_in ! length of input time series + USE multiforce, only: numtim_sim ! length of simulated time series + USE multiforce, only: numtim_sub ! length of subperiod time series + USE multiforce, only: istart ! timestep indices (istart=sim_beg) + USE multiforce, only: sim_beg,sim_end ! timestep indices + USE multiforce, only: eval_beg,eval_end ! timestep indices + USE multiforce, only: SUB_PERIODS_FLAG ! .true. if subperiods are used to run FUSE USE fuse_fileManager,only:date_start_sim,date_end_sim,& date_start_eval,date_end_eval,& @@ -28,7 +29,7 @@ SUBROUTINE GET_TIME_INDICES INTEGER(I4B) :: ERR ! error code CHARACTER(LEN=1024) :: MESSAGE ! error message - ! dummies + ! local variables integer(i4b) :: iy,im,id,ih,imin ! to temporarily store year, month, day, hour, min real(sp) :: isec ! to temporarily store sec real(sp) :: jdate ! to temporarily store a julian date diff --git a/build/FUSE_SRC/share/multiforce_data.f90 b/build/FUSE_SRC/share/multiforce_data.f90 index cd077b2..95e42ca 100644 --- a/build/FUSE_SRC/share/multiforce_data.f90 +++ b/build/FUSE_SRC/share/multiforce_data.f90 @@ -29,8 +29,7 @@ MODULE multiforce public :: gForce, gForce_3d public :: date_start_input, date_end_input - public :: numtim_in, numtim_sim, numtim_sub, numtim_sub_cur - public :: itim_in, itim_sim, itim_sub + public :: numtim_in, numtim_sim, numtim_sub public :: sim_beg, sim_end, eval_beg, eval_end public :: istart, jdayRef public :: deltim @@ -96,10 +95,6 @@ MODULE multiforce INTEGER(i4b) :: numtim_in = -1 ! number of time steps of input (atmospheric forcing) INTEGER(i4b) :: numtim_sim = -1 ! number of time steps of FUSE simulations (including spin-up) INTEGER(i4b) :: numtim_sub = -1 ! number of time steps of subperiod (will be kept in memory) - INTEGER(i4b) :: numtim_sub_cur = -1 ! number of time steps of current subperiod (allows for the last subperiod to be shorter) - INTEGER(i4b) :: itim_in = -1 ! indice within numtim_in - INTEGER(i4b) :: itim_sim = -1 ! indice within numtim_sim - INTEGER(i4b) :: itim_sub = -1 ! indice within numtim_sub INTEGER(i4b) :: sim_beg = -1 ! index for the start of the simulation in fuse_metric INTEGER(i4b) :: sim_end = -1 ! index for the end of the simulation in fuse_metric diff --git a/build/FUSE_SRC/types/work_types.f90 b/build/FUSE_SRC/types/work_types.f90 index 2c1ee0f..f239056 100644 --- a/build/FUSE_SRC/types/work_types.f90 +++ b/build/FUSE_SRC/types/work_types.f90 @@ -33,28 +33,62 @@ module work_types end type ebands ! -------------------------------------------------------------------------------------- - - ! omnibus structure that bundles "everything" required to run fuse for a single cell + ! structure bundles - type fuse_work + ! per-step structure + type fuse_step type(tdata) :: time ! time data type(fdata) :: force ! model forcing data - type(ebands) , allocatable :: sbands(:) ! info/variables for elevation bands (snow model) type(statev) :: state0 ! state variables (start of step) type(statev) :: state1 ! state variables (end of step) type(statev) :: dx_dt ! time derivative in state variables type(fluxes) :: flux ! fluxes - type(fluxes), allocatable :: df_dS(:) ! derivative in fluxes w.r.t. states - type(fluxes), allocatable :: df_dPar(:) ! derivative in fluxes w.r.t. parameters - real(sp), allocatable :: dL_dPar(:) ! derivative in loss function w.r.t. parameters type(runoff) :: route ! hillslope routing + end type fuse_step + + ! snow structure + type fuse_snow + real(sp) :: z_forcing ! elevation of forcing data (m) + type(ebands) , allocatable :: sbands(:) ! info/variables for elevation bands (snow model) + end type fuse_snow + + ! parameter structure + type fuse_param type(par_id) :: param_name ! parameter names type(parinfo) :: param_meta ! metadata on model parameters type(paradj) :: param_adjust ! adjustable model parametrs type(pardvd) :: param_derive ! derived model parameters - type(summary) :: sim_stats ! simulation statistics - real(sp) :: z_forcing ! elevation of forcing data (m) - logical(lgt) :: is_initialized = .false. + end type fuse_param + + ! adjoint structure (differentiable fuse) + type fuse_adjoint + type(fluxes), allocatable :: df_dS(:) ! derivative in fluxes w.r.t. states + type(fluxes), allocatable :: df_dPar(:) ! derivative in fluxes w.r.t. parameters + real(sp), allocatable :: dL_dPar(:) ! derivative in loss function w.r.t. parameters + end type fuse_adjoint + + ! output chunk buffers (allocate per chunk) + type fuse_outputs + type(fluxes), allocatable :: w_flux_3d(:,:,:) ! (nspat1,nspat2,chunk_len) + type(runoff), allocatable :: aroute_3d(:,:,:) ! (nspat1,nspat2,chunk_len) + end type + + ! run-level / evaluation-level + type fuse_run + type(summary) :: stats + end type fuse_run + + ! -------------------------------------------------------------------------------------- + ! omnibus structure that bundles "everything" required to run fuse for a single cell + + type fuse_work + type(fuse_step) :: step ! per-step structure + type(fuse_snow) :: snow ! snow structure + type(fuse_param) :: par ! parameter structure + type(fuse_adjoint) :: adj ! adjoint structure (differentiable fuse) + type(fuse_outputs) :: buf ! output buffer + type(fuse_run) :: run ! run-level structure + logical(lgt) :: is_initialized = .false. end type fuse_work end module work_types diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index 9320b78..6c737d2 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-18T05:46:57Z' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-18T23:03:15Z' character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/fuse-evaluate' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'd5dab2e1a4b5c9eabbcc6a4b6a0d4fe1a7bd9c68' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '7ae53258e9c118f5b41b8dc28cccb3c06919e2d6' From a9bb61c58c270788e243955690f57023a418687b Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Thu, 19 Feb 2026 10:30:30 -0700 Subject: [PATCH 07/11] updated routines to define and write 3d output --- build/FUSE_SRC/driver/fuse_driver.f90 | 6 +- build/FUSE_SRC/driver/fuse_evaluate.f90 | 6 +- build/FUSE_SRC/netcdf/def_output.f90 | 314 ++++++++++------------- build/FUSE_SRC/netcdf/handle_err.f90 | 27 +- build/FUSE_SRC/netcdf/put_output.f90 | 321 +++++++++--------------- build/FUSE_SRC/types/work_types.f90 | 9 +- build/FUSE_SRC/util/varextract.f90 | 285 ++++++--------------- build/Makefile | 8 +- build/generated/fuseversion.inc | 4 +- 9 files changed, 364 insertions(+), 616 deletions(-) diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index 61299ca..13e36e6 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -365,9 +365,9 @@ PROGRAM DISTRIBUTED_DRIVER ENDIF -CALL DEF_PARAMS(NUMPSET) ! define model parameters (initial CREATE) -CALL DEF_SSTATS() ! define summary statistics (REDEF) -CALL DEF_OUTPUT(nSpat1,nSpat2,N_BANDS,NUMPSET,numtim_sim) ! define model output time series (REDEF) +CALL DEF_PARAMS(NUMPSET) ! define model parameters (initial CREATE) +CALL DEF_SSTATS() ! define summary statistics (REDEF) +CALL DEF_OUTPUT(nSpat1,nSpat2,N_BANDS,NUMPAR) ! define model output time series (REDEF) ! --------------------------------------------------------------------------------------- ! RUN FUSE IN DESIRED MODE diff --git a/build/FUSE_SRC/driver/fuse_evaluate.f90 b/build/FUSE_SRC/driver/fuse_evaluate.f90 index 2fa091c..2a54c1b 100644 --- a/build/FUSE_SRC/driver/fuse_evaluate.f90 +++ b/build/FUSE_SRC/driver/fuse_evaluate.f90 @@ -301,6 +301,8 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) ! initialize summary statistics + timer call init_stats() + print*, 'end of initialize' + end subroutine initialize_run ! ------------------------------------------------------------------------------------------------------------------- @@ -319,7 +321,7 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) use time_io, only: get_modtim use getPETgrid_module, only: getPETgrid use get_gforce_module, only: get_gforce_3d - use put_output_module, only: put_goutput_3d + use put_output_module, only: put_output implicit none @@ -436,7 +438,7 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) ! write model output IF (OUTPUT_FLAG) THEN if(isPrint) PRINT *, 'Write output for ',chunk_len,' time steps starting at indices', chunk_start_sim - CALL PUT_GOUTPUT_3D(chunk_start_sim, chunk_start_in, chunk_len) + CALL PUT_OUTPUT(ctx%fuseStruct, chunk_start_sim, chunk_start_in, chunk_len) if(isPrint) PRINT *, 'Done writing output' ELSE if(isPrint) PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' diff --git a/build/FUSE_SRC/netcdf/def_output.f90 b/build/FUSE_SRC/netcdf/def_output.f90 index e93e41f..268f0f7 100644 --- a/build/FUSE_SRC/netcdf/def_output.f90 +++ b/build/FUSE_SRC/netcdf/def_output.f90 @@ -1,189 +1,141 @@ MODULE DEF_OUTPUT_MODULE - - USE nrtype ! variable types, etc. - + USE nrtype + USE netcdf implicit none - private public :: DEF_OUTPUT - contains - - SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR,NTIM) - - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2007 - ! Modified by Martyn Clark to include elevation bands, 12/2025 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Define NetCDF output files -- time-varying model output - ! --------------------------------------------------------------------------------------- - - ! subroutines - USE metaoutput, only: VARDESCRIBE ! define metadata for model variables - - ! data modules - USE globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH - USE metaoutput, only: NOUTVAR ! number of output variables - USE metaoutput, only: VNAME, LNAME, VUNIT ! metadata for all model variables - USE metaoutput, only: isBand, isFlux ! logical flag to define vars with band/flux dimension - USE model_defn, only: FNAME_NETCDF_RUNS ! model definition (includes filename) - USE fuse_fileManager, only: Q_ONLY ! only write streamflow to output file? - USE multiforce, only: GRID_FLAG ! .true. if distributed - USE multiforce, only: latitude,longitude ! dimension arrays - USE multiforce, only: name_psets,time_steps ! dimension arrays - USE multiforce, only: latUnits,lonUnits ! lat/lon units string - USE multiforce, only: timeUnits ! time units string - USE globaldata, only: ncid_out ! NetCDF output file ID - - IMPLICIT NONE - - ! input - INTEGER(I4B), INTENT(IN) :: NTIM ! number of time steps - INTEGER(I4B), INTENT(IN) :: nSpat1,nSpat2 ! length of spatial dimensions - INTEGER(I4B), INTENT(IN) :: n_bands ! number of elevation bands - INTEGER(I4B), INTENT(IN) :: NUMPAR ! number of model parameters - - ! internal - integer(i4b), dimension(n_bands) :: band_i ! coordinate variable - integer(i4b), dimension(NUMPAR) :: param_i ! coordinate variable - REAL(MSP),DIMENSION(nspat1) :: longitude_msp ! coordinate variable (SINGLE PRECISION) - REAL(MSP),DIMENSION(nspat2) :: latitude_msp ! coordinate variable (SINGLE PRECISION) - REAL(SP),parameter :: NA_VALUE_OUT= -9999. ! NA_VALUE for output file - REAL(MSP) :: NA_VALUE_OUT_MSP ! NA_VALUE for output file - - LOGICAL(LGT) :: WRITE_VAR ! used to denote if the variable is written - INTEGER(I4B) :: IERR ! error code - INTEGER(I4B) :: NTIM_DIM ! time - INTEGER(I4B) :: lon_dim ! 1st spatial dimension - INTEGER(I4B) :: lat_dim ! 2nd spatial dimension - INTEGER(I4B) :: par_dim ! parameter dimension - INTEGER(I4B) :: band_dim ! band dimension - INTEGER(I4B), DIMENSION(3) :: TVAR ! dimension list: exclude band, param - INTEGER(I4B), DIMENSION(4) :: EVAR ! dimension list: include band - INTEGER(I4B), DIMENSION(4) :: PVAR ! dimension list: include param - integer(i4b) :: ib ! loop through bands - integer(i4b) :: ip ! loop through parameters - INTEGER(I4B) :: IVAR ! loop through variables - INTEGER(I4B) :: IVAR_ID ! variable ID - - include 'netcdf.inc' ! use netCDF libraries - - ! --------------------------------------------------------------------------------------- - CALL VARDESCRIBE() ! get list of variable descriptions - ! --------------------------------------------------------------------------------------- - - ! put file in define mode - print *, 'Create NetCDF file for runs:' - PRINT *, FNAME_NETCDF_RUNS - - IERR = NF_CREATE(TRIM(FNAME_NETCDF_RUNS),NF_CLOBBER,ncid_out); CALL HANDLE_ERR(IERR) - - ! define dimensions - IERR = NF_DEF_DIM(ncid_out, 'time', NF_UNLIMITED, NTIM_DIM); CALL HANDLE_ERR(IERR) !record dimension (unlimited length) - IERR = NF_DEF_DIM(ncid_out, 'band', n_bands, band_dim); CALL HANDLE_ERR(IERR) - IERR = NF_DEF_DIM(ncid_out, 'param', NUMPAR, par_dim); CALL HANDLE_ERR(IERR) - IERR = NF_DEF_DIM(ncid_out, 'longitude', nSpat1, lon_dim); CALL HANDLE_ERR(IERR) - IERR = NF_DEF_DIM(ncid_out, 'latitude', nSpat2, lat_dim); CALL HANDLE_ERR(IERR) - - ! define dimension vector - TVAR = (/lon_dim, lat_dim, NTIM_DIM/) - PVAR = (/lon_dim, lat_dim, par_dim, NTIM_DIM/) - EVAR = (/lon_dim, lat_dim, band_dim, NTIM_DIM/) - - ! define time-varying output variables - DO IVAR=1,NOUTVAR - - ! check if there is a need to write the variable - see also put_output - ! uncomment variables that should be written to output file - IF (Q_ONLY) THEN - WRITE_VAR=.FALSE. - IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. - IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. - IF (.NOT.WRITE_VAR) CYCLE ! start new iteration of do loop, i.e. skip writting variable - ENDIF - - ! write the variable - if(isBand(iVar))then - IERR = NF_DEF_VAR(ncid_out,TRIM(VNAME(IVAR)),NF_REAL,4,EVAR,IVAR_ID); CALL HANDLE_ERR(IERR) - ELSE - IERR = NF_DEF_VAR(ncid_out,TRIM(VNAME(IVAR)),NF_REAL,3,TVAR,IVAR_ID); CALL HANDLE_ERR(IERR) - ENDIF - - ! define missing value - NA_VALUE_OUT_MSP=NA_VALUE_OUT - - ! write metadata - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',LEN_TRIM(LNAME(IVAR)),TRIM(LNAME(IVAR))); CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',LEN_TRIM(VUNIT(IVAR)),TRIM(VUNIT(IVAR))); CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_FLOAT,1,NA_VALUE_OUT_MSP); CALL HANDLE_ERR(IERR) - - ! define the parameter sensitivity for each flux: extra variable - if(isFlux(iVar))then - IERR = NF_DEF_VAR(ncid_out,TRIM(VNAME(IVAR))//'__dFlux_dParam',NF_REAL,4,PVAR,IVAR_ID); CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_FLOAT,1,NA_VALUE_OUT_MSP); CALL HANDLE_ERR(IERR) - endif - - END DO ! ivar - - ! define the time variable - ierr = nf_def_var(ncid_out,'time',nf_real,1,(/ntim_dim/),ivar_id); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'units',len_trim(timeUnits),trim(timeUnits)) - call handle_err(ierr) - - ! define the latitude variable - ierr = nf_def_var(ncid_out,'latitude',nf_real,1,(/lat_dim/),ivar_id); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'units',8,'degreesN'); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'axis',1,'Y'); call handle_err(ierr) - - ! define the longitude variable - ierr = nf_def_var(ncid_out,'longitude',nf_real,1,(/lon_dim/),ivar_id); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'units',8,'degreesE'); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'axis',1,'X'); call handle_err(ierr) - - ! define the parameter set variable - ierr = nf_def_var(ncid_out,'param',nf_int,1,(/par_dim/),ivar_id); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'units',1,'-'); call handle_err(ierr) - - ! define the band variable - ierr = nf_def_var(ncid_out,'band',nf_int,1,(/band_dim/),ivar_id); call handle_err(ierr) - ierr = nf_put_att_text(ncid_out,ivar_id,'units',1,'-'); call handle_err(ierr) - - ! add global attributes - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "software", len("FUSE"), "FUSE"); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_version", len_trim(FUSE_VERSION), trim(FUSE_VERSION)); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_build_time", len_trim(FUSE_BUILDTIME), trim(FUSE_BUILDTIME)); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_branch", len_trim(FUSE_GITBRANCH), trim(FUSE_GITBRANCH)); call HANDLE_ERR(ierr) - ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_hash", len_trim(FUSE_GITHASH), trim(FUSE_GITHASH)); call HANDLE_ERR(ierr) - - ! end definitions - IERR = NF_ENDDEF(ncid_out); call handle_err(ierr) - - latitude_msp=latitude ! convert to actual single precision - IERR = NF_INQ_VARID(ncid_out,'latitude',IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID - IERR = NF_PUT_VARA_REAL(ncid_out,IVAR_ID,1,nspat2,latitude_msp); CALL HANDLE_ERR(IERR) ! write data - - longitude_msp=longitude ! convert to actual single precision - IERR = NF_INQ_VARID(ncid_out,'longitude',IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID - IERR = NF_PUT_VARA_REAL(ncid_out,IVAR_ID,1,nspat1,longitude_msp); CALL HANDLE_ERR(IERR) ! write data - - band_i = [(ib, ib=1,n_bands)] ! 1..n_bands - ierr = NF_INQ_VARID(ncid_out, 'band', ivar_id); call HANDLE_ERR(ierr) - ierr = NF_PUT_VARA_INT(ncid_out, ivar_id, (/1/), (/n_bands/), band_i); call HANDLE_ERR(ierr) - - param_i = [(ip, ip=1,NUMPAR)] ! 1..NUMPAR - ierr = NF_INQ_VARID(ncid_out, 'param', ivar_id); call HANDLE_ERR(ierr) - ierr = NF_PUT_VARA_INT(ncid_out, ivar_id, (/1/), (/NUMPAR/), param_i); call HANDLE_ERR(ierr) - - PRINT *, 'NetCDF file for model runs defined with dimensions', nSpat1 , nSpat2, n_bands, NUMPAR, NTIM - - ! close output file - IERR = NF_CLOSE(ncid_out) - - ! --------------------------------------------------------------------------------------- +contains + + SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) + + USE metaoutput, only: VARDESCRIBE + USE globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH + USE metaoutput, only: NOUTVAR, VNAME, LNAME, VUNIT, isBand, isFlux + USE model_defn, only: FNAME_NETCDF_RUNS + USE fuse_fileManager, only: Q_ONLY + USE multiforce, only: latitude,longitude, timeUnits + USE globaldata, only: ncid_out + + implicit none + + integer(i4b), intent(in) :: nSpat1, nSpat2, n_bands, NUMPAR + + ! locals + integer(i4b) :: ierr, ivar, varid, varid_time, varid_lat, varid_lon, varid_band, varid_param + integer(i4b) :: dim_time, dim_lon, dim_lat, dim_band, dim_par + integer(i4b), dimension(3) :: dimids_3 + integer(i4b), dimension(4) :: dimids_band + integer(i4b), dimension(4) :: dimids_par + + logical(lgt) :: write_var + + real(msp), dimension(nspat1) :: longitude_msp + real(msp), dimension(nspat2) :: latitude_msp + real(msp), parameter :: NA_VALUE_OUT = -9999._msp + + integer(i4b), dimension(n_bands) :: band_i + integer(i4b), dimension(NUMPAR) :: param_i + integer(i4b) :: ib, ip + + call VARDESCRIBE() + + print *, 'Create NetCDF file for runs:' + print *, trim(FNAME_NETCDF_RUNS) + + ! Create NetCDF-4 file (HDF5 container) + ierr = nf90_create(trim(FNAME_NETCDF_RUNS), NF90_CLASSIC_MODEL, ncid_out) + call handle_err(ierr) + + ! Dimensions + ierr = nf90_def_dim(ncid_out, "time", NF90_UNLIMITED, dim_time); call handle_err(ierr) + ierr = nf90_def_dim(ncid_out, "band", n_bands, dim_band); call handle_err(ierr) + ierr = nf90_def_dim(ncid_out, "param", NUMPAR, dim_par); call handle_err(ierr) + ierr = nf90_def_dim(ncid_out, "longitude", nSpat1, dim_lon); call handle_err(ierr) + ierr = nf90_def_dim(ncid_out, "latitude", nSpat2, dim_lat); call handle_err(ierr) + + dimids_3 = (/ dim_lon, dim_lat, dim_time /) + dimids_band = (/ dim_lon, dim_lat, dim_band, dim_time /) + dimids_par = (/ dim_lon, dim_lat, dim_par, dim_time /) + + ! Time-varying output vars + do ivar = 1, NOUTVAR + + print*, trim(VNAME(ivar)) + + if (Q_ONLY) then + write_var = .false. + if (trim(VNAME(ivar)) == "q_instnt") write_var = .true. + if (trim(VNAME(ivar)) == "q_routed") write_var = .true. + if (.not. write_var) cycle + end if + + if (isBand(ivar)) then + ierr = nf90_def_var(ncid_out, trim(VNAME(ivar)), NF90_FLOAT, dimids_band, varid) + else + ierr = nf90_def_var(ncid_out, trim(VNAME(ivar)), NF90_FLOAT, dimids_3, varid) + end if + call handle_err(ierr) + + ! Attributes + ierr = nf90_put_att(ncid_out, varid, "long_name", trim(LNAME(ivar))); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid, "units", trim(VUNIT(ivar))); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid, "_FillValue", NA_VALUE_OUT); call handle_err(ierr) + + ! Optional: parameter sensitivity var for each flux + if (isFlux(ivar)) then + ierr = nf90_def_var(ncid_out, trim(VNAME(ivar))//"__dFlux_dParam", NF90_FLOAT, dimids_par, varid) + call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid, "_FillValue", NA_VALUE_OUT); call handle_err(ierr) + end if + + end do + + ! Coordinate variables + ierr = nf90_def_var(ncid_out, "time", NF90_FLOAT, (/dim_time/), varid_time); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_time, "units", trim(timeUnits)); call handle_err(ierr) + + ierr = nf90_def_var(ncid_out, "latitude", NF90_FLOAT, (/dim_lat/), varid_lat); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lat, "units", "degreesN"); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lat, "axis", "Y"); call handle_err(ierr) + + ierr = nf90_def_var(ncid_out, "longitude", NF90_FLOAT, (/dim_lon/), varid_lon); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lon, "units", "degreesE"); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lon, "axis", "X"); call handle_err(ierr) + + ierr = nf90_def_var(ncid_out, "param", NF90_INT, (/dim_par/), varid_param); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_param, "units", "-"); call handle_err(ierr) + + ierr = nf90_def_var(ncid_out, "band", NF90_INT, (/dim_band/), varid_band); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_band, "units", "-"); call handle_err(ierr) + + ! Global attributes + ierr = nf90_put_att(ncid_out, NF90_GLOBAL, "software", "FUSE"); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, NF90_GLOBAL, "fuse_version", trim(FUSE_VERSION)); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, NF90_GLOBAL, "fuse_build_time", trim(FUSE_BUILDTIME)); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, NF90_GLOBAL, "fuse_git_branch", trim(FUSE_GITBRANCH)); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, NF90_GLOBAL, "fuse_git_hash", trim(FUSE_GITHASH)); call handle_err(ierr) + + ! Leave define mode + ierr = nf90_enddef(ncid_out); call handle_err(ierr) + + ! Write coordinate data + latitude_msp = latitude + longitude_msp = longitude + + ierr = nf90_put_var(ncid_out, varid_lat, latitude_msp); call handle_err(ierr) + ierr = nf90_put_var(ncid_out, varid_lon, longitude_msp); call handle_err(ierr) + + band_i = [(ib, ib=1,n_bands)] + param_i = [(ip, ip=1,NUMPAR)] + + ierr = nf90_put_var(ncid_out, varid_band, band_i); call handle_err(ierr) + ierr = nf90_put_var(ncid_out, varid_param, param_i); call handle_err(ierr) + + print *, 'NetCDF file for model runs defined with dimensions', nSpat1, nSpat2, n_bands, NUMPAR + + ierr = nf90_close(ncid_out); call handle_err(ierr) + END SUBROUTINE DEF_OUTPUT END MODULE DEF_OUTPUT_MODULE diff --git a/build/FUSE_SRC/netcdf/handle_err.f90 b/build/FUSE_SRC/netcdf/handle_err.f90 index 5bea0ae..24a09f6 100644 --- a/build/FUSE_SRC/netcdf/handle_err.f90 +++ b/build/FUSE_SRC/netcdf/handle_err.f90 @@ -1,10 +1,17 @@ -SUBROUTINE HANDLE_ERR(IERR) -! Used to print our error statements from NetCDF calls and stop -USE nrtype -INTEGER(I4B) :: IERR ! error code -include 'netcdf.inc' -IF (IERR.NE.NF_NOERR) THEN - PRINT *, NF_STRERROR(IERR) - STOP -ENDIF -END SUBROUTINE HANDLE_ERR +subroutine handle_err(ierr, where) + use nrtype, only: i4b + use netcdf, only: NF90_NOERR, nf90_strerror + implicit none + + integer(i4b), intent(in) :: ierr + character(len=*), intent(in), optional :: where + + if (ierr /= NF90_NOERR) then + if (present(where)) then + write(*,'(a,1x,a)') 'NetCDF error in '//trim(where)//':', trim(nf90_strerror(ierr)) + else + write(*,'(a)') trim(nf90_strerror(ierr)) + end if + stop 1 + end if +end subroutine handle_err diff --git a/build/FUSE_SRC/netcdf/put_output.f90 b/build/FUSE_SRC/netcdf/put_output.f90 index 187e625..ccce0cf 100644 --- a/build/FUSE_SRC/netcdf/put_output.f90 +++ b/build/FUSE_SRC/netcdf/put_output.f90 @@ -1,234 +1,147 @@ -MODULE PUT_OUTPUT_MODULE +module put_output_module - USE nrtype ! variable types, etc. + use nrtype + use work_types, only: fuse_work + use iso_fortran_env, only: real32 - implicit none + use netcdf, only: & + NF90_WRITE, NF90_NOERR, & + nf90_open, nf90_close, nf90_inq_varid, nf90_put_var + implicit none private - public :: PUT_GOUTPUT_3D + public :: put_output - contains +contains - SUBROUTINE PUT_GOUTPUT_3D(istart_sim,istart_in,numtim) - ! --------------------------------------------------------------------------------------- + subroutine put_output(fuseStruct, istart_sim, istart_in, numtim) + + ! ------------------------------------------------------------------------------------- ! Creator: ! -------- ! Nans Addor, based on Martyn Clark's 2007 PUT_OUTPUT - ! Modified by Marytn Clark to use the elevation band dimension and add parameter derivatives, 12/2025 - ! --------------------------------------------------------------------------------------- + ! Modified by Martyn Clark to use the elevation band dimension and add parameter derivatives, 12/2025 + ! Modified by Martyn Clark to use output buffers in fuseStruct + ! ------------------------------------------------------------------------------------- ! Purpose: ! -------- - ! write a 3D (or 4D) data structure to the NetCDF output file - ! --------------------------------------------------------------------------------------- + ! Write a 3D (or 4D) data structure to the NetCDF output file (chunk write) + ! ------------------------------------------------------------------------------------- ! subroutines - USE varextract_module, only: VAREXTRACT_3d ! interface for the function to extract variables - - ! data - USE model_defn, only: FNAME_NETCDF_RUNS ! model definition (includes filename) - USE metaoutput, only: NOUTVAR ! number of output variables - USE metaoutput, only: VNAME, LNAME, VUNIT ! metadata for all model variables - USE metaoutput, only: isBand ! logical flag to define vars with elevation dimension - USE multiparam, only: NUMPAR ! variables for parameters - USE multibands, only: MBANDS_VAR_4d, N_BANDS ! variables for elevation bands - USE multiforce, only: timDat,time_steps ! time data - USE multiforce, only: nspat1,nspat2,startSpat2 ! spatial dimensions - USE multiforce, only: gForce_3d ! test only - USE multiforce, only: GRID_FLAG ! .true. if distributed - USE globaldata, only: ncid_out ! NetCDF output file ID - USE fuse_fileManager, only: Q_ONLY ! only write streamflow to output file? - - IMPLICIT NONE + use varextract_module, only: varextract_3d + + ! metadata / config + use model_defn, only: fname_netcdf_runs + use metaoutput, only: noutvar, vname, isband + use multiparam, only: numpar + use multibands, only: mbands_var_4d, n_bands + use multiforce, only: time_steps, nspat1, nspat2 + use fuse_filemanager, only: q_only + + ! global + use globaldata, only: ncid_out + + implicit none ! input - INTEGER(I4B), INTENT(IN) :: istart_sim ! index start time step relative to numtim_sim - INTEGER(I4B), INTENT(IN) :: istart_in ! index start time step relative to numtim_in - for time dimension - INTEGER(I4B), INTENT(IN) :: numtim ! number of time steps to write - - ! internal - LOGICAL(LGT) :: WRITE_VAR ! used to denote if the variable is written - INTEGER(I4B) :: IERR ! error code - integer(i4b), dimension(3) :: start3 ! start indices: exclude elevation bands and parameters - integer(i4b), dimension(3) :: count3 ! count indices: exclude elevation bands and parameters - integer(i4b), dimension(4) :: start4_band ! start indices: include elevation bands - integer(i4b), dimension(4) :: count4_band ! count indices: include elevation bands - integer(i4b), dimension(4) :: start4_param ! start indices: include parameters - integer(i4b), dimension(4) :: count4_param ! count indices: include parameters - INTEGER(I4B) :: IVAR ! loop through variables - REAL(SP) :: XVAR ! desired variable (SP NOT NECESSARILY SP) - REAL(MSP) :: AVAR ! desired variable (SINGLE PRECISION) - REAL(SP), DIMENSION(nspat1,nspat2,numtim) :: XVAR_3d ! desired 3-d variable (SINGLE PRECISION) - REAL(MSP), DIMENSION(nspat1,nspat2,numtim) :: AVAR_3d ! desired 3-d variable (SINGLE PRECISION) - REAL(SP), DIMENSION(nspat1,nspat2,n_bands,numtim) :: XVAR_4d_band ! desired 4-d variable (SINGLE PRECISION) - REAL(MSP), DIMENSION(nspat1,nspat2,n_bands,numtim) :: AVAR_4d_band ! desired 4-d variable (SINGLE PRECISION) - REAL(SP), DIMENSION(nspat1,nspat2,NUMPAR,numtim) :: XVAR_4d_param ! desired 4-d variable (SINGLE PRECISION) - REAL(MSP), DIMENSION(nspat1,nspat2,NUMPAR,numtim) :: AVAR_4d_param ! desired 4-d variable (SINGLE PRECISION) - REAL(MSP), DIMENSION(numtim) :: tDat ! time data - REAL(SP), DIMENSION(numtim) :: time_steps_sub ! time data - INTEGER(I4B) :: IVAR_ID ! variable ID - - INCLUDE 'netcdf.inc' ! use netCDF libraries - - - ! define dimension list (exclude elevation bands) - ! NOTE: if enabling parallel output you need 1,startSpat2 instead of 1,1 below - start3 = (/1,1,istart_sim/) - count3 = (/nspat1,nspat2,numtim/) - - ! define dimension list (include elevation bands) - start4_band = (/1,1,1,istart_sim/) - count4_band = (/nspat1,nspat2,n_bands,numtim/) - - ! define dimension list (include parameter derivatives) - start4_param = (/1,1,1,istart_sim/) - count4_param = (/nspat1,nspat2,NUMPAR,numtim/) - - ! open file - IERR = NF_OPEN(TRIM(FNAME_NETCDF_RUNS),NF_WRITE,ncid_out) - CALL HANDLE_ERR(IERR) + type(fuse_work), intent(in) :: fuseStruct + integer(i4b), intent(in) :: istart_sim + integer(i4b), intent(in) :: istart_in + integer(i4b), intent(in) :: numtim + + ! locals + logical(lgt) :: write_var + integer(i4b) :: ierr + integer(i4b) :: ivar + integer(i4b) :: ivar_id + + integer(i4b), dimension(3) :: start3, count3 + integer(i4b), dimension(4) :: start4_band, count4_band + integer(i4b), dimension(4) :: start4_param, count4_param + + real(real32), dimension(nspat1, nspat2, numtim) :: avar_3d + + real(real32), dimension(nspat1, nspat2, n_bands, numtim) :: avar_4d_band + ! placeholder for future param-derivative write + real(real32), dimension(nspat1, nspat2, numpar, numtim) :: avar_4d_param + + real(real32), dimension(numtim) :: time_steps_sub + + character(len=32) :: subname + subname="put_output.f90" + + ! ----------------------------------------------------------------------------- + ! dimension lists (Fortran nf90 uses 1-based indices) + start3 = (/1, 1, istart_sim/) + count3 = (/nspat1, nspat2, numtim/) + + start4_band = (/1, 1, 1, istart_sim/) + count4_band = (/nspat1, nspat2, n_bands, numtim/) + + start4_param = (/1, 1, 1, istart_sim/) + count4_param = (/nspat1, nspat2, numpar, numtim/) + + ! open file (already defined elsewhere via DEF_OUTPUT) + ierr = nf90_open(trim(fname_netcdf_runs), NF90_WRITE, ncid_out) + call handle_err(ierr, trim(subname)//":nf90_open") ! loop through variables with time-varying model output - DO IVAR=1,NOUTVAR - - ! check if there is a need to write the variable - see also def_output - IF (Q_ONLY) THEN - WRITE_VAR=.FALSE. - IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. - IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. - IF (.NOT.WRITE_VAR) CYCLE ! start new iteration of do loop, i.e. skip writting variable - ENDIF - - ! get variable ID - IERR = NF_INQ_VARID(ncid_out,TRIM(VNAME(IVAR)),IVAR_ID) - CALL HANDLE_ERR(IERR) - - ! 3-d variables - if(.not.isBand(iVar))then - - ! write 3-d matrix - XVAR_3d = VAREXTRACT_3d(VNAME(IVAR), nspat1, nspat2, numtim); AVAR_3d = XVAR_3d ! get variable and convert format - IERR = NF_PUT_VARA_REAL(ncid_out, IVAR_ID, start3, count3, AVAR_3d) ! write data - CALL HANDLE_ERR(IERR) - - ! 4-d variables + do ivar = 1, noutvar + + ! optional "Q_ONLY" filter + if (q_only) then + write_var = .false. + if (trim(vname(ivar)) == 'q_instnt') write_var = .true. + if (trim(vname(ivar)) == 'q_routed') write_var = .true. + if (.not. write_var) cycle + end if + + ! get var id + ierr = nf90_inq_varid(ncid_out, trim(vname(ivar)), ivar_id) + call handle_err(ierr, trim(subname)//":nf90_inq_varid:"//trim(vname(ivar))) + + if (.not. isband(ivar)) then + + ! 3-d variable -- extract from the output buffers in fuseStruct%chunk + call varextract_3d(fuseStruct%chunk, vname(ivar), nspat1, nspat2, numtim, avar_3d) + + ierr = nf90_put_var(ncid_out, ivar_id, avar_3d, start=start3, count=count3) + call handle_err(ierr, trim(subname)//":nf90_put_var(3d):"//trim(vname(ivar))) + else - ! extract variable from 4-D elevation band matrix - select case (trim(VNAME(IVAR))) - case ('swe_z' ); AVAR_4d_band = MBANDS_VAR_4d(:,:,:,1:numtim)%SWE - case ('snwacml_z'); AVAR_4d_band = MBANDS_VAR_4d(:,:,:,1:numtim)%SNOWACCMLTN - case ('snwmelt_z'); AVAR_4d_band = MBANDS_VAR_4d(:,:,:,1:numtim)%SNOWMELT - case default; stop "put_output.f90: cannot identify elevation band variable: "//trim(VNAME(IVAR)) + ! 4-d elevation band variable (stored in MBANDS_VAR_4d) + select case (trim(vname(ivar))) + case ('swe_z'); avar_4d_band = mbands_var_4d(:,:,:,1:numtim)%swe + case ('snwacml_z'); avar_4d_band = mbands_var_4d(:,:,:,1:numtim)%snowaccmltn + case ('snwmelt_z'); avar_4d_band = mbands_var_4d(:,:,:,1:numtim)%snowmelt + case default; stop trim(subname)//":unknown band var:"//trim(vname(ivar)) end select - ! write 4-d matrix for elevation bands - IERR = NF_PUT_VARA_REAL(ncid_out, IVAR_ID, START4_band, COUNT4_band, AVAR_4d_band) - call HANDLE_ERR(IERR) + ierr = nf90_put_var(ncid_out, ivar_id, avar_4d_band, start=start4_band, count=count4_band) + call handle_err(ierr, trim(subname)//":nf90_put_var(4d band):"//trim(vname(ivar))) - endif ! (switch between 3-d and 4-d variables) + end if - ! ! write the parameter sensitivity for each flux: extra variable - ! if(isFlux(iVar))then - ! AVAR_4d_param = fuseStruct%df_dPar(:) - ! endif + ! future: param-derivative writes would go here using count4_param/start4_param + ! e.g. name = trim(vname(ivar))//'__dFlux_dParam' - END DO ! (ivar) + end do - ! write the time - time_steps_sub = time_steps(istart_in:(istart_in+numtim-1)) ! extract time for subperiod - tDat = time_steps_sub ! convert to actual single precision - ierr = nf_inq_varid(ncid_out,'time',ivar_id); CALL handle_err(ierr) ! get variable ID for time - ierr = nf_put_vara_real(ncid_out,ivar_id,(/istart_sim/),(/numtim/),tDat); CALL handle_err(ierr) ! write time variable + ! write time + time_steps_sub = real(time_steps(istart_in:(istart_in + numtim - 1)), kind(real32)) - ! close NetCDF file - IERR = NF_CLOSE(ncid_out) + ierr = nf90_inq_varid(ncid_out, 'time', ivar_id) + call handle_err(ierr, trim(subname)//":nf90_inq_varid:time") - END SUBROUTINE PUT_GOUTPUT_3D + ierr = nf90_put_var(ncid_out, ivar_id, time_steps_sub, start=(/istart_sim/), count=(/numtim/)) + call handle_err(ierr, trim(subname)//":nf90_put_var:time") - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- + ! close + ierr = nf90_close(ncid_out) + call handle_err(ierr, trim(subname)//":nf90_close") - SUBROUTINE PUT_OUTPUT(iSpat1, iSpat2, ITIM) + end subroutine put_output - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2007 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! write NetCDF output files - ! --------------------------------------------------------------------------------------- - - ! subroutines - USE varextract_module, only: VAREXTRACT ! interface for the function to extract variables - - ! data - USE model_defn, only: FNAME_NETCDF_RUNS ! model definition (includes filename) - USE metaoutput, only: NOUTVAR ! number of output variables - USE metaoutput, only: VNAME, LNAME, VUNIT ! metadata for all model variables - USE metaoutput, only: isBand ! logical flag to define vars with elevation dimension - USE multibands, only: MBANDS, N_BANDS ! variables for elevation bands - USE multiforce, only: timDat,time_steps ! time data - USE multiforce, only: nspat1,nspat2,startSpat2 ! spatial dimensions - USE multiforce, only: gForce_3d ! test only - USE multiforce, only: GRID_FLAG ! .true. if distributed - USE globaldata, only: ncid_out ! NetCDF output file ID - USE fuse_fileManager, only: Q_ONLY ! only write streamflow to output file? - - IMPLICIT NONE - ! input - INTEGER(I4B), INTENT(IN) :: iSpat1 ! index of 1st spatial dimension - INTEGER(I4B), INTENT(IN) :: iSpat2 ! index of 2nd spatial dimension - INTEGER(I4B), INTENT(IN) :: ITIM ! time step index - ! internal - LOGICAL(LGT) :: WRITE_VAR ! used to denote if the variable is written - INTEGER(I4B) :: IERR ! error code - !INTEGER(I4B), DIMENSION(5) :: INDX ! indices for time series write - INTEGER(I4B), DIMENSION(3) :: INDX ! indices for time series write - INTEGER(I4B) :: IVAR ! loop through variables - REAL(SP) :: XVAR ! desired variable (SP NOT NECESSARILY SP) - REAL(MSP) :: AVAR ! desired variable (SINGLE PRECISION) - REAL(MSP) :: tDat ! time data - INTEGER(I4B) :: IVAR_ID ! variable ID - INCLUDE 'netcdf.inc' ! use netCDF libraries - ! --------------------------------------------------------------------------------------- - - ! open file - IERR = NF_OPEN(TRIM(FNAME_NETCDF_RUNS),NF_WRITE,ncid_out); CALL HANDLE_ERR(IERR) - - ! define indices for model output - INDX = (/iSpat1, iSpat2, ITIM/) - - ! loop through time-varying model output - DO IVAR=1,NOUTVAR - - ! check if there is a need to write the variable - see also def_output - IF (Q_ONLY) THEN - WRITE_VAR=.FALSE. - IF (TRIM(VNAME(IVAR)).EQ.'q_instnt') WRITE_VAR=.TRUE. - IF (TRIM(VNAME(IVAR)).EQ.'q_routed') WRITE_VAR=.TRUE. - IF (.NOT.WRITE_VAR) CYCLE - ENDIF - - ! write the variable - XVAR = VAREXTRACT(VNAME(IVAR)); AVAR=XVAR ! get variable ivar - IERR = NF_INQ_VARID(ncid_out,TRIM(VNAME(IVAR)),IVAR_ID); CALL HANDLE_ERR(IERR) ! get variable ID - IERR = NF_PUT_VAR1_REAL(ncid_out,IVAR_ID,INDX,AVAR); CALL HANDLE_ERR(IERR) ! write data - - END DO ! (ivar) - - ! write the time - tDat = timDat%dtime ! convert to actual single precision - ierr = nf_inq_varid(ncid_out,'time',ivar_id); CALL handle_err(ierr) ! get variable ID for time - ierr = nf_put_var1_real(ncid_out,ivar_id,(/itim/),tDat); CALL handle_err(ierr) ! write time variable - - ! close NetCDF file - IERR = NF_CLOSE(ncid_out) - - END SUBROUTINE PUT_OUTPUT - -END MODULE PUT_OUTPUT_MODULE +end module put_output_module diff --git a/build/FUSE_SRC/types/work_types.f90 b/build/FUSE_SRC/types/work_types.f90 index f239056..cbe94c7 100644 --- a/build/FUSE_SRC/types/work_types.f90 +++ b/build/FUSE_SRC/types/work_types.f90 @@ -16,6 +16,7 @@ module work_types private public :: bands_var_diff, ebands + public :: fuse_chunk public :: fuse_work ! -------------------------------------------------------------------------------------- @@ -67,11 +68,11 @@ module work_types real(sp), allocatable :: dL_dPar(:) ! derivative in loss function w.r.t. parameters end type fuse_adjoint - ! output chunk buffers (allocate per chunk) - type fuse_outputs + ! chunk buffers (allocate per chunk) + type fuse_chunk type(fluxes), allocatable :: w_flux_3d(:,:,:) ! (nspat1,nspat2,chunk_len) type(runoff), allocatable :: aroute_3d(:,:,:) ! (nspat1,nspat2,chunk_len) - end type + end type fuse_chunk ! run-level / evaluation-level type fuse_run @@ -86,7 +87,7 @@ module work_types type(fuse_snow) :: snow ! snow structure type(fuse_param) :: par ! parameter structure type(fuse_adjoint) :: adj ! adjoint structure (differentiable fuse) - type(fuse_outputs) :: buf ! output buffer + type(fuse_chunk) :: chunk ! chunk buffer type(fuse_run) :: run ! run-level structure logical(lgt) :: is_initialized = .false. end type fuse_work diff --git a/build/FUSE_SRC/util/varextract.f90 b/build/FUSE_SRC/util/varextract.f90 index dbb1767..e643675 100644 --- a/build/FUSE_SRC/util/varextract.f90 +++ b/build/FUSE_SRC/util/varextract.f90 @@ -1,45 +1,32 @@ -MODULE VAREXTRACT_MODULE +module varextract_module - USE nrtype ! variable types, etc. - - IMPLICIT NONE + use nrtype + use iso_fortran_env, only: real32 + use work_types, only: fuse_chunk + use globaldata, only: NA_VALUE_SP + implicit none private - public :: VAREXTRACT_3d - public :: VAREXTRACT + public :: varextract_3d - CONTAINS - - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - PURE FUNCTION VAREXTRACT_3d(VARNAME,nspat1,nspat2,numtim) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Nans Addor, based on Martyn Clark's 2007 VAREXTRACT - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Extracts variable "VARNAME" from relevant data structures +contains + + subroutine varextract_3d(chunk, varname, nspat1, nspat2, numtim, xout) ! --------------------------------------------------------------------------------------- - USE model_numerix ! model numerix parameters - USE globaldata, only: NA_VALUE_SP ! missing value + USE model_numerix USE multiforce, only: gForce_3d, aValid ! model forcing data USE multistate, only: gState_3d ! model states USE multi_flux, only: w_flux_3d ! model fluxes USE multiroute, only: aroute_3d ! routed runoff - IMPLICIT NONE - ! input - CHARACTER(*), INTENT(IN) :: VARNAME ! variable name - INTEGER(i4b), INTENT(IN) :: nspat1,nspat2 ! number of elements in spat1, spat2 (lon, lat) - INTEGER(i4b), INTENT(IN) :: numtim ! number of time steps - ! internal - real(sp), DIMENSION(nspat1,nspat2,numtim) :: XVAR_3d ! variable - integer(i4b) :: ierr ! error code - CHARACTER(LEN=1024) :: MESSAGE ! error message - ! output - real(sp), DIMENSION(nspat1,nspat2,numtim) :: VAREXTRACT_3d ! FUNCTION name - + implicit none + + type(fuse_chunk), intent(in) :: chunk + character(*), intent(in) :: varname + integer(i4b), intent(in) :: nspat1, nspat2, numtim + + ! NetCDF output buffer (matches NF90_FLOAT) + real(real32), intent(out) :: xout(nspat1, nspat2, numtim) + ! --------------------------------------------------------------------------------------- ! the length of the temporal dimension of the state variables (gState_3d and MBANDS_VAR_4d) ! is greater by one time step, so only keeping first numtim time steps, i.e. not writing @@ -48,200 +35,82 @@ PURE FUNCTION VAREXTRACT_3d(VARNAME,nspat1,nspat2,numtim) SELECT CASE (TRIM(VARNAME)) ! extract forcing data - CASE ('ppt') ; XVAR_3d = gForce_3d%PPT - CASE ('temp') ; XVAR_3d = gForce_3d%TEMP - CASE ('pet') ; XVAR_3d = gForce_3d%PET + CASE ('ppt') ; xout = real(gForce_3d(:,:,1:numtim)%PPT , kind=real32) + CASE ('temp') ; xout = real(gForce_3d(:,:,1:numtim)%TEMP, kind=real32) + CASE ('pet') ; xout = real(gForce_3d(:,:,1:numtim)%PET , kind=real32) ! extract response data - CASE ('obsq') ; XVAR_3d = aValid%OBSQ + ! TODO: Check this -- it is weird that obs q is 3d + CASE ('obsq') ; xout = real(aValid(:,:,1:numtim)%OBSQ, kind=real32) ! extract model states - CASE ('tens_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1 - CASE ('tens_1a') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1A - CASE ('tens_1b') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_1B - CASE ('free_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_1 - CASE ('watr_1') ; XVAR_3d = gState_3d(:,:,1:numtim)%WATR_1 - CASE ('tens_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%TENS_2 - CASE ('free_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2 - CASE ('free_2a') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2A - CASE ('free_2b') ; XVAR_3d = gState_3d(:,:,1:numtim)%FREE_2B - CASE ('watr_2') ; XVAR_3d = gState_3d(:,:,1:numtim)%WATR_2 - CASE ('swe_tot') ; XVAR_3d = gState_3d(:,:,1:numtim)%swe_tot + CASE ('tens_1') ; xout = real(gState_3d(:,:,1:numtim)%TENS_1 , kind=real32) + CASE ('tens_1a') ; xout = real(gState_3d(:,:,1:numtim)%TENS_1A, kind=real32) + CASE ('tens_1b') ; xout = real(gState_3d(:,:,1:numtim)%TENS_1B, kind=real32) + CASE ('free_1') ; xout = real(gState_3d(:,:,1:numtim)%FREE_1 , kind=real32) + CASE ('watr_1') ; xout = real(gState_3d(:,:,1:numtim)%WATR_1 , kind=real32) + CASE ('tens_2') ; xout = real(gState_3d(:,:,1:numtim)%TENS_2 , kind=real32) + CASE ('free_2') ; xout = real(gState_3d(:,:,1:numtim)%FREE_2 , kind=real32) + CASE ('free_2a') ; xout = real(gState_3d(:,:,1:numtim)%FREE_2A, kind=real32) + CASE ('free_2b') ; xout = real(gState_3d(:,:,1:numtim)%FREE_2B, kind=real32) + CASE ('watr_2') ; xout = real(gState_3d(:,:,1:numtim)%WATR_2 , kind=real32) + CASE ('swe_tot') ; xout = real(gState_3d(:,:,1:numtim)%swe_tot, kind=real32) ! extract model fluxes - CASE ('eff_ppt') ; XVAR_3d = W_FLUX_3d%EFF_PPT - CASE ('satarea') ; XVAR_3d = W_FLUX_3d%SATAREA - CASE ('qsurf') ; XVAR_3d = W_FLUX_3d%QSURF - CASE ('evap_1a') ; XVAR_3d = W_FLUX_3d%EVAP_1A - CASE ('evap_1b') ; XVAR_3d = W_FLUX_3d%EVAP_1B - CASE ('evap_1') ; XVAR_3d = W_FLUX_3d%EVAP_1 - CASE ('evap_2') ; XVAR_3d = W_FLUX_3d%EVAP_2 - CASE ('rchr2excs') ; XVAR_3d = W_FLUX_3d%RCHR2EXCS - CASE ('tens2free_1'); XVAR_3d = W_FLUX_3d%TENS2FREE_1 - CASE ('oflow_1') ; XVAR_3d = W_FLUX_3d%OFLOW_1 - CASE ('tens2free_2'); XVAR_3d = W_FLUX_3d%TENS2FREE_2 - CASE ('qintf_1') ; XVAR_3d = W_FLUX_3d%QINTF_1 - CASE ('qperc_12') ; XVAR_3d = W_FLUX_3d%QPERC_12 - CASE ('qbase_2') ; XVAR_3d = W_FLUX_3d%QBASE_2 - CASE ('qbase_2a') ; XVAR_3d = W_FLUX_3d%QBASE_2A - CASE ('qbase_2b') ; XVAR_3d = W_FLUX_3d%QBASE_2B - CASE ('oflow_2') ; XVAR_3d = W_FLUX_3d%OFLOW_2 - CASE ('oflow_2a') ; XVAR_3d = W_FLUX_3d%OFLOW_2A - CASE ('oflow_2b') ; XVAR_3d = W_FLUX_3d%OFLOW_2B + CASE ('eff_ppt') ; xout = real(W_FLUX_3d(:,:,1:numtim)%EFF_PPT , kind=real32) + CASE ('satarea') ; xout = real(W_FLUX_3d(:,:,1:numtim)%SATAREA , kind=real32) + CASE ('qsurf') ; xout = real(W_FLUX_3d(:,:,1:numtim)%QSURF , kind=real32) + CASE ('evap_1a') ; xout = real(W_FLUX_3d(:,:,1:numtim)%EVAP_1A , kind=real32) + CASE ('evap_1b') ; xout = real(W_FLUX_3d(:,:,1:numtim)%EVAP_1B , kind=real32) + CASE ('evap_1') ; xout = real(W_FLUX_3d(:,:,1:numtim)%EVAP_1 , kind=real32) + CASE ('evap_2') ; xout = real(W_FLUX_3d(:,:,1:numtim)%EVAP_2 , kind=real32) + CASE ('rchr2excs') ; xout = real(W_FLUX_3d(:,:,1:numtim)%RCHR2EXCS , kind=real32) + CASE ('tens2free_1'); xout = real(W_FLUX_3d(:,:,1:numtim)%TENS2FREE_1, kind=real32) + CASE ('oflow_1') ; xout = real(W_FLUX_3d(:,:,1:numtim)%OFLOW_1 , kind=real32) + CASE ('tens2free_2'); xout = real(W_FLUX_3d(:,:,1:numtim)%TENS2FREE_2, kind=real32) + CASE ('qintf_1') ; xout = real(W_FLUX_3d(:,:,1:numtim)%QINTF_1 , kind=real32) + CASE ('qperc_12') ; xout = real(W_FLUX_3d(:,:,1:numtim)%QPERC_12 , kind=real32) + CASE ('qbase_2') ; xout = real(W_FLUX_3d(:,:,1:numtim)%QBASE_2 , kind=real32) + CASE ('qbase_2a') ; xout = real(W_FLUX_3d(:,:,1:numtim)%QBASE_2A , kind=real32) + CASE ('qbase_2b') ; xout = real(W_FLUX_3d(:,:,1:numtim)%QBASE_2B , kind=real32) + CASE ('oflow_2') ; xout = real(W_FLUX_3d(:,:,1:numtim)%OFLOW_2 , kind=real32) + CASE ('oflow_2a') ; xout = real(W_FLUX_3d(:,:,1:numtim)%OFLOW_2A , kind=real32) + CASE ('oflow_2b') ; xout = real(W_FLUX_3d(:,:,1:numtim)%OFLOW_2B , kind=real32) ! extract extrapolation errors - CASE ('err_tens_1') ; XVAR_3d = W_FLUX_3d%ERR_TENS_1 - CASE ('err_tens_1a'); XVAR_3d = W_FLUX_3d%ERR_TENS_1A - CASE ('err_tens_1b'); XVAR_3d = W_FLUX_3d%ERR_TENS_1B - CASE ('err_free_1') ; XVAR_3d = W_FLUX_3d%ERR_FREE_1 - CASE ('err_watr_1') ; XVAR_3d = W_FLUX_3d%ERR_WATR_1 - CASE ('err_tens_2') ; XVAR_3d = W_FLUX_3d%ERR_TENS_2 - CASE ('err_free_2') ; XVAR_3d = W_FLUX_3d%ERR_FREE_2 - CASE ('err_free_2a'); XVAR_3d = W_FLUX_3d%ERR_FREE_2A - CASE ('err_free_2b'); XVAR_3d = W_FLUX_3d%ERR_FREE_2B - CASE ('err_watr_2') ; XVAR_3d = W_FLUX_3d%ERR_WATR_2 + CASE ('err_tens_1') ; xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_TENS_1 , kind=real32) + CASE ('err_tens_1a'); xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_TENS_1A, kind=real32) + CASE ('err_tens_1b'); xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_TENS_1B, kind=real32) + CASE ('err_free_1') ; xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_FREE_1 , kind=real32) + CASE ('err_watr_1') ; xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_WATR_1 , kind=real32) + CASE ('err_tens_2') ; xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_TENS_2 , kind=real32) + CASE ('err_free_2') ; xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_FREE_2 , kind=real32) + CASE ('err_free_2a'); xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_FREE_2A, kind=real32) + CASE ('err_free_2b'); xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_FREE_2B, kind=real32) + CASE ('err_watr_2') ; xout = real(W_FLUX_3d(:,:,1:numtim)%ERR_WATR_2 , kind=real32) ! time check - CASE ('chk_time') ; XVAR_3d = W_FLUX_3d%CHK_TIME + CASE ('chk_time') ; xout = real(W_FLUX_3d(:,:,1:numtim)%CHK_TIME, kind=real32) ! extract model runoff - CASE ('q_instnt') ; XVAR_3d = AROUTE_3d%Q_INSTNT - CASE ('q_routed') ; XVAR_3d = AROUTE_3d%Q_ROUTED + CASE ('q_instnt') ; xout = real(AROUTE_3d(:,:,1:numtim)%Q_INSTNT, kind=real32) + CASE ('q_routed') ; xout = real(AROUTE_3d(:,:,1:numtim)%Q_ROUTED, kind=real32) ! extract information on numerical solution (shared in MODULE model_numerix) - CASE ('num_funcs') ; XVAR_3d = NUM_FUNCS - CASE ('numjacobian'); XVAR_3d = NUM_JACOBIAN - CASE ('sub_accept') ; XVAR_3d = NUMSUB_ACCEPT - CASE ('sub_reject') ; XVAR_3d = NUMSUB_REJECT - CASE ('sub_noconv') ; XVAR_3d = NUMSUB_NOCONV - CASE ('max_iterns') ; XVAR_3d = MAXNUM_ITERNS + ! TODO: Check the need for this -- broadcasting scalars to the 3-d field + CASE ('num_funcs') ; xout = real(NUM_FUNCS , kind=real32) + CASE ('numjacobian'); xout = real(NUM_JACOBIAN , kind=real32) + CASE ('sub_accept') ; xout = real(NUMSUB_ACCEPT, kind=real32) + CASE ('sub_reject') ; xout = real(NUMSUB_REJECT, kind=real32) + CASE ('sub_noconv') ; xout = real(NUMSUB_NOCONV, kind=real32) + CASE ('max_iterns') ; xout = real(MAXNUM_ITERNS, kind=real32) ! default - case default; XVAR_3d = NA_VALUE_SP + case default; xout = NA_VALUE_SP END SELECT - ! save the output - VAREXTRACT_3d = XVAR_3d - - ! --------------------------------------------------------------------------------------- - END FUNCTION VAREXTRACT_3d - - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - ! --------------------------------------------------------------------------------------- - - ! --------------------------------------------------------------------------------------- - PURE FUNCTION VAREXTRACT(VARNAME) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2007 - ! Modified by Brian Henn to include snow model, 6/2013 - ! Modified by Nans Addor to enable distributed modeling, 9/2016 - ! Modified by Martyn Clark to use dimension for elevation bands, 12/2025 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Extracts variable "VARNAME" from relevant data structures - ! --------------------------------------------------------------------------------------- - USE model_numerix ! model numerix parameters - USE globaldata, only: NA_VALUE_SP ! missing value - USE multiforce, only: MFORCE, valDat ! model forcing data - USE multistate, only: FSTATE ! model states - USE multi_flux, only: W_FLUX ! model fluxes - USE multiroute, only: MROUTE ! routed runoff - IMPLICIT NONE - ! input - CHARACTER(*), INTENT(IN) :: VARNAME ! variable name - ! internal - REAL(SP) :: XVAR ! variable - ! output - REAL(SP) :: VAREXTRACT ! FUNCTION name - ! --------------------------------------------------------------------------------------- - SELECT CASE (TRIM(VARNAME)) - - ! extract forcing data - CASE ('ppt') ; XVAR = MFORCE%PPT - CASE ('temp') ; XVAR = MFORCE%TEMP - CASE ('pet') ; XVAR = MFORCE%PET - - ! extract response data - CASE ('obsq') ; XVAR = valDat%OBSQ - - ! extract model states - CASE ('tens_1') ; XVAR = FSTATE%TENS_1 - CASE ('tens_1a') ; XVAR = FSTATE%TENS_1A - CASE ('tens_1b') ; XVAR = FSTATE%TENS_1B - CASE ('free_1') ; XVAR = FSTATE%FREE_1 - CASE ('watr_1') ; XVAR = FSTATE%WATR_1 - CASE ('tens_2') ; XVAR = FSTATE%TENS_2 - CASE ('free_2') ; XVAR = FSTATE%FREE_2 - CASE ('free_2a') ; XVAR = FSTATE%FREE_2A - CASE ('free_2b') ; XVAR = FSTATE%FREE_2B - CASE ('watr_2') ; XVAR = FSTATE%WATR_2 - CASE ('swe_tot') ; XVAR = FSTATE%swe_tot - - ! extract model fluxes - CASE ('eff_ppt') ; XVAR = W_FLUX%EFF_PPT - CASE ('satarea') ; XVAR = W_FLUX%SATAREA - CASE ('qsurf') ; XVAR = W_FLUX%QSURF - CASE ('evap_1a') ; XVAR = W_FLUX%EVAP_1A - CASE ('evap_1b') ; XVAR = W_FLUX%EVAP_1B - CASE ('evap_1') ; XVAR = W_FLUX%EVAP_1 - CASE ('evap_2') ; XVAR = W_FLUX%EVAP_2 - CASE ('rchr2excs') ; XVAR = W_FLUX%RCHR2EXCS - CASE ('tens2free_1'); XVAR = W_FLUX%TENS2FREE_1 - CASE ('oflow_1') ; XVAR = W_FLUX%OFLOW_1 - CASE ('tens2free_2'); XVAR = W_FLUX%TENS2FREE_2 - CASE ('qintf_1') ; XVAR = W_FLUX%QINTF_1 - CASE ('qperc_12') ; XVAR = W_FLUX%QPERC_12 - CASE ('qbase_2') ; XVAR = W_FLUX%QBASE_2 - CASE ('qbase_2a') ; XVAR = W_FLUX%QBASE_2A - CASE ('qbase_2b') ; XVAR = W_FLUX%QBASE_2B - CASE ('oflow_2') ; XVAR = W_FLUX%OFLOW_2 - CASE ('oflow_2a') ; XVAR = W_FLUX%OFLOW_2A - CASE ('oflow_2b') ; XVAR = W_FLUX%OFLOW_2B - - ! extract extrapolation errors - CASE ('err_tens_1') ; XVAR = W_FLUX%ERR_TENS_1 - CASE ('err_tens_1a'); XVAR = W_FLUX%ERR_TENS_1A - CASE ('err_tens_1b'); XVAR = W_FLUX%ERR_TENS_1B - CASE ('err_free_1') ; XVAR = W_FLUX%ERR_FREE_1 - CASE ('err_watr_1') ; XVAR = W_FLUX%ERR_WATR_1 - CASE ('err_tens_2') ; XVAR = W_FLUX%ERR_TENS_2 - CASE ('err_free_2') ; XVAR = W_FLUX%ERR_FREE_2 - CASE ('err_free_2a'); XVAR = W_FLUX%ERR_FREE_2A - CASE ('err_free_2b'); XVAR = W_FLUX%ERR_FREE_2B - CASE ('err_watr_2') ; XVAR = W_FLUX%ERR_WATR_2 - - ! time check - CASE ('chk_time') ; XVAR = W_FLUX%CHK_TIME - - ! extract model runoff - CASE ('q_instnt') ; XVAR = MROUTE%Q_INSTNT - CASE ('q_routed') ; XVAR = MROUTE%Q_ROUTED - - ! extract information on numerical solution (shared in MODULE model_numerix) - CASE ('num_funcs') ; XVAR = NUM_FUNCS - CASE ('numjacobian'); XVAR = NUM_JACOBIAN - CASE ('sub_accept') ; XVAR = NUMSUB_ACCEPT - CASE ('sub_reject') ; XVAR = NUMSUB_REJECT - CASE ('sub_noconv') ; XVAR = NUMSUB_NOCONV - CASE ('max_iterns') ; XVAR = MAXNUM_ITERNS - - ! default - case default; XVAR = NA_VALUE_SP - - END SELECT - - ! and, save the output - VAREXTRACT = XVAR ! --------------------------------------------------------------------------------------- - END FUNCTION VAREXTRACT - - + END SUBROUTINE VAREXTRACT_3d END MODULE VAREXTRACT_MODULE diff --git a/build/Makefile b/build/Makefile index 503c9fc..2dd2586 100755 --- a/build/Makefile +++ b/build/Makefile @@ -166,7 +166,7 @@ G_DATA = $(SHARE_DIR)/globaldata.f90 FUSE_MODDEF = FUSE_MODDEF += $(TYPES_DIR)/model_defn_types.f90 FUSE_MODDEF += $(SHARE_DIR)/model_defn_data.f90 -MODDEF = $(FUSE_MODDEF) # no patetrn substitution needed +MODDEF = $(FUSE_MODDEF) # no pattern substitution needed # Data types FUSE_TYPES = @@ -365,7 +365,11 @@ endif ifeq ($(FC),gfortran) FFLAGS_NORMA = -O3 -ffree-line-length-none -fmax-errors=0 -cpp - FFLAGS_DEBUG = -g -Wall -ffree-line-length-none -fmax-errors=0 -fbacktrace -fcheck=bounds -cpp + FFLAGS_DEBUG = -O0 -g -fno-omit-frame-pointer \ + -Wall -Wextra -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable \ + -ffree-line-length-none -fmax-errors=0 -cpp \ + -fbacktrace -fcheck=all -ffpe-trap=invalid,zero,overflow \ + -finit-real=snan -finit-integer=-999999 FFLAGS_FIXED = -O2 -c -ffixed-form endif diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index 6c737d2..766b59f 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-18T23:03:15Z' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-19T17:28:43Z' character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/fuse-evaluate' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '7ae53258e9c118f5b41b8dc28cccb3c06919e2d6' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'b8f2947a48c6572ac6cd4d14a15a9adaedb1afbb' From dc8df16c4488b031b0c4a5902413e766eaac4d47 Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Fri, 20 Feb 2026 11:03:07 -0700 Subject: [PATCH 08/11] WIP refactor driver routines (model setup) --- build/FUSE_SRC/driver/fuse_driver.f90 | 563 +++++------------ build/FUSE_SRC/driver/fuse_evaluate.f90 | 3 +- build/FUSE_SRC/driver/sce_driver.f90 | 85 +++ build/FUSE_SRC/driver/setup_domain.f90 | 143 +++++ .../driver/setup_model_definition.f90 | 137 +++++ build/FUSE_SRC/netcdf/def_output.f90 | 20 +- build/FUSE_SRC/netcdf/def_params.f90 | 163 ++--- build/FUSE_SRC/netcdf/def_sstats.f90 | 151 ++--- build/FUSE_SRC/netcdf/domain_decomp.f90 | 133 ++++ build/FUSE_SRC/netcdf/get_mbands.f90 | 324 ++-------- build/FUSE_SRC/netcdf/slob | Bin 2578089 -> 0 bytes build/FUSE_SRC/physics/get_bundle.f90 | 2 + build/FUSE_SRC/prelim/assign_flx.f90 | 176 +++--- build/FUSE_SRC/prelim/assign_par.f90 | 407 +++++++------ build/FUSE_SRC/prelim/assign_stt.f90 | 130 ++-- build/FUSE_SRC/prelim/force_info.f90 | 4 +- build/FUSE_SRC/prelim/getparmeta.f90 | 173 +++--- build/FUSE_SRC/prelim/par_derive.f90 | 79 +-- build/FUSE_SRC/prelim/parse_command_args.f90 | 416 +++++++++++++ build/FUSE_SRC/prelim/uniquemodl.f90 | 288 ++++----- build/FUSE_SRC/runtime/get_time_windows.f90 | 340 +++++++++++ build/FUSE_SRC/share/multiparam_data.f90 | 5 + build/FUSE_SRC/types/info_types.f90 | 1 + build/FUSE_SRC/util/alloc_domain.f90 | 131 ++++ build/FUSE_SRC/util/alloc_scratch.f90 | 143 +++++ build/FUSE_SRC/util/fuse_fileManager.f90 | 569 ++++++++++++------ build/Makefile | 16 +- build/generated/fuseversion.inc | 6 +- 28 files changed, 2962 insertions(+), 1646 deletions(-) create mode 100644 build/FUSE_SRC/driver/sce_driver.f90 create mode 100644 build/FUSE_SRC/driver/setup_domain.f90 create mode 100644 build/FUSE_SRC/driver/setup_model_definition.f90 create mode 100644 build/FUSE_SRC/netcdf/domain_decomp.f90 delete mode 100755 build/FUSE_SRC/netcdf/slob create mode 100644 build/FUSE_SRC/prelim/parse_command_args.f90 create mode 100644 build/FUSE_SRC/runtime/get_time_windows.f90 create mode 100644 build/FUSE_SRC/util/alloc_domain.f90 create mode 100644 build/FUSE_SRC/util/alloc_scratch.f90 diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index 13e36e6..d315804 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -5,500 +5,211 @@ PROGRAM DISTRIBUTED_DRIVER ! Modified by Brian Henn to include snow model, 6/2013 ! Modified by Nans Addor to include distributed modeling, 9/2016 ! Modified by Nans Addor to re-enable catchment-scale modeling, 4/2017 -! Modified by Cyril Thébault to allow different metrics as objective function, 2024 +! Modified by Martyn Clark to modularize and simplify CLI, 12/2025 ! --------------------------------------------------------------------------------------- ! Purpose: ! Driver program to run FUSE with a snow module as either at the catchment-scale or ! at the grid-scale ! --------------------------------------------------------------------------------------- +! data types USE nrtype ! variable types, etc. -USE netcdf ! NetCDF library -USE fuse_fileManager,only:fuse_SetDirsUndPhiles,& ! sets directories and filenames - SETNGS_PATH,MBANDS_INFO,MBANDS_NC, & - OUTPUT_PATH,FORCINGINFO,INPUT_PATH,& - FMODEL_ID,& - suffix_forcing,suffix_elev_bands,& - numtim_sub_str,& - KSTOP_str, MAXN_str, PCENTO_str - -! data modules -USE model_defn,nstateFUSE=>nstate ! model definition structures -USE model_defnames ! defines the integer model options -USE globaldata, ONLY: isPrint ! flag for printing progress to screen -USE globaldata, only: nFUSE_eval ! number of fuse evaluations -USE multiforce, ONLY: forcefile,vname_aprecip ! model forcing structures -USE multiforce, ONLY: AFORCE, aValid ! time series of lumped forcing/response data -USE multiforce, ONLY: nspat1, nspat2 ! grid dimensions -USE multiforce, only: GRID_FLAG ! .true. if distributed -USE multiforce, ONLY: GFORCE, GFORCE_3d ! spatial arrays of gridded forcing data -USE multiforce, only: ancilF, ancilF_3d ! ancillary forcing data -USE multiforce, ONLY: valDat ! response data -USE multiforce, only: DELTIM -USE multiforce, only: ISTART ! index for start of inference -USE multiforce, ONLY: timeUnits,time_steps,julian_day_input ! time data -USE multiforce, only: numtim_in ! length of input time series -USE multiforce, only: numtim_sim ! length of simulated time series -USE multiforce, only: numtim_sub ! length of subperiod time series -USE multiforce, only: sim_beg,sim_end ! timestep indices -USE multiforce, only: eval_beg,eval_end ! timestep indices -USE multiforce, only: SUB_PERIODS_FLAG ! .true. if subperiods are used to run FUSE -USE multiforce, only: NUMPSET ! number of parameter sets - -USE multiforce, only: ncid_forc ! NetCDF forcing file ID -USE multiforce, only: ncid_var ! NetCDF forcing variable ID -USE multistate, only: ncid_out ! NetCDF output file ID - -USE multibands ! basin band stuctures -USE multiparam, ONLY: LPARAM, PARATT, NUMPAR ! parameter metadata structures -USE multistate, only: gState ! gridded state variables -USE multistate, only: gState_3d ! gridded state variables with a time dimension -USE multiroute, ONLY: AROUTE ! model routing structures -USE multiroute, ONLY: AROUTE_3d ! model routing structures with a time dimension -USE multistats ! model statistics structures - -! informational modules -USE selectmodl_module ! reads model control file -USE getpar_str_module ! extracts parameter metadata -USE par_insert_module ! inserts model parameters -USE force_info_module,only:force_info ! get forcing info for NetCDF files -USE def_output_module,only:def_output ! define NetCDF output file -USE get_gforce_module,only:read_ginfo ! get dimension lengths from the NetCDF file -USE get_gforce_module,only:get_varid ! get netCDF ID for forcing variables -USE get_gforce_module,only:get_gforce_3d ! get forcing -USE get_mbands_module,only:GET_MBANDS_INFO ! get elevation bands for snow modeling -USE get_fparam_module ! get SCE parameters from NetCDF file -USE GET_TIME_INDICES_MODULE ! get time indices -USE time_io - -! model numerix -USE model_numerix ! defines decisions on model numerix - -! access to model simulation modules -USE fuse_evaluate_module, only: fuse_evaluate ! run model and compute the metric chosen as objective function +USE info_types, only: cli_options ! command line interface options +USE info_types, only: fuse_info ! info structure (includes "everything") +USE data_types, only: domain_data ! domain data +USE multistats, only: PCOUNT ! counter + +! data +USE globaldata, only: isPrint +USE globaldata, only: ncid_out +USE multiparam, only: NUMPAR +USE multiforce, only: NUMPSET +USE multiforce, only: ncid_forc, GRID_FLAG, SUB_PERIODS_FLAG +USE multiForce, only: AFORCE, gForce, gForce_3d, aValid +USE multiState, only: gState, gState_3d +USE multiRoute, only: aRoute, AROUTE_3d + +! model setup: external subroutines/functions +USE netcdf ! NetCDF library +USE parse_command_args_MODULE, only: parse_command_args ! parse command line arguments +USE setup_domain_module, only: setup_domain ! initialize the model domain +USE setup_model_definition_module, only: setup_model_definition ! setup the FUSE model configuration + +! model run: external subroutines/functions +USE get_fparam_module, only: GET_PRE_PARAM, GET_SCE_PARAM ! read parameters from netcdf file +USE sce_driver_MODULE, only: sce_driver ! SCE optimization + +! model simulation modules +USE fuse_evaluate_module, only: fuse_evaluate ! run model and compute performance metrics #ifdef __MPI__ -use mpi + use mpi #endif + IMPLICIT NONE -! --------------------------------------------------------------------------------------- -! GET COMMAND-LINE ARGUMENTS... -! --------------------------------------------------------------------------------------- -CHARACTER(LEN=256) :: DatString ! file manager -CHARACTER(LEN=256) :: dom_id ! ID of the domain -CHARACTER(LEN=10) :: fuse_mode=' ' ! fuse execution mode (run_def, run_best, run_pre, calib_sce) -CHARACTER(LEN=256) :: file_param ! name of parameter file -CHARACTER(LEN=10) :: index_param ! index of desired parameter set +! error control +integer(i4b) :: err ! error code +character(len=1024) :: message ! error message -! --------------------------------------------------------------------------------------- -! SETUP MODELS FOR SIMULATION -- POPULATE DATA STRUCTURES -! --------------------------------------------------------------------------------------- -! fuse_file_manager -CHARACTER(LEN=1024) :: FFMFILE ! name of fuse_file_manager file -CHARACTER(LEN=1024) :: ELEV_BANDS_NC ! name of NetCDF file for elevation bands -! get model forcing data -INTEGER(I4B) :: NTIM ! number of time steps - still needed ? -INTEGER(I4B) :: INFERN_START ! start of inference period - still needed? -! get model setup -INTEGER(I4B) :: FUSE_ID ! integer defining FUSE model -INTEGER(I4B) :: NMOD ! number of models -INTEGER(I4B) :: ERR ! error code -CHARACTER(LEN=1024) :: MESSAGE ! error message -! get spatial option -CHARACTER(LEN=6) :: SPATIAL_OPTION ! spatial option (catch or grid) -INTEGER(I4B),PARAMETER :: LUMPED=0 ! named variable for lumped simulations -INTEGER(I4B),PARAMETER :: DISTRIBUTED=1 ! named variable for distributed simulations -! define model output -LOGICAL(LGT) :: OUTPUT_FLAG ! .TRUE. = write time series output -INTEGER(I4B) :: ONEMOD=1 ! just specify one model -! timers -INTEGER(I4B) :: T_start_import_forcing ! system clock -INTEGER(I4B) :: T_end_import_forcing ! system clock -! dummies -CHARACTER(LEN=100) :: dummy_string ! used for temporary data storage -integer(i4b) :: file_pass ! used read parameter list +! command line arguments +type(cli_options) :: cli_opts ! command line argument options -! --------------------------------------------------------------------------------------- -! RUN MODEL FOR DIFFERENT PARAMETER SETS -! --------------------------------------------------------------------------------------- -INTEGER(I4B) :: ITIM ! loop thru time steps -INTEGER(I4B) :: IPAR ! loop thru model parameters -INTEGER(I4B) :: IPSET ! index of desired model parameter set -TYPE(PARATT) :: PARAM_META ! parameter metadata (model parameters) +! parameter set; parameter bounds REAL(SP), DIMENSION(:), ALLOCATABLE :: BL ! vector of lower parameter bounds REAL(SP), DIMENSION(:), ALLOCATABLE :: BU ! vector of upper parameter bounds REAL(SP), DIMENSION(:), ALLOCATABLE :: APAR ! model parameter set -INTEGER(KIND=4) :: ISEED ! seed for the random sequence -REAL(KIND=4),DIMENSION(:), ALLOCATABLE :: URAND ! vector of quasi-random numbers U[0,1] -REAL(SP) :: METRIC_VAL ! error from the simulation -! --------------------------------------------------------------------------------------- -! SCE VARIABLES -! --------------------------------------------------------------------------------------- -REAL(MSP) :: AF_MSP ! objective function value -REAL(MSP), DIMENSION(:), ALLOCATABLE :: APAR_MSP ! ! lower bound of model parameters -REAL(MSP), DIMENSION(:), ALLOCATABLE :: BL_MSP ! ! lower bound of model parameters -REAL(MSP), DIMENSION(:), ALLOCATABLE :: BU_MSP ! ! upper bound of model parameters -REAL(MSP), DIMENSION(:), ALLOCATABLE :: URAND_MSP ! vector of quasi-random numbers U[0,1] -INTEGER(I4B) :: NOPT ! number of parameters to be optimized -INTEGER(I4B) :: KSTOP ! number of shuffling loops the value must change by PCENTO -INTEGER(I4B) :: MAXN ! maximum number of trials before optimization is terminated -REAL(MSP) :: PCENTO ! the percentage -CHARACTER(LEN=3) :: CSEED ! starting seed converted to a character -INTEGER(I4B) :: NGS ! # complexes in the initial population -INTEGER(I4B) :: NPG ! # points in each complex -INTEGER(I4B) :: NPS ! # points in a sub-complex -INTEGER(I4B) :: NSPL ! # evolution steps allowed for each complex before shuffling -INTEGER(I4B) :: MINGS ! minimum number of complexes required -INTEGER(I4B) :: INIFLG ! 1 = include initial point in the population -INTEGER(I4B) :: IPRINT ! 0 = supress printing -INTEGER(I4B) :: ISCE ! unit number for SCE write -REAL(MSP) :: FUNCTN ! function name for the model run - -! --------------------------------------------------------------------------------------- -! MPI variables -! --------------------------------------------------------------------------------------- -integer ( kind = 4 ) mpi_error_value -integer ( kind = 4 ) mpi_process -integer ( kind = 4 ) mpi_nprocesses -! --------------------------------------------------------------------------------------- -! Initialize MPI -! --------------------------------------------------------------------------------------- -#ifdef __MPI__ -call MPI_Init(mpi_error_value) -call MPI_Comm_size(MPI_COMM_WORLD, mpi_nprocesses, mpi_error_value) ! determine the number of processes involved in a communicator (mpi_nproccesses) -call MPI_Comm_rank(MPI_COMM_WORLD, mpi_process, mpi_error_value) ! determine the rank of the process in the particular communicator’s group. -#else -mpi_process = 0 -mpi_nprocesses = 1 -#endif +! function evaluation +REAL(SP) :: RMSE ! sim-obs differences -! --------------------------------------------------------------------------------------- -! READ COMMAND LINE ARGUMENTS -! --------------------------------------------------------------------------------------- -! read command-line arguments -CALL GETARG(1,DatString) ! string defining forcinginfo file -CALL GETARG(2,dom_id) ! ID of the domain -CALL GETARG(3,fuse_mode) ! fuse execution mode (run_def, run_best, calib_sce) -IF(TRIM(fuse_mode).EQ.'run_pre')then - CALL GETARG(4,file_param) ! name of parameter file - CALL GETARG(5,index_param) ! index of desired parameter set - IF(LEN_TRIM(index_param).EQ.0) IPSET = 1 - IF(LEN_TRIM(index_param).GT.0) read(index_param,*) IPSET -ENDIF - -! check command-line arguments -IF (LEN_TRIM(DatString).EQ.0) STOP '1st command-line argument is missing (fileManager)' -IF (LEN_TRIM(dom_id).EQ.0) STOP '2nd command-line argument is missing (dom_id)' -IF (LEN_TRIM(fuse_mode).EQ.0) STOP '3rd command-line argument is missing (fuse_mode)' -IF(TRIM(fuse_mode).EQ.'run_pre')THEN - IF(LEN_TRIM(file_param).EQ.0) STOP '4th command-line argument is missing (file_param) and is required in mode run_pre' -ENDIF - -! print command-line arguments -print*, '1st command-line argument (fileManager) = ', trim(DatString) -print*, '2nd command-line argument (dom_id) = ', trim(dom_id) -print*, '3rd command-line argument (fuse_mode) = ', fuse_mode -IF(TRIM(fuse_mode).EQ.'run_pre')THEN - print*, '4th command-line argument (file_param) = ', file_param - print*, '5th command-line argument (index_param) = ', IPSET -ENDIF - -! --------------------------------------------------------------------------------------- -! SET PATHS AND FILES NAME -! --------------------------------------------------------------------------------------- - -! set path to fuse_file_manager -FFMFILE=DatString ! must be in bin folder and you must be in bin to run FUSE - TODO read argument to FFMFILE directly - -! set directories and filenames for control files -call fuse_SetDirsUndPhiles(fuseFileManagerIn=FFMFILE,err=err,message=message) -if (err.ne.0) write(*,*) trim(message); if (err.gt.0) stop - -! define name of forcing info and elevation band file -forcefile= trim(dom_id)//suffix_forcing -ELEV_BANDS_NC=trim(dom_id)//suffix_elev_bands +! model output +LOGICAL(LGT) :: OUTPUT_FLAG ! .TRUE. = write time series output +INTEGER(I4B) :: ONEMOD=1 ! just specify one model -PRINT *, 'Variables defined based on domain name:' -PRINT *, 'forcefile:', TRIM(forcefile) -PRINT *, 'ELEV_BANDS_NC:', TRIM(ELEV_BANDS_NC) +! global domain data +type(fuse_info) :: info ! includes "everything" +type(domain_data) :: domain ! 3d/4d output buffers ! --------------------------------------------------------------------------------------- -! GET MODEL SETUP -- MODEL NUEMERICS, GRID, AND PARAMETER AND VARIABLE INFO FOR ALL MODELS +! ----- model preliminaries (initialize) ------------------------------------------------ ! --------------------------------------------------------------------------------------- -! defines method/parameters used for numerical solution based on numerix file -CALL GETNUMERIX(ERR,MESSAGE) - -! get forcing info from the txt file, ?? including NA_VALUE ?? -call force_info(fuse_mode,err,message) -if(err/=0)then; write(*,*) trim(message); stop; endif - -print *, 'Open forcing file:', trim(INPUT_PATH)//trim(forcefile) - -! open NetCDF forcing file -err = nf90_open(trim(INPUT_PATH)//trim(forcefile), nf90_nowrite, ncid_forc) -if (err.ne.0) write(*,*) trim(message); if (err.gt.0) stop -PRINT *, 'NCID_FORC is', ncid_forc - -! get the grid info (spatial and temporal dimensions) from the NetCDF file -call read_ginfo(ncid_forc,err,message) -if(err/=0)then; write(*,*) trim(message); stop; endif - -! determine period over which to run and evaluate FUSE and their associated indices -CALL GET_TIME_INDICES() - -IF((.NOT.GRID_FLAG).AND.SUB_PERIODS_FLAG)THEN; write(*,*) 'Error: in catchment mode, FUSE must run over entire time series at once, please set numtim_sub to -9999 in the filemanager (', trim(DatString),').'; stop; endif - -! allocate space for the basin/grid-average time series -allocate(aForce(numtim_sub),aRoute(numtim_sub),stat=err) -!allocate(aForce(numtim_sub),aRoute(numtim_sub),aValid(numtim_sub),stat=err) -if(err/=0)then; write(*,*) 'unable to allocate space for basin-average time series [aForce,aRoute]'; stop; endif - -! allocate space for the forcing grid and states -allocate(ancilF(nspat1,nspat2), gForce(nspat1,nspat2), gState(nspat1,nspat2), stat=err) -if(err/=0)then; write(*,*) 'unable to allocate space for forcing grid GFORCE'; stop; endif - -! allocate space for the forcing grid and states with a time dimension - only for subperiod -allocate(AROUTE_3d(nspat1,nspat2,numtim_sub), gState_3d(nspat1,nspat2,numtim_sub+1),gForce_3d(nspat1,nspat2,numtim_sub),aValid(nspat1,nspat2,numtim_sub),stat=err) -if(err/=0)then; write(*,*) 'unable to allocate space for 3d structure'; stop; endif - -! get elevation band info, in particular N_BANDS -CALL GET_MBANDS_INFO(ELEV_BANDS_NC,err,message) ! read band data from NetCDF file -if(err/=0)then; write(*,*) trim(message); stop; endif - -! allocate space for elevation bands -allocate(MBANDS_VAR_4d(nspat1,nspat2,N_BANDS,numtim_sub+1),stat=err) -if(err/=0)then; write(*,*) 'unable to allocate space for elevation bands'; stop; endif - -! get variable ID from the NetCDF file -call get_varID(ncid_forc,err,message) -if(err/=0)then; write(*,*) 'unable to get NetCDF variables ID'; stop; endif - -! Define model attributes (valid for all models) -CALL UNIQUEMODL(NMOD) ! get nmod unique models -CALL GETPARMETA(ERR,MESSAGE) ! read parameter metadata (parameter bounds etc.) - -IF (ERR.NE.0) WRITE(*,*) TRIM(MESSAGE); IF (ERR.GT.0) STOP - -! Identify a single model -CALL SELECTMODL(FMODEL_ID,ERR=ERR,MESSAGE=MESSAGE) -IF (ERR.NE.0) WRITE(*,*) TRIM(MESSAGE); IF (ERR.GT.0) STOP - -! Define list of states and parameters for the current model -CALL ASSIGN_STT() ! state definitions are stored in module model_defn -CALL ASSIGN_FLX() ! flux definitions are stored in module model_defn -CALL ASSIGN_PAR() ! parameter definitions are stored in module multiparam - -! Compute derived model parameters (bucket sizes, etc.) -CALL PAR_DERIVE(ERR,MESSAGE) -IF (ERR.NE.0) WRITE(*,*) TRIM(MESSAGE); IF (ERR.GT.0) STOP +! ----- initialize MPI ------------------------------------------------------------------ -! Define output and parameter files -ONEMOD=1 ! one file per model (i.e., model dimension = 1) -PCOUNT=0 ! counter for parameter sets evaluated (shared in MODULE multistats) - -IF(fuse_mode == 'run_def')THEN ! run FUSE with default parameter values - - ! files to which model run and parameter set will be saved #ifdef __MPI__ - write(FNAME_NETCDF_RUNS, "(A,I0.5,A)") TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_runs_def_', mpi_process, ".nc" - write(FNAME_NETCDF_PARA, "(A,I0.5,A)") TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_para_def_', mpi_process, ".nc" + info%mpi%enabled = .true. + call MPI_Init(err); call MPI_check(err, "MPI_Init") + call MPI_Comm_rank(MPI_COMM_WORLD, info%mpi%rank, err); call MPI_check(err, "MPI_Comm_rank") + call MPI_Comm_size(MPI_COMM_WORLD, info%mpi%nproc, err); call MPI_check(err, "MPI_Comm_size") #else - FNAME_NETCDF_RUNS = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_runs_def.nc' - FNAME_NETCDF_PARA = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_para_def.nc' + info%mpi%enabled = .false. + info%mpi%rank = 0 + info%mpi%nproc = 1 #endif - NUMPSET=1 ! only the default parameter set is run - -ELSE IF(fuse_mode == 'run_pre')THEN ! run FUSE with pre-defined parameter values - - ! files to which model run and parameter set will be saved - FNAME_NETCDF_RUNS = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_runs_pre.nc' - FNAME_NETCDF_PARA = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_para_pre_out.nc' +! suppress printing for higher ranks +if(info%mpi%rank > 0) isPrint=.false. - NUMPSET=1 ! only the one "desired" parameter set is run +! ----- parse command line arguments ---------------------------------------------------- -ELSE IF(fuse_mode == 'calib_sce')THEN ! calibrate FUSE using SCE +call parse_command_args(cli_opts,err,message) +if(err/=0) stop trim(message) - ! files to which model run and parameter set will be saved - FNAME_NETCDF_RUNS = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_runs_sce.nc' - FNAME_NETCDF_PARA = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_para_sce.nc' +if(isPrint)then + print*, 'Control file = ', cli_opts%control_file + print*, 'Run mode = ', cli_opts%runmode +endif - ! assign algorithmic control parameters for SCE - ! convert characters to interger/MSP - READ (MAXN_STR,*) MAXN ! maximum number of trials before optimization is terminated - READ (KSTOP_STR,*) KSTOP ! number of shuffling loops the value must change by PCENTO (MAX=9) - READ (PCENTO_STR,*) PCENTO ! the percentage +! ----- initialize the model domain ----------------------------------------------------- - PRINT *, 'SCE parameters read from file manager:' - PRINT *, 'Maximum number of trials before SCE optimization is stopped (MAXN) = ', MAXN_STR - PRINT *, 'Number of shuffling loops the value must change by PCENTO (KSTOP) = ', KSTOP_STR - PRINT *, 'PCENTO = ', PCENTO_STR +! read forcing metadata (space/time/coords), apply MPI decomposition, and allocate domain arrays +call setup_domain(cli_opts, info, domain, err, message) +if(err/=0) stop trim(message) - NOPT = NUMPAR ! number of parameters to be optimized (NUMPAR in module multiparam) - NGS = 10 ! number of complexes in the initial population - NPG = 2*NOPT + 1 ! number of points in each complex - NPS = NOPT + 1 ! number of points in a sub-complex - NSPL = 2*NOPT + 1 ! number of evolution steps allowed for each complex before shuffling - MINGS = NGS ! minimum number of complexes required - INIFLG = 1 ! 1 = include initial point in the population - IPRINT = 1 ! 0 = supress printing +! ----- initialize model configurations ------------------------------------------------- - NUMPSET=1.2*MAXN ! will be used to define the parameter set dimension of the NetCDF files - ! using 1.2MAXN since the final number of parameter sets produced by SCE is unknown +! choose model, load parameter metadata, derive parameters, and define NetCDF output files +call setup_model_definition(cli_opts, info, APAR, BL, BU, err, message) +if(err/=0) stop trim(message) -ELSE IF(fuse_mode == 'run_best')THEN ! run FUSE with "best" parameter set from a previous SCE calibration +! ----- set initial counters ------------------------------------------------------------ - ! file from which SCE parameters will be loaded - same as FNAME_NETCDF_PARA above - FNAME_NETCDF_PARA_SCE = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_para_sce.nc' - - ! files to which "best" SCE model run and parameter set will be saved - FNAME_NETCDF_RUNS = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_runs_best.nc' - FNAME_NETCDF_PARA = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_para_best.nc' - - NUMPSET=1 ! only the one "best" parameter set is run - -ELSE - - print *, 'Unexpected fuse_mode!' - -ENDIF +! Define output and parameter files +ONEMOD=1 ! one file per model (i.e., model dimension = 1) +PCOUNT=0 ! counter for parameter sets evaluated (shared in MODULE multistats) -CALL DEF_PARAMS(NUMPSET) ! define model parameters (initial CREATE) -CALL DEF_SSTATS() ! define summary statistics (REDEF) -CALL DEF_OUTPUT(nSpat1,nSpat2,N_BANDS,NUMPAR) ! define model output time series (REDEF) +stop '** finished preliminaries' ! --------------------------------------------------------------------------------------- -! RUN FUSE IN DESIRED MODE +! ----- run different FUSE modes -------------------------------------------------------- ! --------------------------------------------------------------------------------------- -! get parameter bounds and random numbers -ALLOCATE(APAR(NUMPAR),BL(NUMPAR),BU(NUMPAR),URAND(NUMPAR)) - -DO IPAR=1,NUMPAR - CALL GETPAR_STR(LPARAM(IPAR)%PARNAME,PARAM_META) - BL(IPAR) = PARAM_META%PARLOW ! lower boundary - BU(IPAR) = PARAM_META%PARUPP ! upper boundary - APAR(IPAR) = PARAM_META%PARDEF ! using default parameter values - !if(PARAM_META%PARFIT) print*, LPARAM(IPAR)%PARNAME, PARAM_META%PARDEF -END DO - -IF(fuse_mode == 'run_def')THEN ! run FUSE with default parameter values - - OUTPUT_FLAG=.TRUE. - - print *, 'Running FUSE with default parameter values' - CALL FUSE_evaluate(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,NUMPSET) - print *, 'Done running FUSE with default parameter values' - -ELSE IF(fuse_mode == 'run_pre')THEN ! run FUSE with pre-defined parameter values - - OUTPUT_FLAG=.TRUE. - - FNAME_NETCDF_PARA_PRE=TRIM(OUTPUT_PATH)//file_param - PRINT *, 'Loading parameter set ',IPSET,':' - - ! load specific parameter set - CALL GET_PRE_PARAM(FNAME_NETCDF_PARA_PRE,IPSET,ONEMOD,NUMPAR,APAR) - - print *, 'Running FUSE with pre-defined parameter set' - CALL FUSE_evaluate(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,1) ! last argument IPSET=1 - print *, 'Done running FUSE with pre-defined parameter set' - -ELSE IF(fuse_mode == 'calib_sce')THEN ! calibrate FUSE using SCE +! select fuse mode +select case(cli_opts%runmode) - ! Calibrate FUSE with SCE - OUTPUT_FLAG=.FALSE. + ! ----- single parameter set ---------------------------------------------------------- - FNAME_ASCII = TRIM(OUTPUT_PATH)//TRIM(dom_id)//'_'//TRIM(FMODEL_ID)//'_sce_output.txt' + case('def', 'idx', 'opt') - ! printing - isPrint = .false. ! turn off printing to screen - nFUSE_eval = 0 ! number of fuse evaluations + OUTPUT_FLAG=.TRUE. - ! convert from SP used in FUSE to MSP used in SCE - ALLOCATE(APAR_MSP(NUMPAR),BL_MSP(NUMPAR),BU_MSP(NUMPAR),URAND_MSP(NUMPAR)) + ! load specific parameter set given index in vector into APAR + if (cli_opts%runmode=='idx') then + CALL GET_PRE_PARAM(cli_opts%sets_file, cli_opts%indx, ONEMOD, NUMPAR, APAR) + endif - APAR_MSP=APAR - PRINT *, 'BL=',BL - BL_MSP=BL - BU_MSP=BU - URAND_MSP=URAND + ! load best parameter set from NetCDF file into APAR + if (cli_opts%runmode=='opt') then + CALL GET_SCE_PARAM(cli_opts%sets_file, ONEMOD, NUMPAR, APAR) + endif - ! set random seed - ISEED = 1 + ! run FUSE + CALL FUSE_EVALUATE(APAR, GRID_FLAG, NCID_FORC, RMSE, OUTPUT_FLAG, NUMPSET) - ! open up ASCII output file - print *, 'Creating SCE output file:', trim(FNAME_ASCII) - ISCE = 96; OPEN(ISCE,FILE=TRIM(FNAME_ASCII)) - ! set random seed - ISEED = 1 + ! ----- SCE calibration run ----------------------------------------------------------- - ! optimize (returns A and AF) - ! note that SCE requires the kind of APAR, BL, BU to be MSP - CALL SCEUA(APAR_MSP,AF_MSP,BL_MSP,BU_MSP,NOPT,MAXN,KSTOP,PCENTO,ISEED,& - NGS,NPG,NPS,NSPL,MINGS,INIFLG,IPRINT,ISCE) + case('sce') - ! close ASCII output file - CLOSE(ISCE) - - PRINT *, 'Done running SCE!' - - ! call the function again with the optimized parameter set (to ensure the last parameter set is the optimum) - !AF_MSP = FUNCTN(NOPT,AF_MSP) - - !PRINT *, 'Done calling the function again with the optimized parameter set!' - -ELSE IF(fuse_mode == 'run_best')THEN ! run FUSE with "best" parameter set from a previous SCE calibration - - OUTPUT_FLAG=.TRUE. - - ! load best SCE parameter set from NetCDF file into APAR - CALL GET_SCE_PARAM(FNAME_NETCDF_PARA_SCE,ONEMOD,NUMPAR,APAR) - - print *, 'Running FUSE with best SCE parameter set' - CALL FUSE_evaluate(APAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,NUMPSET) - print *, 'Done running FUSE with best SCE parameter set' - -ELSE - -print *, 'Unexpected fuse_mode!' -stop - -ENDIF + call sce_driver(APAR, BL, BU) + case default + stop "cannot identify FUSE mode" + +end select ! (FUSE mode) + +! ----- finalize ------------------------------------------------------------------------ + ! deallocate space -DEALLOCATE(APAR,BL,BU,URAND) - -IF(SPATIAL_OPTION == 'CATCH')THEN - DEALLOCATE(aForce,aRoute,aValid) - !if(err/=0)then; write(*,*) 'unable to deallocate space for catchment modeling'; stop; endif +DEALLOCATE(APAR, BL, BU, stat=err) +if(err/=0)then; write(*,*) 'unable to deallocate space for parameter vectors'; stop; endif -ELSE - DEALLOCATE(gForce, gState) - !DEALLOCATE(ancilF_3d, gForce_3d, gState_3d,AROUTE_3d) - DEALLOCATE(gForce_3d, gState_3d,AROUTE_3d) - !if(err/=0)then; write(*,*) 'unable to deallocate space for grid modeling'; stop; endif +DEALLOCATE(aForce, aRoute, aValid, stat=err) +if(err/=0)then; write(*,*) 'unable to deallocate space for catchment modeling'; stop; endif -ENDIF +DEALLOCATE(gForce, gState, gForce_3d, gState_3d, AROUTE_3d, stat=err) +if(err/=0)then; write(*,*) 'unable to deallocate space for grid modeling'; stop; endif ! close NetCDF files IF(GRID_FLAG)THEN PRINT *, 'Closing forcing file' err = nf90_close(ncid_forc) - !if (err.ne.0) write(*,*) trim(message); if (err.gt.0) stop + if(err/=0)then; message=trim(message)//' nf90_close failed: '//trim(nf90_strerror(err)); return; endif ENDIF PRINT *, 'Closing output file' err = nf90_close(ncid_out) -!if (err.ne.0) write(*,*) trim(message); if (err.gt.0) stop +if(err/=0)then; message=trim(message)//' nf90_close failed: '//trim(nf90_strerror(err)); return; endif + PRINT *, 'Done' +STOP + +! --------------------------------------------------------------------------------------- +! --------------------------------------------------------------------------------------- +! --------------------------------------------------------------------------------------- +contains + +! ----- MPI checker --------------------------------------------------------------------- + +subroutine mpi_check(ierr, callee) +#ifdef __MPI__ + use mpi +#endif + implicit none + integer(i4b), intent(in) :: ierr + character(len=*), intent(in) :: callee #ifdef __MPI__ -call MPI_Finalize(mpi_error_value) + integer(i4b) :: slen, ierr2 + character(len=256) :: errstr + if (ierr /= MPI_SUCCESS) then + call MPI_Error_string(ierr, errstr, slen, ierr2) + write(*,*) "MPI error at ", trim(callee), ": ", trim(errstr(1:slen)) + call MPI_Abort(MPI_COMM_WORLD, ierr, ierr2) + end if +#else + ! serial build: do nothing #endif +end subroutine mpi_check -STOP END PROGRAM DISTRIBUTED_DRIVER diff --git a/build/FUSE_SRC/driver/fuse_evaluate.f90 b/build/FUSE_SRC/driver/fuse_evaluate.f90 index 2a54c1b..e32f9f8 100644 --- a/build/FUSE_SRC/driver/fuse_evaluate.f90 +++ b/build/FUSE_SRC/driver/fuse_evaluate.f90 @@ -215,7 +215,8 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) use multistate, only: FSTATE, gState_3d use multistats, only: PCOUNT use multibands - + + use par_derive_module, only: par_derive use par_insert_module use str_2_xtry_module use xtry_2_str_module diff --git a/build/FUSE_SRC/driver/sce_driver.f90 b/build/FUSE_SRC/driver/sce_driver.f90 new file mode 100644 index 0000000..a41e0d4 --- /dev/null +++ b/build/FUSE_SRC/driver/sce_driver.f90 @@ -0,0 +1,85 @@ +module sce_driver_MODULE + + USE nrtype + + implicit none + + private + public :: sce_driver + +contains + + subroutine sce_driver(APAR, BL, BU) + USE multiparam, only: MAXN ! maximum number of trials before optimization is terminated + USE multiparam, only: KSTOP ! number of shuffling loops the value must change by PCENTO + USE multiparam, only: PCENTO ! the percentage + USE multiparam, only: NUMPAR ! # parameters + USE globaldata, only: isPrint ! used to turn of printing for calibration runs + USE globaldata, only: nFUSE_eval ! # FUSE evaluations + USE model_defn, only: FNAME_TEMPRY, FNAME_ASCII + implicit none + ! input variables + real(sp), intent(in) :: APAR(:) ! model parameter set + real(sp), intent(in) :: BL(:) ! vector of lower parameter bounds + real(sp), intent(in) :: BU(:) ! vector of upper parameter bounds + ! internal variables + REAL(MSP) :: AF_MSP ! objective function value + REAL(MSP), DIMENSION(:), ALLOCATABLE :: APAR_MSP ! ! lower bound of model parameters + REAL(MSP), DIMENSION(:), ALLOCATABLE :: BL_MSP ! ! lower bound of model parameters + REAL(MSP), DIMENSION(:), ALLOCATABLE :: BU_MSP ! ! upper bound of model parameters + REAL(MSP), DIMENSION(:), ALLOCATABLE :: URAND_MSP ! vector of quasi-random numbers U[0,1] + INTEGER(I4B) :: NOPT ! number of parameters to be optimized + INTEGER(I4B) :: NGS ! # complexes in the initial population + INTEGER(I4B) :: NPG ! # points in each complex + INTEGER(I4B) :: NPS ! # points in a sub-complex + INTEGER(I4B) :: NSPL ! # evolution steps allowed for each complex before shuffling + INTEGER(I4B) :: MINGS ! minimum number of complexes required + INTEGER(I4B) :: INIFLG ! 1 = include initial point in the population + INTEGER(I4B) :: IPRINT ! 0 = supress printing + INTEGER(I4B) :: ISCE ! unit number for SCE write + integer(i4b) :: NUMPSET ! number of parameter sets + REAL(MSP) :: FUNCTN ! function name for the model run + INTEGER(KIND=4) :: ISEED ! seed for the random sequence + + NOPT = NUMPAR ! number of parameters to be optimized (NUMPAR in module multiparam) + NGS = 10 ! number of complexes in the initial population + NPG = 2*NOPT + 1 ! number of points in each complex + NPS = NOPT + 1 ! number of points in a sub-complex + NSPL = 2*NOPT + 1 ! number of evolution steps allowed for each complex before shuffling + MINGS = NGS ! minimum number of complexes required + INIFLG = 1 ! 1 = include initial point in the population + IPRINT = 1 ! 0 = supress printing + + NUMPSET=1.2*MAXN ! will be used to define the parameter set dimension of the NetCDF files + ! using 1.2MAXN since the final number of parameter sets produced by SCE is unknown + + ! convert from SP used in FUSE to MSP used in SCE + ALLOCATE(APAR_MSP(NUMPAR), BL_MSP(NUMPAR), BU_MSP(NUMPAR)) + APAR_MSP=APAR; BL_MSP=BL; BU_MSP=BU + + ! open up ASCII output file + ISCE = 96 ! (file unit) + FNAME_ASCII = FNAME_TEMPRY//'_sce_output.txt' + print *, 'Creating SCE output file:', trim(FNAME_ASCII) + OPEN(96, FILE=TRIM(FNAME_ASCII) ) + + ! printing + isPrint = .false. ! turn off printing to screen + nFUSE_eval = 0 ! number of fuse evaluations + + ! set random seed + ISEED = 1 + + ! optimize (returns A and AF) + ! note that SCE requires the kind of APAR, BL, BU to be MSP + CALL SCEUA(APAR_MSP,AF_MSP,BL_MSP,BU_MSP,NOPT,MAXN,KSTOP,PCENTO,ISEED,& + NGS,NPG,NPS,NSPL,MINGS,INIFLG,IPRINT,ISCE) + + ! close ASCII output file + CLOSE(ISCE) + + DEALLOCATE(APAR_MSP, BL_MSP, BU_MSP) + + end subroutine sce_driver + +end module sce_driver_MODULE diff --git a/build/FUSE_SRC/driver/setup_domain.f90 b/build/FUSE_SRC/driver/setup_domain.f90 new file mode 100644 index 0000000..388fb53 --- /dev/null +++ b/build/FUSE_SRC/driver/setup_domain.f90 @@ -0,0 +1,143 @@ +module setup_domain_module + + USE nrtype + USE info_types, only: cli_options + USE info_types, only: fuse_info + USE data_types, only: domain_data + USE globaldata, only: isPrint + + implicit none + + private + public :: setup_domain + +contains + + subroutine setup_domain(opts, info, domain, ierr, message) + + ! access subroutines + use netcdf, only: nf90_open, nf90_nowrite, nf90_strerror ! NetCDF functions + USE fuse_fileManager, only: fuse_SetDirsUndPhiles ! sets directories and filenames + USE fuse_fileManager, only: export_filemanager_to_domain ! populates domain%info structure + USE fuse_fileManager, only: finalize_domain_config ! compute additional filenames/variables + USE fuse_fileManager, only: export_domain_to_legacy ! populates legacy modules + + USE force_info_module, only: force_info ! get forcing info for NetCDF files + + USE get_gforce_module, only: read_ginfo ! get dimension lengths from the NetCDF file + USE get_gforce_module, only: get_varID ! list of var ids + + USE get_mbands_module, only: GET_MBANDS_INFO ! get elevation bands for snow modeling + + USE domain_decomp_module, only: read_forcing_dimensions ! get forcing dimensions for MPI domain decomposition + USE domain_decomp_module, only: get_domain_decomp_indices ! get MPI domain decomposition indices + + USE time_windows_module, only: get_time_windows ! get info on the rolling time windows + USE time_windows_module, only: export_time_to_multiforce ! populate legacy multiforce modules + + USE alloc_domain_module, only: allocate_domain_data ! allocate space for data arrays in the domain structure + USE alloc_domain_module, only: set_legacy_arrays ! copy arrays in the domain%data structure to legacy arrays + + ! shared data: TODO move into domain structure + USE multiforce, only: ncid_forc + + implicit none + + ! input + type(cli_options) , intent(in) :: opts ! command line interface options + type(fuse_info) , intent(inout) :: info ! domain info + type(domain_data) , intent(inout) :: domain ! domain data + + ! output + integer(i4b) , intent(out) :: ierr ! error code + character(len=1024) , intent(out) :: message ! error message + + ! ----- internal ----------------------------------------------------------------------- + CHARACTER(LEN=1024) :: CMESSAGE ! error message + ! --------------------------------------------------------------------------------------- + associate(INPUT_PATH => info%files%input_path, & + forcefile => info%files%forcing_file) + ! --------------------------------------------------------------------------------------- + ierr=0; message='setup_domain/' + + ! ----- set paths and file names -------------------------------------------------------- + + ! set directories and filenames for control files + call fuse_SetDirsUndPhiles(fuseFileManagerIn=opts%control_file, err=ierr, message=cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! copy global file information to the domain structure + call export_filemanager_to_domain(opts, info) + + ! derive filenames + parse config strings + call finalize_domain_config(opts, info, ierr, message) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! populate legacy modules + call export_domain_to_legacy(info) + + ! ----- read information on numerical decisions and forcing files ----------------------- + + ! defines method/parameters used for numerical solution based on numerix file + ! NOTE: This routine supports the legacy FUSE v1 numerics experiments + CALL GETNUMERIX(IERR,CMESSAGE) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! get forcing info from the txt file + ! -- forcing info is text that describes the forcing NetCDF files (TODO: needs improvement) + call force_info(ierr,cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + if(isPrint) print *, 'Open forcing file:', trim(INPUT_PATH)//trim(forcefile) + + ! ----- read grid info and define indices for MPI domain decomposition ------------------ + + ! open NetCDF forcing file + ierr = nf90_open(trim(INPUT_PATH)//trim(forcefile), nf90_nowrite, ncid_forc) + if (ierr/=0)then; message=trim(message)//' nf90_open failed: '//trim(nf90_strerror(ierr)); return; endif + if(isPrint) PRINT *, 'NCID_FORC is', ncid_forc + + ! get NetCDF ID for each variable of the forcing file + ! NOTE: populates data structures in multiforce + call get_varID(ncid_forc, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! populate domain structure with (x,y,t) dimension lengths + ! -- nx_global, ny_global, nt_global + call read_forcing_dimensions(ncid_forc, info, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! get indices for MPI decomposition of the spatial domain: y_start_global, ny_local + ! NOTE: These indices will be used later to read different subsets of forcing data for different ranks + call get_domain_decomp_indices(info) + + ! ----- Compute time indices for sim/eval windows and subperiod chunk size -------------- + + call get_time_windows(ncid_forc, info, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! export info%time -> multiforce to keep legacy code working + call export_time_to_multiforce(info) + + ! ----- Get information on elevation bands ---------------------------------------------- + + ! get elevation band info, in particular N_BANDS, from NetCDF file + CALL GET_MBANDS_INFO(info, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! ----- Allocate space for domain data -------------------------------------------------- + + ! allocate space for the arrays in the domain%data structure + call allocate_domain_data(info, domain, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! copy arrays in the domain structure to legacy arrays + call set_legacy_arrays(info, domain, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + end associate + end subroutine setup_domain + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + +end module setup_domain_module diff --git a/build/FUSE_SRC/driver/setup_model_definition.f90 b/build/FUSE_SRC/driver/setup_model_definition.f90 new file mode 100644 index 0000000..ee2ae27 --- /dev/null +++ b/build/FUSE_SRC/driver/setup_model_definition.f90 @@ -0,0 +1,137 @@ +module setup_model_definition_MODULE + + USE nrtype + USE info_types, only: fuse_info + USE info_types, only: cli_options + USE multiparam_types, only: PARATT + + implicit none + + private + public :: setup_model_definition + +contains + + subroutine setup_model_definition(opts, info, APAR, BL, BU, err, message) + + ! access subroutines + use uniquemodl_module, only: uniquemodl ! Defines unique strings for all FUSE models + use GETPARMETA_module, only: GETPARMETA ! Reads parameter metadata from the parameter constraints file + use selectmodl_module, only: selectmodl ! reads model control file + use ASSIGN_STT_module, only: ASSIGN_STT ! state definitions: data are stored in module model_defn + use ASSIGN_FLX_module, only: ASSIGN_FLX ! flux definitions: data are stored in module model_defn + use ASSIGN_PAR_module, only: ASSIGN_PAR ! parameter definitions: data are stored in module multiparam + use PAR_DERIVE_module, only: PAR_DERIVE ! Compute derived model parameters (bucket sizes, etc.) + USE DEF_SSTATS_MODULE, only: DEF_SSTATS ! define summary statistics + USE DEF_PARAMS_MODULE, only: DEF_PARAMS ! define model parameters + USE DEF_OUTPUT_MODULE, only: DEF_OUTPUT ! define model output + USE getpar_str_module, only: GETPAR_STR ! extracts parameter metadata + + ! data stored in legacy modules + USE model_defn, only: NSTATE ! number of state variables + USE multiparam, only: NUMPAR ! number of paramters for the current model + USE multiparam, only: LPARAM ! list of model parameters + USE multiparam, only: MAXN ! maximum number of function evaluations in SCE -- used for NUMPSET + USE multiforce, only: NUMPSET ! number of model parameter sets + + implicit none + + ! input + type(cli_options) , intent(in) :: opts ! command line interface options + type(fuse_info) , intent(inout) :: info ! the fuse info structure that stores "everything" + + ! output + real(sp) , intent(out) , allocatable :: aPar(:) ! parameter vector + real(sp) , intent(out) , allocatable :: BL(:), BU(:) ! parameter bounds + integer(i4b) , intent(out) :: err ! error code + character(len=1024) , intent(out) :: message ! error message + + ! ----- internal ----------------------------------------------------------------------- + INTEGER(I4B) :: IPAR ! parameter index + INTEGER(I4B) :: NMOD ! number of models + TYPE(PARATT) :: PARAM_META ! parameter metadata (model parameters) + CHARACTER(LEN=1024) :: CMESSAGE ! error message + ! ----- output dimensions -------------------------------------------------------------- + integer(i4b) :: nx, ny, nt, nb, nSet, nPar + ! --------------------------------------------------------------------------------------- + associate(fmodel_id => info%config%fmodel_id) ! use info as truth where possible + ! --------------------------------------------------------------------------------------- + err=0; message='setup_model_definition/' + + ! ----- define characteristics of the current model ------------------------------------- + + ! Define model attributes (valid for all models) + CALL UNIQUEMODL(NMOD) ! get nmod unique models: stored in module model_defn; NMOD is intent(out) + CALL GETPARMETA(ERR,CMESSAGE) ! read parameter metadata from constraints txt file (parameter bounds etc.) + if (err/=0)then; message=trim(message)//trim(cmessage); err=20; return; endif + + ! Identify a single model: FMODEL_ID is read from the control file and used to build string for zDecisions + CALL SELECTMODL(FMODEL_ID,ERR=ERR,MESSAGE=CMESSAGE) ! FMODEL_ID is intent(in) + if (err/=0)then; message=trim(message)//trim(cmessage); err=20; return; endif + + ! Define list of states and parameters for the current model + ! NOTE: these definitions are global, so OK to be stored in a shared module + CALL ASSIGN_STT() ! state definitions are stored in module model_defn + CALL ASSIGN_FLX() ! flux definitions are stored in module model_defn + CALL ASSIGN_PAR() ! parameter definitions are stored in module multiparam + + ! save information in global data structures + info%config%nState = NSTATE ! NSTATE is in module model_defn + info%config%nParam = NUMPAR ! NSTATE is in module multiparam + info%config%listParam = LPARAM(1:NUMPAR) ! (performs allocation) LPARAM is in module multiparam + + ! Compute derived model parameters (bucket sizes, etc.) + CALL PAR_DERIVE(ERR,CMESSAGE) + if (err/=0)then; message=trim(message)//trim(cmessage); err=20; return; endif + + ! ----- initialize parameters, statistics, and output ----------------------------------- + + ! get number of parameter sets + ! will be used to define the parameter set dimension of the NetCDF files + select case(opts%runmode) + + ! options that run with a single parameter set + case('def', 'idx', 'opt'); NUMPSET = 1 + + ! use NUMPSET =1.2MAXN since final number of parameter sets produced by SCE is unknown + case('sce'); NUMPSET = int(1.2_sp * real(MAXN, sp)) + + ! check + err=20; message=trim(message)//'opts%runmode is unknown: '//trim(opts%runmode) + + end select + + ! save the number of parameter sets in the global info structure + info%config%nSets = NUMPSET + + ! define NetCDF files + + ! assign dimensions (use info structure for provenance/clarity) + + nx = info%space%nx_local ! NOTE: local to rank (MPI parallelization) + ny = info%space%ny_local + nt = info%time%nt_window + nb = info%snow%n_bands + + nSet = info%config%nSets + nPar = info%config%nParam + + CALL DEF_PARAMS(nSet) ! define model parameters + CALL DEF_OUTPUT(nx,ny,nb,nPar) ! define model output time series (nPar used for parameter derivatives) + CALL DEF_SSTATS() ! define summary statistics (REDEF) + + ! get parameter bounds and random numbers + ALLOCATE(APAR(NUMPAR),BL(NUMPAR),BU(NUMPAR)) + + DO IPAR=1,NUMPAR + CALL GETPAR_STR(LPARAM(IPAR)%PARNAME,PARAM_META) + BL(IPAR) = PARAM_META%PARLOW ! lower boundary + BU(IPAR) = PARAM_META%PARUPP ! upper boundary + APAR(IPAR) = PARAM_META%PARDEF ! using default parameter values + END DO + + end associate + + end subroutine setup_model_definition + +end module setup_model_definition_MODULE diff --git a/build/FUSE_SRC/netcdf/def_output.f90 b/build/FUSE_SRC/netcdf/def_output.f90 index 268f0f7..b10d818 100644 --- a/build/FUSE_SRC/netcdf/def_output.f90 +++ b/build/FUSE_SRC/netcdf/def_output.f90 @@ -61,8 +61,6 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) ! Time-varying output vars do ivar = 1, NOUTVAR - print*, trim(VNAME(ivar)) - if (Q_ONLY) then write_var = .false. if (trim(VNAME(ivar)) == "q_instnt") write_var = .true. @@ -89,7 +87,9 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) ierr = nf90_put_att(ncid_out, varid, "_FillValue", NA_VALUE_OUT); call handle_err(ierr) end if - end do + end do ! looping through variables + + print*, 'coordinate variables' ! Coordinate variables ierr = nf90_def_var(ncid_out, "time", NF90_FLOAT, (/dim_time/), varid_time); call handle_err(ierr) @@ -119,23 +119,33 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) ! Leave define mode ierr = nf90_enddef(ncid_out); call handle_err(ierr) + print*, 'coordinate data' + + print*, nSpat1, nSpat2 + print*, latitude + print*, longitude + ! Write coordinate data latitude_msp = latitude longitude_msp = longitude + print*, 'hello1' + ierr = nf90_put_var(ncid_out, varid_lat, latitude_msp); call handle_err(ierr) ierr = nf90_put_var(ncid_out, varid_lon, longitude_msp); call handle_err(ierr) + print*, 'hello1' band_i = [(ib, ib=1,n_bands)] param_i = [(ip, ip=1,NUMPAR)] + print*, 'hello1' ierr = nf90_put_var(ncid_out, varid_band, band_i); call handle_err(ierr) ierr = nf90_put_var(ncid_out, varid_param, param_i); call handle_err(ierr) + + ierr = nf90_close(ncid_out); call handle_err(ierr) print *, 'NetCDF file for model runs defined with dimensions', nSpat1, nSpat2, n_bands, NUMPAR - ierr = nf90_close(ncid_out); call handle_err(ierr) - END SUBROUTINE DEF_OUTPUT END MODULE DEF_OUTPUT_MODULE diff --git a/build/FUSE_SRC/netcdf/def_params.f90 b/build/FUSE_SRC/netcdf/def_params.f90 index 94c6c88..0e655df 100644 --- a/build/FUSE_SRC/netcdf/def_params.f90 +++ b/build/FUSE_SRC/netcdf/def_params.f90 @@ -1,78 +1,101 @@ -SUBROUTINE DEF_PARAMS(NPAR) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007 -! Modified by Nans Addor to include snow routine -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Define NetCDF output files -- parameter variables -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -USE model_defn, only: FNAME_NETCDF_PARA ! model definition (includes filename) -USE metaparams ! metadata for all model parameters -USE multistats, ONLY: MSTATS ! model statistics structure -USE multistate, only: ncid_out ! NetCDF output file ID -USE globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH -IMPLICIT NONE -! input -INTEGER(I4B), INTENT(IN) :: NPAR ! number of parameter sets -! internal -INTEGER(I4B) :: IERR ! error code -INTEGER(I4B) :: NPAR_DIM ! number of parameter sets -INTEGER(I4B) :: NMOD_DIM ! number of models -INTEGER(I4B) :: NDIF_DIM ! differences in models -INTEGER(I4B) :: NAME_DIM ! length of string defining models -INTEGER(I4B) :: ERRM_DIM ! length of string defining error message -INTEGER(I4B), DIMENSION(1) :: FVAR ! fixed dimensions -INTEGER(I4B), DIMENSION(3) :: SVAR ! model descriptor dimensions -INTEGER(I4B), DIMENSION(3) :: EVAR ! error message dimensions -INTEGER(I4B) :: IVAR ! loop through variables -INTEGER(I4B) :: IVAR_ID ! variable ID -include 'netcdf.inc' ! use netCDF libraries -! --------------------------------------------------------------------------------------- -CALL PARDESCRIBE() ! get list of parameter descriptions -! --------------------------------------------------------------------------------------- -PRINT *, 'Define NetCDF output files - parameter variables = ', TRIM(FNAME_NETCDF_PARA) -! Create file -IERR = NF_CREATE(TRIM(FNAME_NETCDF_PARA),NF_CLOBBER,ncid_out); CALL HANDLE_ERR(IERR) - ! define dimensions - ! IERR = NF_DEF_DIM(ncid_out,'mod',NMOD,NMOD_DIM); CALL HANDLE_ERR(IERR) -! IERR = NF_DEF_DIM(ncid_out,'par',NF_UNLIMITED,NPAR_DIM); CALL HANDLE_ERR(IERR) - IERR = NF_DEF_DIM(ncid_out,'par',NPAR,NPAR_DIM); CALL HANDLE_ERR(IERR) ! TODO : max number of parameter - should not be hard-coded - !IERR = NF_DEF_DIM(ncid_out,'model_differences',9,NDIF_DIM); CALL HANDLE_ERR(IERR) !TODO: this should not be hard-coded - !IERR = NF_DEF_DIM(ncid_out,'model_name_length',10,NAME_DIM); CALL HANDLE_ERR(IERR) - !IERR = NF_DEF_DIM(ncid_out,'error_message_length',LEN(MSTATS%ERR_MESSAGE),ERRM_DIM) - ! assign dimensions to indices - FVAR = (/NPAR_DIM/) ! dimensions for fixed output (parameters) - !SVAR = (/NAME_DIM,NDIF_DIM,NMOD_DIM/) ! dimensions for model names - !EVAR = (/ERRM_DIM,NMOD_DIM,NPAR_DIM/) ! dimensions for error messages - ! define fixed output variables - DO IVAR=1,NOUTPAR - IERR = NF_DEF_VAR(ncid_out,TRIM(PNAME(IVAR)),NF_REAL,1,FVAR,IVAR_ID); CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',LEN_TRIM(PDESC(IVAR)),TRIM(PDESC(IVAR))) - CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',LEN_TRIM(PUNIT(IVAR)),TRIM(PUNIT(IVAR))) - CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_REAL,1,-9999.); CALL HANDLE_ERR(IERR) - END DO ! ivar - ! define model definitions - !IERR = NF_DEF_VAR(ncid_out,'model_description',NF_CHAR,3,SVAR,IVAR_ID); CALL HANDLE_ERR(IERR) - ! define error messages - !IERR = NF_DEF_VAR(ncid_out,'error_message',NF_CHAR,3,EVAR,IVAR_ID); CALL HANDLE_ERR(IERR) -! end definitions and close file +MODULE DEF_PARAMS_MODULE + USE nrtype ! variable types, etc. + + implicit none + + private + public :: DEF_PARAMS + + contains + + SUBROUTINE DEF_PARAMS(NPAR) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! Modified by Nans Addor to include snow routine + ! Modified by Matyn Clark to include band dimension, 12/2025 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Define NetCDF output files -- parameter variables + ! --------------------------------------------------------------------------------------- + + ! subroutines + USE metaparams, only: PARDESCRIBE ! define metadata for model parameters + + ! data modules + USE metaparams, only: NOUTPAR ! number of model parameters + USE metaparams, only: PNAME, PDESC, PUNIT ! metadata for all model parameters + USE metaparams, only: isBand ! logical flag to define vars with elevation dimension + USE model_defn, only: FNAME_NETCDF_PARA ! model definition (includes filename) + USE multistats, ONLY: MSTATS ! model statistics structure + USE multibands, ONLY: N_BANDS ! number of elevation bands + USE globaldata, only: ncid_out ! NetCDF output file ID + USE globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH + + IMPLICIT NONE + + ! input + INTEGER(I4B), INTENT(IN) :: NPAR ! number of parameter sets + + ! internal + INTEGER(I4B) :: IERR ! error code + INTEGER(I4B) :: PAR_DIM ! parameter set dimension + INTEGER(I4B) :: BAND_DIM ! elevation band dimension + INTEGER(I4B), DIMENSION(1) :: DIMS1 ! 1-d parameter vector + INTEGER(I4B), DIMENSION(2) :: DIMS2 ! 2-d parameter-bands matrix + INTEGER(I4B) :: IVAR ! loop through variables + INTEGER(I4B) :: IVAR_ID ! variable ID + + include 'netcdf.inc' ! use netCDF libraries + + ! --------------------------------------------------------------------------------------- + CALL PARDESCRIBE() ! get list of parameter descriptions + ! --------------------------------------------------------------------------------------- + + PRINT *, 'Define NetCDF output files - parameter variables = ', TRIM(FNAME_NETCDF_PARA) + + ! Create file + IERR = NF_CREATE(TRIM(FNAME_NETCDF_PARA),NF_CLOBBER,ncid_out); CALL HANDLE_ERR(IERR) + + ! define dimensions + IERR = NF_DEF_DIM(ncid_out, 'par', NPAR, PAR_DIM); CALL HANDLE_ERR(IERR) + IERR = NF_DEF_DIM(ncid_out, 'band', N_BANDS, BAND_DIM); CALL HANDLE_ERR(IERR) + + ! assign dimensions to indices + DIMS1 = (/PAR_DIM/) ! 1-d parameter vector + DIMS2 = (/PAR_DIM, BAND_DIM/) ! 2-d parameter-bands matrix + + ! define fixed output variables + DO IVAR=1,NOUTPAR + + ! define variables + if(isBand(iVar))then + IERR = NF_DEF_VAR(ncid_out, TRIM(PNAME(IVAR)), NF_REAL, 2, DIMS2, IVAR_ID); CALL HANDLE_ERR(IERR) + else + IERR = NF_DEF_VAR(ncid_out, TRIM(PNAME(IVAR)), NF_REAL, 1, DIMS1, IVAR_ID); CALL HANDLE_ERR(IERR) + endif + + ! define metadata + IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',LEN_TRIM(PDESC(IVAR)),TRIM(PDESC(IVAR))); CALL HANDLE_ERR(IERR) + IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',LEN_TRIM(PUNIT(IVAR)),TRIM(PUNIT(IVAR))); CALL HANDLE_ERR(IERR) + IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_REAL,1,-9999.); CALL HANDLE_ERR(IERR) + + END DO ! ivar + ! add global attributes ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "software", len("FUSE"), "FUSE"); call HANDLE_ERR(ierr) ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_version", len_trim(FUSE_VERSION), trim(FUSE_VERSION)); call HANDLE_ERR(ierr) ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_build_time", len_trim(FUSE_BUILDTIME), trim(FUSE_BUILDTIME)); call HANDLE_ERR(ierr) ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_branch", len_trim(FUSE_GITBRANCH), trim(FUSE_GITBRANCH)); call HANDLE_ERR(ierr) ierr = NF_PUT_ATT_TEXT(ncid_out, NF_GLOBAL, "fuse_git_hash", len_trim(FUSE_GITHASH), trim(FUSE_GITHASH)); call HANDLE_ERR(ierr) + + ! end definitions and close file + IERR = NF_ENDDEF(ncid_out) + IERR = NF_CLOSE(ncid_out) + ! --------------------------------------------------------------------------------------- + END SUBROUTINE DEF_PARAMS - - -IERR = NF_ENDDEF(ncid_out) -IERR = NF_CLOSE(ncid_out) -! --------------------------------------------------------------------------------------- -END SUBROUTINE DEF_PARAMS +END MODULE DEF_PARAMS_MODULE diff --git a/build/FUSE_SRC/netcdf/def_sstats.f90 b/build/FUSE_SRC/netcdf/def_sstats.f90 index 33436c5..3dd5213 100644 --- a/build/FUSE_SRC/netcdf/def_sstats.f90 +++ b/build/FUSE_SRC/netcdf/def_sstats.f90 @@ -1,74 +1,83 @@ -SUBROUTINE DEF_SSTATS() -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Define NetCDF output files -- summary statistics -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -USE model_defn ! model definition (includes filename) -USE meta_stats ! metadata for summary statistics -USE model_numerix ! model numerix decisions -USE multistate, only: ncid_out ! NetCDF output file ID -IMPLICIT NONE -! internal -INTEGER(I4B) :: IERR ! error code; NetCDF ID -INTEGER(I4B) :: NPAR_DIM ! number of parameter sets -INTEGER(I4B) :: NMOD_DIM ! number of models -!INTEGER(I4B) :: NORD_DIM ! number of ordinates in prob distn -INTEGER(I4B), DIMENSION(1) :: FVAR ! dimensions for summary statistics -INTEGER(I4B), DIMENSION(2) :: PVAR ! dimensions for probability distributions -INTEGER(I4B) :: IVAR ! loop through variables -INTEGER(I4B) :: IVAR_ID ! variable ID -!INTEGER(I4B) :: IORD_ID ! ordinates ID -!real(MSP), dimension(size(ORD_NSUBS)) :: rORD ! ordinates of the prob dist (real numbers) -include 'netcdf.inc' ! use netCDF libraries -! --------------------------------------------------------------------------------------- -CALL SUMDESCRIBE() ! get list of summary statistics -! --------------------------------------------------------------------------------------- -! open file and put in define mode -IERR = NF_OPEN(TRIM(FNAME_NETCDF_PARA),NF_WRITE,ncid_out); CALL HANDLE_ERR(IERR) -IERR = NF_REDEF(ncid_out); CALL HANDLE_ERR(IERR) - ! retrieve ID for the model and parameter dimensions - IERR = NF_INQ_DIMID(ncid_out,'par',NPAR_DIM); CALL HANDLE_ERR(IERR) - !IERR = NF_INQ_DIMID(ncid_out,'mod',NMOD_DIM); CALL HANDLE_ERR(IERR) +module DEF_SSTATS_module + implicit none + private + public :: DEF_SSTATS - ! define ord dimension - !IERR = NF_DEF_DIM(ncid_out,'ord',SIZE(ORD_NSUBS),NORD_DIM); CALL HANDLE_ERR(IERR) +contains - ! define variables - FVAR = (/NPAR_DIM/) ! dimensions for fixed output (parameters) - DO IVAR=1,NSUMVAR - IERR = NF_DEF_VAR(ncid_out,TRIM(XNAME(IVAR)),NF_REAL,1,FVAR,IVAR_ID); CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',LEN_TRIM(XDESC(IVAR)),TRIM(XDESC(IVAR))) - CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',LEN_TRIM(XUNIT(IVAR)),TRIM(XUNIT(IVAR))) - CALL HANDLE_ERR(IERR) - IERR = NF_PUT_ATT_REAL(ncid_out,IVAR_ID,'_FillValue',NF_REAL,1,-9999.); CALL HANDLE_ERR(IERR) - END DO ! ivar + SUBROUTINE DEF_SSTATS() + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Define NetCDF output files -- summary statistics + ! --------------------------------------------------------------------------------------- + USE nrtype ! variable types, etc. + USE model_defn ! model definition (includes filename) + USE meta_stats ! metadata for summary statistics + USE model_numerix ! model numerix decisions + USE globaldata, only: ncid_out ! NetCDF output file ID + IMPLICIT NONE + ! internal + INTEGER(I4B) :: IERR ! error code; NetCDF ID + INTEGER(I4B) :: NPAR_DIM ! number of parameter sets + INTEGER(I4B) :: NMOD_DIM ! number of models + !INTEGER(I4B) :: NORD_DIM ! number of ordinates in prob distn + INTEGER(I4B), DIMENSION(1) :: FVAR ! dimensions for summary statistics + INTEGER(I4B), DIMENSION(2) :: PVAR ! dimensions for probability distributions + INTEGER(I4B) :: IVAR ! loop through variables + INTEGER(I4B) :: IVAR_ID ! variable ID + !INTEGER(I4B) :: IORD_ID ! ordinates ID + !real(MSP), dimension(size(ORD_NSUBS)) :: rORD ! ordinates of the prob dist (real numbers) + include 'netcdf.inc' ! use netCDF libraries + ! --------------------------------------------------------------------------------------- + CALL SUMDESCRIBE() ! get list of summary statistics + ! --------------------------------------------------------------------------------------- + ! open file and put in define mode + IERR = NF_OPEN(TRIM(FNAME_NETCDF_PARA),NF_WRITE,ncid_out); CALL HANDLE_ERR(IERR) + IERR = NF_REDEF(ncid_out); CALL HANDLE_ERR(IERR) + ! retrieve ID for the model and parameter dimensions + IERR = NF_INQ_DIMID(ncid_out,'par',NPAR_DIM); CALL HANDLE_ERR(IERR) + !IERR = NF_INQ_DIMID(ncid_out,'mod',NMOD_DIM); CALL HANDLE_ERR(IERR) + + ! define ord dimension + !IERR = NF_DEF_DIM(ncid_out,'ord',SIZE(ORD_NSUBS),NORD_DIM); CALL HANDLE_ERR(IERR) + + ! define variables + FVAR = (/NPAR_DIM/) ! dimensions for fixed output (parameters) + DO IVAR=1,NSUMVAR + IERR = NF_DEF_VAR(ncid_out,TRIM(XNAME(IVAR)),NF_REAL,1,FVAR,IVAR_ID); CALL HANDLE_ERR(IERR) + IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',LEN_TRIM(XDESC(IVAR)),TRIM(XDESC(IVAR))) + + CALL HANDLE_ERR(IERR) + IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',LEN_TRIM(XUNIT(IVAR)),TRIM(XUNIT(IVAR))) + CALL HANDLE_ERR(IERR) + END DO ! ivar + + ! define ordinates of probability distributions + ! IERR = NF_DEF_VAR(ncid_out,'ordinates',NF_REAL,1,NORD_DIM,IORD_ID); CALL HANDLE_ERR(IERR) + ! IERR = NF_PUT_ATT_TEXT(ncid_out,IORD_ID,'long_name',37,'ordinates of probability distribution') + ! CALL HANDLE_ERR(IERR) + + ! IERR = NF_PUT_ATT_TEXT(ncid_out,IORD_ID,'units',1,'-'); CALL HANDLE_ERR(IERR) + + ! define probability distributions + ! PVAR = (/NPAR_DIM,NORD_DIM/) ! dimensions for probability distributions + ! IERR = NF_DEF_VAR(ncid_out,'probability',NF_REAL,2,PVAR,IVAR_ID); CALL HANDLE_ERR(IERR) + ! IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',44,'cumulative probability of number of substeps'); CALL HANDLE_ERR(IERR) + ! IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',1,'-'); CALL HANDLE_ERR(IERR) + + ! end definitions and close file + IERR = NF_ENDDEF(ncid_out) + ! write the ordinates of the probability distribution + !rORD = real(ORD_NSUBS,kind(MSP)) + ! IERR = NF_PUT_VAR_REAL(ncid_out,IORD_ID,rORD); CALL HANDLE_ERR(IERR) ! write data + IERR = NF_CLOSE(ncid_out) + + ! --------------------------------------------------------------------------------------- + END SUBROUTINE DEF_SSTATS - ! define ordinates of probability distributions - ! IERR = NF_DEF_VAR(ncid_out,'ordinates',NF_REAL,1,NORD_DIM,IORD_ID); CALL HANDLE_ERR(IERR) - ! IERR = NF_PUT_ATT_TEXT(ncid_out,IORD_ID,'long_name',37,'ordinates of probability distribution') - ! CALL HANDLE_ERR(IERR) - - ! IERR = NF_PUT_ATT_TEXT(ncid_out,IORD_ID,'units',1,'-'); CALL HANDLE_ERR(IERR) - - ! define probability distributions - ! PVAR = (/NPAR_DIM,NORD_DIM/) ! dimensions for probability distributions - ! IERR = NF_DEF_VAR(ncid_out,'probability',NF_REAL,2,PVAR,IVAR_ID); CALL HANDLE_ERR(IERR) - ! IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'long_name',44,'cumulative probability of number of substeps'); CALL HANDLE_ERR(IERR) - ! IERR = NF_PUT_ATT_TEXT(ncid_out,IVAR_ID,'units',1,'-'); CALL HANDLE_ERR(IERR) - -! end definitions and close file -IERR = NF_ENDDEF(ncid_out) -! write the ordinates of the probability distribution -!rORD = real(ORD_NSUBS,kind(MSP)) -! IERR = NF_PUT_VAR_REAL(ncid_out,IORD_ID,rORD); CALL HANDLE_ERR(IERR) ! write data -IERR = NF_CLOSE(ncid_out) - -! --------------------------------------------------------------------------------------- -END SUBROUTINE DEF_SSTATS +end module DEF_SSTATS_module diff --git a/build/FUSE_SRC/netcdf/domain_decomp.f90 b/build/FUSE_SRC/netcdf/domain_decomp.f90 new file mode 100644 index 0000000..edaec60 --- /dev/null +++ b/build/FUSE_SRC/netcdf/domain_decomp.f90 @@ -0,0 +1,133 @@ +module domain_decomp_module + + use nrtype + use info_types, only: fuse_info + + implicit none + + private + public :: read_forcing_dimensions + public :: get_domain_decomp_indices + +contains + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- read forcing dimensions (used for domain decomposition) ----------------------- + + subroutine read_forcing_dimensions(ncid, info, ierr, message) + use netcdf + USE multiforce,only:vname_aprecip ! name of precip variable + implicit none + integer(i4b), intent(in) :: ncid + type(fuse_info), intent(inout) :: info + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: ivarid + integer(i4b), parameter :: ndims=3 + integer(i4b) :: dimids(ndims), dimLen + associate(nx_global => info%space%nx_global, & + ny_global => info%space%ny_global, & + nt_global => info%time%nt_global ) + + ierr=0; message="read_forcing_dimensions/" + + ! pick one required variable to identify shape (in this case precip) + ierr = nf90_inq_varid(ncid, trim(vname_aprecip), ivarid) + + ! get dimension IDs (x,y,t) + ierr = nf90_inquire_variable(ncid, ivarid, dimids=dimids) + if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif + + ! get dimsension lengths (nx,ny,nt) + ierr = nf90_inquire_dimension(ncid, dimids(1), len=nx_global); if(ierr/=0) return + ierr = nf90_inquire_dimension(ncid, dimids(2), len=ny_global); if(ierr/=0) return + ierr = nf90_inquire_dimension(ncid, dimids(3), len=nt_global); if(ierr/=0) return + + end associate + end subroutine read_forcing_dimensions + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- get indices to decompose the spatial domain ----------------------------------- + ! 1) Determine global run mode (grid vs catchment) + ! 2) Apply MPI decomposition (y dimension) and store local dims + offsets + + subroutine get_domain_decomp_indices(info) + implicit none + type(fuse_info), intent(inout) :: info + + associate(& + grid_flag => info%space%grid_flag, & + nx_global => info%space%nx_global, & + ny_global => info%space%ny_global, & + nx_local => info%space%nx_local, & + ny_local => info%space%ny_local, & + y_start_global => info%space%y_start_global, & + y_end_global => info%space%y_end_global, & + mpi_enabled => info%mpi%enabled, & + nproc => info%mpi%nproc, & + rank => info%mpi%rank ) + + ! Set flag to toggle between grid and lumped catchment modes + grid_flag = (nx_global>1 .or. ny_global>1) + + ! Copy globals + nx_local = nx_global + ny_local = ny_global + y_start_global = 1 + + ! Get indices for split dimensions + if(grid_flag .and. mpi_enabled .and. nproc>1) then + call split_1d(ny_global, rank, nproc, & ! input + y_start_global, ny_local) ! output + endif + y_end_global = y_start_global + ny_local - 1 + + end associate + end subroutine get_domain_decomp_indices + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- split the dimensions for each MPI rank ---------------------------------------- + ! Purpose: Split domain to allow for MPI. + ! Given rank, nproc, and n_global, provide start and n_local indices + ! Creator: Ethan Gutmann, 2020 + ! Modified by Martyn Clark to simplify code and input/output, 12/2025 + + subroutine split_1d(n_global, rank, nproc, start, n_local, verbose) + use nrtype + implicit none + integer(i4b), intent(in) :: n_global, rank, nproc + logical(lgt), intent(in), optional :: verbose + integer(i4b), intent(out) :: start, n_local + + integer(i4b) :: base, extra + logical(lgt) :: talk + + talk = .false.; if(present(verbose)) talk = verbose + + ! --- sanity checks --- + if(nproc <= 0) stop "split_1d: nproc must be > 0" + if(rank < 0 .or. rank >= nproc) stop "split_1d: rank out of range" + if(n_global < 1) stop "split_1d: n_global must be >= 1" + + base = n_global / nproc ! floor(n_global / nproc) rows per rank + extra = mod(n_global, nproc) ! remainder; first 'extra' ranks get +1 row + + n_local = base + merge(1, 0, rank < extra) ! add 1 row for ranks 0..extra-1 + start = rank*base + min(rank, extra) + 1 ! shift start by #extra rows assigned before this rank + + if(talk) then + write(*,'(a,i0,a,i0)') "split_1d: nproc=", nproc, " rank =", rank + write(*,'(a,i0,a,i0)') "split_1d: base =", base, " extra =", extra + write(*,'(a,i0,a,i0)') "split_1d: start=", start, " nLocal=", n_local + write(*,'(a,i0,a,i0)') "split_1d: global rows=", start, ":", start+n_local-1 + endif + end subroutine split_1d + +end module domain_decomp_module diff --git a/build/FUSE_SRC/netcdf/get_mbands.f90 b/build/FUSE_SRC/netcdf/get_mbands.f90 index 6a4e4c8..c8bf012 100644 --- a/build/FUSE_SRC/netcdf/get_mbands.f90 +++ b/build/FUSE_SRC/netcdf/get_mbands.f90 @@ -1,276 +1,64 @@ module get_mbands_module -USE nrtype -USE netcdf -implicit none -private -!public::GET_MBANDS -public::GET_MBANDS_INFO -contains -! -! SUBROUTINE GET_MBANDS(err,message) -! ! --------------------------------------------------------------------------------------- -! ! Creator: -! ! -------- -! ! Created by Brian Henn, 7/2013 -! ! Based on GETFORCING.f90 by Martyn Clark, 2009 -! ! Updated by Dmitri Kavetski, 14 Sept 2014 AD - Chiefleys Newie -! ! --------------------------------------------------------------------------------------- -! ! Purpose: -! ! -------- -! ! Read ASCII basin band data in BATEA format -! ! --------------------------------------------------------------------------------------- -! ! Modules Modified: -! ! ----------------- -! ! MODULE multibands -- populate structure MBANDS(*)%(*) -! ! --------------------------------------------------------------------------------------- -! use nrtype,only:I4B,LGT,SP -! use utilities_dmsl_kit_FUSE,only:getSpareUnit,stripTrailString -! USE fuse_fileManager,only:INPUT_PATH,SETNGS_PATH ! defines data directory -! USE fuse_fileManager,only:MBANDS_NC ! defines elevation bands -! USE multibands,only:N_BANDS,MBANDS,Z_FORCING ! model band structures -! IMPLICIT NONE -! ! dummies -! integer(I4B), intent(out) :: err -! character(*), intent(out) :: message -! ! internal -! integer(i4b),parameter::lenPath=1024 ! DK/2008/10/21: allows longer file paths -! INTEGER(I4B),DIMENSION(2) :: IERR ! error codes -! INTEGER(I4B) :: IUNIT ! input file unit -! CHARACTER(LEN=lenPath) :: CFILE ! name of control file -! CHARACTER(LEN=lenPath) :: BFILE ! name of band file -! LOGICAL(LGT) :: LEXIST ! .TRUE. if control file exists -! CHARACTER(LEN=lenPath) :: FNAME_INPUT ! name of band input file -! INTEGER(I4B) :: NCOLB ! number of band columns -! INTEGER(I4B) :: IX_Z ! column number for band elevation -! INTEGER(I4B) :: IX_AF ! column number for band area fraction -! INTEGER(I4B) :: NHEADB ! number of band header rows -! INTEGER(I4B) :: BAND_START ! index of start of band info -! INTEGER(I4B) :: BAND_END ! index of end of band info -! INTEGER(I4B) :: IHEAD ! header index -! CHARACTER(LEN=lenPath) :: TMPTXT ! descriptive text -! INTEGER(I4B) :: IBANDS ! band index (input data) -! INTEGER(I4B) :: JBAND ! band index (internal data structure) -! REAL(SP),DIMENSION(:),ALLOCATABLE :: TMPDAT ! one line of data -! ! --------------------------------------------------------------------------------------- -! ! read in control file -! err=0 -! CFILE = TRIM(SETNGS_PATH)//MBANDS_NC ! control file info shared in MODULE directory -! print *, 'Elevation bands info file:',TRIM(CFILE) -! -! INQUIRE(FILE=CFILE,EXIST=LEXIST) ! check that elevation band file exists -! IF (.NOT.LEXIST) THEN -! print *, 'f-GET_MBANDS/control file ',TRIM(CFILE),' for band data does not exist ' -! STOP -! ENDIF -! ! read in parameters of the control files -! CALL getSpareUnit(IUNIT,err,message) ! make sure IUNIT is actually available -! IF (err/=0) THEN -! message="f-GET_MBANDS/weird/&"//message -! err=100; return -! ENDIF -! OPEN(IUNIT,FILE=CFILE,STATUS='old') -! READ(IUNIT,'(A)') FNAME_INPUT ! get input filename -! ! number of columns and column numbers -! READ(IUNIT,*) NCOLB,IX_Z,IX_AF ! band data: number of columns, elevation, area fraction -! READ(IUNIT,*) NHEADB,N_BANDS,BAND_START,BAND_END ! number of headers, number of bands, first band line, last band line -! CLOSE(IUNIT) -! ! fill extra characters in filename with white space -! CALL stripTrailString(string=FNAME_INPUT,trailStart='!') -! IF (N_BANDS.NE.(BAND_END-BAND_START+1)) THEN -! message="f-GET_MBANDS/N_BANDS does not match the number of band lines in the band file" -! err=100; return -! ENDIF -! ! --------------------------------------------------------------------------------------- -! ! read band data -! ALLOCATE(MBANDS(N_BANDS),STAT=IERR(1)) ! (shared in module multibands) -! ALLOCATE(TMPDAT(NCOLB),STAT=IERR(2)) ! (only used in this routine -- deallocate later) -! IF (ANY(IERR.NE.0)) THEN -! message="f-GET_MBANDS/problem allocating data structures" -! err=100; return -! ENDIF -! JBAND = 0 -! BFILE = TRIM(INPUT_PATH)//FNAME_INPUT -! INQUIRE(FILE=BFILE,EXIST=LEXIST) ! check that control file exists -! IF (.NOT.LEXIST) THEN -! print *, 'f-GET_MBANDS/band data file '//TRIM(BFILE)//' does not exist ' -! err=100; return -! ENDIF -! CALL getSpareUnit(IUNIT,err,message) ! make sure IUNIT is actually available -! IF (err/=0) THEN -! message="f-GET_MBANDS/weird/&"//message -! err=100; return -! ENDIF -! OPEN(IUNIT,FILE=BFILE,STATUS='old') -! ! read header -! DO IHEAD=1,NHEADB -! IF (IHEAD.EQ.2) THEN -! READ(IUNIT,*) Z_FORCING ! elevation of the forcing data (shared in module multibands) -! ELSE -! READ(IUNIT,*) TMPTXT ! descriptive text -! ENDIF -! END DO -! -! ! read data -! DO IBANDS=1,N_BANDS -! READ(IUNIT,*) TMPDAT -! JBAND = JBAND+1 -! MBANDS(JBAND)%NUM = INT(TMPDAT(1)) -! MBANDS(JBAND)%Z_MID = TMPDAT(IX_Z) -! MBANDS(JBAND)%AF = TMPDAT(IX_AF) -! -! END DO -! CLOSE(IUNIT) -! DEALLOCATE(TMPDAT, STAT=IERR(1)) -! IF (IERR(1).NE.0) THEN -! message='f-GET_MBANDS/problem deallocating TMPDAT' -! err=100; return -! END IF -! ! --------------------------------------------------------------------------------------- -! END SUBROUTINE GET_MBANDS - - -SUBROUTINE GET_MBANDS_INFO(ELEV_BANDS_NC,err,message) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Created by Nans Addor, 2/2017 -! Based on Brian Henn's GET_MBANDS, 7/2013 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Read band data (elevation and area fraction) from a NetCDF grid -! --------------------------------------------------------------------------------------- -! Modules Modified: -! ----------------- -! MODULE multibands -- populate structure MBANDS_INFO_3d and Z_FORCING_grid -! --------------------------------------------------------------------------------------- -use nrtype,only:I4B,LGT,SP -use utilities_dmsl_kit_FUSE,only:getSpareUnit,stripTrailString -USE fuse_fileManager,only:INPUT_PATH,SETNGS_PATH ! defines data directory -USE fuse_fileManager,only:MBANDS_NC ! defines elevation bands - -USE multibands,only:N_BANDS,MBANDS,MBANDS_INFO_3d,Z_FORCING,& - Z_FORCING_grid,elev_mask ! model band structures -USE multiforce,only:nspat1,nspat2,startSpat2,NA_VALUE_SP ! dimension lengths, na_value - -IMPLICIT NONE -! dummies -CHARACTER(LEN=1024),intent(in) :: ELEV_BANDS_NC -integer(I4B), intent(out) :: err -character(*), intent(out) :: message -! internal -integer(i4b),parameter::lenPath=1024 ! DK/2008/10/21: allows longer file paths -INTEGER(I4B) :: IERR ! error code -INTEGER(I4B) :: IUNIT ! input file unit -CHARACTER(LEN=lenPath) :: CFILE ! name of control file -CHARACTER(LEN=lenPath) :: BFILE ! name of band file -LOGICAL(LGT) :: LEXIST ! .TRUE. if control file exists -CHARACTER(LEN=lenPath) :: FNAME_INPUT ! name of band input file -INTEGER(I4B) :: NCOLB ! number of band columns -INTEGER(I4B) :: IX_Z ! column number for band elevation -INTEGER(I4B) :: IX_AF ! column number for band area fraction -INTEGER(I4B) :: BAND_START ! index of start of band info -INTEGER(I4B) :: BAND_END ! index of end of band info -INTEGER(I4B) :: IBANDS ! band index (input data) -INTEGER(I4B) :: JBAND ! band index (internal data structure) -INTEGER(I4B) :: NCID_EB ! NetCDF ID for elevation bands file -INTEGER(I4B) :: iSpat1,iSpat2 ! loop through spatial dimensions -REAL(SP),dimension(:,:,:),allocatable :: AF_TEMP, ME_TEMP ! Temporary data structures to store area_frac and mean_area - -! internal: NetCDF read -integer(i4b) :: ivarid_af,ivarid_me ! NetCDF variable ID for area_frac and mean_area -integer(i4b),parameter :: ndims=3 ! number of dimensions for frac_area -integer(i4b) :: dimid_eb ! ID elevation bands -integer(i4b) :: iDimID ! dimension ID -integer(i4b) :: dimLen ! dimension length - -! --------------------------------------------------------------------------------------- - -! read in NetCDF file defining the elevation bands -err=0; ierr=0 -CFILE = TRIM(INPUT_PATH)//ELEV_BANDS_NC ! control file info shared in MODULE directory -print *, 'Loading elevation bands from:',TRIM(CFILE) - -INQUIRE(FILE=CFILE,EXIST=LEXIST) ! check that control file exists -IF (.NOT.LEXIST) THEN - print *, 'f-GET_MBANDS_GRID/NetCDF file ',TRIM(CFILE),' for elevation bands does not exist ' - STOP -ENDIF - -!open netcdf file -err = nf90_open(CFILE, nf90_nowrite, NCID_EB) -if (err.ne.0) write(*,*) trim(message); if (err.gt.0) stop - -! get the dimension IDs for elevation_band -err = nf90_inq_dimid(NCID_EB, 'elevation_band', dimid_eb) -if(err/=0)then; message=trim(message)//trim(nf90_strerror(err)); return; endif -! get dimension length -err = nf90_inquire_dimension(ncid_eb,dimid_eb,len=dimLen) -if(err/=0)then; message=trim(message)//trim(nf90_strerror(err)); return; endif + USE nrtype -! save the dimension lengths -N_BANDS = dimLen ! number of elevation bands -print *, 'N_BANDS = ', N_BANDS + implicit none -! get the variable ID for the fraction of the area contained in each elevation band -err = nf90_inq_varid(NCID_EB, 'area_frac', ivarid_af) -if(err/=0)then; message=trim(message)//trim(nf90_strerror(err)); return; endif -err = nf90_inq_varid(NCID_EB, 'mean_elev', ivarid_me) -if(err/=0)then; message=trim(message)//trim(nf90_strerror(err)); return; endif + private + public :: GET_MBANDS_INFO -! allocate 1 data stucture -ALLOCATE(MBANDS(N_BANDS),STAT=IERR) - -! allocate data structures -ALLOCATE(Z_FORCING_grid(nspat1,nspat2),MBANDS_INFO_3d(nspat1,nspat2,n_bands),& - AF_TEMP(nspat1,nspat2,n_bands),ME_TEMP(nspat1,nspat2,n_bands),& - elev_mask(nspat1,nspat2),STAT=IERR) - -IF (IERR.NE.0) THEN - message="f-GET_MBANDS/problem allocating elevation band data structures" - err=100; return -ENDIF - -! import data into temporary stuctures -err = nf90_get_var(NCID_EB, ivarid_af, AF_TEMP, start=(/1,startSpat2,1/), count=(/nSpat1,nSpat2,n_bands/)); CALL HANDLE_ERR(err) -if(err/=0)then; message=trim(message)//trim(nf90_strerror(err)); return; endif - -! import data into temporary stuctures -err = nf90_get_var(NCID_EB, ivarid_me, me_TEMP, start=(/1,startSpat2,1/), count=(/nSpat1,nSpat2,n_bands/)); CALL HANDLE_ERR(err) -if(err/=0)then; message=trim(message)//trim(nf90_strerror(err)); return; endif - -! populate MBANDS_INFO_3d, Z_FORCING_grid and elev_mask -DO iSpat2=1,nSpat2 - DO iSpat1=1,nSpat1 - - MBANDS_INFO_3d(iSpat1,iSpat2,:)%Z_MID = me_TEMP(iSpat1,iSpat2,:) - MBANDS_INFO_3d(iSpat1,iSpat2,:)%AF = af_TEMP(iSpat1,iSpat2,:) - Z_FORCING_grid(iSpat1,iSpat2) = sum(me_TEMP(iSpat1,iSpat2,:)*af_TEMP(iSpat1,iSpat2,:)) ! estimate mean elevation of forcing using weighted mean of EB elevation - elev_mask(iSpat1,iSpat2) = me_TEMP(iSpat1,iSpat2,1) .EQ. NA_VALUE_SP ! if mean elevation first band is NA_VALUE, mask this grid cell - - if(.NOT.elev_mask(iSpat1,iSpat2)) THEN ! only check area fraction sum to 1 if not NA_VALUE - - if (abs(sum(MBANDS_INFO_3d(iSpat1,iSpat2,:)%AF)-1).GT.1E-2) then ! check that area fraction sum to 1 - - print *, "The area fraction of all the elevation bands do not add up to 1" - !print *, 'Difference with 1 = ', abs(sum(MBANDS_INFO_3d(iSpat1,iSpat2,:)%AF)-1) - print *, 'AF', MBANDS_INFO_3d(iSpat1,iSpat2,:)%AF - stop - - end if - end if - - END DO -END DO - -err = nf90_close(ncid_eb) -if (err.ne.0) write(*,*) trim(message); if (err.gt.0) stop - -DEALLOCATE(AF_TEMP, ME_TEMP) - -print *, 'Done populating data structures for elevation bands' +contains -END SUBROUTINE GET_MBANDS_INFO + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- get the number of elevation bands (used for allocate statements later) -------- + + subroutine GET_MBANDS_INFO(info, ierr, message) + + use info_types, only: fuse_info + use netcdf, only: nf90_open, nf90_nowrite, nf90_close, nf90_inq_dimid, & + nf90_inquire_dimension, nf90_strerror + + implicit none + + type(fuse_info), intent(inout) :: info + integer(i4b) , intent(out) :: ierr + character(*) , intent(out) :: message + + integer(i4b) :: ncid_eb, dimid_eb, dimLen + character(len=1024) :: cfile + + ierr=0; message="GET_MBANDS_INFO/" + + cfile = trim(info%files%input_path)//trim(info%files%elevbands_file) + + ierr = nf90_open(cfile, nf90_nowrite, ncid_eb) + if(ierr/=0) then + message=trim(message)//"nf90_open failed: "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_inq_dimid(ncid_eb, "elevation_band", dimid_eb) + if(ierr/=0) then + message=trim(message)//"nf90_inq_dimid failed: "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_inquire_dimension(ncid_eb, dimid_eb, len=dimLen) + if(ierr/=0) then + message=trim(message)//"nf90_inquire_dimension failed: "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_close(ncid_eb) + if(ierr/=0) then + message=trim(message)//"nf90_close failed: "//trim(nf90_strerror(ierr)) + return + endif + + info%snow%n_bands = dimLen + + end subroutine GET_MBANDS_INFO end module get_mbands_module diff --git a/build/FUSE_SRC/netcdf/slob b/build/FUSE_SRC/netcdf/slob deleted file mode 100755 index c8b4cbe0c11b4833f0bd06748ebf0e10a22945c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2578089 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�GkZCoLdaAjVLP^ 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

pH6xsXmgZFNsb(V-sgI=) z((J)-u&FaU(uyyW$IqT8V!}tH-iM#~UdT+Qguwha`vbn_mPEu?(Nf=tpNZ8!%8noE zKA_$9A3unHcf0i8h;PByqc>9H$M0Ud*lqv#ftM8Ds5hBEJN@o<+dn&DY5=MJ-R-u2 z^kV#0ul`B(?{2sK2cj+ff_?3i>c2BPtB%#`OW+sck>BKX$HGRqn!RIXr`l5rTl1Gv zh?-s$j&|KKv#H^C%na;zH{_VaL%_4ZE5P3Xn8fF`h0p=t0Y@%E-v<1EvVRTtr@&zs z=9s4fwZNr-viDw`V|D{h24(|GfZG9OKjESra}aPAa3Qb`cotCh85if66~F@E7GM+b z9-!>;OLEK*a0BoJuoK8w;@Gc)`*PqB;BD$J%`y7{%Kt-f{~CA$_yMpk%P~s;Wq%Fs zSAg$;BbOrofFDryui^d_IBXg657Yve0?OWdIr0yj49o_W0Jj6me!>dmA2G^0JsI%1iS|*dwdo058MDe0qg`aF1N>D#i11K8VxrdT7)05cdnxi4ZIX~ z^jZG2gt+GTO@Crs3x|EGajR=J@ThCmc-6IPwCY+lPIavsBYs{Z%<*)-90#jPsfjlS z>qGvq{Ot;+Lw(Tss!Hd#;)f^vG4V$kq*Qj1-ejsBQmVaUmrS**T)FvIxpcF49KTY- zSEb_SUzJiPc8<&k%Ac?wAb+<14&!?=eZqc#{0aL3@+a&E$e*yg=MOP=k~{3D$oi+f zWA0Mz9cwSu&fMwYb<9mFzhiDv?HzOD*oEIta-`z7?HzNJYVVk%RJ(h9+2ME0VXFU* zIZU;8%%QT|mW~-rvv`9sVd8?Tl=+B@dXNx$&lA$O^E=1%38{EoRv<#)_Ys=Z@w9J}z_Nsd(f zw!LGHQtj^T(e}?ArG8TVcg$g`y<-kj?HzNd?6#$22Gi^vGMHxXkij&2hYY6KJ7h4; z-XVi&_GAXDN<-25D1JxHhz6o~|4M!2`X0+8zkS1@3{vX$4w(fDet{kBKt_fYthv5D-@DXqrt|tI3 z0PWi*b}>JI`%T~wxF-Vhfx7|Pvn#roy(e`sy8-3E0^lCtb%6Gfle?Iu;G6=q0QUla z2XdgNeZZv_Bu|YVL*m6~Kaf3J?cw0cby_xvNob5Q0PW-A2s75zJRDd8JP5o8#Un~ARG^*}*OSNujZw$o;;g zcg-Z6YQIkr((P)$FWruDDu7>Ngc@g5@?M#KXGZ2lq6;Ecc`O#?&R*>mUCpzAYG5KT z4mcSo1_lBaa2SvebOj9HyUS4*z=yzFz*gV|;BjCBa2Iehum)HLECQN=0B{aa4U_?+ zfw>6p|4kGl4SM+us0fU<#uXhi$ilD1)(0B!Yp8WG{*VOQ@E44r;2(+Zp#Q2+Lf;!i9zH|43yXW>0tXxTq8^P z?Ln!4-Cw6Is$c(kSFfXcHUG@e)1Nm(yt zKuY#H+8Gfg+c;&Tlp!h4mvWwzVJSIjkspyVDkb|a^%qFVZ1I{ENXapZvPDY1`@w5I zA5GaRC0h%x7fESp(!_x!ZPf9%kLVsD?KnzK+A^f=NsT{Hx_PTXf0Shw)?;bcdU(3M z1Uw#?((g{`hdLG4dzvm&^4`~USyK0brc?R(P}6mnypN>rV<}4^RUST(x^hUBrd^s& zrRh^mr_%IKO{e1L0|(3(9@R;Pw_DSx@IKdcD!eZ=oeJ+usoNuE6{O1lS5k+^wUTlD zOVg>izSeXquDzO0h4+o7Q}KT*b!}44gjD79y{1!f?bCEBt{*g=3U|NMoein{{wQ@n zNy+xE+C2NBikEKXhi(-Q-6}71tGMV^ZJ{1+Rrf)-RhV?EFzHrd(yhW_e^z|D6`yX! zr(5yauT^^3x0PSIm0!A*U%GX^3Wxn%`K4R=rCa%>Tk+ZN6^Cx6FM(V2^^6R=ow96{ zj`l9H&+vOu*^X&fI@*h*Jx8-E9s8Avx2v?Xyp@i2m0td?62qrm>1gkoW$SxrcBP{| zSK9fVgv!6tm1*`oY3Eq2>^-Hf96FWf-crYURyx{Mo)6LNN=Lg&(_xxj>1bDFa=2z! zI@(p5j@0Z*HxYJKCO?yQ&MituyGje+^I|#Bu5`4kwD5cIm0js*A1KT57|pJ9lVDeI z6-qnjG^HCTbrsO5_Bu%F*#4D{c2%awYj&lhU8Q-5W>-4eRhbRb>`F(w%2P;lQ;)~| zM7~eZ{Hb}EHkFqXrJXjV!=rb}@;O=BId`k_!6RzPHa%L}Ij5_3PP^ic(diWoZoJfSE>LlnNgc-=rK4TN$yGJOqh0A}S8-0#>`M0}o}eS2{-#L# zG+e9tn<{l2x0H@{Re#eodr}8`583w4(CkV#L+Yl3r}8mV>SCIXc9oB_G`rH#uJUoV zW>>lyT3EBCopX(flXle}&eiNnN4tuP-wD7nqJO2MUB$&`(Uo24YBX-Wv~yjj{L`+u zLCvmobER%3c&fjJq>gie($TK!W}aqOI@(p;G--CFqg~CNQO&M&w5z(iK(i|y?W(`V zHM`RBIb2nyEz-_)tkQ9Ppxg_jopYMf(QeB2#0Lyn&gVd?dR!#^a1E?ZT*?}$UnQ^4l-FlTxmxPqk@9S*pDpFJQeP{t>!l1y*(l{r zk{6ZNF)3T5WFI_I=I?gJ)pU1C-Q7|yk^cBSd?H`+`T=>(-%F>Sb*aMLAZ;z0?h47f zQp$~z^RSfHN?P1N$@lA2@oUMqH zI>qJKrrafPtNP{lJu|<4O~*M!*|$nN=NzSDnJf3J(#~;F=~#Bky-nI#c1pJcZq+CM zF6~?+D;@2s{chLnN=Lg2>n+W$bhN8Acth&ix6Am4OFMZge9rsIeS)-eU7&Qq!FHa; zNZZY_92%sa-y6g{FOmAo<@IVQCrVi%Sdw^~R2LWZZt2i1>z%doiyQo6^a?lCP5QFcIlm52^UqXnyaP zJaw<}3(fX`wB4ZTek*l1X}aG@-EEp~i`3n%>HaKrzt(hrk-9%>I_5{u-|r>oK`9@S za-)=gkn&+EACdA=DIb^e2`QhF@@Xlbk#dui&r12clrKp6qLiDZd`ZferF=z7mJQR- z_QrfsvK*A|Pg2KxsXAdEl$+^SZkB~|)1PuPEqWQLGGkoIMmO`O`%!MDRk@iqa$nVS zbgT5fDeZ4d`HqzDO8K6YA4vI;l%GiXsg$2d`MH!|O8K0Wd}E5~Xp{0zDgPzq4^mzz zlJbyjG;-;#hMQqgr}A-z)J>PNH>4_q8B$jxE&y1tMqjps_;F_3D^I8W+)QWi@&T*?tro*?B&DNmI0Bq>jpa+H*eSH*FP z)Qy(%R4KM^= zfs}D6Tck`ts&&Ew&8BnSDKC}sN-3|B@@grsk@7kze<9@!Qr;xxEmHnc z%G;#8UCKM9yj#k9rTn#&_euGHl)sbm_fkG2k-b>0Xe!%~HNBJHKTydiZbYPvV2 zZabv%`?l24rgY4oa=#<(%%9R7rn%ph_LDW;ds4@~tkyjrNFCd>($TKM{7ADa-BFtT z6KQ8(SN2b(ZkML}OzLP;ydj$Vb7`Nd>5hS0rRhs)FV%FktFXS(>`F(wS`U4#*_Cdf z=KmXMpQ!1+le*(I-S<*AMbrHtbw5hkE~Wk2Y(Udn)!K`9%goGWFclp!h4mvWwzVJVxWj7S-kvRO*|)!+8^n7ocl znUJzY%K1_*kg`?Eg;Fk(@u$7fX4GluM+%RLaYwTq@-0gIih5xMPepPc9b;EZv08CG@<~~7l zAELPr)!c_^?gGu-PjmOz+{bI~VVe6TxSs}?2D;yn?%N@slZYZxN{ zhWTg62c`Qy$eT3x?b6*N&*qMYd_=k{HTM~s`%KL}TXT6J21%6ut%O4&=w-ct6F@(?KxmGUqt`$~DZlt)N; zq?83x{!GfFq&!+mOUiyy_LuS)DF;YdDCG`WZaMf;$`b*WVOP!FO>_6q+#b!{Q*)2j z++#HNX`1_V%{^Xoa}SB}Zoq zvcKHdsFv5qF)BVN(7~%0elpOWsT=eNy_R z3`%*vlov{Wzm(VfzAC0;xzyh#uP>0YS<1MS2`O8pyiCgbWH}bdaMnouHBz!Z3g!K7 z#!+^heoZ$XZngiECGB;Zj`m}u{~XP(bhHnb_O6;;>0W|e-BWdw_D?h&+l7k1hqMPY z9qlSEk7ido+ErY6nqBE=A1Kq;Q?n}_?L(x!w`NzmUMOF6A9#qg_ttd(i@ooFv!YnO zo}A}`3MwL5a?UyDoU`N%l5h4I0-_)ak_;FTbNu>jSFyd9 zMbYQ;eeeI+`%5AeHTd~nJip>+ z4St^Mf{LFt_>0l_3oCxsa6aIJuyd(MXnG$R8 z^IUaS{H%2n8n2ZuK2zepdXOKVDX|7W_ti`Bv(`z>56AW)Kc0@v{a$uchINpEcYU zTt(-fk>nq(Xz=s-XSCvH4SvowR`IjeU(5xspYi0!GdZjc6r9)UMDpXA9M;;2{3g{m znfzlE4St@BsfwR9-0$#OpH6-}OT!xcT+2+w&l>z(%Phsu8vMMk<|uyF;OAPdQ~a!T zP}zD^}k;6v$j%bJf|DTk8!YOh_P~g50c+hH2Arejf$T& z__>x%ik~(3xt2#2KWnIu@0lJaKk8!*_hETxd{2@e_i3!b&wXuH{H(#xeLbW2S=%oB zJpSj%e^Sxl=dr$^_*sLW``V)TS%aVZdRg(a_Jq)QUu-2m#>pD)vpCl_^5Z^>HTd(; z{OnNttl@na^Vi5fRMFt)T(2vB*4`9;o}b<1|60-D=egLc_*sLWbL~_7tijK7@wVb; zZKu$9E)I|%<6v#2vQ`h0AJ5To&G2(A?^e%9d6L-T)3@w0~O z5c3n{$90S~__?nS6+deaiu^p5kI9ec`B;OW$MT8dXAOSN^_k*l4StjA|3dMz20zz& zO7XLX^E~%;n*2DgvIalLexvwVgP&{pPVut_ze)A|p!iwaD17`}1$ZWk)pDfPper0Y z&mDB;&}&g!=*$-?`4NNb12pajvCuq$JZ6J5U(rk@j{CHfIM!?>j%#p~IM!U!@azGP zADrvTDEwT{MGA+`eL-iwSjmGJj0qa&LoBq*1#;etNz0;WmndNN{M4FuM)>K zCUnSfO!0h=o=`Aoo{_w2F#W zT8ZO6%P4WIl~v-nhH^?AYvoD9GcG)SaIUL{@N+#i6%L*Ig3f$}k_Ryu6Ex0;SZECd za^6~`HB_|PN*w2|qr|aRmoz-D!}Wu6e=U@p9K-##RD6izoE*nC;+P|j=Z@ppMjZ2d zlp3I8%pC=C->nsmbGKDA&eNW>ZOZt-d3@cKoIMl{o%2Fx4xMvDXTDC!j~LVojr&0? zwEhBl3_VF3plH36IPSBz631E}C5~(8tHiO^k2G9UxL=%Knd4l=9LFtltYPNZPs}lQ z%r%j_uCOsKaI^>46&;*)Tu(S2oON7NSO;ev*A>>mS;w`7b#T^kePJD(bzEau2WK7E zI@YHNj@ogpV{JNVfuhYIEmX9bq(zE$Eorf$%_1$KXtPPnplEYQ%c*GKTz4)-2WLIE zqJy)ZN72Dqze>@;S9Uba2-5D>^vqxEAqT-Xu8Y7uO=z7Lry-(H4bts-rpqTNN>AVphE+BJ%HH)(?v?HVz_p2*71BW>)@;-hR<`4DLGl^xP>B)>v)K2gU0o2R5U)f zp)SnlY!L?>uEcOHn@GzkPKkW&1m~L8DtwfP<#ym)8_vJ1gR_ojoLL8F9Wk8$6(uL@ z9EW>e9?J--bFR=ZmXTyHRbo&ReAiLTXeEa0*h1QK0y#H0Uz5POHq^m$4$gCpXOX!r zbo@Mv?VAKg4bV9c;+b|X_P3^m7hlGuOUJ%G@1f1^+5YPFMhdJkA`yS!rvA$0=L*p8bC>qx?fwTo8 z4mC_9dzG-c{}ZHPt#Z3r6yIG)Xg5j3)FllZ`vE%c1y~1XeV3wxvyK=Z&$miW);SLM zyIjjSs_zD&q0jMTuTx@B6MQ#P%w#2o>pM-_BQ&O*0(lM$VW7Q9n2}I`R+@4a6C5$X zWX^Ue(EuCbn6q70=-A+6&UP+M{BKOL!6!mAoBFISI5y}&jsdc+_QQRZpf+U)%Mz9& zEKgX0up(h$!i#guKC6;lfUqDTJ`);AyobQzV(XP;v%fa!4+&(BShT^q{ zgnJ1QUsG)O%mDE>Q@)ji7ty@&-=--|ais*-$tl(n+3e^2!hW_9hj_NJA61*%^ZrB} z{A{zI_b=yTo8#HWdO&-&xjn`>jOGSEpT!1kc#_8Y2t~)|Mu;6r8r!23o7;^}(pVpp zj?TWZP37xqB@v5_@6Cb9obC4trCv8n6rpoBVJX7Wgk=cJ5|$$@PgsGlB4H)M z%7j%2s}fcttWH>iuqI(G!rFv&2%GvQ*wrG(1}Zzo(%xPovM;cCKr2-gsR8 z@JYhWgwGH@NB9Ea7Q&Yaw-Rn6+(Gyn;p>FE3HK82BYd0i0O3Kx_XrOY9w9tN*rTZ2 zf3JxXFOKyUDoBo-hnM_8S(BjGH<8wghtK1Eo)rOeZZa1h}P!XW+u!} zIFhhMXBjt*@O#1xS4%xNVFkh=gu@9Bc9C%>2u~6IN;smc^iLq1O87P5uY_SY8FvX` z3&I|RBMG+O$2~QJN8ZY%H z2%jY!C2klHzk~1x!jY4t{yky2snTvqcs=1Wg!(k;j|eX&EKN9-@H)a{(`Ecg!qbF5 z6Gk(nKPzDl!Xbns2*(jNoh{=B5!RS1?Iwi12&Y^p^?8JQ2({~_Uj7D&^$6P%jw4)7 z*n7T=8%DT^aQyaI z2p=W9g3uv!2|dDGgg#+F7!pQ=F=2u*17SwOiwG|!>_OO*uoq!(!ajt33HuTDCmcXH zkZ=&;HH3o+hY$`W97Z^ta0KBT-CAY@P9!jkr@1@voAk{NUU#IQI*V4K)C{UvTc1 z&ohYO^9wkiSHSsv0?y|Va6W&4^LYcD&lli)o&e|b12~@-!1;Ut&gTJeKK{YE?c*1T z;>CvJ9Xg*6&?jHd!Ev0!kK+@F;}VGD5s2dsi1iM{ItOBX1F^1wSkFMLV<6Tq5bGAW zpX~BI?Fh*A+DG z7o7VA=YGMtU$oQi}$!uLZ>WEFixp*-rKj!kvV#5$+Lu}j@>+pow)O?8fL~PHCO^xGyf;QloBh<(BvyL@@cBmP7&@cP2Kh^Oh=TL35 z=P_Y^k?U!(VUEy0@_l4lx4{Tv-PY#ngagAq=Ydv$^Z!pLG26NnR zFvtA{bKGw*$NdI#+;1@F`wi7r`{(-&)vwk8zgi1ywI0}NO|aFvV5_ykR_nv~)wzL< z7_JAlI!EAYeX!N~#O<}#LTo+6hI#L;@S1|RCA}xL>Cf=Sg4Yro+BQ{qeTCzBt{!3&C8WfmeX@oc>X9EcFh>n4=X+Gt z!yNgT<33h=9C@Z6)kb})jT%*3OkElqeP5DG=0bnWv45DOZ{}i}&+J2t0c|iZ$ip1S z9CN@Nd6;ty?|+VC8-C{8j%{wsYlYjg4L@^k%Qk$ObEp0uf@*Vqb}<-9Pxa-A)YznnIoP##>5=sVU9fQ#fG|( zhdJ^vM;_+L!yI{-L+9U_fX*EAQcP^f0YpDIu7(rGe#8bH$a7d*aLgU@@-YAn=NZm} zSUyIvPsWQ4dHM@Pzu-6yu&=-e2*en{8w3A?z<{iA`xtY`W2l*A z<2u35l$26ot=0!ytq*;v^}$x_!&=0e z=e5<~2DvuA7AJ44kypvyEfz8CQq3fuXf3g2M~QR91sMJYWPdA?!X7Y2;;g9>tIwAB z)EtT5&y{%NO%e_9@G;tD6^jpeV3@>1BPCY7R^q^g5>G9YID_gMO?6q~fK16VLSj+s zH#6+U=!rW~6o>(mXj-=hcK?%$M<{mP#B-&wTv2T-rB?6A1E69WQa^ zWQp5mO0;g4_!d2zbGQTP;+_ZXy3?~sQ>IC~C)Kl^^1ev>|GOp9zn|Loyjt3q&^X?q zdB{NXS)A%9KSjnhruKVi9_CSh@6!D2B)n4Gte~!Esr@M$$7pIlZJzYMPW$Iq8dpWy z{~yxNO)u^)i?DYOCee(8y3sBf%L4=QaUbn5x&w_`p42Zdfq7QQIz*4I=*qy z!2H}s>pBnh({Q-duNx(CJN5fD&Erto|M@8I=QMwL==f-I7l*J{FNXne2IdErGm zF1Jx#-_U-XNb~yu)nAR~Z#1ok<22ttw3GEc)kWf!v~C`zxB*oEZBwPc9@SlDk+i?1 zb=iQ9&&zL>`n={6AE0qRLi_0nia$dA%%(ctX(8i3r}bN%j<033|8~)Q)*2(@ex~`F zMDsP5_E#~=e;v)&L^@BMCag)v=^aC49-qe7k=EfLIxaHOe(Fl&DMtHw9OW-e^=6@Y zJ4ty9(f*uA`=Ji4lgnrw&!+YTslE)fKl||cgvQZ~>Rn6iPSA1WP`yW~-tn|wUZ-_% zgzzZ!Q=N|2r)a#{sJ}O8K5wObKhpVsHMMJhhn$}kbUZAjdUnt_KceeG&WSQ^5v{N1 zM@V}at3Gb!#yO-wqEy_2G)ZBdo6~W1lyD)<&n#MRV`;vxpmmdbsLVTr)=l9N(#}omXW=+$H>CM$K-hxkk8nQW z0>T<}y_-(>Jgp~xip*D&a0IP$o6bLwXWd>jQ)X=)AIla6j$mX0%^D!tR7+=y-aGt_N4rb*dF%JKFzQ>G*C(c#!t{ z4#MnoJg*rm>nlt9|3Sjxv<{rn(qEY{8y#Oc2oDl|P1uO?)gatS>u4jbhlzB&b*A%i zHChL)=sfZT;rKbS-B}Sdp-y_@@(ye?$C}3gF%;5^JxJaSI5=;izFl z3~+$L#iihkp6r9oe*A4>v0GAN#p&)0$Nz!i|NR8c|Bnis|JM}$x04#f|8weq&>s;S z>iSCHfo&7??-T-;7?FI_|wGkwx7-3O}Uq_Z5Cb;l~tyT;U%m{6mFf?zk_^ z8*|JhbByIlv0?vU9-bqPI+>#{=9o9sjrie?#EFDc2&WNFAe>4#p73tMdkL>4oJlyF za1P;o!W#$|5Y8pMm2e^9I>HADHxX_me2Q>0;q!#}pI#W(vxNA+Uapl#DKG2PH^rEob!Nl9&nB? zuf%|}UP0j%1?QaL98*cr!C9}V=-^xfIM)EK#`8Qw=XtKBv<2sQaE=G(_}YT=dI#s4 z!MO%-t^vG`*sun`IX^h(2j~2V<(%N06P$B`a~^Qc1I~Hi=RDw?2b}YOV?%8~&I8VQ z>Iu$yz&Q^%=K<$D;G74X^VAod^MG?aILCu?JdoqTxnFSZ7o78ea~^PP7*`2_!-$tu zIAU4PDee=R2)iZ4!ETylH%qdcC)q8MY~g|+S^`Jk7z@rztb?o^Wr2WK7g$2vIcm|NDtS;skqL9lTr2m*ejxmf z#D;p<=DEOlpmBcK;M|^VHD2u>e%NYz*x1k?<_NhsA8ggnbI$Rwk&Ekv4Iht>ZH~vh zBRAIvTb)0?=5qgRb9=VAKfV^TpRdQsHuuNZW%jep`Pk-ozD9FAUw64aw%L#K1ANIg z=Vw3XhmHB;{Q+B@57@}X{W0fwwz)sHxj)#5RolZ>rC2$ItW4ey)#g%s*<{BR157@vAnj z1+cO4H5nS}Mqhl*Kwan;SX^w##kqOTpdlVLH4qzeLW3V1HE|#CBMv&x4d>&vq}sUe zORg1Ka&Bnp<;I+%FZh{rKCTJ1?-U#BsJ)1Y2kIpx8ibWd&qY|B@KW+$Mwl=gw+VekMmR7UqzUgum)jHfqZX)dpG9Ln+O|o3EouU&4}~8AjjZ75S;G`S;ze# z>&%g}rJ^&3-b&G#=OQgPVIIP(2=fx=BgC3OpExFf1qllg;=UI;))o-Q3J~W8ARjX& z$i`ZO&iCs$7GUH22*lb4;`|82eE<;e%Yj(;KwQ6pI8Oj^d;@X(0gzX616Lui%NZ5%`eB6;TPVwXa6r4ghtDv-J6aGZU z+bY7KXw_+1a^czztXg^-`W=I6GTk$xLt?~*dUBw;DS(u8FQ%Mz9& zEKgX0up(h4!pekI2&)oSBdktXgRmxHEyCJ_bqMPc)+4M>*nqGhVI#uEgiQ#W5;h}j zPS}F5C1ESV)`V>c+Y+`TY){yMup?n7!p?+O6Lul&O4yCCJ7EvPo`k&!@1k|Gn(%(Y z2MO;byoYdIPPsn~abm?fz~B4@E+oX?{e^uq;Yy0zL0G`jQ~U)93lSD3EJ9e6uoz)+ z!V-if2}=={CM-i(marUQdBO^W6$vX5Rwk@MSe39EVRgb9gf$6k5!NQGLs*xv9$|gL z280a>8xb}pY(m(Suo+=jP4FS4gAY~sFoh3S_z2=p3gnzmDSWfw zobzdgL+AX^nU~b%zAtaknlL3UBD{qV{|5r~FCoPLe1N@-@HWER3GX0WPIxCF{w6=# z;eQ7Jzb3q!@Ls|-glh?1aZy0LLHG^ny9vJ}+(&qd@GZi339Hg)-4zIH66V(BXO!LP zGw;oWMhn^R1j1#6uM^%`M*1r`vVEJD((X+-mhehj`k$ouex%PQY)t;8WZzA=lj^&l z?86IX91~Om;oO5rkt2GnbX|Ha%B|C%r+eID7R$Sz5EKjHCAa-3h0{T-o0&o*2^n46z_S_mke2?9a=|`hO<$#7#GjgKC7YW|4WfkiDPqG~wl0rT;gw9dWab_N}`~oL*jH zcha9HoKJW>n`~cO+~lL(2V@T+dl2Cy!Xt!735!>d?S3JuIVG=gA%fiV`P8d zSLzK3vs9M0M|hmtFQW6=VnY1F1p2>&+HII7?E|$X<|2Pr!q$Xa=vkD8l>bN4XA!od zXT1iOk##O0I|pGV@z4qStwp$+@Fd~dfzrRaoNRxP?8~cAU4ta9sUZDr$Zkgd5oE6* z+)OyXl8g`Oc>0m-X5zsX)bn%|>3@#w*9iL&UP{ldRU;fgIF4`@VfLyrPZ_d{50UwY z5SFeg?X6_*t|sGup!gv}rN3)+sV^XWh4hMaJ;+M9gz_~adotlz!VQFZ>3UapxXjyMK9)r7MM zw-aWqF8x=HmRPQd%wLV{MP#p_^H#<&GHz9K8TSNXofgvmneurxWZY@ezaq@iQpS}g z%sy7e=sdHJ@;^+v zIbFtwb*LY*AMGUVHT`7XM+tAHJa-UUGi2PIH%c5tc@~mBk8nBRrdBd;Bin?}5Pm>d zWsvMQ+e{hXi*N&B9>Qk`KO}5TxSen(;k$(8u90~M4VJi%?80?rKc}vhc$)CiS<>D< zQpWctyU0*!ccFGY2se_xXBhQEdW+dIPd~x|gzE_B5+>%zxT9njAbSwuY{IuG?-8=~ zxw734q<1H~-xyiP+hiXiEL%^;|48=cGSYrvoQ&@~UgEP9x0P_^^)hblBC&?(*JN5iFuYvtV{1}u2>}F zhcuG<7{d1{F1SVdA0~YX*#&Qv@sBN*{-b1�-R&5^DF#cAEItftn%y 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

0uD{hp{P22h=>}V>WKDC4$!Ymk@=w1 z+1O1c_tCcr^O%%F=7FA)V^dFIASDOMG;E~Dr^?Z{lY?beG}4n&7AtmtPv>c=T~H@E zQs?_Wn2%bZ2WG9Ti82y$t%}iCKfuq{|jA;+27;_e)sUfc*nq|F?r|NalGW0rme9qVse3LC&%Et;mF64uv z<$;6+V2aK`f9sp7X96dIDoQPSH_7}o=VDYvYOxwMmUAH{t<2l;vV<<+b@iBo)oi8YJ*_#3-oj%Ycb*jpt(&>tN zNu8#kwoZG>JY7K@oDiBJb%ug!ok`UCECqFQuBObhm0{Kkh5VL<{0F*EWomC$i1T-> z7pV)*l}t6~I7|(x3l(HJFQURzmnu=VfAy6$7Csyyde zs=k&j$U-h-b=}RD=h4g>${4%9$T%n?V+mz6rIa4WA{Oz1+}MT8gE1MTrqHg97GebErS@S3Iju2e zq-Ii0cDWqvw^FmH6DRS@S*x>`3S_H>oue8yET5fIb5$Kjk;e*fwK*5+=~>pBh-X=B zjp&VNP&;*d`wC=r3bVR{_06momSeTXcnmftHPa9!&n!Nz1i8$0D-Dw;pJctpI zuK7$9(j-l~maI&Z+acY4DVQR{)PYQqKccs%J5vyBK{Ro?3&pgpN7l)EqRXLeIQaml zM`t{AOFpP(O3euqdPq%_`1Ff1BsZ##$Axhf5@cCiCt7dD6k;V`_zIYkCsC_f$tv_x zz2qTmkd2ZAR$EhxwgX{Fa@*<@@)?U!m3-|wL|F$*z>wVjsX&%95CbFmW+E-+aRSWs zA4dxmc5cM@OTNEEps3Rmt(g2kL3vJFRCMygYlT+i^ye)9v7(ha-*f)l#dkQ{1EjihHi{v5wT&VIG3qE9_G9@O@<6)V6m+O!Oo zmDEg$CeiGbNWT>H=$R%wyd=N48Y_|`>-?7#&i0aJ{woDpj;!)uE68?ak^e?PVMo^Z zZxs}EWQqSyL3xg>@ZT$_$dLv92L+X?^&PHKB*Uay-*peHRO`Fxfo)S)vQq?fHSKjs zSy=aySsvI;t+UxW+to<-RcmxmXQ|BeJ$h;a`ft+F?-h81u7z2TcL0*j6$Wz{ofCuk zL7-YOPMW;QKmCtm$e43$EABE9s9-y0f7&`5Ea@*XW(e_=@CshbwlHBSTX_#_j^ z;i8W7F&0%+t9gYqelRvJr39_!T_XNQCDtJZ#Mc?bqY7a`t6Djg)wy;UP_^}f?{Yl! zGRkz>zi30i)U{!fW)w?Ny3M1+D%tsTpM@XWGg`~GN9)0_00w@PM7tF!dVZV*=rnU9 zMt0W)j8UoXJR@UVY%-ggGr-n;;xyEez*@~sKy+KqB3)(<07vI;+~*jVn|zNCuopJq zd~Iv&GW-@`reM>}lojsv}aT+PzrON(cvd+5A4}j+#lk0=l<6rpzOkFo!)NfBI ziXp{nQ31X6PoQ>Su~dLL3asr{q9+6vOH{+O8Cc9Bbi5B`3M}Sfkd7ZfvWlYf@OZ{v zdK~>;uM_b+N_Q^;%Tdr))B2!7_5Q4q4#4zfYvTt>AX6XRkG(+Oo3w*L>z~BqY0&$z z-SvH#?|g)QY^(~ztY*wYXm zM6zy@tfwT?269-h0_A=Lqp!IQ47EH7So=K)+Mp6d(Q7ngZ*vz((%1Ws1SW)n43O?M z#N>CI^QhlIj`JTNssP0`_A{%&)NEi3Cb>IEtPNwR*^Gqh>Vwucax8r$h)cf;+3O&2 zeLKIpq86)GRae|%OVcGqf0RzUo~p>8&b5G-vw8z$WGmRf^rF=*fY=ie9tZajsaPe_ zz;8^|od?3-5o(d&KB&9`$qkh^C!^GnVmy(GK$Q?mcNoG|UTz&)=2n}@trwU^BB0MrwywEEAH#DT;SX9LBTse<_q*b$cjb2XXxSJw+nD-b54 zYMAv?lJy&Y*7Y9Q*xWqptw^b|-i6p+NGe%p2LRPiMv~(ZBjP8 zsJjtvL3-62UXTjp$xhYx6nqk8+yuru5L9nag!4pHe;b45G00HM#LKcwX!S3Hc_$M{ z7kNV@UoQ#v*Wcv6cbcw!6SD1Z;YtkXj-3!ViRsfhC=VFsAbML}2rMo_Wk<}D?1=ho z&J6sZr`1=0pdo$V!zpjBnww^gm(66q4D8n; zDAli}>cMs%ZB%^+kKv%$HJUa`7T~XC0oJknsJZS38BiSn_wNN|SEK6HT=%WCQXLs(04aDH zU~LdL5M#iN6X_d~p!R9NwGZGijOSv8zl7L`H}F_ZZpD5H*)8jnmh7B^o7mS1dwm2- zClJ(xqRx?XLK&(rK~ozq8#0&Ff}{QSxYL3}|3vZjox>UPuLk#QZvnR-uZbC3jVfrs z*A=R`ZyKE1huLV`0T6I7!g3^5McyII(?L{4R`A_`wSn9qE(G_@2*y8*+mWa?%@S{A z5jr6@d@np8_cm}mi0~{}R1v-xx%y~rFs1whv|=c3d}b&KyLOYHjlPCU)i%8rTn{7s z3mQzQ#hHI@MvPb4(aONlPxhd%vp}N>^6-rD2Ehh^!)(mY{baxS7JJhjz#YW(b~+?3 zV*c-`<(6BCwx}TE5kuby{NX=@>_39p?TkLdedWUj(|-+A|0HDI15H$YJu2l&h5Y(b zaCgAo$_{Sh3FBELP+1M)rf?*&&l+D6`!(Q$xoS@%GFxxHV%Jwgk)8-@)_6fOJCMS) zL!QIK>LLALJUDLt5f@cKncPL~+^nwD_&i_^v{83fR}vm1cvk>mH)N=71K4K@-o;zp z_|7*MbIgI9N~~@iw4Dgvj|#QAlX-uDeScu4y?ChFSUvX8$0C519fzFjj)4jb5FSR2 z_1lT6w0beoBS@sxT>-+K2=9@|U4$ja-(Lh#wulPcN#6P{kjAo%+8kDG66;sEgS6{XgH4G8cL;t@_HVH^qd)N2(&Ur8~W1bwt%mjNsDhBcSl_A|(i zzbp&x2DDZhs*49Mx^PA?dMXn`x4UC4V@(>}byg+J4eaH+E4*ydd*~c@-Pv7wDKkXO zrru(DbUO``p|O{WpTa$7A2CnHyw6OQ8#R-=BJG4pGc;qUe2u8FfKbN8QfXwZrXYh^ zE-YG2+YIImT?~+#!NkZ$?E*>FO(rfC*J{R)Dhtr1N@fd_qUOtPAoHk*ag|b3<9u?p z#JkgNqOnGl?xvxW7}w}eqta?_&FB!4?y1#0lEFlcTUfC*TQZnDL+SZ3F`{Rsq*8jS zxK@K*kEds~C$kEe?lPTq6-;NDH##?;b+nojm~4Mm^hks6NII(&he(Q=38YGvhd0Yo z#kHFGnJmYtEIa#CL(Tgj)y_wEuAPQQ=iy879KM2&3;4JikD7Jh8GZ*rIlx}?AmQf# z!ysmKyF_1P^dpIGM^xp|q7Aeb&|$Y>gpKNtjvFvvKPSc)XdKlY4#Pxbt(GR#KS0N9 zhfZgmOHz9o?B}wFwwIy2ibJ`hjQM++aYq@^ySVgrk|Fk$sB;XYbmWG@dYB}w=0+l_ zIaVKIGk07M;nw5Ktg}k@Jkxa+-e=>GOfdS)q{?G0|x5UK3M1aKvDe$o$;4|+n0sL0N{zFqjCWA z@R)v+93ESW=qMf@({Gl(n?lwDSTp)90zVCSNHz+m-zMYQSU7$^8oqbS5RRh$Wfj%$ z5l!v_EIV@jPeMO@Iw}h{MP_F^cDGmYqFygBSbu}?lQ7x_%uGo4Xm7OiRe)>HI2n)I z0gX5ZkpdU<;07?Rz`8iR9eP$h(>{kVyeFXkTR=M;v=KuA%>(y{gAh3t5p5vX!wbN9 zErM~Ru>fqUU)B?|4q?O;FkeDu%;iVujy(Zk4aGfy%x@u~ZZuG15Y`iYC(w@wdS9Rp zK=>2UR|EYb(S!I(>Rsq$JfvUT3;AUR*DxF)*O~^{2oA8FNHT(h%!nhS7jUBfb%Z3+ zjo_%t2UhD}gmg7PsWDeK1RP@#4j>nYWm|BK;Lz+t_OUGVR_OIMf^pw8>L7OakzGOP z#pUh(lZkA4<5ZtxICd+95gfmVQ3|w~kMw6CtY*T#6M zrM$Z9knB!`_n7okq~Nz&>>gPG0aUnbl-@@5m)X#fj)QGpcXc~_% z)EyB(`ykY_&$NQrKpqtx4b&KfLx~OoT_oszfjR(T4$)siMtece2kH!jbBOK;?*2fJ z=#9uI(xq6NSgecno59k&nyy2#`w&J912-=!@UQN5R2)t|*{_3JUb%SV=WNMtgz4A^ zB794#ST%3T0(YNK4*_K?Lh)Wc^&O$|=A1St7xT#usG=7e+rd!V4RCEWALV!qvjeEF zI>biohX-#e4nG)?{$qeY8T`W+0UEvxk712uJsYw5ce9`i!iY-&1@cu9RzQW-2$v$& zh{+(NNvOLNsH+jy5q&Grdkgw$pm3bWeun6WfgVS6{Wn0_xO+0CJ#MNrG20n&G>Whpok)B%rk-KiGI4TO)u!-G$e)Hxx?E=0JA zsioAt^hSuiNT`cIxgR0Y56j91Y8BA=mBL)TacTcuXtBRBnY5)XHUBJ=4d$!fE0OF* z1RXX&4dB{JJnDVy@Vx*HAA|?~>X^mn2y>CmfLltCO+r+D7t;FMS*U3exY^N@LWmUs z=3dZ)D*@6Kg^cd44Xn)gsCI z0U-AqHwS)C6wFht_`{|hT{g?Q5YKV?-RKO4tLr-;k=MfYVi^A4W_urBxRa8PFS(k% zH{yLev4Yx9MKoY;f2G8>dFQTgA8OKxT`yqn1a`cORo|Gp5^S2*XxKgRukU_w;HEJe zFy94J-v_W78#Ai}u~iV%We&g51k4ZDgChYwjAImHClEt=Ac=mZPOBqeCNGHD6S9y~ zWjTfD`h?t8INo~+vjA`!)Tz4M170lzaD@Vn{sYIvLW;#MaSL(|uY}zGb(%Ku38eke z)FvDcV%1$8fztJ(UoFMI&KwTl-vK=)98KA>Zv}ZPsz7fmDg?|)1+DB!As6I&ou5f` zebNy0wz5a%JT=rBj~TUmHNW-(I04$1pXUMZqi$Ol@iGi3-$8*kCyI{xgo`mA+P331 z3EABPpt^+nN@%m>yqJCTRusFs)%R33V6Fki-cbopcYUCCb!lF`pl{8f??Jm)C)z9Y zh73A_N~tazpwLfd&_|#@RF@y7&|5O-TbO0CL7}&2(0@l!t1C`d=yx;d+c1e$r>;`y z&obzVR4{$7LTl&ydf$pkx4QCqg$`%XFQcxitKL%Rq72$ZeO9;rMxiS+=pI<%s@r@faJK z(LC&}t7}&(#)C49N1>ZkcfL-c$7j%gVkPu`K%r-4(6!WduNM`1Nd~=A2fEL@3cWmo zZa~+l?)RfYugaib#E`4*-@FiaQn$Lc=*#FTS7aEULr<-)uT$uoGH70|uO84m{VsI; z>V2ju#(Of1pR#NNPg3ZO8MI0CATRxL*3ChfgQ^GLq!^#iFs{K1i|V0|D)iP2dNcdY ze)L8GZFgqS12HXB5C2G^cV*C*Gq?S%eT4hF3_1(lsqM5@3TCI6Pk(o^uT43&WuE3FF-3ktkqg<8G&Q zn@T?h{|q|qFkfa?wp?=0+GiW$L0)pt8pt#_PN2#C1?!HB2|fW$0+rOn7Vi#$8hU03 z(z`>TR$NyhLAJGvy!7r6=qyp*bk9z-0c(g-dm`doi%3ATX*EXe^(RmaudLe}&Oj9T z246z`+xK5jQE4m4E9>?HN+&zWE9>@y=Llz53+qgiLsn!?QP~#r2obXu5y{Nd4CQvC ziXxTU4NmNaa=WoFqsr~Z5sWIY8dCqttAEguc%%(T4K@z8nh|WT>oNg3t9L4A|$wjW#hZn*xmlovJ`tTw~*%+Z7 zh%82sBI%lO0d6~5wo{Ex`h`iNYukI2>fh+M6Y+>L&2M&xRJM6T9HfNS6SzjHs*i2CvqK*PV>qqtWoo zeb7sSo6vmWSEwp$=PY#d@K&maQ&2%(tq;G-)}c=ZgIDXr+jwCo+hPkx?VL8p0E+Q| zKu%l5rv>RmBd3}KIp?UHXt?4;Bd79mpyPC+kyCXKM8xStBc~m|>uCm^XymkCf_Stt zr=}yI7@cV3)OwO*l#$bg1a>uk49e-MXm*fJG;+GBju#I0!Zsj6v!Rb zU!ZW1E(LN&D=1169NH!ZKq~Bbc8M`ZP~OLQ#9pIl%A*T`*!Il=89}-bh`s(dfvn)i zNEO>L7rlgM=CZ8<;B9ds5FK+5;z7C)h`r~Fq6>l8`@Sf;5Qu%ial*!=3xU{&+-!`yT5h^_n!nbUYJ z5{*4o3Hfol5Qsf3(bG^Nv1j;!E>6olwu!DWFg-vLkurEAT8NpDB5<}E+*DOy6Ccu` zd^Gk1DV5tjjx9q2=PL|g_$#AQH4xePGqGQb_m zga%y(xcfbXXtwn@o&`Due1MQ6k1rS-j6RT)&0)p9DHQIIYJ+;cem=rSNgCJK=zG1U4+Rv%_}%*NpI;QVgx^40*0=rX`PmC-m|2Ds<5 zR9c9uZx5fnt5&RB2DsDap(H`N3~;BbNdm=TvKb1pf^-?+&U{LWYO8|JQnYZ8E(6>- z6oE-8hRe=w!yUp{AEe6wcizcD8W^O@0C)a*0*w#SWq`YYBIz=qgf0Wzg`9#smjNYo z8Q?Bb7;za;LYD#VV!%T3tX5$E^(_z_f23sK`~pi3z*5y>_G_^hje3i8r>eD?KVqf)%)AD^>I zAS=jg{_(kr2BqYhe|+I4CgU~#_#&mR7Ho@2F20xqj;#=zk{hvB*CL|j*T+x#0#KaS z{NpEg#e^T{HUIc|#Ht-u7V1y5i)i`b_%l_k&iz@7n_?^suldI}vj|!#zb)GF5`7eS z61>qIFVoe6sg+5gD|Dr?r4>Jo#0^&bMBX1Sr$#KJl=z~2h%wUjF<$eJU$zaBam_!* zYyR;o6*Rn@TH%_%YN`)aQ;iMsnt%Kg)r{kVyyhSOR8_>JvOlA@#q)IqPAfZ{MM&w) z9``iLc+EdvrE>)EGHDsF`N!Mp+>Y>?e;Kd&$J=}GM`jtX`NunX@W*BuuldJ2d+;Y_ z8L#=ryGw4oL|8V5+4b_^&&)Dj^N;uO;IGUw-pq;*)lZlFzcb5tdMQ3as*BhB%XmdS zK2m=amBDNNWxS*wALXS#!z$yKn)t!`m6Cp?mEcRj_#s~URaP0V`Nt2_xp%{@O{=UR z5AYFQerv4+uldKv>D(pontvIu`Nt=D>9<&Atf%;7{T|8xFIE}9ZpNp2@K&pgmzm?! zJ$Sp7;M>ahEd4ssXNQ&GC$jilos*-9YyM@t<{zJ@)Au9nSwU}R2@92Uyh2?OZ0z0ao<+sJ^70BVYFR}kdi|( ztyuAg0gu0W{~OhdzSjM&l{qSed; zqS^T^BthgOmT#p9t> z!F1yB&`Q06sPFNRCZlz36)@RWz*5+R z4@`Q4QQA;}XC+74P=V(p$0xv>RmmKc5t&sp3Dqb@WL7Ps80aX^zKDs7z^u-U+G2WT zmt93(nqJxEjB-+->6M*S5U$x^i#rc0kBDLXb`;aZ$O^qEDqt~>Tw(?Sl+3WV^=#a6KzTMU zqip)z#bBN5vwH61!i$;Mg^l|;{>R0}jf;&N7aKP&Hf~&O+_>1daj|jZV&lfe#*K@O z8y6clE;eplY}~lmxN)&@<6`5+#m0?`jT>*~J}$iOIOHCJjmwqLvvH{^D@ob7RIka# zRaNG>j|*?pID698%Sp>npsklvdos%FS~+6t#l_Z(i>((ITQ4rQUR-RwxY&AevGw9& z>&2V7kINBT&!nxFBeq^ZY`v)1dNJC1F|qXm&1}7#CR;D3g{_yPIMQhAMO)Z< z(T^0Z2)&TDUZAC|C+^~+M@~k1aTga|L3U;9MVoBBXfs5;Ru_jwD zc6wV(bTT1fcN1%2>&05wda*MVr?T~8XDLY8da)L^UhEtWKiYb^WTLGn^=zp5k+z-> z`?j73=XZ-W*?KXt^>S$I#gwg=yB2b}oe}notru&u^P=q z7n`Lxm8}=^Z9NA&-dMwTB1GAGu@<&otc9%?TR@Q+TQ4T3k(=9ku|+*0%Ceelz1U*G zG_&<$O9a!*){C{Y^*A>QB_OFaBh>W=eDr*+(SK& zzhdjThpQyMt>-q`dTt9_&&}9+0ngTRn`}LI1i#Yd(Cl%Qt(WWDdZINZBC++{CR@*) zt=1D|>$!6-la^Puo;z33d|S_Lvh`fwrJLA#ZpPNjWmAf+cMT%2^<1&_a%k(hCtrk0 z%Au|2DqBxha9UNO9c?{VY`q-XdhVtfXt^BPdTw)D&uwPwxn=qaQCQh}ZiTKi&e(eH zzuS85Me;r=UGLD=b1zFE7ub3ZZ9Vr&1+}#G+z(Y#DO=BNVe7e{s)kdxo||#$Cbpj2 z($;f#v-RAzI`@hhThDFp!Je(>cJg4))^j_1uxIPJO)lNU)^nR&x{0mlHo0^YThHCi z)^kTlb!BWlccgv|S}0@dxlJzJ#MX0nv-R9Vy!4)}=N_hW50kO=+}&(FcQ;$lo#dtW zY(00f&Ydw`x{0mlPW52V)^n$OuxIPJyV-i~ZnmD=%+|~GZ9VB~v=GY9rVM1 zXX~*S(bn@fowW4=V(ZDYAhw=#@PNe{OX_#i;w#tL7krCt7A?L%5MSCKt$Yc<)Du`^ z^aNK$W3`pKJP4?a!i?2+x&dcqk~9e`<$|6ZY5NlrRjr2!_&fsdKUT`IkZR`hA!wCy zDn!5^0cx#31>g4wl{}@X%RH38c*EbhVqq@2J7ZzKdXI&PZTKDw zGwpp%++$(Fp8Ky_n2$h49uHG0Q!}d!mR(XzP2Y5@g^716>^o&{CTMPs1*$^K%`zH` z=MfZpvz+$kCV(j#oE0=U(_(PSvGH~=P%ClgqXY9YR!^(?mIiD`rfGc-48^AqW+SJx z*rDwx`amQ}iybQ96o6Wr@4=T1qq42op@YfCy9w1iBOmw9$ZH1k(3aktF-gl%G=B6P ziImF_dN;N-NzGsV=;?jw^geG|>YJwb2@|JPy-%3lXGwh1tTfuvj<@+!WJa|_UjuBk zn}(+roQKDq2%))nct1sEv_Bbu_i@jWL$207{5BcpAy=#EvlxHL$(nU6C^?N5+&F-P zzvN^sWEAfTwIEYP0f>0-mz=CceEHz;B6Bj(if#wO{0<*TJOMOPh4~deAdLz`EzA=J zfh6k}Ux>o|LLNx*B?>+ThIa-4RW=F~4bxS8Kt4UfJ7Sow;sb3c9*zUUbQK?HtJ0O? z?UF3TZ`A1kABcQbtzrL4w_e!QyFt4KiNR`}=c$FvDzaB6xQ z?jyK|5F^?H^C2!gXm2pJHuJtrFIWl|Ip&NWa1+9T%l7nw|Kq)2swLDE))**NCw{{W;qKrUYd)LHePJlydA%Q(-qvZ`t^ z03x@cO0>v@tmVw$zYT={jf0=!|9$XBW$;I3@W=G0sF1pz<~P=MG&`D8b7k3??4y$9^u|o{-<_>|BI%3 z9gX7MCiL57FxvBdG@hF7)u|Xv_gql)3N9M+*#6SsY4Ulqzt$F?X$`IN{!D`(TcH{p zzrJa2D8SfX-qhe~u(!O1VtOZ;yyHvWnWYxDQLvOF%@|~gt1bQTFQBfcupb6^ZpfUp z5Ya5TTVmDRfOt0VmRPlnauv3%v&hT4C01ufgO)YmW&98EmqV?6C@C~tmiAi_)w1N5 zLoNCF)a+SUVlD5~jF!z`4z>EIWz@xCyz z3l>>Dk3a>6=oQu)EJ|=^Vhs`OYhbg69*HM@SQ3w!V9l9?NFf$|RIRnI{G_Y8#gJsm_plXo-;;a=)$MjS;07E!( z6p&`*?Ib!uq&1SnBF_TjMsCJ49x;JWM%v1=3osRtoe-6ZoCQoeaxvnyk)cS{Ir1kw zyF}&#(=~Dn;v2O{1DNoyH*k+>k(EF`u0@6ci49Lwe*tK{y{tQauUU=W7R-VUV~~~J zj)mlT8n+d}POR?=Y?$~%S9(n&Ah#k3LT3_of{-^GS?FU2p%3PN$LM(lVa5^YE3Q!P zuuDQXw9^X6cO*i#2}!c+J%o}PFx$DZ>lN@6fJHuQ;YeyCcpYapipN0Ni;=vf2l{}1 zloaL~Bq*6i#TE+uDB*{j;5?MO)hZ+``HVU)5vEB%7L~^wyAGj5uJ*1G!aX3A$kkp2 zKf~1Pn0hl)uaWO&{{WJI1uKzyEyA`;kp{6yUxBWQB%qT-WkVyt}kb@qRx4a-4nr;UUAtCz~!Pw!CedPl>vy6Mtzgq6`;6soBb_Q<7AW?)inKv0w}LU~jrG*OBm!p%siO7mBydx_M7FG0{zRKaabQ9(+Qo^SXQb=cz1!*xbATM;3%Ri0MC;hRdJezNEr zMALO`3*;Eu3lC)0ikZlpRzS4Su`60R_WP&pSu6NEBYW10pIs~HY1{h<&t7Ar*X)P> zcpbWyS}PJNd$Wz4HMyJMQRL^({nD~Lj+*wo% zBDW9v?fG<)@z&!&6pZw;b!FIpz`i{V54AK2$R8FclzCr#Hx)6(AnTznUEouSWfD_Z%*#dOJ_li9MqC?;lliFVS`cnVXv`3gB2jOR zN68Kh=I2PD$6b96D{UAEMeia(tO%QP(s)Q((WWy|!OI}Nj-VFJIX3`@B;{c5fWXB; z%_eeM=yW7elZb$qQ9@BY_=X_xC#hBW2R8!0L5PQeFb;vgr>%&iNPJm{Cxfs8VgC$q zEs38A@hK3VLztN%K0)HXZSW}iGYEf2pg$g0=HgA*o32H*8aDew2n;b;Y687}WMxBGwnQo~Q${U+}@t2+xn|EkYC8JSzN z<;8;9A!myxBAZ)&?D?<8GxQb&*@1c65O;W&D6n`Mq8R33{yJjdxLX9WzSWRz5QK*av)9a;@ezg^CYhwyi))ZlFpOKyYs zegrzAf;>M0jB>ILSaM!f`4NyPdqqHch3~Im5|b%^1spj{CN~_i6LUcc5qAK!Fcts%eFd2G72vGn zO~7c>d3kSWA@?YpSEwp$hxaI)tyIsyN8!Ax8pgXv;cUwVF=~gKyaa^XDh_q6C!FyT z;Jx`*UIM~RUIN1MZe6?tgq4>7xz-c*yaa@syaa@6J;~xFAl$-BK)9=-scSvq7T0>h z-G@kdqT(eW+(SX?T2HvAg4DI1aEog_;bzx*E=MutT2ENK1pNEW5l&IL-p!H!q?Z7b zUIKpR=16#VF9E;*%@OwO|8qA-I6{8z=7^&G^39RXNblVoA^UH*IU-&H)XkB2)6Eg_ z65!n&3AKhK-W-v61YQD|iFgU%BnB@5%!%iE{CVc*Z;pgGg@~5`l{DA8Ir1xB0)E@g zk!D^3`Xd|VC4f_A4nfRnKYerLDWUQC3pYoac?l4Syg8E7Bs=;`H%EAd0Bs5{0WEHh ze1{x4yUKlqI3Y8Ksm9Ek23HQ@C!Fb z)V@J^3HZHkj%`u~QTBTZfc*wvbQ2~cp$n7JD5sNLw*}oH8RUTrPPd4NI?;PKmxzHxw4*Rj~Xj z#L6t;iJt{PrFivAFXi2qKM<4`;Juk}6TtNIFbQ8m7>bn22Z5ab`6p;vWj*%DM}kmA zW%RyOMr%DD$Tkl!|7woUHjgpdPNMQNBQ?yb?KhB_4O26vzMT*kX$N)~3@q>+kXp?` z!+32+<2COt>JH;|1O6G>j7KxZYp7DaA*hA49}vn{{(|wkyLB134SATfbpB_!J@9=U z9ER5Sd>t@~#RMIXUBdHqAkmY7%@RX5U>y%y$oGD5JyR?12aIwlQr-^~L}T&<%A(`B z>U!P}qKNw551v5$r@bHi36u!;X!J%Dy#^8g-GH+`jV|wbKd3>J zHT>(|54sCySc~aQiJfC_*Isg zuS`tk;V&Dh{@sQ>8BB55u$O_FC*BY8#QQBJur ziKn~h%Gbcmu2~R`KGh!RT;=^hqRNKtL#*1jS|Ho8h|$ZY`g#QQo_IgVYvKKX2|e!z zPaqnwHse{SQ^3CvTzP!Y81H$yx!fFAF-8#VUx8G_HVs%NXaOsTXAyUgExaF;3#|%I zC3}Cw+{cj2Why0cH`(}5bL@N&#nWBvIMpGPr@JQa2M%o5H^?NW+-}|vNbo(~#a4VQ zkn(i*%ia%u5KiUkuF3mBgx(J*M4H4<^CMY(nB6fKI}8slfcJxr0E_AAE_N!Txyt(i zOQl8D;?d7%@2Zt3Pj|6t#|BXxdb<11dq1EEd|eHT4Xf;P--cZwB<1NYHvdwAl&8BU z?+2}TmZ63BgI4r(*TVZjD|(u0;r*Z$J>C73_k){}NygJ%Z0QCF&v?3vog}{v>wCKU zt=gvs7JE4S|2uBJ6(m`*2WmV8gxvP(0nagSjqp zUTSH>IJcr)o{h*wl?%@4^*~8OaIX&IM`@s@`^mJEFPj~Qs zz`Y{9AC%M69c)+ye`J=^(;d7YDEMQuoSyFB{XoH=nC0|z*UbAt`5b1~)6>~2aqPuRoz!A+=PdOs-V8T)27Y&kvM!TSM!VA)Ksgl9T< zx@+eBpq!rW;QfGm7}~Jq^mGUB2P(g{@I1FN@K7sO^ydRYF z9Dg(K2j%p1*UbAt89m*>`vHGF0I$%jGJ3j$_XAFj^mJEFPj~QsuukakbQfX2V(m*; zE7u}tAkN^y0gDU)i(RWwoHDSe{-*N+!~+%wjZDFh0#qH`w_)D}Cai4O73it#Ys!XI z+g(em&_Bbv>wPKpZM$CWU@BwQPN^@YGte0(0hN9b%Il>I0bT~MlG}Z~j8$1BhG;nl z*%ng77)=ta5@WQ2CE5i_YcXL{qzq~gtFFpCBxn&9^mZhvz6MZ}?Mj_tyUxKsL!19t#&%6&UgOtot-`UVA>4P)9@`bQvB#mp zf0xnv1E*7Z0N>-X4;8V;W#1l`eabz1bE9}%nkeUHn&|L0xyCH2lQ)VzBFzO8mIEWV>*&{Zs$24j;S%>E9H zxJXD6uUsUEgM-2j0OhV(`zn|>yu_E5V>fX~?>Y?{esZUVBt5&VG2=W&wpV9PU}1BU6sO6yZlW z2>;ph)c@0u`ugX4`HA$W&-d~qj-0bvfQTIC@xS5O>+feOb-wp0MEQzC{hAm*uG7F% zzb3|}<|iKYYhup{C(rjXjeowEq5>B4$St-1rGJe`p>lisu&G67kpD}`(mzYQ2xRXp zF{3P)I!mk|e*PT+ymyvZqW_7r#QZ$!oh4=zxo9E259OCkQ8sgy7!E467|s$;!n<5o zzDm0CRnqPKzu0>Z_^PU`ZTy^j&rQzFO>*15B)JJmAc=Gcy($PQMNz#{6vooTV%!pPpBU;IfXeBeEmCT4%G9y~ajA$h@qLs{uRx%@6$&6?vGoqEu zh*mNqTFH!|l}xO77gA(lOME$`@N9`GDr-mE5>q^1EBO;!V!Ch7!j||M{8bzSHnb&X z1P_coC3#Miej4*_i8c1`Y>6qZXG`3&9`*(Zo`xRw3ka1FJ#0qwuo=!4-VP2?t%ohayAg9zc$V6HPs+%>j1Yo5;E%6|oetR3!(K17 z;_G356wKGdULu&Uht*i1hc#`9?#BXF2tz8>~z!KjCwN735j zV7VqaF^5o359_nidRU*8*2D4*VPk49^tWqPo*q`m(U$l@FpfFx5L-b#Ec5a7uxA4G zY>7$k+Y(bt>gi$o3Qy=Cp@%&Ia2u_M6;SJ8&ta(6!(Ii@Dme+97$~nTY>Al(V+4mS zF>|7*g8Mg)r5<8MczRgoFC)MV@LTVb7Ne`AN75`eBYN13=wUOWhs}r{HdCO7WkOF6 z%gcFT8-Zt)O$OWHS0;~L35hK+KfWz%LWaIA@dO0q*`_gP4}dXe9|o+JZp5c&OMJM* z9fPOleJ!A}YUEwURGQ-kytB~5{uz;;9#(eA!-d2sThy5G0Je#10eM`h@*_N0rFeoX}!xq{Szb;X}9`D zf1-zN`x8BE+t&23(Gs%tZX8P=ok8ghJ?soYy&K2=ogUV=C03$`Wo7Fd$N09gWPVf7 zmY8J|+_NR77=pu=nB6by<8dnsJ?sFWo*vd)KWw0f%|Z`*5Q#XkXC|Btkb{@j!|F9k zYkFAHdV1KqykuGrd%j@Q!;*6)^stPV9+Mf%B}f~shox{<2_=3EKPd$UBF~oC!m8HO z!|G*}?}dIV=_0M!5_e*pN&rK2A9R?yUYdRRSS!UzTSm+(UGEefp~Ul02r zR7ve95i4HnVdsMl^sq|nVYT(}D5dqV8r!ZNr3&@1x~Y6UtZv2)^svc7J#5m`!!mp5 zVUwO7_8Fkm!zMjFESDqH!zMjFtj0f#COti@#y^TCJw2?(KaM6h(8DG-(8DG-(8DG@ zJuLNwQTPZCbSIo*tH~HtJ!M zo*q``ccoMB>0!A_pdL2q>0x#Hr=8>mdf4O!df4O!df0kT4@=t<>S60WJuC-D>S2?f z9=1f{dE*%S6>DF*8f=OG0hm7zk2xfWIqX_h(u-JBf8+2G;F!agMr?_zz*Tqfn8QVW zdwWzHzeG)XJHGw3Pp^zZDy|+fyXfX96n+wK5m?j9WY~# zRlERdc!aqX$j7N8$Tdau_W<~l1a+8?#4Au_1e)BbAA^XJH5fuKj5Xd3SUx+CiT`{g zcDaa*b!L{>b-7(p$XJ)d1gp_ETNgdQ8Yp-U$Df2l%DBECEv{V^#r21?aqW^wF6S<; z`-Wu3<=n;f>k%Tiau>HFL%EK-xIM*2%JKZ8@8OPXUq^D~cJb-VuGC35Z!-zMm~|UI zBFHah-9`)I%Ei-eQ-UDBm~}U6Ly&%u+^PKt^8PgU@%2o`FJ|2*n16|QM~e5j1r#p5 zBgLBuvOW{exrF$|Y`iDI67hIgGU64|@-x|zttc01OXTM5#GUQY8C~v`6Dzv|WX)=O z*DZyq<8rT@xLYT4U47eEAE7M8N7YPIPEuq}RtblBC2JC&*?R*`aj%^C+}j*mDK=W- z3tMxmq^ZLv_9+3~mjXkC6!*%Bf7<6GihJegAOJ+9qoCt3NA4U2kK*ne(tjmcmdJOv zrM0gj+NG&U?hGboOefe`Mes0WSsH~|BS!?1NWE79o^+C zCLs6XRQdA>l-lJT-Q_P(RMrmn%H?Y*9`?#E@8~XnQFj9Gj_&f8)-tu5>@XOqWv`s< zs3|O$*XboYF@lqNTz|E%_sYq}eGx2sUz zIoa%Smc4Sa7bC#gavmw{s`^j3A$eQkS=LC;O(Q1Syxdb0_<0Ou0A1$|u=h zW0fv%=S~jL>1tfw&Yc{jv3m3iiYvEsCx^@;$Q#>I4blS+CfM8q-7n*$`tE`5{0nbv zliRsdLu{IY8C--tf2tEUUN>-t?^{G+M0d{HUmD(W-kZnhs z<MW0%)%xdTAfz>5dpSb+MRB@9>FEtn5Hrl zhoA?z+(Ktx{y{BNrnBjtIqF)rl)fL{nyU(gF#_T!S+fwTKbyQM|NUoxDac*X5<%>J&|>TwdC( z7Hh1H%S*e}lC?rv>GINUbsFDFZlR+jA`@wnh+dbF)W_K!-wE-mK5Ahxq^jW-TAe^p zw$SPYbX**)NaJigR2e6{~9`e#|b)d!^mzQ>{gJ>(qw^9l| zUB{KWCtx5^Gswc*LaSLj3E?o8mv*Z|#LIERRxU5?Ra4b?S_RS&;=|=6qk0p15iooSdBg$b$MyGI*tah{2Z5CXmvI#Tei?q zzO5{o-xMQ2$Fd1tr0beu2>zoL?TD0T`FPwauE}k^5~#~dyK~z#dDTu+=G;hKwUt(J zX>Q#6B;tIZo1j3-w&4~!x2s;dI4&>k&h4&~V68tEQg_XbAg#+wyK|!kddawj&P~n> zR)cqioU2l~Z5b~;CO4KV6WK!NCQ&#mN{L4!UP^(1NVd?q=?f6#azmLr*q=5Rp;B`* zo{@4mE8Y<>cmG$7I|>=ML5K;uc#Ba=Ceo;JX!NQ?3M3Hw=JPH7s|` z3&3OxojdLa2Ozi5xicB67f){k66umwRcY?gBGi;@p>u2QM2pB4I`F&%FD9Q zNpTCE8}FrG=n4kEyXQ#ZhsG7>!i4a&K=<4>zsDnLg%L2 z3q_vwPCIU)b2DuYj@&}0xP{IgVxJ=M*g{9yuUPxi)!;Op>RJ9gJmHWa;jnAvMJyK8 z-%rqJH{tN5ksKHsA3ktG-6-I?4!4zSjkOZzNx<%R?Ai>}mFTkpGC^y@;pYsOt`7wLcep@ITd! z&1UbwXx9z|NwGK6o{Fyd$~ypaR?OW;2O}tvI*i-yx>!L%{7$@;)rJn(3mz z?!*OShwg}MPqecv8kf3VU!yQxbT+BxcZqdf57NOPZGJ{jzSy&YHc4G|4=bk!E2r~b z7`^OfzNa^UsB?_$dou4Yf%e>M>VcLm3-D|Yc#(#?RjTHjwmLfuK%)Sl@eq9ZyoL(0{UYc;YanHO+E7P z&NApC-Fbd8L@U-O5w61u!qw`x@{c}=DAp$t#l}fQtnLiP8z&L5`gsVElZaS5GL(~u zSo<+TCnpib`Xr**IEjeKNkrUnouiqAClN&rClKUGL{Z~1g7n>0)O0yPoebtFw%hO$`LPKJc%goNl>3exFbYc z&yxsuD^>$(^+`lrwDt*}M8sEmTKfb~BI0+g6+$P$lZd!~5|Q9ZMEo9o%o=FzNs7$x zLXNJdwT~NG`*?5?AzJ%*coI?GHEw9_dA4=*7qMQk?MoQ{6=0H5AitzNIq@92~eMt0VtIO#_qL)-RPahI}q`7(ekT_Oq z-n%{hLFU5Khtfj{vNoej0X&1B2;`kUl+L>bAt`)6JTVF_uW0JiPsWf{S~T@((bT6! zQ=b-1eOfg2Y0=cDMN^;VnCqrRQ=b-1eOfg2Y0=cDMN^*^O?_H4^=Z-6r?sYDP9I8F zyaE;(d_R0Hq)71eq4Wic%G%-SL+M(IhqZEorw^qs>W24DA4*@^2ay@KtivPto290{ ztfQuYKQRQAbz+36vL45w zHL}#ymo)4rw?U)FO>465!&f5;ORqI ze~ncpc=}N0pFSjb`cO7#1f^-HN57!Ba{5p<tecypl zY0=cDMN^+1Px7>A>eHgBPm88LEt>kYXzJ5iQ!l3vi_$%Ex^!n493~L;3i#1S?JO^r3u$#&G)3 z0o9Xi%bu-|8B!BhkROj3(l3)W`SF+`y{;C00Gq-Dj~UXh&?6RGfX58!^$!b%yN;cM zkVYRfq$bi+ae~JT>34lrJZ4D0=d02{#|+GbF@ocmfjLoB!Tn=~^h2zO1dkcgk1>DLo)zT~ z@~lrJdTy=nmMs6I&^}&?aWCPdOk| z5$sVsX2_g8L@+nOV}{Hrno=cr%#c~Eu{H@FGh~)*CzO>59y4T4dxWKEz%c`f$ix}O z5Pi%*QXh|_IFm!XqEBYwkwEi2X2_gCFh@;&<}8-VigJGDC@9H$Th;oQAv5h!lqA7p zhKzsAkl-;x#y@6A@R%WUkS#@Zb;12(h6IlpGBd~m#|(6{pPBVOrNxcfJZ8uo@`6Nd zmEbW$X7<~HO-b;WAv1?8qc~=$;W0yIE{7oRn4yNp44Ff9h#WK2@R%VpPeSxDLk*7^ zGKWcsK4wVpm?1O&D`diBh6IlpGDjDo^gL!r@R%WU%-(|D8%^+-Arl-kBzVk_IhI{5 z+VF5R!DEKZasL!_O*D&RhRoTlY<O*s~KB0p#GtV}|UmdR^iqc+8O9ol^5u zR39^BN02tbV}|Ugo4jN^X2?!HO|TlgHsoB9%5KYe=`mT+)aSV4&Q79mR+JLoho4A| zfk=)SveUmnP=cH8?7?d#W8{VMWoH~9n3Lc!Lw2T)gHUqJke%BWWlivyA?qJABzVk_ zoyQ1Ht5G&3zdda`41iTJEPKqhz;e{oXOCNi0YArMhU}RP)hnY(fJC~aRZ*IK^azq~ z&stowJ^EITn)>WxEP_=l#|+uLeKlz6a$~|x&lpocAOZj@{4KF)MvwE2GP`KceX#1 z^h=a&x){I0|o%-FAH_q4f62sHKCsa|?dQ=i>e93=CY zK{WN*{XKlGBbxf`0Uo~2spBz2cDntw$g|$5<1s^arp>`I(9~xSv9)CZj~UpnSo_k| zaLn*LVE#PZbx7bk>{^u~7K>WO?u1aP^j(K9jSLHA7-@9}Z+CAK+Bag`(NPF%&$VA9 zDy421$N-)QcmYBDdr)jQ*V$A!mm3`{&IE{7s; zK7P%EfZcky@gN<@$3&3O) z-Isv}kSuuw-uScKZZBevNpS%ZOGz;!uvmB!^F=HtN2Qo6Q_Y}^wee6ll|t>sDm=6_ zmB&IdR_URs)Ves(Di2ku2QZVy@*Y~5x*WTNSha`Nq`rl8u^JDpPtC^w607yl#?-wO zqs~J+rh1`WWAz@|HFXU+x3_y>H4tfNPW5NnMq4Xd`=p}eyqQ;`0jWQtH^w@9=#bQb zM7!FTqaHB7ree&f+1^jktx{EJn^;eKjG)`3(x{>+}VO3fgv zq4rHeyj`jr)=078b_^Xj(y&wNRJ3huggsn{C#Di4-pUhla%y!Y(5-E@Vx(b8st$cM zwvAl66KR-=tq#!bJ(;JaJ^@v1oO}g^c^V>M)f(By?vLQKQ#8RrPMJ)~25SFL5vN8T-QrRo8sD4wselxnI0c61+5;5Jc3>57kuqDf#lrFceOynr_y z!O%wilRS?dBUrr}3`vSl&^a`!-e}X}6E)URbs^7_G}cv>pc#r6X{=fC+nnOX8tbEY zKU(pry1@pZko%xu$v4q`8jH7Ng{aq1#l>f90}tqr@je%y@d4xN5fqa65WqNZ&w~;u);HE^QC7s>EAhj8WjN*eRCOdo?UdrO>l!;yL0@mum+Ezi4f&8$}N zWnos*Yi=Q#Y@FC>E(cO^B&e-y*Le3w$>AQn5%C_Ah02mN@n(`TO}cBm%Ug)a2vJuO zWq8mR?@2~h^gc9kycgM2(w%DTw&X%cTN=BY!=swQk@FrsQd+8%*u8q7bd-fM#8x$l z+%5`6FLA|A6?%QuV;Dl5*k5R@k$)JqYUR&BFSYacVp$c*x5W}B3U{lBI4t%OO)b=9 zj+8GaWbA`d9t5#I+%1F?sfry^6g#+K%;U#$NnV=YPZ;bKP~Kli$=+Kg z59#L;E02dkhb(la3@LWFXYk$$p9w;r4nkQ;h7ciZ_DWE`1kmOl6n3s zGH0KaY5r@CIZ9^vZ#3pAndHCKSgDdZ{yUAOluYs8YfLGb;eXIrrIHE$UmB~?^Sfnh zv|i8ewud(A`912P9a9&vQ^agN>~&4S{i+o!^3Xndo-MZ7u91czdXA3UELF7OHaoQ! zUhY`JZY%go+bUr_RsfUL5nkp}bWXg?4G5|x%s5#>abEX`@ZQVIkV4iq_PEWEqE==? zf9?2GPs^fhecPpsYs(7%7C~*#6_oE(uUu4AvZK5tS-b~BcWB_5o_CS_@yCV zBR9czLpfe*t6>z#b@J~0iBAiX3trNj$*m@?qD#D0bkh{P_wG^-8Mu9EK4RQ6HDYaz zS3Y7r{$#Mez7S>S`g#@ep427besf;9b@|Eq`e(1He{z+&w|brik&B$@bI3e;8>=hY z0sY*WxPagb2z6$h3efxPvG@TtP;dJR1i|eXio?B2FQ#)vIoxY8!1(8=XuB6*p1AC0 zdMyW7BF)u@NfRYf>jPMgCJeOHUc)TLNEUuoY=NpBjQT2LZgLQJAVSI{$C1qOa-ijs z>nP^>5>d%{G;_}M!Rsr1XM0Mz6HyUn9EF(!H1!NBeJy_1qfANZJKK`ajLai=WPOqVP(L7e1z6-3p{ulsvlroC1^Hcy5PMupd~z!h zm3tZwN&h0#zhkDiD%r(i{zh$_bfmBT9CV~_P=V}7Qy^|-S6uf7%cNGnG5-}hlHQSR zheCPVumu1M`_y_Y=bSy+QeK~8v-o}LBQ|)m{Raf$iwLhz^$7b^k8=^B`&5sxPxWBi z=|0tyNxgm~S0kA)qDt*onZ-!S!mpLGzPRKvZrV9+LiKrk`e}-=I&8kv`S< zm!MD8cF=ta=dA8M_&t2V|G#}oZ|ylaZFFd2k1BF*#k1J!P3|~IiV^BEgkkPM#|cKL zxE`TyL_|qALY3$d>Rf~-^a#bIrTS1sMko_TRGB@TS&We^{Q9^KH98EHRvwH{&mp8- zk5J693}am~9HF)*sz)g1d=$`BI6^%@RF6;;=2f8SUa0i}_}z>$rNR;F2gF$!E}MoR z@*w=|?S2GF_I(6p*YoilA5Y++e3AgjML=3T03C@ZmK8G3fv}SNE=7nvt|dNgRdiJAQ;zMVW63b3J64Z75urPl3{$#e^?R}|3r|{E1n0ce3Agjm4VxOuxR5Z(6P8H z;=fArt4D}Ewk1AoxF&2f4i8EH1=CM6({IqRScZtTv_$|e!?S9Al z<;TA<=U`-1bO;`WH`jZoyT$g*K`2s zI_Ds2L`3?$a6?k%3$fpB>EP`az~RnP8Hm-$krXhTzNu( zBs;7L_>L>!JKp1~lS~MbD0kNi)V&sEVnLGK{3J2vvb)aHb>Aa4=`xX^)SXG`CTonx zB<^1Pgw9QpXm9D&sAv>;{~a0pID@CLQCOC}nDzj#ELLicJNP;fCHHMa@DKsNU};Be zjxr^WVA5?_ZRtG^nPa&-vT~A-lf@n^bnx-1AG>^ zeg1_Y_eJvTs|5hSRQ)`0+?yCji%M3l`#G_LSO#7I;mjgBooulwt?d{^o}CdCum246 z$wwh|y!}=PMJL$;fApcKK++cy4zo`1n%%5$$yrNTUslY%2?^X|iw@R-vr*J0OwM0c+Kg#=QtGF9+Bx;QUH}eFzr! zDcSl=oG!Up@G9AcAhTTw@k>UYCqks$XNir{SjN2_!j_D_QsR{R0OQ8oELf#Go?N!Q zTQGctMr=Ec)w?{=D;cZPHM;wg%l4XQNB8gKvV+DtyO%NDIE{66w;QhDGj(*hG@e#UitA z6RCxQIa0NWG^>_P&sIoe)=ONerR)l%v8{05;i!*lDIC zD7V)>bAU4D4?x@e9h~ezHv)YTXobvPLrI(-j0t5CriZEz+JI!#ZICd!bp6p)uP}v& zK6_Nn*zg~|r9vLn>{w$^h=jwZviky$G>PCVAT&qmu}JX) zXhrZyd&+V+f<*900|mbVs0bcuq~LEdiyE$pO1)iM+g-u7Y)+&SGlGpyNZYhpwuALK zsBpp3--0=~ozhtt2fgc*2%=|u*C}a?{y#eD--NzSiOWQ$qW!7ci4hoi z{Ozs23dwE!9KmI@KXsef3(IJK>UO>op_X@@60Z*{!F5U}aFo;6DS4a|;%%xIBf#0a zPD#hh9E$6C zrlyl>|2m~xAVSO6Dcy^ha!P>{Eh{+zfbWVeaVOPF-gQcC0kW?2=jFN#+7(;kZe0fL ziY;+ZgHV=QDVu51B!ygL6?2$JIYR~lmCT~vCCH_7cS4YNof1K0W|i}!x~V>CaGeqp zXJ8Kf9{&Che2guZAeXL~iQG$I4&4#m%ezjAqOy_}yBIOnQalW)acvH*t1P%q=}ScZ z^g5**P&FC2@uE4_FZ?vwyApUbICyTnXy_YruEaBC)4Nxi+|z^*d=LKkZoJU)z8kMC z5X_S3>y)$su%^ci#Re^t*cH<==je}E60!3EbT z<$vPFD^KI#mabD;hD;1MURQ&;;l?Y1%HTK1aT*72svEC_xbb3Ti*ax{-&U5)Z;A&{ z5|&NyB3;)ML+~H1@*zlhjgQBz61eet5~%0Ki}NDKr3P>fuLLfE8?PTpq}_OR#2Fch zXdIl`wLymU*4%iJ)^p=E)=Ng?;LPOig3*l^Ip^TUi}BK9GGnRpD-(}alPH{3PKozG zyp#e1Q3q^eN;A{x+UFOz@uH1xi*CFa!8K1g*HupfspbN};+4SsQo2mL@mh=ml+idi zb0$Oe4E`M;kxpL;%ulS#wr4HMmB3}%jTehx)%b3_wgF9B&yAN}&9r_c@Gelf*HI!? zJdJ}h=bndg6UIx40ykcX0ykcDlqz)NrJKrkJlRJvUy=9!5vCtI!U( zPH8`&G!Cx42K?cfnrlTG2iJOTyfhwO39Rw(N??uu@+*PoOa9+SYq^WUbxK@J&^Wl( zbK`X`T8PHMwHvtcs^vGxxK8OzNx#HtyMY_8TF;Fa*Dy2=uJzn_>HMyA+InuhxJsaL zaP0$&l|SmNJst#bA&*1mML zIymY9%%6wH91_GFcC9v2Ei9_P=sXT^%;8HTL-0*NbqBAvr+3B%Zn52jisT0EA3YLo zatJ*CU>V*{%zBrw4)nFYOGz~tu?=5?^hf+`km+lEg={9`tcG&%Xuz)M6nD!r&a4V+!i0B7IwTU@WJ?1KpK59v1D=t*9{GQdt&2_-v~xZ ztxO@)yO@X6il9%Dw$oa);_jg9j1R!=!`Z1LOQ%_#EX+u=nOrJsA(JPDlD-lVixAOn zU)FYS?$4}F%?P{%fgKL8?43zlOWH0sA!rqTb}Tx68SGf3M=(HoQd_Hnb=j4B{j9gw z@79wQ+m&-yx0uu8YQV)b=yI9~VgQAO{9@Abi(aQE!MNiLe;$8J4#z^(89|;U+hLS-wz?6Z zRg}O0SLqDwi9f~DV+bEa60jtUKQm7vZ8 z28>p`(&;}5Y)fb(=4>NEh)ro%cYw@&_a}aAMKSXRKc^6`>WDGDcZQYIU4~19J(BbH6 z$=@L^ntZDsEBEAPNSRJPj*v|9Iy|$+DNd?N7t8BF~cQ(tPce=R{E|F!u7sZ0C9Qv_tv1=*SfS%r9A5JCS2R2M{0 zdl#!sPb3eow}g*CM;!Fay@?gICj@!U%pbkr`1B3HBm79%$tn zkYO$5rJu?0BM@#?zcnD?mJEb4PO5f)Ml5G~saiqr0IDSt)ZP{B)`Q(iVAuB5dStVZ zsj8RuPq@qQ%SZ#B&)54|W?{8S_rpgM_&tae898fR%@l7lAIVnG&9?Hh6?Au?R;7yx zfp)AJX~cgp+1;cYjM2h=o#^1LF^Y;9F=>>_VMvlhk}5fl9W9OUD2S}eiHI49n7V!O zovIM$7a>R!riJh&5?XCKqa4ln?MgmUo*iu#XwWuzR6mINT7#dC=_N5^8Dq8C2Z;{A z?{p;874aO?O<`=CJyF*O;J2EQGG9E&5*&@lYCld_yo4_mmX()6#J@9zRKZP5aWiA; zIcxlg2n_c-F2}4PV-f>oOscZl@g;5FwmpW-OPC5DU0#Jh5o^*5!Hn=SUT@9_voISR zi{IW?h6lkvSGnmpO<>=eaxnO6*u-_&A{0^np;&F14Ok z6GGmz1st3hf-Z>GvZFcl0UE6%$ay8U3xFN*E8?RL8nI$mPit{%7o+uE5gh*t6H8Iu zY=Eww2;(1Ny;oF!0z*7Eo~7uwMeUX`MAu1tc@!b-nSraPNLNphuAUoRJvYYlH6R;! zKgi-QVZtdoaWz3|NsCS*yZDXF{S=0}dLE5aZ(1aJ(>V2}MN2;=U2QYKGnrorJb$*c zC0|alaZa(tTYODWt3`RDlW?}ev(z4kXIT^C@DV*K6l&4g2>Gd6R8;A4trlgPDAb}? z;IH!xQn_1_J8IO?YEjOD+?Pe67JZ&X1!_^JKrQNMwJ3Atxfzn|5RdqL#})7$@A1`1 zCIm^K7M&O*nOKlyH$O>%TGV-uLQjfHo~4dfi)suffl!OiBs;AZWx?53P~iQ~X7J-o zJB@YD0{>Jk`W}cpwWxqvEqXNAcxq8ro2M3K<#=jQ7TQybvM`=nl!90>w$HbKq??9n zQGW2@6sSd=0=1}9pcZwsT9jp=S~RZJqGX$O+~ZCGFO}^MOKWw*K#crqdQZzbQoV*Z zV7?mL54J+;G{hdQXm5Iq+HU|vQpa?`ly8e#^*W?ac1G32>wB|MTCGZj9y-|r_#>UH zOd#n?35Vh*947SDsu{dRj#jHu9@ei`t8yejhjI$ls*YBxDx?y%Y7QDLvWTzU3~#~n ze0?&qs7&-2M$TMRCYlMdK@(0BX}PFO^duPLOS2aMsphEFhSeUQi1?D_1d%|VM}ee* zv~fDLDQ%cWGJXM9+IR#(IR`Z8HK;!drrtr*#MG(XAiKH) zO;)Um@O0IuJ-|&3M{J4O291?aUjZ&v!}_2>)c0t_aJ5+OFzzaPFoqL`Zkl7o2;j^vEdKQ#_u~Z{!;b}`1A?~l1x)7AlSZaS%;@^-1;-0nCD7=r) z;Z;OQp10Jlz+SM_?jTufscFdlMN6Fl>?P=wk>AUfT8cmGEOh~dc*Rnu;?LhLwHyAt z3Ky41u-;OGQKHu%HPZdVQh&pr*DduA{CNW|Dk0#Tmf8jN@s_1NK(=pN>Ra%9$5Lk^ z?p;gOp0lqFl1ASd)ZvrKMg%@_$;Y1cm;}QqLpZ*Or=s1m9Td5!B1KAVJ)Bmbx8f_})_2 zg69ty((vbBmU;n!Kf($X%of<{8;EqQt=>lR<81XjNRGGFGbr>zTMYxr3ASp398R>= zEs*6TTSZZ@MYigSz>{s&fSNePR&SsR79#<$CAOLbAx^bbContBR-Yij>9(2;>LN&ej;+o^6Q66Vz3^w5tscXl<+e(I^?A06K=|`* zl^twZ7uaetl3!@6@sR8yTWt@Li*5BjNG`Ee8h#0dt8Mi!kX(a5NO!HRx*+a4TlE0X>uvQgNN%vzbI9mMTP=g|H`(eQ zF#Ch8u7~h9+v-acdWEgtK^bmA6(H_bP@-P`XsbgJc$=**2AA8B4uN;rYBMCb(^f^m zR-z_QOLy7oGcdc`R)-+>du+7=t#Yre9>t&gY}EwG?zh#Ez#gzwF~nVEs}!(5+3G|v zd(c)xkkLc7>W+GO*j7EkbG5A=0MAEkbpet;YO4}d-TSthgKGW2wkq#M3a7mNA33o8 z0l8YL8w3Jhu!yKPku<6*Nu%yShB4(Lq*(1J&s~srTs?!Vi&O{jb5#n(E>ZJQX$ds| zA*Jejq%Bjm$h2JDiF!+_H&Ka6%#DaHKZf?MnI942mM?l6GB~$_L-{Ebhf`h&Qj{;z zm}6zcje2rKBmqJ?FH3I4>4Gy@oF*lywq4E(s%C7RP<|>UO59G z*;56czDqA_9EX0*(!L7ZpQb^st`(+@@?` zou`NOba)$CRoC<<_TvHFmjaV+DwF-weo2x+r*H%SA|gBr!yMo9@u-y%zh;rzETnVj z*DO*;kcFX!BT}z1dR1qt_$W-kk#+*ouUV$&Y*bjBR*RWlGQZMXG1F%mL+RHnb1cD( z_%+MUJ&3t{k6f~c5=1UmY!HAW@e=`UD?T4^cHTHXo$Q4+>RO3kGxa2Dz)}Mtzpcct znfhZ9dz1JzQ{vZ5iC;4%e$CYN5Xx2J*G!3DGbMh_l=wAM;@3=xUo$0s&6M~xQ`)at z{5cdhyW&Jh0q>sA4}}yC{hDQ8ps1{!#aL2g*HSzztsN@zvoGp~$NKN8Hb7r0MP$@f z9cJQhHSJ1NM@?Zlv@21a7{Rr?s}G%O#3n>Fo`>Kh?MhTr9@U+sU5V;E2BFZpBS3ZG zF?Y04_2^O#&a^90%^v4!@=(1P!9|?~K~!%Y=Q{LjrhK~+hjt~Z@77YDltaH}s-MP` zL%(LKzs4#Z`ZZIY31E%0KMr(MU{{iGC~llLo~t2O66}Mj%QZ+3pkK3GGk0KFC)al= zGkgOj$Apf)gK-vcM2TNBC4SA6_%&1F*G!3DGo}5S#XqSAr=fH?8s8Q*pBr-xz=U%X zo~8Evc$SfS86gBej6WIis-7DaN9{TEYnI!ANBC?znl9wVT_~9A(63o;{1CxP9r`uP zP0(1%ig!RKYSWfIJ41tjRK>*I$d9HAl`oSu`O$Qta^0hXMI4$gRKD_xV2(q-W|iv? zPLY!C(-p!q;y%4%;;n!k`ZcS3*Jnl3h06DQRy19xe4lR!8IfIJ53iVmplWIFJmfIxw<|0 zCuzD+`G|ltU8sDt7ei^fP`PF}K)4qGCkD!Eo3vuggfW5_>(`p13XX9`OcyF2VnsN+ zqd!$X#{8LSY&Q5E<&zept5l7=5~vctW@?dW>rV%4q-X;YgTpSOJL1cKiakG z#OFvvzh+e@{Y8Q?k)XR*En);r7aW={RGs{$V6O8TYP#waO{pCEHLF^zu{I9?aV4ow%T=8$C+rVI5nU8tJNA;|M< zR!`G~szY^%_%*Ai=|a^!3DJJd>S?-Ab(n-`zh(~onpMre6q(R;!J%KXs-tg4&NN+c z{?49pOahfb(**~M5UXkd3qtql4*i-{9jnoYqYmAQR2{cmBwQ1%hUr4p*{p0aU5N2* zWy$=esKzYEvI$zZN+{v#Y^Ak!5-9=D=3`K_M=>O6=dH&`b2{DhtWIe5`@A-}6$mpBgnn&o%bNnGfYA$8aM2+}(AYnC6ii04i@5y3{wz!HX!#kWCmVW4%g^-Y zLiqbb(VYC;QjCiZ^_}@cz04hYN6XJ+1mDmYJ47{*b~^&F;QRZSLBNtUfXE-$6a73% z1Bm>Y4AtwaF@U6uNh?*FfAj#7(*PpBW*ZbDNdt)dV=RKzUJM}edHWpDG|&JdUu)}W z7b4)T$+xq$#Ew;`y`$xix(bpvQX)1V4IuL8R-t=G8irNV03v^WN7O5vuvgOnB7c#_ zwriwRFo4hv{()}r$qv1vPh&&A-@*Qn1YG?qFrvXI1i-&(0&C>~czPpEi6wT8Kd%mZKe;m!z346Y; z=-ugrJwJol4e;*fX#kO*~&(*Pnr)l2`hli!Q{_qDl%qj$7C4IuLSd-z%>&-XijfQPSh8mNQM zPq*I|dDc4(G=Rv@v^m7m03yFHBJzjWA4)t7AY$xStbOTfbyjROVE#Nj;gBHVuxr(d zSS+f)<)8x=+!cZ{$=TfZKy?RC$O0zL&nK$uW$D1rC#oB{bclCjXw$R5wc~ zzoe+{Bj9voRy{zHeFc`)Ln0jdQ`Lvre`If-fc&Ztx61&d^X6@g5Ye$uWl3B zl3jTvB(1K9`1x_cQe7G0o`?B;ObM$vHUf3?W6?pX^B!87cbP%8mo}AOh?lCm#zR&9 zbk;;$53S7O%YLi6)VqOPLEd35SxgtA4u50%gC#So%B`Lj zSw?x+g1-8INTo<*xyMHGjkrZDd#8@sct_Vr^I}x?tm*KU8U0<1*kjdy?Sz~ajwS5UU%dtg4H|Y z$>pd=KpAa#I^xhgv+igLgZD1tJcB-0cMSVsv|(+;nS*{(w?LyWMV#9y-HEK1Xv4aQ zvj$aJcZx>eh&Z>Tfu2f#XDLHg=#UBtp}(HGTXjeq3Ar5or0zByl9P~Oxi7z9#BSXU|!Gn8ZFAb@n6r#?gX49d+(NyVt#Qm*l%P>Z~NIcmE*h`lv&7eccDT z2=7Flr7ZQwe04b0IqfLbXDl*0Qq1>iRNP4!P=2@8=OtLHX;?WN+b6RgPw(wI|3b9vH0vH^cV;C#&$e5mhf~Kn(gyYz`xu8|YDeoH=ahk|)!{;~PLyI? zVQ02Sqd0Y6bg0Kh5Z)j9TjpbfJRKiH~^3Cw98 z|E;taFfq>k*ftR*nOU3N9DgUxC(l>pIzgL`eP(cD>HQ>i7rt ztS+{e3~f9SEmB(7`#q34-=V$huhA{%wfMD+U>l!|x2aytD)oU3dB-?AS!hgII&BNr zVn9=MeK^uCP0e%8b>$0$NM=Oi2kNgUsPiL(*P#*Li>L9alluI$Py@!mW2r?3mEr)MHaGdQt#CjQ` z(T8m3`3^vbYIGr{$3Z~1(&%brO3m#^Bo)DjLCJ_77-_bn2O+G}?;}8Z2-us|Cm;&P zy-R2NV-zPkPp{5bkbDU`VRW8=7P>)n9&5SF9jM~yyj=*skAi9tO!h!X*J%*Psna}E z1Js!C6wvN%FiX#!GaE*NtdBGucsLD=wz|)?oW@5H-+iB1mea%qOONhw_u+J7UOl?d zgvsg69)^EXxF#fP-VxZ3w$<}qP{rs*cnU&$@u)QxmF+?A@eH6TtQTPQ=tVQ8Sls4D z%d+~|^F+ZHB$x&F8H?yKKyTyoRjejI!ss`+kg2k)@Ld+}9iE{xdd?!4tK^ETN3xa$`OUji@ zIpp_{q$>?ZUy^UQY%Cj{@_B_&p138!?;{>I*5(z?%`V8oy5&DGj@J8NzRt$aRQ# z9lvsjw2kx$Vg8^*GU8qQx-e4MN_NjNa?ly5hUtuWh1K;Y<#-1XBlnzfh=&%9M*Y|* zvx}cjFJz4fM@(CUvPLw6b!0FcF`9v(Q^=qTNO}bfB>ZS$V2wDVCvskB4?`@C(=J5t z6CM1jJ)R8LAV{kAcvkH@z;x9fUr@D+!m2%=RlAMY)Luvi?ikeI2rwUmUvDti<&YGc zA+d!n~avUK0T0s{f`YimGk?|ct_^u?I zAE4GK4nNm;?Ce{&@WG+I5x&I=MBIVj@Cm@?QYQWzeLO3t?>cafMK3xp?N*FOZydc0 zoyh+9GYS3Vg}htAW1BJM*iyt~jbq!}o`|8=?#R9i6URAis@-j0WKZklh0H?87@9Z6 zE@2sLd(8D<5xbnjIa2S<)H04D^w^kT1U8*MV63qgy&M=;b|0+m z74JoT@b~?-znZB%EZZH=!oG;cP®tYZ5#Jlz?1z=HlbJd3FQj2z2IiQb%eOi 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 (required unless --version) + ! -m/--runmode (required unless --version) + ! -d/--domid (required unless --version) + ! -s/--sets (required for idx,opt) + ! -i/--index (required for idx) + ! -r/--restart (optional) + ! -t/--tag (optional) + ! -p/--param (optional) + ! -v/--version (prints version info and exits) + ! -h/--help (prints help and exits) + ! ----------------------------------------------------------------------------------------- + + nArg = command_argument_count() + if (nArg < 1) call printCommandHelp() + + i = 1 + do while (i <= narg) + call get_arg(i,a) + + select case (trim(a)) + + case ('-h','--help') + opts%show_help = .true. + i = i + 1 + + case ('-v','--version') + opts%show_version = .true. + i = i + 1 + + case ('-t','--tag') + call require_next(i, narg, a, v, err, cmessage) + opts%tag = trim(v) + i = i + 2 + + case ('-c','--control') + call require_next(i, narg, a, v, err, cmessage) + opts%control_file = trim(v) + i = i + 2 + + case ('-m','--runmode') + call require_next(i, narg, a, v, err, cmessage) + opts%runmode = to_lower(trim(v)) + i = i + 2 + + case ('-d','--domid') + call require_next(i, narg, a, v, err, cmessage) + opts%domain_id = trim(v) + i = i + 2 + + case ('-p', '--param') + call require_next(i, narg, a, kv, err, cmessage) + i = i + 2 + + case ('-s','--sets','--param-sets') + call require_next(i, narg, a, v, err, cmessage) + opts%sets_file = trim(v) + i = i + 2 + + case ('-i','--index') + call require_next(i, narg, a, cIndex, err, cmessage) + i = i + 2 + + case ('-r','--restart') + call require_next(i, narg, a, v, err, cmessage) + opts%restart_freq = to_lower(trim(v)) + i = i + 2 + + case default + if (len_trim(a) > 0 .and. a(1:1) == '-') then + err = 1 + cmessage = "unknown option: "//trim(a)//"; type 'fuse.exe --help' for usage" + else + err = 1 + cmessage = "unexpected positional argument: "//trim(a)//"; type 'fuse.exe --help' for usage" + end if + end select + + ! process error code + if(err/=0)then + message=trim(message)//trim(cmessage) + err=20; return + endif + + ! process parameters -- needs to be in the do loop since multiple parameters + if(allocated(kv))then + + ! split name/value based on the equal sign + call split_param_kv(trim(kv), pname, pval_str, err, cmessage) + if(err /= 0)then; message=trim(message)//trim(cmessage); err=20; return; endif + + ! convert characters to real values + call parse_real_sp(pval_str, pval, err, cmessage) + if (err /= 0) then + message=trim(message)//"invalid --param value for "//trim(pname)//": "//trim(cmessage) + err=20; return + end if + + ! add to structure in opts + call push_param(opts%param_name, opts%param_value, pname, pval) + print*, opts%param_name + print*, opts%param_value + + endif ! if processing parameters + + end do ! looping through arguments + + ! Early exits + if (opts%show_help) then + call printCommandHelp() + stop 0 + end if + if (opts%show_version) then + call printVersionInfo() + stop 0 + end if + + ! Parse parameter index + if(allocated(cIndex))then + call parse_int(cIndex, opts%indx, err, cmessage) + if(err/=0)then + message=trim(message)//trim(cmessage) + err=20; return + endif + endif + + ! Validate required args + if (.not. allocated(opts%control_file)) then + err = 1; message = trim(message)//"missing required --control; type 'fuse.exe --help' for usage"; return + end if + if (.not. allocated(opts%domain_id)) then + err = 1; message = trim(message)//"missing required --domid; type 'fuse.exe --help' for usage"; return + end if + if (.not. allocated(opts%runmode)) then + err = 1; message = trim(message)//"missing required --runmode; type 'fuse.exe --help' for usage"; return + end if + + if (.not. is_valid_mode(opts%runmode)) then + err = 1; message = trim(message)//"invalid --runmode: "//trim(opts%runmode)//" (expect def|idx|opt|sce)"; return + end if + + ! Mode-dependent requirements + select case (trim(opts%runmode)) + case ('idx') + if (.not. allocated(opts%sets_file)) then + err = 1; message = trim(message)//"runmode idx requires --sets "; return + end if + if (opts%indx < 0) then + err = 1; message = trim(message)//"runmode idx requires --index "; return + end if + case ('opt') + if (.not. allocated(opts%sets_file)) then + err = 1; message = trim(message)//"runmode opt requires --sets "; return + end if + case ('def','sce') + ! no extra requirements + end select + + ! Validate frequencies if provided (optional) + if (allocated(opts%restart_freq)) then + if (.not. is_valid_restart(opts%restart_freq)) then + err = 1; message = trim(message)//"invalid --restart: "//trim(opts%restart_freq)//" (expect y|m|d|e|never)"; return + end if + end if + + end subroutine parse_command_args + + ! ----- list version ---------------------------------------------------------------------- + + subroutine printVersionInfo() + ! Assumes these are available, e.g. from: + ! include "fuseversion.inc" + ! somewhere in a used module (e.g., globaldata) OR add that include here. + use globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH + implicit none + print '(A)', repeat('-', 70) + print '(A)', 'FUSE' + print '(" ",A12," : ",A)', 'Version', trim(FUSE_VERSION) + print '(" ",A12," : ",A)', 'Build time', trim(FUSE_BUILDTIME) + print '(" ",A12," : ",A)', 'Git branch', trim(FUSE_GITBRANCH) + print '(" ",A12," : ",A)', 'Git hash', trim(FUSE_GITHASH) + print '(A)', repeat('-', 70) + end subroutine printVersionInfo + + ! ----- list command usage ---------------------------------------------------------------- + + subroutine printCommandHelp() + implicit none + print "(A)", "" + print "(A)", "Usage:" + print "(A)", " fuse.exe -d domain_id -c control_file -m {def|idx|opt|sce} [options]" + print "(A)", "" + + print "(A)", "Run modes:" + print "(A)", " def : run with default parameter sets" + print "(A)", " idx : run using a given index from a parameter sets file" + print "(A)", " opt : run using best simulation from a parameter sets file" + print "(A)", " sce : optimize (SCE)" + print "(A)", "" + + print "(A)", "Required:" + print "(A)", " -d, --domid Domain ID" + print "(A)", " -c, --control Control file" + print "(A)", " -m, --runmode def|idx|opt|sce" + print "(A)", "" + + print "(A)", "Conditional:" + print "(A)", " -s, --sets Parameter sets file (required for idx,opt)" + print "(A)", " -i, --index Index (required for idx)" + print "(A)", "" + + print "(A)", "Optional:" + print "(A)", " -r, --restart y|m|d|e|never" + print "(A)", " -t, --tag Add tag to output filename" + print "(A)", " -v, --version Print version info and exit" + print "(A)", " -h, --help Print this help and exit" + print "(A)", "" + + print "(A)", "Examples:" + print "(A)", " Default run (no parameter-set file):" + print "(A)", " fuse.exe -d camels-12345 -c ./control/FUSE_control.txt -m def" + print "(A)", "" + + print "(A)", " Default run and write restart file every day:" + print "(A)", " fuse.exe -d camels-12345 -c ./control/FUSE_control.txt -m def -r d" + print "(A)", "" + + print "(A)", " Run using parameter set index 17 from a sets file:" + print "(A)", " fuse.exe -d camels-12345 -c ./control/FUSE_control.txt -m idx -s ./params/sets.nc -i 17" + print "(A)", "" + + print "(A)", " Run using the best simulation from a sets file:" + print "(A)", " fuse.exe -d camels-12345 -c ./control/FUSE_control.txt -m opt -s ./params/sets.nc" + print "(A)", "" + + print "(A)", " Optimize using SCE:" + print "(A)", " fuse.exe -d camels-12345 -c ./control/FUSE_control.txt -m sce" + print "(A)", "" + + print "(A)", " Print version information:" + print "(A)", " fuse.exe --version" + print "(A)", "" + end subroutine printCommandHelp + + ! ----------------------------------------------------------------------------------------- + ! Helpers + ! ----------------------------------------------------------------------------------------- + + subroutine get_arg(i, out) + integer, intent(in) :: i + character(len=:), allocatable, intent(out) :: out + integer :: L + call get_command_argument(i, length=L) + allocate(character(len=L) :: out) + call get_command_argument(i, out) + end subroutine get_arg + + subroutine require_next(i, narg, opt, val, err, message) + integer, intent(in) :: i, narg + character(len=*), intent(in) :: opt + character(len=:), allocatable, intent(out) :: val + integer, intent(out) :: err + character(len=:), allocatable, intent(out) :: message + err = 0 + message = "" + if (i+1 > narg) then + err = 1 + message = "missing value after "//trim(opt)//"; type 'fuse.exe --help' for usage" + return + end if + call get_arg(i+1, val) + end subroutine require_next + + subroutine split_param_kv(kv, name, val, err, message) + character(len=*), intent(in) :: kv + character(len=:), allocatable, intent(out) :: name, val + integer(i4b), intent(out) :: err + character(len=:), allocatable, intent(out) :: message + integer(i4b) :: p + + err = 0; message = "" + p = index(kv, '=') + if (p <= 1 .or. p >= len_trim(kv)) then + err = 1 + message = "expected NAME=VALUE after --param, got: "//trim(kv) + return + end if + + name = adjustl(kv(1:p-1)) + val = adjustl(kv(p+1:)) + + if (len_trim(name) == 0 .or. len_trim(val) == 0) then + err = 1 + message = "expected NAME=VALUE after --param, got: "//trim(kv) + return + end if + end subroutine split_param_kv + + subroutine parse_real_sp(s, x, err, message) + character(len=*), intent(in) :: s + real(sp), intent(out) :: x + integer, intent(out) :: err + character(len=:), allocatable, intent(out) :: message + integer(i4b) :: ios + err = 0; message = "" + read(s, *, iostat=ios) x + if (ios /= 0) then + err = 1 + message = "invalid real: "//trim(s) + end if + end subroutine parse_real_sp + + subroutine parse_int(s, x, err, message) + character(len=*), intent(in) :: s + integer, intent(out) :: x + integer, intent(out) :: err + character(len=:), allocatable, intent(out) :: message + integer :: ios + err = 0 + message = "" + read(s, *, iostat=ios) x + if (ios /= 0) then + err = 1 + message = "invalid integer: "//trim(s) + end if + end subroutine parse_int + + pure function to_lower(s) result(t) + character(len=*), intent(in) :: s + character(len=len(s)) :: t + integer :: k, c + t = s + do k = 1, len(s) + c = iachar(t(k:k)) + if (c >= iachar('A') .and. c <= iachar('Z')) then + t(k:k) = achar(c + (iachar('a') - iachar('A'))) + end if + end do + end function to_lower + + subroutine push_param(pnames, pvals, name, val) + use nrtype + implicit none + character(len=:), allocatable, intent(inout) :: pnames(:) + real(sp), allocatable, intent(inout) :: pvals(:) + character(len=*), intent(in) :: name + real(sp), intent(in) :: val + + character(len=:), allocatable :: new_names(:) + real(sp), allocatable :: new_vals(:) + integer :: n + + n = 0 + if (allocated(pvals)) n = size(pvals) + + allocate(character(len=len_trim(name)) :: new_names(n+1)) + allocate(new_vals(n+1)) + + if (n > 0) then + new_names(1:n) = pnames + new_vals(1:n) = pvals + end if + + new_names(n+1) = trim(name) + new_vals(n+1) = val + + call move_alloc(new_names, pnames) + call move_alloc(new_vals, pvals) + end subroutine push_param + + pure logical function is_valid_mode(m) + character(len=*), intent(in) :: m + is_valid_mode = (trim(m) == 'def' .or. trim(m) == 'idx' .or. trim(m) == 'opt' .or. trim(m) == 'sce') + end function is_valid_mode + + pure logical function is_valid_restart(f) + character(len=*), intent(in) :: f + is_valid_restart = (trim(f) == 'y' .or. trim(f) == 'm' .or. trim(f) == 'd' .or. trim(f) == 'e' .or. trim(f) == 'never') + end function is_valid_restart + +end module parse_command_args_MODULE + + + diff --git a/build/FUSE_SRC/prelim/uniquemodl.f90 b/build/FUSE_SRC/prelim/uniquemodl.f90 index e9de2a7..a2ea619 100644 --- a/build/FUSE_SRC/prelim/uniquemodl.f90 +++ b/build/FUSE_SRC/prelim/uniquemodl.f90 @@ -1,139 +1,149 @@ -SUBROUTINE UNIQUEMODL(NMOD) -! --------------------------------------------------------------------------------------- -! Creator: -! -------- -! Martyn Clark, 2007; modified in 2008 to include rainfall errors -! Modified by Brian Henn to include snow model, 6/2013 -! --------------------------------------------------------------------------------------- -! Purpose: -! -------- -! Creates an array of character strings that define different model combinations -! --------------------------------------------------------------------------------------- -! Modules Modified: -! ----------------- -! MODULE model_defn -! LIST_* = lists of options for * different model components -! AMODL%* = structure that holds all (NMOD) unique combinations -! --------------------------------------------------------------------------------------- -USE nrtype -USE model_defn -USE model_defnames -IMPLICIT NONE -! Output -INTEGER(I4B) :: NMOD ! number of model combinations -! Internal -INTEGER(I4B) :: ICOUNT ! loop through unique models -INTEGER(I4B) :: ISW_RFERR ! loop thru rainfall errors -INTEGER(I4B) :: ISW_ARCH1 ! loop thru upper layer architecture -INTEGER(I4B) :: ISW_ARCH2 ! loop thru lower layer architecture -INTEGER(I4B) :: ISW_QSURF ! loop thru surface runoff -INTEGER(I4B) :: ISW_QPERC ! loop thru percolation -INTEGER(I4B) :: ISW_ESOIL ! loop thru evaporation -INTEGER(I4B) :: ISW_QINTF ! loop thru interflow -INTEGER(I4B) :: ISW_Q_TDH ! loop thru time delay options -INTEGER(I4B) :: ISW_SNOWM ! loop thru snow model options -! Start procedure here -!err=0; message="UNIQUEMODL/ok" -! --------------------------------------------------------------------------------------- -! (1) POPULATE LISTS OF OPTIONS FOR THE DIFFERENT MODEL COMPONENTS -! --------------------------------------------------------------------------------------- -! rainfall error -LIST_RFERR(1)%MCOMPONENT = 'additive_e' ! additive rainfall error -LIST_RFERR(2)%MCOMPONENT = 'multiplc_e' ! multiplicative rainfall error -! upper-layer architecture -LIST_ARCH1(1)%MCOMPONENT = 'tension1_1' ! upper layer broken up into tension and free storage -LIST_ARCH1(2)%MCOMPONENT = 'tension2_1' ! tension storage sub-divided into recharge and excess -LIST_ARCH1(3)%MCOMPONENT = 'onestate_1' ! upper layer defined by a single state variable -! lower-layer architecture -- defines method for computing baseflow -LIST_ARCH2(1)%MCOMPONENT = 'tens2pll_2' ! tension reservoir plus two parallel tanks -LIST_ARCH2(2)%MCOMPONENT = 'unlimfrc_2' ! baseflow resvr of unlimited size (0-HUGE), frac rate -LIST_ARCH2(3)%MCOMPONENT = 'unlimpow_2' ! baseflow resvr of unlimited size (0-HUGE), power recession -LIST_ARCH2(4)%MCOMPONENT = 'fixedsiz_2' ! baseflow reservoir of fixed size -! surface runoff -LIST_QSURF(1)%MCOMPONENT = 'arno_x_vic' ! ARNO/Xzang/VIC parameterization (upper zone control) -LIST_QSURF(2)%MCOMPONENT = 'prms_varnt' ! PRMS variant (fraction of upper tension storage) -LIST_QSURF(3)%MCOMPONENT = 'tmdl_param' ! TOPMODEL parameterization (only valid for TOPMODEL qb) -! percolation -LIST_QPERC(1)%MCOMPONENT = 'perc_f2sat' ! water from (field cap to sat) avail for percolation -LIST_QPERC(2)%MCOMPONENT = 'perc_w2sat' ! water from (wilt pt to sat) avail for percolation -LIST_QPERC(3)%MCOMPONENT = 'perc_lower' ! perc defined by moisture content in lower layer (SAC) -! evaporation fluxes (lower layer evap = 0 for ['tension2_1','unlimfrc_2','unlimpow_2','topmdexp_2'] -LIST_ESOIL(1)%MCOMPONENT = 'sequential' ! sequential evaporation model -LIST_ESOIL(2)%MCOMPONENT = 'rootweight' ! root weighting -! interflow -LIST_QINTF(1)%MCOMPONENT = 'intflwnone' ! no interflow -LIST_QINTF(2)%MCOMPONENT = 'intflwsome' ! interflow -! time delay in runoff -LIST_Q_TDH(1)%MCOMPONENT = 'rout_gamma' ! use a Gamma distribution with shape parameter = 2.5 -LIST_Q_TDH(2)%MCOMPONENT = 'no_routing' ! no routing -! snow model switch -LIST_SNOWM(1)%MCOMPONENT = 'no_snowmod' ! no snow model -LIST_SNOWM(2)%MCOMPONENT = 'temp_index' ! temperature index snow model -! --------------------------------------------------------------------------------------- -! (2) LOOP THROUGH MODEL COMPONENTS AND DEFINE A SET OF UNIQUE MODELS -! --------------------------------------------------------------------------------------- -! sequence of model-building decisions -! a) define rainfall error -! b) define upper-layer architecture -! c) define lower-layer architecture -! d) define surface runoff method -! e) define percolation method -! f) define evaporation method -! g) define interflow method -! h) define time delay in runoff -ICOUNT = 0 ! initialize counter -! loop through snow model options -DO ISW_SNOWM=1,SIZE(LIST_SNOWM) -! (loop through time delay options) -DO ISW_Q_TDH=1,SIZE(LIST_Q_TDH) - ! (loop through interflow options) - DO ISW_QINTF=1,SIZE(LIST_QINTF) - ! (loop through evaporation options) - DO ISW_ESOIL=1,SIZE(LIST_ESOIL) - ! (loop through percolation options) - DO ISW_QPERC=1,SIZE(LIST_QPERC) - ! (loop through surface runoff options) - DO ISW_QSURF=1,SIZE(LIST_QSURF) - ! (loop through lower-layer architecture options) - DO ISW_ARCH2=1,SIZE(LIST_ARCH2) - ! (loop through upper-layer architecture options) - DO ISW_ARCH1=1,SIZE(LIST_ARCH1) - ! (loop through rainfall error options) - DO ISW_RFERR=1,SIZE(LIST_RFERR) - ! don't allow a lower tension tank when there are two upper ones - IF (LIST_ARCH1(ISW_ARCH1)%MCOMPONENT(1:10).EQ.'tension2_1'.AND. & - LIST_ARCH2(ISW_ARCH2)%MCOMPONENT(1:10).EQ.'tens2pll_2') CYCLE - ! don't allow percolation below field capacity if there are multiple upper tanks - IF (LIST_ARCH1(ISW_ARCH1)%MCOMPONENT(1:10).NE.'onestate_1'.AND. & - LIST_QPERC(ISW_QPERC)%MCOMPONENT(1:10).EQ.'perc_w2sat') CYCLE - ICOUNT = ICOUNT + 1 ! (increment counter) - IF (ICOUNT.LE.SIZE(AMODL)) THEN - ! save unique model combinations - AMODL(ICOUNT)%iRFERR = desc_str2int(LIST_RFERR(ISW_RFERR)%MCOMPONENT) - AMODL(ICOUNT)%iARCH1 = desc_str2int(LIST_ARCH1(ISW_ARCH1)%MCOMPONENT) - AMODL(ICOUNT)%iARCH2 = desc_str2int(LIST_ARCH2(ISW_ARCH2)%MCOMPONENT) - AMODL(ICOUNT)%iQSURF = desc_str2int(LIST_QSURF(ISW_QSURF)%MCOMPONENT) - AMODL(ICOUNT)%iQPERC = desc_str2int(LIST_QPERC(ISW_QPERC)%MCOMPONENT) - AMODL(ICOUNT)%iESOIL = desc_str2int(LIST_ESOIL(ISW_ESOIL)%MCOMPONENT) - AMODL(ICOUNT)%iQINTF = desc_str2int(LIST_QINTF(ISW_QINTF)%MCOMPONENT) - AMODL(ICOUNT)%iQ_TDH = desc_str2int(LIST_Q_TDH(ISW_Q_TDH)%MCOMPONENT) - AMODL(ICOUNT)%iSNOWM = desc_str2int(LIST_Q_TDH(ISW_SNOWM)%MCOMPONENT) - !write(*,'(i3,1x,7(a10,1x))') icount, amodl(icount) - ELSE - ! need to allocate more space - print *, 'insufficent space to hold model combinations' - stop - ENDIF - END DO ! RFERR - END DO ! ARCH1 - END DO ! ARCH2 - END DO ! QSURF - END DO ! QPERC - END DO ! ESOIL - END DO ! QINTF -END DO ! Q_TDH -END DO ! SNOWM -! --------------------------------------------------------------------------------------- -NMOD = ICOUNT -!pause -END SUBROUTINE UNIQUEMODL +module uniquemodl_module + implicit none + private + public :: uniquemodl + +contains + + + SUBROUTINE UNIQUEMODL(NMOD) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Martyn Clark, 2007; modified in 2008 to include rainfall errors + ! Modified by Brian Henn to include snow model, 6/2013 + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Creates an array of character strings that define different model combinations + ! --------------------------------------------------------------------------------------- + ! Modules Modified: + ! ----------------- + ! MODULE model_defn + ! LIST_* = lists of options for * different model components + ! AMODL%* = structure that holds all (NMOD) unique combinations + ! --------------------------------------------------------------------------------------- + USE nrtype + USE model_defn + USE model_defnames + IMPLICIT NONE + ! Output + INTEGER(I4B) , intent(out) :: NMOD ! number of model combinations + ! Internal + INTEGER(I4B) :: ICOUNT ! loop through unique models + INTEGER(I4B) :: ISW_RFERR ! loop thru rainfall errors + INTEGER(I4B) :: ISW_ARCH1 ! loop thru upper layer architecture + INTEGER(I4B) :: ISW_ARCH2 ! loop thru lower layer architecture + INTEGER(I4B) :: ISW_QSURF ! loop thru surface runoff + INTEGER(I4B) :: ISW_QPERC ! loop thru percolation + INTEGER(I4B) :: ISW_ESOIL ! loop thru evaporation + INTEGER(I4B) :: ISW_QINTF ! loop thru interflow + INTEGER(I4B) :: ISW_Q_TDH ! loop thru time delay options + INTEGER(I4B) :: ISW_SNOWM ! loop thru snow model options + ! Start procedure here + !err=0; message="UNIQUEMODL/ok" + ! --------------------------------------------------------------------------------------- + ! (1) POPULATE LISTS OF OPTIONS FOR THE DIFFERENT MODEL COMPONENTS + ! --------------------------------------------------------------------------------------- + ! rainfall error + LIST_RFERR(1)%MCOMPONENT = 'additive_e' ! additive rainfall error + LIST_RFERR(2)%MCOMPONENT = 'multiplc_e' ! multiplicative rainfall error + ! upper-layer architecture + LIST_ARCH1(1)%MCOMPONENT = 'tension1_1' ! upper layer broken up into tension and free storage + LIST_ARCH1(2)%MCOMPONENT = 'tension2_1' ! tension storage sub-divided into recharge and excess + LIST_ARCH1(3)%MCOMPONENT = 'onestate_1' ! upper layer defined by a single state variable + ! lower-layer architecture -- defines method for computing baseflow + LIST_ARCH2(1)%MCOMPONENT = 'tens2pll_2' ! tension reservoir plus two parallel tanks + LIST_ARCH2(2)%MCOMPONENT = 'unlimfrc_2' ! baseflow resvr of unlimited size (0-HUGE), frac rate + LIST_ARCH2(3)%MCOMPONENT = 'unlimpow_2' ! baseflow resvr of unlimited size (0-HUGE), power recession + LIST_ARCH2(4)%MCOMPONENT = 'fixedsiz_2' ! baseflow reservoir of fixed size + ! surface runoff + LIST_QSURF(1)%MCOMPONENT = 'arno_x_vic' ! ARNO/Xzang/VIC parameterization (upper zone control) + LIST_QSURF(2)%MCOMPONENT = 'prms_varnt' ! PRMS variant (fraction of upper tension storage) + LIST_QSURF(3)%MCOMPONENT = 'tmdl_param' ! TOPMODEL parameterization (only valid for TOPMODEL qb) + ! percolation + LIST_QPERC(1)%MCOMPONENT = 'perc_f2sat' ! water from (field cap to sat) avail for percolation + LIST_QPERC(2)%MCOMPONENT = 'perc_w2sat' ! water from (wilt pt to sat) avail for percolation + LIST_QPERC(3)%MCOMPONENT = 'perc_lower' ! perc defined by moisture content in lower layer (SAC) + ! evaporation fluxes (lower layer evap = 0 for ['tension2_1','unlimfrc_2','unlimpow_2','topmdexp_2'] + LIST_ESOIL(1)%MCOMPONENT = 'sequential' ! sequential evaporation model + LIST_ESOIL(2)%MCOMPONENT = 'rootweight' ! root weighting + ! interflow + LIST_QINTF(1)%MCOMPONENT = 'intflwnone' ! no interflow + LIST_QINTF(2)%MCOMPONENT = 'intflwsome' ! interflow + ! time delay in runoff + LIST_Q_TDH(1)%MCOMPONENT = 'rout_gamma' ! use a Gamma distribution with shape parameter = 2.5 + LIST_Q_TDH(2)%MCOMPONENT = 'no_routing' ! no routing + ! snow model switch + LIST_SNOWM(1)%MCOMPONENT = 'no_snowmod' ! no snow model + LIST_SNOWM(2)%MCOMPONENT = 'temp_index' ! temperature index snow model + ! --------------------------------------------------------------------------------------- + ! (2) LOOP THROUGH MODEL COMPONENTS AND DEFINE A SET OF UNIQUE MODELS + ! --------------------------------------------------------------------------------------- + ! sequence of model-building decisions + ! a) define rainfall error + ! b) define upper-layer architecture + ! c) define lower-layer architecture + ! d) define surface runoff method + ! e) define percolation method + ! f) define evaporation method + ! g) define interflow method + ! h) define time delay in runoff + ICOUNT = 0 ! initialize counter + ! loop through snow model options + DO ISW_SNOWM=1,SIZE(LIST_SNOWM) + ! (loop through time delay options) + DO ISW_Q_TDH=1,SIZE(LIST_Q_TDH) + ! (loop through interflow options) + DO ISW_QINTF=1,SIZE(LIST_QINTF) + ! (loop through evaporation options) + DO ISW_ESOIL=1,SIZE(LIST_ESOIL) + ! (loop through percolation options) + DO ISW_QPERC=1,SIZE(LIST_QPERC) + ! (loop through surface runoff options) + DO ISW_QSURF=1,SIZE(LIST_QSURF) + ! (loop through lower-layer architecture options) + DO ISW_ARCH2=1,SIZE(LIST_ARCH2) + ! (loop through upper-layer architecture options) + DO ISW_ARCH1=1,SIZE(LIST_ARCH1) + ! (loop through rainfall error options) + DO ISW_RFERR=1,SIZE(LIST_RFERR) + ! don't allow a lower tension tank when there are two upper ones + IF (LIST_ARCH1(ISW_ARCH1)%MCOMPONENT(1:10).EQ.'tension2_1'.AND. & + LIST_ARCH2(ISW_ARCH2)%MCOMPONENT(1:10).EQ.'tens2pll_2') CYCLE + ! don't allow percolation below field capacity if there are multiple upper tanks + IF (LIST_ARCH1(ISW_ARCH1)%MCOMPONENT(1:10).NE.'onestate_1'.AND. & + LIST_QPERC(ISW_QPERC)%MCOMPONENT(1:10).EQ.'perc_w2sat') CYCLE + ICOUNT = ICOUNT + 1 ! (increment counter) + IF (ICOUNT.LE.SIZE(AMODL)) THEN + ! save unique model combinations + AMODL(ICOUNT)%iRFERR = desc_str2int(LIST_RFERR(ISW_RFERR)%MCOMPONENT) + AMODL(ICOUNT)%iARCH1 = desc_str2int(LIST_ARCH1(ISW_ARCH1)%MCOMPONENT) + AMODL(ICOUNT)%iARCH2 = desc_str2int(LIST_ARCH2(ISW_ARCH2)%MCOMPONENT) + AMODL(ICOUNT)%iQSURF = desc_str2int(LIST_QSURF(ISW_QSURF)%MCOMPONENT) + AMODL(ICOUNT)%iQPERC = desc_str2int(LIST_QPERC(ISW_QPERC)%MCOMPONENT) + AMODL(ICOUNT)%iESOIL = desc_str2int(LIST_ESOIL(ISW_ESOIL)%MCOMPONENT) + AMODL(ICOUNT)%iQINTF = desc_str2int(LIST_QINTF(ISW_QINTF)%MCOMPONENT) + AMODL(ICOUNT)%iQ_TDH = desc_str2int(LIST_Q_TDH(ISW_Q_TDH)%MCOMPONENT) + AMODL(ICOUNT)%iSNOWM = desc_str2int(LIST_Q_TDH(ISW_SNOWM)%MCOMPONENT) + !write(*,'(i3,1x,7(a10,1x))') icount, amodl(icount) + ELSE + ! need to allocate more space + print *, 'insufficent space to hold model combinations' + stop + ENDIF + END DO ! RFERR + END DO ! ARCH1 + END DO ! ARCH2 + END DO ! QSURF + END DO ! QPERC + END DO ! ESOIL + END DO ! QINTF + END DO ! Q_TDH + END DO ! SNOWM + ! --------------------------------------------------------------------------------------- + NMOD = ICOUNT + !pause + END SUBROUTINE UNIQUEMODL + +end module uniquemodl_module diff --git a/build/FUSE_SRC/runtime/get_time_windows.f90 b/build/FUSE_SRC/runtime/get_time_windows.f90 new file mode 100644 index 0000000..6381c15 --- /dev/null +++ b/build/FUSE_SRC/runtime/get_time_windows.f90 @@ -0,0 +1,340 @@ +module time_windows_module + + use nrtype + use netcdf + use info_types, only: fuse_info + use fuse_fileManager, only: date_start_sim, date_end_sim, date_start_eval, date_end_eval, numtim_sub_str + use time_io, only: date_extractor, juldayss + + implicit none + + private + public :: get_time_windows + public :: export_time_to_multiforce + + contains + + subroutine get_time_windows(ncid, info, ierr, message) + + integer(i4b), intent(in) :: ncid + type(fuse_info), intent(inout) :: info + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: nt + real(sp), allocatable :: time_steps(:) + character(len=1024) :: units_local + integer(i4b) :: ios + character(len=1024) :: cmessage + + ierr=0; message="get_time_windows/" + + ! ----- read forcing time axis ------------------------------------------------------ + + call read_time_axis(ncid, time_steps, units_local, nt, ierr, cmessage) + if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + + info%time%nt_global = nt + info%time%units = trim(units_local) + + ! ----- build julian-day axis ------------------------------------------------------- + + call build_julian_axis(time_steps, trim(units_local), info%time%jdate_ref, info%time%jdate, ierr, cmessage) + if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + + ! ----- compute indices for sim/eval windows ---------------------------------------- + + ! simulation indices + call map_dates_to_indices(info%time%jdate, date_start_sim, date_end_sim, & + info%time%sim_beg, info%time%sim_end, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + + ! evaluation indices + call map_dates_to_indices(info%time%jdate, date_start_eval, date_end_eval, & + info%time%eval_beg, info%time%eval_end, ierr, cmessage) + if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + + ! ----- validate window consistency ------------------------------------------------- + + call validate_windows(info%time, ierr, cmessage) + if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + + ! ----- derive simulation length ---------------------------------------------------- + + info%time%nt_sim = info%time%sim_end - info%time%sim_beg + 1 + + ! ----- configure sub-period windowing ---------------------------------------------- + + ! convert sub-period string to integer + read(numtim_sub_str,*,iostat=ios) info%time%nt_window + if(ios/=0) then + ierr=1; message=trim(message)//"cannot parse numtim_sub_str"; return + endif + + ! handle cases where sub-periods are undefined + if(info%time%nt_window == -9999) then + info%time%use_subperiods = .false. + info%time%nt_window = info%time%nt_sim + else + info%time%use_subperiods = .true. + ! keep nt_window as user-chosen chunk size + endif + + ! ----- validate time-window configuration (subperiods allowed only in grid mode) --- + if( (.not. info%space%grid_flag) .and. info%time%use_subperiods ) then + ierr = 1 + message = trim(message)// & + "catchment mode requires running the full time series in one chunk; " // & + "set numtim_sub = -9999 in the filemanager." + return + endif + + ! ----- finalize -------------------------------------------------------------------- + + if(allocated(time_steps)) deallocate(time_steps) + + end subroutine get_time_windows + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- backwards compatibility: export to multiforce globals ------------------------- + + ! - New code stores all time-window metadata in info%time (source of truth). + ! - Legacy routines still read multiforce globals (sim_beg, sim_end, numtim_sub, ...). + + subroutine export_time_to_multiforce(info) + use multiforce, only: sim_beg, sim_end, eval_beg, eval_end, numtim_sim, numtim_sub, & + SUB_PERIODS_FLAG, istart + implicit none + type(fuse_info), intent(in) :: info + + sim_beg = info%time%sim_beg + sim_end = info%time%sim_end + eval_beg = info%time%eval_beg + eval_end = info%time%eval_end + + numtim_sim = info%time%nt_sim + numtim_sub = info%time%nt_window + SUB_PERIODS_FLAG = info%time%use_subperiods + + istart = sim_beg + end subroutine + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + ! ----- helper routines --------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- helper: read time axis from NetCDF -------------------------------------------- + + subroutine read_time_axis(ncid, time_steps, units, nt, ierr, message) + + integer(i4b), intent(in) :: ncid + real(sp), allocatable, intent(out) :: time_steps(:) + character(len=*), intent(out) :: units + integer(i4b), intent(out) :: nt, ierr + character(*), intent(out) :: message + + integer(i4b) :: varid, dimids(1) + + ierr=0; message="read_time_axis/" + + ierr = nf90_inq_varid(ncid, "time", varid) + if(ierr/=nf90_noerr) then + message=trim(message)//"cannot find time variable"; return + endif + + ierr = nf90_inquire_variable(ncid, varid, dimids=dimids) + if(ierr/=nf90_noerr) then + message=trim(message)//trim(nf90_strerror(ierr)); return + endif + + ierr = nf90_inquire_dimension(ncid, dimids(1), len=nt) + if(ierr/=nf90_noerr) then + message=trim(message)//trim(nf90_strerror(ierr)); return + endif + + allocate(time_steps(nt), stat=ierr) + if(ierr/=0) then + message=trim(message)//"allocate(time_steps) failed"; return + endif + + ierr = nf90_get_var(ncid, varid, time_steps) + if(ierr/=nf90_noerr) then + message=trim(message)//trim(nf90_strerror(ierr)); return + endif + + ierr = nf90_get_att(ncid, varid, "units", units) + if(ierr/=nf90_noerr) then + message=trim(message)//"cannot read time units attribute"; return + endif + + end subroutine read_time_axis + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- helper: build julian axis ----------------------------------------------------- + + subroutine build_julian_axis(time_steps, units, jref, jdate, ierr, message) + + real(sp), intent(in) :: time_steps(:) + character(len=*), intent(in) :: units + real(sp), intent(out) :: jref + real(sp), allocatable, intent(out) :: jdate(:) + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: iy,im,id,ih + character(len=1024) :: cmessage + real(sp) :: scale_to_days + + ierr=0; message="build_julian_axis/" + + ! extract reference date from the units string + call date_extractor(trim(units), iy, im, id, ih) + call juldayss(iy,im,id,ih, jref, ierr, cmessage) + if(ierr/=0) then; message=trim(message)//trim(cmessage); return; endif + + ! determine scaling factor to convert time_steps into days + scale_to_days = time_units_to_days(units, ierr, cmessage) + if(ierr/=0) then; message=trim(message)//trim(cmessage); return; endif + + ! build julian axis + allocate(jdate(size(time_steps)), stat=ierr) + if(ierr/=0) then; message=trim(message)//"allocate(jdate) failed"; return; endif + jdate = jref + time_steps * scale_to_days + + end subroutine build_julian_axis + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- helper: determine scaling factor to convert time_steps into days -------------- + + real(sp) function time_units_to_days(units, ierr, message) + implicit none + character(len=*), intent(in) :: units + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + character(len=:), allocatable :: u + integer(i4b) :: p + + ierr=0; message="time_units_to_days/" + + ! lower-case copy (simple approach) + u = tolower_str( trim(adjustl(units)) ) + + ! Look at the first token before a space + p = index(u, " ") + if(p <= 1) then + ierr=1; message=trim(message)//"cannot parse units string: "//trim(units) + time_units_to_days = 0._sp + return + endif + + select case (trim(u(1:p-1))) + case ("days", "day") + time_units_to_days = 1._sp + case ("hours", "hour") + time_units_to_days = 1._sp / 24._sp + case ("minutes", "minute", "mins", "min") + time_units_to_days = 1._sp / 1440._sp + case ("seconds", "second", "secs", "sec") + time_units_to_days = 1._sp / 86400._sp + case default + ierr=1 + message=trim(message)//"unsupported time unit: "//trim(u(1:p-1)) + time_units_to_days = 0._sp + end select + + end function time_units_to_days + + pure function tolower_str(s) result(out) + character(len=*), intent(in) :: s + character(len=len(s)) :: out + integer :: i + do i=1,len(s) + select case(s(i:i)) + case("A":"Z"); out(i:i) = achar(iachar(s(i:i)) + 32) + case default; out(i:i) = s(i:i) + end select + end do + end function tolower_str + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- helper: map start/end date strings to indices --------------------------------- + + subroutine map_dates_to_indices(jdate, date_start, date_end, i_beg, i_end, ierr, message) + + real(sp), intent(in) :: jdate(:) + character(len=*), intent(in) :: date_start, date_end + integer(i4b), intent(out) :: i_beg, i_end + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: iy,im,id,ih + real(sp) :: j_start, j_end + character(len=1024) :: cmessage + + ierr=0; message="map_dates_to_indices/" + + ! start date + call date_extractor(trim(date_start), iy,im,id,ih) + call juldayss(iy,im,id,ih, j_start, ierr, cmessage) + if(ierr/=0) then; message=trim(message)//trim(cmessage); return; endif + + ! end date + call date_extractor(trim(date_end), iy,im,id,ih) + call juldayss(iy,im,id,ih, j_end, ierr, cmessage) + if(ierr/=0) then; message=trim(message)//trim(cmessage); return; endif + + ! validate + + if(j_start > j_end) then + ierr=1; message=trim(message)//"start date > end date"; return + endif + + if(j_start < minval(jdate) .or. j_end > maxval(jdate)) then + ierr=1; message=trim(message)//"requested window outside forcing range"; return + endif + + ! get indices in jdate vector + i_beg = minloc(abs(jdate - j_start), 1) + i_end = minloc(abs(jdate - j_end ), 1) + + end subroutine map_dates_to_indices + + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- helper: validate sim/eval logic ----------------------------------------------- + + subroutine validate_windows(ti, ierr, message) + + use info_types, only: time_info + type(time_info), intent(in) :: ti + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + ierr=0; message="validate_windows/" + + if(ti%eval_beg < ti%sim_beg) then + ierr=1; message=trim(message)//"eval start < sim start"; return + endif + if(ti%eval_end > ti%sim_end) then + ierr=1; message=trim(message)//"eval end > sim end"; return + endif + + end subroutine validate_windows + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + +end module time_windows_module diff --git a/build/FUSE_SRC/share/multiparam_data.f90 b/build/FUSE_SRC/share/multiparam_data.f90 index 2fc8071..4de449a 100644 --- a/build/FUSE_SRC/share/multiparam_data.f90 +++ b/build/FUSE_SRC/share/multiparam_data.f90 @@ -20,6 +20,7 @@ MODULE multiparam public :: MAXPAR, NUMPAR public :: APARAM, MPARAM, DPARAM public :: PARMETA, LPARAM + public :: MAXN, KSTOP, PCENTO public :: SOBOL_INDX INTEGER(I4B), PARAMETER :: MAXPAR=50 ! maximum number of parameters for a single model @@ -32,6 +33,10 @@ MODULE multiparam TYPE(PARINFO) :: PARMETA ! parameter metadata (all parameters) TYPE(PAR_ID), DIMENSION(MAXPAR) :: LPARAM ! list of model parameter names (need to modify to 16 for SCE) + integer(i4b) :: MAXN ! maximum number of trials before optimization is terminated + integer(i4b) :: KSTOP ! number of shuffling loops the value must change by PCENTO + REAL(MSP) :: PCENTO ! the percentage + INTEGER(I4B) :: SOBOL_INDX ! code to re-assemble Sobol parameters END MODULE multiparam diff --git a/build/FUSE_SRC/types/info_types.f90 b/build/FUSE_SRC/types/info_types.f90 index 8721942..b9c5e11 100644 --- a/build/FUSE_SRC/types/info_types.f90 +++ b/build/FUSE_SRC/types/info_types.f90 @@ -6,6 +6,7 @@ module info_types private public :: cli_options + public :: time_info public :: fuse_info ! -------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/util/alloc_domain.f90 b/build/FUSE_SRC/util/alloc_domain.f90 new file mode 100644 index 0000000..9c445d4 --- /dev/null +++ b/build/FUSE_SRC/util/alloc_domain.f90 @@ -0,0 +1,131 @@ +module alloc_domain_module + + USE nrtype + USE info_types, only: fuse_info + USE data_types, only: domain_data + + implicit none + private + public :: allocate_domain_data + public :: set_legacy_arrays + +CONTAINS + + subroutine allocate_domain_data(info, domain, ierr, message) + + implicit none + + type(fuse_info), intent(in) :: info + type(domain_data), intent(inout) :: domain + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: nx, ny, nt, nb + + ierr=0; message="allocate_domain_data/" + + ! define dimensions + nx = info%space%nx_local ! NOTE: local to rank (MPI parallelization) + ny = info%space%ny_local + nt = info%time%nt_window + nb = info%snow%n_bands + + ! allocate validity mask + allocate(domain%valid(nx,ny,nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate valid"; return; endif + + ! allocate ancillary forcing + allocate(domain%ancil(nx,ny), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate ancil"; return; endif + + ! allocate forcing window + allocate(domain%force(nx,ny,nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate force"; return; endif + + ! allocate state window + allocate(domain%state(nx,ny,nt+1), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate state"; return; endif + + ! allocate flux window + allocate(domain%flux(nx,ny,nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate flux"; return; endif + + ! allocate basin averages + allocate(domain%aForce(nt), domain%aRoute(nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate aForce/aRoute"; return; endif + + ! allocate routing if needed + allocate(domain%route(nx,ny,nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate route"; return; endif + + ! allocate bands + allocate(domain%bands(nx,ny,nb,nt+1), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate bands"; return; endif + + end subroutine allocate_domain_data + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- copy arrays in the domain structure to legacy arrays --------------------- + + subroutine set_legacy_arrays(info, domain, ierr, message) + + ! legacy modules + use multiforce, only: nSpat1, nSpat2, numtim_sub + use multiForce, only: gForce_3d, ancilF, aValid + use multiState, only: gState_3d + use multiRoute, only: AROUTE_3d + use multiBands, only: MBANDS_VAR_4d, N_BANDS + implicit none + + type(fuse_info), intent(in) :: info + type(domain_data), intent(inout) :: domain + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + ierr = 0 + message = 'set_legacy_arrays/' + + ! ensure the spatial dimensions match what is in domain%info + ! NOTE: dimension variables stored in legacy data modules + nSpat1 = info%space%nx_local ! NOTE: local to rank (MPI parallelization) + nSpat2 = info%space%ny_local + numtim_sub = info%time%nt_window + n_bands = info%snow%n_bands + + ! allocate space for the forcing grid and states + allocate(ancilF(nspat1,nspat2), stat=ierr) + if(ierr/=0)then + message=trim(message)//'unable to allocate space for 2-d ancillary grid' + ierr=20; return + endif + + ! allocate space for the forcing grid and states with a time dimension - only for subperiod + allocate(aValid( nspat1,nspat2,numtim_sub), & + gForce_3d(nspat1,nspat2,numtim_sub), & + gState_3d(nspat1,nspat2,numtim_sub+1), & + AROUTE_3d(nspat1,nspat2,numtim_sub), stat=ierr) + if(ierr/=0)then + message=trim(message)//'unable to allocate space for 3d structure' + ierr=20; return + endif + + ! allocate space for elevation bands + allocate(MBANDS_VAR_4d(nspat1,nspat2,N_BANDS,numtim_sub+1), stat=ierr) + if(ierr/=0)then + message=trim(message)//'unable to allocate space for elevation bands' + ierr=20; return + endif + + ! copy arrays in the domain structure to legacy arrays + aValid = domain%valid ! validity mask + ancilF = domain%ancil ! ancillary forcing + gForce_3d = domain%force ! forcing window + gState_3d = domain%state ! state window + AROUTE_3d = domain%route ! routing window + MBANDS_VAR_4d = domain%bands ! elevation band window + + end subroutine set_legacy_arrays + +end module alloc_domain_module diff --git a/build/FUSE_SRC/util/alloc_scratch.f90 b/build/FUSE_SRC/util/alloc_scratch.f90 new file mode 100644 index 0000000..37b0771 --- /dev/null +++ b/build/FUSE_SRC/util/alloc_scratch.f90 @@ -0,0 +1,143 @@ +module alloc_scratch_module + + + USE nrtype + use info_types, only: fuse_info + use work_types, only: fuse_work + + implicit none + private + public :: init_fuse_work + +CONTAINS + + subroutine init_fuse_work(info, work, ierr, message) + + use globaldata, only: NPAR_SNOW + implicit none + + type(fuse_info), intent(in) :: info + type(fuse_work), intent(inout) :: work + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: ib + integer(i4b) :: nBands, nState, nPar + + ierr=0; message="init_fuse_work/" + + ! identify dimensions + nBands = info%snow%n_bands + nState = info%config%nState + nPar = info%config%nParam + + ! If already initialized, don't reallocate unless sizes mismatch + if (work%is_initialized) then + call free_fuse_work(work, ierr, message) + if(ierr/=0) return + endif + + ! optional debug scratch + ! allocate(work%dSdt(nState), work%J(nState,nState), stat=ierr) + + ! ---- allocate differentiable parent derivatives ---- + allocate(work%adj%df_dS(nState), & + work%adj%df_dPar(nPar), & + work%adj%dL_dPar(nPar), stat=ierr) + if(ierr/=0) then + message=trim(message)//"cannot allocate derivatives" + return + endif + + ! ---- allocate elevation band containers ---- + allocate(work%snow%sbands(nBands), stat=ierr) + if(ierr/=0) then + message=trim(message)//"cannot allocate sbands" + return + endif + + ! ---- allocate per-band parameter derivative vectors ---- + do ib=1,nBands + allocate(work%snow%sbands(ib)%var%dSWE_dParam(nPar_snow), stat=ierr) + if(ierr/=0) then + message=trim(message)//"cannot allocate dSWE_dParam for band" + return + endif + work%snow%sbands(ib)%var%dSWE_dParam(:) = 0._sp + enddo + + ! ---- initialize the band snow vars once ---- + work%snow%sbands(:)%var%SWE = 0._sp + work%snow%sbands(:)%var%SNOWACCMLTN = 0._sp + work%snow%sbands(:)%var%SNOWMELT = 0._sp + work%snow%sbands(:)%var%DSWE_DT = 0._sp + + work%is_initialized = .true. + + end subroutine init_fuse_work + + ! ------------------------------------------------------------------------------------- + + subroutine free_fuse_work(work, ierr, message) + + implicit none + type(fuse_work), intent(inout) :: work + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: ib, istat + + ierr = 0 + message = "free_fuse_work/" + + ! ---- derivative arrays ---- + if (allocated(work%adj%df_dS)) then + deallocate(work%adj%df_dS, stat=istat) + call note_fail("adj%df_dS", istat) + endif + + if (allocated(work%adj%df_dPar)) then + deallocate(work%adj%df_dPar, stat=istat) + call note_fail("adj%df_dPar", istat) + endif + + if (allocated(work%adj%dL_dPar)) then + deallocate(work%adj%dL_dPar, stat=istat) + call note_fail("adj%dL_dPar", istat) + endif + + ! ---- elevation band structures ---- + if (allocated(work%snow%sbands)) then + + do ib = 1, size(work%snow%sbands) + if (allocated(work%snow%sbands(ib)%var%dSWE_dParam)) then + deallocate(work%snow%sbands(ib)%var%dSWE_dParam, stat=istat) + call note_fail("sbands%var%dSWE_dParam", istat) + endif + enddo + + deallocate(work%snow%sbands, stat=istat) + call note_fail("snow%sbands", istat) + + endif + + work%is_initialized = .false. + + contains + + subroutine note_fail(where, istat) + character(*), intent(in) :: where + integer(i4b), intent(in) :: istat + + if (istat /= 0) then + ! preserve the first nonzero stat as ierr + if (ierr == 0) ierr = istat + + ! append context (do not overwrite) + message = trim(message)//" dealloc_fail("//trim(where)//")" + endif + end subroutine note_fail + + end subroutine free_fuse_work + +end module alloc_scratch_module diff --git a/build/FUSE_SRC/util/fuse_fileManager.f90 b/build/FUSE_SRC/util/fuse_fileManager.f90 index 2352ec5..7ea1447 100644 --- a/build/FUSE_SRC/util/fuse_fileManager.f90 +++ b/build/FUSE_SRC/util/fuse_fileManager.f90 @@ -3,209 +3,390 @@ !****************************************************************** ! Edited by Brian Henn to include snow model, 7/2013 ! Edited by Nans Addor to set simulation and evaluation periods, 11/2017 -! Edited by Cyril Thébault to allow different metrics as objective function, 2024 +! Modified by Martyn Clark to populate domain structure, 12/2025 MODULE fuse_filemanager -use kinds_dmsl_kit_FUSE,only:mik,mlk - -implicit none -public -! FUSE-wide pathlength -integer(mik),parameter::fusePathLen=256 -! defines the path for data files -CHARACTER(LEN=fusePathLen) :: SETNGS_PATH -CHARACTER(LEN=fusePathLen) :: INPUT_PATH -CHARACTER(LEN=fusePathLen) :: OUTPUT_PATH -! content of input directory -CHARACTER(LEN=fusePathLen) :: suffix_forcing ! suffix for forcing file -CHARACTER(LEN=fusePathLen) :: suffix_elev_bands ! suffix for elevation band file -! content of settings directory -CHARACTER(LEN=fusePathLen) :: M_DECISIONS ! definition of model decisions -CHARACTER(LEN=fusePathLen) :: CONSTRAINTS ! definition of parameter constraints -CHARACTER(LEN=fusePathLen) :: MOD_NUMERIX ! definition of numerical solution technique -CHARACTER(LEN=fusePathLen) :: FORCINGINFO ! info on forcing data files -CHARACTER(LEN=fusePathLen) :: MBANDS_INFO ! info on basin band data files ! not needed anymore -CHARACTER(LEN=fusePathLen) :: MBANDS_NC ! netcdf file defining the elevation bands -CHARACTER(LEN=fusePathLen) :: BATEA_PARAM ! definition of BATEA parameters ! remove this -! content of output directory -CHARACTER(LEN=64) :: FMODEL_ID ! string defining FUSE model -CHARACTER(LEN=64) :: Q_ONLY_STR ! TRUE = restrict attention to simulated runoff -LOGICAL :: Q_ONLY ! .TRUE. = restrict attention to simulated runoff -! define simulation and evaluation periods -CHARACTER(len=20) :: date_start_sim ! date start simulation -CHARACTER(len=20) :: date_end_sim ! date end simulation -CHARACTER(len=20) :: date_start_eval ! date start evaluation period -CHARACTER(len=20) :: date_end_eval ! date end evaluation period -CHARACTER(len=20) :: numtim_sub_str ! number of time steps of subperiod (will be kept in memory) -! evaluation metrics and transformation -CHARACTER(len=20) :: METRIC ! metric chosen as objective function -CHARACTER(len=20) :: TRANSFO ! streamflow transformation -! SCE parameters -CHARACTER(len=20) :: KSTOP_str ! number of shuffling loops the value must change by PCENTO -CHARACTER(len=20) :: MAXN_str ! maximum number of trials before optimization is terminated -CHARACTER(len=20) :: PCENTO_str ! the percentage -!---------------------------------------------------- + use nrtype + use kinds_dmsl_kit_FUSE,only:mik,mlk + use info_types, only: cli_options + use info_types, only: fuse_info + + implicit none + private + + public :: fuse_SetDirsUndPhiles + public :: export_filemanager_to_domain + public :: finalize_domain_config + public :: export_domain_to_legacy + + ! expose legacy globals + public :: SETNGS_PATH, INPUT_PATH, OUTPUT_PATH + public :: suffix_forcing, suffix_elev_bands + public :: FORCINGINFO, CONSTRAINTS, MOD_NUMERIX, M_DECISIONS + public :: MBANDS_INFO, MBANDS_NC + public :: FMODEL_ID, Q_ONLY_STR, Q_ONLY + public :: date_start_sim, date_end_sim, date_start_eval, date_end_eval, numtim_sub_str + public :: METRIC, TRANSFO + public :: KSTOP_str, MAXN_str, PCENTO_str + + ! FUSE-wide pathlength + integer(mik),parameter::fusePathLen=512 + + ! defines the path for data files + CHARACTER(LEN=fusePathLen) :: SETNGS_PATH + CHARACTER(LEN=fusePathLen) :: INPUT_PATH + CHARACTER(LEN=fusePathLen) :: OUTPUT_PATH + + ! content of input directory + CHARACTER(LEN=fusePathLen) :: suffix_forcing ! suffix for forcing file + CHARACTER(LEN=fusePathLen) :: suffix_elev_bands ! suffix for elevation band file + + ! content of settings directory + CHARACTER(LEN=fusePathLen) :: M_DECISIONS ! definition of model decisions + CHARACTER(LEN=fusePathLen) :: CONSTRAINTS ! definition of parameter constraints + CHARACTER(LEN=fusePathLen) :: MOD_NUMERIX ! definition of numerical solution technique + CHARACTER(LEN=fusePathLen) :: FORCINGINFO ! info on forcing data files + CHARACTER(LEN=fusePathLen) :: MBANDS_INFO ! info on basin band data files ! not needed anymore + CHARACTER(LEN=fusePathLen) :: MBANDS_NC ! netcdf file defining the elevation bands + + ! content of output directory + CHARACTER(LEN=64) :: FMODEL_ID ! string defining FUSE model + CHARACTER(LEN=64) :: Q_ONLY_STR ! TRUE = restrict attention to simulated runoff + LOGICAL :: Q_ONLY ! .TRUE. = restrict attention to simulated runoff + + ! define simulation and evaluation periods + CHARACTER(len=20) :: date_start_sim ! date start simulation + CHARACTER(len=20) :: date_end_sim ! date end simulation + CHARACTER(len=20) :: date_start_eval ! date start evaluation period + CHARACTER(len=20) :: date_end_eval ! date end evaluation period + CHARACTER(len=20) :: numtim_sub_str ! number of time steps of subperiod (will be kept in memory) + + ! evaluation metrics and transformation + CHARACTER(len=20) :: METRIC ! metric chosen as objective function + CHARACTER(len=20) :: TRANSFO ! streamflow transformation + + ! SCE parameters + CHARACTER(len=20) :: KSTOP_str ! number of shuffling loops the value must change by PCENTO + CHARACTER(len=20) :: MAXN_str ! maximum number of trials before optimization is terminated + CHARACTER(len=20) :: PCENTO_str ! the percentage + contains -!---------------------------------------------------- -subroutine fuse_SetDirsUndPhiles(fuseMusterDirektorIn,fuseFileManagerIn,err,message) -! Purpose: Sets direcotries and philenames for FUSE. -! --- -! Programmer: Dmitri Kavetski -! History: -! Darby St, 18/10/2009 AD - leid out basik frammenverk -! Sonnental, 17/06/2012 AD - more general path handling -! --- -! Usage -! fuseMusterDirektorIn = master direktor file (path to filemanager) -! fuseFileManagerIn = global names/path file -! --- -! Comments: -! 1. If present will try to use fuseMasterIn, otherwise default file. -! if default not present in EXE path then uses default options -! --- -use utilities_dmsl_kit_FUSE,only:getSpareUnit -implicit none -! dummies -character(*),intent(in),optional::fuseMusterDirektorIn,fuseFileManagerIn -integer(mik),intent(out)::err -character(*),intent(out)::message -! registered settings -character(*),parameter::procnam="fuseSetDirsUndPhiles" -character(*),parameter::pathDelim="/\",defpathSymb="*",blank=" " -character(*),parameter::fuseMusterDirektorHeader="FUSE_MUSTERDIREKTOR_V1.0" -character(*),parameter::fuseFileManagerHeader="FUSE_FILEMANAGER_V1.5" -! locals -logical(mlk)::haveFMG,haveMUS -character(LEN=fusePathLen)::fuseMusterDirektor,fuseFileManager,defpath -character(LEN=100)::temp -integer(mik)::unt,i -! Start procedure here -err=0; message=procnam//"/ok"; defpath=blank -haveMUS=present(fuseMusterDirektorIn); haveFMG=present(fuseFileManagerIn) -if(haveMUS)haveMUS=len_trim(fuseMusterDirektorIn)>0 -if(haveFMG)haveFMG=len_trim(fuseFileManagerIn)>0 ! check for zero-string -if(haveMUS.and.haveFMG)then - message="f-"//procnam//"/mustSpecifyEither(notBoth)& - &[fuseMusterDirektor.or.fuseFileManager]" - err=10; return -elseif(haveFMG)then - fuseFileManager=fuseFileManagerIn - i=scan(fuseFileManager,pathDelim,back=.true.) - if(i>0)defpath=fuseFileManager(:i-1)//pathDelim(1:1) - print *, 'fuseFileManager:', TRIM(fuseFileManager) - -elseif(haveMUS)then - fuseMusterDirektor=fuseMusterDirektorIn - i=scan(fuseMusterDirektor,pathDelim,back=.true.) - if(i>0)defpath=fuseMusterDirektor(:i-1)//pathDelim(1:1) - print *, 'fuseMusterDirektor:', TRIM(fuseMusterDirektor) - -else - message="f-"//procnam//"/mustSpecifyEither& - &[fuseMusterDirektor.or.fuseFileManager]" - err=20; return -endif -call getSpareUnit(unt,err,message) ! make sure 'unt' is actually available -if(err/=0)then - message="f-"//procnam//"/weird/&"//message - err=100; return -endif -if(.not.haveFMG)then ! grab it from the muster-direktor - -! 2. Open muster-direktor and read it - open(unt,file=fuseMusterDirektor,status="old",action="read",iostat=err) + + ! ----- copies the globals into the domain structure ---------------------------------- + + ! NOTE: this should be called after call fuse_SetDirsUndPhiles(fuseFileManagerIn, ..) + + subroutine export_filemanager_to_domain(cli_opts, info) + + implicit none + type(cli_options), intent(in) :: cli_opts ! command line interface options + type(fuse_info), intent(inout) :: info + + ! ----- file information ------------------------------------------------------------ + + ! directories + info%files%setngs_path = trim(SETNGS_PATH) + info%files%input_path = trim(INPUT_PATH) + info%files%output_path = trim(OUTPUT_PATH) + + ! suffixes + info%files%suffix_forcing = trim(suffix_forcing) + info%files%suffix_elev_bands = trim(suffix_elev_bands) + + ! settings filenames + info%files%forcinginfo = trim(FORCINGINFO) + info%files%constraints = trim(CONSTRAINTS) + info%files%mod_numerix = trim(MOD_NUMERIX) + info%files%m_decisions = trim(M_DECISIONS) + + ! ----- configuration options ------------------------------------------------------- + + ! Convenience alias (already available via config%cli_opts%control_file) + info%config%file_manager_file = trim(cli_opts%control_file) + + ! provenance: CLI options + info%config%cli_opts = cli_opts ! control file, tags, etc. + + ! runtime information + info%config%fmodel_id = trim(FMODEL_ID) + info%config%q_only = Q_ONLY + + ! user-defined simulation/evaluation time periods: strings + info%config%date_start_sim = trim(date_start_sim) + info%config%date_end_sim = trim(date_end_sim) + info%config%date_start_eval = trim(date_start_eval) + info%config%date_end_eval = trim(date_end_eval) + + ! user-defined sub-window time slice length + info%config%numtim_sub_str = trim(numtim_sub_str) + + ! user-defined SCE control parameters (used for SCE calibration runs) + info%config%maxn_str = trim(MAXN_str) + info%config%kstop_str = trim(KSTOP_str) + info%config%pcento_str = trim(PCENTO_str) + + end subroutine export_filemanager_to_domain + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + subroutine finalize_domain_config(cli_opts, info, ierr, message) + + implicit none + + type(cli_options), intent(in) :: cli_opts + type(fuse_info), intent(inout) :: info + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + character(len=256) :: dom_id, tag, run_mode + integer(i4b) :: ios + + ierr=0; message="finalize_domain_config/" + + dom_id = trim(cli_opts%domain_id) + run_mode = trim(cli_opts%runmode) + + tag = "" + if(allocated(cli_opts%tag)) tag = trim(cli_opts%tag) + + ! ---- derived input filenames ---- + info%files%forcing_file = trim(dom_id)//trim(info%files%suffix_forcing) + info%files%elevbands_file = trim(dom_id)//trim(info%files%suffix_elev_bands) + + ! ---- derived output base name ---- + info%files%fname_tempry = trim(info%files%output_path)// & + trim(dom_id)//'_'//trim(info%config%fmodel_id)//'_'//trim(tag) + + info%files%fname_netcdf_runs = trim(info%files%fname_tempry)//'_runs_'//trim(run_mode)//'.nc' + info%files%fname_netcdf_para = trim(info%files%fname_tempry)//'_para_'//trim(run_mode)//'.nc' + + ! ---- parse numeric config ---- + read(info%config%maxn_str, *, iostat=ios) info%config%maxn + if(ios/=0) then; ierr=1; message=trim(message)//"cannot parse MAXN"; return; endif + + read(info%config%kstop_str, *, iostat=ios) info%config%kstop + if(ios/=0) then; ierr=1; message=trim(message)//"cannot parse KSTOP"; return; endif + + read(info%config%pcento_str,*, iostat=ios) info%config%pcento + if(ios/=0) then; ierr=1; message=trim(message)//"cannot parse PCENTO"; return; endif + + end subroutine finalize_domain_config + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- export domain config variables to legacy modules ------------------------------ + + subroutine export_domain_to_legacy(info) + use model_defn, only: FNAME_TEMPRY, FNAME_NETCDF_RUNS, FNAME_NETCDF_PARA + use multiparam, only: MAXN, KSTOP, PCENTO + use multiforce, only: forcefile + + type(fuse_info), intent(in) :: info + + ! populate module model_defn + FNAME_TEMPRY = trim(info%files%fname_tempry) + FNAME_NETCDF_RUNS = trim(info%files%fname_netcdf_runs) + FNAME_NETCDF_PARA = trim(info%files%fname_netcdf_para) + + ! populate module multiforce + forcefile = trim(info%files%forcing_file) + + ! populate shared public variable in this module (fuse_filemanager) + MBANDS_NC = trim(info%files%elevbands_file) + + ! populate module multiparam + MAXN = info%config%maxn + KSTOP = info%config%kstop + PCENTO = info%config%pcento + + end subroutine export_domain_to_legacy + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- + + ! ----- sets directories and filenames for FUSE -------------------------------------- + + subroutine fuse_SetDirsUndPhiles(fuseMusterDirektorIn,fuseFileManagerIn,err,message) + ! Purpose: Sets direcotries and philenames for FUSE. + ! --- + ! Programmer: Dmitri Kavetski + ! History: + ! Darby St, 18/10/2009 AD - leid out basik frammenverk + ! Sonnental, 17/06/2012 AD - more general path handling + ! --- + ! Usage + ! fuseMusterDirektorIn = master direktor file (path to filemanager) + ! fuseFileManagerIn = global names/path file + ! --- + ! Comments: + ! 1. If present will try to use fuseMasterIn, otherwise default file. + ! if default not present in EXE path then uses default options + ! --- + use utilities_dmsl_kit_FUSE,only:getSpareUnit + + implicit none + + ! dummies + character(*),intent(in),optional::fuseMusterDirektorIn,fuseFileManagerIn + integer(mik),intent(out)::err + character(*),intent(out)::message + + ! registered settings + character(*),parameter::procnam="fuseSetDirsUndPhiles" + character(*),parameter::pathDelim="/\",defpathSymb="*",blank=" " + character(*),parameter::fuseMusterDirektorHeader="FUSE_MUSTERDIREKTOR_V1.0" + character(*),parameter::fuseFileManagerHeader="FUSE_FILEMANAGER_V1.5" + + ! locals + logical(mlk)::haveFMG,haveMUS + character(LEN=fusePathLen)::fuseMusterDirektor,fuseFileManager,defpath + character(LEN=100)::temp + integer(mik)::unt,i + + ! Start procedure here + err=0; message=procnam//"/ok"; defpath=blank + + haveMUS=present(fuseMusterDirektorIn); haveFMG=present(fuseFileManagerIn) + if(haveMUS)haveMUS=len_trim(fuseMusterDirektorIn)>0 + if(haveFMG)haveFMG=len_trim(fuseFileManagerIn)>0 ! check for zero-string + if(haveMUS.and.haveFMG)then + message="f-"//procnam//"/mustSpecifyEither(notBoth)& + &[fuseMusterDirektor.or.fuseFileManager]" + err=10; return + + elseif(haveFMG)then + fuseFileManager=fuseFileManagerIn + i=scan(fuseFileManager,pathDelim,back=.true.) + if(i>0)defpath=fuseFileManager(:i-1)//pathDelim(1:1) + print *, 'fuseFileManager:', TRIM(fuseFileManager) + + elseif(haveMUS)then + fuseMusterDirektor=fuseMusterDirektorIn + i=scan(fuseMusterDirektor,pathDelim,back=.true.) + if(i>0)defpath=fuseMusterDirektor(:i-1)//pathDelim(1:1) + print *, 'fuseMusterDirektor:', TRIM(fuseMusterDirektor) + + else + message="f-"//procnam//"/mustSpecifyEither& + &[fuseMusterDirektor.or.fuseFileManager]" + err=20; return + endif + + call getSpareUnit(unt,err,message) ! make sure 'unt' is actually available + + if(err/=0)then + message="f-"//procnam//"/weird/&"//message + err=100; return + endif + + ! Open muster-direktor and read it + if(.not.haveFMG)then ! grab it from the muster-direktor + + open(unt,file=fuseMusterDirektor,status="old",action="read",iostat=err) + if(err/=0)then + message="f-"//procnam//"/musterDirektorFileOpenError['"//trim(fuseMusterDirektor)//"']" + err=10; return + endif + + read(unt,*)temp + + if(temp/=fuseMusterDirektorHeader)then + message="f-"//procnam//"/unknownHeader&[file='"//trim(fuseMusterDirektor)//"']&& + &[header='"//trim(temp)//"']" + err=20; return + endif + + read(unt,*)fuseFileManager + close(unt) + + endif + + ! open file manager file + open(unt,file=fuseFileManager,status="old",action="read",iostat=err) if(err/=0)then - message="f-"//procnam//"/musterDirektorFileOpenError['"//trim(fuseMusterDirektor)//"']" + message="f-"//procnam//"/fileManagerOpenError['"//trim(fuseFileManager)//"']" err=10; return endif + read(unt,*)temp - if(temp/=fuseMusterDirektorHeader)then - message="f-"//procnam//"/unknownHeader&[file='"//trim(fuseMusterDirektor)//"']&& - &[header='"//trim(temp)//"']" + if(temp/=fuseFileManagerHeader)then + message="f-"//procnam//"/unknownHeader&[file='"//trim(fuseFileManager)//"']&& + &[header="//trim(temp)//"]" + + message='This version of FUSE requires the file manager to follow the following format: '//trim(fuseFileManagerHeader)//' not '//trim(temp) + err=20; return endif - read(unt,*)fuseFileManager + + read(unt,'(a)')temp + read(unt,*)SETNGS_PATH + read(unt,*)INPUT_PATH + read(unt,*)OUTPUT_PATH + + read(unt,'(a)')temp + read(unt,*)suffix_forcing + read(unt,*)suffix_elev_bands + + read(unt,'(a)')temp + read(unt,*)FORCINGINFO + read(unt,*)CONSTRAINTS + read(unt,*)MOD_NUMERIX + read(unt,*)M_DECISIONS + + read(unt,'(a)')temp + read(unt,*)FMODEL_ID + read(unt,*)Q_ONLY_STR + + read(unt,'(a)')temp + read(unt,*)date_start_sim + read(unt,*)date_end_sim + read(unt,*)date_start_eval + read(unt,*)date_end_eval + read(unt,*)numtim_sub_str + + read(unt,'(a)')temp + read(unt,*)METRIC + read(unt,*)TRANSFO + + read(unt,'(a)')temp + read(unt,*)MAXN_STR + read(unt,*)KSTOP_STR + read(unt,*)PCENTO_STR + close(unt) -endif -! open file manager file -open(unt,file=fuseFileManager,status="old",action="read",iostat=err) -if(err/=0)then - message="f-"//procnam//"/fileManagerOpenError['"//trim(fuseFileManager)//"']" - err=10; return -endif -read(unt,*)temp -if(temp/=fuseFileManagerHeader)then - message="f-"//procnam//"/unknownHeader&[file='"//trim(fuseFileManager)//"']&& - &[header="//trim(temp)//"]" - - message='This version of FUSE requires the file manager to follow the following format: '//trim(fuseFileManagerHeader)//' not '//trim(temp) - - err=20; return -endif -read(unt,'(a)')temp -read(unt,*)SETNGS_PATH -read(unt,*)INPUT_PATH -read(unt,*)OUTPUT_PATH -read(unt,'(a)')temp -read(unt,*)suffix_forcing -read(unt,*)suffix_elev_bands -read(unt,'(a)')temp -read(unt,*)FORCINGINFO -read(unt,*)CONSTRAINTS -read(unt,*)MOD_NUMERIX -read(unt,*)M_DECISIONS -read(unt,'(a)')temp -read(unt,*)FMODEL_ID -read(unt,*)Q_ONLY_STR -read(unt,'(a)')temp -read(unt,*)date_start_sim -read(unt,*)date_end_sim -read(unt,*)date_start_eval -read(unt,*)date_end_eval -read(unt,*)numtim_sub_str -read(unt,'(a)')temp -read(unt,*)METRIC -read(unt,*)TRANSFO -read(unt,'(a)')temp -read(unt,*)MAXN_STR -read(unt,*)KSTOP_STR -read(unt,*)PCENTO_STR -close(unt) - -! Convert Q_ONLY to logical -if(Q_ONLY_STR=='TRUE')then - Q_ONLY = .TRUE. -elseif(Q_ONLY_STR=='FALSE')then - Q_ONLY = .FALSE. -else - message="Q_ONLY must be either TRUE or FALSE" - err=20; return -endif - -PRINT*, 'Q_ONLY', Q_ONLY - -! process paths a bit -if(SETNGS_PATH(1:1)==defpathSymb)SETNGS_PATH=trim(defpath)//SETNGS_PATH(2:) -if( INPUT_PATH(1:1)==defpathSymb) INPUT_PATH=trim(defpath)//INPUT_PATH (2:) -if(OUTPUT_PATH(1:1)==defpathSymb)OUTPUT_PATH=trim(defpath)//OUTPUT_PATH(2:) - -PRINT *, 'Paths defined in file manager:' -PRINT *, 'SETNGS_PATH:', TRIM(SETNGS_PATH) -PRINT *, 'INPUT_PATH:', TRIM(INPUT_PATH) -PRINT *, 'OUTPUT_PATH:', TRIM(OUTPUT_PATH) - -PRINT *, 'Dates defined in file manager:' -PRINT *, 'date_start_sim:', TRIM(date_start_sim) -PRINT *, 'date_end_sim:', TRIM(date_end_sim) -PRINT *, 'date_start_eval:', TRIM(date_start_eval) -PRINT *, 'date_end_eval:', TRIM(date_end_eval) -PRINT *, 'numtim_sub_str:', TRIM(numtim_sub_str) - -PRINT *, 'Metrics and transformations defined in file manager:' -PRINT *, 'METRIC:', TRIM(METRIC) -PRINT *, 'TRANSFO:', TRIM(TRANSFO) - -! End procedure here -endsubroutine fuse_SetDirsUndPhiles + + ! Convert Q_ONLY to logical + if(Q_ONLY_STR=='TRUE')then + Q_ONLY = .TRUE. + elseif(Q_ONLY_STR=='FALSE')then + Q_ONLY = .FALSE. + else + message="Q_ONLY must be either TRUE or FALSE" + err=20; return + endif + + PRINT*, 'Q_ONLY', Q_ONLY + + ! process paths a bit + if(SETNGS_PATH(1:1)==defpathSymb)SETNGS_PATH=trim(defpath)//SETNGS_PATH(2:) + if( INPUT_PATH(1:1)==defpathSymb) INPUT_PATH=trim(defpath)//INPUT_PATH (2:) + if(OUTPUT_PATH(1:1)==defpathSymb)OUTPUT_PATH=trim(defpath)//OUTPUT_PATH(2:) + + PRINT *, 'Paths defined in file manager:' + PRINT *, 'SETNGS_PATH:', TRIM(SETNGS_PATH) + PRINT *, 'INPUT_PATH:', TRIM(INPUT_PATH) + PRINT *, 'OUTPUT_PATH:', TRIM(OUTPUT_PATH) + + PRINT *, 'Dates defined in file manager:' + PRINT *, 'date_start_sim:', TRIM(date_start_sim) + PRINT *, 'date_end_sim:', TRIM(date_end_sim) + PRINT *, 'date_start_eval:', TRIM(date_start_eval) + PRINT *, 'date_end_eval:', TRIM(date_end_eval) + PRINT *, 'numtim_sub_str:', TRIM(numtim_sub_str) + + ! End procedure here + endsubroutine fuse_SetDirsUndPhiles !---------------------------------------------------- END MODULE fuse_filemanager diff --git a/build/Makefile b/build/Makefile index 2dd2586..bccd07d 100755 --- a/build/Makefile +++ b/build/Makefile @@ -140,10 +140,10 @@ DRIVER_EX = fuse.exe # Define the driver program and associated subroutines FUSE_DRIVER = -#FUSE_DRIVER += setup_domain.f90 -#FUSE_DRIVER += setup_model_definition.f90 +FUSE_DRIVER += setup_domain.f90 +FUSE_DRIVER += setup_model_definition.f90 FUSE_DRIVER += fuse_evaluate.f90 functn.f90 -#FUSE_DRIVER += sce_driver.f90 +FUSE_DRIVER += sce_driver.f90 FUSE_DRIVER += fuse_driver.f90 DRIVER = $(patsubst %, $(DRIVER_DIR)/%, $(FUSE_DRIVER)) @@ -207,8 +207,8 @@ TIMUTILS = $(patsubst %, $(TIME_DIR)/%, $(FUSE_TIMEMS)) # Utility modules FUSE_UTILMS = FUSE_UTILMS += fuse_fileManager.f90 -#FUSE_UTILMS += alloc_domain.f90 -#FUSE_UTILMS += alloc_scratch.f90 +FUSE_UTILMS += alloc_domain.f90 +FUSE_UTILMS += alloc_scratch.f90 FUSE_UTILMS += metaoutput.f90 FUSE_UTILMS += metaparams.f90 FUSE_UTILMS += meta_stats.f90 @@ -282,7 +282,7 @@ SOLVER = $(patsubst %, $(SOLVER_DIR)/%, $(FUSE_SOLVER)) # FUSE preliminaries FUSE_PRELIM = -#FUSE_PRELIM += parse_command_args.f90 +FUSE_PRELIM += parse_command_args.f90 FUSE_PRELIM += ascii_util.f90 FUSE_PRELIM += uniquemodl.f90 FUSE_PRELIM += getnumerix.f90 @@ -307,7 +307,7 @@ FUSE_RUNTIME += metrics.f90 FUSE_RUNTIME += conv_funcs.f90 FUSE_RUNTIME += clrsky_rad.f90 FUSE_RUNTIME += getPETgrid.f90 -#FUSE_RUNTIME += get_time_windows.f90 +FUSE_RUNTIME += get_time_windows.f90 FUSE_RUNTIME += get_time_indices.f90 FUSE_RUNTIME += initfluxes.f90 FUSE_RUNTIME += set_all.f90 @@ -321,7 +321,7 @@ RUNTIME = $(patsubst %, $(RUNTIME_DIR)/%, $(FUSE_RUNTIME)) FUSE_NETCDF = FUSE_NETCDF += handle_err.f90 FUSE_NETCDF += extractor.f90 juldayss.f90 caldatss.f90 -#FUSE_NETCDF += domain_decomp.f90 +FUSE_NETCDF += domain_decomp.f90 FUSE_NETCDF += get_gforce.f90 FUSE_NETCDF += get_mbands.f90 FUSE_NETCDF += get_smodel.f90 diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index 766b59f..bf95afb 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-19T17:28:43Z' -character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/fuse-evaluate' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'b8f2947a48c6572ac6cd4d14a15a9adaedb1afbb' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-20T16:39:50Z' +character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/driver' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'a9bb61c58c270788e243955690f57023a418687b' From 3adde8a66ad2c4deb40cf346f69fd7438be98075 Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Sun, 22 Feb 2026 09:40:56 -0700 Subject: [PATCH 09/11] refactor driver (bit-for-bit matching) --- build/FUSE_SRC/driver/functn.f90 | 26 +- build/FUSE_SRC/driver/fuse_driver.f90 | 33 +- build/FUSE_SRC/driver/fuse_evaluate.f90 | 249 ++---- .../FUSE_SRC/driver/sce_callback_context.f90 | 33 + build/FUSE_SRC/driver/sce_driver.f90 | 28 +- build/FUSE_SRC/driver/setup_domain.f90 | 91 +-- .../driver/setup_model_definition.f90 | 16 +- build/FUSE_SRC/netcdf/def_output.f90 | 73 +- build/FUSE_SRC/netcdf/domain_decomp.f90 | 45 +- build/FUSE_SRC/netcdf/get_domain_dims.f90 | 222 ++++++ build/FUSE_SRC/netcdf/get_gforce.f90 | 712 ++++++++---------- build/FUSE_SRC/netcdf/get_mbands.f90 | 64 -- build/FUSE_SRC/netcdf/read_elevbands.f90 | 225 ++++++ build/FUSE_SRC/netcdf/time_io.f90 | 4 +- build/FUSE_SRC/physics/get_bundle.f90 | 2 +- build/FUSE_SRC/physics/q_baseflow_diff.f90 | 4 +- build/FUSE_SRC/physics/qsatexcess_diff.f90 | 12 +- build/FUSE_SRC/physics_orig/mstate_eqn.f90 | 2 +- build/FUSE_SRC/physics_orig/q_baseflow.f90 | 2 +- build/FUSE_SRC/physics_orig/qsatexcess.f90 | 2 +- build/FUSE_SRC/physics_orig/update_swe.f90 | 1 + build/FUSE_SRC/runtime/get_time_indices.f90 | 122 --- build/FUSE_SRC/runtime/get_time_windows.f90 | 35 +- build/FUSE_SRC/runtime/mean_stats.f90 | 36 +- build/FUSE_SRC/sce/sce_driver.f90 | 157 ---- build/FUSE_SRC/share/multiforce_data.f90 | 23 +- build/FUSE_SRC/types/data_types.f90 | 37 +- build/FUSE_SRC/types/info_types.f90 | 12 +- build/FUSE_SRC/types/work_types.f90 | 10 + build/FUSE_SRC/util/alloc_domain.f90 | 127 ++-- build/FUSE_SRC/util/alloc_scratch.f90 | 71 +- build/Makefile | 5 +- build/generated/fuseversion.inc | 4 +- 33 files changed, 1259 insertions(+), 1226 deletions(-) create mode 100644 build/FUSE_SRC/driver/sce_callback_context.f90 create mode 100644 build/FUSE_SRC/netcdf/get_domain_dims.f90 delete mode 100644 build/FUSE_SRC/netcdf/get_mbands.f90 create mode 100644 build/FUSE_SRC/netcdf/read_elevbands.f90 delete mode 100644 build/FUSE_SRC/runtime/get_time_indices.f90 delete mode 100644 build/FUSE_SRC/sce/sce_driver.f90 diff --git a/build/FUSE_SRC/driver/functn.f90 b/build/FUSE_SRC/driver/functn.f90 index 14be1ae..1ff846b 100644 --- a/build/FUSE_SRC/driver/functn.f90 +++ b/build/FUSE_SRC/driver/functn.f90 @@ -10,6 +10,7 @@ FUNCTION FUNCTN(NOPT,A) ! Wrapper for SCE (used to compute the objective function) ! --------------------------------------------------------------------------------------- USE nrtype ! variable types, etc. +USE sce_callback_context, only: ctx ! access FUSE data structures USE fuse_evaluate_module, only: fuse_evaluate ! run model and compute the metric chosen as objective function USE multiforce, only: ncid_forc ! NetCDF forcing file ID USE fuse_fileManager,only:METRIC, TRANSFO ! metric and transformation requested in the filemanager @@ -21,7 +22,7 @@ FUNCTION FUNCTN(NOPT,A) REAL(MSP), DIMENSION(100), INTENT(IN) :: A ! model parameter set - can be bumped up to 100 elements ! internal -REAL(SP), DIMENSION(:), ALLOCATABLE :: SCE_PAR ! sce parameter set +REAL(SP), DIMENSION(NOPT) :: SCE_PAR ! sce parameter set INTEGER(I4B) :: IERR ! error code for allocate/deallocate INTEGER(I4B) :: ERR ! error code for fuse_metric CHARACTER(LEN=256) :: MESSAGE ! error message for fuse_metric @@ -36,25 +37,18 @@ FUNCTION FUNCTN(NOPT,A) nFUSE_eval = nFUSE_eval + 1 ! get SCE parameter set -ALLOCATE(SCE_PAR(NOPT), STAT=IERR); IF (IERR.NE.0) STOP ' problem allocating space ' SCE_PAR(1:NOPT) = A(1:NOPT) ! convert from MSP used in SCE to SP used in FUSE +OUTPUT_FLAG=.FALSE. ! do not produce *runs.nc files only, param.nc files -OUTPUT_FLAG=.FALSE. ! do not produce *runs.nc files only, param.nc files - -CALL FUSE_evaluate(SCE_PAR,.FALSE.,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,1) ! 2nd argument FALSE, always return METRIC value - -! deallocate parameter set -DEALLOCATE(SCE_PAR, STAT=IERR); IF (IERR.NE.0) STOP ' problem deallocating space ' -print *, 'METRIC_VAL [Metric:',METRIC,' / Transfo:',TRANSFO,'] =', METRIC_VAL +CALL FUSE_evaluate(SCE_PAR, ctx%info, ctx%work, ctx%domain, OUTPUT_FLAG, METRIC_VAL) ! save objective function value: SCE is a minimization algorithm -IF (METRIC=="KGE" .OR. METRIC=="KGEP" .OR. METRIC=="NSE") THEN - FUNCTN = -METRIC_VAL -ELSE IF (METRIC=="MAE" .OR. METRIC=="RMSE" ) THEN - FUNCTN = METRIC_VAL -ELSE - STOP 'The requested metric is not available in metrics module' -END IF +select case(metric) + case ("KGE", "KGEP", "NSE"); FUNCTN = -METRIC_VAL + case ("MAE", "RMSE"); FUNCTN = METRIC_VAL + case default + STOP 'The requested metric is not available in metrics module' +end select ! --------------------------------------------------------------------------------------- END FUNCTION FUNCTN diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index d315804..fd52e26 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -15,6 +15,7 @@ PROGRAM DISTRIBUTED_DRIVER USE nrtype ! variable types, etc. USE info_types, only: cli_options ! command line interface options USE info_types, only: fuse_info ! info structure (includes "everything") +USE work_types, only: fuse_work ! structures that depend on nState/nPar USE data_types, only: domain_data ! domain data USE multistats, only: PCOUNT ! counter @@ -23,7 +24,7 @@ PROGRAM DISTRIBUTED_DRIVER USE globaldata, only: ncid_out USE multiparam, only: NUMPAR USE multiforce, only: NUMPSET -USE multiforce, only: ncid_forc, GRID_FLAG, SUB_PERIODS_FLAG +USE multiforce, only: SUB_PERIODS_FLAG USE multiForce, only: AFORCE, gForce, gForce_3d, aValid USE multiState, only: gState, gState_3d USE multiRoute, only: aRoute, AROUTE_3d @@ -33,6 +34,7 @@ PROGRAM DISTRIBUTED_DRIVER USE parse_command_args_MODULE, only: parse_command_args ! parse command line arguments USE setup_domain_module, only: setup_domain ! initialize the model domain USE setup_model_definition_module, only: setup_model_definition ! setup the FUSE model configuration +USE alloc_scratch_module, only: init_fuse_work ! initialze work structure ! model run: external subroutines/functions USE get_fparam_module, only: GET_PRE_PARAM, GET_SCE_PARAM ! read parameters from netcdf file @@ -60,7 +62,7 @@ PROGRAM DISTRIBUTED_DRIVER REAL(SP), DIMENSION(:), ALLOCATABLE :: APAR ! model parameter set ! function evaluation -REAL(SP) :: RMSE ! sim-obs differences +REAL(SP) :: METRIC_VAL ! sim-obs differences ! model output LOGICAL(LGT) :: OUTPUT_FLAG ! .TRUE. = write time series output @@ -68,6 +70,7 @@ PROGRAM DISTRIBUTED_DRIVER ! global domain data type(fuse_info) :: info ! includes "everything" +type(fuse_work) :: work ! structures that depend on nState/nPar type(domain_data) :: domain ! 3d/4d output buffers ! --------------------------------------------------------------------------------------- @@ -109,7 +112,13 @@ PROGRAM DISTRIBUTED_DRIVER ! ----- initialize model configurations ------------------------------------------------- ! choose model, load parameter metadata, derive parameters, and define NetCDF output files -call setup_model_definition(cli_opts, info, APAR, BL, BU, err, message) +call setup_model_definition(cli_opts, info, domain, APAR, BL, BU, err, message) +if(err/=0) stop trim(message) + +! ----- initialize work structures ------------------------------------------------------ + +! allocate space for work structures that depend on number of states and parameters +call init_fuse_work(info, work, err, message) if(err/=0) stop trim(message) ! ----- set initial counters ------------------------------------------------------------ @@ -118,14 +127,12 @@ PROGRAM DISTRIBUTED_DRIVER ONEMOD=1 ! one file per model (i.e., model dimension = 1) PCOUNT=0 ! counter for parameter sets evaluated (shared in MODULE multistats) -stop '** finished preliminaries' - ! --------------------------------------------------------------------------------------- ! ----- run different FUSE modes -------------------------------------------------------- ! --------------------------------------------------------------------------------------- ! select fuse mode -select case(cli_opts%runmode) +select case(trim(cli_opts%runmode)) ! ----- single parameter set ---------------------------------------------------------- @@ -144,14 +151,14 @@ PROGRAM DISTRIBUTED_DRIVER endif ! run FUSE - CALL FUSE_EVALUATE(APAR, GRID_FLAG, NCID_FORC, RMSE, OUTPUT_FLAG, NUMPSET) + CALL FUSE_EVALUATE(APAR, info, work, domain, OUTPUT_FLAG, METRIC_VAL) ! ----- SCE calibration run ----------------------------------------------------------- case('sce') - call sce_driver(APAR, BL, BU) + call sce_driver(info, work, domain, APAR, BL, BU) case default stop "cannot identify FUSE mode" @@ -167,15 +174,13 @@ PROGRAM DISTRIBUTED_DRIVER DEALLOCATE(aForce, aRoute, aValid, stat=err) if(err/=0)then; write(*,*) 'unable to deallocate space for catchment modeling'; stop; endif -DEALLOCATE(gForce, gState, gForce_3d, gState_3d, AROUTE_3d, stat=err) +DEALLOCATE(gForce_3d, gState_3d, AROUTE_3d, stat=err) if(err/=0)then; write(*,*) 'unable to deallocate space for grid modeling'; stop; endif ! close NetCDF files -IF(GRID_FLAG)THEN - PRINT *, 'Closing forcing file' - err = nf90_close(ncid_forc) - if(err/=0)then; message=trim(message)//' nf90_close failed: '//trim(nf90_strerror(err)); return; endif -ENDIF +PRINT *, 'Closing forcing file' +err = nf90_close(info%files%ncid_forc) +if(err/=0)then; message=trim(message)//' nf90_close failed: '//trim(nf90_strerror(err)); return; endif PRINT *, 'Closing output file' err = nf90_close(ncid_out) diff --git a/build/FUSE_SRC/driver/fuse_evaluate.f90 b/build/FUSE_SRC/driver/fuse_evaluate.f90 index e32f9f8..4faecd1 100644 --- a/build/FUSE_SRC/driver/fuse_evaluate.f90 +++ b/build/FUSE_SRC/driver/fuse_evaluate.f90 @@ -2,24 +2,15 @@ MODULE fuse_evaluate_module use nrtype use multi_flux_types, only: fluxes + use info_types, only: fuse_info use work_types, only: fuse_work + use data_types, only: domain_data IMPLICIT NONE - ! temporary type: run context - type :: run_ctx - - ! scratch state vectors - real(sp), allocatable :: state0(:), state1(:) - - ! differentiable work struct - type(fuse_work) :: fuseStruct - - end type run_ctx - CONTAINS - SUBROUTINE fuse_evaluate(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,MPARAM_FLAG) + SUBROUTINE fuse_evaluate(XPAR, info, work, domain, OUTPUT_FLAG, METRIC_VAL) ! --------------------------------------------------------------------------------------- ! Creator: @@ -50,19 +41,15 @@ SUBROUTINE fuse_evaluate(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,M IMPLICIT NONE ! input - REAL(SP),DIMENSION(:),INTENT(IN) :: XPAR ! model parameter set - LOGICAL(LGT), INTENT(IN) :: GRID_FLAG ! .TRUE. if running FUSE on a grid - INTEGER(I4B), INTENT(IN) :: NCID_FORC ! NetCDF ID for the forcing file - LOGICAL(LGT), INTENT(IN) :: OUTPUT_FLAG ! .TRUE. if desire time series output - INTEGER(I4B), INTENT(IN) :: IPSET ! index parameter set - LOGICAL(LGT), INTENT(IN), OPTIONAL :: MPARAM_FLAG ! .FALSE. (used to turn off writing statistics) + REAL(SP),DIMENSION(:) , intent(in) :: XPAR ! model parameter set + type(fuse_info) , intent(in) :: info ! info structures (runtime settings etc.) + type(fuse_work) , intent(inout) :: work ! work structures that depend on npar/nState + type(domain_data) , intent(inout) :: domain ! the fuse domain structure that stores data arrays + LOGICAL(LGT) , intent(in) :: OUTPUT_FLAG ! .TRUE. if desire time series output ! output REAL(SP),INTENT(OUT) :: METRIC_VAL ! metric - ! run context - type(run_ctx) :: ctx ! container for allocatable structures - ! error control integer(i4b) :: err, ierr character(len=1024) :: message @@ -71,23 +58,20 @@ SUBROUTINE fuse_evaluate(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,M real(sp) :: t1, t2 ! --------------------------------------------------------------------------------------- - ! allocate run-time data structures - call allocate_run(ctx, NSTATE, NUMPAR, N_BANDS, NPAR_SNOW, nspat1, nspat2, numtim_sub, ierr) - if (ierr /= 0) stop "problem allocating run context in fuse_evaluate" ! allocate 3d data structure for fluxes allocate(w_flux_3d(nspat1, nspat2, numtim_sub), stat=ierr) if (ierr /= 0) stop "problem allocating w_flux_3d in fuse_evaluate" ! populate parameter structures and initialize states - call initialize_run(ctx, XPAR, GRID_FLAG, MPARAM_FLAG, ierr, message) + call initialize_run(XPAR, work, ierr, message) if (ierr /= 0) stop trim(message) ! initialize timing CALL CPU_TIME(T1) ! run fuse for the entire time series - call run_time_loop(ctx, GRID_FLAG, NCID_FORC, OUTPUT_FLAG, err, message) + call run_time_loop(info, work, OUTPUT_FLAG, err, message) if (err /= 0) stop trim(message) ! get timing information @@ -95,7 +79,8 @@ SUBROUTINE fuse_evaluate(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,M if(isPrint) WRITE(*,*) "TIME ELAPSED = ", t2-t1 ! calculate mean summary statistics - IF(.NOT.GRID_FLAG)THEN + ! NOTE: .NOT.GRID_FLAG means catchment mode (lumped or distributed) + if( .not. info%space%grid_flag)then if(isPrint) PRINT *, 'Calculating performance metrics...' CALL MEAN_STATS() @@ -104,15 +89,11 @@ SUBROUTINE fuse_evaluate(XPAR,GRID_FLAG,NCID_FORC,METRIC_VAL,OUTPUT_FLAG,IPSET,M write(*,'(i6,1x,a6,1x,f12.6,1x,a20,1x,f12.6)') nFUSE_eval, "NSE = ", MSTATS%NASH_SUTT, "; TIME ELAPSED = ", t2-t1 !if(nFUSE_eval > 10) stop "checking results" - ENDIF + endif ! if catchment mode (lumped or distributed) if(isPrint) PRINT *, 'Writing model statistics...' CALL PUT_SSTATS(PCOUNT) - ! deallocate run context - call deallocate_run(ctx, n_bands, ierr) - if (ierr /= 0) stop "problem deallocating run context in fuse_evaluate" - ! deallocate output buffer DEALLOCATE(W_FLUX_3d); IF (IERR.NE.0) STOP ' problem deallocating W_FLUX_3d in fuse_metric ' @@ -121,90 +102,11 @@ END SUBROUTINE fuse_evaluate ! ------------------------------------------------------------------------------------------------------------------- ! ------------------------------------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------------------------------------- - ! ----- private subroutine allocate_run: allocate run-time variables ------------------------------------------------ - ! ------------------------------------------------------------------------------------------------------------------- - - subroutine allocate_run(ctx, nState, numpar, n_bands, npar_snow, nspat1, nspat2, numtim_sub, ierr) - implicit none - - type(run_ctx), intent(inout) :: ctx - integer(i4b), intent(in) :: nState, numpar, n_bands, npar_snow, nspat1, nspat2, numtim_sub - integer(i4b), intent(out) :: ierr - - integer(i4b) :: iBands - - ierr = 0 - - ! allocate state vectors - allocate(ctx%state0(nState), ctx%state1(nState), stat=ierr) - if (ierr /= 0) return - - ! allocate flux derivative vectors (inside fuseStruct) - allocate(ctx%fuseStruct%adj%df_dS(nState), ctx%fuseStruct%adj%df_dPar(numpar), ctx%fuseStruct%adj%dL_dPar(numpar), stat=ierr) - if (ierr /= 0) return - - ! allocate elevation bands - allocate(ctx%fuseStruct%snow%sbands(n_bands), stat=ierr) - if (ierr /= 0) return - - ! allocate parameter derivative for each elevation band - do iBands = 1, n_bands - - allocate(ctx%fuseStruct%snow%sbands(iBands)%var%dSWE_dParam(npar_snow), stat=ierr) - if (ierr /= 0) return - - ctx%fuseStruct%snow%sbands(iBands)%var%dSWE_dParam(:) = 0._sp - - end do - - end subroutine allocate_run - - ! ------------------------------------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------------------------------------- - - ! ------------------------------------------------------------------------------------------------------------------- - ! ----- private subroutine deallocate_run: deallocate run-time variables -------------------------------------------- - ! ------------------------------------------------------------------------------------------------------------------- - - subroutine deallocate_run(ctx, n_bands, ierr) - implicit none - - type(run_ctx), intent(inout) :: ctx - integer(i4b), intent(in) :: n_bands - integer(i4b), intent(out) :: ierr - integer(i4b) :: iBands - - ierr = 0 - - ! deallocate parameter derivative vectors - do iBands=1,n_bands - deallocate(ctx%fuseStruct%snow%sbands(iBands)%var%dSWE_dParam, stat=ierr) - if (ierr /= 0) return - end do - - ! deallocate state vectors - DEALLOCATE(ctx%STATE0,ctx%STATE1,STAT=IERR) - if (ierr /= 0) return - - ! deallocate flux derivative vectors - deallocate(ctx%fuseStruct%adj%df_dS, ctx%fuseStruct%adj%df_dPar, ctx%fuseStruct%adj%dL_dPar, stat=ierr) - if (ierr /= 0) return - - ! deallocate elevation bands - deallocate(ctx%fuseStruct%snow%sbands, stat=ierr) - if (ierr /= 0) return - - end subroutine deallocate_run - - ! ------------------------------------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------------------------------------- ! ----- private subroutine initialize_run: populate param sets and initialize states ------------------------------- ! ------------------------------------------------------------------------------------------------------------------- - subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) + subroutine initialize_run(xpar, work, err, message) use globaldata, only: isPrint, fracstate0 use model_defn, only: SMODL @@ -223,13 +125,11 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) use put_params_module, only: put_params implicit none - type(run_ctx), intent(inout) :: ctx - real(sp), dimension(:), intent(in) :: xpar - logical(lgt), intent(in) :: grid_flag - logical(lgt), intent(in), optional :: mparam_flag + real(sp), dimension(:) , intent(in) :: xpar + type(fuse_work) , intent(inout) :: work - integer(i4b), intent(out) :: err - character(len=*), intent(out) :: message + integer(i4b) , intent(out) :: err + character(len=*) , intent(out) :: message integer(i4b) :: iSpat1, iSpat2, iBands @@ -237,11 +137,7 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) message = "" ! increment parameter counter for model output - if (.not. present(mparam_flag)) then - PCOUNT = PCOUNT + 1 - else - if (mparam_flag) PCOUNT = PCOUNT + 1 - end if + PCOUNT = PCOUNT + 1 ! add parameter set to the data structure call put_parset(xpar) @@ -258,10 +154,8 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) end if ! get elevation bands (if catchment) - if (SMODL%iSNOWM == iopt_temp_index .and. .not. grid_flag) then - Z_FORCING = Z_FORCING_grid(1,1) - MBANDS(:)%info = MBANDS_INFO_3d(1,1,:) - end if + Z_FORCING = Z_FORCING_grid(1,1) + MBANDS(:)%info = MBANDS_INFO_3d(1,1,:) if (isPrint) print *, 'Writing parameter values...' call put_params(PCOUNT) @@ -270,8 +164,8 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) do iSpat2 = 1, nSpat2 do iSpat1 = 1, nSpat1 call init_state(fracstate0) - call str_2_xtry(FSTATE, ctx%state0) - call xtry_2_str(ctx%state0, FSTATE) + call str_2_xtry(FSTATE, work%num%x0) + call xtry_2_str(work%num%x0, FSTATE) gState_3d(iSpat1, iSpat2, 1) = FSTATE end do end do @@ -282,16 +176,16 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) if (SMODL%iSNOWM == iopt_temp_index) then ! initialize template once - ctx%fuseStruct%snow%sbands(:)%var%SWE = 0._sp - ctx%fuseStruct%snow%sbands(:)%var%SNOWACCMLTN = 0._sp - ctx%fuseStruct%snow%sbands(:)%var%SNOWMELT = 0._sp - ctx%fuseStruct%snow%sbands(:)%var%DSWE_DT = 0._sp + work%snow%sbands(:)%var%SWE = 0._sp + work%snow%sbands(:)%var%SNOWACCMLTN = 0._sp + work%snow%sbands(:)%var%SNOWMELT = 0._sp + work%snow%sbands(:)%var%DSWE_DT = 0._sp ! copy to every grid cell (legacy staging) do iSpat2 = 1, nSpat2 do iSpat1 = 1, nSpat1 do iBands = 1, n_bands - MBANDS_VAR_4d(iSpat1, iSpat2, iBands, 1) = ctx%fuseStruct%snow%sbands(iBands)%var%bands_var + MBANDS_VAR_4d(iSpat1, iSpat2, iBands, 1) = work%snow%sbands(iBands)%var%bands_var end do end do end do @@ -302,8 +196,6 @@ subroutine initialize_run(ctx, xpar, grid_flag, mparam_flag, err, message) ! initialize summary statistics + timer call init_stats() - print*, 'end of initialize' - end subroutine initialize_run ! ------------------------------------------------------------------------------------------------------------------- @@ -313,7 +205,7 @@ end subroutine initialize_run ! ----- private subroutine run_time_loop: run fuse for the entire time series -------------------------------------- ! ------------------------------------------------------------------------------------------------------------------- - subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) + subroutine run_time_loop(info, work, output_flag, ierr, message) use globaldata, only: isPrint use multiforce, only: nspat1, nspat2, DELTIM, sim_beg, sim_end, numtim_sub @@ -326,13 +218,12 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) implicit none - type(run_ctx), intent(inout) :: ctx - logical(lgt), intent(in) :: grid_flag - integer(i4b), intent(in) :: ncid_forc - logical(lgt), intent(in) :: output_flag + type(fuse_info) , intent(in) :: info ! info structures that include "everything" + type(fuse_work) , intent(inout) :: work ! work structures that depend on npar/nState + logical(lgt) , intent(in) :: output_flag - integer(i4b), intent(out) :: ierr - character(len=*), intent(out):: message + integer(i4b) , intent(out) :: ierr + character(len=*) , intent(out) :: message ! time management integer(i4b) :: sim_idx ! index of simulation: 1..numtim_sim @@ -349,7 +240,7 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) integer(i4b) :: iSpat1, iSpat2, iBands ierr = 0 - message = "" + message = "run_time_loop/" ! This version of FUSE enables the user to load slices of the forcing ! @@ -393,7 +284,7 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) ! load forcing for desired period into gForce_3d if(isPrint) PRINT *, 'New subperiod: loading forcing for ',chunk_len,' time steps' - CALL get_gforce_3d(chunk_start_in,chunk_len,ncid_forc,ierr,message) + call get_gforce_3d(info, chunk_start_in, chunk_len, ierr, message) IF(ierr/=0) stop 'Error while extracting 3d forcing: '//trim(message) if(isPrint) PRINT *, 'Forcing loaded. Running FUSE...' @@ -407,9 +298,9 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) ! get indices in the input file (in_idx) and the simulation period (sim_idx) in_idx = chunk_start_in + sub_idx - 1 sim_idx = chunk_start_sim + sub_idx - 1 - + ! get the model time - CALL get_modtim(in_idx,ncid_forc,ierr,message) + CALL get_modtim(info%files%ncid_forc, in_idx, ierr, message) IF(ierr/=0) stop TRIM(message) ! compute potential ET @@ -419,16 +310,20 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) ! loop through grid points and run the model for one time step DO iSpat2=1,nSpat2 DO iSpat1=1,nSpat1 - + ! run fuse for one grid cell - call advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_full, ierr, message) + call advance_one_cell(work, sub_idx, iSpat1, iSpat2, dt_sub, dt_full, ierr, message) if (ierr /= 0) stop trim(message) - + + !if(sub_idx > 100) stop "check" + END DO ! (looping thru 2nd spatial dimension) END DO ! (looping thru 1st spatial dimension) end do ! looping through subperiod + !stop "looping through time period" + ! ----------------------------------------------------------------------------------------------------------------- ! ----------------------------------------------------------------------------------------------------------------- @@ -439,7 +334,7 @@ subroutine run_time_loop(ctx, grid_flag, ncid_forc, output_flag, ierr, message) ! write model output IF (OUTPUT_FLAG) THEN if(isPrint) PRINT *, 'Write output for ',chunk_len,' time steps starting at indices', chunk_start_sim - CALL PUT_OUTPUT(ctx%fuseStruct, chunk_start_sim, chunk_start_in, chunk_len) + CALL PUT_OUTPUT(work, chunk_start_sim, chunk_start_in, chunk_len) if(isPrint) PRINT *, 'Done writing output' ELSE if(isPrint) PRINT *, 'OUTPUT_FLAG is set on FALSE, no output written' @@ -467,7 +362,7 @@ end subroutine run_time_loop ! ----- private subroutine advance_one_cell: run fuse for one grid cell --------------------------------------------- ! ------------------------------------------------------------------------------------------------------------------- - subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_full, err, message) + subroutine advance_one_cell(work, sub_idx, iSpat1, iSpat2, dt_sub, dt_full, err, message) ! switches / options use globaldata, only: NA_VALUE_SP @@ -498,19 +393,18 @@ subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_ implicit none - type(run_ctx), intent(inout) :: ctx - logical(lgt), intent(in) :: grid_flag - integer(i4b), intent(in) :: sub_idx, iSpat1, iSpat2 - real(sp), intent(inout) :: dt_sub, dt_full - integer(i4b), intent(out) :: err - character(len=*), intent(out):: message + type(fuse_work) , intent(inout) :: work ! work structures that depend on npar/nState + integer(i4b) , intent(in) :: sub_idx, iSpat1, iSpat2 + real(sp) , intent(inout) :: dt_sub, dt_full + integer(i4b) , intent(out) :: err + character(len=*) , intent(out) :: message ! locals - integer(i4b) :: ierr - character(len=1024) :: cmessage + integer(i4b) :: ierr + character(len=1024) :: cmessage err = 0 - message = "" + message = "advance_one_cell/" ierr = 0 cmessage = "" @@ -546,14 +440,14 @@ subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_ ! extract model states for this grid cell and time step FSTATE = gState_3d(iSpat1,iSpat2,sub_idx) MSTATE = FSTATE - call STR_2_XTRY(FSTATE, ctx%STATE0) + call STR_2_XTRY(FSTATE, work%num%x0) ! initialize model fluxes ! If INITFLUXES lives somewhere else in your tree, swap this line accordingly. call INITFLUXES() ! populate fuse work structure (diff path only) - if (diff_mode == differentiable) call get_bundle(ctx%fuseStruct) + if (diff_mode == differentiable) call get_bundle(work) ! ------------------------- ! snow module @@ -567,16 +461,16 @@ subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_ MBANDS(:)%var = MBANDS_VAR_4d(iSpat1,iSpat2,:,sub_idx) if (diff_mode == differentiable) then - ctx%fuseStruct%snow%z_forcing = Z_FORCING - ctx%fuseStruct%snow%sbands(:)%info = MBANDS(:)%info - ctx%fuseStruct%snow%sbands(:)%var%bands_var = MBANDS(:)%var + work%snow%z_forcing = Z_FORCING + work%snow%sbands(:)%info = MBANDS(:)%info + work%snow%sbands(:)%var%bands_var = MBANDS(:)%var end if select case(diff_mode) case(original) call UPDATE_SWE(DELTIM) case(differentiable) - call UPDATE_SWE_DIFF(ctx%fuseStruct, DELTIM) + call UPDATE_SWE_DIFF(work, DELTIM) case default err=1; message='advance_one_cell: cannot identify diff_mode (snow)'; return end select @@ -595,17 +489,18 @@ subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_ select case(diff_mode) case(original) - call ODE_INT(FUSE_SOLVE, ctx%STATE0, ctx%STATE1, dt_sub, dt_full, ierr, cmessage) + call ODE_INT(FUSE_SOLVE, work%num%x0, work%num%x1, dt_sub, dt_full, ierr, cmessage) if (ierr /= 0) then err=1; message=trim(cmessage); return end if + !print*, 'original = ', mstate%watr_1, mstate%watr_2, w_flux%QSURF, w_flux%QBASE_2 case(differentiable) - call implicit_solve(ctx%fuseStruct, ctx%state0, ctx%state1, nState, ierr, cmessage) + call implicit_solve(work, work%num%x0, work%num%x1, nState, ierr, cmessage) if (ierr /= 0) then err=1; message=trim(cmessage); return end if - W_FLUX = ctx%fuseStruct%step%flux + W_FLUX = work%step%flux case default err=1; message='advance_one_cell: cannot identify diff_mode (soil)'; return @@ -622,7 +517,7 @@ subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_ end if ! write back to 3D buffers - call XTRY_2_STR(ctx%STATE1, FSTATE) + call XTRY_2_STR(work%num%x1, FSTATE) gState_3d(iSpat1,iSpat2,sub_idx+1) = FSTATE W_FLUX_3d(iSpat1,iSpat2,sub_idx) = W_FLUX AROUTE_3d(iSpat1,iSpat2,sub_idx) = MROUTE @@ -630,9 +525,9 @@ subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_ if (SMODL%iSNOWM == iopt_temp_index) then if (diff_mode == differentiable) then - Z_FORCING = ctx%fuseStruct%snow%z_forcing - MBANDS(:)%info = ctx%fuseStruct%snow%sbands(:)%info - MBANDS(:)%var = ctx%fuseStruct%snow%sbands(:)%var%bands_var + Z_FORCING = work%snow%z_forcing + MBANDS(:)%info = work%snow%sbands(:)%info + MBANDS(:)%var = work%snow%sbands(:)%var%bands_var end if gState_3d(iSpat1,iSpat2,sub_idx+1)%SWE_TOT = sum(MBANDS(:)%var%SWE * MBANDS(:)%info%AF) @@ -641,10 +536,8 @@ subroutine advance_one_cell(ctx, grid_flag, sub_idx, iSpat1, iSpat2, dt_sub, dt_ end if ! forcing diagnostics - if (grid_flag) then - aForce(sub_idx)%ppt = sum(gForce_3d(:,:,sub_idx)%ppt) / real(size(gForce_3d(:,:,sub_idx)), kind=sp) - aForce(sub_idx)%pet = sum(gForce_3d(:,:,sub_idx)%pet) / real(size(gForce_3d(:,:,sub_idx)), kind=sp) - end if + aForce(sub_idx)%ppt = sum(gForce_3d(:,:,sub_idx)%ppt) / real(size(gForce_3d(:,:,sub_idx)), kind=sp) + aForce(sub_idx)%pet = sum(gForce_3d(:,:,sub_idx)%pet) / real(size(gForce_3d(:,:,sub_idx)), kind=sp) ! stats call COMP_STATS() diff --git a/build/FUSE_SRC/driver/sce_callback_context.f90 b/build/FUSE_SRC/driver/sce_callback_context.f90 new file mode 100644 index 0000000..1a74af6 --- /dev/null +++ b/build/FUSE_SRC/driver/sce_callback_context.f90 @@ -0,0 +1,33 @@ +module sce_callback_context + use info_types, only: fuse_info + use data_types, only: domain_data + use work_types, only: fuse_work + implicit none + private + public :: ctx + public :: set_sce_context, clear_sce_context + + type :: sce_context + type(fuse_info), pointer :: info => null() + type(fuse_work), pointer :: work => null() + type(domain_data), pointer :: domain => null() + end type sce_context + + type(sce_context), save :: ctx + +contains + + subroutine set_sce_context(info, work, domain) + type(fuse_info), target, intent(inout) :: info + type(fuse_work), target, intent(inout) :: work + type(domain_data), target, intent(inout) :: domain + ctx%info => info + ctx%work => work + ctx%domain => domain + end subroutine + + subroutine clear_sce_context() + nullify(ctx%info, ctx%work, ctx%domain) + end subroutine + +end module sce_callback_context diff --git a/build/FUSE_SRC/driver/sce_driver.f90 b/build/FUSE_SRC/driver/sce_driver.f90 index a41e0d4..27475e9 100644 --- a/build/FUSE_SRC/driver/sce_driver.f90 +++ b/build/FUSE_SRC/driver/sce_driver.f90 @@ -1,6 +1,11 @@ module sce_driver_MODULE USE nrtype + use info_types, only: fuse_info + use work_types, only: fuse_work + use data_types, only: domain_data + + use sce_callback_context, only: set_sce_context, clear_sce_context implicit none @@ -9,7 +14,7 @@ module sce_driver_MODULE contains - subroutine sce_driver(APAR, BL, BU) + subroutine sce_driver(info, work, domain, APAR, BL, BU) USE multiparam, only: MAXN ! maximum number of trials before optimization is terminated USE multiparam, only: KSTOP ! number of shuffling loops the value must change by PCENTO USE multiparam, only: PCENTO ! the percentage @@ -18,10 +23,13 @@ subroutine sce_driver(APAR, BL, BU) USE globaldata, only: nFUSE_eval ! # FUSE evaluations USE model_defn, only: FNAME_TEMPRY, FNAME_ASCII implicit none - ! input variables - real(sp), intent(in) :: APAR(:) ! model parameter set - real(sp), intent(in) :: BL(:) ! vector of lower parameter bounds - real(sp), intent(in) :: BU(:) ! vector of upper parameter bounds + ! input/output + type(fuse_info) , intent(inout) :: info ! info structures (runtime settings etc.) + type(fuse_work) , intent(inout) :: work ! work structures that depend on npar/nState + type(domain_data) , intent(inout) :: domain ! the fuse domain structure that stores data arrays + real(sp) , intent(in) :: APAR(:) ! model parameter set + real(sp) , intent(in) :: BL(:) ! vector of lower parameter bounds + real(sp) , intent(in) :: BU(:) ! vector of upper parameter bounds ! internal variables REAL(MSP) :: AF_MSP ! objective function value REAL(MSP), DIMENSION(:), ALLOCATABLE :: APAR_MSP ! ! lower bound of model parameters @@ -57,9 +65,13 @@ subroutine sce_driver(APAR, BL, BU) ALLOCATE(APAR_MSP(NUMPAR), BL_MSP(NUMPAR), BU_MSP(NUMPAR)) APAR_MSP=APAR; BL_MSP=BL; BU_MSP=BU + ! pass the FUSE structures to the context setter + ! NOTE: in sce_context_set, info/work/domain have the target attribute so can point to them + call set_sce_context(info, work, domain) + ! open up ASCII output file ISCE = 96 ! (file unit) - FNAME_ASCII = FNAME_TEMPRY//'_sce_output.txt' + FNAME_ASCII = trim(FNAME_TEMPRY)//'_sce_output.txt' print *, 'Creating SCE output file:', trim(FNAME_ASCII) OPEN(96, FILE=TRIM(FNAME_ASCII) ) @@ -78,6 +90,10 @@ subroutine sce_driver(APAR, BL, BU) ! close ASCII output file CLOSE(ISCE) + ! nullify pointers in the context setter + call clear_sce_context() + + ! deallocate space for real32 vectors DEALLOCATE(APAR_MSP, BL_MSP, BU_MSP) end subroutine sce_driver diff --git a/build/FUSE_SRC/driver/setup_domain.f90 b/build/FUSE_SRC/driver/setup_domain.f90 index 388fb53..bb3b586 100644 --- a/build/FUSE_SRC/driver/setup_domain.f90 +++ b/build/FUSE_SRC/driver/setup_domain.f90 @@ -17,30 +17,26 @@ subroutine setup_domain(opts, info, domain, ierr, message) ! access subroutines use netcdf, only: nf90_open, nf90_nowrite, nf90_strerror ! NetCDF functions - USE fuse_fileManager, only: fuse_SetDirsUndPhiles ! sets directories and filenames - USE fuse_fileManager, only: export_filemanager_to_domain ! populates domain%info structure - USE fuse_fileManager, only: finalize_domain_config ! compute additional filenames/variables - USE fuse_fileManager, only: export_domain_to_legacy ! populates legacy modules + USE fuse_fileManager, only: fuse_SetDirsUndPhiles ! sets directories and filenames + USE fuse_fileManager, only: export_filemanager_to_domain ! populates domain%info structure + USE fuse_fileManager, only: finalize_domain_config ! compute additional filenames/variables + USE fuse_fileManager, only: export_domain_to_legacy ! populates legacy modules - USE force_info_module, only: force_info ! get forcing info for NetCDF files + USE force_info_module, only: force_info ! get forcing info for NetCDF files + USE get_gforce_module, only: get_varID ! list of var ids - USE get_gforce_module, only: read_ginfo ! get dimension lengths from the NetCDF file - USE get_gforce_module, only: get_varID ! list of var ids + USE domain_dims_module, only: get_domain_dims ! get nx, ny, nt, and nbands + USE domain_decomp_module, only: get_domain_decomp_indices ! get MPI domain decomposition indices - USE get_mbands_module, only: GET_MBANDS_INFO ! get elevation bands for snow modeling - - USE domain_decomp_module, only: read_forcing_dimensions ! get forcing dimensions for MPI domain decomposition - USE domain_decomp_module, only: get_domain_decomp_indices ! get MPI domain decomposition indices - - USE time_windows_module, only: get_time_windows ! get info on the rolling time windows - USE time_windows_module, only: export_time_to_multiforce ! populate legacy multiforce modules + USE time_windows_module, only: get_time_windows ! get info on the rolling time windows + USE time_windows_module, only: export_time_to_multiforce ! populate legacy multiforce modules - USE alloc_domain_module, only: allocate_domain_data ! allocate space for data arrays in the domain structure - USE alloc_domain_module, only: set_legacy_arrays ! copy arrays in the domain%data structure to legacy arrays + USE get_gforce_module, only: read_latlon_2d ! read lat/lon + USE read_elevbands_module, only: read_elevbands ! read elevation bands + + USE alloc_domain_module, only: allocate_domain_data ! allocate space for data arrays in the domain structure + USE alloc_domain_module, only: set_legacy_arrays ! copy arrays in the domain%data structure to legacy arrays - ! shared data: TODO move into domain structure - USE multiforce, only: ncid_forc - implicit none ! input @@ -70,7 +66,7 @@ subroutine setup_domain(opts, info, domain, ierr, message) call export_filemanager_to_domain(opts, info) ! derive filenames + parse config strings - call finalize_domain_config(opts, info, ierr, message) + call finalize_domain_config(opts, info, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif ! populate legacy modules @@ -83,57 +79,68 @@ subroutine setup_domain(opts, info, domain, ierr, message) CALL GETNUMERIX(IERR,CMESSAGE) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + ! ----- read domain metadata ------------------------------------------------------------ + ! get forcing info from the txt file + ! NOTE: This will soon be replaced with the TOML file so keeping it visible for now ! -- forcing info is text that describes the forcing NetCDF files (TODO: needs improvement) call force_info(ierr,cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - if(isPrint) print *, 'Open forcing file:', trim(INPUT_PATH)//trim(forcefile) - + + ! populate domain structure with dimension lengths + ! -- nx_global, ny_global, nt_global, n_bands + call get_domain_dims(info, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + ! ----- read grid info and define indices for MPI domain decomposition ------------------ ! open NetCDF forcing file - ierr = nf90_open(trim(INPUT_PATH)//trim(forcefile), nf90_nowrite, ncid_forc) + ierr = nf90_open(trim(INPUT_PATH)//trim(forcefile), nf90_nowrite, info%files%ncid_forc) if (ierr/=0)then; message=trim(message)//' nf90_open failed: '//trim(nf90_strerror(ierr)); return; endif - if(isPrint) PRINT *, 'NCID_FORC is', ncid_forc - - ! get NetCDF ID for each variable of the forcing file - ! NOTE: populates data structures in multiforce - call get_varID(ncid_forc, ierr, cmessage) - if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - - ! populate domain structure with (x,y,t) dimension lengths - ! -- nx_global, ny_global, nt_global - call read_forcing_dimensions(ncid_forc, info, ierr, cmessage) - if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + if(isPrint) print *, 'Open forcing file:', trim(INPUT_PATH)//trim(forcefile) + if(isPrint) PRINT *, 'NCID_FORC is', info%files%ncid_forc ! get indices for MPI decomposition of the spatial domain: y_start_global, ny_local ! NOTE: These indices will be used later to read different subsets of forcing data for different ranks call get_domain_decomp_indices(info) - + ! ----- Compute time indices for sim/eval windows and subperiod chunk size -------------- - call get_time_windows(ncid_forc, info, ierr, cmessage) + call get_time_windows(info, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif ! export info%time -> multiforce to keep legacy code working call export_time_to_multiforce(info) - ! ----- Get information on elevation bands ---------------------------------------------- - - ! get elevation band info, in particular N_BANDS, from NetCDF file - CALL GET_MBANDS_INFO(info, ierr, cmessage) - if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! ----- Allocate space for domain data -------------------------------------------------- ! allocate space for the arrays in the domain%data structure call allocate_domain_data(info, domain, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + ! ----- Read lat/lon and elevation band arrays ----------------------------------------- + + ! read lat/lon and store in the domain%data%coords structure + call read_latlon_2d(info%files%ncid_forc, info, domain%coords, ierr, message) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + ! read elevation bands information and store in the domain%data structure + call read_elevbands(info, domain, ierr, message) + + ! ----- Routines that use the old structures -------------------------------------------- + ! copy arrays in the domain structure to legacy arrays call set_legacy_arrays(info, domain, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + ! get NetCDF ID for each variable of the forcing file + ! NOTE: populates data structures in multiforce + call get_varID(info%files%ncid_forc, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + + print*, 'end of setup_domain' + end associate end subroutine setup_domain diff --git a/build/FUSE_SRC/driver/setup_model_definition.f90 b/build/FUSE_SRC/driver/setup_model_definition.f90 index ee2ae27..ce47233 100644 --- a/build/FUSE_SRC/driver/setup_model_definition.f90 +++ b/build/FUSE_SRC/driver/setup_model_definition.f90 @@ -3,6 +3,7 @@ module setup_model_definition_MODULE USE nrtype USE info_types, only: fuse_info USE info_types, only: cli_options + USE data_types, only: domain_data USE multiparam_types, only: PARATT implicit none @@ -12,7 +13,7 @@ module setup_model_definition_MODULE contains - subroutine setup_model_definition(opts, info, APAR, BL, BU, err, message) + subroutine setup_model_definition(opts, info, domain, APAR, BL, BU, err, message) ! access subroutines use uniquemodl_module, only: uniquemodl ! Defines unique strings for all FUSE models @@ -39,6 +40,7 @@ subroutine setup_model_definition(opts, info, APAR, BL, BU, err, message) ! input type(cli_options) , intent(in) :: opts ! command line interface options type(fuse_info) , intent(inout) :: info ! the fuse info structure that stores "everything" + type(domain_data) , intent(in) :: domain ! the fuse domain structure that stores data arrays ! output real(sp) , intent(out) , allocatable :: aPar(:) ! parameter vector @@ -88,7 +90,7 @@ subroutine setup_model_definition(opts, info, APAR, BL, BU, err, message) ! get number of parameter sets ! will be used to define the parameter set dimension of the NetCDF files - select case(opts%runmode) + select case(trim(opts%runmode)) ! options that run with a single parameter set case('def', 'idx', 'opt'); NUMPSET = 1 @@ -97,7 +99,9 @@ subroutine setup_model_definition(opts, info, APAR, BL, BU, err, message) case('sce'); NUMPSET = int(1.2_sp * real(MAXN, sp)) ! check - err=20; message=trim(message)//'opts%runmode is unknown: '//trim(opts%runmode) + case default + message=trim(message)//'opts%runmode is unknown: '//trim(opts%runmode) + err=20; return end select @@ -116,9 +120,9 @@ subroutine setup_model_definition(opts, info, APAR, BL, BU, err, message) nSet = info%config%nSets nPar = info%config%nParam - CALL DEF_PARAMS(nSet) ! define model parameters - CALL DEF_OUTPUT(nx,ny,nb,nPar) ! define model output time series (nPar used for parameter derivatives) - CALL DEF_SSTATS() ! define summary statistics (REDEF) + CALL DEF_PARAMS(nSet) ! define model parameters + CALL DEF_OUTPUT(domain%coords,nx,ny,nb,nPar) ! define model output time series (nPar used for parameter derivatives) + CALL DEF_SSTATS() ! define summary statistics (REDEF) ! get parameter bounds and random numbers ALLOCATE(APAR(NUMPAR),BL(NUMPAR),BU(NUMPAR)) diff --git a/build/FUSE_SRC/netcdf/def_output.f90 b/build/FUSE_SRC/netcdf/def_output.f90 index b10d818..46e883a 100644 --- a/build/FUSE_SRC/netcdf/def_output.f90 +++ b/build/FUSE_SRC/netcdf/def_output.f90 @@ -1,38 +1,41 @@ MODULE DEF_OUTPUT_MODULE USE nrtype USE netcdf + use data_types, only: coord_data + use iso_fortran_env, only: real32 implicit none private public :: DEF_OUTPUT contains - SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) + SUBROUTINE DEF_OUTPUT(coords,nSpat1,nSpat2,n_bands,NUMPAR) USE metaoutput, only: VARDESCRIBE USE globaldata, only: FUSE_VERSION, FUSE_BUILDTIME, FUSE_GITBRANCH, FUSE_GITHASH USE metaoutput, only: NOUTVAR, VNAME, LNAME, VUNIT, isBand, isFlux USE model_defn, only: FNAME_NETCDF_RUNS USE fuse_fileManager, only: Q_ONLY - USE multiforce, only: latitude,longitude, timeUnits + USE multiforce, only: timeUnits USE globaldata, only: ncid_out implicit none - integer(i4b), intent(in) :: nSpat1, nSpat2, n_bands, NUMPAR + type(coord_data), intent(in) :: coords + integer(i4b), intent(in) :: nSpat1, nSpat2, n_bands, NUMPAR ! locals integer(i4b) :: ierr, ivar, varid, varid_time, varid_lat, varid_lon, varid_band, varid_param - integer(i4b) :: dim_time, dim_lon, dim_lat, dim_band, dim_par + integer(i4b) :: dim_time, dim_x, dim_y, dim_band, dim_par integer(i4b), dimension(3) :: dimids_3 integer(i4b), dimension(4) :: dimids_band integer(i4b), dimension(4) :: dimids_par logical(lgt) :: write_var - real(msp), dimension(nspat1) :: longitude_msp - real(msp), dimension(nspat2) :: latitude_msp - real(msp), parameter :: NA_VALUE_OUT = -9999._msp + real(real32), dimension(nspat1,nspat2) :: longitude + real(real32), dimension(nspat1,nspat2) :: latitude + real(real32), parameter :: NA_VALUE_OUT = -9999._real32 integer(i4b), dimension(n_bands) :: band_i integer(i4b), dimension(NUMPAR) :: param_i @@ -51,12 +54,12 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) ierr = nf90_def_dim(ncid_out, "time", NF90_UNLIMITED, dim_time); call handle_err(ierr) ierr = nf90_def_dim(ncid_out, "band", n_bands, dim_band); call handle_err(ierr) ierr = nf90_def_dim(ncid_out, "param", NUMPAR, dim_par); call handle_err(ierr) - ierr = nf90_def_dim(ncid_out, "longitude", nSpat1, dim_lon); call handle_err(ierr) - ierr = nf90_def_dim(ncid_out, "latitude", nSpat2, dim_lat); call handle_err(ierr) + ierr = nf90_def_dim(ncid_out, "x", nSpat1, dim_x); call handle_err(ierr) + ierr = nf90_def_dim(ncid_out, "y", nSpat2, dim_y); call handle_err(ierr) - dimids_3 = (/ dim_lon, dim_lat, dim_time /) - dimids_band = (/ dim_lon, dim_lat, dim_band, dim_time /) - dimids_par = (/ dim_lon, dim_lat, dim_par, dim_time /) + dimids_3 = (/ dim_y, dim_y, dim_time /) + dimids_band = (/ dim_y, dim_y, dim_band, dim_time /) + dimids_par = (/ dim_y, dim_y, dim_par, dim_time /) ! Time-varying output vars do ivar = 1, NOUTVAR @@ -89,25 +92,23 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) end do ! looping through variables - print*, 'coordinate variables' - ! Coordinate variables - ierr = nf90_def_var(ncid_out, "time", NF90_FLOAT, (/dim_time/), varid_time); call handle_err(ierr) - ierr = nf90_put_att(ncid_out, varid_time, "units", trim(timeUnits)); call handle_err(ierr) - - ierr = nf90_def_var(ncid_out, "latitude", NF90_FLOAT, (/dim_lat/), varid_lat); call handle_err(ierr) - ierr = nf90_put_att(ncid_out, varid_lat, "units", "degreesN"); call handle_err(ierr) - ierr = nf90_put_att(ncid_out, varid_lat, "axis", "Y"); call handle_err(ierr) + ierr = nf90_def_var(ncid_out, "time", NF90_FLOAT, (/dim_time/), varid_time); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_time, "units", trim(timeUnits)); call handle_err(ierr) - ierr = nf90_def_var(ncid_out, "longitude", NF90_FLOAT, (/dim_lon/), varid_lon); call handle_err(ierr) - ierr = nf90_put_att(ncid_out, varid_lon, "units", "degreesE"); call handle_err(ierr) - ierr = nf90_put_att(ncid_out, varid_lon, "axis", "X"); call handle_err(ierr) + ierr = nf90_def_var(ncid_out, "latitude", NF90_FLOAT, (/dim_x, dim_y/), varid_lat); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lat, "standard_name", "latitude"); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lat, "units", "degrees_north"); call handle_err(ierr) + + ierr = nf90_def_var(ncid_out, "longitude", NF90_FLOAT, (/dim_x, dim_y/), varid_lon); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lon, "standard_name", "longitude"); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_lon, "units", "degrees_east"); call handle_err(ierr) - ierr = nf90_def_var(ncid_out, "param", NF90_INT, (/dim_par/), varid_param); call handle_err(ierr) - ierr = nf90_put_att(ncid_out, varid_param, "units", "-"); call handle_err(ierr) + ierr = nf90_def_var(ncid_out, "param", NF90_INT, (/dim_par/), varid_param); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_param, "units", "-"); call handle_err(ierr) - ierr = nf90_def_var(ncid_out, "band", NF90_INT, (/dim_band/), varid_band); call handle_err(ierr) - ierr = nf90_put_att(ncid_out, varid_band, "units", "-"); call handle_err(ierr) + ierr = nf90_def_var(ncid_out, "band", NF90_INT, (/dim_band/), varid_band); call handle_err(ierr) + ierr = nf90_put_att(ncid_out, varid_band, "units", "-"); call handle_err(ierr) ! Global attributes ierr = nf90_put_att(ncid_out, NF90_GLOBAL, "software", "FUSE"); call handle_err(ierr) @@ -119,26 +120,16 @@ SUBROUTINE DEF_OUTPUT(nSpat1,nSpat2,n_bands,NUMPAR) ! Leave define mode ierr = nf90_enddef(ncid_out); call handle_err(ierr) - print*, 'coordinate data' - - print*, nSpat1, nSpat2 - print*, latitude - print*, longitude - ! Write coordinate data - latitude_msp = latitude - longitude_msp = longitude - - print*, 'hello1' + latitude = real(coords%lat_2d, kind(real32)) + longitude = real(coords%lon_2d, kind(real32)) - ierr = nf90_put_var(ncid_out, varid_lat, latitude_msp); call handle_err(ierr) - ierr = nf90_put_var(ncid_out, varid_lon, longitude_msp); call handle_err(ierr) + ierr = nf90_put_var(ncid_out, varid_lat, latitude); call handle_err(ierr) + ierr = nf90_put_var(ncid_out, varid_lon, longitude); call handle_err(ierr) - print*, 'hello1' band_i = [(ib, ib=1,n_bands)] param_i = [(ip, ip=1,NUMPAR)] - print*, 'hello1' ierr = nf90_put_var(ncid_out, varid_band, band_i); call handle_err(ierr) ierr = nf90_put_var(ncid_out, varid_param, param_i); call handle_err(ierr) diff --git a/build/FUSE_SRC/netcdf/domain_decomp.f90 b/build/FUSE_SRC/netcdf/domain_decomp.f90 index edaec60..503e09f 100644 --- a/build/FUSE_SRC/netcdf/domain_decomp.f90 +++ b/build/FUSE_SRC/netcdf/domain_decomp.f90 @@ -6,7 +6,6 @@ module domain_decomp_module implicit none private - public :: read_forcing_dimensions public :: get_domain_decomp_indices contains @@ -14,44 +13,6 @@ module domain_decomp_module ! ------------------------------------------------------------------------------------- ! ------------------------------------------------------------------------------------- - ! ----- read forcing dimensions (used for domain decomposition) ----------------------- - - subroutine read_forcing_dimensions(ncid, info, ierr, message) - use netcdf - USE multiforce,only:vname_aprecip ! name of precip variable - implicit none - integer(i4b), intent(in) :: ncid - type(fuse_info), intent(inout) :: info - integer(i4b), intent(out) :: ierr - character(*), intent(out) :: message - - integer(i4b) :: ivarid - integer(i4b), parameter :: ndims=3 - integer(i4b) :: dimids(ndims), dimLen - associate(nx_global => info%space%nx_global, & - ny_global => info%space%ny_global, & - nt_global => info%time%nt_global ) - - ierr=0; message="read_forcing_dimensions/" - - ! pick one required variable to identify shape (in this case precip) - ierr = nf90_inq_varid(ncid, trim(vname_aprecip), ivarid) - - ! get dimension IDs (x,y,t) - ierr = nf90_inquire_variable(ncid, ivarid, dimids=dimids) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - - ! get dimsension lengths (nx,ny,nt) - ierr = nf90_inquire_dimension(ncid, dimids(1), len=nx_global); if(ierr/=0) return - ierr = nf90_inquire_dimension(ncid, dimids(2), len=ny_global); if(ierr/=0) return - ierr = nf90_inquire_dimension(ncid, dimids(3), len=nt_global); if(ierr/=0) return - - end associate - end subroutine read_forcing_dimensions - - ! ------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------- - ! ----- get indices to decompose the spatial domain ----------------------------------- ! 1) Determine global run mode (grid vs catchment) ! 2) Apply MPI decomposition (y dimension) and store local dims + offsets @@ -61,7 +22,6 @@ subroutine get_domain_decomp_indices(info) type(fuse_info), intent(inout) :: info associate(& - grid_flag => info%space%grid_flag, & nx_global => info%space%nx_global, & ny_global => info%space%ny_global, & nx_local => info%space%nx_local, & @@ -72,16 +32,13 @@ subroutine get_domain_decomp_indices(info) nproc => info%mpi%nproc, & rank => info%mpi%rank ) - ! Set flag to toggle between grid and lumped catchment modes - grid_flag = (nx_global>1 .or. ny_global>1) - ! Copy globals nx_local = nx_global ny_local = ny_global y_start_global = 1 ! Get indices for split dimensions - if(grid_flag .and. mpi_enabled .and. nproc>1) then + if(mpi_enabled .and. nproc>1) then call split_1d(ny_global, rank, nproc, & ! input y_start_global, ny_local) ! output endif diff --git a/build/FUSE_SRC/netcdf/get_domain_dims.f90 b/build/FUSE_SRC/netcdf/get_domain_dims.f90 new file mode 100644 index 0000000..3e74333 --- /dev/null +++ b/build/FUSE_SRC/netcdf/get_domain_dims.f90 @@ -0,0 +1,222 @@ +module domain_dims_module + use nrtype + use info_types, only: fuse_info + implicit none + private + public :: get_domain_dims + +contains + + subroutine get_domain_dims(info, ierr, message) + + implicit none + + type(fuse_info), intent(inout) :: info + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + character(len=1024) :: forc_file ! forcing file + character(len=1024) :: elev_file ! elev bands file + + character(len=1024) :: cmessage + integer(i4b) :: dimLen + + ierr = 0 + message = "get_domain_metadata/" + + ! get filenames + forc_file = trim(info%files%input_path)//trim(info%files%forcing_file) + elev_file = trim(info%files%input_path)//trim(info%files%elevbands_file) + + ! read forcing dimensions + call read_forcing_dimensions(forc_file, info, ierr, cmessage) + if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + + ! read number of elevation bands + call nc_get_dimlen_from_file(elev_file, "elevation_band", dimlen, ierr, cmessage) + if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + info%snow%n_bands = dimLen + + end subroutine get_domain_dims + + + ! ----- utility routines -------------------------------------------------------------------------------------------- + + ! ----- read forcing dimensions ------------------------------------------------------------------------------------- + + subroutine read_forcing_dimensions(filepath, info, ierr, message) + + use nrtype + use netcdf + use info_types, only: fuse_info + use multiforce, only: vname_aprecip + implicit none + + character(*), intent(in) :: filepath + type(fuse_info), intent(inout) :: info + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: ncid + integer(i4b) :: varid + integer(i4b) :: ndims + integer(i4b) :: dimids(NF90_MAX_VAR_DIMS) + character(len=NF90_MAX_NAME) :: dimname + integer(i4b) :: idim,dimlen + integer(i4b) :: time_varid + + associate(grid_flag => info%space%grid_flag, & + nx_global => info%space%nx_global, & + ny_global => info%space%ny_global, & + nt_global => info%time%nt_global, & + nInput => info%config%nInput) + + ierr=0; message="read_forcing_dimensions/" + + ! --- open NetCDF file for reading (nf90_nowrite) --- + ierr = nf90_open(trim(filepath), nf90_nowrite, ncid) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_open failed: "//trim(nf90_strerror(ierr))// & + " [file="//trim(filepath)//"]" + return + endif + + ! --- get dimension lengths from precip variable shape --- + ierr = nf90_inq_varid(ncid, trim(vname_aprecip), varid) + if(ierr /= nf90_noerr) then + message = trim(message)//"cannot find var '"//trim(vname_aprecip)//"': "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_inquire_variable(ncid, varid, ndims=ndims, dimids=dimids) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire_variable failed: "//trim(nf90_strerror(ierr)) + return + endif + + ! --- get the length of the time dimension (expect it is the last dimension) --- + ierr = nf90_inquire_dimension(ncid, dimids(ndims), name=dimname, len=nt_global) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire_dimension failed: "//trim(nf90_strerror(ierr)) + return + endif + + ! --- check that the last dimension is time --- + if(trim(dimname) /= "time")then + message=trim(message)//"FUSE expects (…, time) ordering; i.e., time dimension is last" + ierr=20; return + endif + + ! --- require rank 2 or 3 and require time last (already checked earlier) --- + if (ndims /= 2 .and. ndims /= 3) then + message = trim(message)//"expected forcing var rank 2 (spat,time) or 3 (spat,spat,time)" + ierr = 20; return + endif + + ! ndims == 2: enforce (hru,time) in the feature order + ! -> the only non-time dim is the "hru"/feature dimension + if (ndims == 2) then + + ierr = nf90_inquire_dimension(ncid, dimids(1), len=ny_global) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire_dimension failed: "//trim(nf90_strerror(ierr)) + return + endif + nx_global = 1 + + ! ndims == 3: enforce (x,y,time) in the file order + ! -> can be (y,x,time) also since the spatial dimensions are general + else + + ierr = nf90_inquire_dimension(ncid, dimids(1), len=nx_global) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire_dimension failed: "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_inquire_dimension(ncid, dimids(2), len=ny_global) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire_dimension failed: "//trim(nf90_strerror(ierr)) + return + endif + + endif ! (ndims=3) + + ! define grid + ! TODO: includes point list of catchments, but logic not implemented yet + grid_flag = nx_global > 1 + + ! set the number of input variables (3 = ppt, temp, pet; 4 = + obsq) + nInput = merge(3,4,grid_flag) + + ! --- close NetCDF file --- + ierr = nf90_close(ncid) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_close failed: "//trim(nf90_strerror(ierr))// & + " [file="//trim(filepath)//"]" + return + endif + + end associate + end subroutine read_forcing_dimensions + + ! ----- get dimension length from file ------------------------------------------------------------------------------ + + + subroutine nc_get_dimlen_from_file(filepath, dimname, dimlen, ierr, message) + + use netcdf, only: nf90_open, nf90_close, nf90_nowrite, & + nf90_inq_dimid, nf90_inquire_dimension, & + nf90_strerror, nf90_noerr + implicit none + + ! inputs + character(*), intent(in) :: filepath + character(*), intent(in) :: dimname + + ! outputs + integer(i4b), intent(out) :: dimlen + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + ! locals + integer(i4b) :: ncid, dimid + + ierr = 0 + dimlen = -1 + message = "nc_get_dimlen_from_file/" + + ! open NetCDF file for reading (nf90_nowrite) + ierr = nf90_open(trim(filepath), nf90_nowrite, ncid) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_open failed: "//trim(nf90_strerror(ierr))// & + " [file="//trim(filepath)//"]" + return + endif + + ! get dimension ID + ierr = nf90_inq_dimid(ncid, trim(dimname), dimid) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_inq_dimid failed: "//trim(nf90_strerror(ierr))// & + " [dim="//trim(dimname)//"]" + return + endif + + ! get dimension length + ierr = nf90_inquire_dimension(ncid, dimid, len=dimlen) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_inquire_dimension failed: "//trim(nf90_strerror(ierr))// & + " [dim="//trim(dimname)//"]" + return + endif + + ! close + ierr = nf90_close(ncid) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_close failed: "//trim(nf90_strerror(ierr)) + return + endif + + end subroutine nc_get_dimlen_from_file + +end module domain_dims_module diff --git a/build/FUSE_SRC/netcdf/get_gforce.f90 b/build/FUSE_SRC/netcdf/get_gforce.f90 index f990a04..2f56bbb 100644 --- a/build/FUSE_SRC/netcdf/get_gforce.f90 +++ b/build/FUSE_SRC/netcdf/get_gforce.f90 @@ -1,197 +1,181 @@ module get_gforce_module -USE nrtype -USE netcdf -USE time_io + +use nrtype +use info_types, only: fuse_info + +use netcdf +use time_io + implicit none + private -public::read_ginfo -public::get_dimIds -public::get_gforce -public::get_gforce_3d + public::get_varid +public::get_gforce_3d +public::read_latlon_2d contains - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Ethan Gutmann, 2020 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Split domain to allow for MPI. Given proc and nproc, provide start and update nSpat2 - - subroutine split_dims(nSpat2, proc, nproc, start) - - implicit none - integer(i4b), intent(inout) :: nSpat2, start - integer(i4b), intent(in) :: proc, nproc - - integer(i4b) :: newn, offset, even_multiple, count - - print*, 'Number of cores to be used (nproc)', nproc - - newn = nSpat2 / nproc ! number of rows of the domain to be run by each process - print*, 'Number of rows of domain per core (newn) ', newn - - even_multiple = nproc * newn - print*, 'nproc x newn', even_multiple - - count = nSpat2 - even_multiple - print*, 'Difference to',nSpat2,':', count - - offset = 0 - if (proc < count) offset = 1 - - start = (proc * newn) + min(proc, count) + 1 - - nSpat2 = newn + offset - - print*, "PROCESS (proc, start, start+newn, newn)" - print*, proc, start, start+newn, newn - - end subroutine split_dims - - SUBROUTINE read_ginfo(ncid,ierr,message) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2012 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Read grid info (spatial and temporal dimensions) from the NetCDF file - ! --------------------------------------------------------------------------------------- - ! Modules Modified: - ! ----------------- - ! MODULE multiforce -- populate dimension lengths - ! --------------------------------------------------------------------------------------- - USE fuse_fileManager,only:SETNGS_PATH,FORCINGINFO,& ! defines data directory - INPUT_PATH - USE multiforce,only:forcefile,vname_aprecip ! model forcing structures - USE multiforce,only:nspat1,nspat2,startSpat2,numtim_in! dimension lengths - USE multiforce,only:GRID_FLAG ! .true. if distributed - USE multiforce,only:latitude,longitude ! dimension arrays - USE multiforce,only:time_steps,julian_day_input ! dimension arrays - USE multiforce,only:latUnits,lonUnits,timeUnits ! units string for time - USE multiforce,only:vname_dtime ! variable name: time sice reference time - USE multiforce, only: nForce, nInput ! number of parameter set and their names - USE multiforce, only: NA_VALUE ! NA_VALUE for the forcing - -#ifdef __MPI__ - use mpi -#endif - - IMPLICIT NONE - ! input - integer(i4b),intent(in) :: ncid ! NetCDF file ID -! output - integer(i4b), intent(out) :: ierr ! error code - character(*), intent(out) :: message ! error message - ! internal: general - integer(i4b),parameter::lenPath=1024 ! DK211008: allows longer file paths - INTEGER(I4B) :: I ! looping - CHARACTER(LEN=lenPath) :: cmessage ! message of downwind routine - ! internal: NetCDF read - integer(i4b) :: ivarid ! NetCDF variable ID - integer(i4b),parameter :: ndims=3 ! number of dimensions for precipitation - integer(i4b),dimension(ndims) :: dimids_ppt ! vector of dimension IDs for precipitation - integer(i4b) :: iDimID ! dimension ID - integer(i4b) :: dimLen ! dimension length - - - integer ( kind = 4 ) mpi_error_value - integer ( kind = 4 ) mpi_process - integer ( kind = 4 ) mpi_nprocesses - - - ! --------------------------------------------------------------------------------------- - ! Initialize MPI - ! --------------------------------------------------------------------------------------- -#ifdef __MPI__ - print *,'__MPI__ is defined, getting mpi_nprocesses and mpi_process' - call MPI_Comm_size(MPI_COMM_WORLD, mpi_nprocesses, mpi_error_value) - call MPI_Comm_rank(MPI_COMM_WORLD, mpi_process, mpi_error_value) -#else - print *,'__MPI__ is NOT defined, setting mpi_nprocesses = 1 and mpi_process = 0' - mpi_process = 0 - mpi_nprocesses = 1 -#endif - - - ! --------------------------------------------------------------------------------------- - ! initialize error control - ierr=0; message='read_ginfo/' - ! --------------------------------------------------------------------------------------- - - ! get the variable ID for precipitation - ierr = nf90_inq_varid(ncid, vname_aprecip, ivarid) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - - ! get the dimension IDs for precipitation - call get_dimIds(ncid, ivarid, ndims, dimids_ppt, ierr, cmessage) - if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif - - ! loop through dimensions - do iDimID=1,ndims - - ! get the dimension lengths - ierr = nf90_inquire_dimension(ncid,dimids_ppt(iDimID),len=dimLen) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - ! save the dimension lengths - if(iDimID==1) nspat1 = dimLen ! 1st spatial dimension - if(iDimID==2) nspat2 = dimLen ! 2nd spatial dimension - if(iDimID==3) numtim_in = dimLen ! record dimension (always last) + subroutine read_latlon_2d(ncid, info, coord, ierr, message) + + use netcdf + use nrtype + use info_types, only: fuse_info + use data_types, only: coord_data + implicit none + + integer(i4b), intent(in) :: ncid + type(fuse_info), intent(in) :: info + type(coord_data),intent(inout) :: coord + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: vid_lat, vid_lon + integer(i4b) :: nd_lat, nd_lon + integer(i4b) :: dimids_lat(NF90_MAX_VAR_DIMS), dimids_lon(NF90_MAX_VAR_DIMS) + integer(i4b) :: nx, ny, ystart + integer(i4b) :: len_lat, len_lon + integer(i4b) :: start2(2), count2(2) + real(sp), allocatable :: lon_1d(:), lat_1d(:) + + ierr = 0 + message = "read_latlon_2d/" + + nx = info%space%nx_local + ny = info%space%ny_local + ystart = info%space%y_start_global + + ! Ensure 2D storage exists + if (.not. allocated(coord%lat_2d)) allocate(coord%lat_2d(nx, ny)) + if (.not. allocated(coord%lon_2d)) allocate(coord%lon_2d(nx, ny)) + + ! --- get varids --- + ierr = nf90_inq_varid(ncid, "latitude", vid_lat) + if(ierr /= nf90_noerr) then + message = trim(message)//"missing var 'latitude': "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_inq_varid(ncid, "longitude", vid_lon) + if(ierr /= nf90_noerr) then + message = trim(message)//"missing var 'longitude': "//trim(nf90_strerror(ierr)) + return + endif - end do + ! --- ranks/dims --- + ierr = nf90_inquire_variable(ncid, vid_lat, ndims=nd_lat, dimids=dimids_lat) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire latitude failed: "//trim(nf90_strerror(ierr)) + return + endif - startSpat2 = 1 + ierr = nf90_inquire_variable(ncid, vid_lon, ndims=nd_lon, dimids=dimids_lon) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire longitude failed: "//trim(nf90_strerror(ierr)) + return + endif - ! define the spatial flag - PRINT *, ' ' - if(nSpat1.GT.1.OR.nSpat2.GT.1) THEN - PRINT *, '### FUSE set to run in grid mode' - GRID_FLAG=.TRUE. - nInput=3 ! number of variables to be retrieved from input file (P, T, PET) + !---------------------------------------------------------------------------- + ! Case A: Rectilinear OR point-list (lat 1D, lon 1D) + !---------------------------------------------------------------------------- + if (nd_lat == 1 .and. nd_lon == 1) then + + ! Read full 1D vectors (easiest because slice depends on grid shape) + ! NOTE: do MPI slice later + ierr = nf90_inquire_dimension(ncid, dimids_lat(1), len=len_lat) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire lat dim failed: "//trim(nf90_strerror(ierr)) + return + endif + ierr = nf90_inquire_dimension(ncid, dimids_lon(1), len=len_lon) + if(ierr /= nf90_noerr) then + message = trim(message)//"inquire lon dim failed: "//trim(nf90_strerror(ierr)) + return + endif + + allocate(lat_1d(len_lat)) + allocate(lon_1d(len_lon)) + + ierr = nf90_get_var(ncid, vid_lat, lat_1d) + if(ierr /= nf90_noerr) then + message = trim(message)//"get_var(latitude) failed: "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_get_var(ncid, vid_lon, lon_1d) + if(ierr /= nf90_noerr) then + message = trim(message)//"get_var(longitude) failed: "//trim(nf90_strerror(ierr)) + return + endif + + coord%is_curvilinear = .false. + coord%is_point_list = (info%space%nx_global == 1) ! our convention + + if (coord%is_point_list) then + ! Point-list/HRU: lat(hru), lon(hru) -> store as (1,ny_local) + if (nx /= 1) then + message = trim(message)//"point-list detected but nx_local /= 1" + ierr = 20; return + endif + coord%lat_2d(1,:) = lat_1d(ystart:ystart+ny-1) + coord%lon_2d(1,:) = lon_1d(ystart:ystart+ny-1) + + else + ! Rectilinear grid: lat(ny), lon(nx) -> broadcast to 2D + + ! lon_1d is global length nx_global + coord%lon_2d(:,:) = spread(lon_1d(1:nx), dim=2, ncopies=ny) + + ! lat_1d is global length ny_global; take this rank's slice then replicate across x + coord%lat_2d(:,:) = spread(lat_1d(ystart:ystart+ny-1), dim=1, ncopies=nx) + + endif + + deallocate(lat_1d, lon_1d) + + return + endif - call split_dims(nSpat2, mpi_process, mpi_nprocesses, startSpat2) - ELSE + !---------------------------------------------------------------------------- + ! Case B: Curvilinear (lat 2D, lon 2D) + !---------------------------------------------------------------------------- + if (nd_lat == 2 .and. nd_lon == 2) then - PRINT *, '### FUSE set to run in catchment mode' - GRID_FLAG=.FALSE. - nInput=4 ! number of variables to be retrieved from input file (P, T, PET, Q) + ! Read local slab in file order: (spat1,spat2) with y split along dim2 - ENDIF + start2 = (/ 1, ystart /) + count2 = (/ nx, ny /) - print*, 'spatial dimensions of the grid= ', nSpat1, 'x' ,nSpat2 - print*, 'NA_VALUE = ', NA_VALUE - print*, 'GRID_FLAG = ', GRID_FLAG + ierr = nf90_get_var(ncid, vid_lat, coord%lat_2d, start=start2, count=count2) + if(ierr /= nf90_noerr) then + message = trim(message)//"get_var(latitude 2D) failed: "//trim(nf90_strerror(ierr)) + return + endif - ! allocate arrays - allocate(longitude(nspat1),latitude(nspat2),time_steps(numtim_in),julian_day_input(numtim_in)) + ierr = nf90_get_var(ncid, vid_lon, coord%lon_2d, start=start2, count=count2) + if(ierr /= nf90_noerr) then + message = trim(message)//"get_var(longitude 2D) failed: "//trim(nf90_strerror(ierr)) + return + endif - ! get longitude - ierr = nf90_inq_varid(ncid, 'longitude', iVarID) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr))//'[variable=longitude]'; return; endif - ierr = nf90_get_var(ncid, iVarID, longitude, start=(/1/), count=(/nSpat1/)); CALL HANDLE_ERR(IERR) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif + coord%is_curvilinear = .true. + coord%is_point_list = .false. - ! get latitude - ierr = nf90_inq_varid(ncid, 'latitude', iVarID) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr))//'[variable=latitude]'; return; endif - ierr = nf90_get_var(ncid, iVarID, latitude, start=(/startSpat2/), count=(/nSpat2/)); CALL HANDLE_ERR(IERR) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif + return + endif - ! get time - ierr = nf90_inq_varid(ncid, trim(vname_dtime), iVarID) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr))//'[variable='//trim(vname_dtime)//']'; return; endif - ierr = nf90_get_var(ncid, iVarID, time_steps, start=(/1/), count=(/numtim_in/)); CALL HANDLE_ERR(IERR) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - ierr = nf90_get_att(ncid, iVarID, 'units', timeUnits) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr))//'[variable='//trim(vname_dtime)//']'; return; endif + !---------------------------------------------------------------------------- + ! Anything else is unsupported under preprocessing + layout rules + !---------------------------------------------------------------------------- + ierr = 20 + write(message,'(a,i0,a,i0,a)') trim(message)// & + "unsupported lat/lon ranks (lat_ndims=", nd_lat, ", lon_ndims=", nd_lon, & + "). If coords include time, preprocess to remove time from latitude/longitude." - end subroutine read_ginfo + end subroutine read_latlon_2d + ! -------------------------------------------------------------------------------------- + ! -------------------------------------------------------------------------------------- ! -------------------------------------------------------------------------------------- subroutine get_dimIds(ncid, varid, nexpect, varDimIDs, ierr, message) ! used to get the vector of dimension ids for a given variable @@ -218,7 +202,7 @@ subroutine get_dimIds(ncid, varid, nexpect, varDimIDs, ierr, message) if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif end subroutine get_dimIds ! -------------------------------------------------------------------------------------- - + SUBROUTINE get_varID(ncid,ierr,message) ! --------------------------------------------------------------------------------------- ! Creator: @@ -235,7 +219,7 @@ SUBROUTINE get_varID(ncid,ierr,message) ! --------------------------------------------------------------------------------------- USE multiforce, only: nForce, nInput ! number of forcing variables USE multiforce, only: ncid_var ! NetCDF forcing variable ID - + USE multiforce,only:forcefile ! name of forcing file USE multiforce,only:vname_aprecip ! variable name: precipitation USE multiforce,only:vname_airtemp ! variable name: temperature @@ -244,7 +228,7 @@ SUBROUTINE get_varID(ncid,ierr,message) USE multiforce,only:vname_swdown ! variable name: downward shortwave radiation USE multiforce,only:vname_potevap ! variable name: potential ET USE multiforce,only:vname_q ! variable indice: observed discharge - + USE multiforce,only:ilook_aprecip ! variable indice: precipitation USE multiforce,only:ilook_airtemp ! variable indice: temperature USE multiforce,only:ilook_spechum ! variable indice: specific humidity @@ -252,9 +236,9 @@ SUBROUTINE get_varID(ncid,ierr,message) USE multiforce,only:ilook_swdown ! variable indice: downward shortwave radiation USE multiforce,only:ilook_potevap ! variable indice: potential ET USE multiforce,only:ilook_q ! variable indice: observed discharge - + IMPLICIT NONE - + ! input integer(i4b), intent(in) :: ncid ! NetCDF file ID ! output @@ -267,11 +251,11 @@ SUBROUTINE get_varID(ncid,ierr,message) end type names type(names),dimension(nForce) :: cVec ! names of character strings integer(i4b) :: iVar ! loop through forcing data - + ! --------------------------------------------------------------------------------------- ! initialize error control ierr=0; message='get_varID/' - + ! get the vector of variable names cVec(ilook_aprecip)%vname = trim(vname_aprecip) ! variable name: precipitation cVec(ilook_potevap)%vname = trim(vname_potevap) ! variable name: potential ET @@ -280,244 +264,152 @@ SUBROUTINE get_varID(ncid,ierr,message) cVec(ilook_spechum)%vname = trim(vname_spechum) ! variable name: specific humidity cVec(ilook_airpres)%vname = trim(vname_airpres) ! variable name: surface pressure cVec(ilook_swdown)%vname = trim(vname_swdown) ! variable name: downward shortwave radiation - + do ivar=1,nInput - + ! get the variable ID ierr = nf90_inq_varid(ncid, trim(cVec(iVar)%vname), ncid_var(ivar)) if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr))//'[variable='//trim(cVec(iVar)%vname)//']'; return; endif - + END DO + + END SUBROUTINE get_varID + + SUBROUTINE get_gforce_3d(info, itim_start, numtim, ierr, message) + ! --------------------------------------------------------------------------------------- + ! Creator: + ! -------- + ! Nans Addor, based on Martyn Clark's get_gforce + ! --------------------------------------------------------------------------------------- + ! Purpose: + ! -------- + ! Read NetCDF gridded forcing data for a range of time steps + ! --------------------------------------------------------------------------------------- + ! Modules Modified: + ! ----------------- + ! MODULE multiforce -- populate structure GFORCE_3d(*,*)%(*) + ! --------------------------------------------------------------------------------------- + USE fuse_fileManager,only:INPUT_PATH ! defines data directory + USE multiforce,only:forcefile ! name of forcing file + USE multiforce,only:nSpat1, nSpat2, numtim_sub ! dimensions of local slice + USE multiforce,only:startSpat2 ! starting y index for data read + USE multiforce,only:vname_aprecip ! variable name: precipitation + USE multiforce,only:vname_airtemp ! variable name: temperature + USE multiforce,only:vname_spechum ! variable name: specific humidity + USE multiforce,only:vname_airpres ! variable name: surface pressure + USE multiforce,only:vname_swdown ! variable name: downward shortwave radiation + USE multiforce,only:vname_potevap ! variable name: potential ET + USE multiforce,only:vname_q ! variable name: observed discharge + + USE multiforce,only:ilook_aprecip ! variable indice: precipitation + USE multiforce,only:ilook_airtemp ! variable indice: temperature + USE multiforce,only:ilook_spechum ! variable indice: specific humidity + USE multiforce,only:ilook_airpres ! variable indice: surface pressure + USE multiforce,only:ilook_swdown ! variable indice: downward shortwave radiation + USE multiforce,only:ilook_potevap ! variable indice: potential ET + USE multiforce,only:ilook_q ! variable indice: observed discharge + + USE multiforce,only:ncid_var ! NetCDF ID for forcing variables + USE multiforce,only:amult_ppt,amult_pet ! multipliers o convert to mm/day + USE multiforce,only:gForce_3d ! gridded forcing data + USE multiforce,only:ancilF_3d ! ancillary forcing data + USE multiforce,only:nForce, nInput ! number of forcing variables + USE multiforce,only:aValid ! time series of lumped forcing/response data + + IMPLICIT NONE + ! input + type(fuse_info), intent(in) :: info ! info data structure that holds spatial indices + integer(i4b), intent(in) :: itim_start ! index of model time step - start of the period to extract + integer(i4b), intent(in) :: numtim ! number of model time steps to extract + ! output + integer(i4b), intent(out) :: ierr ! error code + character(*), intent(out) :: message ! error message + ! internal + real(sp),parameter :: amiss=-9999._sp ! value for missing data + integer(i4b),parameter :: strLen=1024 ! length of character string + integer(i4b) :: iVar ! loop through forcing data + real(sp),dimension(:,:,:),allocatable :: gTemp ! temporary 3d grid + type names + character(len=strLen) :: vname ! singlecharacter strings + end type names + type(names),dimension(nForce) :: cVec ! names of character strings + logical(lgt),dimension(nForce) :: lCheck ! check the existence of variables + + ! integer(i4b) :: nx, ny, ystart + ! integer(i4b) :: start_3d(3), count_3d(3) + ! + ! nx = info%space%nx_local + ! ny = info%space%ny_local + ! ystart = info%space%y_start_global + ! + ! start_3d = (/ 1, ystart, itim_start/) + ! count_3d = (/nx, ny, numtim/) - END SUBROUTINE get_varID - - SUBROUTINE get_gforce(itim,ncid_forc,ierr,message) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2012 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Read NetCDF gridded forcing data for a given time step - ! --------------------------------------------------------------------------------------- - ! Modules Modified: - ! ----------------- - ! MODULE multiforce -- populate structure GFORCE(*,*)%(*) - ! --------------------------------------------------------------------------------------- - USE fuse_fileManager,only:INPUT_PATH ! defines data directory - USE multiforce,only:forcefile ! name of forcing file - USE multiforce,only:vname_aprecip ! variable name: precipitation - USE multiforce,only:vname_airtemp ! variable name: temperature - USE multiforce,only:vname_spechum ! variable name: specific humidity - USE multiforce,only:vname_airpres ! variable name: surface pressure - USE multiforce,only:vname_swdown ! variable name: downward shortwave radiation - USE multiforce,only:vname_potevap ! variable name: potential ET - - USE multiforce,only:ilook_aprecip ! variable indice: precipitation - USE multiforce,only:ilook_airtemp ! variable indice: temperature - USE multiforce,only:ilook_spechum ! variable indice: specific humidity - USE multiforce,only:ilook_airpres ! variable indice: surface pressure - USE multiforce,only:ilook_swdown ! variable indice: downward shortwave radiation - USE multiforce,only:ilook_potevap ! variable indice: potential ET - - USE multiforce,only:nspat1,nspat2,startSpat2 ! dimension lengths - USE multiforce,only:ncid_var ! NetCDF ID for forcing variables - USE multiforce,only:amult_ppt,amult_pet ! multipliers o convert to mm/day - USE multiforce,only:gForce ! gridded forcing data - USE multiforce,only:ancilF ! ancillary forcing data - USE multiforce,only:nForce ! number of forcing variables - - IMPLICIT NONE - ! input - integer(i4b), intent(in) :: itim ! index of model time step - integer(i4b), intent(in) :: ncid_forc ! NetCDF ID for the forcing file - - ! output - integer(i4b), intent(out) :: ierr ! error code - character(*), intent(out) :: message ! error message - ! internal - real(sp),parameter :: amiss=-9999._sp ! value for missing data - integer(i4b),parameter :: strLen=1024 ! length of character string - integer(i4b) :: iVar ! loop through forcing data - real(sp),dimension(:,:,:),allocatable :: gTemp ! temporary grid - type names - character(len=strLen) :: vname ! singlecharacter strings - end type names - type(names),dimension(nForce) :: cVec ! names of character strings - logical(lgt),dimension(nForce) :: lCheck ! check the existence of variables - - ! --------------------------------------------------------------------------------------- - ! initialize error control - ierr=0; message='get_gforce/' - ! --------------------------------------------------------------------------------------- - - ! initialize lCheck - lCheck=.false. - - ! allocate space for the temporary grid - allocate(gTemp(nSpat1,nSpat2,1), stat=ierr) - if(ierr/=0)then; message=trim(message)//'problem allocating space for gTemp'; return; endif - - ! get the vector of variable names - cVec(ilook_aprecip)%vname = trim(vname_aprecip) ! variable name: precipitation - cVec(ilook_potevap)%vname = trim(vname_potevap) ! variable name: potential ET - cVec(ilook_airtemp)%vname = trim(vname_airtemp) ! variable name: temperature - cVec(ilook_spechum)%vname = trim(vname_spechum) ! variable name: specific humidity - cVec(ilook_airpres)%vname = trim(vname_airpres) ! variable name: surface pressure - cVec(ilook_swdown)%vname = trim(vname_swdown) ! variable name: downward shortwave radiation - - ! get forcing grids - ! do ivar=1,nForce - do ivar=1,3 + ! --------------------------------------------------------------------------------------- + ! initialize error control + ierr=0; message='get_gforce_3d/' + ! --------------------------------------------------------------------------------------- + + ! initialize lCheck + lCheck=.false. + + ! allocate space for the temporary grid + allocate(gTemp(nSpat1,nSpat2,numtim), stat=ierr) + if(ierr/=0)then; message=trim(message)//'problem allocating space for gTemp'; return; endif + + ! get the vector of variable names + cVec(ilook_aprecip)%vname = trim(vname_aprecip) ! variable name: precipitation + cVec(ilook_potevap)%vname = trim(vname_potevap) ! variable name: potential ET + cVec(ilook_airtemp)%vname = trim(vname_airtemp) ! variable name: temperature + cVec(ilook_q)%vname = trim(vname_q) ! variable name: observed discharge + cVec(ilook_spechum)%vname = trim(vname_spechum) ! variable name: specific humidity + cVec(ilook_airpres)%vname = trim(vname_airpres) ! variable name: surface pressure + cVec(ilook_swdown)%vname = trim(vname_swdown) ! variable name: downward shortwave radiation + + ! get forcing grids + do ivar=1,nInput + ! get the data - ierr = nf90_get_var(ncid_forc, ncid_var(ivar), gTemp, start=(/1,startSpat2,iTim/), count=(/nSpat1,nSpat2,1/)); CALL HANDLE_ERR(IERR) + ierr = nf90_get_var(info%files%ncid_forc, ncid_var(ivar), gTemp, start=(/1,startSpat2,itim_start/), count=(/nSpat1,nSpat2,numtim/)); CALL HANDLE_ERR(IERR) if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - ! save the data in the structure -- and convert fluxes to mm/day - if(trim(cVec(iVar)%vname) == trim(vname_aprecip) )then; gForce(:,:)%ppt = gTemp(:,:,1)*amult_ppt; lCheck(ilook_aprecip) = .true.; endif - if(trim(cVec(iVar)%vname) == trim(vname_potevap) )then; gForce(:,:)%pet = gTemp(:,:,1)*amult_pet; lCheck(ilook_potevap) = .true.; endif - if(trim(cVec(iVar)%vname) == trim(vname_airtemp) )then; gForce(:,:)%temp = gTemp(:,:,1); lCheck(ilook_airtemp) = .true.; endif - - ! save the other variables required to compute PET - !if( trim(cVec(iVar)%vname) == trim(vname_airtemp) )then; ancilF(:,:)%airtemp = gTemp(:,:,1); lCheck(ilook_airtemp) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_spechum) )then; ancilF(:,:)%spechum = gTemp(:,:,1); lCheck(ilook_spechum) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_airpres) )then; ancilF(:,:)%airpres = gTemp(:,:,1); lCheck(ilook_airpres) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_swdown) )then; ancilF(:,:)%swdown = gTemp(:,:,1); lCheck(ilook_swdown) = .true.; endif - - end do ! (loop thru forcing variables) - - PRINT *, 'gForce', gForce - - ! deallocate space for gTemp - deallocate(gTemp, stat=ierr) - if(ierr/=0)then; message=trim(message)//'problem deallocating space for gTemp'; return; endif - - end subroutine get_gforce - - SUBROUTINE get_gforce_3d(itim_start,numtim,ncid_forc,ierr,message) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Nans Addor, based on Martyn Clark's get_gforce - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Read NetCDF gridded forcing data for a range of time steps - ! --------------------------------------------------------------------------------------- - ! Modules Modified: - ! ----------------- - ! MODULE multiforce -- populate structure GFORCE_3d(*,*)%(*) - ! --------------------------------------------------------------------------------------- - USE fuse_fileManager,only:INPUT_PATH ! defines data directory - USE multiforce,only:forcefile ! name of forcing file - USE multiforce,only:vname_aprecip ! variable name: precipitation - USE multiforce,only:vname_airtemp ! variable name: temperature - USE multiforce,only:vname_spechum ! variable name: specific humidity - USE multiforce,only:vname_airpres ! variable name: surface pressure - USE multiforce,only:vname_swdown ! variable name: downward shortwave radiation - USE multiforce,only:vname_potevap ! variable name: potential ET - USE multiforce,only:vname_q ! variable name: observed discharge - - USE multiforce,only:ilook_aprecip ! variable indice: precipitation - USE multiforce,only:ilook_airtemp ! variable indice: temperature - USE multiforce,only:ilook_spechum ! variable indice: specific humidity - USE multiforce,only:ilook_airpres ! variable indice: surface pressure - USE multiforce,only:ilook_swdown ! variable indice: downward shortwave radiation - USE multiforce,only:ilook_potevap ! variable indice: potential ET - USE multiforce,only:ilook_q ! variable indice: observed discharge - - USE multiforce,only:nspat1,nspat2,startSpat2 ! dimension lengths - USE multiforce,only:ncid_var ! NetCDF ID for forcing variables - USE multiforce,only:amult_ppt,amult_pet ! multipliers o convert to mm/day - USE multiforce,only:gForce_3d ! gridded forcing data - USE multiforce,only:ancilF_3d ! ancillary forcing data - USE multiforce,only:nForce, nInput ! number of forcing variables - USE multiforce,only:aValid ! time series of lumped forcing/response data - - IMPLICIT NONE - ! input - integer(i4b), intent(in) :: itim_start ! index of model time step - start of the period to extract - integer(i4b), intent(in) :: numtim ! number of model time steps to extract - integer(i4b), intent(in) :: ncid_forc ! NetCDF ID for the forcing file - ! output - integer(i4b), intent(out) :: ierr ! error code - character(*), intent(out) :: message ! error message - ! internal - real(sp),parameter :: amiss=-9999._sp ! value for missing data - integer(i4b),parameter :: strLen=1024 ! length of character string - integer(i4b) :: iVar ! loop through forcing data - real(sp),dimension(:,:,:),allocatable :: gTemp ! temporary 3d grid - type names - character(len=strLen) :: vname ! singlecharacter strings - end type names - type(names),dimension(nForce) :: cVec ! names of character strings - logical(lgt),dimension(nForce) :: lCheck ! check the existence of variables - - ! --------------------------------------------------------------------------------------- - ! initialize error control - ierr=0; message='get_gforce_3d/' - ! --------------------------------------------------------------------------------------- - - ! initialize lCheck - lCheck=.false. - - ! allocate space for the temporary grid - allocate(gTemp(nSpat1,nSpat2,numtim), stat=ierr) - if(ierr/=0)then; message=trim(message)//'problem allocating space for gTemp'; return; endif - - ! get the vector of variable names - cVec(ilook_aprecip)%vname = trim(vname_aprecip) ! variable name: precipitation - cVec(ilook_potevap)%vname = trim(vname_potevap) ! variable name: potential ET - cVec(ilook_airtemp)%vname = trim(vname_airtemp) ! variable name: temperature - cVec(ilook_q)%vname = trim(vname_q) ! variable name: observed discharge - cVec(ilook_spechum)%vname = trim(vname_spechum) ! variable name: specific humidity - cVec(ilook_airpres)%vname = trim(vname_airpres) ! variable name: surface pressure - cVec(ilook_swdown)%vname = trim(vname_swdown) ! variable name: downward shortwave radiation - - ! get forcing grids - do ivar=1,nInput - - ! get the data - ierr = nf90_get_var(ncid_forc, ncid_var(ivar), gTemp, start=(/1,startSpat2,itim_start/), count=(/nSpat1,nSpat2,numtim/)); CALL HANDLE_ERR(IERR) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - - ! save the data in the structure -- and convert fluxes to mm/day - if(trim(cVec(iVar)%vname) == trim(vname_aprecip) )then - - gForce_3d(:,:,1:numtim)%ppt = gTemp(:,:,:)*amult_ppt; lCheck(ilook_aprecip) = .true. - - endif - - if(trim(cVec(iVar)%vname) == trim(vname_potevap) )then - gForce_3d(:,:,1:numtim)%pet = gTemp(:,:,:)*amult_pet; lCheck(ilook_potevap) = .true. - endif - - if(trim(cVec(iVar)%vname) == trim(vname_airtemp) )then - gForce_3d(:,:,1:numtim)%temp = gTemp(:,:,:); lCheck(ilook_airtemp) = .true. - endif - - if(trim(cVec(iVar)%vname) == trim(vname_q) )then - aValid(:,:,1:numtim)%obsq = gTemp(:,:,:); lCheck(ilook_q) = .true. - endif - - ! save the other variables required to compute PET - !if( trim(cVec(iVar)%vname) == trim(vname_airtemp) )then; ancilF(:,:)%airtemp = gTemp(:,:,1); lCheck(ilook_airtemp) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_spechum) )then; ancilF(:,:)%spechum = gTemp(:,:,1); lCheck(ilook_spechum) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_airpres) )then; ancilF(:,:)%airpres = gTemp(:,:,1); lCheck(ilook_airpres) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_swdown) )then; ancilF(:,:)%swdown = gTemp(:,:,1); lCheck(ilook_swdown) = .true.; endif - - end do ! (loop thru forcing variables) - - ! deallocate space for gTemp - deallocate(gTemp, stat=ierr) - if(ierr/=0)then; message=trim(message)//'problem deallocating space for gTemp'; return; endif - - !PRINT *, 'PET', gForce_3d(:,:,1:numtim)%pet - !PRINT *, 'PPT', gForce_3d(:,:,1:numtim)%ppt - !PRINT *, 'TEMP', gForce_3d(:,:,1:numtim)%temp - - end subroutine get_gforce_3d + ! save the data in the structure -- and convert fluxes to mm/day + if(trim(cVec(iVar)%vname) == trim(vname_aprecip) )then + + gForce_3d(:,:,1:numtim)%ppt = gTemp(:,:,:)*amult_ppt; lCheck(ilook_aprecip) = .true. + + endif + + if(trim(cVec(iVar)%vname) == trim(vname_potevap) )then + gForce_3d(:,:,1:numtim)%pet = gTemp(:,:,:)*amult_pet; lCheck(ilook_potevap) = .true. + endif + + if(trim(cVec(iVar)%vname) == trim(vname_airtemp) )then + gForce_3d(:,:,1:numtim)%temp = gTemp(:,:,:); lCheck(ilook_airtemp) = .true. + endif + + if(trim(cVec(iVar)%vname) == trim(vname_q) )then + aValid(:,:,1:numtim)%obsq = gTemp(:,:,:); lCheck(ilook_q) = .true. + + endif + + ! save the other variables required to compute PET + !if( trim(cVec(iVar)%vname) == trim(vname_airtemp) )then; ancilF(:,:)%airtemp = gTemp(:,:,1); lCheck(ilook_airtemp) = .true.; endif + !if( trim(cVec(iVar)%vname) == trim(vname_spechum) )then; ancilF(:,:)%spechum = gTemp(:,:,1); lCheck(ilook_spechum) = .true.; endif + !if( trim(cVec(iVar)%vname) == trim(vname_airpres) )then; ancilF(:,:)%airpres = gTemp(:,:,1); lCheck(ilook_airpres) = .true.; endif + !if( trim(cVec(iVar)%vname) == trim(vname_swdown) )then; ancilF(:,:)%swdown = gTemp(:,:,1); lCheck(ilook_swdown) = .true.; endif + + end do ! (loop thru forcing variables) + + ! deallocate space for gTemp + deallocate(gTemp, stat=ierr) + if(ierr/=0)then; message=trim(message)//'problem deallocating space for gTemp'; return; endif + + !PRINT *, 'PET', gForce_3d(:,:,1:numtim)%pet + !PRINT *, 'PPT', gForce_3d(:,:,1:numtim)%ppt + !PRINT *, 'TEMP', gForce_3d(:,:,1:numtim)%temp + + end subroutine get_gforce_3d end module get_gforce_module diff --git a/build/FUSE_SRC/netcdf/get_mbands.f90 b/build/FUSE_SRC/netcdf/get_mbands.f90 deleted file mode 100644 index c8bf012..0000000 --- a/build/FUSE_SRC/netcdf/get_mbands.f90 +++ /dev/null @@ -1,64 +0,0 @@ -module get_mbands_module - - USE nrtype - - implicit none - - private - public :: GET_MBANDS_INFO - -contains - - ! ------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------- - - ! ----- get the number of elevation bands (used for allocate statements later) -------- - - subroutine GET_MBANDS_INFO(info, ierr, message) - - use info_types, only: fuse_info - use netcdf, only: nf90_open, nf90_nowrite, nf90_close, nf90_inq_dimid, & - nf90_inquire_dimension, nf90_strerror - - implicit none - - type(fuse_info), intent(inout) :: info - integer(i4b) , intent(out) :: ierr - character(*) , intent(out) :: message - - integer(i4b) :: ncid_eb, dimid_eb, dimLen - character(len=1024) :: cfile - - ierr=0; message="GET_MBANDS_INFO/" - - cfile = trim(info%files%input_path)//trim(info%files%elevbands_file) - - ierr = nf90_open(cfile, nf90_nowrite, ncid_eb) - if(ierr/=0) then - message=trim(message)//"nf90_open failed: "//trim(nf90_strerror(ierr)) - return - endif - - ierr = nf90_inq_dimid(ncid_eb, "elevation_band", dimid_eb) - if(ierr/=0) then - message=trim(message)//"nf90_inq_dimid failed: "//trim(nf90_strerror(ierr)) - return - endif - - ierr = nf90_inquire_dimension(ncid_eb, dimid_eb, len=dimLen) - if(ierr/=0) then - message=trim(message)//"nf90_inquire_dimension failed: "//trim(nf90_strerror(ierr)) - return - endif - - ierr = nf90_close(ncid_eb) - if(ierr/=0) then - message=trim(message)//"nf90_close failed: "//trim(nf90_strerror(ierr)) - return - endif - - info%snow%n_bands = dimLen - - end subroutine GET_MBANDS_INFO - -end module get_mbands_module diff --git a/build/FUSE_SRC/netcdf/read_elevbands.f90 b/build/FUSE_SRC/netcdf/read_elevbands.f90 new file mode 100644 index 0000000..2a6b79b --- /dev/null +++ b/build/FUSE_SRC/netcdf/read_elevbands.f90 @@ -0,0 +1,225 @@ +module read_elevbands_module + !! + !! Read elevation-band information (area fraction + mean elevation) from an elevation-band NetCDF file, + !! supporting either: + !! - rank-3 variables: (spat1, spat2, band) [grid] + !! - rank-2 variables: (spat2, band) [list/HRU], mapped internally to (nx=1, ny=spat2, band) + !! + !! This module reads into REAL arrays (af, zmid) so you can then copy into your derived type + !! MBANDS_INFO_3d(:,:,:)%AF / %Z_MID without baking that type into the reader. + !! + use nrtype + use netcdf + use info_types, only: fuse_info + use info_types, only: space_info + use data_types, only: domain_data + implicit none + private + + public :: read_elevbands + +contains + + subroutine read_elevbands(info, domain, ierr, message) + + use globaldata, only: NA_VALUE_SP + + implicit none + + type(fuse_info) , intent(in) :: info ! domain info + type(domain_data) , intent(inout) :: domain ! domain data + + integer(i4b) , intent(out) :: ierr + character(*) , intent(out) :: message + + character(len=1024) :: eb_file ! elev bands file + + integer(i4b) :: ncid_eb + integer(i4b) :: vid_af, vid_me + integer(i4b) :: nd_af, nd_me + integer(i4b) :: i, j, ib + real(sp) :: afsum + real(sp) :: af(info%space%nx_local, info%space%ny_local, info%snow%n_bands) + real(sp) :: zmid(info%space%nx_local, info%space%ny_local, info%snow%n_bands) + character(len=1024) :: cmessage + + ierr = 0 + message = "read_elevbands_arrays/" + + ! ---- get name of file that holds elevation bands ---- + eb_file = trim(info%files%input_path)//trim(info%files%elevbands_file) + + ! --- open NetCDF file for reading (nf90_nowrite) --- + ierr = nf90_open(trim(eb_file), nf90_nowrite, ncid_eb) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_open failed: "//trim(nf90_strerror(ierr))// & + " [file="//trim(eb_file)//"]" + return + endif + + ! ---- lookup varids ---- + ierr = nf90_inq_varid(ncid_eb, "area_frac", vid_af) + if (ierr /= nf90_noerr) then + message = trim(message)//"nf90_inq_varid(area_frac) failed: "//trim(nf90_strerror(ierr)) + return + end if + + ierr = nf90_inq_varid(ncid_eb, "mean_elev", vid_me) + if (ierr /= nf90_noerr) then + message = trim(message)//"nf90_inq_varid(mean_elev) failed: "//trim(nf90_strerror(ierr)) + return + end if + + ! ---- inquire ranks (we support 2D or 3D) ---- + ierr = nf90_inquire_variable(ncid_eb, vid_af, ndims=nd_af) + if (ierr /= nf90_noerr) then + message = trim(message)//"inquire_variable(area_frac) failed: "//trim(nf90_strerror(ierr)) + return + end if + + ierr = nf90_inquire_variable(ncid_eb, vid_me, ndims=nd_me) + if (ierr /= nf90_noerr) then + message = trim(message)//"inquire_variable(mean_elev) failed: "//trim(nf90_strerror(ierr)) + return + end if + + if (nd_af /= nd_me) then + message = trim(message)//"area_frac and mean_elev have different rank; unsupported." + ierr=20; return + end if + if (nd_af /= 2 .and. nd_af /= 3) then + message = trim(message)//"expected rank-2 (spat2,band) or rank-3 (spat1,spat2,band)" + ierr=20; return + end if + + ! ---- read into canonical arrays ---- + + !! Reads either: + !! rank-3 (spat1,spat2,band) into out3d(nx,ny,band) + !! rank-2 (spat2,band) into out3d(1,ny,band) [requires nx_local==1] + + call read_elev_vars_to_canonical(ncid_eb, vid_af, vid_me, nd_af, info%space, info%snow%n_bands, & + af, zmid, ierr, cmessage) + if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif + + ! ---- compute weighted mean elevation + mask + AF sanity check ---- + do j = 1, info%space%ny_local + do i = 1, info%space%nx_local + + domain%z_forcing(i,j) = sum(zmid(i,j,:) * af(i,j,:)) + + ! if mean elevation first band is NA_VALUE, mask this grid cell + domain%elev_mask(i,j) = zmid(i,j,1) == NA_VALUE_SP ! TODO check comparison against real + if(.NOT.domain%elev_mask(i,j)) THEN ! only check area fraction sum to 1 if not NA_VALUE + + do ib=1,info%snow%n_bands + domain%bands_info(i,j,ib)%num = ib + domain%bands_info(i,j,ib)%af = af(i,j,ib) + domain%bands_info(i,j,ib)%z_mid = zmid(i,j,ib) + end do + + afsum = sum(af(i,j,:)) + if (abs(afsum - 1.0_sp) > 1.0e-2_sp) then + write(message,'(a,2(i0,1x),a,f10.6)') trim(message)// & + "AF sum != 1 at (i,j)= ", i, j, " sum=", afsum + ierr=20; return + end if + + endif ! if masked + + end do + end do + + ! --- close NetCDF file --- + ierr = nf90_close(ncid_eb) + if(ierr /= nf90_noerr) then + message = trim(message)//"nf90_close failed: "//trim(nf90_strerror(ierr))// & + " [file="//trim(eb_file)//"]" + return + endif + + end subroutine read_elevbands + + + ! ------------------------------------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + ! ----- private subroutine read_elev_vars_to_canonical (read elevation-band variables) ------------------------------ + + subroutine read_elev_vars_to_canonical(ncid, vid_af, vid_me, ndims, space, n_bands, af, zmid, ierr, message) + + !---------------------------------------------------------------------------------------- + ! Read elevation-band variables (area_frac, mean_elev) from the elevation-band NetCDF + ! file and map them into the model’s canonical (nx_local, ny_local, n_bands) layout. + ! Supports both grid layout (spat1,spat2,band) and list layout (spat2,band → nx=1). + ! Computes weighted mean forcing elevation for the local subdomain. + !---------------------------------------------------------------------------------------- + + implicit none + + integer(i4b), intent(in) :: ncid, vid_af, vid_me, ndims + type(space_info), intent(in) :: space + integer(i4b), intent(in) :: n_bands + + real(sp), intent(out) :: af(space%nx_local, space%ny_local, n_bands) + real(sp), intent(out) :: zmid(space%nx_local, space%ny_local, n_bands) + + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: start3(3), count3(3) + integer(i4b) :: start2(2), count2(2) + real(sp) :: tmp2_af(space%ny_local, n_bands) + real(sp) :: tmp2_me(space%ny_local, n_bands) + + ierr = 0 + message = "read_elev_vars_to_canonical/" + + if (ndims == 3) then + + start3 = (/ 1, space%y_start_global, 1 /) + count3 = (/ space%nx_local, space%ny_local, n_bands /) + + ierr = nf90_get_var(ncid, vid_af, af, start=start3, count=count3) + if (ierr /= nf90_noerr) then + message = trim(message)//"nf90_get_var(area_frac) failed: "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_get_var(ncid, vid_me, zmid, start=start3, count=count3) + if (ierr /= nf90_noerr) then + message = trim(message)//"nf90_get_var(mean_elev) failed: "//trim(nf90_strerror(ierr)) + return + endif + + else + + ! rank-2 list case + if (space%nx_local /= 1) then + message = trim(message)//"rank-2 elevband file requires nx_local=1" + ierr = 20; return + endif + + start2 = (/ space%y_start_global, 1 /) + count2 = (/ space%ny_local, n_bands /) + + ierr = nf90_get_var(ncid, vid_af, tmp2_af, start=start2, count=count2) + if (ierr /= nf90_noerr) then + message = trim(message)//"nf90_get_var(area_frac list) failed: "//trim(nf90_strerror(ierr)) + return + endif + + ierr = nf90_get_var(ncid, vid_me, tmp2_me, start=start2, count=count2) + if (ierr /= nf90_noerr) then + message = trim(message)//"nf90_get_var(mean_elev list) failed: "//trim(nf90_strerror(ierr)) + return + endif + + af(1,:,:) = tmp2_af + zmid(1,:,:) = tmp2_me + + endif + + end subroutine + +end module read_elevbands_module diff --git a/build/FUSE_SRC/netcdf/time_io.f90 b/build/FUSE_SRC/netcdf/time_io.f90 index 9345aac..ced37c0 100644 --- a/build/FUSE_SRC/netcdf/time_io.f90 +++ b/build/FUSE_SRC/netcdf/time_io.f90 @@ -8,7 +8,7 @@ module time_io contains - SUBROUTINE get_modtim(itim,ncid,ierr,message) + SUBROUTINE get_modtim(ncid, itim, ierr, message) ! --------------------------------------------------------------------------------------- ! Creator: ! -------- @@ -31,8 +31,8 @@ SUBROUTINE get_modtim(itim,ncid,ierr,message) IMPLICIT NONE ! input - integer(i4b), intent(in) :: itim ! index of model time step integer(i4b), intent(in) :: ncid ! NetCDF file ID + integer(i4b), intent(in) :: itim ! index of model time step ! output integer(i4b), intent(out) :: ierr ! error code character(*), intent(out) :: message ! error message diff --git a/build/FUSE_SRC/physics/get_bundle.f90 b/build/FUSE_SRC/physics/get_bundle.f90 index 5afa9cf..f0e90ce 100644 --- a/build/FUSE_SRC/physics/get_bundle.f90 +++ b/build/FUSE_SRC/physics/get_bundle.f90 @@ -14,7 +14,7 @@ subroutine get_bundle(fuseStruct) use multistate, only: mState use multi_flux, only: m_flux use multiparam, only: parMeta,mParam,dParam - + implicit none type(fuse_work), intent(inout) :: fuseStruct integer(i4b) :: iState diff --git a/build/FUSE_SRC/physics/q_baseflow_diff.f90 b/build/FUSE_SRC/physics/q_baseflow_diff.f90 index 5bc7c7e..5fca4be 100644 --- a/build/FUSE_SRC/physics/q_baseflow_diff.f90 +++ b/build/FUSE_SRC/physics/q_baseflow_diff.f90 @@ -38,8 +38,8 @@ SUBROUTINE Q_BASEFLOW_DIFF(fuseStruct, want_dflux) TSTATE => fuseStruct%step%state1 , & ! trial state variables (end of step) M_FLUX => fuseStruct%step%flux , & ! fluxes dfx_dS => fuseStruct%adj%df_dS , & ! deriv in fluxes w.r.t. states - MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters - DPARAM => fuseStruct%par%param_derive & ! derived model parameters + MPARAM => fuseStruct%par%param_adjust , & ! adjustable model parameters + DPARAM => fuseStruct%par%param_derive & ! derived model parameters ) ! (associate) ! check the need to compute flux derivatives diff --git a/build/FUSE_SRC/physics/qsatexcess_diff.f90 b/build/FUSE_SRC/physics/qsatexcess_diff.f90 index b575c31..3b8d699 100644 --- a/build/FUSE_SRC/physics/qsatexcess_diff.f90 +++ b/build/FUSE_SRC/physics/qsatexcess_diff.f90 @@ -46,6 +46,9 @@ SUBROUTINE QSATEXCESS_DIFF(fuseStruct, want_dflux) logical(lgt) :: comp_dflux ! flag to compute flux derivatives integer(i4b) :: iState ! state index real(sp), parameter :: ms=1.e-4_sp ! smoothing in smax function + + real(sp) :: w, wmax, b + ! ------------------------------------------------------------------------------------------------- ! associate variables with elements of data structure associate(& @@ -69,8 +72,11 @@ SUBROUTINE QSATEXCESS_DIFF(fuseStruct, want_dflux) CASE(iopt_arno_x_vic) ! define variables - associate(w=>TSTATE%WATR_1, wmax=>MPARAM%MAXWATR_1, b=>MPARAM%AXV_BEXP) - + !associate(w=>TSTATE%WATR_1, wmax=>MPARAM%MAXWATR_1, b=>MPARAM%AXV_BEXP) + w = TSTATE%WATR_1 + wmax = MPARAM%MAXWATR_1 + b = MPARAM%AXV_BEXP + ! ----- compute flux ---------------------------------------------------------------------------- u = 1._sp - w/wmax xp = smax(u, 0._sp, ms) ! smooth version of max(u,0) @@ -98,7 +104,7 @@ SUBROUTINE QSATEXCESS_DIFF(fuseStruct, want_dflux) endif ! if want derivatives - end associate + !end associate ! ------------------------------------------------------------------------------------------------ ! ----- PRMS variant (fraction of upper tension storage) ----------------------------------------- diff --git a/build/FUSE_SRC/physics_orig/mstate_eqn.f90 b/build/FUSE_SRC/physics_orig/mstate_eqn.f90 index 45b371f..9733770 100644 --- a/build/FUSE_SRC/physics_orig/mstate_eqn.f90 +++ b/build/FUSE_SRC/physics_orig/mstate_eqn.f90 @@ -56,7 +56,7 @@ SUBROUTINE MSTATE_EQN() CASE(iopt_unlimfrc_2,iopt_unlimpow_2,iopt_topmdexp_2,iopt_fixedsiz_2) ! single state ! (NOTE: M_FLUX%OFLOW_2=0 for 'unlimfrc_2','unlimpow_2','topmdexp_2') DY_DT%WATR_2 = M_FLUX%QPERC_12 - M_FLUX%EVAP_2 - M_FLUX%QBASE_2 - M_FLUX%OFLOW_2 - !print *, 'in mstate_eqn, layer2 ', M_FLUX%EVAP_2, M_FLUX%QBASE_2, M_FLUX%OFLOW_2 + !print *, 'in mstate_eqn, layer2 ', DY_DT%WATR_2, M_FLUX%EVAP_2, M_FLUX%QBASE_2, M_FLUX%OFLOW_2 CASE DEFAULT print *, "SMODL%iARCH2 must be iopt_tens2pll_2, iopt_unlimfrc_2, iopt_unlimpow_2" print *, " iopt_topmdexp_2, or iopt_fixedsiz_2" diff --git a/build/FUSE_SRC/physics_orig/q_baseflow.f90 b/build/FUSE_SRC/physics_orig/q_baseflow.f90 index d13da29..2f74d70 100644 --- a/build/FUSE_SRC/physics_orig/q_baseflow.f90 +++ b/build/FUSE_SRC/physics_orig/q_baseflow.f90 @@ -34,7 +34,7 @@ SUBROUTINE Q_BASEFLOW() ! -------------------------------------------------------------------------------------- CASE(iopt_unlimpow_2) ! baseflow resvr of unlimited size (0-HUGE), power recession M_FLUX%QBASE_2 = DPARAM%QBSAT * (TSTATE%WATR_2/MPARAM%MAXWATR_2)**MPARAM%QB_POWR - ! -------------------------------------------------------------------------------------- + ! -------------------------------------------------------------------------------------- CASE(iopt_topmdexp_2) ! topmodel exponential reservoir (-HUGE to HUGE) M_FLUX%QBASE_2 = DPARAM%QBSAT * EXP( -(1. - TSTATE%WATR_2/MPARAM%MAXWATR_2) ) ! -------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/physics_orig/qsatexcess.f90 b/build/FUSE_SRC/physics_orig/qsatexcess.f90 index 68eb47c..00ffea2 100644 --- a/build/FUSE_SRC/physics_orig/qsatexcess.f90 +++ b/build/FUSE_SRC/physics_orig/qsatexcess.f90 @@ -33,7 +33,7 @@ SUBROUTINE QSATEXCESS() ! saturated area method SELECT CASE(SMODL%iQSURF) CASE(iopt_arno_x_vic) ! ARNO/Xzang/VIC parameterization (upper zone control) - M_FLUX%SATAREA = 1._sp - ( 1._sp - MIN(TSTATE%WATR_1/MPARAM%MAXWATR_1, 1._sp) )**MPARAM%AXV_BEXP + M_FLUX%SATAREA = 1._sp - ( 1._sp - MIN(TSTATE%WATR_1/MPARAM%MAXWATR_1, 1._sp) )**MPARAM%AXV_BEXP CASE(iopt_prms_varnt) ! PRMS variant (fraction of upper tension storage) M_FLUX%SATAREA = MIN(TSTATE%TENS_1/DPARAM%MAXTENS_1, 1._sp) * MPARAM%SAREAMAX CASE(iopt_tmdl_param) ! TOPMODEL parameterization (only valid for TOPMODEL qb) diff --git a/build/FUSE_SRC/physics_orig/update_swe.f90 b/build/FUSE_SRC/physics_orig/update_swe.f90 index 90e8751..be5d69d 100644 --- a/build/FUSE_SRC/physics_orig/update_swe.f90 +++ b/build/FUSE_SRC/physics_orig/update_swe.f90 @@ -128,4 +128,5 @@ SUBROUTINE UPDATE_SWE(DT) end associate END DO ! looping through bands + END SUBROUTINE UPDATE_SWE diff --git a/build/FUSE_SRC/runtime/get_time_indices.f90 b/build/FUSE_SRC/runtime/get_time_indices.f90 deleted file mode 100644 index 82c5fbe..0000000 --- a/build/FUSE_SRC/runtime/get_time_indices.f90 +++ /dev/null @@ -1,122 +0,0 @@ -MODULE GET_TIME_INDICES_MODULE - - USE nrtype - use time_io - implicit none - - contains - SUBROUTINE GET_TIME_INDICES - - ! EXTRACT DATES AND DETERMINE ASSOCIATED INDICES - - ! convert start and end date of the NetCDF input file to julian day (Julian day is the continuous - ! count of days since the beginning of the Julian Period around 4700 BC) - - USE multiforce, ONLY: timeUnits,time_steps,julian_day_input ! time data - USE multiforce, only: numtim_in ! length of input time series - USE multiforce, only: numtim_sim ! length of simulated time series - USE multiforce, only: numtim_sub ! length of subperiod time series - USE multiforce, only: istart ! timestep indices (istart=sim_beg) - USE multiforce, only: sim_beg,sim_end ! timestep indices - USE multiforce, only: eval_beg,eval_end ! timestep indices - USE multiforce, only: SUB_PERIODS_FLAG ! .true. if subperiods are used to run FUSE - - USE fuse_fileManager,only:date_start_sim,date_end_sim,& - date_start_eval,date_end_eval,& - numtim_sub_str - - real(sp) :: jdate_ref_netcdf - INTEGER(I4B) :: ERR ! error code - CHARACTER(LEN=1024) :: MESSAGE ! error message - - ! local variables - integer(i4b) :: iy,im,id,ih,imin ! to temporarily store year, month, day, hour, min - real(sp) :: isec ! to temporarily store sec - real(sp) :: jdate ! to temporarily store a julian date - real(sp) :: jdate_start_sim ! date start simulation - real(sp) :: jdate_end_sim ! date end simulation - real(sp) :: jdate_start_eval ! date start evaluation period - real(sp) :: jdate_end_eval ! date end evaluation period - - ! --------------------------------------------------------------------------------------- - ! process time data from foring file - call date_extractor(trim(timeUnits),iy,im,id,ih) ! break down reference date of NetCDF file - call juldayss(iy,im,id,ih, & ! convert it to julian day - jdate_ref_netcdf,err,message) - - julian_day_input=jdate_ref_netcdf+time_steps ! julian day of each time step of the input file - - call caldatss(julian_day_input(1),iy,im,id,ih,imin,isec) - print *, 'Start date input file=',iy,im,id - - call caldatss(julian_day_input(numtim_in),iy,im,id,ih,imin,isec) - print *, 'End date input file= ',iy,im,id - - ! convert dates for simulation into julian day - call date_extractor(trim(date_start_sim),iy,im,id,ih) ! break down date - call juldayss(iy,im,id,ih,jdate_start_sim,err,message) ! convert it to julian day - if(jdate_start_sim.lt.minval(julian_day_input))then ! check forcing available - call caldatss(jdate_start_sim,iy,im,id,ih,imin,isec) - print *, 'Error: hydrologic simulation cannot start on ',iy,im,id,' because atmospheric forcing starts later (see above)';stop; - endif - sim_beg= minloc(abs(julian_day_input-jdate_start_sim),1) ! find correponding index - call caldatss(julian_day_input(sim_beg),iy,im,id,ih,imin,isec) - print *, 'Date start sim= ',iy,im,id - - call date_extractor(trim(date_end_sim),iy,im,id,ih) ! break down date - call juldayss(iy,im,id,ih,jdate_end_sim,err,message) ! convert it to julian day - if(jdate_end_sim.gt.maxval(julian_day_input))then ! check forcing available - call caldatss(jdate_end_sim,iy,im,id,ih,imin,isec) - print *, 'Error: hydrologic simulation cannot end on ',iy,im,id,' because atmospheric forcing ends earlier (see above)';stop; - endif - sim_end= minloc(abs(julian_day_input-jdate_end_sim),1) ! find correponding index - call caldatss(julian_day_input(sim_end),iy,im,id,ih,imin,isec) - print *, 'Date end sim= ',iy,im,id - - call date_extractor(trim(date_start_eval),iy,im,id,ih) ! break down date - call juldayss(iy,im,id,ih,jdate_start_eval,err,message) ! convert it to julian day - eval_beg= minloc(abs(julian_day_input-jdate_start_eval),1) ! find correponding index - call caldatss(julian_day_input(eval_beg),iy,im,id,ih,imin,isec) - print *, 'Date start eval= ',iy,im,id - - call date_extractor(trim(date_end_eval),iy,im,id,ih) ! break down date - call juldayss(iy,im,id,ih,jdate_end_eval,err,message) ! convert it to julian day - eval_end= minloc(abs(julian_day_input-jdate_end_eval),1) ! find correponding index - call caldatss(julian_day_input(eval_end),iy,im,id,ih,imin,isec) - print *, 'Date end eval= ',iy,im,id - - ! check start before end - if(jdate_start_sim.gt.jdate_end_sim)then; print *, 'Error: date_start_sim > date_end_sim '; stop; endif - if(jdate_start_eval.gt.jdate_end_eval)then; print *, 'Error: date_start_eval > date_end_eval '; stop; endif - - ! check input data available for desired runs - if(jdate_start_sim.lt.julian_day_input(1))then; print *, 'Error: date_start_sim is before the start if the input data'; stop; endif - if(jdate_end_sim.gt.julian_day_input(numtim_in))then; print *, 'Error: the date_stop_sim is after the end of the input data'; stop; endif - - ! check input data available for desired runs - if(jdate_start_eval.lt.jdate_start_sim)then; print *, 'Error: date_start_eval < date_start_sim'; stop; endif - if(jdate_end_eval.gt.jdate_end_sim)then; print *, 'Error: date_end_eval > date_end_sim'; stop; endif - - ! determine length of simulations - numtim_sim=sim_end-sim_beg+1 - istart=sim_beg - - ! determine length of subperiods - read(numtim_sub_str,*,iostat=err) numtim_sub ! convert string to integer - - if(numtim_sub.eq.-9999)then - - print *, 'numtim_sub = -9999, FUSE will be run in 1 chunk of ',numtim_sim, 'time steps' - SUB_PERIODS_FLAG=.FALSE. - - numtim_sub=numtim_sim ! no subperiods, run the whole time series - - else - - print *, 'FUSE will be run in chunks of ',numtim_sub, 'time steps' - SUB_PERIODS_FLAG=.TRUE. - - end if - - END SUBROUTINE GET_TIME_INDICES -END MODULE diff --git a/build/FUSE_SRC/runtime/get_time_windows.f90 b/build/FUSE_SRC/runtime/get_time_windows.f90 index 6381c15..84e0d46 100644 --- a/build/FUSE_SRC/runtime/get_time_windows.f90 +++ b/build/FUSE_SRC/runtime/get_time_windows.f90 @@ -14,24 +14,22 @@ module time_windows_module contains - subroutine get_time_windows(ncid, info, ierr, message) + subroutine get_time_windows(info, ierr, message) - integer(i4b), intent(in) :: ncid type(fuse_info), intent(inout) :: info integer(i4b), intent(out) :: ierr character(*), intent(out) :: message integer(i4b) :: nt - real(sp), allocatable :: time_steps(:) character(len=1024) :: units_local integer(i4b) :: ios character(len=1024) :: cmessage - + ierr=0; message="get_time_windows/" ! ----- read forcing time axis ------------------------------------------------------ - call read_time_axis(ncid, time_steps, units_local, nt, ierr, cmessage) + call read_time_axis(info%files%ncid_forc, info%time%time_steps, units_local, nt, ierr, cmessage) if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif info%time%nt_global = nt @@ -39,7 +37,7 @@ subroutine get_time_windows(ncid, info, ierr, message) ! ----- build julian-day axis ------------------------------------------------------- - call build_julian_axis(time_steps, trim(units_local), info%time%jdate_ref, info%time%jdate, ierr, cmessage) + call build_julian_axis(info%time%time_steps, trim(units_local), info%time%jdate_ref, info%time%jdate, ierr, cmessage) if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif ! ----- compute indices for sim/eval windows ---------------------------------------- @@ -80,19 +78,6 @@ subroutine get_time_windows(ncid, info, ierr, message) ! keep nt_window as user-chosen chunk size endif - ! ----- validate time-window configuration (subperiods allowed only in grid mode) --- - if( (.not. info%space%grid_flag) .and. info%time%use_subperiods ) then - ierr = 1 - message = trim(message)// & - "catchment mode requires running the full time series in one chunk; " // & - "set numtim_sub = -9999 in the filemanager." - return - endif - - ! ----- finalize -------------------------------------------------------------------- - - if(allocated(time_steps)) deallocate(time_steps) - end subroutine get_time_windows ! ------------------------------------------------------------------------------------- @@ -104,15 +89,19 @@ end subroutine get_time_windows ! - Legacy routines still read multiforce globals (sim_beg, sim_end, numtim_sub, ...). subroutine export_time_to_multiforce(info) + use multiforce, only: time_steps, timeUnits use multiforce, only: sim_beg, sim_end, eval_beg, eval_end, numtim_sim, numtim_sub, & SUB_PERIODS_FLAG, istart implicit none type(fuse_info), intent(in) :: info - sim_beg = info%time%sim_beg - sim_end = info%time%sim_end - eval_beg = info%time%eval_beg - eval_end = info%time%eval_end + time_steps = info%time%time_steps + timeUnits = info%time%units + + sim_beg = info%time%sim_beg + sim_end = info%time%sim_end + eval_beg = info%time%eval_beg + eval_end = info%time%eval_end numtim_sim = info%time%nt_sim numtim_sub = info%time%nt_window diff --git a/build/FUSE_SRC/runtime/mean_stats.f90 b/build/FUSE_SRC/runtime/mean_stats.f90 index e80b641..f8b26f8 100644 --- a/build/FUSE_SRC/runtime/mean_stats.f90 +++ b/build/FUSE_SRC/runtime/mean_stats.f90 @@ -17,6 +17,7 @@ SUBROUTINE MEAN_STATS() USE nrtype ! variable types, etc. USE metrics ! available metrics and transformations USE fuse_fileManager,only:METRIC, TRANSFO ! metric and transformation requested in the filemanager +USE globaldata, only: isPrint ! FUSE modules USE multiforce ! model forcing data (obs streamflow) USE multiroute ! routed runoff @@ -54,7 +55,6 @@ SUBROUTINE MEAN_STATS() ! --------------------------------------------------------------------------------------- ! define sample size NS = eval_end-eval_beg+1 -PRINT *, 'Number of time steps in evaluation period (EP) = ', NS ! allocate space for observed and simulated runoff ALLOCATE(QOBS(NS),QOBS_MASK(NS),QSIM(NS),STAT=IERR) @@ -67,9 +67,12 @@ SUBROUTINE MEAN_STATS() ! check for missing QOBS values QOBS_MASK = QOBS.ne.REAL(NA_VALUE, KIND(SP)) ! find the time steps for which QOBS is available -NUM_AVAIL = COUNT(QOBS_MASK) ! number of time steps for which QOBS is available +NUM_AVAIL = COUNT(QOBS_MASK) ! number of time steps for which QOBS is available -PRINT *, 'Number of time steps with observed streamflow in EP = ', NUM_AVAIL +if(isPrint)then + PRINT *, 'Number of time steps in evaluation period (EP) = ', NS + PRINT *, 'Number of time steps with observed streamflow in EP = ', NUM_AVAIL +endif IF (NUM_AVAIL.EQ.0) THEN @@ -85,13 +88,12 @@ SUBROUTINE MEAN_STATS() ALLOCATE(QOBS_AVAIL(NUM_AVAIL),QSIM_AVAIL(NUM_AVAIL),DOBS(NUM_AVAIL),DSIM(NUM_AVAIL),RAWD(NUM_AVAIL),LOGD(NUM_AVAIL),STAT=IERR) IF (IERR /= 0) STOP ' PROBLEM ALLOCATING SPACE FOR AVAILABLE DATA IN MEAN_STATS.F90 ' - QOBS_AVAIL=PACK(QOBS,QOBS_MASK,QOBS_AVAIL) ! moves QOBS time steps indicated by QOBS_MASK to QOBS_AVAIL, - ! if no values is missing (i.e. NS = NUM_AVAIL) then QOBS_AVAIL - ! should be a copy of QOBS + ! if no values is missing (i.e. NS = NUM_AVAIL) then QOBS_AVAIL + ! should be a copy of QOBS QSIM_AVAIL=PACK(QSIM,QOBS_MASK,QSIM_AVAIL) ! moves QSIM time steps indicated by QOBS_MASK to QSIM_AVAIL - ! if no values is missing (i.e. NS = NUM_AVAIL) then QSIM_AVAIL - ! should be a copy of QSIM + ! if no values is missing (i.e. NS = NUM_AVAIL) then QSIM_AVAIL + ! should be a copy of QSIM ! compute mean XB_OBS = SUM(QOBS_AVAIL(:)) / INT(NUM_AVAIL, KIND(SP)) @@ -149,7 +151,7 @@ SUBROUTINE MEAN_STATS() MSTATS%MAE = get_MAE(QOBS_AVAIL, QSIM_AVAIL, '1') ! No transformation ! Compute the metric chosen as objective function using the metrics module - + IF (METRIC == "KGE") THEN MSTATS%METRIC_VAL = get_KGE(QOBS_AVAIL, QSIM_AVAIL, TRANSFO) ELSE IF (METRIC == "KGEP") THEN @@ -169,13 +171,15 @@ SUBROUTINE MEAN_STATS() END IF -PRINT *, 'NSE = ', MSTATS%NASH_SUTT -PRINT *, 'KGE = ', MSTATS%KGE -PRINT *, 'KGEP = ', MSTATS%KGEP -PRINT *, 'MAE = ', MSTATS%MAE -PRINT *, 'RAW_RMSE = ', MSTATS%RAW_RMSE -PRINT *, 'LOG_RMSE = ', MSTATS%LOG_RMSE -PRINT *, 'METRIC_VAL [Metric:',METRIC,' / Transfo:',TRANSFO,'] =', MSTATS%METRIC_VAL +if(isPrint)then + PRINT *, 'NSE = ', MSTATS%NASH_SUTT + PRINT *, 'KGE = ', MSTATS%KGE + PRINT *, 'KGEP = ', MSTATS%KGEP + PRINT *, 'MAE = ', MSTATS%MAE + PRINT *, 'RAW_RMSE = ', MSTATS%RAW_RMSE + PRINT *, 'LOG_RMSE = ', MSTATS%LOG_RMSE + PRINT *, 'METRIC_VAL [Metric:',METRIC,' / Transfo:',TRANSFO,'] =', MSTATS%METRIC_VAL +endif ! --------------------------------------------------------------------------------------- ! (3§) COMPUTE STATISTICS ON NUMERICAL ACCURACY AND EFFICIENCY diff --git a/build/FUSE_SRC/sce/sce_driver.f90 b/build/FUSE_SRC/sce/sce_driver.f90 deleted file mode 100644 index 1c11e82..0000000 --- a/build/FUSE_SRC/sce/sce_driver.f90 +++ /dev/null @@ -1,157 +0,0 @@ -PROGRAM sce_driver -! --------------------------------------------------------------------------------------- -! Creator: -! Martyn Clark, 2008 -! --------------------------------------------------------------------------------------- -! Purpose: -! Driver program for SCE -! --------------------------------------------------------------------------------------- -USE nrtype ! variable types, etc. -!USE ddirectory ! directory for data files - commented because couldn't be found -USE fuse_fileManager,only:fuse_SetDirsUndPhiles,& ! use fuse_fileManager instead - sets directories and filenames - OUTPUT_PATH,FORCINGINFO -! data modules -USE model_defn ! model definition structures -USE multiparam, ONLY: PARATT, LPARAM, NUMPAR ! parameter metadata structures -USE multistats ! model statistics structures -USE model_numerix ! model numerix structures -! informational modules -USE selectmodl_module ! reads model control file -USE getpar_str_module ! extracts parameter metadata -IMPLICIT NONE -! command-line arguments -CHARACTER(LEN=6) :: FMODEL_ID=' ' ! integer defining FUSE model -CHARACTER(LEN=6) :: NSOLUTION=' ' ! numerical solution (0=implicit, 1=explicit) -CHARACTER(LEN=6) :: FADAPTIVE=' ' ! identifier for adaptive sub-steps (0=fixed, 1=adaptive) -CHARACTER(LEN=6) :: TRUNC_ABS=' ' ! absolute temporal truncation error tolerance -CHARACTER(LEN=6) :: TRUNC_REL=' ' ! relative temporal truncation error tolerance -! forcing data -INTEGER(I4B) :: INFERN_START ! start of inference period -INTEGER(I4B) :: NTIM ! number of time steps -! model setup -INTEGER(I4B) :: FUSE_ID ! integer definining FUSE model -INTEGER(I4B) :: I,J,K ! looping -INTEGER(I4B) :: NMOD ! number of models -INTEGER(I4B) :: ERR ! error code -CHARACTER(LEN=256) :: MESSAGE ! error message -TYPE(PARATT) :: PARAM_META ! parameter metadata -! define output files -INTEGER(I4B) :: ONEMOD ! index for defining output file (one file per model) -! SCE variables -REAL(MSP), DIMENSION(16) :: A ! parameter set -REAL(MSP) :: AF ! objective function value -REAL(MSP), DIMENSION(16) :: BL ! lower bound of model parameters -REAL(MSP), DIMENSION(16) :: BU ! upper bound of model parameters -INTEGER(I4B) :: NOPT ! number of parameters to be optimized -INTEGER(I4B) :: MAXN ! maximum number of trials before optimization is terminated -INTEGER(I4B) :: KSTOP ! number of shuffling loops the value must change by PCENTO -REAL(MSP) :: PCENTO ! the percentage -INTEGER(I4B) :: ISEED ! starting seed for the random sequence -CHARACTER(LEN=3) :: CSEED ! starting seed converted to a character -INTEGER(I4B) :: NGS ! # complexes in the initial population -INTEGER(I4B) :: NPG ! # points in each complex -INTEGER(I4B) :: NPS ! # points in a sub-complex -INTEGER(I4B) :: NSPL ! # evolution steps allowed for each complex before shuffling -INTEGER(I4B) :: MINGS ! minimum number of complexes required -INTEGER(I4B) :: INIFLG ! 1 = include initial point in the population -INTEGER(I4B) :: IPRINT ! 0 = supress printing -INTEGER(I4B) :: ISCE ! unit number for SCE write -REAL(MSP) :: FUNCTN ! function name for the model run -! --------------------------------------------------------------------------------------- -! (1) GET COMMAND-LINE ARGUMENTS... -! --------------------------------------------------------------------------------------- -! read command-line arguments -CALL GETARG(1,FMODEL_ID) ! integer defining FUSE model -CALL GETARG(2,NSOLUTION) ! numerical solution (0=explicit, 1=implicit) -CALL GETARG(3,FADAPTIVE) ! identifier for adaptive sub-steps (0=fixed, 1=adaptive) -CALL GETARG(4,TRUNC_ABS) ! absolute temporal truncation error tolerance -CALL GETARG(5,TRUNC_REL) ! relative temporal truncation error tolerance -! check command-line arguments -IF (LEN_TRIM(FMODEL_ID).EQ.0) STOP '1st command-line argument is missing (FMODEL_ID)' -IF (LEN_TRIM(NSOLUTION).EQ.0) STOP '2nd command-line argument is missing (NSOLUTION)' -IF (LEN_TRIM(FADAPTIVE).EQ.0) STOP '3rd command-line argument is missing (FADAPTIVE)' -IF (LEN_TRIM(TRUNC_ABS).EQ.0) STOP '4th command-line argument is missing (TRUNC_ABS)' -IF (LEN_TRIM(TRUNC_REL).EQ.0) STOP '5th command-line argument is missing (TRUNC_REL)' -! read model numerix parameters -CALL GETNUMERIX() ! defines method/parameters used for numerical solution -! process command-line arguments -READ(FMODEL_ID,*) FUSE_ID ! integer definining FUSE model -READ(NSOLUTION,*) SOLUTION_METHOD ! numerical solution (0=implicit, 1=explicit) -READ(FADAPTIVE,*) TEMPORAL_ERROR_CONTROL ! identifier for adaptive sub-steps (0=fixed, 1=adaptive) -READ(TRUNC_ABS,*) ERR_TRUNC_ABS ! absolute temporal truncation error tolerance -READ(TRUNC_REL,*) ERR_TRUNC_REL ! relative temporal truncation error tolerance -! --------------------------------------------------------------------------------------- -! (2) GET MODEL SETUP -- MODEL DEFINITION, AND PARAMETER AND VARIABLE INFO FOR ALL MODELS -! --------------------------------------------------------------------------------------- -! Read data from the "BATEA-compliant" ASCII files -CALL GETFORCING(INFERN_START,NTIM) -! Define model attributes (valid for all models) -CALL UNIQUEMODL(NMOD) ! get nmod unique models -CALL GETPARMETA() ! parameter meta data (parameter bounds, etc.) -! Identify a single model -CALL SELECTMODL(FUSE_ID,ISTATUS=ERR,MESSAGE=MESSAGE) -IF (ERR.NE.0) THEN - PRINT *, TRIM(MESSAGE); STOP -ENDIF -! Define list of states and parameters for the current model -CALL ASSIGN_STT() ! state definitions are stored in module model_defn -CALL ASSIGN_FLX() ! flux definitions are stored in module model_defn -CALL ASSIGN_PAR() ! parameter defintions are stored in module multiparam -! Get parameter bounds and a default parameter set -IF (NUMPAR.GT.16) STOP ' NUMBER OF PARAMETERS MUST NOT EXCEED 16 IN SCE ' -DO I=1,NUMPAR - CALL GETPAR_STR(TRIM(LPARAM(I)%PARNAME),PARAM_META) - BL(I) = PARAM_META%PARLOW - BU(I) = PARAM_META%PARUPP - A(I) = PARAM_META%PARDEF -END DO -! -------------------------------------------------------------------------------------- -! -------------------------------------------------------------------------------------- -! -------------------------------------------------------------------------------------- -! loop through different starting seeds -DO ISEED=10,100,10 - ! get the seed as a character string - WRITE(CSEED,'(i3.3)') ISEED - ! -------------------------------------------------------------------------------------- - ! (3) DEFINE NETCDF OUTPUT FILES - ! -------------------------------------------------------------------------------------- - ! Define output file names - FNAME_NETCDF = TRIM(OUTPUT_PATH)//TRIM(SMODL%MNAME)//'__'//& - TRIM(NSOLUTION)//'-'//TRIM(FADAPTIVE)//'_SCE_'//CSEED//'.nc' ! shared in MODULE model_defn - FNAME_ASCII = TRIM(OUTPUT_PATH)//TRIM(SMODL%MNAME)//'__'//& - TRIM(NSOLUTION)//'-'//TRIM(FADAPTIVE)//'_SCE_'//CSEED//'.dat' ! shared in MODULE model_defn - ! Define NetCDF output files (only write parameters and summary statistics) - ONEMOD=1 ! one file per model (i.e., model dimension = 1) - PCOUNT=0 ! counter for parameter sets evaluated (shared in MODULE multistats) - CALL DEF_PARAMS(ONEMOD) ! define model parameters (initial CREATE) - !CALL DEF_OUTPUT(NTIM) ! define model output (REDEF) - CALL DEF_SSTATS() ! define summary statistics (REDEF) - ! -------------------------------------------------------------------------------------- - ! (4) SCE WRAPPER - ! -------------------------------------------------------------------------------------- - ! assign algorithmic control parameters for SCE - NOPT = NUMPAR ! number of parameters to be optimized (NUMPAR in module multiparam) - MAXN = 1000 ! maximum number of trials before optimization is terminated - KSTOP = 9 ! number of shuffling loops the value must change by PCENTO (MAX=9) - PCENTO = 0.001 ! the percentage - NGS = 10 ! number of complexes in the initial population - NPG = 2*NOPT + 1 ! number of points in each complex - NPS = NOPT + 1 ! number of points in a sub-complex - NSPL = 2*NOPT + 1 ! number of evolution steps allowed for each complex before shuffling - MINGS = NGS ! minimum number of complexes required - INIFLG = 1 ! 1 = include initial point in the population - IPRINT = 1 ! 0 = supress printing - ! open up ASCII output file - ISCE = 96; OPEN(ISCE,FILE=TRIM(FNAME_ASCII)) - ! optimize (returns A and AF) - CALL SCEUA(A,AF,BL,BU,NOPT,MAXN,KSTOP,PCENTO,ISEED,& - NGS,NPG,NPS,NSPL,MINGS,INIFLG,IPRINT,ISCE) - ! close ASCII output file - CLOSE(ISCE) - ! call the function again with the optimized parameter set (to ensure the last parameter set is the optimum( - AF = FUNCTN(NOPT,A) - ! -------------------------------------------------------------------------------------- -END DO ! looping through seeds -! --------------------------------------------------------------------------------------- -STOP -END diff --git a/build/FUSE_SRC/share/multiforce_data.f90 b/build/FUSE_SRC/share/multiforce_data.f90 index 95e42ca..68207a5 100644 --- a/build/FUSE_SRC/share/multiforce_data.f90 +++ b/build/FUSE_SRC/share/multiforce_data.f90 @@ -59,23 +59,24 @@ MODULE multiforce SAVE ! general - INTEGER(I4B),PARAMETER :: STRLEN=256 ! length of the character string + INTEGER(I4B),PARAMETER :: STRLEN=256 ! length of the character string ! time data structures - TYPE(tData) :: timDat ! model time structure + TYPE(tData) :: timDat ! model time structure ! response data structures - TYPE(vData) :: valDat ! validation structure - TYPE(vData), DIMENSION(:,:,:), POINTER :: aValid ! all model validation data + TYPE(vData) :: valDat ! validation structure + TYPE(vData), allocatable :: aValid(:,:,:) ! all model validation data ! forcing data structures - TYPE(FDATA), DIMENSION(:), POINTER :: AFORCE ! all model forcing data - TYPE(FDATA), DIMENSION(:), POINTER :: CFORCE ! COPY of model forcing data - TYPE(FDATA) :: MFORCE ! model forcing data for a single time step - TYPE(aData), DIMENSION(:,:), POINTER :: ancilF ! ancillary forcing data for the 2-d grid - TYPE(fData), DIMENSION(:,:), POINTER :: gForce ! model forcing data for a 2-d grid - TYPE(fData), DIMENSION(:,:,:), POINTER :: gForce_3d ! model forcing data for a 3-d grid (time as 3rd dimension) - TYPE(aData), DIMENSION(:,:,:), POINTER :: ancilF_3d ! ancillary forcing data for the 3-d grid + TYPE(FDATA), allocatable :: AFORCE(:) ! all model forcing data + TYPE(FDATA), allocatable :: CFORCE(:) ! COPY of model forcing data + TYPE(FDATA) :: MFORCE ! model forcing data for a single time step + + TYPE(aData), allocatable :: ancilF(:,:) ! ancillary forcing data for the 2-d grid + TYPE(fData), allocatable :: gForce(:,:) ! model forcing data for a 2-d grid + TYPE(fData), allocatable :: gForce_3d(:,:,:) ! model forcing data for a 3-d grid (time as 3rd dimension) + TYPE(aData), allocatable :: ancilF_3d(:,:,:) ! ancillary forcing data for the 3-d grid ! NetCDF diff --git a/build/FUSE_SRC/types/data_types.f90 b/build/FUSE_SRC/types/data_types.f90 index 46771e4..9d2d239 100644 --- a/build/FUSE_SRC/types/data_types.f90 +++ b/build/FUSE_SRC/types/data_types.f90 @@ -3,7 +3,7 @@ module data_types use nrtype use multiforce_types, only: ADATA, FDATA, VDATA - use multibands_types, only: BANDS_VAR + use multibands_types, only: BANDS_INFO, BANDS_VAR use multistate_types, only: STATEV use multi_flux_types, only: FLUXES use multiroute_types, only: RUNOFF @@ -39,29 +39,36 @@ module data_types type(coord_data) :: coords ! 2D ancillary forcing (optional, for PET etc.) - type(ADATA), allocatable :: ancil(:,:) ! (nx_local, ny_local) + type(ADATA), allocatable :: ancil(:,:) ! (nx_local, ny_local) - ! 3D forcing window (nx_local, ny_local, numtim_sub) - type(FDATA), allocatable :: force(:,:,:) ! force_3d + ! 3D forcing window + type(FDATA), allocatable :: force(:,:,:) ! gForce_3d (nx_local, ny_local, nt_window) - ! 3D state window (nx_local, ny_local, numtim_sub+1) - type(STATEV), allocatable :: state(:,:,:) ! state_3d + ! 3D state window + type(STATEV), allocatable :: state(:,:,:) ! gState_3d (nx_local, ny_local, nt_window+1) - ! 3D flux window (nx_local, ny_local, numtim_sub) - type(FLUXES), allocatable :: flux(:,:,:) ! flux_3d + ! 3D flux window + type(FLUXES), allocatable :: flux(:,:,:) ! w_flux_3d (nx_local, ny_local, nt_window) - ! 3D routing window (nx_local, ny_local, numtim_sub) - type(RUNOFF), allocatable :: route(:,:,:) ! route_3d + ! 3D routing window + type(RUNOFF), allocatable :: route(:,:,:) ! AROUTE_3d (nx_local, ny_local, nt_window) - ! 4D snow-band state window (nx_local, ny_local, n_bands, numtim_sub+1) - type(BANDS_VAR), allocatable :: bands(:,:,:,:) ! bands_var_4d + ! 2D elevation information + logical(lgt), allocatable :: elev_mask(:,:) ! elev_mask (nx_local, ny_local) + real(sp), allocatable :: z_forcing(:,:) ! Z_FORCING_grid (nx_local, ny_local) + + ! 3D snow-band information + type(BANDS_INFO), allocatable :: bands_info(:,:,:) ! MBANDS_INFO_3d (nx_local, ny_local, n_bands) + + ! 4D snow-band state window + type(BANDS_VAR), allocatable :: bands_var(:,:,:,:) ! MBANDS_VAR_4d (nx_local, ny_local, n_bands, nt_window+1) ! 3D observed discharge / validity (optional) - type(VDATA), allocatable :: valid(:,:,:) ! (nx_local, ny_local, numtim_sub) + type(VDATA), allocatable :: valid(:,:,:) ! aValid (nx_local, ny_local, nt_window) ! basin-average time series for output convenience - type(FDATA), allocatable :: aForce(:) ! (numtim_sub) - type(RUNOFF), allocatable :: aRoute(:) ! (numtim_sub) + type(FDATA), allocatable :: aForce(:) ! (nt_window) + type(RUNOFF), allocatable :: aRoute(:) ! (nt_window) end type domain_data diff --git a/build/FUSE_SRC/types/info_types.f90 b/build/FUSE_SRC/types/info_types.f90 index b9c5e11..a94a003 100644 --- a/build/FUSE_SRC/types/info_types.f90 +++ b/build/FUSE_SRC/types/info_types.f90 @@ -7,6 +7,7 @@ module info_types private public :: cli_options public :: time_info + public :: space_info public :: fuse_info ! -------------------------------------------------------------------------------------- @@ -80,7 +81,8 @@ module info_types ! bookkeeping for time axis character(len=:), allocatable :: units real(sp) :: jdate_ref = 0._sp - real(sp), allocatable :: jdate(:) ! julian day for each forcing record + real(sp), allocatable :: time_steps(:) ! time since reference time (transferred to output) + real(sp), allocatable :: jdate(:) ! julian day for each forcing record end type time_info @@ -118,6 +120,9 @@ module info_types character(len=512) :: fname_netcdf_runs = "" character(len=512) :: fname_netcdf_para = "" + ! NetCDF file IDs + integer(i4b) :: ncid_forc = -9999 ! NetCDF file ID for forcing data + end type file_info ! ------------------------------------------------------------------------------------- @@ -136,7 +141,10 @@ module info_types ! model information integer(i4b) :: nState = -9999 integer(i4b) :: nParam = -9999 - + + ! number of input variables (3 = ppt, temp, pet; 4 = + obsq) + integer(i4b) :: nInput + ! list of model parameters type(par_id), allocatable :: listParam(:) diff --git a/build/FUSE_SRC/types/work_types.f90 b/build/FUSE_SRC/types/work_types.f90 index cbe94c7..0b56c8b 100644 --- a/build/FUSE_SRC/types/work_types.f90 +++ b/build/FUSE_SRC/types/work_types.f90 @@ -42,11 +42,14 @@ module work_types type(fdata) :: force ! model forcing data type(statev) :: state0 ! state variables (start of step) type(statev) :: state1 ! state variables (end of step) + type(statev) :: tState ! state variables (trial) type(statev) :: dx_dt ! time derivative in state variables type(fluxes) :: flux ! fluxes type(runoff) :: route ! hillslope routing end type fuse_step + real(sp) , allocatable :: x0(:) ! state variables (start of step) + real(sp) , allocatable :: x1(:) ! state variables (end of step) ! snow structure type fuse_snow real(sp) :: z_forcing ! elevation of forcing data (m) @@ -61,6 +64,12 @@ module work_types type(pardvd) :: param_derive ! derived model parameters end type fuse_param + ! numerix structure (linear algebra, ...) + type fuse_numerix + real(sp) , allocatable :: x0(:) ! state variables (start of step) + real(sp) , allocatable :: x1(:) ! state variables (end of step) + end type fuse_numerix + ! adjoint structure (differentiable fuse) type fuse_adjoint type(fluxes), allocatable :: df_dS(:) ! derivative in fluxes w.r.t. states @@ -86,6 +95,7 @@ module work_types type(fuse_step) :: step ! per-step structure type(fuse_snow) :: snow ! snow structure type(fuse_param) :: par ! parameter structure + type(fuse_numerix) :: num ! numerix structure (linear algebra, ...) type(fuse_adjoint) :: adj ! adjoint structure (differentiable fuse) type(fuse_chunk) :: chunk ! chunk buffer type(fuse_run) :: run ! run-level structure diff --git a/build/FUSE_SRC/util/alloc_domain.f90 b/build/FUSE_SRC/util/alloc_domain.f90 index 9c445d4..9d5220a 100644 --- a/build/FUSE_SRC/util/alloc_domain.f90 +++ b/build/FUSE_SRC/util/alloc_domain.f90 @@ -58,9 +58,17 @@ subroutine allocate_domain_data(info, domain, ierr, message) allocate(domain%route(nx,ny,nt), stat=ierr) if(ierr/=0)then; message=trim(message)//"cannot allocate route"; return; endif - ! allocate bands - allocate(domain%bands(nx,ny,nb,nt+1), stat=ierr) - if(ierr/=0)then; message=trim(message)//"cannot allocate bands"; return; endif + ! allocate elevation grid + allocate(domain%z_forcing(nx,ny), domain%elev_mask(nx,ny), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate elev grid"; return; endif + + ! allocate elevation bands (info) + allocate(domain%bands_info(nx,ny,nb), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate elev bands (info)"; return; endif + + ! allocate elevation bands (var) + allocate(domain%bands_var(nx,ny,nb,nt+1), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate elev bands (var)"; return; endif end subroutine allocate_domain_data @@ -73,10 +81,14 @@ subroutine set_legacy_arrays(info, domain, ierr, message) ! legacy modules use multiforce, only: nSpat1, nSpat2, numtim_sub - use multiForce, only: gForce_3d, ancilF, aValid + USE multiforce, only: startSpat2 ! starting y index for data read + USE multiforce, only: ncid_forc + use multiforce, only: timeUnits + use multiforce, only: nInput + use multiForce, only: aForce, gForce_3d, ancilF, aValid use multiState, only: gState_3d - use multiRoute, only: AROUTE_3d - use multiBands, only: MBANDS_VAR_4d, N_BANDS + use multiRoute, only: aRoute, AROUTE_3d + use multiBands, only: N_BANDS, MBANDS, MBANDS_INFO_3d, MBANDS_VAR_4d, Z_FORCING_grid, elev_mask implicit none type(fuse_info), intent(in) :: info @@ -84,47 +96,78 @@ subroutine set_legacy_arrays(info, domain, ierr, message) integer(i4b), intent(out) :: ierr character(*), intent(out) :: message + integer(i4b) :: nx, ny, nt, nb + ierr = 0 message = 'set_legacy_arrays/' - ! ensure the spatial dimensions match what is in domain%info - ! NOTE: dimension variables stored in legacy data modules - nSpat1 = info%space%nx_local ! NOTE: local to rank (MPI parallelization) - nSpat2 = info%space%ny_local - numtim_sub = info%time%nt_window - n_bands = info%snow%n_bands - - ! allocate space for the forcing grid and states - allocate(ancilF(nspat1,nspat2), stat=ierr) - if(ierr/=0)then - message=trim(message)//'unable to allocate space for 2-d ancillary grid' - ierr=20; return - endif - - ! allocate space for the forcing grid and states with a time dimension - only for subperiod - allocate(aValid( nspat1,nspat2,numtim_sub), & - gForce_3d(nspat1,nspat2,numtim_sub), & - gState_3d(nspat1,nspat2,numtim_sub+1), & - AROUTE_3d(nspat1,nspat2,numtim_sub), stat=ierr) - if(ierr/=0)then - message=trim(message)//'unable to allocate space for 3d structure' - ierr=20; return - endif - - ! allocate space for elevation bands - allocate(MBANDS_VAR_4d(nspat1,nspat2,N_BANDS,numtim_sub+1), stat=ierr) - if(ierr/=0)then - message=trim(message)//'unable to allocate space for elevation bands' - ierr=20; return - endif + ! define dimensions + nx = info%space%nx_local ! NOTE: local to rank (MPI parallelization) + ny = info%space%ny_local + nt = info%time%nt_window + nb = info%snow%n_bands + + ! set variables in multiforce + nSpat1 = nx + nSpat2 = ny + numtim_sub = nt + startSpat2 = info%space%y_start_global + + ncid_forc = info%files%ncid_forc + + nInput = info%config%nInput + + ! set bands + N_BANDS = nb + + ! allocate validity mask + allocate(aValid(nx,ny,nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate valid"; return; endif + + ! allocate ancillary forcing + allocate(ancilF(nx,ny), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate ancil"; return; endif + + ! allocate forcing window + allocate(gForce_3d(nx,ny,nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate force"; return; endif + + ! allocate state window + allocate(gState_3d(nx,ny,nt+1), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate state"; return; endif + + ! allocate flux window + !allocate(w_flux_3d(nx,ny,nt), stat=ierr) + !if(ierr/=0)then; message=trim(message)//"cannot allocate flux"; return; endif + + ! allocate basin averages + allocate(aForce(nt), aRoute(nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate aForce/aRoute"; return; endif + + ! allocate routing if needed + allocate(AROUTE_3d(nx,ny,nt), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate route"; return; endif + + ! allocate elevation grid and mask + allocate(Z_FORCING_grid(nx,ny), elev_mask(nx, ny), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate elev grid"; return; endif + + ! allocate elevation bands + allocate(MBANDS(nb), MBANDS_INFO_3d(nx,ny,nb), MBANDS_VAR_4d(nx,ny,nb,nt+1), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate elev bands"; return; endif ! copy arrays in the domain structure to legacy arrays - aValid = domain%valid ! validity mask - ancilF = domain%ancil ! ancillary forcing - gForce_3d = domain%force ! forcing window - gState_3d = domain%state ! state window - AROUTE_3d = domain%route ! routing window - MBANDS_VAR_4d = domain%bands ! elevation band window + aValid = domain%valid ! validity mask + ancilF = domain%ancil ! ancillary forcing + aForce = domain%aForce ! all model forcing data + gForce_3d = domain%force ! forcing data + gState_3d = domain%state ! state data + aRoute = domain%aRoute ! all routing data + AROUTE_3d = domain%route ! routing data + elev_mask = domain%elev_mask ! elevation mask + Z_FORCING_grid = domain%z_forcing ! elevation grid + MBANDS_INFO_3d = domain%bands_info ! elevation band info + MBANDS_VAR_4d = domain%bands_var ! elevation band vars end subroutine set_legacy_arrays diff --git a/build/FUSE_SRC/util/alloc_scratch.f90 b/build/FUSE_SRC/util/alloc_scratch.f90 index 37b0771..a9e0ecb 100644 --- a/build/FUSE_SRC/util/alloc_scratch.f90 +++ b/build/FUSE_SRC/util/alloc_scratch.f90 @@ -23,20 +23,32 @@ subroutine init_fuse_work(info, work, ierr, message) integer(i4b) :: ib integer(i4b) :: nBands, nState, nPar + logical(lgt) :: redo ierr=0; message="init_fuse_work/" - ! identify dimensions nBands = info%snow%n_bands nState = info%config%nState nPar = info%config%nParam - ! If already initialized, don't reallocate unless sizes mismatch + ! check if there is a need to reallocate + redo = needs_realloc_work(work, nBands, nState, nPar, NPAR_SNOW) + if (.not. redo) return + + ! if need to reallocate, then need to free up space if (work%is_initialized) then call free_fuse_work(work, ierr, message) if(ierr/=0) return endif + ! ---- allocate state vectors ---- + allocate(work%num%x0(nState), & + work%num%x1(nState), stat=ierr) + if(ierr/=0) then + message=trim(message)//"cannot allocate state vectors" + return + endif + ! optional debug scratch ! allocate(work%dSdt(nState), work%J(nState,nState), stat=ierr) @@ -90,6 +102,17 @@ subroutine free_fuse_work(work, ierr, message) ierr = 0 message = "free_fuse_work/" + ! ---- state vectors ---- + if(allocated(work%num%x0)) then + deallocate(work%num%x0, stat=istat) + call note_fail("num%x0", istat) + endif + + if(allocated(work%num%x1)) then + deallocate(work%num%x1, stat=istat) + call note_fail("num%x1", istat) + endif + ! ---- derivative arrays ---- if (allocated(work%adj%df_dS)) then deallocate(work%adj%df_dS, stat=istat) @@ -140,4 +163,48 @@ end subroutine note_fail end subroutine free_fuse_work + ! ------------------------------------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------------------------------------- + + ! Private: decide if we need to free+reallocate work arrays + logical(lgt) function needs_realloc_work(work, nBands, nState, nPar, nParSnow) result(redo) + + type(fuse_work), intent(in) :: work + integer(i4b), intent(in) :: nBands, nState, nPar, nParSnow + + integer(i4b) :: ib + + redo = .false. + + ! Not initialized => must allocate + if (.not. work%is_initialized) then + redo = .true. + return + endif + + ! Must be allocated if we claim initialized + if (.not. allocated(work%adj%df_dS)) then; redo=.true.; return; endif + if (.not. allocated(work%adj%df_dPar)) then; redo=.true.; return; endif + if (.not. allocated(work%adj%dL_dPar)) then; redo=.true.; return; endif + if (.not. allocated(work%snow%sbands)) then; redo=.true.; return; endif + + ! Size checks + if (size(work%adj%df_dS) /= nState) then; redo=.true.; return; endif + if (size(work%adj%df_dPar) /= nPar) then; redo=.true.; return; endif + if (size(work%adj%dL_dPar) /= nPar) then; redo=.true.; return; endif + if (size(work%snow%sbands) /= nBands) then; redo=.true.; return; endif + + ! Per-band arrays + do ib = 1, nBands + if (.not. allocated(work%snow%sbands(ib)%var%dSWE_dParam)) then + redo = .true.; return + endif + if (size(work%snow%sbands(ib)%var%dSWE_dParam) /= nParSnow) then + redo = .true.; return + endif + enddo + + end function needs_realloc_work + + end module alloc_scratch_module diff --git a/build/Makefile b/build/Makefile index bccd07d..62cc33a 100755 --- a/build/Makefile +++ b/build/Makefile @@ -142,6 +142,7 @@ DRIVER_EX = fuse.exe FUSE_DRIVER = FUSE_DRIVER += setup_domain.f90 FUSE_DRIVER += setup_model_definition.f90 +FUSE_DRIVER += sce_callback_context.f90 FUSE_DRIVER += fuse_evaluate.f90 functn.f90 FUSE_DRIVER += sce_driver.f90 FUSE_DRIVER += fuse_driver.f90 @@ -308,7 +309,6 @@ FUSE_RUNTIME += conv_funcs.f90 FUSE_RUNTIME += clrsky_rad.f90 FUSE_RUNTIME += getPETgrid.f90 FUSE_RUNTIME += get_time_windows.f90 -FUSE_RUNTIME += get_time_indices.f90 FUSE_RUNTIME += initfluxes.f90 FUSE_RUNTIME += set_all.f90 FUSE_RUNTIME += ode_int.f90 @@ -321,9 +321,10 @@ RUNTIME = $(patsubst %, $(RUNTIME_DIR)/%, $(FUSE_RUNTIME)) FUSE_NETCDF = FUSE_NETCDF += handle_err.f90 FUSE_NETCDF += extractor.f90 juldayss.f90 caldatss.f90 +FUSE_NETCDF += get_domain_dims.f90 +FUSE_NETCDF += read_elevbands.f90 FUSE_NETCDF += domain_decomp.f90 FUSE_NETCDF += get_gforce.f90 -FUSE_NETCDF += get_mbands.f90 FUSE_NETCDF += get_smodel.f90 FUSE_NETCDF += get_fparam.f90 FUSE_NETCDF += def_params.f90 diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index bf95afb..e25e401 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-20T16:39:50Z' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-22T16:36:12Z' character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/driver' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'a9bb61c58c270788e243955690f57023a418687b' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'dc8df16c4488b031b0c4a5902413e766eaac4d47' From fb6624e5e77051c2e8468df6abaced0d4c05613e Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Sun, 22 Feb 2026 17:59:44 -0700 Subject: [PATCH 10/11] initial implementation of the TOML control file --- build/FUSE_SRC/driver/fuse_driver.f90 | 6 +- build/FUSE_SRC/driver/setup_domain.f90 | 26 +- build/FUSE_SRC/types/info_types.f90 | 55 +-- build/FUSE_SRC/util/fuse_fileManager.f90 | 519 ++++++++++------------- build/FUSE_SRC/util/selectmodl.f90 | 6 +- build/Makefile | 48 ++- build/generated/fuseversion.inc | 6 +- 7 files changed, 303 insertions(+), 363 deletions(-) diff --git a/build/FUSE_SRC/driver/fuse_driver.f90 b/build/FUSE_SRC/driver/fuse_driver.f90 index fd52e26..6cda7e7 100644 --- a/build/FUSE_SRC/driver/fuse_driver.f90 +++ b/build/FUSE_SRC/driver/fuse_driver.f90 @@ -50,11 +50,11 @@ PROGRAM DISTRIBUTED_DRIVER IMPLICIT NONE ! error control -integer(i4b) :: err ! error code -character(len=1024) :: message ! error message +integer(i4b) :: err ! error code +character(len=1024) :: message ! error message ! command line arguments -type(cli_options) :: cli_opts ! command line argument options +type(cli_options) :: cli_opts ! command line argument options ! parameter set; parameter bounds REAL(SP), DIMENSION(:), ALLOCATABLE :: BL ! vector of lower parameter bounds diff --git a/build/FUSE_SRC/driver/setup_domain.f90 b/build/FUSE_SRC/driver/setup_domain.f90 index bb3b586..d0f3914 100644 --- a/build/FUSE_SRC/driver/setup_domain.f90 +++ b/build/FUSE_SRC/driver/setup_domain.f90 @@ -17,9 +17,7 @@ subroutine setup_domain(opts, info, domain, ierr, message) ! access subroutines use netcdf, only: nf90_open, nf90_nowrite, nf90_strerror ! NetCDF functions - USE fuse_fileManager, only: fuse_SetDirsUndPhiles ! sets directories and filenames - USE fuse_fileManager, only: export_filemanager_to_domain ! populates domain%info structure - USE fuse_fileManager, only: finalize_domain_config ! compute additional filenames/variables + USE fuse_fileManager, only: read_fuse_control_file ! sets directories and filenames USE fuse_fileManager, only: export_domain_to_legacy ! populates legacy modules USE force_info_module, only: force_info ! get forcing info for NetCDF files @@ -51,24 +49,14 @@ subroutine setup_domain(opts, info, domain, ierr, message) ! ----- internal ----------------------------------------------------------------------- CHARACTER(LEN=1024) :: CMESSAGE ! error message ! --------------------------------------------------------------------------------------- - associate(INPUT_PATH => info%files%input_path, & - forcefile => info%files%forcing_file) - ! --------------------------------------------------------------------------------------- ierr=0; message='setup_domain/' ! ----- set paths and file names -------------------------------------------------------- - ! set directories and filenames for control files - call fuse_SetDirsUndPhiles(fuseFileManagerIn=opts%control_file, err=ierr, message=cmessage) + ! read fuse control file (set paths/filenames etc.) + call read_fuse_control_file(trim(opts%control_file), opts, info, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! copy global file information to the domain structure - call export_filemanager_to_domain(opts, info) - - ! derive filenames + parse config strings - call finalize_domain_config(opts, info, ierr, cmessage) - if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! populate legacy modules call export_domain_to_legacy(info) @@ -93,11 +81,11 @@ subroutine setup_domain(opts, info, domain, ierr, message) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif ! ----- read grid info and define indices for MPI domain decomposition ------------------ - + ! open NetCDF forcing file - ierr = nf90_open(trim(INPUT_PATH)//trim(forcefile), nf90_nowrite, info%files%ncid_forc) + ierr = nf90_open(trim(info%files%fname_netcdf_forc), nf90_nowrite, info%files%ncid_forc) if (ierr/=0)then; message=trim(message)//' nf90_open failed: '//trim(nf90_strerror(ierr)); return; endif - if(isPrint) print *, 'Open forcing file:', trim(INPUT_PATH)//trim(forcefile) + if(isPrint) print *, 'Open forcing file:', trim(info%files%fname_netcdf_forc) if(isPrint) PRINT *, 'NCID_FORC is', info%files%ncid_forc ! get indices for MPI decomposition of the spatial domain: y_start_global, ny_local @@ -138,10 +126,8 @@ subroutine setup_domain(opts, info, domain, ierr, message) call get_varID(info%files%ncid_forc, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - print*, 'end of setup_domain' - end associate end subroutine setup_domain ! ------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/types/info_types.f90 b/build/FUSE_SRC/types/info_types.f90 index a94a003..774d61e 100644 --- a/build/FUSE_SRC/types/info_types.f90 +++ b/build/FUSE_SRC/types/info_types.f90 @@ -97,30 +97,31 @@ module info_types type :: file_info ! directories - character(len=512) :: setngs_path = "" - character(len=512) :: input_path = "" - character(len=512) :: output_path = "" + character(len=:), allocatable :: setngs_path + character(len=:), allocatable :: input_path + character(len=:), allocatable :: output_path ! settings filenames (relative or absolute) - character(len=512) :: forcinginfo = "" - character(len=512) :: constraints = "" - character(len=512) :: mod_numerix = "" - character(len=512) :: m_decisions = "" + character(len=:), allocatable :: forcinginfo + character(len=:), allocatable :: constraints + character(len=:), allocatable :: mod_numerix + character(len=:), allocatable :: m_decisions ! domain-derived input suffixes - character(len=512) :: suffix_forcing = "" - character(len=512) :: suffix_elev_bands = "" + character(len=:), allocatable :: suffix_forcing + character(len=:), allocatable :: suffix_elev_bands ! actual input filenames for this domain (derived once dom_id known) - character(len=512) :: forcing_file = "" ! dom_id//suffix_forcing - character(len=512) :: elevbands_file = "" ! dom_id//suffix_elev_bands + character(len=:), allocatable :: forcing_file ! dom_id//suffix_forcing + character(len=:), allocatable :: elevbands_file ! dom_id//suffix_elev_bands ! output base name + concrete outputs - character(len=512) :: fname_tempry = "" - character(len=512) :: fname_netcdf_runs = "" - character(len=512) :: fname_netcdf_para = "" + character(len=512) :: fname_tempry + character(len=512) :: fname_netcdf_forc + character(len=512) :: fname_netcdf_runs + character(len=512) :: fname_netcdf_para - ! NetCDF file IDs + ! NetCDF forcing file info integer(i4b) :: ncid_forc = -9999 ! NetCDF file ID for forcing data end type file_info @@ -136,7 +137,7 @@ module info_types type(cli_options) :: cli_opts ! model selection - character(len=64) :: fmodel_id = "" + character(len=:), allocatable :: fmodel_id ! model information integer(i4b) :: nState = -9999 @@ -152,11 +153,11 @@ module info_types logical(lgt) :: q_only = .false. ! requested time windows (strings as read from filemanager) - character(len=20) :: date_start_sim = "" - character(len=20) :: date_end_sim = "" - character(len=20) :: date_start_eval = "" - character(len=20) :: date_end_eval = "" - character(len=20) :: numtim_sub_str = "" + character(len=:), allocatable :: date_start_sim + character(len=:), allocatable :: date_end_sim + character(len=:), allocatable :: date_start_eval + character(len=:), allocatable :: date_end_eval + character(len=:), allocatable :: numtim_sub_str ! parsed / derived values (optional convenience) integer(i4b) :: numtim_sub = -9999 ! parsed from numtim_sub_str @@ -164,12 +165,16 @@ module info_types ! output dimension for number of parameter sets integer(i4b) :: nSets + ! calibration metrics and metric transformations + character(len=:), allocatable :: metric + character(len=:), allocatable :: transfo + ! SCE settings (store as numeric types) - integer(i4b) :: maxn = -9999 - integer(i4b) :: kstop = -9999 - real(sp) :: pcento = -9999._sp + integer(i4b) :: maxn = -9999 + integer(i4b) :: kstop = -9999 + real(sp) :: pcento = -9999._sp - ! store raw strings too if you care about provenance + ! store raw strings too character(len=20) :: maxn_str = "" character(len=20) :: kstop_str = "" character(len=20) :: pcento_str = "" diff --git a/build/FUSE_SRC/util/fuse_fileManager.f90 b/build/FUSE_SRC/util/fuse_fileManager.f90 index 7ea1447..30aafce 100644 --- a/build/FUSE_SRC/util/fuse_fileManager.f90 +++ b/build/FUSE_SRC/util/fuse_fileManager.f90 @@ -1,6 +1,3 @@ -!****************************************************************** -! (C) Copyright 2009-2010 --- Dmitri Kavetski and Martyn Clark --- All rights reserved -!****************************************************************** ! Edited by Brian Henn to include snow model, 7/2013 ! Edited by Nans Addor to set simulation and evaluation periods, 11/2017 ! Modified by Martyn Clark to populate domain structure, 12/2025 @@ -14,23 +11,22 @@ MODULE fuse_filemanager implicit none private - public :: fuse_SetDirsUndPhiles - public :: export_filemanager_to_domain - public :: finalize_domain_config + public :: read_fuse_control_file public :: export_domain_to_legacy + ! ----- all of these legacy globals are stored in the "info" data structure --------------------- + ! expose legacy globals public :: SETNGS_PATH, INPUT_PATH, OUTPUT_PATH public :: suffix_forcing, suffix_elev_bands - public :: FORCINGINFO, CONSTRAINTS, MOD_NUMERIX, M_DECISIONS - public :: MBANDS_INFO, MBANDS_NC + public :: M_DECISIONS, CONSTRAINTS, MOD_NUMERIX, FORCINGINFO, MBANDS_NC public :: FMODEL_ID, Q_ONLY_STR, Q_ONLY public :: date_start_sim, date_end_sim, date_start_eval, date_end_eval, numtim_sub_str public :: METRIC, TRANSFO public :: KSTOP_str, MAXN_str, PCENTO_str ! FUSE-wide pathlength - integer(mik),parameter::fusePathLen=512 + integer(i4b),parameter::fusePathLen=512 ! defines the path for data files CHARACTER(LEN=fusePathLen) :: SETNGS_PATH @@ -46,7 +42,6 @@ MODULE fuse_filemanager CHARACTER(LEN=fusePathLen) :: CONSTRAINTS ! definition of parameter constraints CHARACTER(LEN=fusePathLen) :: MOD_NUMERIX ! definition of numerical solution technique CHARACTER(LEN=fusePathLen) :: FORCINGINFO ! info on forcing data files - CHARACTER(LEN=fusePathLen) :: MBANDS_INFO ! info on basin band data files ! not needed anymore CHARACTER(LEN=fusePathLen) :: MBANDS_NC ! netcdf file defining the elevation bands ! content of output directory @@ -72,321 +67,239 @@ MODULE fuse_filemanager contains - ! ----- copies the globals into the domain structure ---------------------------------- - - ! NOTE: this should be called after call fuse_SetDirsUndPhiles(fuseFileManagerIn, ..) - - subroutine export_filemanager_to_domain(cli_opts, info) - - implicit none - type(cli_options), intent(in) :: cli_opts ! command line interface options - type(fuse_info), intent(inout) :: info - - ! ----- file information ------------------------------------------------------------ - - ! directories - info%files%setngs_path = trim(SETNGS_PATH) - info%files%input_path = trim(INPUT_PATH) - info%files%output_path = trim(OUTPUT_PATH) - - ! suffixes - info%files%suffix_forcing = trim(suffix_forcing) - info%files%suffix_elev_bands = trim(suffix_elev_bands) - - ! settings filenames - info%files%forcinginfo = trim(FORCINGINFO) - info%files%constraints = trim(CONSTRAINTS) - info%files%mod_numerix = trim(MOD_NUMERIX) - info%files%m_decisions = trim(M_DECISIONS) - - ! ----- configuration options ------------------------------------------------------- - - ! Convenience alias (already available via config%cli_opts%control_file) - info%config%file_manager_file = trim(cli_opts%control_file) - - ! provenance: CLI options - info%config%cli_opts = cli_opts ! control file, tags, etc. - - ! runtime information - info%config%fmodel_id = trim(FMODEL_ID) - info%config%q_only = Q_ONLY - - ! user-defined simulation/evaluation time periods: strings - info%config%date_start_sim = trim(date_start_sim) - info%config%date_end_sim = trim(date_end_sim) - info%config%date_start_eval = trim(date_start_eval) - info%config%date_end_eval = trim(date_end_eval) - - ! user-defined sub-window time slice length - info%config%numtim_sub_str = trim(numtim_sub_str) - - ! user-defined SCE control parameters (used for SCE calibration runs) - info%config%maxn_str = trim(MAXN_str) - info%config%kstop_str = trim(KSTOP_str) - info%config%pcento_str = trim(PCENTO_str) - - end subroutine export_filemanager_to_domain - ! ------------------------------------------------------------------------------------- ! ------------------------------------------------------------------------------------- - subroutine finalize_domain_config(cli_opts, info, ierr, message) - - implicit none - - type(cli_options), intent(in) :: cli_opts - type(fuse_info), intent(inout) :: info - integer(i4b), intent(out) :: ierr - character(*), intent(out) :: message - - character(len=256) :: dom_id, tag, run_mode - integer(i4b) :: ios - - ierr=0; message="finalize_domain_config/" - - dom_id = trim(cli_opts%domain_id) - run_mode = trim(cli_opts%runmode) - - tag = "" - if(allocated(cli_opts%tag)) tag = trim(cli_opts%tag) - - ! ---- derived input filenames ---- - info%files%forcing_file = trim(dom_id)//trim(info%files%suffix_forcing) - info%files%elevbands_file = trim(dom_id)//trim(info%files%suffix_elev_bands) - - ! ---- derived output base name ---- - info%files%fname_tempry = trim(info%files%output_path)// & - trim(dom_id)//'_'//trim(info%config%fmodel_id)//'_'//trim(tag) - - info%files%fname_netcdf_runs = trim(info%files%fname_tempry)//'_runs_'//trim(run_mode)//'.nc' - info%files%fname_netcdf_para = trim(info%files%fname_tempry)//'_para_'//trim(run_mode)//'.nc' - - ! ---- parse numeric config ---- - read(info%config%maxn_str, *, iostat=ios) info%config%maxn - if(ios/=0) then; ierr=1; message=trim(message)//"cannot parse MAXN"; return; endif - - read(info%config%kstop_str, *, iostat=ios) info%config%kstop - if(ios/=0) then; ierr=1; message=trim(message)//"cannot parse KSTOP"; return; endif - - read(info%config%pcento_str,*, iostat=ios) info%config%pcento - if(ios/=0) then; ierr=1; message=trim(message)//"cannot parse PCENTO"; return; endif - - end subroutine finalize_domain_config + subroutine read_fuse_control_file(fuseFileManagerIn, opts, info, err, message) - ! ------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------- +use tomlf_all, only: toml_table, toml_error, toml_key, toml_value ! data types +use tomlf_all, only: toml_load, get_value ! procedures +! or: use tomlf, only: toml_table, toml_load, toml_error +! use tomlf_type_keyval, only: toml_key (if toml_key not re-exported) + ! Purpose: Reads FUSE control file (TOML version) AND populates info structure + implicit none - ! ----- export domain config variables to legacy modules ------------------------------ + ! dummies + character(*), intent(in) :: fuseFileManagerIn + type(cli_options), intent(in) :: opts + type(fuse_info), intent(inout) :: info + integer(i4b), intent(out) :: err + character(*), intent(out) :: message + + ! TOML table + type(toml_table), allocatable :: tbl ! root TOML table + type(toml_table), pointer :: subtable ! sub-table for a given section + type(toml_key), allocatable :: sections(:) ! top-level sections + type(toml_key), allocatable :: keys(:) ! sub-table keys + type(toml_error), allocatable :: error - subroutine export_domain_to_legacy(info) - use model_defn, only: FNAME_TEMPRY, FNAME_NETCDF_RUNS, FNAME_NETCDF_PARA - use multiparam, only: MAXN, KSTOP, PCENTO - use multiforce, only: forcefile - - type(fuse_info), intent(in) :: info - - ! populate module model_defn - FNAME_TEMPRY = trim(info%files%fname_tempry) - FNAME_NETCDF_RUNS = trim(info%files%fname_netcdf_runs) - FNAME_NETCDF_PARA = trim(info%files%fname_netcdf_para) - - ! populate module multiforce - forcefile = trim(info%files%forcing_file) - - ! populate shared public variable in this module (fuse_filemanager) - MBANDS_NC = trim(info%files%elevbands_file) - - ! populate module multiparam - MAXN = info%config%maxn - KSTOP = info%config%kstop - PCENTO = info%config%pcento + ! locals + integer(i4b) :: istat + integer(i4b) :: n, i, j + character(len=256) :: lookup - end subroutine export_domain_to_legacy + ! create file paths + character(len=256) :: dom_id, tag, run_mode - ! ------------------------------------------------------------------------------------- - ! ------------------------------------------------------------------------------------- + err = 0 + message = "read_fuse_control_file/" - ! ----- sets directories and filenames for FUSE -------------------------------------- - - subroutine fuse_SetDirsUndPhiles(fuseMusterDirektorIn,fuseFileManagerIn,err,message) - ! Purpose: Sets direcotries and philenames for FUSE. - ! --- - ! Programmer: Dmitri Kavetski - ! History: - ! Darby St, 18/10/2009 AD - leid out basik frammenverk - ! Sonnental, 17/06/2012 AD - more general path handling - ! --- - ! Usage - ! fuseMusterDirektorIn = master direktor file (path to filemanager) - ! fuseFileManagerIn = global names/path file - ! --- - ! Comments: - ! 1. If present will try to use fuseMasterIn, otherwise default file. - ! if default not present in EXE path then uses default options - ! --- - use utilities_dmsl_kit_FUSE,only:getSpareUnit - - implicit none - - ! dummies - character(*),intent(in),optional::fuseMusterDirektorIn,fuseFileManagerIn - integer(mik),intent(out)::err - character(*),intent(out)::message - - ! registered settings - character(*),parameter::procnam="fuseSetDirsUndPhiles" - character(*),parameter::pathDelim="/\",defpathSymb="*",blank=" " - character(*),parameter::fuseMusterDirektorHeader="FUSE_MUSTERDIREKTOR_V1.0" - character(*),parameter::fuseFileManagerHeader="FUSE_FILEMANAGER_V1.5" - - ! locals - logical(mlk)::haveFMG,haveMUS - character(LEN=fusePathLen)::fuseMusterDirektor,fuseFileManager,defpath - character(LEN=100)::temp - integer(mik)::unt,i - - ! Start procedure here - err=0; message=procnam//"/ok"; defpath=blank - - haveMUS=present(fuseMusterDirektorIn); haveFMG=present(fuseFileManagerIn) - if(haveMUS)haveMUS=len_trim(fuseMusterDirektorIn)>0 - if(haveFMG)haveFMG=len_trim(fuseFileManagerIn)>0 ! check for zero-string - if(haveMUS.and.haveFMG)then - message="f-"//procnam//"/mustSpecifyEither(notBoth)& - &[fuseMusterDirektor.or.fuseFileManager]" + ! ----- load the root TOML table ----- + call toml_load(tbl, trim(fuseFileManagerIn), error=error) + if (allocated(error)) then + message = "problem loading toml file['"//trim(fuseFileManagerIn)//"']: "//trim(error%message) err=10; return - - elseif(haveFMG)then - fuseFileManager=fuseFileManagerIn - i=scan(fuseFileManager,pathDelim,back=.true.) - if(i>0)defpath=fuseFileManager(:i-1)//pathDelim(1:1) - print *, 'fuseFileManager:', TRIM(fuseFileManager) - - elseif(haveMUS)then - fuseMusterDirektor=fuseMusterDirektorIn - i=scan(fuseMusterDirektor,pathDelim,back=.true.) - if(i>0)defpath=fuseMusterDirektor(:i-1)//pathDelim(1:1) - print *, 'fuseMusterDirektor:', TRIM(fuseMusterDirektor) - - else - message="f-"//procnam//"/mustSpecifyEither& - &[fuseMusterDirektor.or.fuseFileManager]" - err=20; return endif - - call getSpareUnit(unt,err,message) ! make sure 'unt' is actually available - - if(err/=0)then - message="f-"//procnam//"/weird/&"//message - err=100; return + + ! ----- get the top-level sections ----- + call tbl%get_keys(sections) + if(.not.allocated(sections)) then + message = "problem loading toml sections['"//trim(fuseFileManagerIn)//"']" + err=10; return endif - - ! Open muster-direktor and read it - if(.not.haveFMG)then ! grab it from the muster-direktor - - open(unt,file=fuseMusterDirektor,status="old",action="read",iostat=err) - if(err/=0)then - message="f-"//procnam//"/musterDirektorFileOpenError['"//trim(fuseMusterDirektor)//"']" + + ! ----- loop through sections ----- + do i = 1, size(sections) + + ! ----- load the TOML sub-table for the current section ----- + call get_value(tbl, trim(sections(i)%key), subtable, requested=.false.) + if(.not.associated(subtable)) then + message = "problem loading toml sub-sections['"//trim(fuseFileManagerIn)//"']:"//trim(sections(i)%key) err=10; return endif - - read(unt,*)temp - - if(temp/=fuseMusterDirektorHeader)then - message="f-"//procnam//"/unknownHeader&[file='"//trim(fuseMusterDirektor)//"']&& - &[header='"//trim(temp)//"']" - err=20; return - endif - - read(unt,*)fuseFileManager - close(unt) - - endif - - ! open file manager file - open(unt,file=fuseFileManager,status="old",action="read",iostat=err) - if(err/=0)then - message="f-"//procnam//"/fileManagerOpenError['"//trim(fuseFileManager)//"']" - err=10; return - endif - read(unt,*)temp - if(temp/=fuseFileManagerHeader)then - message="f-"//procnam//"/unknownHeader&[file='"//trim(fuseFileManager)//"']&& - &[header="//trim(temp)//"]" - - message='This version of FUSE requires the file manager to follow the following format: '//trim(fuseFileManagerHeader)//' not '//trim(temp) - - err=20; return - endif - - read(unt,'(a)')temp - read(unt,*)SETNGS_PATH - read(unt,*)INPUT_PATH - read(unt,*)OUTPUT_PATH - - read(unt,'(a)')temp - read(unt,*)suffix_forcing - read(unt,*)suffix_elev_bands - - read(unt,'(a)')temp - read(unt,*)FORCINGINFO - read(unt,*)CONSTRAINTS - read(unt,*)MOD_NUMERIX - read(unt,*)M_DECISIONS - - read(unt,'(a)')temp - read(unt,*)FMODEL_ID - read(unt,*)Q_ONLY_STR + ! ----- get keys for a given section (sub-table) ----- + call subtable%get_keys(keys) + + ! ----- loop through the sub-table ----- + do j = 1, size(keys) + + + ! --------------------------------------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------------------------------------- + + ! ----- control file assignment block --------------------------------------------------------------------------- + + lookup = trim(sections(i)%key)//'.'//trim(keys(j)%key) + + select case(lookup) + + ! ---- files: paths ---- + case ("paths.input_path" ); call get_value(subtable, trim(keys(j)%key), info%files%input_path , stat=istat) + case ("paths.output_path" ); call get_value(subtable, trim(keys(j)%key), info%files%output_path , stat=istat) + case ("paths.setngs_path" ); call get_value(subtable, trim(keys(j)%key), info%files%setngs_path , stat=istat) + + ! ---- files: suffixes ---- + case ("input.suffix_forcing" ); call get_value(subtable, trim(keys(j)%key), info%files%suffix_forcing , stat=istat) + case ("input.suffix_elev_bands"); call get_value(subtable, trim(keys(j)%key), info%files%suffix_elev_bands, stat=istat) + + ! ---- files: settings filenames ---- + case ("settings.forcinginfo" ); call get_value(subtable, trim(keys(j)%key), info%files%forcinginfo , stat=istat) + case ("settings.constraints" ); call get_value(subtable, trim(keys(j)%key), info%files%constraints , stat=istat) + case ("settings.mod_numerix" ); call get_value(subtable, trim(keys(j)%key), info%files%mod_numerix , stat=istat) + case ("settings.m_decisions" ); call get_value(subtable, trim(keys(j)%key), info%files%m_decisions , stat=istat) + + ! ---- config: runtime ---- + case ("output.fmodel_id" ); call get_value(subtable, trim(keys(j)%key), info%config%fmodel_id , stat=istat) + case ("output.q_only" ); call get_value(subtable, trim(keys(j)%key), info%config%q_only , stat=istat) + + ! ---- config: periods ---- + case ("periods.date_start_sim" ); call get_value(subtable, trim(keys(j)%key), info%config%date_start_sim , stat=istat) + case ("periods.date_end_sim" ); call get_value(subtable, trim(keys(j)%key), info%config%date_end_sim , stat=istat) + case ("periods.date_start_eval"); call get_value(subtable, trim(keys(j)%key), info%config%date_start_eval , stat=istat) + case ("periods.date_end_eval" ); call get_value(subtable, trim(keys(j)%key), info%config%date_end_eval , stat=istat) + case ("periods.numtim_sub_str" ); call get_value(subtable, trim(keys(j)%key), info%config%numtim_sub_str , stat=istat) + + ! ---- config: calibration ---- + case ("calibration.metric" ); call get_value(subtable, trim(keys(j)%key), info%config%metric , stat=istat) + case ("calibration.transfo" ); call get_value(subtable, trim(keys(j)%key), info%config%transfo , stat=istat) + + ! ---- config: SCE (read numeric, then next populate legacy strings) ---- + case ("sce.maxn" ); call get_value(subtable, trim(keys(j)%key), info%config%maxn , stat=istat) + case ("sce.kstop" ); call get_value(subtable, trim(keys(j)%key), info%config%kstop , stat=istat) + case ("sce.pcento" ); call get_value(subtable, trim(keys(j)%key), info%config%pcento , stat=istat) + + ! ---- default case (something in the table that is not specified above) ----- + case default + message = trim(message)// "unexpected entry: section = "//trim(sections(i)%key)//"; sub-section = "//trim(keys(j)%key) + err=20; return + + end select ! (select key/value pair based on lookup) + + ! ---- error checking ----- + if(istat /= 0)then + message=trim(message)// "get_value error: section = "//trim(sections(i)%key)//"; sub-section = "//trim(keys(j)%key) + err=20; return + endif + + end do ! (looping through sub-sections) + end do ! (looping through sections) + + ! ---- populate legacy strings ---- + write(info%config%maxn_str, '(i0)' ) info%config%maxn + write(info%config%kstop_str, '(i0)' ) info%config%kstop + write(info%config%pcento_str,'(es20.10)') info%config%pcento + + ! ---- domain id, run mode and tag for output files ---- + dom_id = trim(opts%domain_id) + run_mode = trim(opts%runmode) + + tag = "" + if(allocated(opts%tag)) tag = trim(opts%tag) + + ! ---- derived input filenames ---- + info%files%forcing_file = trim(dom_id)//trim(info%files%suffix_forcing) + info%files%elevbands_file = trim(dom_id)//trim(info%files%suffix_elev_bands) + + ! ---- derived output base name ---- + info%files%fname_tempry = trim(info%files%output_path)// & + trim(dom_id)//'_'//trim(info%config%fmodel_id)//'_'//trim(tag) + + ! ---- final filenames ---- + info%files%fname_netcdf_forc = trim(info%files%input_path)//trim(info%files%forcing_file) + info%files%fname_netcdf_runs = trim(info%files%fname_tempry)//'_runs_'//trim(run_mode)//'.nc' + info%files%fname_netcdf_para = trim(info%files%fname_tempry)//'_para_'//trim(run_mode)//'.nc' + + end subroutine read_fuse_control_file + + ! ------------------------------------------------------------------------------------- + ! ------------------------------------------------------------------------------------- - read(unt,'(a)')temp - read(unt,*)date_start_sim - read(unt,*)date_end_sim - read(unt,*)date_start_eval - read(unt,*)date_end_eval - read(unt,*)numtim_sub_str - - read(unt,'(a)')temp - read(unt,*)METRIC - read(unt,*)TRANSFO - - read(unt,'(a)')temp - read(unt,*)MAXN_STR - read(unt,*)KSTOP_STR - read(unt,*)PCENTO_STR + ! ----- export domain config variables to legacy modules ------------------------------ + + subroutine export_domain_to_legacy(info) + use model_defn, only: FNAME_TEMPRY, FNAME_NETCDF_RUNS, FNAME_NETCDF_PARA + use multiparam, only: MAXN, KSTOP, PCENTO + use multiforce, only: forcefile + + implicit none + + type(fuse_info), intent(in) :: info + + ! ---- populate legacy module globals ---- + + SETNGS_PATH = trim(info%files%setngs_path) + INPUT_PATH = trim(info%files%input_path) + OUTPUT_PATH = trim(info%files%output_path) + suffix_forcing = trim(info%files%suffix_forcing) + suffix_elev_bands = trim(info%files%suffix_elev_bands) + FORCINGINFO = trim(info%files%forcinginfo) + CONSTRAINTS = trim(info%files%constraints) + MOD_NUMERIX = trim(info%files%mod_numerix) + M_DECISIONS = trim(info%files%m_decisions) + + FMODEL_ID = trim(info%config%fmodel_id) + Q_ONLY = info%config%q_only + + date_start_sim = trim(info%config%date_start_sim) + date_end_sim = trim(info%config%date_end_sim) + date_start_eval = trim(info%config%date_start_eval) + date_end_eval = trim(info%config%date_end_eval) + numtim_sub_str = trim(info%config%numtim_sub_str) + + METRIC = trim(info%config%metric) + TRANSFO = trim(info%config%transfo) + + MAXN = info%config%maxn + KSTOP = info%config%kstop + PCENTO = info%config%pcento + + MAXN_str = trim(info%config%maxn_str) + KSTOP_str = trim(info%config%kstop_str) + PCENTO_str = trim(info%config%pcento_str) + + ! populate module model_defn + FNAME_TEMPRY = trim(info%files%fname_tempry) + FNAME_NETCDF_RUNS = trim(info%files%fname_netcdf_runs) + FNAME_NETCDF_PARA = trim(info%files%fname_netcdf_para) - close(unt) + ! populate module multiforce + forcefile = trim(info%files%forcing_file) - ! Convert Q_ONLY to logical - if(Q_ONLY_STR=='TRUE')then - Q_ONLY = .TRUE. - elseif(Q_ONLY_STR=='FALSE')then - Q_ONLY = .FALSE. - else - message="Q_ONLY must be either TRUE or FALSE" - err=20; return - endif + ! populate shared public variable in this module (fuse_filemanager) + MBANDS_NC = trim(info%files%elevbands_file) - PRINT*, 'Q_ONLY', Q_ONLY + ! populate module multiparam + MAXN = info%config%maxn + KSTOP = info%config%kstop + PCENTO = info%config%pcento - ! process paths a bit - if(SETNGS_PATH(1:1)==defpathSymb)SETNGS_PATH=trim(defpath)//SETNGS_PATH(2:) - if( INPUT_PATH(1:1)==defpathSymb) INPUT_PATH=trim(defpath)//INPUT_PATH (2:) - if(OUTPUT_PATH(1:1)==defpathSymb)OUTPUT_PATH=trim(defpath)//OUTPUT_PATH(2:) + ! ---- logging ---- + print *, 'Paths defined in file manager:' + print *, 'SETNGS_PATH:', trim(info%files%setngs_path) + print *, 'INPUT_PATH:', trim(info%files%input_path) + print *, 'OUTPUT_PATH:', trim(info%files%output_path) - PRINT *, 'Paths defined in file manager:' - PRINT *, 'SETNGS_PATH:', TRIM(SETNGS_PATH) - PRINT *, 'INPUT_PATH:', TRIM(INPUT_PATH) - PRINT *, 'OUTPUT_PATH:', TRIM(OUTPUT_PATH) + print *, 'Dates defined in file manager:' + print *, 'date_start_sim:', trim(info%config%date_start_sim) + print *, 'date_end_sim:', trim(info%config%date_end_sim) + print *, 'date_start_eval:', trim(info%config%date_start_eval) + print *, 'date_end_eval:', trim(info%config%date_end_eval) + print *, 'numtim_sub_str:', trim(info%config%numtim_sub_str) - PRINT *, 'Dates defined in file manager:' - PRINT *, 'date_start_sim:', TRIM(date_start_sim) - PRINT *, 'date_end_sim:', TRIM(date_end_sim) - PRINT *, 'date_start_eval:', TRIM(date_start_eval) - PRINT *, 'date_end_eval:', TRIM(date_end_eval) - PRINT *, 'numtim_sub_str:', TRIM(numtim_sub_str) + print *, 'Q_ONLY', info%config%q_only - ! End procedure here - endsubroutine fuse_SetDirsUndPhiles + end subroutine export_domain_to_legacy + !---------------------------------------------------- END MODULE fuse_filemanager diff --git a/build/FUSE_SRC/util/selectmodl.f90 b/build/FUSE_SRC/util/selectmodl.f90 index bb3269d..026603c 100644 --- a/build/FUSE_SRC/util/selectmodl.f90 +++ b/build/FUSE_SRC/util/selectmodl.f90 @@ -24,7 +24,7 @@ SUBROUTINE SELECTMODL(FUSE_ID,ERR,MESSAGE) IMPLICIT NONE ! Input !INTEGER(I4B), INTENT(IN), OPTIONAL :: FUSE_ID ! identifier for FUSE model -CHARACTER(LEN=6), INTENT(IN), OPTIONAL :: FUSE_ID ! identifier for FUSE model +CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: FUSE_ID ! identifier for FUSE model ! Output INTEGER(I4B), INTENT(OUT) :: ERR ! error code CHARACTER(LEN=*), INTENT(OUT) :: MESSAGE ! error message @@ -67,7 +67,6 @@ SUBROUTINE SELECTMODL(FUSE_ID,ERR,MESSAGE) ! --------------------------------------------------------------------------------------- ! (0) INITIALIZE ! --------------------------------------------------------------------------------------- - NAME_FMT=1 ! format for the naming convention ICOUNT =0 IX_MODEL=0 @@ -82,8 +81,7 @@ SUBROUTINE SELECTMODL(FUSE_ID,ERR,MESSAGE) !CFILE = TRIM(SETNGS_PATH)//M_DECISIONS ! control file info shared in MODULE ddirectory CFILE = TRIM(SETNGS_PATH)//'fuse_zDecisions_'//TRIM(FUSE_ID)//'.txt' ! control file info shared in MODULE ddirectory - -INQUIRE(FILE=CFILE,EXIST=LEXIST) ! check that control file exists +INQUIRE(FILE=trim(CFILE),EXIST=LEXIST) ! check that control file exists IF (.not.LEXIST) THEN message="f-SELECTMODL/decisions file '"//trim(CFILE)//"' does not exist" err=100; return diff --git a/build/Makefile b/build/Makefile index 62cc33a..9c2e4d3 100755 --- a/build/Makefile +++ b/build/Makefile @@ -48,14 +48,14 @@ $(VERSIONFILE): | $(GENINC) printf "character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '%s'\n" "$(GITHASH)"; \ } > $@ -#======================================================================== -# Define the libraries, driver programs, and executables -#======================================================================== - # default Fortran compiler is set to `gfortran` # other options: ifort FC = gfortran +#======================================================================== +# Define the NetCDF libraries +#======================================================================== + # find HDF5 # Check if pkg-config is available for HDF5 # Check if all required environment variables are set @@ -112,6 +112,44 @@ endif INCLUDES += -I$(HDF5_INCLUDE_DIR) -I$(NETCDF_C_INCLUDE) -I$(NETCDF_F_INCLUDE) LIBS += -L$(HDF5_LIB_DIR) -lhdf5 -lhdf5_hl -L$(NETCDF_F_LIB) -lnetcdff -L$(NETCDF_C_LIB) -lnetcdf +#======================================================================== +# Define the TOML-f libraries +#======================================================================== + +# Optional user override: set TOMLF_PREFIX=/path/to/toml-f/prefix +# Otherwise prefer pkgconf, then Homebrew. +ifeq ($(strip $(TOMLF_PREFIX)),) + # No user override: try pkgconf first + ifneq ($(shell pkgconf --exists toml-f && echo yes),) + TOMLF_PREFIX := $(shell pkgconf --variable=prefix toml-f) + TOMLF_INCLUDE := $(shell pkgconf --variable=includedir toml-f)/toml-f + TOMLF_LIB := $(shell pkgconf --variable=libdir toml-f) + else + # Fallback to Homebrew + TOMLF_PREFIX := $(shell brew --prefix toml-f 2>/dev/null) + TOMLF_INCLUDE := $(TOMLF_PREFIX)/include/toml-f + TOMLF_LIB := $(TOMLF_PREFIX)/lib + endif +else + # User override provided + TOMLF_INCLUDE := $(TOMLF_PREFIX)/include/toml-f + TOMLF_LIB := $(TOMLF_PREFIX)/lib +endif + +# toml-f module directory (where *.mod live on Homebrew) +TOMLF_MODDIR := $(TOMLF_INCLUDE)/modules + +# RPATH (macOS: runtime search path for dylibs) +RPATHS += -Wl,-rpath,$(TOMLF_LIB) + +# add toml-f include+lib +INCLUDES += -I$(TOMLF_MODDIR) -I$(TOMLF_INCLUDE) +LIBS += -L$(TOMLF_LIB) -ltoml-f + +$(info TOMLF_PREFIX = $(TOMLF_PREFIX)) +$(info TOMLF_INCLUDE = $(TOMLF_INCLUDE)) +$(info TOMLF_MODDIR = $(TOMLF_MODDIR)) +$(info TOMLF_LIB = $(TOMLF_LIB)) $(info INCLUDES are $(INCLUDES)) $(info LIBS are $(LIBS)) @@ -423,7 +461,7 @@ all: compile install clean # compile target compile: sce_16plus.o $(VERSIONFILE) $(FC) $(FUSE_ALL) $(DRIVER) \ - $(FFLAGS) $(LIBS) $(INCLUDES) -o $(DRIVER_EX) + $(FFLAGS) $(LIBS) $(RPATHS) $(INCLUDES) -o $(DRIVER_EX) # Remove object files clean: diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index e25e401..2d9c8c5 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-22T16:36:12Z' -character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/driver' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'dc8df16c4488b031b0c4a5902413e766eaac4d47' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-23T00:57:22Z' +character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/inputs' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '3adde8a66ad2c4deb40cf346f69fd7438be98075' From 59eed4a2d881f443e3d3c64aab3eaba2647ce20e Mon Sep 17 00:00:00 2001 From: Martyn Clark Date: Mon, 23 Feb 2026 19:08:40 -0700 Subject: [PATCH 11/11] clean up transition to new data structures --- build/FUSE_SRC/driver/fuse_evaluate.f90 | 10 +- build/FUSE_SRC/driver/setup_domain.f90 | 56 ++-- build/FUSE_SRC/netcdf/domain_decomp.f90 | 1 - build/FUSE_SRC/netcdf/get_domain_dims.f90 | 16 +- build/FUSE_SRC/netcdf/get_gforce.f90 | 273 +++++++----------- build/FUSE_SRC/prelim/force_info.f90 | 254 ---------------- build/FUSE_SRC/prelim/getnumerix.f90 | 2 +- build/FUSE_SRC/runtime/get_time_windows.f90 | 40 ++- build/FUSE_SRC/share/globaldata.f90 | 6 +- build/FUSE_SRC/types/info_types.f90 | 32 +- build/FUSE_SRC/types/work_types.f90 | 2 - build/FUSE_SRC/util/alloc_domain.f90 | 8 +- build/FUSE_SRC/util/fuse_fileManager.f90 | 73 +++-- .../time_io.f90 => util/time_utils.f90} | 69 +---- build/Makefile | 7 +- build/generated/fuseversion.inc | 6 +- 16 files changed, 267 insertions(+), 588 deletions(-) delete mode 100644 build/FUSE_SRC/prelim/force_info.f90 rename build/FUSE_SRC/{netcdf/time_io.f90 => util/time_utils.f90} (66%) diff --git a/build/FUSE_SRC/driver/fuse_evaluate.f90 b/build/FUSE_SRC/driver/fuse_evaluate.f90 index 4faecd1..2cdcd84 100644 --- a/build/FUSE_SRC/driver/fuse_evaluate.f90 +++ b/build/FUSE_SRC/driver/fuse_evaluate.f90 @@ -208,10 +208,11 @@ end subroutine initialize_run subroutine run_time_loop(info, work, output_flag, ierr, message) use globaldata, only: isPrint + use multiforce, only: timDat ! NOTE: used in legacy cides use multiforce, only: nspat1, nspat2, DELTIM, sim_beg, sim_end, numtim_sub use multistate, only: gState_3d use multibands, only: MBANDS_VAR_4d - use time_io, only: get_modtim + use time_utils, only: caldatss use getPETgrid_module, only: getPETgrid use get_gforce_module, only: get_gforce_3d use put_output_module, only: put_output @@ -300,9 +301,10 @@ subroutine run_time_loop(info, work, output_flag, ierr, message) sim_idx = chunk_start_sim + sub_idx - 1 ! get the model time - CALL get_modtim(info%files%ncid_forc, in_idx, ierr, message) - IF(ierr/=0) stop TRIM(message) - + call caldatss(info%time%jdate(in_idx), work%step%time%iy, work%step%time%im, work%step%time%id, & + work%step%time%ih, work%step%time%imin, work%step%time%dsec) + timDat = work%step%time ! NOTE: used in the legacy data structures + ! compute potential ET IF(computePET) CALL getPETgrid(ierr,message) IF(ierr/=0) stop TRIM(message) diff --git a/build/FUSE_SRC/driver/setup_domain.f90 b/build/FUSE_SRC/driver/setup_domain.f90 index d0f3914..d1f02da 100644 --- a/build/FUSE_SRC/driver/setup_domain.f90 +++ b/build/FUSE_SRC/driver/setup_domain.f90 @@ -16,12 +16,8 @@ module setup_domain_module subroutine setup_domain(opts, info, domain, ierr, message) ! access subroutines - use netcdf, only: nf90_open, nf90_nowrite, nf90_strerror ! NetCDF functions + use netcdf, only: nf90_open, nf90_nowrite, nf90_strerror ! NetCDF functions USE fuse_fileManager, only: read_fuse_control_file ! sets directories and filenames - USE fuse_fileManager, only: export_domain_to_legacy ! populates legacy modules - - USE force_info_module, only: force_info ! get forcing info for NetCDF files - USE get_gforce_module, only: get_varID ! list of var ids USE domain_dims_module, only: get_domain_dims ! get nx, ny, nt, and nbands USE domain_decomp_module, only: get_domain_decomp_indices ! get MPI domain decomposition indices @@ -29,6 +25,7 @@ subroutine setup_domain(opts, info, domain, ierr, message) USE time_windows_module, only: get_time_windows ! get info on the rolling time windows USE time_windows_module, only: export_time_to_multiforce ! populate legacy multiforce modules + USE get_gforce_module, only: get_forcing_varids ! get name/varid table for forcing variables USE get_gforce_module, only: read_latlon_2d ! read lat/lon USE read_elevbands_module, only: read_elevbands ! read elevation bands @@ -57,29 +54,17 @@ subroutine setup_domain(opts, info, domain, ierr, message) call read_fuse_control_file(trim(opts%control_file), opts, info, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! populate legacy modules - call export_domain_to_legacy(info) - - ! ----- read information on numerical decisions and forcing files ----------------------- - - ! defines method/parameters used for numerical solution based on numerix file - ! NOTE: This routine supports the legacy FUSE v1 numerics experiments - CALL GETNUMERIX(IERR,CMESSAGE) - if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! ----- read domain metadata ------------------------------------------------------------ - ! get forcing info from the txt file - ! NOTE: This will soon be replaced with the TOML file so keeping it visible for now - ! -- forcing info is text that describes the forcing NetCDF files (TODO: needs improvement) - call force_info(ierr,cmessage) - if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! populate domain structure with dimension lengths ! -- nx_global, ny_global, nt_global, n_bands call get_domain_dims(info, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + ! get indices for MPI decomposition of the spatial domain: y_start_global, ny_local + ! NOTE: These indices will be used later to read different subsets of forcing data for different ranks + call get_domain_decomp_indices(info) + ! ----- read grid info and define indices for MPI domain decomposition ------------------ ! open NetCDF forcing file @@ -88,32 +73,33 @@ subroutine setup_domain(opts, info, domain, ierr, message) if(isPrint) print *, 'Open forcing file:', trim(info%files%fname_netcdf_forc) if(isPrint) PRINT *, 'NCID_FORC is', info%files%ncid_forc - ! get indices for MPI decomposition of the spatial domain: y_start_global, ny_local - ! NOTE: These indices will be used later to read different subsets of forcing data for different ranks - call get_domain_decomp_indices(info) - ! ----- Compute time indices for sim/eval windows and subperiod chunk size -------------- - - call get_time_windows(info, ierr, cmessage) + ! + ! Reads the forcing-file NetCDF time coordinate (and units), and: + ! - builds a Julian-day time axis and timestep in days + ! - maps the user-specified simulation/evaluation date ranges into index windows + ! (and optional subperiod chunks) stored in info%time + call get_time_windows(info%files%ncid_forc, info, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! export info%time -> multiforce to keep legacy code working - call export_time_to_multiforce(info) - ! ----- Allocate space for domain data -------------------------------------------------- ! allocate space for the arrays in the domain%data structure call allocate_domain_data(info, domain, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! ----- Read lat/lon and elevation band arrays ----------------------------------------- + ! ----- Read lat/lon, elevation band arrays, and forcing var ids ----------------------- ! read lat/lon and store in the domain%data%coords structure call read_latlon_2d(info%files%ncid_forc, info, domain%coords, ierr, message) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif ! read elevation bands information and store in the domain%data structure - call read_elevbands(info, domain, ierr, message) + call read_elevbands(info, domain, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif + + call get_forcing_varids(info%files%ncid_forc, info, ierr, cmessage) + if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif ! ----- Routines that use the old structures -------------------------------------------- @@ -121,9 +107,9 @@ subroutine setup_domain(opts, info, domain, ierr, message) call set_legacy_arrays(info, domain, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif - ! get NetCDF ID for each variable of the forcing file - ! NOTE: populates data structures in multiforce - call get_varID(info%files%ncid_forc, ierr, cmessage) + ! defines method/parameters used for numerical solution based on numerix file + ! NOTE: This routine supports the legacy FUSE v1 numerics experiments + CALL GETNUMERIX(IERR,CMESSAGE) if (ierr/=0)then; message=trim(message)//trim(cmessage); ierr=20; return; endif print*, 'end of setup_domain' diff --git a/build/FUSE_SRC/netcdf/domain_decomp.f90 b/build/FUSE_SRC/netcdf/domain_decomp.f90 index 503e09f..27e0a49 100644 --- a/build/FUSE_SRC/netcdf/domain_decomp.f90 +++ b/build/FUSE_SRC/netcdf/domain_decomp.f90 @@ -1,6 +1,5 @@ module domain_decomp_module - use nrtype use info_types, only: fuse_info implicit none diff --git a/build/FUSE_SRC/netcdf/get_domain_dims.f90 b/build/FUSE_SRC/netcdf/get_domain_dims.f90 index 3e74333..dcb8388 100644 --- a/build/FUSE_SRC/netcdf/get_domain_dims.f90 +++ b/build/FUSE_SRC/netcdf/get_domain_dims.f90 @@ -49,7 +49,6 @@ subroutine read_forcing_dimensions(filepath, info, ierr, message) use nrtype use netcdf use info_types, only: fuse_info - use multiforce, only: vname_aprecip implicit none character(*), intent(in) :: filepath @@ -65,11 +64,12 @@ subroutine read_forcing_dimensions(filepath, info, ierr, message) integer(i4b) :: idim,dimlen integer(i4b) :: time_varid - associate(grid_flag => info%space%grid_flag, & - nx_global => info%space%nx_global, & - ny_global => info%space%ny_global, & - nt_global => info%time%nt_global, & - nInput => info%config%nInput) + associate(precip_name => info%files%precip_name, & + grid_flag => info%space%grid_flag, & + nx_global => info%space%nx_global, & + ny_global => info%space%ny_global, & + nt_global => info%time%nt_global, & + nInput => info%config%nInput) ierr=0; message="read_forcing_dimensions/" @@ -82,9 +82,9 @@ subroutine read_forcing_dimensions(filepath, info, ierr, message) endif ! --- get dimension lengths from precip variable shape --- - ierr = nf90_inq_varid(ncid, trim(vname_aprecip), varid) + ierr = nf90_inq_varid(ncid, trim(precip_name), varid) if(ierr /= nf90_noerr) then - message = trim(message)//"cannot find var '"//trim(vname_aprecip)//"': "//trim(nf90_strerror(ierr)) + message = trim(message)//"cannot find var '"//trim(precip_name)//"': "//trim(nf90_strerror(ierr)) return endif diff --git a/build/FUSE_SRC/netcdf/get_gforce.f90 b/build/FUSE_SRC/netcdf/get_gforce.f90 index 2f56bbb..b95d36b 100644 --- a/build/FUSE_SRC/netcdf/get_gforce.f90 +++ b/build/FUSE_SRC/netcdf/get_gforce.f90 @@ -4,18 +4,24 @@ module get_gforce_module use info_types, only: fuse_info use netcdf -use time_io + +use globaldata, only: NVAR_FORC +use globaldata, only: iPRECIP, iTEMP, iPET, iQOBS implicit none private -public::get_varid -public::get_gforce_3d -public::read_latlon_2d +public :: get_gforce_3d +public :: read_latlon_2d +public :: get_forcing_varids contains + ! -------------------------------------------------------------------------------------- + ! -------------------------------------------------------------------------------------- + ! -------------------------------------------------------------------------------------- + subroutine read_latlon_2d(ncid, info, coord, ierr, message) use netcdf @@ -50,15 +56,15 @@ subroutine read_latlon_2d(ncid, info, coord, ierr, message) if (.not. allocated(coord%lon_2d)) allocate(coord%lon_2d(nx, ny)) ! --- get varids --- - ierr = nf90_inq_varid(ncid, "latitude", vid_lat) + ierr = nf90_inq_varid(ncid, trim(info%files%latitude_name), vid_lat) if(ierr /= nf90_noerr) then - message = trim(message)//"missing var 'latitude': "//trim(nf90_strerror(ierr)) + message = trim(message)//"missing var '"//trim(info%files%latitude_name)//"': "//trim(nf90_strerror(ierr)) return endif - ierr = nf90_inq_varid(ncid, "longitude", vid_lon) + ierr = nf90_inq_varid(ncid, trim(info%files%longitude_name), vid_lon) if(ierr /= nf90_noerr) then - message = trim(message)//"missing var 'longitude': "//trim(nf90_strerror(ierr)) + message = trim(message)//"missing var '"//trim(info%files%longitude_name)//"': "//trim(nf90_strerror(ierr)) return endif @@ -179,107 +185,102 @@ end subroutine read_latlon_2d ! -------------------------------------------------------------------------------------- subroutine get_dimIds(ncid, varid, nexpect, varDimIDs, ierr, message) ! used to get the vector of dimension ids for a given variable + implicit none + ! input integer(i4b),intent(in) :: ncid ! NetCDF file ID integer(i4b),intent(in) :: varid ! NetCDF variable ID integer(i4b),intent(in) :: nexpect ! number of dimensions expected + ! output integer(i4b),intent(out) :: varDimIDs(nexpect) ! vector of dimension IDs integer(i4b),intent(out) :: ierr ! error code character(*), intent(out) :: message ! error message + ! internal variables integer(i4b) :: nVarDims ! number of dimensions for given variable + ! initialize error control ierr=0; message='get_dimIds/' + ! get number of dimensions ierr = nf90_inquire_variable(ncid, varid, ndims=nVarDims) if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif + ! check number of dimensions if(nVarDims/=nexpect)then; message=trim(message)//'unexpected number of dimensions for variable'; return; endif + ! get vector of dimension IDs ierr = nf90_inquire_variable(ncid, varid, dimids=varDimIDs(:nVarDims)) if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - end subroutine get_dimIds - ! -------------------------------------------------------------------------------------- - - SUBROUTINE get_varID(ncid,ierr,message) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Nans Addor, 2017 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Get NetCDF ID for each variable of the forcing file - ! --------------------------------------------------------------------------------------- - ! Modules Modified: - ! ----------------- - ! MODULE multiforce -- populate structure ncid_var%(*) - ! --------------------------------------------------------------------------------------- - USE multiforce, only: nForce, nInput ! number of forcing variables - USE multiforce, only: ncid_var ! NetCDF forcing variable ID - - USE multiforce,only:forcefile ! name of forcing file - USE multiforce,only:vname_aprecip ! variable name: precipitation - USE multiforce,only:vname_airtemp ! variable name: temperature - USE multiforce,only:vname_spechum ! variable name: specific humidity - USE multiforce,only:vname_airpres ! variable name: surface pressure - USE multiforce,only:vname_swdown ! variable name: downward shortwave radiation - USE multiforce,only:vname_potevap ! variable name: potential ET - USE multiforce,only:vname_q ! variable indice: observed discharge - - USE multiforce,only:ilook_aprecip ! variable indice: precipitation - USE multiforce,only:ilook_airtemp ! variable indice: temperature - USE multiforce,only:ilook_spechum ! variable indice: specific humidity - USE multiforce,only:ilook_airpres ! variable indice: surface pressure - USE multiforce,only:ilook_swdown ! variable indice: downward shortwave radiation - USE multiforce,only:ilook_potevap ! variable indice: potential ET - USE multiforce,only:ilook_q ! variable indice: observed discharge - - IMPLICIT NONE - ! input - integer(i4b), intent(in) :: ncid ! NetCDF file ID - ! output - integer(i4b), intent(out) :: ierr ! error code - character(*), intent(out) :: message ! error message - ! internal - integer(i4b),parameter :: strLen=1024 ! length of character string - type names - character(len=strLen) :: vname ! singlecharacter strings - end type names - type(names),dimension(nForce) :: cVec ! names of character strings - integer(i4b) :: iVar ! loop through forcing data - - ! --------------------------------------------------------------------------------------- - ! initialize error control - ierr=0; message='get_varID/' - - ! get the vector of variable names - cVec(ilook_aprecip)%vname = trim(vname_aprecip) ! variable name: precipitation - cVec(ilook_potevap)%vname = trim(vname_potevap) ! variable name: potential ET - cVec(ilook_airtemp)%vname = trim(vname_airtemp) ! variable name: temperature - cVec(ilook_q)%vname = trim(vname_q) ! variable name: observed discharge - cVec(ilook_spechum)%vname = trim(vname_spechum) ! variable name: specific humidity - cVec(ilook_airpres)%vname = trim(vname_airpres) ! variable name: surface pressure - cVec(ilook_swdown)%vname = trim(vname_swdown) ! variable name: downward shortwave radiation + end subroutine get_dimIds - do ivar=1,nInput + ! -------------------------------------------------------------------------------------- - ! get the variable ID - ierr = nf90_inq_varid(ncid, trim(cVec(iVar)%vname), ncid_var(ivar)) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr))//'[variable='//trim(cVec(iVar)%vname)//']'; return; endif + subroutine get_forcing_varids(ncid, info, ierr, message) + implicit none + integer(i4b), intent(in) :: ncid + type(fuse_info), intent(inout) :: info + integer(i4b), intent(out) :: ierr + character(*), intent(out) :: message + + integer(i4b) :: ivar + + ierr = 0 + message = "get_forcing_varids/" + + ! get table of name/varid pairs (names set in TOML read) + info%files%forc%name(iPRECIP) = info%files%precip_name + info%files%forc%name(iTEMP) = info%files%temp_name + info%files%forc%name(iPET) = info%files%pet_name + info%files%forc%name(iQOBS) = info%files%qobs_name + + info%files%forc%varid(:) = -1 + + ! get varid for each forcing variable + do ivar = 1, NVAR_FORC + + if(info%space%grid_flag .and. ivar == iQOBS) cycle ! skips qobs if a grid + + call lookup_varid(ncid, trim(info%files%forc%name(ivar)), info%files%forc%varid(ivar), ierr, message) + if(ierr/=0) return + + end do ! ivar + + contains + + subroutine lookup_varid(ncid, vname, vid, ierr, message) - END DO + integer(i4b), intent(in) :: ncid + character(len=*), intent(in) :: vname + integer(i4b), intent(inout) :: vid + integer(i4b), intent(inout) :: ierr + character(*), intent(inout) :: message + + if (len_trim(vname) == 0) then + ierr = 20 + message = trim(message)//"empty variable name" + return + end if + + ierr = nf90_inq_varid(ncid, trim(vname), vid) + if (ierr /= 0) then + message = trim(message)//trim(nf90_strerror(ierr))//" [var="//trim(vname)//"]" + end if + + end subroutine lookup_varid - END SUBROUTINE get_varID + end subroutine get_forcing_varids + SUBROUTINE get_gforce_3d(info, itim_start, numtim, ierr, message) ! --------------------------------------------------------------------------------------- ! Creator: ! -------- ! Nans Addor, based on Martyn Clark's get_gforce + ! Modified by Martyn Clark to simplify and update to new data structures, 02/2026 ! --------------------------------------------------------------------------------------- ! Purpose: ! -------- @@ -289,116 +290,66 @@ SUBROUTINE get_gforce_3d(info, itim_start, numtim, ierr, message) ! ----------------- ! MODULE multiforce -- populate structure GFORCE_3d(*,*)%(*) ! --------------------------------------------------------------------------------------- - USE fuse_fileManager,only:INPUT_PATH ! defines data directory - USE multiforce,only:forcefile ! name of forcing file - USE multiforce,only:nSpat1, nSpat2, numtim_sub ! dimensions of local slice - USE multiforce,only:startSpat2 ! starting y index for data read - USE multiforce,only:vname_aprecip ! variable name: precipitation - USE multiforce,only:vname_airtemp ! variable name: temperature - USE multiforce,only:vname_spechum ! variable name: specific humidity - USE multiforce,only:vname_airpres ! variable name: surface pressure - USE multiforce,only:vname_swdown ! variable name: downward shortwave radiation - USE multiforce,only:vname_potevap ! variable name: potential ET - USE multiforce,only:vname_q ! variable name: observed discharge - - USE multiforce,only:ilook_aprecip ! variable indice: precipitation - USE multiforce,only:ilook_airtemp ! variable indice: temperature - USE multiforce,only:ilook_spechum ! variable indice: specific humidity - USE multiforce,only:ilook_airpres ! variable indice: surface pressure - USE multiforce,only:ilook_swdown ! variable indice: downward shortwave radiation - USE multiforce,only:ilook_potevap ! variable indice: potential ET - USE multiforce,only:ilook_q ! variable indice: observed discharge - - USE multiforce,only:ncid_var ! NetCDF ID for forcing variables - USE multiforce,only:amult_ppt,amult_pet ! multipliers o convert to mm/day USE multiforce,only:gForce_3d ! gridded forcing data - USE multiforce,only:ancilF_3d ! ancillary forcing data - USE multiforce,only:nForce, nInput ! number of forcing variables USE multiforce,only:aValid ! time series of lumped forcing/response data IMPLICIT NONE + ! input type(fuse_info), intent(in) :: info ! info data structure that holds spatial indices integer(i4b), intent(in) :: itim_start ! index of model time step - start of the period to extract integer(i4b), intent(in) :: numtim ! number of model time steps to extract + ! output integer(i4b), intent(out) :: ierr ! error code character(*), intent(out) :: message ! error message + ! internal - real(sp),parameter :: amiss=-9999._sp ! value for missing data - integer(i4b),parameter :: strLen=1024 ! length of character string integer(i4b) :: iVar ! loop through forcing data real(sp),dimension(:,:,:),allocatable :: gTemp ! temporary 3d grid - type names - character(len=strLen) :: vname ! singlecharacter strings - end type names - type(names),dimension(nForce) :: cVec ! names of character strings - logical(lgt),dimension(nForce) :: lCheck ! check the existence of variables - - ! integer(i4b) :: nx, ny, ystart - ! integer(i4b) :: start_3d(3), count_3d(3) - ! - ! nx = info%space%nx_local - ! ny = info%space%ny_local - ! ystart = info%space%y_start_global - ! - ! start_3d = (/ 1, ystart, itim_start/) - ! count_3d = (/nx, ny, numtim/) - - - ! --------------------------------------------------------------------------------------- + integer(i4b) :: nx, ny ! grid dimensions + integer(i4b) :: ystart ! start index iin input file (for MPI) + integer(i4b) :: start_3d(3) ! start indices in NetCDF file + integer(i4b) :: count_3d(3) ! count in NetCDF file + ! initialize error control ierr=0; message='get_gforce_3d/' ! --------------------------------------------------------------------------------------- - ! initialize lCheck - lCheck=.false. - + ! 3-d grid dimensions + nx = info%space%nx_local + ny = info%space%ny_local + ystart = info%space%y_start_global ! start index in input file (for MPI) + + ! indices for NetCDF rea + start_3d = (/ 1, ystart, itim_start/) + count_3d = (/nx, ny, numtim/) + ! allocate space for the temporary grid - allocate(gTemp(nSpat1,nSpat2,numtim), stat=ierr) + allocate(gTemp(nx,ny,numtim), stat=ierr) if(ierr/=0)then; message=trim(message)//'problem allocating space for gTemp'; return; endif - ! get the vector of variable names - cVec(ilook_aprecip)%vname = trim(vname_aprecip) ! variable name: precipitation - cVec(ilook_potevap)%vname = trim(vname_potevap) ! variable name: potential ET - cVec(ilook_airtemp)%vname = trim(vname_airtemp) ! variable name: temperature - cVec(ilook_q)%vname = trim(vname_q) ! variable name: observed discharge - cVec(ilook_spechum)%vname = trim(vname_spechum) ! variable name: specific humidity - cVec(ilook_airpres)%vname = trim(vname_airpres) ! variable name: surface pressure - cVec(ilook_swdown)%vname = trim(vname_swdown) ! variable name: downward shortwave radiation - ! get forcing grids - do ivar=1,nInput + do ivar = 1, NVAR_FORC + + if(info%space%grid_flag .and. ivar == iQOBS) cycle ! skips qobs if a grid ! get the data - ierr = nf90_get_var(info%files%ncid_forc, ncid_var(ivar), gTemp, start=(/1,startSpat2,itim_start/), count=(/nSpat1,nSpat2,numtim/)); CALL HANDLE_ERR(IERR) + ierr = nf90_get_var(info%files%ncid_forc, info%files%forc%varid(ivar), gTemp, start=start_3d, count=count_3d) if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif ! save the data in the structure -- and convert fluxes to mm/day - if(trim(cVec(iVar)%vname) == trim(vname_aprecip) )then - - gForce_3d(:,:,1:numtim)%ppt = gTemp(:,:,:)*amult_ppt; lCheck(ilook_aprecip) = .true. - - endif - - if(trim(cVec(iVar)%vname) == trim(vname_potevap) )then - gForce_3d(:,:,1:numtim)%pet = gTemp(:,:,:)*amult_pet; lCheck(ilook_potevap) = .true. - endif - - if(trim(cVec(iVar)%vname) == trim(vname_airtemp) )then - gForce_3d(:,:,1:numtim)%temp = gTemp(:,:,:); lCheck(ilook_airtemp) = .true. - endif - - if(trim(cVec(iVar)%vname) == trim(vname_q) )then - aValid(:,:,1:numtim)%obsq = gTemp(:,:,:); lCheck(ilook_q) = .true. + select case(ivar) - endif - - ! save the other variables required to compute PET - !if( trim(cVec(iVar)%vname) == trim(vname_airtemp) )then; ancilF(:,:)%airtemp = gTemp(:,:,1); lCheck(ilook_airtemp) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_spechum) )then; ancilF(:,:)%spechum = gTemp(:,:,1); lCheck(ilook_spechum) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_airpres) )then; ancilF(:,:)%airpres = gTemp(:,:,1); lCheck(ilook_airpres) = .true.; endif - !if( trim(cVec(iVar)%vname) == trim(vname_swdown) )then; ancilF(:,:)%swdown = gTemp(:,:,1); lCheck(ilook_swdown) = .true.; endif + case (iPRECIP); gForce_3d(:,:,1:numtim)%ppt = gTemp(:,:,:) + case (iTEMP) ; gForce_3d(:,:,1:numtim)%temp = gTemp(:,:,:) + case (iPET) ; gForce_3d(:,:,1:numtim)%pet = gTemp(:,:,:) + case (iQOBS) ; aValid( :,:,1:numtim)%obsq = gTemp(:,:,:) ! TODO: check dimensions (works for nx=1, ny=1) + case default + message=trim(message)//'unable to identify forcing variable' + ierr=10; return + + end select ! identify forcing variable end do ! (loop thru forcing variables) @@ -406,10 +357,6 @@ SUBROUTINE get_gforce_3d(info, itim_start, numtim, ierr, message) deallocate(gTemp, stat=ierr) if(ierr/=0)then; message=trim(message)//'problem deallocating space for gTemp'; return; endif - !PRINT *, 'PET', gForce_3d(:,:,1:numtim)%pet - !PRINT *, 'PPT', gForce_3d(:,:,1:numtim)%ppt - !PRINT *, 'TEMP', gForce_3d(:,:,1:numtim)%temp - end subroutine get_gforce_3d end module get_gforce_module diff --git a/build/FUSE_SRC/prelim/force_info.f90 b/build/FUSE_SRC/prelim/force_info.f90 deleted file mode 100644 index 7f9b6eb..0000000 --- a/build/FUSE_SRC/prelim/force_info.f90 +++ /dev/null @@ -1,254 +0,0 @@ -module force_info_module -USE nrtype -USE netcdf -implicit none -private -public::force_info -contains - - SUBROUTINE force_info(ierr,message) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2012 - ! Modified by Nans Addor to add numtim_sub for distributed modeling, 2017 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Read information describing the forcing data file - ! --------------------------------------------------------------------------------------- - ! Modules Modified: - ! ----------------- - ! MODULE multiforce -- populate variable names and time steps - ! --------------------------------------------------------------------------------------- - USE fuse_fileManager,only:SETNGS_PATH,FORCINGINFO,& ! defines data directory - INPUT_PATH - USE ascii_util_module,only:file_open ! open file (performs a few checks as well) - USE ascii_util_module,only:get_vlines ! get a list of character strings from non-comment lines - USE multiforce,only:vname_aprecip ! variable name: precipitation - USE multiforce,only:vname_airtemp ! variable name: temperature - USE multiforce,only:vname_spechum ! variable name: specific humidity - USE multiforce,only:vname_airpres ! variable name: surface pressure - USE multiforce,only:vname_swdown ! variable name: downward shortwave radiation - USE multiforce,only:vname_potevap ! variable name: potential ET - USE multiforce,only:vname_q ! variable name: runoff - USE multiforce,only:vname_iy,vname_im,vname_id ! names of time variables (day of year) - USE multiforce,only:vname_ih,vname_imin,vname_dsec ! names of time variables (time of day) - USE multiforce,only:vname_dtime ! name of time variable (time since reference time) - USE multiforce,only:deltim ! model timestep (days) - USE multiforce,only:istart,numtim_sim ! index for start of inference, and number steps in the reduced array - USE multiforce,only:amult_ppt,amult_pet,amult_q ! used to convert fluxes to mm/day - USE multiforce,only:numtim_sub ! number of time steps of subperiod (will be kept in memory) - - IMPLICIT NONE - ! output - integer(i4b), intent(out) :: ierr ! error code - character(*), intent(out) :: message ! error message - ! internal: general - integer(i4b),parameter :: strLen=1024 ! length of character strings - character(len=strLen) :: cmessage ! message of downwind routine - character(len=strLen),parameter :: cVersion='FORCINGINFO.VERSION.2.2' ! version of forcinginfo file - ! internal: read data from file - integer(i4b) :: iunit ! file unit - character(len=strLen) :: cfile ! name of control file - character(len=strLen),allocatable :: charlines(:) ! vector of character strings - ! internal: assign data - integer(i4b) :: iLine ! index of line in charlines - integer(i4b) :: ibeg_name ! start index of variable name in string charlines(iLine) - integer(i4b) :: iend_name ! end index of variable name in string charlines(iLine) - integer(i4b) :: iend_data ! end index of data in string charlines(iLine) - character(len=strLen) :: cName,cData ! name and data from charlines(iLine) - ! internal: named variables - integer(i4b),parameter :: maxinfo=22 ! maximum number of informational elements - logical(lgt),dimension(maxinfo) :: lCheck ! vector to check that we have the infomation we need - integer(i4b),parameter :: iVname_iy =1 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_im =2 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_id =3 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_ih =4 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_imin =5 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_dsec =6 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_dtime =7 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_aprecip =8 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_airtemp =9 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_spechum =10 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_airpres =11 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_swdown =12 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_potevap =13 ! named variable for element of lCheck - integer(i4b),parameter :: iVname_q =14 ! named variable for element of lCheck - integer(i4b),parameter :: iUnits_aprecip =15 ! named variable for element of lCheck - integer(i4b),parameter :: iUnits_airtemp =16 ! named variable for element of lCheck - integer(i4b),parameter :: iUnits_spechum =17 ! named variable for element of lCheck - integer(i4b),parameter :: iUnits_airpres =18 ! named variable for element of lCheck - integer(i4b),parameter :: iUnits_swdown =19 ! named variable for element of lCheck - integer(i4b),parameter :: iUnits_potevap =20 ! named variable for element of lCheck - integer(i4b),parameter :: iUnits_q =21 ! named variable for element of lCheck - integer(i4b),parameter :: iDeltim =22 ! named variable for element of lCheck - ! get units strings (used to define variable multipliers) - character(len=strLen) :: units_aprecip='undefined' ! unit string for precipitation - character(len=strLen) :: units_airtemp='undefined' ! unit string for air temperature - character(len=strLen) :: units_spechum='undefined' ! unit string for specific humidity - character(len=strLen) :: units_airpres='undefined' ! unit string for air pressure - character(len=strLen) :: units_swdown ='undefined' ! unit string for downward sw radiation - character(len=strLen) :: units_potevap='undefined' ! unit string for potential ET - character(len=strLen) :: units_q ='undefined' ! unit string for runoff - integer(i4b) :: iVar ! loop through variables - ! --------------------------------------------------------------------------------------- - ! initialize error control - ierr=0; message='force_info/' - ! --------------------------------------------------------------------------------------- - ! build filename - cfile = trim(SETNGS_PATH)//trim(FORCINGINFO) ! uses paths and filenames from MODULE fuse_fileManager - - print *, 'Reading forcing info from:' - print *, trim(cfile) - ! open file (also returns un-used file unit used to open the file) - call file_open(trim(cfile),iunit,ierr,cmessage) - if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif - ! get a list of character strings from non-comment lines - call get_vlines(iunit,charlines,ierr,cmessage) - if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif - ! close the file unit - close(iunit) - ! --------------------------------------------------------------------------------------- - ! initialize the check vector - lCheck(:)=.false. - ! loop through the non-comment lines in the input file - do iLine=1,size(charlines) - ! identify start and end of the name and the data - ibeg_name = index(charlines(iLine),'<'); if(ibeg_name==0) ierr=20 - iend_name = index(charlines(iLine),'>'); if(iend_name==0) ierr=20 - iend_data = index(charlines(iLine),'!'); if(iend_data==0) ierr=20 - if(ierr/=0)then; message=trim(message)//'problem disentangling charlines(iLine) [string='//trim(charlines(iLine))//']'; return; endif - ! extract name of the information, and the information itself - cName = adjustl(charlines(iLine)(ibeg_name:iend_name)) - cData = adjustl(charlines(iLine)(iend_name+1:iend_data-1)) - ! put the information in its correct place - select case(trim(cName)) - ! check version - case('') - if(trim(cData)/=cVersion)then - message=trim(message)//'version mis-match [version='//trim(cData)//'; expect "'//cVersion//'"]' - ierr=20; return - endif - ! put character strings in their correct place - case(''); vname_iy = trim(cData); lCheck(iVname_iy) = .true. - case(''); vname_im = trim(cData); lCheck(iVname_im) = .true. - case(''); vname_id = trim(cData); lCheck(iVname_id) = .true. - case(''); vname_ih = trim(cData); lCheck(iVname_ih) = .true. - case(''); vname_imin = trim(cData); lCheck(iVname_imin) = .true. - case(''); vname_dsec = trim(cData); lCheck(iVname_dsec) = .true. - case(''); vname_dtime = trim(cData); lCheck(iVname_dtime) = .true. - case(''); vname_aprecip = trim(cData); lCheck(iVname_aprecip) = .true. - case(''); vname_airtemp = trim(cData); lCheck(iVname_airtemp) = .true. - case(''); vname_spechum = trim(cData); lCheck(iVname_spechum) = .true. - case(''); vname_airpres = trim(cData); lCheck(iVname_airpres) = .true. - case(''); vname_swdown = trim(cData); lCheck(iVname_swdown) = .true. - case(''); vname_potevap = trim(cData); lCheck(iVname_potevap) = .true. - case(''); vname_q = trim(cData); lCheck(iVname_q) = .true. - case(''); units_aprecip = trim(cData); lCheck(iUnits_aprecip) = .true. - case(''); units_airtemp = trim(cData); lCheck(iUnits_airtemp) = .true. - case(''); units_spechum = trim(cData); lCheck(iUnits_spechum) = .true. - case(''); units_airpres = trim(cData); lCheck(iUnits_airpres) = .true. - case(''); units_swdown = trim(cData); lCheck(iUnits_swdown) = .true. - case(''); units_potevap = trim(cData); lCheck(iUnits_potevap) = .true. - case(''); units_q = trim(cData); lCheck(iUnits_q) = .true. - ! put real numbers and integers in their correct place - case(''); read(cData,*,iostat=ierr) deltim; lCheck(iDeltim) = .true. - ! check for an unexpected string - case default - ierr=20; message=trim(message)//'do not have a case for string ['//trim(cName)//']'; return - endselect - ! check if there were any errors in the internal read statements - if(ierr/=0)then - message=trim(message)//'problem reading data for variable '//trim(cName)//'[data='//trim(cData)//']' - ierr=50; return - endif - end do ! (looping through non-comment lines in the file - - ! deallocate space for the variable line vector - deallocate(charlines, stat=ierr) - if(ierr/=0)then; message=trim(message)//'problem deallocating space for the variable line vector'; return; endif - ! check that we got all desired variables - if(any(lCheck .eqv. .false.))then - ierr=20; message=trim(message)//'missing variable' - write(*,'(a,1x,a,1x,L1)') '', trim(vname_iy), lCheck(iVname_iy) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_im), lCheck(iVname_im) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_id), lCheck(iVname_id) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_ih), lCheck(iVname_ih) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_imin), lCheck(iVname_im) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_dsec), lCheck(iVname_dsec) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_dtime), lCheck(iVname_dtime) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_aprecip), lCheck(iVname_aprecip) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_airtemp), lCheck(iVname_airtemp) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_spechum), lCheck(iVname_spechum) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_airpres), lCheck(iVname_airpres) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_swdown), lCheck(iVname_swdown) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_potevap), lCheck(iVname_potevap) - write(*,'(a,1x,a,1x,L1)') '', trim(vname_q), lCheck(iVname_q) - write(*,'(a,1x,a,1x,L1)') '', trim(units_aprecip), lCheck(iUnits_aprecip) - write(*,'(a,1x,a,1x,L1)') '', trim(units_airtemp), lCheck(iUnits_airtemp) - write(*,'(a,1x,a,1x,L1)') '', trim(units_spechum), lCheck(iUnits_spechum) - write(*,'(a,1x,a,1x,L1)') '', trim(units_airpres), lCheck(iUnits_airpres) - write(*,'(a,1x,a,1x,L1)') '', trim(units_swdown), lCheck(iUnits_swdown) - write(*,'(a,1x,a,1x,L1)') '', trim(units_potevap), lCheck(iUnits_potevap) - write(*,'(a,1x,a,1x,L1)') '', trim(units_q), lCheck(iUnits_q) - write(*,'(a,1x,f9.6,1x,L1)') '', deltim, lCheck(iDeltim) - print*, lCheck, size(lcheck) - return - endif ! if we missed a variable - - ! get multipliers for each variable - do ivar=1,3 - if(ivar==1) call get_multiplier(units_aprecip, amult_ppt, ierr, cmessage) - if(ivar==2) call get_multiplier(units_potevap, amult_pet, ierr, cmessage) - if(ivar==3) call get_multiplier(units_q, amult_q, ierr, cmessage) - if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif - end do - - PRINT *, 'Done reading forcing info' - - end subroutine force_info - - ! ***** new subroutine: get multiplier for given flux variable (L/T) - subroutine get_multiplier(cunits, amult, ierr, message) - implicit none - ! define input - character(*),intent(in) :: cunits ! units - ! define output - real(sp),intent(out) :: amult ! multiplier - integer(i4b), intent(out) :: ierr ! error code - character(*), intent(out) :: message ! error message - ! define internal variables - integer(i4b),parameter :: strLen=32 ! length of sub-strings - integer(i4b) :: ipos ! position of the "/" character - character(strLen) :: cLength ! length unit - character(strLen) :: cTime ! time unit - real(sp),parameter :: secprday=86400._sp ! number of seconds per day - real(sp),parameter :: hrprday=24._sp ! number of hours per day - ! initialize error control - ierr=0; message='get_multiplier/' - ! if units are undefined, assume mm/day and have an early return - if(trim(cunits)=='undefined')then; amult=1._sp; return; endif - ! find the position of the "/" character - ipos = index(trim(cunits),'/') - ! check the "/" character exists - if(ipos==0)then - message=trim(message)//'expect the character "/" in the units string [units='//trim(cunits)//']' - ierr=20; return - endif - ! get the length units - cLength=cunits(1:ipos-1) - if(cLength/='mm')then; ierr=20; message=trim(message)//'expect the length units to be "mm" [units='//trim(cLength)//']'; return; endif - ! get the time units - cTime=cunits(ipos+1:len_trim(cunits)) - ! get the multiplier - select case(trim(cTime)) - case('d','day'); amult=1._sp - case('h','hour'); amult=hrprday - case('s','second'); amult=secprday - case default - ierr=20; message=trim(message)//'cannot identify the time units [time units = '//trim(cTime)//']'; return - end select - end subroutine get_multiplier - -end module force_info_module diff --git a/build/FUSE_SRC/prelim/getnumerix.f90 b/build/FUSE_SRC/prelim/getnumerix.f90 index 9a4d3c5..72c4589 100644 --- a/build/FUSE_SRC/prelim/getnumerix.f90 +++ b/build/FUSE_SRC/prelim/getnumerix.f90 @@ -1,4 +1,4 @@ -SUBROUTINE GETNUMERIX(err,message) +SUBROUTINE GETNUMERIX(err, message) ! --------------------------------------------------------------------------------------- ! Creator: ! -------- diff --git a/build/FUSE_SRC/runtime/get_time_windows.f90 b/build/FUSE_SRC/runtime/get_time_windows.f90 index 84e0d46..f3c52b6 100644 --- a/build/FUSE_SRC/runtime/get_time_windows.f90 +++ b/build/FUSE_SRC/runtime/get_time_windows.f90 @@ -1,10 +1,8 @@ module time_windows_module use nrtype - use netcdf use info_types, only: fuse_info - use fuse_fileManager, only: date_start_sim, date_end_sim, date_start_eval, date_end_eval, numtim_sub_str - use time_io, only: date_extractor, juldayss + use time_utils, only: date_extractor, juldayss implicit none @@ -14,14 +12,16 @@ module time_windows_module contains - subroutine get_time_windows(info, ierr, message) + subroutine get_time_windows(ncid, info, ierr, message) + integer(i4b), intent(in) :: ncid type(fuse_info), intent(inout) :: info integer(i4b), intent(out) :: ierr character(*), intent(out) :: message integer(i4b) :: nt character(len=1024) :: units_local + real(sp) :: scale_to_days, dt_native, dt_days integer(i4b) :: ios character(len=1024) :: cmessage @@ -29,7 +29,7 @@ subroutine get_time_windows(info, ierr, message) ! ----- read forcing time axis ------------------------------------------------------ - call read_time_axis(info%files%ncid_forc, info%time%time_steps, units_local, nt, ierr, cmessage) + call read_time_axis(ncid, info%time%time_steps, units_local, nt, ierr, cmessage) if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif info%time%nt_global = nt @@ -37,18 +37,19 @@ subroutine get_time_windows(info, ierr, message) ! ----- build julian-day axis ------------------------------------------------------- - call build_julian_axis(info%time%time_steps, trim(units_local), info%time%jdate_ref, info%time%jdate, ierr, cmessage) + call build_julian_axis(info%time%time_steps, trim(units_local), & + info%time%jdate_ref, info%time%jdate, info%time%deltim_days, ierr, cmessage) if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif ! ----- compute indices for sim/eval windows ---------------------------------------- ! simulation indices - call map_dates_to_indices(info%time%jdate, date_start_sim, date_end_sim, & + call map_dates_to_indices(info%time%jdate, info%config%date_start_sim, info%config%date_end_sim, & info%time%sim_beg, info%time%sim_end, ierr, cmessage) if (ierr/=0)then; message=trim(message)//trim(cmessage); return; endif ! evaluation indices - call map_dates_to_indices(info%time%jdate, date_start_eval, date_end_eval, & + call map_dates_to_indices(info%time%jdate, info%config%date_start_eval, info%config%date_end_eval, & info%time%eval_beg, info%time%eval_end, ierr, cmessage) if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif @@ -64,7 +65,7 @@ subroutine get_time_windows(info, ierr, message) ! ----- configure sub-period windowing ---------------------------------------------- ! convert sub-period string to integer - read(numtim_sub_str,*,iostat=ios) info%time%nt_window + read(info%config%numtim_sub_str,*,iostat=ios) info%time%nt_window if(ios/=0) then ierr=1; message=trim(message)//"cannot parse numtim_sub_str"; return endif @@ -78,6 +79,11 @@ subroutine get_time_windows(info, ierr, message) ! keep nt_window as user-chosen chunk size endif + ! ----- export info to legacy data structures --------------------------------------- + + ! export info%time -> multiforce to keep legacy code working + call export_time_to_multiforce(info) + end subroutine get_time_windows ! ------------------------------------------------------------------------------------- @@ -91,7 +97,7 @@ end subroutine get_time_windows subroutine export_time_to_multiforce(info) use multiforce, only: time_steps, timeUnits use multiforce, only: sim_beg, sim_end, eval_beg, eval_end, numtim_sim, numtim_sub, & - SUB_PERIODS_FLAG, istart + SUB_PERIODS_FLAG, istart, deltim implicit none type(fuse_info), intent(in) :: info @@ -108,6 +114,8 @@ subroutine export_time_to_multiforce(info) SUB_PERIODS_FLAG = info%time%use_subperiods istart = sim_beg + + deltim = info%time%deltim_days end subroutine ! ------------------------------------------------------------------------------------- @@ -120,6 +128,10 @@ subroutine export_time_to_multiforce(info) subroutine read_time_axis(ncid, time_steps, units, nt, ierr, message) + use netcdf + + implicit none + integer(i4b), intent(in) :: ncid real(sp), allocatable, intent(out) :: time_steps(:) character(len=*), intent(out) :: units @@ -167,12 +179,13 @@ end subroutine read_time_axis ! ----- helper: build julian axis ----------------------------------------------------- - subroutine build_julian_axis(time_steps, units, jref, jdate, ierr, message) + subroutine build_julian_axis(time_steps, units, jref, jdate, deltim_days, ierr, message) real(sp), intent(in) :: time_steps(:) character(len=*), intent(in) :: units real(sp), intent(out) :: jref real(sp), allocatable, intent(out) :: jdate(:) + real(sp), intent(out) :: deltim_days integer(i4b), intent(out) :: ierr character(*), intent(out) :: message @@ -191,11 +204,14 @@ subroutine build_julian_axis(time_steps, units, jref, jdate, ierr, message) scale_to_days = time_units_to_days(units, ierr, cmessage) if(ierr/=0) then; message=trim(message)//trim(cmessage); return; endif - ! build julian axis + ! build julian axis (units of days) allocate(jdate(size(time_steps)), stat=ierr) if(ierr/=0) then; message=trim(message)//"allocate(jdate) failed"; return; endif jdate = jref + time_steps * scale_to_days + ! define length of forcing time steps + deltim_days = jdate(2) - jdate(1) + end subroutine build_julian_axis ! ------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/share/globaldata.f90 b/build/FUSE_SRC/share/globaldata.f90 index 070d824..d0b66aa 100644 --- a/build/FUSE_SRC/share/globaldata.f90 +++ b/build/FUSE_SRC/share/globaldata.f90 @@ -25,7 +25,11 @@ MODULE globaldata logical(lgt), save :: isPrint=.true. logical(lgt), save :: isDebug=.false. - ! snow parameters + ! indices of forcing variables in vectors + integer(i4b), parameter :: NVAR_FORC=4 + integer(i4b), parameter :: iPRECIP=1, iTEMP=2, iPET=3, iQOBS=4 + + ! indices of snow parameters in vectors integer(i4b), parameter :: NPAR_SNOW=7 integer(i4b), parameter :: iMBASE=1, iMFMAX=2, iMFMIN=3, iPXTEMP=4, iOPG=5, iLAPSE=6 ! indices in vectors integer(i4b), parameter :: iPERR=7 ! not a snow parameter, but used here diff --git a/build/FUSE_SRC/types/info_types.f90 b/build/FUSE_SRC/types/info_types.f90 index 774d61e..59787ec 100644 --- a/build/FUSE_SRC/types/info_types.f90 +++ b/build/FUSE_SRC/types/info_types.f90 @@ -83,7 +83,9 @@ module info_types real(sp) :: jdate_ref = 0._sp real(sp), allocatable :: time_steps(:) ! time since reference time (transferred to output) real(sp), allocatable :: jdate(:) ! julian day for each forcing record - + + real(sp) :: deltim_days ! forcing time step in units of days + end type time_info ! ------------------------------------------------------------------------------------- @@ -94,6 +96,15 @@ module info_types ! ------------------------------------------------------------------------------------- + ! --- forcing_vars used in file_info + + type :: forcing_vars + character(len=64), allocatable :: name(:) ! NFORC + integer(i4b), allocatable :: varid(:) ! NFORC + end type + + ! --- + type :: file_info ! directories @@ -101,7 +112,7 @@ module info_types character(len=:), allocatable :: input_path character(len=:), allocatable :: output_path - ! settings filenames (relative or absolute) + ! settings filenames character(len=:), allocatable :: forcinginfo character(len=:), allocatable :: constraints character(len=:), allocatable :: mod_numerix @@ -112,8 +123,8 @@ module info_types character(len=:), allocatable :: suffix_elev_bands ! actual input filenames for this domain (derived once dom_id known) - character(len=:), allocatable :: forcing_file ! dom_id//suffix_forcing - character(len=:), allocatable :: elevbands_file ! dom_id//suffix_elev_bands + character(len=512) :: forcing_file ! dom_id//suffix_forcing + character(len=512) :: elevbands_file ! dom_id//suffix_elev_bands ! output base name + concrete outputs character(len=512) :: fname_tempry @@ -122,7 +133,18 @@ module info_types character(len=512) :: fname_netcdf_para ! NetCDF forcing file info - integer(i4b) :: ncid_forc = -9999 ! NetCDF file ID for forcing data + integer(i4b) :: ncid_forc = -9999 ! NetCDF file ID for forcing data + + character(len=:), allocatable :: time_name ! name of coordinate variables + character(len=:), allocatable :: latitude_name ! name of coordinate variables + character(len=:), allocatable :: longitude_name ! name of coordinate variables + + character(len=:), allocatable :: precip_name ! name of forcing variables + character(len=:), allocatable :: temp_name ! name of forcing variables + character(len=:), allocatable :: pet_name ! name of forcing variables + character(len=:), allocatable :: qobs_name ! name of forcing variables + + type(forcing_vars) :: forc ! name/varid table end type file_info diff --git a/build/FUSE_SRC/types/work_types.f90 b/build/FUSE_SRC/types/work_types.f90 index 0b56c8b..fb435c1 100644 --- a/build/FUSE_SRC/types/work_types.f90 +++ b/build/FUSE_SRC/types/work_types.f90 @@ -48,8 +48,6 @@ module work_types type(runoff) :: route ! hillslope routing end type fuse_step - real(sp) , allocatable :: x0(:) ! state variables (start of step) - real(sp) , allocatable :: x1(:) ! state variables (end of step) ! snow structure type fuse_snow real(sp) :: z_forcing ! elevation of forcing data (m) diff --git a/build/FUSE_SRC/util/alloc_domain.f90 b/build/FUSE_SRC/util/alloc_domain.f90 index 9d5220a..9c078af 100644 --- a/build/FUSE_SRC/util/alloc_domain.f90 +++ b/build/FUSE_SRC/util/alloc_domain.f90 @@ -3,6 +3,8 @@ module alloc_domain_module USE nrtype USE info_types, only: fuse_info USE data_types, only: domain_data + + use globaldata, only: NVAR_FORC implicit none private @@ -15,7 +17,7 @@ subroutine allocate_domain_data(info, domain, ierr, message) implicit none - type(fuse_info), intent(in) :: info + type(fuse_info), intent(inout) :: info type(domain_data), intent(inout) :: domain integer(i4b), intent(out) :: ierr character(*), intent(out) :: message @@ -70,6 +72,10 @@ subroutine allocate_domain_data(info, domain, ierr, message) allocate(domain%bands_var(nx,ny,nb,nt+1), stat=ierr) if(ierr/=0)then; message=trim(message)//"cannot allocate elev bands (var)"; return; endif + ! allocate forcing lookup table + allocate(info%files%forc%name(NVAR_FORC), info%files%forc%varid(NVAR_FORC), stat=ierr) + if(ierr/=0)then; message=trim(message)//"cannot allocate forcing lookup table"; return; endif + end subroutine allocate_domain_data ! ------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/util/fuse_fileManager.f90 b/build/FUSE_SRC/util/fuse_fileManager.f90 index 30aafce..0709757 100644 --- a/build/FUSE_SRC/util/fuse_fileManager.f90 +++ b/build/FUSE_SRC/util/fuse_fileManager.f90 @@ -8,11 +8,13 @@ MODULE fuse_filemanager use info_types, only: cli_options use info_types, only: fuse_info + use globaldata, only: NVAR_FORC + use globaldata, only: iPRECIP, iTEMP, iPET, iQOBS + implicit none private public :: read_fuse_control_file - public :: export_domain_to_legacy ! ----- all of these legacy globals are stored in the "info" data structure --------------------- @@ -25,6 +27,8 @@ MODULE fuse_filemanager public :: METRIC, TRANSFO public :: KSTOP_str, MAXN_str, PCENTO_str + ! ------------------------------------------------------------------------------------------------ + ! FUSE-wide pathlength integer(i4b),parameter::fusePathLen=512 @@ -71,12 +75,11 @@ MODULE fuse_filemanager ! ------------------------------------------------------------------------------------- subroutine read_fuse_control_file(fuseFileManagerIn, opts, info, err, message) - -use tomlf_all, only: toml_table, toml_error, toml_key, toml_value ! data types -use tomlf_all, only: toml_load, get_value ! procedures -! or: use tomlf, only: toml_table, toml_load, toml_error -! use tomlf_type_keyval, only: toml_key (if toml_key not re-exported) + use tomlf_all, only: toml_table, toml_error, toml_key, toml_value ! data types + use tomlf_all, only: toml_load, get_value ! procedures + ! Purpose: Reads FUSE control file (TOML version) AND populates info structure + ! implicit none ! dummies @@ -139,45 +142,56 @@ subroutine read_fuse_control_file(fuseFileManagerIn, opts, info, err, message) ! --------------------------------------------------------------------------------------------------------------- ! ----- control file assignment block --------------------------------------------------------------------------- - + lookup = trim(sections(i)%key)//'.'//trim(keys(j)%key) select case(lookup) ! ---- files: paths ---- - case ("paths.input_path" ); call get_value(subtable, trim(keys(j)%key), info%files%input_path , stat=istat) - case ("paths.output_path" ); call get_value(subtable, trim(keys(j)%key), info%files%output_path , stat=istat) - case ("paths.setngs_path" ); call get_value(subtable, trim(keys(j)%key), info%files%setngs_path , stat=istat) + case ("filepaths.input_dir" ); call get_value(subtable, trim(keys(j)%key), info%files%input_path , stat=istat) + case ("filepaths.output_dir" ); call get_value(subtable, trim(keys(j)%key), info%files%output_path , stat=istat) + case ("filepaths.settings_dir" ); call get_value(subtable, trim(keys(j)%key), info%files%setngs_path , stat=istat) ! ---- files: suffixes ---- - case ("input.suffix_forcing" ); call get_value(subtable, trim(keys(j)%key), info%files%suffix_forcing , stat=istat) - case ("input.suffix_elev_bands"); call get_value(subtable, trim(keys(j)%key), info%files%suffix_elev_bands, stat=istat) + case ("input.forcing_suffix" ); call get_value(subtable, trim(keys(j)%key), info%files%suffix_forcing , stat=istat) + case ("input.elevbands_suffix" ); call get_value(subtable, trim(keys(j)%key), info%files%suffix_elev_bands, stat=istat) ! ---- files: settings filenames ---- - case ("settings.forcinginfo" ); call get_value(subtable, trim(keys(j)%key), info%files%forcinginfo , stat=istat) - case ("settings.constraints" ); call get_value(subtable, trim(keys(j)%key), info%files%constraints , stat=istat) - case ("settings.mod_numerix" ); call get_value(subtable, trim(keys(j)%key), info%files%mod_numerix , stat=istat) - case ("settings.m_decisions" ); call get_value(subtable, trim(keys(j)%key), info%files%m_decisions , stat=istat) + case ("model.decisions_file" ); call get_value(subtable, trim(keys(j)%key), info%files%m_decisions , stat=istat) + case ("model.numerics_file" ); call get_value(subtable, trim(keys(j)%key), info%files%mod_numerix , stat=istat) + case ("model.constraints_file" ); call get_value(subtable, trim(keys(j)%key), info%files%constraints , stat=istat) + case ("model.forcinginfo_file" ); call get_value(subtable, trim(keys(j)%key), info%files%forcinginfo , stat=istat) + + ! ---- files: forcing coordinate names ---- + case ("forcing_coords.time" ); call get_value(subtable, trim(keys(j)%key), info%files%time_name , stat=istat) + case ("forcing_coords.latitude" ); call get_value(subtable, trim(keys(j)%key), info%files%latitude_name , stat=istat) + case ("forcing_coords.longitude" ); call get_value(subtable, trim(keys(j)%key), info%files%longitude_name , stat=istat) + + ! ---- files: forcing variable names ---- + case ("forcing_vars.precip" ); call get_value(subtable, trim(keys(j)%key), info%files%precip_name , stat=istat) + case ("forcing_vars.temp" ); call get_value(subtable, trim(keys(j)%key), info%files%temp_name , stat=istat) + case ("forcing_vars.pet" ); call get_value(subtable, trim(keys(j)%key), info%files%pet_name , stat=istat) + case ("forcing_vars.qobs" ); call get_value(subtable, trim(keys(j)%key), info%files%qobs_name , stat=istat) ! ---- config: runtime ---- - case ("output.fmodel_id" ); call get_value(subtable, trim(keys(j)%key), info%config%fmodel_id , stat=istat) - case ("output.q_only" ); call get_value(subtable, trim(keys(j)%key), info%config%q_only , stat=istat) + case ("output.model_id" ); call get_value(subtable, trim(keys(j)%key), info%config%fmodel_id , stat=istat) + case ("output.q_only" ); call get_value(subtable, trim(keys(j)%key), info%config%q_only , stat=istat) ! ---- config: periods ---- - case ("periods.date_start_sim" ); call get_value(subtable, trim(keys(j)%key), info%config%date_start_sim , stat=istat) - case ("periods.date_end_sim" ); call get_value(subtable, trim(keys(j)%key), info%config%date_end_sim , stat=istat) - case ("periods.date_start_eval"); call get_value(subtable, trim(keys(j)%key), info%config%date_start_eval , stat=istat) - case ("periods.date_end_eval" ); call get_value(subtable, trim(keys(j)%key), info%config%date_end_eval , stat=istat) - case ("periods.numtim_sub_str" ); call get_value(subtable, trim(keys(j)%key), info%config%numtim_sub_str , stat=istat) + case ("run_periods.date_start_sim" ); call get_value(subtable, trim(keys(j)%key), info%config%date_start_sim , stat=istat) + case ("run_periods.date_end_sim" ); call get_value(subtable, trim(keys(j)%key), info%config%date_end_sim , stat=istat) + case ("run_periods.date_start_eval"); call get_value(subtable, trim(keys(j)%key), info%config%date_start_eval , stat=istat) + case ("run_periods.date_end_eval" ); call get_value(subtable, trim(keys(j)%key), info%config%date_end_eval , stat=istat) + case ("run_periods.numtim_sub_str" ); call get_value(subtable, trim(keys(j)%key), info%config%numtim_sub_str , stat=istat) ! ---- config: calibration ---- - case ("calibration.metric" ); call get_value(subtable, trim(keys(j)%key), info%config%metric , stat=istat) - case ("calibration.transfo" ); call get_value(subtable, trim(keys(j)%key), info%config%transfo , stat=istat) + case ("calibration.metric" ); call get_value(subtable, trim(keys(j)%key), info%config%metric , stat=istat) + case ("calibration.transfo" ); call get_value(subtable, trim(keys(j)%key), info%config%transfo , stat=istat) ! ---- config: SCE (read numeric, then next populate legacy strings) ---- - case ("sce.maxn" ); call get_value(subtable, trim(keys(j)%key), info%config%maxn , stat=istat) - case ("sce.kstop" ); call get_value(subtable, trim(keys(j)%key), info%config%kstop , stat=istat) - case ("sce.pcento" ); call get_value(subtable, trim(keys(j)%key), info%config%pcento , stat=istat) + case ("sce.maxn" ); call get_value(subtable, trim(keys(j)%key), info%config%maxn , stat=istat) + case ("sce.kstop" ); call get_value(subtable, trim(keys(j)%key), info%config%kstop , stat=istat) + case ("sce.pcento" ); call get_value(subtable, trim(keys(j)%key), info%config%pcento , stat=istat) ! ---- default case (something in the table that is not specified above) ----- case default @@ -220,6 +234,9 @@ subroutine read_fuse_control_file(fuseFileManagerIn, opts, info, err, message) info%files%fname_netcdf_runs = trim(info%files%fname_tempry)//'_runs_'//trim(run_mode)//'.nc' info%files%fname_netcdf_para = trim(info%files%fname_tempry)//'_para_'//trim(run_mode)//'.nc' + ! ---- populate legacy modules ---- + call export_domain_to_legacy(info) + end subroutine read_fuse_control_file ! ------------------------------------------------------------------------------------- diff --git a/build/FUSE_SRC/netcdf/time_io.f90 b/build/FUSE_SRC/util/time_utils.f90 similarity index 66% rename from build/FUSE_SRC/netcdf/time_io.f90 rename to build/FUSE_SRC/util/time_utils.f90 index ced37c0..ccf1623 100644 --- a/build/FUSE_SRC/netcdf/time_io.f90 +++ b/build/FUSE_SRC/util/time_utils.f90 @@ -1,73 +1,14 @@ -module time_io +module time_utils use nrtype - use netcdf implicit none - public::get_modtim + public :: date_extractor + public :: juldayss + public :: caldatss contains - SUBROUTINE get_modtim(ncid, itim, ierr, message) - ! --------------------------------------------------------------------------------------- - ! Creator: - ! -------- - ! Martyn Clark, 2012 - ! --------------------------------------------------------------------------------------- - ! Purpose: - ! -------- - ! Read NetCDF time variable for a given time step - ! --------------------------------------------------------------------------------------- - ! Modules Modified: - ! ----------------- - ! MODULE multiforce -- populate structure timDat%(*) - ! --------------------------------------------------------------------------------------- - USE fuse_fileManager,only:INPUT_PATH ! defines data directory - USE multiforce,only:forcefile ! name of forcing file - USE multiforce,only:vname_dtime ! variable name: time since reference time - USE multiforce,only:timDat ! time data strructure - USE multiforce,only:jdayRef ! reference time (days) - USE multiforce,only:latUnits,lonUnits,timeUnits ! units string for time - - IMPLICIT NONE - ! input - integer(i4b), intent(in) :: ncid ! NetCDF file ID - integer(i4b), intent(in) :: itim ! index of model time step - ! output - integer(i4b), intent(out) :: ierr ! error code - character(*), intent(out) :: message ! error message - ! internal - integer(i4b),parameter :: strLen=1024 ! length of character string - character(len=strLen) :: cmessage ! error message of downwind routine - integer(i4b) :: iVarID ! NetCDF variable ID - integer(i4b) :: iy,im,id ! time of year - integer(i4b) :: ih ! time of day - real(sp),dimension(1) :: atime ! time array - ! --------------------------------------------------------------------------------------- - ! initialize error control - ierr=0; message='get_modtim/' - - ! get variable ID for time - ierr = nf90_inq_varid(ncid, trim(vname_dtime), iVarID) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr))//'[variable='//trim(vname_dtime)//']'; return; endif - - ! identify reference time - call date_extractor(timeUnits,iy,im,id,ih) - call juldayss(iy,im,id,ih,jdayRef,ierr,cmessage) - if(ierr/=0)then; message=trim(message)//trim(cmessage); return; endif - - ! get the time - ierr = nf90_get_var(ncid, iVarID, aTime, start=(/iTim/), count=(/1/)) - if(ierr/=0)then; message=trim(message)//trim(nf90_strerror(ierr)); return; endif - - ! put the time into the structure - timDat%dtime = aTime(1) - - ! compute the year, month, day, hour, minute, second - call caldatss(jdayRef+timDat%dtime,timDat%iy,timDat%im,timDat%id,timDat%ih,timDat%imin,timDat%dsec) - - END SUBROUTINE get_modtim - subroutine date_extractor(refDate,iy,im,id,ih) ! used to extract the date from a units string ! (based on a routine written by David Rupp) @@ -218,4 +159,4 @@ SUBROUTINE caldatss(juliandd,iyyy,im,id,ih,imin,asec) if(julian.lt.0)iyyy=iyyy-100*(1-julian/36525) END SUBROUTINE caldatss -end module time_io +end module time_utils diff --git a/build/Makefile b/build/Makefile index 9c2e4d3..900ed93 100755 --- a/build/Makefile +++ b/build/Makefile @@ -238,16 +238,12 @@ SHARE = $(patsubst %, $(SHARE_DIR)/%, $(FUSE_SHARE)) # combine data modules together DATAMS = $(G_DATA) $(MODDEF) $(TYPES) $(SHARE) -# Time I/O modules -FUSE_TIMEMS = -FUSE_TIMEMS += time_io.f90 -TIMUTILS = $(patsubst %, $(TIME_DIR)/%, $(FUSE_TIMEMS)) - # Utility modules FUSE_UTILMS = FUSE_UTILMS += fuse_fileManager.f90 FUSE_UTILMS += alloc_domain.f90 FUSE_UTILMS += alloc_scratch.f90 +FUSE_UTILMS += time_utils.f90 FUSE_UTILMS += metaoutput.f90 FUSE_UTILMS += metaparams.f90 FUSE_UTILMS += meta_stats.f90 @@ -325,7 +321,6 @@ FUSE_PRELIM += parse_command_args.f90 FUSE_PRELIM += ascii_util.f90 FUSE_PRELIM += uniquemodl.f90 FUSE_PRELIM += getnumerix.f90 -FUSE_PRELIM += force_info.f90 FUSE_PRELIM += getparmeta.f90 FUSE_PRELIM += assign_stt.f90 FUSE_PRELIM += assign_flx.f90 diff --git a/build/generated/fuseversion.inc b/build/generated/fuseversion.inc index 2d9c8c5..466759f 100644 --- a/build/generated/fuseversion.inc +++ b/build/generated/fuseversion.inc @@ -4,6 +4,6 @@ integer, parameter :: FUSE_BUILDTIME_LEN = 32 integer, parameter :: FUSE_GITBRANCH_LEN = 64 integer, parameter :: FUSE_GITHASH_LEN = 64 character(len=FUSE_VERSION_LEN), parameter :: FUSE_VERSION = 'v2.0.0' -character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-23T00:57:22Z' -character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/inputs' -character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = '3adde8a66ad2c4deb40cf346f69fd7438be98075' +character(len=FUSE_BUILDTIME_LEN), parameter :: FUSE_BUILDTIME = '2026-02-24T02:06:14Z' +character(len=FUSE_GITBRANCH_LEN), parameter :: FUSE_GITBRANCH = 'refactor/new-data-structures' +character(len=FUSE_GITHASH_LEN), parameter :: FUSE_GITHASH = 'fb6624e5e77051c2e8468df6abaced0d4c05613e'

-|FLEoZ%zXg^0s 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%0Ac$HJ4Dz~!n%^eZy!QG7jcA5AZ!w0(+HbM*c`&< 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