Skip to content

Commit b441de5

Browse files
authored
Merge pull request #14 from TOSSHtoolbox/ry-patch
Streamlined RecessionAnalysis signature output and added more description
2 parents 61c773e + 5318a31 commit b441de5

File tree

3 files changed

+83
-29
lines changed

3 files changed

+83
-29
lines changed

TOSSH_code/calculation_functions/calc_All.m

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@
106106
Q_var_error_str = strings(size(Q_mat,1),1);
107107
QP_elasticity = NaN(size(Q_mat,1),1);
108108
QP_elasticity_error_str = strings(size(Q_mat,1),1);
109-
RecessionParameters = NaN(size(Q_mat,1),2);
109+
RecessionParameters_a = NaN(size(Q_mat,1),1);
110+
RecessionParameters_b = NaN(size(Q_mat,1),1);
111+
RecessionParameters_T0 = NaN(size(Q_mat,1),1);
110112
RecessionParameters_error_str = strings(size(Q_mat,1),1);
111113
RecessionK_early = NaN(size(Q_mat,1),1);
112114
RecessionK_early_error_str = strings(size(Q_mat,1),1);
@@ -196,8 +198,17 @@
196198
[Q_skew(i),~,Q_skew_error_str(i)] = sig_Q_skew(Q_mat{i},t_mat{i});
197199
[Q_var(i),~,Q_var_error_str(i)] = sig_Q_var(Q_mat{i},t_mat{i});
198200
[QP_elasticity(i),~,QP_elasticity_error_str(i)] = sig_QP_elasticity(Q_mat{i},t_mat{i},P_mat{i});
199-
[RecessionParameters(i,:),~,~,RecessionParameters_error_str(i)] = ...
201+
[RecessionParametersTemp,~,~,RecessionParameters_error_str(i)] = ...
200202
sig_RecessionAnalysis(Q_mat{i},t_mat{i},'fit_individual',false);
203+
204+
% Post-processing of RecessionParameters (see sig_RecessionAnalysis
205+
% function description for the details)
206+
RecessionParameters_a(i) = median((RecessionParametersTemp(:,1)),'omitnan');
207+
RecessionParameters_b(i) = median(RecessionParametersTemp(:,2),'omitnan');
208+
RecessionParametersT0Temp = 1./(RecessionParametersTemp(:,1).*median(Q_mat{i}(Q_mat{i}>0),'omitnan').^(RecessionParametersTemp(:,2)-1));
209+
ReasonableT0 = and(RecessionParametersTemp(:,2)>0.5,RecessionParametersTemp(:,2)<5);
210+
RecessionParameters_T0(i) = median(RecessionParametersT0Temp(ReasonableT0),'omitnan');
211+
201212
[RecessionK_early(i),~,RecessionK_early_error_str(i)] = sig_RecessionParts(Q_mat{i},t_mat{i},'early');
202213
[Spearmans_rho(i),~,Spearmans_rho_error_str(i)] = sig_RecessionUniqueness(Q_mat{i},t_mat{i});
203214
[ResponseTime(i),~,ResponseTime_error_str(i)] = sig_ResponseTime(Q_mat{i},t_mat{i},P_mat{i});
@@ -278,7 +289,9 @@
278289
results.Q_var_error_str = Q_var_error_str;
279290
results.QP_elasticity = QP_elasticity;
280291
results.QP_elasticity_error_str = QP_elasticity_error_str;
281-
results.RecessionParameters = RecessionParameters;
292+
results.RecessionParameters_a = RecessionParameters_a;
293+
results.RecessionParameters_b = RecessionParameters_b;
294+
results.RecessionParameters_T0 = RecessionParameters_T0;
282295
results.RecessionParameters_error_str = RecessionParameters_error_str;
283296
results.RecessionK_early = RecessionK_early;
284297
results.RecessionK_early_error_str = RecessionK_early_error_str;

