diff --git a/src/suews/src/suews_ctrl_driver.f95 b/src/suews/src/suews_ctrl_driver.f95 index 906b1411..00cf58b4 100644 --- a/src/suews/src/suews_ctrl_driver.f95 +++ b/src/suews/src/suews_ctrl_driver.f95 @@ -469,7 +469,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & !input modState) ! input/output: - debugState%state_dailystate = modState + debugState%state_01_dailystate = modState !======== Calculate soil moisture ========= IF (Diagnose == 1) WRITE (*, *) 'Calling SUEWS_update_SoilMoist...' @@ -477,7 +477,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_soilmoist = modState + debugState%state_02_soilmoist = modState IF (Diagnose == 1) WRITE (*, *) 'Calling SUEWS_cal_WaterUse...' !=================Gives the external and internal water uses per timestep================= @@ -485,14 +485,14 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_wateruse = modState + debugState%state_03_wateruse = modState ! ===================ANTHROPOGENIC HEAT AND CO2 FLUX====================== CALL SUEWS_cal_AnthropogenicEmission_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_anthroemis = modState + debugState%state_04_anthroemis = modState ! ======================================================================== ! N.B.: the following parts involves snow-related calculations. @@ -505,7 +505,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & modState, & ! input/output: dataOutLineSPARTACUS) ! output - debugState%state_qn = modState + debugState%state_05_qn = modState IF (diagnose == 1) PRINT *, 'Tsfc_surf before QS', heatState%tsfc_surf CALL SUEWS_cal_Qs_DTS( & @@ -513,7 +513,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & modState, & ! input/output: dataOutLineESTM) - debugState%state_qs = modState + debugState%state_06_qs = modState !==================Energy related to snow melting/freezing processes======= IF (Diagnose == 1) WRITE (*, *) 'Calling MeltHeat' @@ -524,7 +524,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_qhqe_lumps = modState + debugState%state_07_qhqe_lumps = modState !============= calculate water balance ============= IF (Diagnose == 1) WRITE (*, *) 'Calling SUEWS_cal_Water...' @@ -532,7 +532,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_water = modState + debugState%state_08_water = modState !============= calculate water balance end ============= !===============Resistance Calculations======================= @@ -541,7 +541,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_resist = modState + debugState%state_09_resist = modState ! atmState, & ! roughnessState, & ! hydroState, & @@ -577,7 +577,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_qe = modState + debugState%state_10_qe = modState !======== Evaporation and surface state_id end======== END IF @@ -587,7 +587,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_qh = modState + debugState%state_11_qh = modState !============ Sensible heat flux end =============== ! ============ update surface temperature of this iteration =============== @@ -595,7 +595,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_tsurf = modState + debugState%state_12_tsurf = modState i_iter = i_iter + 1 IF (i_iter == max_iter .AND. .NOT. flag_converge) THEN @@ -618,7 +618,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & modState, & ! input/output: dataoutLineRSL) ! output - debugState%state_rsl = modState + debugState%state_13_rsl = modState ! ============ BIOGENIC CO2 FLUX ======================= IF (Diagnose == 1) WRITE (*, *) 'Calling SUEWS_cal_BiogenCO2_DTS...' @@ -626,7 +626,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & timer, config, forcing, siteInfo, & ! input modState) ! input/output: - debugState%state_biogenco2 = modState + debugState%state_14_biogenco2 = modState ! calculations of diagnostics end !============================================================== @@ -653,7 +653,7 @@ SUBROUTINE SUEWS_cal_Main_DTS( & modState, & ! input/output: dataOutLineBEERS) ! output - debugState%state_beers = modState + debugState%state_15_beers = modState !==============translation of output variables into output array=========== IF (Diagnose == 1) WRITE (*, *) 'Calling BEERS_cal_main_DTS...' diff --git a/src/suews/src/suews_ctrl_type.f95 b/src/suews/src/suews_ctrl_type.f95 index 215837a3..03ed6991 100644 --- a/src/suews/src/suews_ctrl_type.f95 +++ b/src/suews/src/suews_ctrl_type.f95 @@ -839,21 +839,21 @@ MODULE SUEWS_DEF_DTS ! Naming convention: state_XX_YYY ! XX: sequence number in the main SUEWS calculation ! YYY: name of the physical module - TYPE(SUEWS_STATE) :: state_dailystate - TYPE(SUEWS_STATE) :: state_soilmoist - TYPE(SUEWS_STATE) :: state_wateruse - TYPE(SUEWS_STATE) :: state_anthroemis - TYPE(SUEWS_STATE) :: state_qn - TYPE(SUEWS_STATE) :: state_qs - TYPE(SUEWS_STATE) :: state_qhqe_lumps - TYPE(SUEWS_STATE) :: state_water - TYPE(SUEWS_STATE) :: state_resist - TYPE(SUEWS_STATE) :: state_qe - TYPE(SUEWS_STATE) :: state_qh - TYPE(SUEWS_STATE) :: state_tsurf - TYPE(SUEWS_STATE) :: state_rsl - TYPE(SUEWS_STATE) :: state_biogenco2 - TYPE(SUEWS_STATE) :: state_beers + TYPE(SUEWS_STATE) :: state_01_dailystate + TYPE(SUEWS_STATE) :: state_02_soilmoist + TYPE(SUEWS_STATE) :: state_03_wateruse + TYPE(SUEWS_STATE) :: state_04_anthroemis + TYPE(SUEWS_STATE) :: state_05_qn + TYPE(SUEWS_STATE) :: state_06_qs + TYPE(SUEWS_STATE) :: state_07_qhqe_lumps + TYPE(SUEWS_STATE) :: state_08_water + TYPE(SUEWS_STATE) :: state_09_resist + TYPE(SUEWS_STATE) :: state_10_qe + TYPE(SUEWS_STATE) :: state_11_qh + TYPE(SUEWS_STATE) :: state_12_tsurf + TYPE(SUEWS_STATE) :: state_13_rsl + TYPE(SUEWS_STATE) :: state_14_biogenco2 + TYPE(SUEWS_STATE) :: state_15_beers ! TYPE(SUEWS_STATE) :: state_snow ! unavailable - to be added #234 CONTAINS PROCEDURE :: init => init_suews_debug @@ -866,19 +866,19 @@ SUBROUTINE init_suews_debug(self, nlayer, ndepth) INTEGER, INTENT(in) :: nlayer, ndepth ! Initialise the SUEWS_DEBUG type - CALL self%state_dailystate%ALLOCATE(nlayer, ndepth) - CALL self%state_soilmoist%ALLOCATE(nlayer, ndepth) - CALL self%state_wateruse%ALLOCATE(nlayer, ndepth) - CALL self%state_anthroemis%ALLOCATE(nlayer, ndepth) - CALL self%state_qn%ALLOCATE(nlayer, ndepth) - CALL self%state_qs%ALLOCATE(nlayer, ndepth) - CALL self%state_resist%ALLOCATE(nlayer, ndepth) - CALL self%state_qe%ALLOCATE(nlayer, ndepth) - CALL self%state_qh%ALLOCATE(nlayer, ndepth) - CALL self%state_tsurf%ALLOCATE(nlayer, ndepth) - CALL self%state_rsl%ALLOCATE(nlayer, ndepth) - CALL self%state_biogenco2%ALLOCATE(nlayer, ndepth) - CALL self%state_beers%ALLOCATE(nlayer, ndepth) + CALL self%state_01_dailystate%ALLOCATE(nlayer, ndepth) + CALL self%state_02_soilmoist%ALLOCATE(nlayer, ndepth) + CALL self%state_03_wateruse%ALLOCATE(nlayer, ndepth) + CALL self%state_04_anthroemis%ALLOCATE(nlayer, ndepth) + CALL self%state_05_qn%ALLOCATE(nlayer, ndepth) + CALL self%state_06_qs%ALLOCATE(nlayer, ndepth) + CALL self%state_09_resist%ALLOCATE(nlayer, ndepth) + CALL self%state_10_qe%ALLOCATE(nlayer, ndepth) + CALL self%state_11_qh%ALLOCATE(nlayer, ndepth) + CALL self%state_12_tsurf%ALLOCATE(nlayer, ndepth) + CALL self%state_13_rsl%ALLOCATE(nlayer, ndepth) + CALL self%state_14_biogenco2%ALLOCATE(nlayer, ndepth) + CALL self%state_15_beers%ALLOCATE(nlayer, ndepth) ! CALL self%state_snow%init() ! unavailable - to be added #234 END SUBROUTINE init_suews_debug diff --git a/src/supy/_post.py b/src/supy/_post.py index bb208d90..894a9f6d 100644 --- a/src/supy/_post.py +++ b/src/supy/_post.py @@ -295,3 +295,68 @@ def pack_dict_debug(dts_debug): } return dict_debug + + +def has_dict(d): + """ + Check if a dictionary contains any values that are dictionaries. + + Parameters: + d (dict): The dictionary to check. + + Returns: + bool: True if the dictionary contains any values that are dictionaries, False otherwise. + """ + return any(isinstance(v, dict) for v in d.values()) + + +def pack_df_debug_raw(dict_debug): + """ + Packs a dictionary of debug information into a pandas DataFrame. + + Args: + dict_debug (dict): A dictionary containing debug information. + + Returns: + pandas.DataFrame: A DataFrame containing the packed debug information. + """ + + dict_df_debug = {} + for k, v in dict_debug.items(): + + if has_dict(v): + dict_df_debug[k] = pack_df_debug_raw(v) + else: + dict_df_debug[k] = pd.Series(v) + + df_debug = pd.concat(dict_df_debug, axis=0) + + return df_debug + + +def pack_df_debug(dict_debug): + """ + Packs the debug dictionary into a DataFrame. + + Args: + dict_debug (dict): The debug dictionary containing the debug information. + + Returns: + pandas.DataFrame: The packed DataFrame with debug information. + + """ + df_debug_raw = pack_df_debug_raw(dict_debug) + df_debug_raw.index = df_debug_raw.index.rename( + [ + "grid", + "step", + "group", + "var", + ] + ) + df_debug = ( + df_debug_raw.unstack(level=["group", "var"]) + .sort_index(level=0, axis=1) + .dropna(axis=1, how="all") + ) + return df_debug diff --git a/src/supy/_run.py b/src/supy/_run.py index 35ca8040..5e0313d0 100644 --- a/src/supy/_run.py +++ b/src/supy/_run.py @@ -26,7 +26,14 @@ list_var_output, list_var_output_multitsteps, ) -from ._post import pack_df_output_line, pack_df_output_array, pack_df_state, pack_dict_debug +from ._post import ( + pack_df_output_line, + pack_df_output_array, + pack_df_state, + pack_dict_debug, + pack_df_debug, +) + from ._env import logger_supy @@ -388,9 +395,7 @@ def run_supy_ser( for dict_state_input in list_dict_state_input ] - list_dict_state_end, list_df_output, list_dict_debug = zip( - *list_res_grid - ) + list_dict_state_end, list_df_output, list_dict_debug = zip(*list_res_grid) except: path_zip_debug = save_zip_debug(df_forcing, df_state_init) @@ -417,6 +422,7 @@ def run_supy_ser( # collect debug info dict_debug = {grid: debug for grid, debug in zip(list_grid, list_dict_debug)} + df_debug = pack_df_debug(dict_debug) # save results as time-aware DataFrame df_output0 = pd.concat(dict_df_output, names=["grid"]).sort_index() @@ -436,7 +442,7 @@ def run_supy_ser( # print(f'Execution time: {(end - start):.1f} s') # print(f'====================\n') if df_state_init["debug"].any().any(): - return df_output, df_state_final, dict_debug + return df_output, df_state_final, df_debug else: return df_output, df_state_final