diff --git a/ChangeLog b/ChangeLog index ddcb7a346dd9a4a77731ddaa75f8c695b7dbc7a4..32dc281bfbb87a0ec5eb963424b2bfd3ec4fbf9c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2024-09-30 Uwe Schulzweida + + * Ydrunstat: added parameter rm=c (readMethod=circular) + +2024-09-19 Uwe Schulzweida + + * Version 2.4.4 release + * cmor operator update + 2024-09-16 Uwe Schulzweida * Timselstat: added support for parameter nskip=-1 diff --git a/doc/tex/mod/Ydrunstat b/doc/tex/mod/Ydrunstat index 26ff47455215d129a25984b56d713cdbf1392598..b73210457d5fa6be47d9ca39dcfb6718a7ce06da 100644 --- a/doc/tex/mod/Ydrunstat +++ b/doc/tex/mod/Ydrunstat @@ -24,7 +24,7 @@ only if the input time series does include the (nts-1)/2 days before and after e @BeginOperator_ydrunmin @Title = Multi-year daily running minimum -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription @IfMan @@ -47,7 +47,7 @@ o(\mbox{366},x) = \mbox{\textbf{min}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mbo @BeginOperator_ydrunmax @Title = Multi-year daily running maximum -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription @IfMan @@ -70,7 +70,7 @@ o(\mbox{366},x) = \mbox{\textbf{max}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mbo @BeginOperator_ydrunsum @Title = Multi-year daily running sum -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription @IfMan @@ -93,7 +93,7 @@ o(\mbox{366},x) = \mbox{\textbf{sum}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mbo @BeginOperator_ydrunmean @Title = Multi-year daily running mean -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription @IfMan @@ -116,7 +116,7 @@ o(\mbox{366},x) = \mbox{\textbf{mean}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mb @BeginOperator_ydrunavg @Title = Multi-year daily running average -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription @IfMan @@ -139,7 +139,7 @@ o(\mbox{366},x) = \mbox{\textbf{avg}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mbo @BeginOperator_ydrunvar @Title = Multi-year daily running variance -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription Normalize by n. @@ -164,7 +164,7 @@ o(\mbox{366},x) = \mbox{\textbf{var}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mbo @BeginOperator_ydrunvar1 @Title = Multi-year daily running variance (n-1) -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription Normalize by (n-1). @@ -189,7 +189,7 @@ o(\mbox{366},x) = \mbox{\textbf{var1}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mb @BeginOperator_ydrunstd @Title = Multi-year daily running standard deviation -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription Normalize by n. @@ -214,7 +214,7 @@ o(\mbox{366},x) = \mbox{\textbf{std}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mbo @BeginOperator_ydrunstd1 @Title = Multi-year daily running standard deviation (n-1) -@Parameter = nts +@Parameter = nts [rm=c] @BeginDescription Normalize by (n-1). @@ -240,6 +240,8 @@ o(\mbox{366},x) = \mbox{\textbf{std1}}\{i(t,x), i(t+1,x), ..., i(t+nts-1,x); \mb @BeginParameter @Item = nts INTEGER Number of timesteps +@Item = rm=c +STRING Read method circular @EndParameter diff --git a/src/Ydrunstat.cc b/src/Ydrunstat.cc index 34aedbc28dc9769f17c46c214586b3418db752a9..9e80e2cf0f049bc51d0b52f9335cac0eb42d4745 100644 --- a/src/Ydrunstat.cc +++ b/src/Ydrunstat.cc @@ -25,6 +25,7 @@ #include "cdi.h" #include "calendar.h" +#include "cdo_options.h" #include "process_int.h" #include "param_conversion.h" #include "datetime.h" @@ -124,6 +125,57 @@ ydstat_finalize(YdayStats &stats, int operfunc) } } +namespace +{ +struct Parameter +{ + int nts{ -1 }; + std::string rm; +}; +} // namespace + +static Parameter +get_parameter() +{ + Parameter parameter; + + auto numParams = cdo_operator_argc(); + if (numParams < 1) cdo_abort("Too few arguments!"); + + auto param1 = cdo_operator_argv(0); + int start = 0; + if (std::isdigit(param1[0]) && !string_contains(param1, '=')) + { + parameter.nts = parameter_to_int(param1); + start = 1; + } + + for (int i = start; i < numParams; ++i) + { + const auto ¶m = cdo_operator_argv(i); + if (!string_contains(param, '=')) cdo_abort("Missing '=' for parameter >%s<!", param); + auto keyValue = split_with_seperator(param, '='); + if (keyValue.size() != 2) cdo_abort("Invalid parameter>%s<!", param); + const auto &key = keyValue[0]; + const auto &value = keyValue[1]; + // clang-format off + if (key == "nts") parameter.nts = parameter_to_int(value); + else if (key == "rm") parameter.rm += value[0]; + else cdo_abort("Invalid parameter key >%s<!", key); + // clang-format on + } + + return parameter; +} + +static void +check_parameter(const Parameter ¶meter) +{ + if (parameter.nts == -1) cdo_abort("Too few parameter!"); + if (parameter.nts <= 0) cdo_abort("Parameter nts must be greater than 0!"); + if (parameter.rm.size() && parameter.rm[0] != 'c') cdo_abort("Parameter rm must only contain 'c'!"); +} + class Ydrunstat : public Process { public: @@ -156,9 +208,9 @@ private: int taxisID2; int vlistID1; - char readMethod; + char readMethod{ 0 }; bool lvarstd; - int numDates; + int numDates{ -1 }; int dpy; FieldVector3D varsData1; @@ -173,11 +225,13 @@ public: auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); - operator_input_arg("number of timesteps"); - auto numParams = cdo_operator_argc(); - numDates = parameter_to_int(cdo_operator_argv(0)); - readMethod = (numParams == 2) ? cdo_operator_argv(1)[0] : '0'; - operator_check_argc((numParams == 2 && readMethod == 'c') ? 2 : 1); + operator_input_arg("number of timesteps, read method"); + + auto parameter = get_parameter(); + check_parameter(parameter); + numDates = parameter.nts; + if (parameter.rm.size()) readMethod = 'c'; + if (Options::cdoVerbose) cdo_print("numDates=%d readMethod=%c", numDates, readMethod); auto lminmax = (operfunc == FieldFunc_Min || operfunc == FieldFunc_Max); lvarstd = (operfunc == FieldFunc_Std || operfunc == FieldFunc_Var || operfunc == FieldFunc_Std1 || operfunc == FieldFunc_Var1); @@ -298,8 +352,12 @@ public: tsID++; } - if (readMethod == 'c' && cdo_assert_files_only()) + cdo_stream_close(streamID1); + + if (readMethod == 'c') { + if (cdo_assert_files_only() == false) cdo_warning("Operators cannot be piped in circular mode"); + auto endYear = cdiDateTimes[numDates - 1].date.year; auto cdiStream = streamOpenRead(cdo_get_stream_name(0)); auto cdiVlistID = streamInqVlist(cdiStream); @@ -356,8 +414,6 @@ public: streamClose(cdiStream); } - else if (readMethod == 'c') - cdo_warning("Operators cannot be piped in circular mode"); ydstat_finalize(stats, operfunc); @@ -388,6 +444,5 @@ public: close() override { cdo_stream_close(streamID2); - cdo_stream_close(streamID1); } }; diff --git a/src/operator_help.cc b/src/operator_help.cc index 56b24157dd83ed3ebc1baaccbef034e3b0680be6..9a1a9c8faf3b4b388e0e45ff1e10060b80d2ff9c 100644 --- a/src/operator_help.cc +++ b/src/operator_help.cc @@ -4098,7 +4098,7 @@ const CdoHelp YdrunstatHelp = { " ydrunvar, ydrunvar1 - Multi-year daily running statistics", "", "SYNOPSIS", - " <operator>,nts infile outfile", + " <operator>,nts[,rm=c] infile outfile", "", "DESCRIPTION", " This module writes running statistical values for each day of year in infile to outfile.", @@ -4160,7 +4160,8 @@ const CdoHelp YdrunstatHelp = { " o(366,x) = var1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", "", "PARAMETER", - " nts INTEGER Number of timesteps", + " nts INTEGER Number of timesteps", + " rm=c STRING Read method circular", }; const CdoHelp YdrunpctlHelp = {