1 /*
2   This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data.
3 
4   Copyright (C) 2006 Brockmann Consult
5 
6   Author: Ralf Quast
7 
8 */
9 
10 // clang-format off
11 /*
12       MODULE      OPERATOR     INDEX    DESCRIPTION
13 
14       EcaCfd      eca_cfd      CFD      maximum number of consecutive frost days
15       EcaCsu      eca_csu      CSU      maximum number of consecutive summer days
16       EcaCwdi     eca_cwdi     CWDI     cold wave duration index
17       EcaCwfi     eca_cwfi     CWFI     number of cold-spell days
18       EcaEtr      eca_etr      ETR      intra-period extreme temperature range
19       EcaFd       eca_fd       FD       number of frost days
20       EcaGsl      eca_gsl      GSL      growing season length
21       EcaHd       eca_hd       HD       heating degree days
22       EcaHwdi     eca_hwdi     HWDI     heat wave duration index
23       EcaHwfi     eca_hwfi     HWFI     number of warm-spell days
24       EcaId       eca_id       ID       number of ice days
25       EcaSu       eca_su       SU       number of summer days
26       EcaTg10p    eca_tg10p    TG10p    percent of time TX < 10th percentile of daily mean temperature
27       EcaTg90p    eca_tg90p    TG90p    percent of time TX > 90th percentile of daily mean temperature
28       EcaTn10p    eca_tn10p    TN10p    percent of time TX < 10th percentile of daily minimum temperature
29       EcaTn90p    eca_tn90p    TN90p    percent of time TX > 90th percentile of daily minimum temperature
30       EcaTr       eca_tr       TR       number of tropical nights
31       EcaTx10p    eca_tx10p    TX10p    percent of time TX < 10th percentile of daily maximum temperature
32       EcaTx90p    eca_tx90p    TX90p    percent of time TX > 90th percentile of daily maximum temperature
33 
34       EcaCdd      eca_cdd      CDD      maximum number of consecutive dry days
35       EcaCwd      eca_cwd      CWD      maximum number of consecutive wet days
36       EcaR10mm    eca_r10mm    R10mm    number of days with precipitation >= 10 mm
37       EcaR20mm    eca_r20mm    R20mm    number of days with precipitation >= 20 mm
38       EcaR75p     eca_r75p     R75p     Percent of time RR > 75th percentile of daily precipitation amount
39       EcaR75ptot  eca_r75ptot  R75pTOT  Percentage of annual total precipitation due to events with RR > 75th percentile of daily precipitation amount
40       EcaR90p     eca_r90p     R90p     Percent of time RR > 90th percentile of daily precipitation amount
41       EcaR90ptot  eca_r90ptot  R90pTOT  Percentage of annual total precipitation due to events with RR > 90th percentile of daily precipitation amount
42       EcaR95p     eca_r95p     R95p     Percent of time RR > 95th percentile of daily precipitation amount
43       EcaR95ptot  eca_r95ptot  R95pTOT  Percentage of annual total precipitation due to events with RR > 95th percentile of daily precipitation amount
44       EcaR99p     eca_r99p     R99p     Percent of time RR > 75th percentile of daily precipitation amount
45       EcaR99ptot  eca_r99ptot  R99pTOT  Percentage of annual total precipitation due to events with RR > 99th percentile of daily precipitation amount
46       EcaRr1      eca_rr1      RR1      number of wet days
47       EcaSdii     eca_sdii     SDII     simple daily intensity index
48 
49       Fdns        fdns                  frost days without surface snow
50 
51       Strwin      strwin                number of strong-wind days
52       Strbre      strbre                number of strong-breeze days
53       Strgal      strgal                number of strong-gale days
54       Hurr        hurr                  number of hurricane days
55 */
56 // clang-format on
57 
58 #include "process_int.h"
59 #include "cdo_options.h"
60 #include "param_conversion.h"
61 #include "ecacore.h"
62 #include "ecautil.h"
63 #include "util_date.h"
64 #include "pmlist.h"
65 
66 #define TO_DEG_CELSIUS(x) ((x) -273.15)
67 #define TO_KELVIN(x) ((x) + 273.15)
68 
69 constexpr int ECA_refdate = 19550101;
70 constexpr int ETC_refdate = 18500101;
71 
72 // clang-format off
73 
74 static const char CFD_NAME[]         = "consecutive_frost_days_index_per_time_period";
75 static const char CFD_LONGNAME[]     = "Consecutive frost days index is the greatest number of consecutive frost days in a given time period. Frost days is the number of days where minimum of temperature is below 0 degree Celsius. The time period should be defined by the bounds of the time coordinate.";
76 //static const char CFD_UNITS[]        = "No.";
77 static const char CFD_NAME2[]        = "number_of_cfd_periods_with_more_than_%ddays_per_time_period";
78 static const char CFD_LONGNAME2[]    = "Number of cfd periods in given time period with more than %d days. The time period should be defined by the bounds of the time coordinate.";
79 static const char CFD_UNITS2[]       = "No.";
80 
81 static const char CSU_NAME[]         = "consecutive_summer_days_index_per_time_period";
82 static const char CSU_LONGNAME[]     = "Consecutive summer days index is the greatest number of consecutive summer days in a given time period. Summer days is the number of days where maximum of temperature is above 25 degree Celsius. The time period should be defined by the bounds of the time coordinate.";
83 //static const char CSU_UNITS[]        = "No.";
84 static const char CSU_NAME2[]        = "number_of_csu_periods_with_more_than_%ddays_per_time_period";
85 static const char CSU_LONGNAME2[]    = "Number of csu periods in given time period with more than %d days. The time period should be defined by the bounds of the time coordinate.";
86 static const char CSU_UNITS2[]       = "No.";
87 
88 static const char CWDI_NAME[]        = "cold_wave_duration_index_wrt_mean_of_reference_period";
89 static const char CWDI_LONGNAME[]    = "This is the number of days per time period where in intervals of at least %d consecutive days the daily minimum temperature is more than %1.0f degrees below a reference value. The reference value is calculated  as the mean of minimum temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
90 static const char CWDI_UNITS[]       = "No.";
91 static const char CWDI_NAME2[]       = "cold_waves_per_time_period";
92 static const char CWDI_LONGNAME2[]   = "Number of cold waves per time period. The time period should be defined by the bounds of the time coordinate.";
93 static const char CWDI_UNITS2[]      = "No.";
94 
95 static const char CWFI_NAME[]        = "cold_spell_days_index_wrt_10th_percentile_of_reference_period";
96 static const char CWFI_NAME_ET[]     = "csdiETCCDI";
97 static const char CWFI_LONGNAME[]    = "This is the number of days per time period where in intervals of at least %d consecutive days the daily mean temperature is below a reference value. The reference value is calculated  as the 10th percentile of daily mean temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
98 static const char CWFI_LONGNAME_ET[] = "Cold Spell Duration Index";
99 static const char CWFI_UNITS[]       = "No.";
100 static const char CWFI_UNITS_ET[]    = "days";
101 static const char CWFI_NAME2[]       = "cold_spell_periods_per_time_period";
102 static const char CWFI_LONGNAME2[]   = "Number of cold spell periods per time period. The time period should be defined by the bounds of the time coordinate.";
103 static const char CWFI_UNITS2[]      = "No.";
104 
105 static const char ETR_NAME[]         = "intra_period_extreme_temperature_range";
106 static const char ETR_LONGNAME[]     = "Difference between the absolute extreme temperatures in observation period. The time period should be defined by the bounds of the time coordinate.";
107 //static const char ETR_UNITS[]        = "K";
108 
109 static const char FD_NAME[]          = "frost_days_index_per_time_period";
110 static const char FD_NAME_ET[]       = "fdETCCDI";
111 static const char FD_LONGNAME[]      = "Frost days index is the number of days where minimum of temperature is below 0 degree Celsius. The time period should be defined by the bounds of the time coordinate.";
112 static const char FD_LONGNAME_ET[]   = "Number of Frost Days";
113 //static const char FD_UNITS[]         = "No.";
114 static const char FD_UNITS_ET[]      = "days";
115 
116 static const char GSL_NAME[]         = "thermal_growing_season_length";
117 static const char GSL_LONGNAME[]     = "Counted are the number of days per calendar year between the first occurrence of at least %d consecutive days where the daily mean temperature is above %1.0f degree Celsius and the first occurrence of at least %d consecutive days after 1st of July where the daily mean temperature is below %1.0f degree Celsius. The time period should be defined by the bounds of the time coordinate.";
118 static const char GSL_UNITS[]        = "No.";
119 static const char GSL_NAME2[]        = "day_of_year_of_growing_season_start";
120 static const char GSL_LONGNAME2[]    = "Day of year of growing season start. The time period should be defined by the bounds of the time coordinate.";
121 static const char GSL_UNITS2[]       = "No.";
122 
123 static const char HD_NAME[]          = "heating_degree_days_per_time_period";
124 static const char HD_LONGNAME[]      = "Heating degree days relates the outside temperature with the room temperature during the heating period. It is the sum of the difference between room temperature X and daily mean temperature Y on days where Y is below a given constant A. X is 20 degree Celsius and A is 15 degree Celsius according to VDI guidelines. According to ECAD both X and A are 17 degree Celsius. The time period should be defined by the bounds of the time coordinate.";
125 static const char HD_UNITS[]         = "No.";
126 
127 static const char HWDI_NAME[]        = "heat_wave_duration_index_wrt_mean_of_reference_period";
128 static const char HWDI_LONGNAME[]    = "This is the number of days per time period where in intervals of at least %d consecutive days the daily maximum temperature is more than %1.0f degrees above a reference value. The reference value is calculated  as the mean of maximum temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
129 static const char HWDI_UNITS[]       = "No.";
130 static const char HWDI_NAME2[]       = "heat_waves_per_time_period";
131 static const char HWDI_LONGNAME2[]   = "Number of heat waves per time period. The time period should be defined by the bounds of the time coordinate.";
132 static const char HWDI_UNITS2[]      = "No.";
133 
134 static const char HWFI_NAME[]        = "warm_spell_days_index_wrt_90th_percentile_of_reference_period";
135 static const char HWFI_NAME_ET[]     = "wsdiETCCDI";
136 static const char HWFI_LONGNAME[]    = "This is the number of days per time period where in intervals of at least %d consecutive days the daily mean temperature is above a reference value. The reference value is calculated  as the 90th percentile of daily mean temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
137 static const char HWFI_LONGNAME_ET[] = "Warm Spell Duration Index";
138 static const char HWFI_UNITS[]       = "No.";
139 static const char HWFI_UNITS_ET[]    = "days";
140 static const char HWFI_NAME2[]       = "warm_spell_periods_per_time_period";
141 static const char HWFI_LONGNAME2[]   = "Number of warm spell periods per time period. The time period should be defined by the bounds of the time coordinate.";
142 static const char HWFI_UNITS2[]      = "No.";
143 
144 static const char ID_NAME[]          = "ice_days_index_per_time_period";
145 static const char ID_NAME_ET[]       = "idETCCDI";
146 static const char ID_LONGNAME[]      = "Ice days index is the number of days where maximum of temperature is below 0 degree Celsius. The time period should be defined by the bounds of the time coordinate.";
147 static const char ID_LONGNAME_ET[]   = "Number of Icing Days";
148 static const char ID_UNITS[]         = "No.";
149 static const char ID_UNITS_ET[]      = "days";
150 
151 static const char SU_NAME[]          = "summer_days_index_per_time_period";
152 static const char SU_NAME_ET[]       = "suETCCDI";
153 static const char SU_LONGNAME[]      = "Summer days index is the number of days where maximum of temperature is above %1.0f degree Celsius. The time period should be defined by the bounds of the time coordinate.";
154 static const char SU_LONGNAME_ET[]   = "Number of Summer Days";
155 //static const char SU_UNITS[]         = "No.";
156 static const char SU_UNITS_ET[]      = "days";
157 
158 static const char TG10P_NAME[]       = "cold_days_percent_wrt_10th_percentile_of_reference_period";
159 static const char TG10P_LONGNAME[]   = "This is the percent of time per time period where daily mean temperature is below a reference value. The reference value is calculated as the 10th percentile of daily mean temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
160 static const char TG10P_UNITS[]      = "Percent";
161 
162 static const char TG90P_NAME[]       = "warm_days_percent_wrt_90th_percentile_of_reference_period";
163 static const char TG90P_LONGNAME[]   = "This is the percent of time per time period where daily mean temperature is above a reference value. The reference value is calculated as the 90th percentile of daily mean temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
164 static const char TG90P_UNITS[]      = "Percent";
165 
166 static const char TN10P_NAME[]       = "cold_nights_percent_wrt_10th_percentile_of_reference_period";
167 static const char TN10P_LONGNAME[]   = "This is the percent of time per time period where daily minimum temperature is below a reference value. The reference value is calculated as the 10th percentile of daily minimum temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
168 static const char TN10P_UNITS[]      = "Percent";
169 
170 static const char TN90P_NAME[]       = "warm_nights_percent_wrt_90th_percentile_of_reference_period";
171 static const char TN90P_LONGNAME[]   = "This is the percent of time per time period where daily minimum temperature is above a reference value. The reference value is calculated as the 90th percentile of daily minimum temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
172 static const char TN90P_UNITS[]      = "Percent";
173 
174 static const char TR_NAME[]          = "tropical_nights_index_per_time_period";
175 static const char TR_NAME_ET[]       = "trETCCDI";
176 static const char TR_LONGNAME[]      = "Tropical nights index is the number of days where minimum of temperature is above %1.0f degree Celsius. The time period should be defined by the bounds of the time coordinate.";
177 static const char TR_LONGNAME_ET[]   = "Number of Tropical Nights";
178 static const char TR_UNITS[]         = "No.";
179 static const char TR_UNITS_ET[]      = "days";
180 
181 static const char TX10P_NAME[]       = "very_cold_days_percent_wrt_10th_percentile_of_reference_period";
182 static const char TX10P_LONGNAME[]   = "This is the percent of time per time period where daily maximum temperature is below a reference value. The reference value is calculated as the 10th percentile of daily maximum temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
183 static const char TX10P_UNITS[]      = "Percent";
184 
185 static const char TX90P_NAME[]       = "very_warm_days_percent_wrt_90th_percentile_of_reference_period";
186 static const char TX90P_LONGNAME[]   = "This is the percent of time per time period where daily maximum temperature is above a reference value. The reference value is calculated as the 90th percentile of daily maximum temperatures of a five day window centred on each calendar day of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
187 static const char TX90P_UNITS[]      = "Percent";
188 
189 static const char CDD_NAME[]         = "consecutive_dry_days_index_per_time_period";
190 static const char CDD_NAME_ET[]      = "cddETCCDI";
191 static const char CDD_LONGNAME[]     = "Consecutive dry days is the greatest number of consecutive days per time period with daily precipitation amount below %g mm. The time period should be defined by the bounds of the time coordinate.";
192 static const char CDD_LONGNAME_ET[]  = "Maximum Number of Consecutive Days with Less Than 1mm of Precipitation [days]";
193 static const char CDD_UNITS[]        = "No.";
194 static const char CDD_UNITS_ET[]      = "days";
195 static const char CDD_NAME2[]        = "number_of_cdd_periods_with_more_than_%ddays_per_time_period";
196 static const char CDD_LONGNAME2[]    = "Number of cdd periods in given time period with more than %d days. The time period should be defined by the bounds of the time coordinate.";
197 static const char CDD_UNITS2[]       = "No.";
198 
199 static const char CWD_NAME[]         = "consecutive_wet_days_index_per_time_period";
200 static const char CWD_NAME_ET[]      = "cwdETCCDI";
201 static const char CWD_LONGNAME[]     = "Consecutive wet days is the greatest number of consecutive days per time period with daily precipitation above %g mm. The time period should be defined by the bounds of the time coordinate.";
202 static const char CWD_LONGNAME_ET[]  = "Maximum Number of Consecutive Days with At Least 1mm of Precipitation";
203 static const char CWD_UNITS[]        = "No.";
204 static const char CWD_UNITS_ET[]     = "days";
205 static const char CWD_NAME2[]        = "number_of_cwd_periods_with_more_than_%ddays_per_time_period";
206 static const char CWD_LONGNAME2[]    = "Number of cwd periods in given time period with more than %d days. The time period should be defined by the bounds of the time coordinate.";
207 static const char CWD_UNITS2[]       = "No.";
208 
209 static const char PD_NAME[]          = "precipitation_days_index_per_time_period";
210 static const char PD_NAME_ET[]       = "r1mmETCCDI";
211 static const char PD_LONGNAME[]      = "precipitation days is the number of days per time period with daily precipitation sum exceeding %g mm. The time period should be defined by the bounds of the time coordinate.";
212 static const char PD_LONGNAME_ET[]   = "Count of Days with At Least 1mm of Precipitation";
213 static const char PD_UNITS[]         = "No.";
214 static const char PD_UNITS_ET[]      = "days";
215 
216 static const char R10MM_NAME[]       = "heavy_precipitation_days_index_per_time_period";
217 static const char R10MM_NAME_ET[]    = "r10mmETCCDI";
218 static const char R10MM_LONGNAME[]   = "Heavy precipitation days is the number of days per time period with daily precipitation sum exceeding 10 mm. The time period should be defined by the bounds of the time coordinate.";
219 static const char R10MM_LONGNAME_ET[]= "Count of Days with At Least 10mm of Precipitation";
220 static const char R10MM_UNITS[]      = "No.";
221 static const char R10MM_UNITS_ET[]   = "days";
222 
223 static const char R20MM_NAME[]       = "very_heavy_precipitation_days_index_per_time_period";
224 static const char R20MM_NAME_ET[]    = "r20mmETCCDI";
225 static const char R20MM_LONGNAME[]   = "Very heavy precipitation days is the number of days with daily precipitation sum exceeding 20 mm. The time period should be defined by the bounds of the time coordinate.";
226 static const char R20MM_LONGNAME_ET[]= "Count of Days with At Least 20mm of Precipitation";
227 static const char R20MM_UNITS[]      = "No.";
228 static const char R20MM_UNITS_ET[]   = "days";
229 
230 static const char R75P_NAME[]        = "moderate_wet_days_wrt_75th_percentile_of_reference_period";
231 static const char R75P_LONGNAME[]    = "This is the percent of time per time period of wet days (daily sum at least 1 mm / day) where daily precipitation amount of a wet day is above a reference value. The reference value is calculated as the 75th percentile of all wet days of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
232 static const char R75P_UNITS[]       = "Percent";
233 
234 static const char R75PTOT_NAME[]     = "precipitation_percent_due_to_R75p_days";
235 static const char R75PTOT_LONGNAME[] = "Percentage of total precipitation amount per time period due to moderate_wet_days_wrt_75th_percentile_of_reference_period. The time period should be defined by the bounds of the time coordinate.";
236 static const char R75PTOT_UNITS[]    = "Percent";
237 
238 static const char R90P_NAME[]        = "wet_days_wrt_90th_percentile_of_reference_period";
239 static const char R90P_LONGNAME[]    = "This is the percent of time per time period of wet days (daily sum at least 1 mm / day) where daily precipitation amount of a wet day is above a reference value. The reference value is calculated as the 90th percentile of all wet days of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
240 static const char R90P_UNITS[]       = "Percent";
241 
242 static const char R90PTOT_NAME[]     = "precipitation_percent_due_to_R90p_days";
243 static const char R90PTOT_LONGNAME[] = "Percentage of total precipitation amount per time period due towet_days_wrt_90th_percentile_of_reference_period. The time period should be defined by the bounds of the time coordinate.";
244 static const char R90PTOT_UNITS[]    = "Percent";
245 
246 static const char R95P_NAME[]        = "very_wet_days_wrt_95th_percentile_of_reference_period";
247 static const char R95P_LONGNAME[]    = "This is the percent of time per time period of wet days (daily sum at least 1 mm / day) where daily precipitation amount of a wet day is above a reference value. The reference value is calculated as the 95th percentile of all wet days of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
248 static const char R95P_UNITS[]       = "Percent";
249 
250 static const char R95PTOT_NAME[]     = "precipitation_percent_due_to_R95p_days";
251 static const char R95PTOT_LONGNAME[] = "Percentage of total precipitation amount per time period due to very_wet_days_wrt_95th_percentile_of_reference_period. The time period should be defined by the bounds of the time coordinate.";
252 static const char R95PTOT_UNITS[]    = "Percent";
253 
254 static const char R99P_NAME[]        = "extremely_wet_days_wrt_99th_percentile_of_reference_period";
255 static const char R99P_LONGNAME[]    = "This is the percent of time per time period of wet days (daily sum at least 1 mm / day) where daily precipitation amount of a wet day is above a reference value. The reference value is calculated as the 99th percentile of all wet days of a given 30 year climate reference period. The time period should be defined by the bounds of the time coordinate.";
256 static const char R99P_UNITS[]       = "Percent";
257 
258 static const char R99PTOT_NAME[]     = "precipitation_percent_due_to_R99p_days";
259 static const char R99PTOT_LONGNAME[] = "percentage of total  precipitation amount per time period due to extremely_wet_days_wrt_99th_percentile_of_reference_period. The time period should be defined by the bounds of the time coordinate.";
260 //static const char R99PTOT_UNITS[]    = "Percent";
261 
262 static const char RR1_NAME[]         = "wet_days_index_per_time_period";
263 static const char RR1_LONGNAME[]     = "Wet days index is the number of days per time period with daily precipitation of at least %g mm. The time period should be defined by the bounds of the time coordinate.";
264 static const char RR1_UNITS[]        = "No.";
265 
266 static const char RX1DAY_NAME[]      = "highest_one_day_precipitation_amount_per_time_period";
267 static const char RX1DAY_NAME_ET[]   = "rx1dayETCCDI";
268 static const char RX1DAY_LONGNAME[]  = "Highest one day precipitation is the maximum of one day precipitation amount in a given time period. The time period should be defined by the bounds of the time coordinate.";
269 static const char RX1DAY_LONGNAME_ET[]= "Maximum 1-day Precipitation";
270 static const char RX1DAY_UNITS[]     = "mm per day";
271 static const char RX1DAY_UNITS_ET[]  = "mm";
272 
273 static const char RX5DAY_NAME[]      = "highest_five_day_precipitation_amount_per_time_period";
274 static const char RX5DAY_NAME_ET[]   = "rx5dayETCCDI";
275 static const char RX5DAY_LONGNAME[]  = "Highest precipitation amount for five day interval (including the calendar day as the last day). The time period should be defined by the bounds of the time coordinate.";
276 static const char RX5DAY_LONGNAME_ET[]= "Maximum Consecutive 5-day Precipitation";
277 static const char RX5DAY_UNITS[]     = "mm per 5 day";
278 static const char RX5DAY_UNITS_ET[]  = "mm";
279 static const char RX5DAY_NAME2[]     = "number_of_5day_heavy_precipitation_periods_per_time_period";
280 static const char RX5DAY_LONGNAME2[] = "Number of 5day periods in given time period with precipitation amount exceeding %1.0f mm / 5 days. The time period should be defined by the bounds of the time coordinate.";
281 static const char RX5DAY_UNITS2[]    = "No.";
282 
283 static const char SDII_NAME[]        = "simple_daily_intensity_index_per_time_period";
284 static const char SDII_NAME_ET[]     = "sdiiETCCDI";
285 static const char SDII_LONGNAME[]    = "Simple daily intensity index is the mean of precipitation amount on wet days. A wet day is a day with precipitation sum of at least %g mm. The time period should be defined by the bounds of the time coordinate.";
286 static const char SDII_LONGNAME_ET[] = "Simple Precipitation Intensity Index";
287 static const char SDII_UNITS[]       = "mm";
288 static const char SDII_UNITS_ET[]    = "mm d-1";
289 
290 static const char FDNS_NAME[]        = "frost_days_where_no_snow_index_per_time_period";
291 static const char FDNS_LONGNAME[]    = "Frost days where no snow index is the number of days without snowcover and where the minimum of temperature is below 0 degree Celsius. The time period should be defined by the bounds of the time coordinate.";
292 static const char FDNS_UNITS[]       = "No.";
293 
294 static const char STRWIN_NAME[]      = "strong_wind_days_index_per_time_period";
295 static const char STRWIN_LONGNAME[]  = "Strong wind days index is the number of days per time period where maximum wind speed is above %1.0f m/s. The time period should be defined by the bounds of the time coordinate.";
296 static const char STRWIN_UNITS[]     = "No.";
297 static const char STRWIN_NAME2[]     = "consecutive_strong_wind_days_index_per_time_period";
298 static const char STRWIN_LONGNAME2[] = "Greatest number of consecutive strong wind days per time period. The time period should be defined by the bounds of the time coordinate.";
299 static const char STRWIN_UNITS2[]    = "No.";
300 
301 static const char STRBRE_NAME[]      = "strong_breeze_days_index_per_time_period";
302 static const char STRBRE_LONGNAME[]  = "Strong breeze days index is the number of days per time period where maximum wind speed is above 10.5 m/s. The time period should be defined by the bounds of the time coordinate.";
303 static const char STRBRE_NAME2[]     = "consecutive_strong_breeze_days_index_per_time_period";
304 static const char STRBRE_LONGNAME2[] = "Greatest number of consecutive strong breeze days per time period. The time period should be defined by the bounds of the time coordinate.";
305 
306 //static const char STRGAL_NAME[]      = "strong_gale_days_index_per_time_period";
307 //static const char STRGAL_LONGNAME[]  = "Strong gale days index is the number of days per time period where maximum wind speed is above 20.5 m/s. The time period should be defined by the bounds of the time coordinate.";
308 //static const char STRGAL_NAME2[]     = "consecutive_strong_gale_days_index_per_time_period";
309 //static const char STRGAL_LONGNAME2[] = "Greatest number of consecutive strong gale days per time period. The time period should be defined by the bounds of the time coordinate.";
310 
311 static const char HURR_NAME[]        = "hurricane_days_index_per_time_period";
312 static const char HURR_LONGNAME[]    = "Hurricane days index is the number of days per time period where maximum wind speed is above 32.5 m/s. The time period should be defined by the bounds of the time coordinate.";
313 static const char HURR_NAME2[]       = "consecutive_hurricane_days_index_per_time_period";
314 static const char HURR_LONGNAME2[]   = "Greatest number of consecutive hurricane days per time period. The time period should be defined by the bounds of the time coordinate.";
315 
316 // clang-format on
317 
318 /* ECA temperature indices */
319 
320 static int
addWithFrequency(const std::vector<std::string> & params,const char * operatorName,size_t defaultDays)321 addWithFrequency(const std::vector<std::string> &params, const char *operatorName, size_t defaultDays)
322 {
323   int opID = 0;
324 
325   KVList kvlist;
326   if (kvlist.parse_arguments(1, params) != 0) cdo_abort("Argument parse error!");
327   auto kv = kvlist.search("freq");
328   if (kv && kv->nvalues > 0)
329     {
330       if (kv->values[0] == "month")
331         opID = cdo_operator_add(operatorName, 0, 8, nullptr);
332       else if (kv->values[0] == "year")
333         opID = cdo_operator_add(operatorName, 0, 10, nullptr);
334       else
335         cdo_abort("Frequency '%s' unknown.", kv->values[0]);
336     }
337   else
338     opID = cdo_operator_add(operatorName, 0, defaultDays, nullptr);
339 
340   return opID;
341 }
342 
343 void *
EcaCfd(void * process)344 EcaCfd(void *process)
345 {
346   int ndays = 5;
347 
348   cdo_initialize(process);
349 
350   if (cdo_operator_argc() > 2) cdo_abort("Too many arguments!");
351   if (cdo_operator_argc() > 1)
352     {
353       auto params = cdo_get_oper_argv();
354       params = std::vector<std::string>(params.begin() + 1, params.end());
355       addWithFrequency(params, "eca_cfd", 31);
356     }
357   else
358     {
359       if (cdo_operator_argc() > 0) ndays = parameter_to_int(cdo_operator_argv(0));
360       cdo_operator_add("eca_cfd", 0, 31, nullptr);
361     }
362 
363   char cfd_longname2[1024];
364   char cfd_name2[1024];
365   sprintf(cfd_longname2, CFD_LONGNAME2, ndays);
366   sprintf(cfd_name2, CFD_NAME2, ndays);
367 
368   ECA_REQUEST_1 request;
369 
370   request.var1.name = CFD_NAME;
371   request.var1.longname = CFD_LONGNAME;
372   request.var1.refdate = ECA_refdate;
373   request.var1.f1 = vfarselltc;
374   request.var1.f1arg = TO_KELVIN(0.0);
375   request.var1.f2 = vfarnum2;
376   request.var1.f3 = field2_max;
377   request.var2.name = cfd_name2;
378   request.var2.longname = cfd_longname2;
379   request.var2.units = CFD_UNITS2;
380   request.var2.h1 = vfarseleqc;
381   request.var2.h1arg = ndays + 1;
382   request.var2.h3 = vfarnum;
383 
384   eca1(request);
385 
386   cdo_finish();
387 
388   return 0;
389 }
390 
391 void *
EcaCsu(void * process)392 EcaCsu(void *process)
393 {
394   double argT = 25.0;
395   int ndays = 5;
396 
397   cdo_initialize(process);
398 
399   if (cdo_operator_argc() > 3) cdo_abort("Too many arguments!");
400   if (cdo_operator_argc() > 2)
401     {
402       auto params = cdo_get_oper_argv();
403       params = std::vector<std::string>(params.begin() + 2, params.end());
404       addWithFrequency(params, "eca_csu", 31);
405     }
406   else if (cdo_operator_argc() > 0)
407     {
408       cdo_operator_add("eca_csu", 0, 31, nullptr);
409       argT = parameter_to_double(cdo_operator_argv(0));
410       if (cdo_operator_argc() == 2) ndays = parameter_to_int(cdo_operator_argv(1));
411     }
412   else
413     cdo_operator_add("eca_csu", 0, 31, nullptr);
414 
415   char csu_longname2[1024];
416   char csu_name2[1024];
417   sprintf(csu_longname2, CSU_LONGNAME2, ndays);
418   sprintf(csu_name2, CSU_NAME2, ndays);
419 
420   ECA_REQUEST_1 request;
421 
422   request.var1.name = CSU_NAME;
423   request.var1.longname = CSU_LONGNAME;
424   request.var1.refdate = ECA_refdate;
425   request.var1.f1 = vfarselgtc;
426   request.var1.f1arg = TO_KELVIN(argT);
427   request.var1.f2 = vfarnum2;
428   request.var1.f3 = field2_max;
429   request.var2.name = csu_name2;
430   request.var2.longname = csu_longname2;
431   request.var2.units = CSU_UNITS2;
432   request.var2.h1 = vfarseleqc;
433   request.var2.h1arg = ndays + 1;
434   request.var2.h3 = vfarnum;
435 
436   eca1(request);
437 
438   cdo_finish();
439 
440   return 0;
441 }
442 
443 void *
EcaCwdi(void * process)444 EcaCwdi(void *process)
445 {
446   int argN = 6;
447   double argT = 5.0;
448 
449   cdo_initialize(process);
450 
451   if (cdo_operator_argc() > 2)
452     {
453       auto params = cdo_get_oper_argv();
454       params = std::vector<std::string>(params.begin() + 2, params.end());
455       addWithFrequency(params, "eca_cwdi", 31);
456       argT = parameter_to_double(cdo_operator_argv(1));
457       argN = parameter_to_int(cdo_operator_argv(0));
458     }
459   else
460     {
461       if (cdo_operator_argc() > 1)
462         argT = parameter_to_double(cdo_operator_argv(1));
463       else if (cdo_operator_argc() > 0)
464         argN = parameter_to_int(cdo_operator_argv(0));
465       cdo_operator_add("eca_cwdi", 0, 31, nullptr);
466     }
467 
468   char longname[sizeof(CWDI_LONGNAME) + 80];
469   sprintf(longname, CWDI_LONGNAME, argN, argT);
470 
471   ECA_REQUEST_2 request;
472 
473   request.var1.name = CWDI_NAME;
474   request.var1.longname = longname;
475   request.var1.refdate = ECA_refdate;
476   request.var1.units = CWDI_UNITS;
477   request.var1.f2 = fieldc_sub;
478   request.var1.f2arg = argT;
479   request.var1.f3 = vfarsellt;
480   request.var1.f4 = vfarnum2;
481   request.var1.f5 = vfarnum3;
482   request.var1.f5arg = argN;
483   request.var2.name = CWDI_NAME2;
484   request.var2.longname = CWDI_LONGNAME2;
485   request.var2.units = CWDI_UNITS2;
486   request.var2.h1 = vfarseleqc;
487   request.var2.h1arg = argN;
488   request.var2.h2 = vfarnum;
489 
490   eca2(request);
491 
492   cdo_finish();
493 
494   return 0;
495 }
496 
497 void *
EcaCwfi(void * process)498 EcaCwfi(void *process)
499 {
500   int argN = 6;
501 
502   cdo_initialize(process);
503 
504   int OPID_ECA = 0, OPID_ETC = 0;
505   if (cdo_operator_argc() > 1)
506     {
507       auto params = cdo_get_oper_argv();
508       params = std::vector<std::string>(params.begin() + 1, params.end());
509       OPID_ECA = addWithFrequency(params, "eca_cwfi", 31);
510       OPID_ETC = addWithFrequency(params, "etccdi_csdi", 10);
511       argN = parameter_to_int(cdo_operator_argv(0));
512     }
513   else
514     {
515       if (cdo_operator_argc() > 0) argN = parameter_to_int(cdo_operator_argv(0));
516       OPID_ECA = cdo_operator_add("eca_cwfi", 0, 31, nullptr);
517       OPID_ETC = cdo_operator_add("etccdi_csdi", 0, 10, nullptr);
518     }
519 
520   char longname[sizeof(CWFI_LONGNAME) + 40];
521   sprintf(longname, CWFI_LONGNAME, argN);
522 
523   ECA_REQUEST_2 request;
524 
525   if (OPID_ECA == cdo_operator_id())
526     {
527       request.var1.name = CWFI_NAME;
528       request.var1.longname = longname;
529       request.var1.units = CWFI_UNITS;
530       request.var1.refdate = ECA_refdate;
531     }
532   else if (OPID_ETC == cdo_operator_id())
533     {
534       request.var1.name = CWFI_NAME_ET;
535       request.var1.longname = CWFI_LONGNAME_ET;
536       request.var1.units = CWFI_UNITS_ET;
537       request.var1.refdate = ETC_refdate;
538     }
539 
540   request.var1.f3 = vfarsellt;
541   request.var1.f4 = vfarnum2;
542   request.var1.f5 = vfarnum3;
543   request.var1.f5arg = argN;
544   request.var2.name = CWFI_NAME2;
545   request.var2.longname = CWFI_LONGNAME2;
546   request.var2.units = CWFI_UNITS2;
547   request.var2.h1 = vfarseleqc;
548   request.var2.h1arg = argN;
549   request.var2.h2 = vfarnum;
550 
551   eca2(request);
552 
553   cdo_finish();
554 
555   return 0;
556 }
557 
558 void *
EcaEtr(void * process)559 EcaEtr(void *process)
560 {
561   cdo_initialize(process);
562 
563   cdo_operator_add("eca_etr", 0, 31, nullptr);
564 
565   ECA_REQUEST_3 request;
566 
567   request.name = ETR_NAME;
568   request.longname = ETR_LONGNAME;
569   request.refdate = ECA_refdate;
570   request.f1 = field2_max;
571   request.f2 = field2_min;
572   request.f3 = field2_sub;
573 
574   eca3(request);
575   cdo_finish();
576 
577   return 0;
578 }
579 
580 void *
EcaFd(void * process)581 EcaFd(void *process)
582 {
583   cdo_initialize(process);
584 
585   int OPID_ECA = 0, OPID_ETC = 0;
586   if (cdo_operator_argc() > 0)
587     {
588       auto params = cdo_get_oper_argv();
589       OPID_ECA = addWithFrequency(params, "eca_fd", 31);
590       OPID_ETC = addWithFrequency(params, "etccdi_fd", 10);
591     }
592   else
593     {
594       OPID_ECA = cdo_operator_add("eca_fd", 0, 31, nullptr);
595       OPID_ETC = cdo_operator_add("etccdi_fd", 0, 10, nullptr);
596     }
597 
598   ECA_REQUEST_1 request;
599 
600   if (OPID_ECA == cdo_operator_id())
601     {
602       request.var1.name = FD_NAME;
603       request.var1.longname = FD_LONGNAME;
604       request.var1.refdate = ECA_refdate;
605     }
606   else if (OPID_ETC == cdo_operator_id())
607     {
608       request.var1.name = FD_NAME_ET;
609       request.var1.longname = FD_LONGNAME_ET;
610       request.var1.units = FD_UNITS_ET;
611       request.var1.refdate = ETC_refdate;
612     }
613 
614   request.var1.f1 = vfarselltc;
615   request.var1.f1arg = TO_KELVIN(0.0);
616   request.var1.f2 = vfarnum;
617 
618   eca1(request);
619 
620   cdo_finish();
621 
622   return 0;
623 }
624 
625 /*
626  * Definition of GSL: (Thermal) Growing Season Length start at the first span
627  * of at least 6 (argN) days with T > 5.0°C (argT) in first half of the year
628  * and ends at the first span of ar least 6 (argN) days with T < 5.0°C (argT)
629  * in the second half.
630  * ATTENTION: Year of the northern hemisphere starts in january to
631  * december, whereas for the southern hemisphere is goes from july to june!
632  * Hence, at least 18 Month of data is needed for computing the gsl of the whole earth.
633  */
634 void *
EcaGsl(void * process)635 EcaGsl(void *process)
636 {
637   int argN = 6;
638   double argT = 5.0;
639   double minLandFraction = 0.5;
640 
641   cdo_initialize(process);
642   cdo_operator_add("eca_gsl", 0, 10, nullptr);
643 
644   if (cdo_operator_argc() > 0) argN = parameter_to_int(cdo_operator_argv(0));
645   if (cdo_operator_argc() > 1) argT = parameter_to_double(cdo_operator_argv(1));
646   if (cdo_operator_argc() > 2) minLandFraction = parameter_to_double(cdo_operator_argv(2));
647 
648   char longname[sizeof(GSL_LONGNAME) + 160];
649   sprintf(longname, GSL_LONGNAME, argN, argT, argN, argT);
650 
651   ECA_REQUEST_4 request;
652 
653   request.name = GSL_NAME;
654   request.longname = longname;
655   request.units = GSL_UNITS;
656   request.name2 = GSL_NAME2;
657   request.longname2 = GSL_LONGNAME2;
658   request.units2 = GSL_UNITS2;
659   request.s1 = vfarselgtc;
660   request.s1arg = TO_KELVIN(argT);
661   request.s2 = vfarselltc;
662   request.s2arg = TO_KELVIN(argT);
663   request.s3 = vfarselgec;
664   request.s3arg = minLandFraction;
665   request.consecutiveDays = argN;
666 
667   eca4(request);
668 
669   cdo_finish();
670 
671   return 0;
672 }
673 
674 void *
EcaHd(void * process)675 EcaHd(void *process)
676 {
677   double argX = 17.0;
678   double argA = 17.0;
679 
680   cdo_initialize(process);
681 
682   cdo_operator_add("eca_hd", 0, 31, nullptr);
683 
684   if (cdo_operator_argc() > 0)
685     {
686       argX = parameter_to_double(cdo_operator_argv(0));
687       argA = argX;
688     }
689   if (cdo_operator_argc() > 1) argA = parameter_to_double(cdo_operator_argv(1));
690 
691   ECA_REQUEST_1 request;
692 
693   request.var1.name = HD_NAME;
694   request.var1.longname = HD_LONGNAME;
695   request.var1.refdate = ECA_refdate;
696   request.var1.units = HD_UNITS;
697   request.var1.f1 = vfarselltc;
698   request.var1.f1arg = TO_KELVIN(argA);
699   request.var1.f2 = field2_sum;
700   request.var1.mulc = -1.0;
701   request.var1.addc = TO_KELVIN(argX);
702 
703   eca1(request);
704 
705   cdo_finish();
706 
707   return 0;
708 }
709 
710 void *
EcaHwdi(void * process)711 EcaHwdi(void *process)
712 {
713   int argN = 6;
714   double argT = 5.0;
715 
716   cdo_initialize(process);
717 
718   if (cdo_operator_argc() > 2)
719     {
720       auto params = cdo_get_oper_argv();
721       params = std::vector<std::string>(params.begin() + 2, params.end());
722       addWithFrequency(params, "eca_hwdi", 31);
723       argN = parameter_to_int(cdo_operator_argv(0));
724       argT = parameter_to_double(cdo_operator_argv(1));
725     }
726   else
727     {
728       if (cdo_operator_argc() > 0) argN = parameter_to_int(cdo_operator_argv(0));
729       if (cdo_operator_argc() > 1) argT = parameter_to_double(cdo_operator_argv(1));
730       cdo_operator_add("eca_hwdi", 0, 31, nullptr);
731     }
732 
733   char longname[sizeof(HWDI_LONGNAME) + 80];
734   sprintf(longname, HWDI_LONGNAME, argN, argT);
735 
736   ECA_REQUEST_2 request;
737 
738   request.var1.name = HWDI_NAME;
739   request.var1.longname = longname;
740   request.var1.refdate = ECA_refdate;
741   request.var1.units = HWDI_UNITS;
742   request.var1.f2 = fieldc_add;
743   request.var1.f2arg = argT;
744   request.var1.f3 = vfarselgt;
745   request.var1.f4 = vfarnum2;
746   request.var1.f5 = vfarnum3;
747   request.var1.f5arg = argN;
748   request.var2.name = HWDI_NAME2;
749   request.var2.longname = HWDI_LONGNAME2;
750   request.var2.units = HWDI_UNITS2;
751   request.var2.h1 = vfarseleqc;
752   request.var2.h1arg = argN;
753   request.var2.h2 = vfarnum;
754 
755   eca2(request);
756 
757   cdo_finish();
758 
759   return 0;
760 }
761 
762 void *
EcaHwfi(void * process)763 EcaHwfi(void *process)
764 {
765   int argN = 6;
766 
767   cdo_initialize(process);
768 
769   int OPID_ECA = 0, OPID_ETC = 0;
770   if (cdo_operator_argc() > 1)
771     {
772       auto params = cdo_get_oper_argv();
773       params = std::vector<std::string>(params.begin() + 1, params.end());
774       OPID_ECA = addWithFrequency(params, "eca_hwfi", 31);
775       OPID_ETC = addWithFrequency(params, "etccdi_wsdi", 10);
776       argN = parameter_to_int(cdo_operator_argv(0));
777     }
778   else
779     {
780       if (cdo_operator_argc() > 0) argN = parameter_to_int(cdo_operator_argv(0));
781       OPID_ECA = cdo_operator_add("eca_hwfi", 0, 31, nullptr);
782       OPID_ETC = cdo_operator_add("etccdi_wsdi", 0, 10, nullptr);
783     }
784 
785   char longname[sizeof(HWFI_LONGNAME) + 40];
786   sprintf(longname, HWFI_LONGNAME, argN);
787 
788   ECA_REQUEST_2 request;
789 
790   if (OPID_ECA == cdo_operator_id())
791     {
792       request.var1.name = HWFI_NAME;
793       request.var1.longname = longname;
794       request.var1.units = HWFI_UNITS;
795       request.var1.refdate = ECA_refdate;
796     }
797   else if (OPID_ETC == cdo_operator_id())
798     {
799       request.var1.name = HWFI_NAME_ET;
800       request.var1.longname = HWFI_LONGNAME_ET;
801       request.var1.units = HWFI_UNITS_ET;
802       request.var1.refdate = ETC_refdate;
803     }
804 
805   request.var1.f3 = vfarselgt;
806   request.var1.f4 = vfarnum2;
807   request.var1.f5 = vfarnum3;
808   request.var1.f5arg = argN;
809   request.var2.name = HWFI_NAME2;
810   request.var2.longname = HWFI_LONGNAME2;
811   request.var2.units = HWFI_UNITS2;
812   request.var2.h1 = vfarseleqc;
813   request.var2.h1arg = argN;
814   request.var2.h2 = vfarnum;
815 
816   eca2(request);
817 
818   cdo_finish();
819 
820   return 0;
821 }
822 
823 void *
EcaId(void * process)824 EcaId(void *process)
825 {
826   cdo_initialize(process);
827 
828   int OPID_ECA = 0, OPID_ETC = 0;
829   if (cdo_operator_argc() > 0)
830     {
831       auto params = cdo_get_oper_argv();
832       OPID_ECA = addWithFrequency(params, "eca_id", 31);
833       OPID_ETC = addWithFrequency(params, "etccdi_id", 10);
834     }
835   else
836     {
837       OPID_ETC = cdo_operator_add("etccdi_id", 0, 10, nullptr);
838       OPID_ECA = cdo_operator_add("eca_id", 0, 31, nullptr);
839     }
840 
841   ECA_REQUEST_1 request;
842 
843   if (OPID_ECA == cdo_operator_id())
844     {
845       request.var1.name = ID_NAME;
846       request.var1.longname = ID_LONGNAME;
847       request.var1.units = ID_UNITS;
848     }
849   else if (OPID_ETC == cdo_operator_id())
850     {
851       request.var1.name = ID_NAME_ET;
852       request.var1.longname = ID_LONGNAME_ET;
853       request.var1.units = ID_UNITS_ET;
854     }
855 
856   request.var1.f1 = vfarselltc;
857   request.var1.f1arg = TO_KELVIN(0.0);
858   request.var1.f2 = vfarnum;
859 
860   eca1(request);
861 
862   cdo_finish();
863 
864   return 0;
865 }
866 
867 void *
EcaSu(void * process)868 EcaSu(void *process)
869 {
870   double argT = 25.0;
871 
872   cdo_initialize(process);
873 
874   int OPID_ECA = 0, OPID_ETC = 0;
875   if (cdo_operator_argc() > 0) argT = parameter_to_double(cdo_operator_argv(0));
876   if (cdo_operator_argc() > 1)
877     {
878       auto params = cdo_get_oper_argv();
879       params = std::vector<std::string>(params.begin() + 1, params.end());
880       OPID_ECA = addWithFrequency(params, "eca_su", 31);
881       OPID_ETC = addWithFrequency(params, "etccdi_su", 10);
882     }
883   else
884     {
885       OPID_ETC = cdo_operator_add("etccdi_su", 0, 10, nullptr);
886       OPID_ECA = cdo_operator_add("eca_su", 0, 31, nullptr);
887     }
888 
889   char longname[sizeof(SU_LONGNAME) + 40];
890   sprintf(longname, SU_LONGNAME, argT);
891 
892   ECA_REQUEST_1 request;
893 
894   if (OPID_ECA == cdo_operator_id())
895     {
896       request.var1.name = SU_NAME;
897       request.var1.longname = longname;
898       request.var1.refdate = ECA_refdate;
899     }
900   else if (OPID_ETC == cdo_operator_id())
901     {
902       request.var1.name = SU_NAME_ET;
903       request.var1.longname = SU_LONGNAME_ET;
904       request.var1.units = SU_UNITS_ET;
905       request.var1.refdate = ETC_refdate;
906     }
907 
908   request.var1.f1 = vfarselgtc;
909   request.var1.f1arg = TO_KELVIN(argT);
910   request.var1.f2 = vfarnum;
911 
912   eca1(request);
913 
914   cdo_finish();
915 
916   return 0;
917 }
918 
919 void *
EcaTg10p(void * process)920 EcaTg10p(void *process)
921 {
922   cdo_initialize(process);
923 
924   cdo_operator_add("eca_tg10p", 0, 31, nullptr);
925 
926   ECA_REQUEST_2 request;
927 
928   request.var1.name = TG10P_NAME;
929   request.var1.longname = TG10P_LONGNAME;
930   request.var1.refdate = ECA_refdate;
931   request.var1.units = TG10P_UNITS;
932   request.var1.f3 = vfarsellt;
933   request.var1.f4 = vfarnum;
934   request.var1.epilog = PERCENT_OF_TIME;
935 
936   eca2(request);
937 
938   cdo_finish();
939 
940   return 0;
941 }
942 
943 void *
EcaTg90p(void * process)944 EcaTg90p(void *process)
945 {
946   cdo_initialize(process);
947 
948   cdo_operator_add("eca_tg90p", 0, 31, nullptr);
949 
950   ECA_REQUEST_2 request;
951 
952   request.var1.name = TG90P_NAME;
953   request.var1.longname = TG90P_LONGNAME;
954   request.var1.refdate = ECA_refdate;
955   request.var1.units = TG90P_UNITS;
956   request.var1.f3 = vfarselgt;
957   request.var1.f4 = vfarnum;
958   request.var1.epilog = PERCENT_OF_TIME;
959 
960   eca2(request);
961 
962   cdo_finish();
963 
964   return 0;
965 }
966 
967 void *
EcaTn10p(void * process)968 EcaTn10p(void *process)
969 {
970   cdo_initialize(process);
971 
972   cdo_operator_add("eca_tn10p", 0, 31, nullptr);
973 
974   ECA_REQUEST_2 request;
975 
976   request.var1.name = TN10P_NAME;
977   request.var1.longname = TN10P_LONGNAME;
978   request.var1.refdate = ECA_refdate;
979   request.var1.units = TN10P_UNITS;
980   request.var1.f3 = vfarsellt;
981   request.var1.f4 = vfarnum;
982   request.var1.epilog = PERCENT_OF_TIME;
983 
984   eca2(request);
985 
986   cdo_finish();
987 
988   return 0;
989 }
990 
991 void *
EcaTn90p(void * process)992 EcaTn90p(void *process)
993 {
994   cdo_initialize(process);
995 
996   cdo_operator_add("eca_tn90p", 0, 31, nullptr);
997 
998   ECA_REQUEST_2 request;
999 
1000   request.var1.name = TN90P_NAME;
1001   request.var1.longname = TN90P_LONGNAME;
1002   request.var1.refdate = ECA_refdate;
1003   request.var1.units = TN90P_UNITS;
1004   request.var1.f3 = vfarselgt;
1005   request.var1.f4 = vfarnum;
1006   request.var1.epilog = PERCENT_OF_TIME;
1007 
1008   eca2(request);
1009 
1010   cdo_finish();
1011 
1012   return 0;
1013 }
1014 
1015 void *
EcaTr(void * process)1016 EcaTr(void *process)
1017 {
1018   double argT = 20.0;
1019 
1020   cdo_initialize(process);
1021 
1022   int OPID_ECA = 0, OPID_ETC = 0;
1023   if (cdo_operator_argc() > 0) argT = parameter_to_double(cdo_operator_argv(0));
1024   if (cdo_operator_argc() > 1)
1025     {
1026       auto params = cdo_get_oper_argv();
1027       params = std::vector<std::string>(params.begin() + 1, params.end());
1028       OPID_ECA = addWithFrequency(params, "eca_tr", 31);
1029       OPID_ETC = addWithFrequency(params, "etccdi_tr", 10);
1030     }
1031   else
1032     {
1033       OPID_ETC = cdo_operator_add("etccdi_tr", 0, 10, nullptr);
1034       OPID_ECA = cdo_operator_add("eca_tr", 0, 31, nullptr);
1035     }
1036 
1037   char tr_longname[1024];
1038   sprintf(tr_longname, TR_LONGNAME, argT);
1039 
1040   ECA_REQUEST_1 request;
1041 
1042   if (OPID_ECA == cdo_operator_id())
1043     {
1044       request.var1.name = TR_NAME;
1045       request.var1.longname = tr_longname;
1046       request.var1.units = TR_UNITS;
1047       request.var1.refdate = ECA_refdate;
1048     }
1049   else if (OPID_ETC == cdo_operator_id())
1050     {
1051       request.var1.name = TR_NAME_ET;
1052       request.var1.longname = TR_LONGNAME_ET;
1053       request.var1.units = TR_UNITS_ET;
1054       request.var1.refdate = ETC_refdate;
1055     }
1056 
1057   request.var1.f1 = vfarselgtc;
1058   request.var1.f1arg = TO_KELVIN(argT);
1059   request.var1.f2 = vfarnum;
1060 
1061   eca1(request);
1062 
1063   cdo_finish();
1064 
1065   return 0;
1066 }
1067 
1068 void *
EcaTx10p(void * process)1069 EcaTx10p(void *process)
1070 {
1071   cdo_initialize(process);
1072 
1073   cdo_operator_add("eca_tx10p", 0, 31, nullptr);
1074 
1075   ECA_REQUEST_2 request;
1076 
1077   request.var1.name = TX10P_NAME;
1078   request.var1.longname = TX10P_LONGNAME;
1079   request.var1.refdate = ECA_refdate;
1080   request.var1.units = TX10P_UNITS;
1081   request.var1.f3 = vfarsellt;
1082   request.var1.f4 = vfarnum;
1083   request.var1.epilog = PERCENT_OF_TIME;
1084 
1085   eca2(request);
1086 
1087   cdo_finish();
1088 
1089   return 0;
1090 }
1091 
1092 void *
EcaTx90p(void * process)1093 EcaTx90p(void *process)
1094 {
1095   cdo_initialize(process);
1096   if (cdo_operator_argc() > 0)
1097     {
1098       if ('m' == cdo_operator_argv(0)[0])
1099         cdo_operator_add("eca_tx90p", 0, 8, nullptr); /* monthly mode */
1100       else
1101         cdo_warning("Parameter value '%s' is invalid. The only valid value is "
1102                     "'m' indicating monthly mode. Operating in yearly mode now.",
1103                     cdo_operator_argv(0));
1104     }
1105   else
1106     cdo_operator_add("eca_tx90p", 0, 31, nullptr);
1107 
1108   ECA_REQUEST_2 request;
1109 
1110   request.var1.name = TX90P_NAME;
1111   request.var1.longname = TX90P_LONGNAME;
1112   request.var1.refdate = ECA_refdate;
1113   request.var1.units = TX90P_UNITS;
1114   request.var1.f3 = vfarselgt;
1115   request.var1.f4 = vfarnum;
1116   request.var1.epilog = PERCENT_OF_TIME;
1117 
1118   eca2(request);
1119 
1120   cdo_finish();
1121 
1122   return 0;
1123 }
1124 
1125 // ECA precipitation indices
1126 
1127 void *
EcaCdd(void * process)1128 EcaCdd(void *process)
1129 {
1130   double threshold = 1;
1131   int ndays = 5;
1132 
1133   cdo_initialize(process);
1134 
1135   int OPID_ECA = 0, OPID_ETC = 0;
1136   if (cdo_operator_argc() > 3)
1137     cdo_abort("Too many arguments!");
1138   else if (cdo_operator_argc() > 2)
1139     {
1140       auto params = cdo_get_oper_argv();
1141       params = std::vector<std::string>(params.begin() + 2, params.end());
1142       OPID_ECA = addWithFrequency(params, "eca_cdd", 31);
1143       OPID_ETC = addWithFrequency(params, "etccdi_cdd", 10);
1144     }
1145   else if (cdo_operator_argc() > 0)
1146     {
1147       threshold = parameter_to_double(cdo_operator_argv(0));
1148       if (cdo_operator_argc() == 2) ndays = parameter_to_int(cdo_operator_argv(1));
1149       OPID_ECA = cdo_operator_add("eca_cdd", 0, 31, nullptr);
1150       OPID_ETC = cdo_operator_add("etccdi_cdd", 0, 10, nullptr);
1151     }
1152   else
1153     {
1154       OPID_ECA = cdo_operator_add("eca_cdd", 0, 31, nullptr);
1155       OPID_ETC = cdo_operator_add("etccdi_cdd", 0, 10, nullptr);
1156     }
1157 
1158   char cdd_longname[1024];
1159   char cdd_longname2[1024];
1160   char cdd_name2[1024];
1161   sprintf(cdd_longname, CDD_LONGNAME, threshold);
1162   sprintf(cdd_longname2, CDD_LONGNAME2, ndays);
1163   sprintf(cdd_name2, CDD_NAME2, ndays);
1164 
1165   ECA_REQUEST_1 request;
1166 
1167   if (OPID_ECA == cdo_operator_id())
1168     {
1169       request.var1.name = CDD_NAME;
1170       request.var1.longname = cdd_longname;
1171       request.var1.units = CDD_UNITS;
1172       request.var1.refdate = ECA_refdate;
1173     }
1174   else if (OPID_ETC == cdo_operator_id())
1175     {
1176       request.var1.name = CDD_NAME_ET;
1177       request.var1.longname = CDD_LONGNAME_ET;
1178       request.var1.units = CDD_UNITS_ET;
1179       request.var1.refdate = ETC_refdate;
1180     }
1181 
1182   request.var1.f1 = vfarselltc;
1183   request.var1.f1arg = threshold;
1184   request.var1.f2 = vfarnum2;
1185   request.var1.f3 = field2_max;
1186   request.var2.name = cdd_name2;
1187   request.var2.longname = cdd_longname2;
1188   request.var2.units = CDD_UNITS2;
1189   request.var2.h1 = vfarseleqc;
1190   request.var2.h1arg = ndays + 1;
1191   request.var2.h3 = vfarnum;
1192 
1193   eca1(request);
1194 
1195   cdo_finish();
1196 
1197   return 0;
1198 }
1199 
1200 void *
EcaCwd(void * process)1201 EcaCwd(void *process)
1202 {
1203   double threshold = 1;
1204   int ndays = 5;
1205 
1206   cdo_initialize(process);
1207 
1208   int OPID_ECA = 0, OPID_ETC = 0;
1209 
1210   if (cdo_operator_argc() > 3)
1211     cdo_abort("Too many arguments!");
1212   else if (cdo_operator_argc() > 2)
1213     {
1214       auto params = cdo_get_oper_argv();
1215       params = std::vector<std::string>(params.begin() + 2, params.end());
1216       OPID_ECA = addWithFrequency(params, "eca_cwd", 31);
1217       OPID_ETC = addWithFrequency(params, "etccdi_cwd", 10);
1218     }
1219   else if (cdo_operator_argc() > 0)
1220     {
1221       threshold = parameter_to_double(cdo_operator_argv(0));
1222       if (cdo_operator_argc() == 2) ndays = parameter_to_int(cdo_operator_argv(1));
1223       OPID_ECA = cdo_operator_add("eca_cwd", 0, 31, nullptr);
1224       OPID_ETC = cdo_operator_add("etccdi_cwd", 0, 10, nullptr);
1225     }
1226   else
1227     {
1228       OPID_ECA = cdo_operator_add("eca_cwd", 0, 31, nullptr);
1229       OPID_ETC = cdo_operator_add("etccdi_cwd", 0, 10, nullptr);
1230     }
1231 
1232   char cwd_longname[1024];
1233   char cwd_longname2[1024];
1234   char cwd_name2[1024];
1235   sprintf(cwd_longname, CWD_LONGNAME, threshold);
1236   sprintf(cwd_longname2, CWD_LONGNAME2, ndays);
1237   sprintf(cwd_name2, CWD_NAME2, ndays);
1238 
1239   ECA_REQUEST_1 request;
1240 
1241   if (OPID_ECA == cdo_operator_id())
1242     {
1243       request.var1.name = CWD_NAME;
1244       request.var1.longname = cwd_longname;
1245       request.var1.units = CWD_UNITS;
1246       request.var1.refdate = ECA_refdate;
1247     }
1248   else if (OPID_ETC == cdo_operator_id())
1249     {
1250       request.var1.name = CWD_NAME_ET;
1251       request.var1.longname = CWD_LONGNAME_ET;
1252       request.var1.units = CWD_UNITS_ET;
1253       request.var1.refdate = ETC_refdate;
1254     }
1255   request.var1.f1 = vfarselgec;
1256   request.var1.f1arg = threshold;
1257   request.var1.f2 = vfarnum2;
1258   request.var1.f3 = field2_max;
1259   request.var2.name = cwd_name2;
1260   request.var2.longname = cwd_longname2;
1261   request.var2.units = CWD_UNITS2;
1262   request.var2.h1 = vfarseleqc;
1263   request.var2.h1arg = ndays + 1;
1264   request.var2.h3 = vfarnum;
1265 
1266   eca1(request);
1267 
1268   cdo_finish();
1269 
1270   return 0;
1271 }
1272 
1273 void *
EcaPd(void * process)1274 EcaPd(void *process)
1275 {
1276   char lnamebuffer[1024];
1277   double threshold = 0;
1278   ECA_REQUEST_1 request;
1279 
1280   cdo_initialize(process);
1281 
1282   int datelenOp = 31;
1283   if (cdo_operator_argc() > 0)
1284     {
1285       auto params = cdo_get_oper_argv();
1286       KVList kvlist;
1287       if (strstr(cdo_operator_argv(0).c_str(), "=") || cdo_operator_argc() > 1)
1288         {
1289           if (cdo_operator_argc() > 1) params = std::vector<std::string>(params.begin() + 1, params.end());
1290           if (kvlist.parse_arguments(1, params) != 0) cdo_abort("Argument parse error!");
1291           auto kv = kvlist.search("freq");
1292           if (kv && kv->nvalues > 0)
1293             {
1294               if (kv->values[0] == "month")
1295                 datelenOp = 8;
1296               else if (kv->values[0] == "year")
1297                 datelenOp = 10;
1298             }
1299         }
1300     }
1301 
1302   // clang-format off
1303   const auto ECA_PD       = cdo_operator_add("eca_pd",       0, datelenOp, nullptr);
1304   const auto ETCCDI_PD    = cdo_operator_add("etccdi_r1mm",  0, datelenOp, nullptr);
1305   const auto ECA_R10MM    = cdo_operator_add("eca_r10mm",    0, datelenOp, nullptr);
1306   const auto ETCCDI_R10MM = cdo_operator_add("etccdi_r10mm", 0, datelenOp, nullptr);
1307   const auto ECA_R20MM    = cdo_operator_add("eca_r20mm",    0, datelenOp, nullptr);
1308   const auto ETCCDI_R20MM = cdo_operator_add("etccdi_r20mm", 0, datelenOp, nullptr);
1309   // clang-format on
1310 
1311   const auto operatorID = cdo_operator_id();
1312 
1313   if (operatorID == ECA_PD || operatorID == ETCCDI_PD)
1314     {
1315       if (operatorID == ECA_PD)
1316         {
1317           operator_input_arg("daily precipitation amount threshold in [mm]");
1318 
1319           if (cdo_operator_argc() < 1) cdo_abort("Too few arguments!");
1320           if (cdo_operator_argc() > 2) cdo_abort("Too many arguments!");
1321           threshold = parameter_to_double(cdo_operator_argv(0));
1322           sprintf(lnamebuffer, PD_LONGNAME, threshold);
1323           request.var1.name = PD_NAME;
1324           request.var1.longname = lnamebuffer;
1325           request.var1.units = PD_UNITS;
1326         }
1327       else
1328         {
1329           threshold = 1;
1330           request.var1.name = PD_NAME_ET;
1331           request.var1.longname = PD_LONGNAME_ET;
1332           request.var1.units = PD_UNITS_ET;
1333         }
1334       if (threshold < 0) cdo_abort("Parameter out of range: threshold = %g", threshold);
1335     }
1336   else if (operatorID == ECA_R10MM || operatorID == ETCCDI_R10MM)
1337     {
1338       threshold = 10;
1339       if (operatorID == ECA_R10MM)
1340         {
1341           request.var1.name = R10MM_NAME;
1342           request.var1.longname = R10MM_LONGNAME;
1343           request.var1.units = R10MM_UNITS;
1344           request.var1.refdate = ECA_refdate;
1345         }
1346       else
1347         {
1348           request.var1.name = R10MM_NAME_ET;
1349           request.var1.longname = R10MM_LONGNAME_ET;
1350           request.var1.units = R10MM_UNITS_ET;
1351           request.var1.refdate = ETC_refdate;
1352         }
1353     }
1354   else if (operatorID == ECA_R20MM || operatorID == ETCCDI_R20MM)
1355     {
1356       threshold = 20;
1357       if (operatorID == ECA_R20MM)
1358         {
1359           request.var1.name = R20MM_NAME;
1360           request.var1.longname = R20MM_LONGNAME;
1361           request.var1.units = R20MM_UNITS;
1362           request.var1.refdate = ECA_refdate;
1363         }
1364       else
1365         {
1366           request.var1.name = R20MM_NAME_ET;
1367           request.var1.longname = R20MM_LONGNAME_ET;
1368           request.var1.units = R20MM_UNITS_ET;
1369           request.var1.refdate = ETC_refdate;
1370         }
1371     }
1372 
1373   if (Options::cdoVerbose) cdo_print("threshold = %g", threshold);
1374 
1375   request.var1.f1 = vfarselgec;
1376   request.var1.f1arg = threshold;
1377   request.var1.f2 = vfarnum;
1378 
1379   eca1(request);
1380 
1381   cdo_finish();
1382 
1383   return 0;
1384 }
1385 
1386 void *
EcaR75p(void * process)1387 EcaR75p(void *process)
1388 {
1389   cdo_initialize(process);
1390 
1391   cdo_operator_add("eca_r75p", 0, 31, nullptr);
1392 
1393   ECA_REQUEST_2 request;
1394 
1395   request.var1.name = R75P_NAME;
1396   request.var1.longname = R75P_LONGNAME;
1397   request.var1.refdate = ECA_refdate;
1398   request.var1.units = R75P_UNITS;
1399   request.var1.f1 = vfarselgec;
1400   request.var1.f3 = vfarselgt;
1401   request.var1.f4 = vfarnum;
1402   request.var1.epilog = PERCENT_OF_TIME;
1403 
1404   eca2(request);
1405 
1406   cdo_finish();
1407 
1408   return 0;
1409 }
1410 
1411 void *
EcaR75ptot(void * process)1412 EcaR75ptot(void *process)
1413 {
1414   cdo_initialize(process);
1415 
1416   cdo_operator_add("eca_r75ptot", 0, 31, nullptr);
1417 
1418   ECA_REQUEST_2 request;
1419 
1420   request.var1.name = R75PTOT_NAME;
1421   request.var1.longname = R75PTOT_LONGNAME;
1422   request.var1.refdate = ECA_refdate;
1423   request.var1.units = R75PTOT_UNITS;
1424   request.var1.f1 = vfarselgec;
1425   request.var1.f3 = vfarselgt;
1426   request.var1.f4 = field2_sum;
1427   request.var1.epilog = PERCENT_OF_TOTAL_AMOUNT;
1428 
1429   eca2(request);
1430 
1431   cdo_finish();
1432 
1433   return 0;
1434 }
1435 
1436 void *
EcaR90p(void * process)1437 EcaR90p(void *process)
1438 {
1439   cdo_initialize(process);
1440 
1441   cdo_operator_add("eca_r90p", 0, 31, nullptr);
1442 
1443   ECA_REQUEST_2 request;
1444 
1445   request.var1.name = R90P_NAME;
1446   request.var1.longname = R90P_LONGNAME;
1447   request.var1.refdate = ECA_refdate;
1448   request.var1.units = R90P_UNITS;
1449   request.var1.f1 = vfarselgec;
1450   request.var1.f3 = vfarselgt;
1451   request.var1.f4 = vfarnum;
1452   request.var1.epilog = PERCENT_OF_TIME;
1453 
1454   eca2(request);
1455 
1456   cdo_finish();
1457 
1458   return 0;
1459 }
1460 
1461 void *
EcaR90ptot(void * process)1462 EcaR90ptot(void *process)
1463 {
1464   cdo_initialize(process);
1465 
1466   cdo_operator_add("eca_r90ptot", 0, 31, nullptr);
1467 
1468   ECA_REQUEST_2 request;
1469 
1470   request.var1.name = R90PTOT_NAME;
1471   request.var1.longname = R90PTOT_LONGNAME;
1472   request.var1.refdate = ECA_refdate;
1473   request.var1.units = R90PTOT_UNITS;
1474   request.var1.f1 = vfarselgec;
1475   request.var1.f3 = vfarselgt;
1476   request.var1.f4 = field2_sum;
1477   request.var1.epilog = PERCENT_OF_TOTAL_AMOUNT;
1478 
1479   eca2(request);
1480 
1481   cdo_finish();
1482 
1483   return 0;
1484 }
1485 
1486 void *
EcaR95p(void * process)1487 EcaR95p(void *process)
1488 {
1489   cdo_initialize(process);
1490 
1491   cdo_operator_add("eca_r95p", 0, 31, nullptr);
1492 
1493   ECA_REQUEST_2 request;
1494 
1495   request.var1.name = R95P_NAME;
1496   request.var1.longname = R95P_LONGNAME;
1497   request.var1.refdate = ECA_refdate;
1498   request.var1.units = R95P_UNITS;
1499   request.var1.f1 = vfarselgec;
1500   request.var1.f3 = vfarselgt;
1501   request.var1.f4 = vfarnum;
1502   request.var1.epilog = PERCENT_OF_TIME;
1503 
1504   eca2(request);
1505 
1506   cdo_finish();
1507 
1508   return 0;
1509 }
1510 
1511 void *
EcaR95ptot(void * process)1512 EcaR95ptot(void *process)
1513 {
1514   cdo_initialize(process);
1515 
1516   cdo_operator_add("eca_r95ptot", 0, 31, nullptr);
1517 
1518   ECA_REQUEST_2 request;
1519 
1520   request.var1.name = R95PTOT_NAME;
1521   request.var1.longname = R95PTOT_LONGNAME;
1522   request.var1.refdate = ECA_refdate;
1523   request.var1.units = R95PTOT_UNITS;
1524   request.var1.f1 = vfarselgec;
1525   request.var1.f3 = vfarselgt;
1526   request.var1.f4 = field2_sum;
1527   request.var1.epilog = PERCENT_OF_TOTAL_AMOUNT;
1528 
1529   eca2(request);
1530 
1531   cdo_finish();
1532 
1533   return 0;
1534 }
1535 
1536 void *
EcaR99p(void * process)1537 EcaR99p(void *process)
1538 {
1539   cdo_initialize(process);
1540 
1541   cdo_operator_add("eca_r99p", 0, 31, nullptr);
1542 
1543   ECA_REQUEST_2 request;
1544 
1545   request.var1.name = R99P_NAME;
1546   request.var1.longname = R99P_LONGNAME;
1547   request.var1.refdate = ECA_refdate;
1548   request.var1.units = R99P_UNITS;
1549   request.var1.f1 = vfarselgec;
1550   request.var1.f3 = vfarselgt;
1551   request.var1.f4 = vfarnum;
1552   request.var1.epilog = PERCENT_OF_TIME;
1553 
1554   eca2(request);
1555 
1556   cdo_finish();
1557 
1558   return 0;
1559 }
1560 
1561 void *
EcaR99ptot(void * process)1562 EcaR99ptot(void *process)
1563 {
1564   cdo_initialize(process);
1565 
1566   cdo_operator_add("eca_r99ptot", 0, 31, nullptr);
1567 
1568   ECA_REQUEST_2 request;
1569 
1570   request.var1.name = R99PTOT_NAME;
1571   request.var1.longname = R99PTOT_LONGNAME;
1572   request.var1.refdate = ECA_refdate;
1573   request.var1.f1 = vfarselgec;
1574   request.var1.f3 = vfarselgt;
1575   request.var1.f4 = field2_sum;
1576   request.var1.epilog = PERCENT_OF_TOTAL_AMOUNT;
1577 
1578   eca2(request);
1579 
1580   cdo_finish();
1581 
1582   return 0;
1583 }
1584 
1585 void *
EcaRr1(void * process)1586 EcaRr1(void *process)
1587 {
1588   double threshold = 1;
1589 
1590   cdo_initialize(process);
1591 
1592   if (cdo_operator_argc() > 2)
1593     cdo_abort("Too many arguments!");
1594   else if (cdo_operator_argc() > 1)
1595     {
1596       auto params = cdo_get_oper_argv();
1597       params = std::vector<std::string>(params.begin() + 1, params.end());
1598       addWithFrequency(params, "eca_rr1", 31);
1599     }
1600   else
1601     {
1602       if (cdo_operator_argc() == 1) threshold = parameter_to_double(cdo_operator_argv(0));
1603       cdo_operator_add("eca_rr1", 0, 31, nullptr);
1604     }
1605 
1606   char lnamebuffer[1024];
1607   sprintf(lnamebuffer, RR1_LONGNAME, threshold);
1608 
1609   ECA_REQUEST_1 request;
1610 
1611   request.var1.name = RR1_NAME;
1612   request.var1.longname = lnamebuffer;
1613   request.var1.units = RR1_UNITS;
1614   request.var1.f1 = vfarselgec;
1615   request.var1.f1arg = threshold;
1616   request.var1.f2 = vfarnum;
1617 
1618   eca1(request);
1619 
1620   cdo_finish();
1621 
1622   return 0;
1623 }
1624 
1625 void *
EcaRx1day(void * process)1626 EcaRx1day(void *process)
1627 {
1628   cdo_initialize(process);
1629 
1630   int OPID_ECA = 0, OPID_ETC = 0;
1631 
1632   if (cdo_operator_argc() > 0)
1633     {
1634       auto params = cdo_get_oper_argv();
1635       OPID_ECA = addWithFrequency(params, "eca_rx1day", 31);
1636       OPID_ETC = addWithFrequency(params, "etccdi_rx1day", 10);
1637     }
1638   else
1639     {
1640       OPID_ECA = cdo_operator_add("eca_rx1day", 0, 31, nullptr);
1641       OPID_ETC = cdo_operator_add("etccdi_rx1day", 0, 10, nullptr);
1642     }
1643 
1644   ECA_REQUEST_1 request;
1645 
1646   if (OPID_ECA == cdo_operator_id())
1647     {
1648       request.var1.name = RX1DAY_NAME;
1649       request.var1.longname = RX1DAY_LONGNAME;
1650       request.var1.units = RX1DAY_UNITS;
1651       request.var1.refdate = ECA_refdate;
1652     }
1653   else if (OPID_ETC == cdo_operator_id())
1654     {
1655       request.var1.name = RX1DAY_NAME_ET;
1656       request.var1.longname = RX1DAY_LONGNAME_ET;
1657       request.var1.units = RX1DAY_UNITS_ET;
1658       request.var1.refdate = ETC_refdate;
1659     }
1660   request.var1.f2 = field2_max;
1661 
1662   eca1(request);
1663 
1664   cdo_finish();
1665 
1666   return 0;
1667 }
1668 
1669 void *
EcaRx5day(void * process)1670 EcaRx5day(void *process)
1671 {
1672   double argX = 50.0;
1673 
1674   cdo_initialize(process);
1675 
1676   int OPID_ECA = 0, OPID_ETC = 0;
1677   if (cdo_operator_argc() > 0)
1678     {
1679       argX = parameter_to_double(cdo_operator_argv(0));
1680       if (cdo_operator_argc() > 1)
1681         {
1682           auto params = cdo_get_oper_argv();
1683           params = std::vector<std::string>(params.begin() + 1, params.end());
1684           OPID_ECA = addWithFrequency(params, "eca_rx5day", 31);
1685           OPID_ETC = addWithFrequency(params, "etccdi_rx5day", 10);
1686         }
1687       else
1688         {
1689           OPID_ECA = cdo_operator_add("eca_rx5day", 0, 31, nullptr);
1690           OPID_ETC = cdo_operator_add("etccdi_rx5day", 0, 10, nullptr);
1691         }
1692     }
1693   else
1694     {
1695       OPID_ECA = cdo_operator_add("eca_rx5day", 0, 31, nullptr);
1696       OPID_ETC = cdo_operator_add("etccdi_rx5day", 0, 10, nullptr);
1697     }
1698 
1699   char longname[sizeof(RX5DAY_LONGNAME2) + 40];
1700   sprintf(longname, RX5DAY_LONGNAME2, argX);
1701 
1702   ECA_REQUEST_1 request;
1703 
1704   if (OPID_ECA == cdo_operator_id())
1705     {
1706       request.var1.name = RX5DAY_NAME;
1707       request.var1.longname = RX5DAY_LONGNAME;
1708       request.var1.units = RX5DAY_UNITS;
1709       request.var1.refdate = ECA_refdate;
1710     }
1711   else if (OPID_ETC == cdo_operator_id())
1712     {
1713       request.var1.name = RX5DAY_NAME_ET;
1714       request.var1.longname = RX5DAY_LONGNAME_ET;
1715       request.var1.units = RX5DAY_UNITS_ET;
1716       request.var1.refdate = ETC_refdate;
1717     }
1718   request.var1.f2 = field2_max;
1719   request.var2.name = RX5DAY_NAME2;
1720   request.var2.longname = longname;
1721   request.var2.units = RX5DAY_UNITS2;
1722   request.var2.h1 = vfarselgec;
1723   request.var2.h1arg = argX;
1724   request.var2.h2 = vfarnum;
1725 
1726   eca1(request);
1727 
1728   cdo_finish();
1729 
1730   return 0;
1731 }
1732 
1733 void *
EcaSdii(void * process)1734 EcaSdii(void *process)
1735 {
1736   ECA_REQUEST_1 request;
1737   char lnamebuffer[1024];
1738   double threshold = 1;
1739 
1740   cdo_initialize(process);
1741   int OPID_ECA = 0, OPID_ETC = 0;
1742 
1743   if (cdo_operator_argc() > 2)
1744     cdo_abort("Too many arguments!");
1745   else if (cdo_operator_argc() > 1)
1746     {
1747       auto params = cdo_get_oper_argv();
1748       params = std::vector<std::string>(params.begin() + 1, params.end());
1749       OPID_ECA = addWithFrequency(params, "eca_sdii", 31);
1750       OPID_ETC = addWithFrequency(params, "etccdi_sdii", 10);
1751     }
1752   else
1753     {
1754       OPID_ECA = cdo_operator_add("eca_sdii", 0, 31, nullptr);
1755       OPID_ETC = cdo_operator_add("etccdi_sdii", 0, 31, nullptr);
1756       if (cdo_operator_argc() == 1) threshold = parameter_to_double(cdo_operator_argv(0));
1757     }
1758 
1759   sprintf(lnamebuffer, SDII_LONGNAME, threshold);
1760   if (OPID_ECA == cdo_operator_id())
1761     {
1762       request.var1.name = SDII_NAME;
1763       request.var1.longname = lnamebuffer;
1764       request.var1.units = SDII_UNITS;
1765     }
1766   else if (OPID_ETC == cdo_operator_id())
1767     {
1768       request.var1.name = SDII_NAME_ET;
1769       request.var1.longname = SDII_LONGNAME_ET;
1770       request.var1.units = SDII_UNITS_ET;
1771     }
1772 
1773   request.var1.f1 = vfarselgec;
1774   request.var1.f1arg = threshold;
1775   request.var1.f2 = field2_sum;
1776   request.var1.epilog = MEAN;
1777 
1778   eca1(request);
1779   cdo_finish();
1780 
1781   return 0;
1782 }
1783 
1784 void *
Fdns(void * process)1785 Fdns(void *process)
1786 {
1787   ECA_REQUEST_2 request;
1788 
1789   cdo_initialize(process);
1790   cdo_operator_add("fdns", 0, 31, nullptr);
1791 
1792   request.var1.name = FDNS_NAME;
1793   request.var1.longname = FDNS_LONGNAME;
1794   request.var1.refdate = ECA_refdate;
1795   request.var1.units = FDNS_UNITS;
1796   request.var1.f1 = vfarsellec;
1797   request.var1.f1arg = TO_KELVIN(0.0);
1798   request.var1.f2 = vfarsellec;
1799   request.var1.f2arg = 0.01;
1800   request.var1.f3 = field2_add;  // any f with f(a, b) = miss, if a = miss or b = miss will do here
1801   request.var1.f4 = vfarnum;
1802 
1803   eca2(request);
1804 
1805   cdo_finish();
1806 
1807   return 0;
1808 }
1809 
1810 void *
Strwin(void * process)1811 Strwin(void *process)
1812 {
1813   double maxWind = 10.5;
1814 
1815   cdo_initialize(process);
1816 
1817   if (cdo_operator_argc() > 2)
1818     cdo_abort("Too many arguments!");
1819   else if (cdo_operator_argc() > 1)
1820     {
1821       auto params = cdo_get_oper_argv();
1822       params = std::vector<std::string>(params.begin() + 1, params.end());
1823       addWithFrequency(params, "strwin", 31);
1824     }
1825   else
1826     {
1827       if (cdo_operator_argc() > 0) maxWind = parameter_to_double(cdo_operator_argv(0));
1828       cdo_operator_add("strwin", 0, 31, nullptr);
1829     }
1830 
1831   char longname[sizeof(STRWIN_LONGNAME) + 40];
1832   sprintf(longname, STRWIN_LONGNAME, maxWind);
1833 
1834   ECA_REQUEST_1 request;
1835 
1836   request.var1.name = STRWIN_NAME;
1837   request.var1.longname = longname;
1838   request.var1.refdate = ECA_refdate;
1839   request.var1.units = STRWIN_UNITS;
1840   request.var1.f1 = vfarselgec;
1841   request.var1.f1arg = maxWind;
1842   request.var1.f2 = vfarnum;
1843   request.var2.name = STRWIN_NAME2;
1844   request.var2.longname = STRWIN_LONGNAME2;
1845   request.var2.units = STRWIN_UNITS2;
1846   request.var2.h1 = vfarselgec;
1847   request.var2.h1arg = maxWind;
1848   request.var2.h2 = vfarnum2;
1849   request.var2.h3 = field2_max;
1850 
1851   eca1(request);
1852 
1853   cdo_finish();
1854 
1855   return 0;
1856 }
1857 
1858 void *
Strbre(void * process)1859 Strbre(void *process)
1860 {
1861   static const double maxWind = 10.5;
1862   ECA_REQUEST_1 request;
1863 
1864   cdo_initialize(process);
1865   if (cdo_operator_argc() > 0)
1866     {
1867       auto params = cdo_get_oper_argv();
1868       addWithFrequency(params, "strbre", 31);
1869     }
1870   else
1871     cdo_operator_add("strbre", 0, 31, nullptr);
1872 
1873   request.var1.name = STRBRE_NAME;
1874   request.var1.longname = STRBRE_LONGNAME;
1875   request.var1.refdate = ECA_refdate;
1876   request.var1.units = STRWIN_UNITS;
1877   request.var1.f1 = vfarselgec;
1878   request.var1.f1arg = maxWind;
1879   request.var1.f2 = vfarnum;
1880   request.var2.name = STRBRE_NAME2;
1881   request.var2.longname = STRBRE_LONGNAME2;
1882   request.var2.units = STRWIN_UNITS2;
1883   request.var2.h1 = vfarselgec;
1884   request.var2.h1arg = maxWind;
1885   request.var2.h2 = vfarnum2;
1886   request.var2.h3 = field2_max;
1887 
1888   eca1(request);
1889   cdo_finish();
1890 
1891   return 0;
1892 }
1893 
1894 void *
Strgal(void * process)1895 Strgal(void *process)
1896 {
1897   static const double maxWind = 20.5;
1898   ECA_REQUEST_1 request;
1899 
1900   cdo_initialize(process);
1901   if (cdo_operator_argc() > 0)
1902     {
1903       auto params = cdo_get_oper_argv();
1904       addWithFrequency(params, "strgal", 31);
1905     }
1906   else
1907     cdo_operator_add("strgal", 0, 31, nullptr);
1908 
1909   request.var1.name = STRBRE_NAME;
1910   request.var1.longname = STRBRE_LONGNAME;
1911   request.var1.refdate = ECA_refdate;
1912   request.var1.units = STRWIN_UNITS;
1913   request.var1.f1 = vfarselgec;
1914   request.var1.f1arg = maxWind;
1915   request.var1.f2 = vfarnum;
1916   request.var2.name = STRBRE_NAME2;
1917   request.var2.longname = STRBRE_LONGNAME2;
1918   request.var2.units = STRWIN_UNITS2;
1919   request.var2.h1 = vfarselgec;
1920   request.var2.h1arg = maxWind;
1921   request.var2.h2 = vfarnum2;
1922   request.var2.h3 = field2_max;
1923 
1924   eca1(request);
1925   cdo_finish();
1926 
1927   return 0;
1928 }
1929 
1930 void *
Hurr(void * process)1931 Hurr(void *process)
1932 {
1933   static const double maxWind = 32.5;
1934   ECA_REQUEST_1 request;
1935 
1936   cdo_initialize(process);
1937   if (cdo_operator_argc() > 0)
1938     {
1939       auto params = cdo_get_oper_argv();
1940       addWithFrequency(params, "hurr", 31);
1941     }
1942   else
1943     cdo_operator_add("hurr", 0, 31, nullptr);
1944 
1945   request.var1.name = HURR_NAME;
1946   request.var1.longname = HURR_LONGNAME;
1947   request.var1.refdate = ECA_refdate;
1948   request.var1.units = STRWIN_UNITS;
1949   request.var1.f1 = vfarselgec;
1950   request.var1.f1arg = maxWind;
1951   request.var1.f2 = vfarnum;
1952   request.var2.name = HURR_NAME2;
1953   request.var2.longname = HURR_LONGNAME2;
1954   request.var2.units = STRWIN_UNITS2;
1955   request.var2.h1 = vfarselgec;
1956   request.var2.h1arg = maxWind;
1957   request.var2.h2 = vfarnum2;
1958   request.var2.h3 = field2_max;
1959 
1960   eca1(request);
1961 
1962   cdo_finish();
1963 
1964   return 0;
1965 }
1966