TOSSH_code/calculation_functions/calc_McMillan_Groundwater.m

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
function [results] = calc_McMillan_Groundwater(Q_mat, t_mat, P_mat, PET_mat, varargin)
22
%calc_McMillan_Groundwater calculates various groundwater signatures.
3-
% Calculates 15 signatures from McMillan (2020), related to groundwater
4-
% storage, groundwater dynamics and baseflow. These signatures come from
5-
% previous experimental studies that link catchment or hillslope
6-
% processes to streamflow response dynamics. Some signatures are
3+
% Calculates 15 signatures from McMillan (2020), related to groundwater
4+
% storage, groundwater dynamics and baseflow. These signatures come from
5+
% previous experimental studies that link catchment or hillslope
6+
% processes to streamflow response dynamics. Some signatures are
77
% implemented direct from the original papers, others are interpreted
88
% from a qualitative description in the paper.
99
%
@@ -13,7 +13,7 @@
1313
% P_mat: precipitation [mm/timestep] matrix (cell array)
1414
% PET_mat: pot. evapotranspiration [mm/timestep] matrix (cell array)
1515
% OPTIONAL
16-
% start_water_year: first month of water year, default = 10 (October)
16+
% start_water_year: first month of water year, default = 10 (October)
1717
% plot_results: whether to plot results, default = false
1818
% recession_length: min. length of recessions [days], default = 15
1919
% n_start: days to be removed after start of recession
@@ -75,7 +75,7 @@
7575

7676
% initialise arrays
7777

78-
% Section: Groundwater
78+
% Section: Groundwater
7979
% Signatures referring to double peaks in streamflow are not coded due to
8080
% subjectivity in identification of the peaks.
8181
% Total runoff ratio describes overall water loss to deep groundwater.
@@ -98,73 +98,79 @@
9898
% Seasonal variations in recession parameters (Shaw and Riha, 2012).
9999
Recession_a_Seasonality = NaN(size(Q_mat,1),1);
100100
Recession_a_Seasonality_error_str = strings(size(Q_mat,1),1);
101-
% Average storage from average baseflow and storage-discharge relationship
101+
% Average storage from average baseflow and storage-discharge relationship
102102
% (McNamara et al., 2011).
103103
AverageStorage = NaN(size(Q_mat,1),1);
104104
AverageStorage_error_str = strings(size(Q_mat,1),1);
105105
% Recession analysis parameters approximate storage-discharge relationship.
106106
% This fits a single relationship to the point cloud.
107-
RecessionParameters = NaN(size(Q_mat,1),3);
107+
RecessionParameters_a = NaN(size(Q_mat,1),1);
108+
RecessionParameters_b = NaN(size(Q_mat,1),1);
109+
RecessionParameters_T0 = NaN(size(Q_mat,1),1);
108110
RecessionParameters_error_str = strings(size(Q_mat,1),1);
109-
% Changes of slope in a master recession curve (MRC) or recession analysis
111+
% Changes of slope in a master recession curve (MRC) or recession analysis
110112
% plot indicate multiple linear reservoirs.
111113
MRC_num_segments = NaN(size(Q_mat,1),1);
112114
MRC_num_segments_error_str = strings(size(Q_mat,1),1);
113115
% First: steep section of the master recession curve = storage that is
114116
% quickly depleted (Estrany et al., 2010).
115117
First_Recession_Slope = NaN(size(Q_mat,1),1);
116-
% Second: mid section of the master recession curve = water retention
118+
% Second: mid section of the master recession curve = water retention
117119
% capacity of the catchment (Estrany et al., 2010).
118120
Mid_Recession_Slope = NaN(size(Q_mat,1),1);
119121
% Non-uniqueness in the storage-discharge relationship (McMillan et al.,
120-
% 2011; Harman et al., 2009). Tested using Spearman rank correlation on Q
122+
% 2011; Harman et al., 2009). Tested using Spearman rank correlation on Q
121123
% vs. dQ/dt.
122124
Spearmans_rho = NaN(size(Q_mat,1),1);
123125
Spearmans_rho_error_str = strings(size(Q_mat,1),1);
124-
% Ratio between event and total runoff coefficient: low = large storage
126+
% Ratio between event and total runoff coefficient: low = large storage
125127
% capacity (Blume et al., 2008).
126128
EventRR_TotalRR_ratio = NaN(size(Q_mat,1),1);
127-
% Variability index of flow. Low variability index shows higher water
129+
% Variability index of flow. Low variability index shows higher water
128130
% storage (Estrany et al., 2010).
129131
VariabilityIndex = NaN(size(Q_mat,1),1);
130132
VariabilityIndex_error_str = strings(size(Q_mat,1),1);
131133

132-
% Section: Baseflow
134+
% Section: Baseflow
133135
% Visual inspection of hydrograph for stable baseflow: not coded.
134-
% Baseflow index indicates baseflow proportion and baseflow residence time
136+
% Baseflow index indicates baseflow proportion and baseflow residence time
135137
% (Yilmaz et al., 2008; Bulygina et al., 2009; Hrachowitz et al., 2014).
136138
BFI = NaN(size(Q_mat,1),1);
137139
BFI_error_str = strings(size(Q_mat,1),1);
138140
% Baseflow recession constant K (assuming exponential recession behaviour),
139-
% slower recessions show greater groundwater influence and longer
141+
% slower recessions show greater groundwater influence and longer
140142
% subsurface flow paths (Safeeq et al., 2013).
141143
BaseflowRecessionK = NaN(size(Q_mat,1),1);
142144
BaseflowRecessionK_error_str = strings(size(Q_mat,1),1);
143145

