diff --git a/ChangeLog b/ChangeLog index ab4f36f1a4752abfeb44623af17c0e30d459147d..73af592fc419474d2275dd6a473ca208fe69d2da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * Using CDI library version 2.5.1 * Version 2.5.1 release +2025-01-23 Uwe Schulzweida + + * New operator: cinfo - Compact information listed by parameter name + 2025-01-17 Uwe Schulzweida * consects/consecsum: wrong result since release 2.4.0 [Bug #12030] diff --git a/NEWS b/NEWS index 45e8656135ca5d78a98cabbe557963b467a71ea6..bf2de73fce5006ec7818f8747613596e5bf08aee 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ Improvement Version 2.5.1 (6 Feb 2025): + New operators: + * cinfo: Compact information listed by parameter name Fixed bugs: * consects/consecsum: wrong result since release 2.4.0 [Bug #12030] diff --git a/OPERATORS b/OPERATORS index 56dc21b79e59ab0fa3baf9a3c5c32f2c92d4b5c6..876c5031c77b2cb206852d8b26c6dca10c848a54 100644 --- a/OPERATORS +++ b/OPERATORS @@ -9,6 +9,7 @@ Operator catalog: ------------------------------------------------------------- Info info Dataset information listed by parameter identifier Info infon Dataset information listed by parameter name + Info cinfo Compact information listed by parameter name Info map Dataset information and simple map Sinfo sinfo Short information listed by parameter identifier Sinfo sinfon Short information listed by parameter name diff --git a/doc/tex/mod/Info b/doc/tex/mod/Info index 050b5de495e8cb30884cda40a7ae9b9533b00936..41807274ed29d43ca79085d562226a1b95776809 100644 --- a/doc/tex/mod/Info +++ b/doc/tex/mod/Info @@ -5,11 +5,11 @@ @Section = Information @Class = Information @Arguments = infiles -@Operators = info infon map +@Operators = info infon cinfo map @BeginDescription This module writes information about the structure and contents for each field of all input files -to standard output. A field is a horizontal layer of a data variable. All input files need to have +to standard output. A field is a horizontal layer of a data variable. All input files need to have the same structure with the same variables on different timesteps. The information displayed depends on the chosen operator. @EndDescription @@ -43,6 +43,15 @@ identifier to label the parameter. @EndOperator +@BeginOperator_cinfo +@Title = Compact information listed by parameter name + +@BeginDescription +@oper{cinfo} is a compact version of @oper{infon}. It prints the minimum, mean and maximum value for each variable across all layers and time steps. +@EndDescription +@EndOperator + + @BeginOperator_map @Title = Dataset information and simple map @@ -60,18 +69,18 @@ To print information and simple statistics for each field of a dataset use: @EndVerbatim This is an example result of a dataset with one 2D parameter over 12 timesteps: @BeginListing - -1 : Date Time Level Size Miss : Minimum Mean Maximum : Name - 1 : 1987-01-31 12:00:00 0 2048 1361 : 232.77 266.65 305.31 : SST - 2 : 1987-02-28 12:00:00 0 2048 1361 : 233.64 267.11 307.15 : SST - 3 : 1987-03-31 12:00:00 0 2048 1361 : 225.31 267.52 307.67 : SST - 4 : 1987-04-30 12:00:00 0 2048 1361 : 215.68 268.65 310.47 : SST - 5 : 1987-05-31 12:00:00 0 2048 1361 : 215.78 271.53 312.49 : SST - 6 : 1987-06-30 12:00:00 0 2048 1361 : 212.89 272.80 314.18 : SST - 7 : 1987-07-31 12:00:00 0 2048 1361 : 209.52 274.29 316.34 : SST - 8 : 1987-08-31 12:00:00 0 2048 1361 : 210.48 274.41 315.83 : SST - 9 : 1987-09-30 12:00:00 0 2048 1361 : 210.48 272.37 312.86 : SST - 10 : 1987-10-31 12:00:00 0 2048 1361 : 219.46 270.53 309.51 : SST - 11 : 1987-11-30 12:00:00 0 2048 1361 : 230.98 269.85 308.61 : SST - 12 : 1987-12-31 12:00:00 0 2048 1361 : 241.25 269.94 309.27 : SST + -1 : Date Time Level Size Miss : Minimum Mean Maximum : Name + 1 : 1987-01-31 12:00:00 0 2048 1361 : 232.77 266.65 305.31 : SST + 2 : 1987-02-28 12:00:00 0 2048 1361 : 233.64 267.11 307.15 : SST + 3 : 1987-03-31 12:00:00 0 2048 1361 : 225.31 267.52 307.67 : SST + 4 : 1987-04-30 12:00:00 0 2048 1361 : 215.68 268.65 310.47 : SST + 5 : 1987-05-31 12:00:00 0 2048 1361 : 215.78 271.53 312.49 : SST + 6 : 1987-06-30 12:00:00 0 2048 1361 : 212.89 272.80 314.18 : SST + 7 : 1987-07-31 12:00:00 0 2048 1361 : 209.52 274.29 316.34 : SST + 8 : 1987-08-31 12:00:00 0 2048 1361 : 210.48 274.41 315.83 : SST + 9 : 1987-09-30 12:00:00 0 2048 1361 : 210.48 272.37 312.86 : SST + 10 : 1987-10-31 12:00:00 0 2048 1361 : 219.46 270.53 309.51 : SST + 11 : 1987-11-30 12:00:00 0 2048 1361 : 230.98 269.85 308.61 : SST + 12 : 1987-12-31 12:00:00 0 2048 1361 : 241.25 269.94 309.27 : SST @EndListing @EndExample diff --git a/src/Info.cc b/src/Info.cc index 96af398e6914f52f451f0d17621db9c3b237ca6b..d869c8cd95106cdcb4a69fea268eae6897a24c35 100644 --- a/src/Info.cc +++ b/src/Info.cc @@ -298,6 +298,18 @@ print_header(int fileIndex, bool lvinfo, int operfunc) reset_text_color(stdout); } +static void +print_xheader(int fileIndex) +{ + auto e = "Parameter name"; + auto v = (Options::cdoVerbose) ? " : Extra" : ""; + + set_text_color(stdout, BRIGHT); + if (fileIndex) + fprintf(stdout, "%6d : NumSteps NumLevels Gridsize NumMiss : Minimum Mean Maximum : %s%s\n", fileIndex, e, v); + reset_text_color(stdout); +} + static void compute_stat_real(const Field &field, InfoStat &infoStat, size_t &imiss, size_t gridsize) { @@ -347,49 +359,91 @@ print_stat_comp(const InfoStat &infoStat) } static void -info(Field &field, int indg, int indf, int tsID, int fieldID, int levelID, CdiDateTime vDateTime, CdoVar &var, int operfunc, - bool printMap, bool lvinfo, InfoStat &infoStat) +print_xinfo(int numSteps, CdoVar const &var, InfoStat const &infoStat) { - if ((tsID == 0 && fieldID == 0) || printMap) print_header(-(indf + 1), lvinfo, operfunc); + fprintf(stdout, "%6d : ", var.ID + 1); + set_text_color(stdout, GREEN); + fprintf(stdout, "%8d %7d %9zu %9zu ", numSteps, var.nlevels, var.gridsize, infoStat.numMissVals); + reset_text_color(stdout); - auto numMissVals = field.numMissVals; - auto loutput = !lvinfo; + fprintf(stdout, ":"); - if (loutput) infostat_init(infoStat); + set_text_color(stdout, BLUE); + // clang-format off + if (var.nwpv == CDI_REAL) print_stat_real(infoStat); + else print_stat_comp(infoStat); + // clang-format on + reset_text_color(stdout); - infoStat.nlevels += 1; - infoStat.numMissVals += numMissVals; + fprintf(stdout, " : "); + + // set_text_color(stdout, GREEN); + fprintf(stdout, "%-14s", var.name.c_str()); + // reset_text_color(stdout); - if (var.nlevels == infoStat.nlevels) loutput = true; + fprintf(stdout, "\n"); +} +static void +print_info(int indg, int levelID, CdiDateTime &vDateTime, CdoVar const &var, int operfunc, bool lvinfo, InfoStat const &infoStat) +{ char paramstr[32]; - if (loutput) - { - cdiParamToString(var.param, paramstr, sizeof(paramstr)); + cdiParamToString(var.param, paramstr, sizeof(paramstr)); - fprintf(stdout, "%6d ", indg); - fprintf(stdout, ":"); + fprintf(stdout, "%6d :", indg); - auto vdateString = date_to_string(vDateTime.date); - auto vtimeString = time_to_string(vDateTime.time); + auto vdateString = date_to_string(vDateTime.date); + auto vtimeString = time_to_string(vDateTime.time); - set_text_color(stdout, MAGENTA); - fprintf(stdout, "%s %s ", vdateString.c_str(), vtimeString.c_str()); - reset_text_color(stdout); + set_text_color(stdout, MAGENTA); + fprintf(stdout, "%s %s ", vdateString.c_str(), vtimeString.c_str()); + reset_text_color(stdout); - set_text_color(stdout, GREEN); - if (lvinfo) - fprintf(stdout, "%7d ", var.nlevels); - else - fprintf(stdout, "%7g ", cdo_zaxis_inq_level(var.zaxisID, levelID)); + set_text_color(stdout, GREEN); + if (lvinfo) + fprintf(stdout, "%7d ", var.nlevels); + else + fprintf(stdout, "%7g ", cdo_zaxis_inq_level(var.zaxisID, levelID)); - fprintf(stdout, "%8zu %7zu ", var.gridsize, infoStat.numMissVals); - reset_text_color(stdout); + fprintf(stdout, "%8zu %7zu ", var.gridsize, infoStat.numMissVals); + reset_text_color(stdout); - fprintf(stdout, ":"); + fprintf(stdout, ":"); - set_text_color(stdout, BLUE); - } + set_text_color(stdout, BLUE); + // clang-format off + if (var.nwpv == CDI_REAL) print_stat_real(infoStat); + else print_stat_comp(infoStat); + // clang-format on + reset_text_color(stdout); + + fprintf(stdout, " : "); + + // set_text_color(stdout, GREEN); + // clang-format off + if (operfunc == Func_Name) fprintf(stdout, "%-14s", var.name.c_str()); + else if (operfunc == Func_Code) fprintf(stdout, "%4d ", var.code); + else fprintf(stdout, "%-14s", paramstr); + // clang-format on + // reset_text_color(stdout); + + fprintf(stdout, "\n"); +} + +static void +info(Field &field, int indg, int indf, int levelID, CdiDateTime vDateTime, CdoVar &var, int operfunc, bool printMap, bool lvinfo, + bool lcinfo, InfoStat &infoStat) +{ + if (printMap) print_header(-(indf + 1), lvinfo, operfunc); + + auto numMissVals = field.numMissVals; + auto loutput = (not lvinfo and not lcinfo); + + if (loutput) infostat_init(infoStat); + + infoStat.numMissVals += numMissVals; + infoStat.nlevels += 1; + if (not lcinfo and (var.nlevels == infoStat.nlevels)) loutput = true; size_t numNANs = (Options::fast || std::isnan(field.missval)) ? 0 : field_num_NANs(field); var.counter += numNANs; @@ -405,27 +459,7 @@ info(Field &field, int indg, int indf, int tsID, int fieldID, int levelID, CdiDa else compute_stat_comp(field, infoStat, imiss, var.gridsize); // clang-format on - if (loutput) - { - // clang-format off - if (var.nwpv == CDI_REAL) print_stat_real(infoStat); - else print_stat_comp(infoStat); - // clang-format on - - reset_text_color(stdout); - - fprintf(stdout, " : "); - - // set_text_color(stdout, GREEN); - // clang-format off - if (operfunc == Func_Name) fprintf(stdout, "%-14s", var.name.c_str()); - else if (operfunc == Func_Code) fprintf(stdout, "%4d ", var.code); - else fprintf(stdout, "%-14s", paramstr); - // clang-format on - // reset_text_color(stdout); - - fprintf(stdout, "\n"); - } + if (loutput) print_info(indg, levelID, vDateTime, var, operfunc, lvinfo, infoStat); if (imiss != numMissVals && numMissVals) cdo_warning("Found %zu of %zu missing values (%s)!", imiss, numMissVals, var.name); @@ -455,8 +489,8 @@ public: { "infop", Func_Param, 0, InfoHelp }, { "infon", Func_Name, 0, InfoHelp }, { "infoc", Func_Code, 0, InfoHelp }, - { "vinfon", Func_Name, 0, InfoHelp }, - { "xinfon", Func_Name, 0, InfoHelp }, + { "vinfo", Func_Name, 0, InfoHelp }, + { "cinfo", Func_Name, 0, InfoHelp }, { "map", Func_Param, 0, InfoHelp } }, // clang-format on .aliases = {}, @@ -470,6 +504,7 @@ public: bool printMap; bool lvinfo; + bool lcinfo; public: void @@ -477,8 +512,8 @@ public: { if (Options::lazyGridLoad && this_is_the_only_process()) { cdiDefGlobal("NETCDF_LAZY_GRID_LOAD", true); } - auto VINFON = module.get_id("vinfon"); - auto XINFON = module.get_id("xinfon"); + auto VINFO = module.get_id("vinfo"); + auto CINFO = module.get_id("cinfo"); auto MAP = module.get_id("map"); auto operatorID = cdo_operator_id(); @@ -487,7 +522,8 @@ public: operator_check_argc(0); printMap = (operatorID == MAP); - lvinfo = (operatorID == VINFON || operatorID == XINFON); + lvinfo = (operatorID == VINFO); + lcinfo = (operatorID == CINFO); } void @@ -513,6 +549,14 @@ public: FieldVector fieldVector(numTasks); std::vector<InfoStat> infoStatList(numVars); + if (lcinfo) + print_xheader(-(indf + 1)); + else if (not printMap) + print_header(-(indf + 1), lvinfo, operfunc); + + if (lcinfo) + for (auto &infoStat : infoStatList) infostat_init(infoStat); + numSets = 0; int tsID = 0; while (true) @@ -522,7 +566,8 @@ public: auto vDateTime = taxisInqVdatetime(taxisID); - for (int varID = 0; varID < numVars; ++varID) infostat_init(infoStatList[varID]); + if (not lcinfo) + for (auto &infoStat : infoStatList) infostat_init(infoStat); for (int fieldID = 0; fieldID < numFields; ++fieldID) { @@ -537,9 +582,8 @@ public: numSets = lvinfo ? varID + 1 : numSets + 1; - std::function<void()> info_func - = std::bind(info, std::ref(field), numSets, indf, tsID, fieldID, levelID, vDateTime, std::ref(var), operfunc, - printMap, lvinfo, std::ref(infoStatList[varID])); + std::function<void()> info_func = std::bind(info, std::ref(field), numSets, indf, levelID, vDateTime, std::ref(var), + operfunc, printMap, lvinfo, lcinfo, std::ref(infoStatList[varID])); runAsync ? task->doAsync(info_func) : info_func(); } @@ -549,6 +593,11 @@ public: if (runAsync) task->wait(); + cdo_stream_close(streamID); + + if (lcinfo) + for (auto const &var : varList.vars) print_xinfo(tsID, var, infoStatList[var.ID]); + for (auto const &var : varList.vars) { if (var.counter > 0) @@ -558,11 +607,9 @@ public: var.name, var.counter); } } - - cdo_stream_close(streamID); } - if (numSets > 36 && !printMap) print_header(0, lvinfo, operfunc); + if (numSets > 36 && !printMap && !lcinfo) print_header(0, lvinfo, operfunc); } void diff --git a/src/operator_help.cc b/src/operator_help.cc index b24f090e3733f8aabd1abe458106ff29f0bee5ed..2063ca30004801e2ed9aa4f045bd28d244ffb0bc 100644 --- a/src/operator_help.cc +++ b/src/operator_help.cc @@ -6,14 +6,14 @@ const CdoHelp InfoHelp = { "NAME", - " info, infon, map - Information and simple statistics", + " info, infon, cinfo, map - Information and simple statistics", "", "SYNOPSIS", " <operator> infiles", "", "DESCRIPTION", " This module writes information about the structure and contents for each field of all input files", - " to standard output. A field is a horizontal layer of a data variable. All input files need to have ", + " to standard output. A field is a horizontal layer of a data variable. All input files need to have", " the same structure with the same variables on different timesteps.", " The information displayed depends on the chosen operator.", "", @@ -29,6 +29,8 @@ const CdoHelp InfoHelp = { " infon Dataset information listed by parameter name", " The same as operator info but using the name instead of the", " identifier to label the parameter.", + " cinfo Compact information listed by parameter name", + " cinfo is a compact version of infon. It prints the minimum, mean and maximum value for each variable across all layers and time steps.", " map Dataset information and simple map", " Prints information, simple statistics and a map for each field of all input", " datasets. The map will be printed only for fields on a regular lon/lat grid.",