144146
% loop over all catchments
145147
for i = 1:size(Q_mat,1)
146-
148+
147149
% Section: Groundwater
148150
[TotalRR(i),~,TotalRR_error_str(i)] = sig_TotalRR(Q_mat{i},t_mat{i},P_mat{i});
149151
[RR_Seasonality(i),~,RR_Seasonality_error_str(i)] = sig_RR_Seasonality(Q_mat{i}, t_mat{i}, P_mat{i}, ...
150152
'summer_start', start_water_year-6);
151153
[EventRR(i),~,EventRR_error_str(i)] = sig_EventRR(Q_mat{i},t_mat{i},P_mat{i});
152154
[StorageFraction(i,1),StorageFraction(i,2),StorageFraction(i,3),~,StorageFraction_error_str(i)] = ...
153155
sig_StorageFraction(Q_mat{i},t_mat{i},P_mat{i},PET_mat{i},'plot_results',plot_results);
154-
156+
155157
% Section: Storage (especially groundwater)
156158
[Recession_a_Seasonality(i),~,Recession_a_Seasonality_error_str(i)] = ...
157159
sig_SeasonalVarRecessions(Q_mat{i},t_mat{i},'eps',eps,'recession_length',recession_length,'plot_results',plot_results,'n_start',n_start);
158160
[AverageStorage(i),~,AverageStorage_error_str(i)] = ...
159161
sig_StorageFromBaseflow(Q_mat{i},t_mat{i},P_mat{i},PET_mat{i},'start_water_year',start_water_year,'plot_results',plot_results,'recession_length',recession_length,'n_start',n_start,'eps',eps);
160162
[RecessionParametersTemp,~,~,RecessionParameters_error_str_temp] = ...
161163
sig_RecessionAnalysis(Q_mat{i},t_mat{i},'fit_individual',true,'plot_results',plot_results,'recession_length',recession_length,'n_start',n_start,'eps',eps);
162-
RecessionParameters(i,1) = median((RecessionParametersTemp(:,1)),'omitnan');
163-
RecessionParameters(i,2) = median(RecessionParametersTemp(:,2),'omitnan');
164+
165+
% Post-processing of RecessionParameters (see sig_RecessionAnalysis
166+
% function description for the details)
167+
RecessionParameters_a(i) = median((RecessionParametersTemp(:,1)),'omitnan');
168+
RecessionParameters_b(i) = median(RecessionParametersTemp(:,2),'omitnan');
164169
RecessionParametersT0Temp = 1./(RecessionParametersTemp(:,1).*median(Q_mat{i}(Q_mat{i}>0),'omitnan').^(RecessionParametersTemp(:,2)-1));
165170
ReasonableT0 = and(RecessionParametersTemp(:,2)>0.5,RecessionParametersTemp(:,2)<5);
166-
RecessionParameters(i,3) = median(RecessionParametersT0Temp(ReasonableT0),'omitnan');
171+
RecessionParameters_T0(i) = median(RecessionParametersT0Temp(ReasonableT0),'omitnan');
167172
RecessionParameters_error_str(i) = RecessionParameters_error_str_temp;
173+
168174
[MRC_num_segments(i),Segment_slopes,~,MRC_num_segments_error_str(i)] = ...
169175
sig_MRC_SlopeChanges(Q_mat{i},t_mat{i},'plot_results',plot_results,'eps',eps,'recession_length',recession_length,'n_start',n_start);
170176
First_Recession_Slope(i) = Segment_slopes(1);
@@ -174,12 +180,12 @@
174180
[Spearmans_rho(i),~,Spearmans_rho_error_str(i)] = sig_RecessionUniqueness(Q_mat{i},t_mat{i},'eps',eps,'recession_length',recession_length,'n_start',n_start);
175181
EventRR_TotalRR_ratio(i) = EventRR(i)/TotalRR(i);
176182
[VariabilityIndex(i),~,VariabilityIndex_error_str(i)] = sig_VariabilityIndex(Q_mat{i},t_mat{i});
177-
183+
178184
% Section: Baseflow
179185
[BFI(i),~,BFI_error_str(i)] = sig_BFI(Q_mat{i},t_mat{i},'method','UKIH');
180186
[BaseflowRecessionK(i),~,BaseflowRecessionK_error_str(i)] = ...
181-
sig_BaseflowRecessionK(Q_mat{i},t_mat{i},'eps',eps,'recession_length',recession_length,'n_start',n_start);
182-
187+
sig_BaseflowRecessionK(Q_mat{i},t_mat{i},'eps',eps,'recession_length',recession_length,'n_start',n_start);
188+
183189
end
184190

185191
% add results to struct array
@@ -195,7 +201,9 @@
195201
results.Recession_a_Seasonality_error_str = Recession_a_Seasonality_error_str;
196202
results.AverageStorage = AverageStorage;
197203
results.AverageStorage_error_str = AverageStorage_error_str;
198-
results.RecessionParameters = RecessionParameters;
204+
results.RecessionParameters_a = RecessionParameters_a;
205+
results.RecessionParameters_b = RecessionParameters_b;
206+
results.RecessionParameters_T0 = RecessionParameters_T0;
199207
results.RecessionParameters_error_str = RecessionParameters_error_str;
200208
results.MRC_num_segments = MRC_num_segments;
201209
results.MRC_num_segments_error_str = MRC_num_segments_error_str;

TOSSH_code/signature_functions/sig_RecessionAnalysis.m

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
%
2626
% OUTPUT
2727
% Recession_Parameters: matrix with parameters alpha, beta (=1 for
28-
% exponential fit) for each recession segment
28+
% exponential fit) for each recession segment.
29+
% Recession_Parameters(:,1): a, scaling parameter
30+
% Recession_Parameters(:,2): b, parameter of non-linearity
2931
% recession_month: approx. month of recession
3032
% error_flag: 0 (no error), 1 (warning), 2 (error in data check), 3
3133
% (error in signature calculation)
@@ -57,6 +59,37 @@
5759
% This software is distributed under the GNU Public License Version 3.
5860
% See <https://www.gnu.org/licenses/gpl-3.0.en.html> for details.
5961

62+
% NOTE: Post-processing of Recession Parameters
63+
%
64+
% Post-processing of Recession parameters can be done as:
65+
% RecessionParameters_a(i) = median((RecessionParametersTemp(:,1)),'omitnan');
66+
% RecessionParameters_b(i) = median(RecessionParametersTemp(:,2),'omitnan');
67+
% RecessionParametersT0Temp = 1./(RecessionParametersTemp(:,1).*median(Q_mat{i}(Q_mat{i}>0),'omitnan').^(RecessionParametersTemp(:,2)-1));
68+
% ReasonableT0 = and(RecessionParametersTemp(:,2)>0.5,RecessionParametersTemp(:,2)<5);
69+
% RecessionParameters_T0(i) = median(RecessionParametersT0Temp(ReasonableT0),'omitnan');
70+
71+
% RecessionParameters_T0 is characteristic timescale of recessions at median flow; It can be obtained
72+
% by fitting a line to the dQ/dt versus Q point cloud in log-log space for each individual recession,
73+
% with Q scaled by median Q; T0 is the median value of −1/intercept (McMillan et al., 2021).
74+
75+
% RecessionParameters_T0 can be derived from RecessionParameters_a and RecessionParameters_b as follows (McMillan et al, 2014):
76+
% Let Qhat = Q/Qmedian, then:
77+
% dQhat/dt = - (1/T0) * Qhat^b
78+
% Separating constant terms,
79+
% 1/Qmedian * dQ/dt = - (1/T0) * Q^b * (1/Qmedian)^b
80+
% dQ/dt = - (1/T0) * Q^b * (1/Qmedian) ^ (b-1)
81+
% As our estimate of a and b parameters are from:
82+
% dQ/dt = - a * Q^b
83+
% It leads to:
84+
% a = (1/T0) * (1/Qmedian) ^ (b-1)
85+
% T0 = (1/a) * (1/Qmedian) ^ (b-1)
86+
% T0 = 1 / (a * Qmedian ^ (b-1)) # This corresponds to the code for calculating RecessionParametersT0Temp
87+
%
88+
% McMillan, H., Gueguen, M., Grimon, E., Woods, R., Clark, M., & Rupp, D. E. (2014).
89+
% Spatial variability of hydrological processes and model structure diagnostics in a 50 km2 catchment.
90+
% Hydrological Processes, 28(18), 4896-4913. https://doi.org/10.1002/hyp.9988
91+
92+
6093
% check input parameters
6194
if nargin < 2
6295
error('Not enough input arguments.')

0 commit comments

Comments
 (0)