diff --git a/CITATION b/CITATION index 8105be9996fa488f1dfde73a8a5bb12a7adb6c88..2073289a03b108f309171e4ec9f72a1219127ccb 100644 --- a/CITATION +++ b/CITATION @@ -1,14 +1,14 @@ If you use the Climate Data Operators (CDO) to process data for an article in a scientific publication, please cite: -Schulzweida, Uwe. (2022). CDO User Guide (2.1.0). Zenodo. https://doi.org/10.5281/zenodo.7112925 +Schulzweida, Uwe. (2023). CDO User Guide (2.3.0). Zenodo. https://doi.org/10.5281/zenodo.10020800 -@misc{schulzweida_uwe_2022_7112925, +@misc{schulzweida_2023_10020800, author = {Schulzweida, Uwe}, title = {CDO User Guide}, month = oct, - year = 2022, + year = 2023, publisher = {Zenodo}, - version = {2.1.0}, - doi = {10.5281/zenodo.7112925}, - url = {https://doi.org/10.5281/zenodo.7112925} -} \ No newline at end of file + version = {2.3.0}, + doi = {10.5281/zenodo.10020800}, + url = {https://doi.org/10.5281/zenodo.10020800} +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5710d59f73624034568008ef561b3dae62b90c5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,33 @@ +# cmake options: +# +# -DCMAKE_INSTALL_PREFIX=/path/to/install + +cmake_minimum_required( VERSION 3.12 FATAL_ERROR ) + +project( cdo VERSION 2.4.0 LANGUAGES C CXX ) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 20) + +configure_file ( + "${PROJECT_SOURCE_DIR}/cmake/cdo_config.h.in" + "${PROJECT_BINARY_DIR}/config.h" + ) + +include_directories("${PROJECT_BINARY_DIR}") + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +find_package(NetCDF) + +set(HAVE_NETCDF ${netCDF_FOUND} ) + +if (netCDF_FOUND) + set(HAVE_NETCDF 1) +endif () + +add_subdirectory( libcdi/src ) +add_subdirectory( src/lib/yac ) +add_subdirectory( src/lib/gradsdes ) +add_subdirectory( src/lib/healpix ) +add_subdirectory( src ) +#target_link_libraries(cdolib PRIVATE NetCDF) diff --git a/ChangeLog b/ChangeLog index a99c828c6fa88570916b4163a867a6bc3a8ee954..246830ee911d12a1e1d0cd4a65a2b17e7f452b19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,58 @@ -2023-11-29 Uwe Schulzweida +2024-02-22 Uwe Schulzweida + + * Using CDI library version 2.4.0 + * Using YAC version 3.1.0 + * Version 2.4.0 release + +2024-02-21 Uwe Schulzweida + + * setgridtype,lonlat: Converts a regular lonlat grid stored as projection back to a lonlat grid + +2024-02-20 Uwe Schulzweida + + * showattribute: print special global attributes uuidOfHGrid and grid_file_uri + +2024-02-13 Uwe Schulzweida + + * expr: var statement failed (bug fix) + +2024-01-23 Uwe Schulzweida + + * Arith: fill mode for infile2 doesn't work with pipes [Bug #11733] + +2024-01-16 Uwe Schulzweida + + * after: change computation of geopotential height from full to half levels [Bug #11346] + +2024-01-16 Uwe Schulzweida + + * rotated pole mapping failed with negative north_pole_grid_longitude attribute [Bug #11661] + +2024-01-15 Uwe Schulzweida + + * select: allow negative numbers for parameter levidx to select level indices from the end + +2024-01-14 Uwe Schulzweida + + * Vertintml: wrong result with data on model half-levels (bug fix) + +2024-01-12 Uwe Schulzweida + + * New operator: gheight_half - geopotential height on model half-levels + +2024-01-05 Uwe Schulzweida + + * timcor: add pvalue to output, if input has only one field + +2023-10-28 Uwe Schulzweida + + * gradsdes: fix integer overflow in map file + +2023-10-27 Uwe Schulzweida + + * pack: add support to read pack parameters from file + +2023-11-07 Uwe Schulzweida * Using CDI library version 2.3.1 * Version 2.3.1 release diff --git a/NEWS b/NEWS index d6711f14781974cb32f3af00b83d8b42d0e8e776..d57123914b77e3f770a3b261abd77b3cf7f0482b 100644 --- a/NEWS +++ b/NEWS @@ -3,12 +3,25 @@ CDO NEWS Improvement -Version 2.4.0 (21 October 2024): +Version 2.4.0 (22 Feb 2024): New features: + * Changed to C++20 + * Add FDB (Fields DataBase) support (status: experimental) * Remapweights: Use environment variable REMAP_MAP3D=1 to generate all mapfiles of the first 3D field with variing masks + * pack: add support to read pack parameters from file + * select: allow negative numbers for parameter levidx to select level indices from the end New operators: + * New operator: pressure - pressure on full-levels + * New operator: pressure_half - pressure on half-levels + * New operator: delta_pressure - pressure difference of half-levels + * New operator: gheight_half - geopotential height on half-levels Fixed bugs: + * after: change computation of geopotential height from full to half levels [Bug #11346] + * expr: var statement failed + * gradsdes: fix integer overflow in map file + * Arith: fill mode for infile2 doesn't work with pipes [Bug #11733] + * rotated pole mapping failed with negative north_pole_grid_longitude attribute [Bug #11661] Version 2.3.1 (29 November 2023): diff --git a/OPERATORS b/OPERATORS index 53d31f2e272528a9bd4923a61b0536bf65c358ee..129dee6f7ea4e41ada682e99fef6082039a9d662 100644 --- a/OPERATORS +++ b/OPERATORS @@ -649,8 +649,12 @@ Operator catalog: Rotuv rotuvb Backward rotation Mrotuvb mrotuvb Backward rotation of MPIOM data Mastrfu mastrfu Mass stream function + Pressure pressure_half Pressure on half-levels + Pressure pressure Pressure on full-levels + Pressure delta_pressure Pressure difference of half-levels Derivepar sealevelpressure Sea level pressure - Derivepar gheight Geopotential height + Derivepar gheight Geopotential height on full-levels + Derivepar gheight_half Geopotential height on half-levels Adisit adisit Potential temperature to in-situ temperature Adisit adipot In-situ temperature to potential temperature Rhopot rhopot Calculates potential density @@ -694,6 +698,7 @@ Operator catalog: EcaCfd eca_cfd Consecutive frost days index per time period EcaCsu eca_csu Consecutive summer days index per time period EcaCwd eca_cwd Consecutive wet days index per time period + EcaCwd etccdi_cwd Consecutive wet days index per time period EcaCwdi eca_cwdi Cold wave duration index wrt mean of reference period EcaCwfi eca_cwfi Cold-spell days index wrt 10th percentile of reference period EcaCwfi etccdi_csdi Cold-spell duration index @@ -704,6 +709,7 @@ Operator catalog: EcaHd eca_hd Heating degree days per time period EcaHwdi eca_hwdi Heat wave duration index wrt mean of reference period EcaHwfi eca_hwfi Warm spell days index wrt 90th percentile of reference period + EcaHwfi etccdi_wsdi Warm Spell Duration Index EcaId eca_id Ice days index per time period EcaId etccdi_id Ice days index per time period EcaR75p eca_r75p Moderate wet days wrt 75th percentile of reference period diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake new file mode 100644 index 0000000000000000000000000000000000000000..194b1a0d32a629aefc0841582c1df02f0b681083 --- /dev/null +++ b/cmake/FindNetCDF.cmake @@ -0,0 +1,131 @@ +#[==[ +Provides the following variables: + + * `NetCDF_FOUND`: Whether NetCDF was found or not. + * `NetCDF_INCLUDE_DIRS`: Include directories necessary to use NetCDF. + * `NetCDF_LIBRARIES`: Libraries necessary to use NetCDF. + * `NetCDF_VERSION`: The version of NetCDF found. + * `NetCDF::NetCDF`: A target to use with `target_link_libraries`. + * `NetCDF_HAS_PARALLEL`: Whether or not NetCDF was found with parallel IO support. +#]==] + +function(FindNetCDF_get_is_parallel_aware include_dir) + file(STRINGS "${include_dir}/netcdf_meta.h" _netcdf_lines + REGEX "#define[ \t]+NC_HAS_PARALLEL[ \t]") + string(REGEX REPLACE ".*NC_HAS_PARALLEL[ \t]*([0-1]+).*" "\\1" _netcdf_has_parallel "${_netcdf_lines}") + if (_netcdf_has_parallel) + set(NetCDF_HAS_PARALLEL TRUE PARENT_SCOPE) + else() + set(NetCDF_HAS_PARALLEL FALSE PARENT_SCOPE) + endif() +endfunction() + +# Try to find a CMake-built NetCDF. +find_package(netCDF CONFIG QUIET) +if (netCDF_FOUND) + # Forward the variables in a consistent way. + set(NetCDF_FOUND "${netCDF_FOUND}") + set(NetCDF_INCLUDE_DIRS "${netCDF_INCLUDE_DIR}") + set(NetCDF_LIBRARIES "${netCDF_LIBRARIES}") + set(NetCDF_VERSION "${NetCDFVersion}") + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(NetCDF + REQUIRED_VARS NetCDF_INCLUDE_DIRS NetCDF_LIBRARIES + VERSION_VAR NetCDF_VERSION) + + if (NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF INTERFACE IMPORTED) + if (TARGET "netCDF::netcdf") + # 4.7.3 + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "netCDF::netcdf") + elseif (TARGET "netcdf") + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "netcdf") + else () + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "${netCDF_LIBRARIES}") + endif () + endif () + + FindNetCDF_get_is_parallel_aware("${NetCDF_INCLUDE_DIRS}") + # Skip the rest of the logic in this file. + return () +endif () + +find_package(PkgConfig QUIET) +if (PkgConfig_FOUND) + pkg_check_modules(_NetCDF QUIET netcdf IMPORTED_TARGET) + if (_NetCDF_FOUND) + # Forward the variables in a consistent way. + set(NetCDF_FOUND "${_NetCDF_FOUND}") + set(NetCDF_INCLUDE_DIRS "${_NetCDF_INCLUDE_DIRS}") + set(NetCDF_LIBRARIES "${_NetCDF_LIBRARIES}") + set(NetCDF_VERSION "${_NetCDF_VERSION}") + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(NetCDF + REQUIRED_VARS NetCDF_LIBRARIES + # This is not required because system-default include paths are not + # reported by `FindPkgConfig`, so this might be empty. Assume that if we + # have a library, the include directories are fine (if any) since + # PkgConfig reported that the package was found. + # NetCDF_INCLUDE_DIRS + VERSION_VAR NetCDF_VERSION) + + if (NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF INTERFACE IMPORTED) + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "PkgConfig::_NetCDF") + endif () + + FindNetCDF_get_is_parallel_aware("${_NetCDF_INCLUDEDIR}") + # Skip the rest of the logic in this file. + return () + endif () +endif () + +find_path(NetCDF_INCLUDE_DIR + NAMES netcdf.h + DOC "netcdf include directories") +mark_as_advanced(NetCDF_INCLUDE_DIR) + +find_library(NetCDF_LIBRARY + NAMES netcdf + DOC "netcdf library") +mark_as_advanced(NetCDF_LIBRARY) + +if (NetCDF_INCLUDE_DIR) + file(STRINGS "${NetCDF_INCLUDE_DIR}/netcdf_meta.h" _netcdf_version_lines + REGEX "#define[ \t]+NC_VERSION_(MAJOR|MINOR|PATCH|NOTE)") + string(REGEX REPLACE ".*NC_VERSION_MAJOR *\([0-9]*\).*" "\\1" _netcdf_version_major "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_MINOR *\([0-9]*\).*" "\\1" _netcdf_version_minor "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_PATCH *\([0-9]*\).*" "\\1" _netcdf_version_patch "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_NOTE *\"\([^\"]*\)\".*" "\\1" _netcdf_version_note "${_netcdf_version_lines}") + set(NetCDF_VERSION "${_netcdf_version_major}.${_netcdf_version_minor}.${_netcdf_version_patch}${_netcdf_version_note}") + unset(_netcdf_version_major) + unset(_netcdf_version_minor) + unset(_netcdf_version_patch) + unset(_netcdf_version_note) + unset(_netcdf_version_lines) + + FindNetCDF_get_is_parallel_aware("${NetCDF_INCLUDE_DIR}") +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NetCDF + REQUIRED_VARS NetCDF_LIBRARY NetCDF_INCLUDE_DIR + VERSION_VAR NetCDF_VERSION) + +if (NetCDF_FOUND) + set(NetCDF_INCLUDE_DIRS "${NetCDF_INCLUDE_DIR}") + set(NetCDF_LIBRARIES "${NetCDF_LIBRARY}") + + if (NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF UNKNOWN IMPORTED) + set_target_properties(NetCDF::NetCDF PROPERTIES + IMPORTED_LOCATION "${NetCDF_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_INCLUDE_DIR}") + endif () +endif () diff --git a/cmake/cdo_config.h.in b/cmake/cdo_config.h.in new file mode 100644 index 0000000000000000000000000000000000000000..e88c2884c0989b3f2dc50872d80083084aa3d35d --- /dev/null +++ b/cmake/cdo_config.h.in @@ -0,0 +1,20 @@ +#ifndef cdo_config_h +#define cdo_config_h + +#define PACKAGE_NAME "@PROJECT_NAME@" + +#define VERSION "@PROJECT_VERSION@" + +#define CDI 1 + +#define HAVE_LIBGRIB 1 +#define HAVE_LIBCGRIBEX 1 +#define HAVE_LIBEXTRA 1 +#define HAVE_LIBSERVICE 1 +#define HAVE_LIBIEG 1 + +#define HAVE_NETCDF @HAVE_NETCDF@ +#define HAVE_NETCDF_NC4 @netCDF_HAS_NC4@ +#define NETCDF_FOUND @NetCDF_FOUND@ + +#endif /* cdo_config_h */ diff --git a/config/default b/config/default index 383873aafc1ef4681dcb8e54df3a7f4ed9a737e1..ed4724e917f1ca461ed85760af1ed0172ba174d2 100755 --- a/config/default +++ b/config/default @@ -30,20 +30,22 @@ set -x # case "${HOSTNAME}" in # i386-apple-darwin10 +# --with-magics=/opt/local " bailung*|d146*) CDOLIBS="--with-fftw3 \ - --with-eccodes=$HOME/local/eccodes-2.32.0 \ - --with-netcdf=$HOME/local/netcdf-4.9.0 \ - --with-hdf5=$HOME/local/hdf5-1.12.1-threadsafe \ + --with-fdb5=$HOME/local/ecmwf \ + --with-eccodes=/opt/local \ + --with-netcdf=/opt/local \ + --with-hdf5=/opt/local \ --with-udunits2=/opt/local \ --with-curl=/opt/local \ - --with-cmor=$HOME/local/cmor-3.6.1 \ --with-libxml2=/opt/local \ --with-ossp-uuid=/opt/local \ - --with-proj=/opt/local/lib/proj7 \ - --with-szlib=/opt/local/lib/libaec \ - --with-magics=/opt/local " - LDFLAGS="-Wl,-rpath,$HOME/local/eccodes-2.32.0/lib -L/opt/local/lib -ljson-c" + --with-proj=/opt/local/lib/proj9 \ + --with-cmor=$HOME/local/cmor-3.6.1 \ + --with-szlib=/opt/local/lib/libaec" +# LDFLAGS="-Wl,-rpath,$HOME/local/eccodes-2.32.0/lib -L/opt/local/lib -ljson-c" + LDFLAGS="-Wl,-rpath,$HOME/local/ecmwf/lib -L/opt/local/lib -ljson-c" if test "$COMP" = intel ; then ${CONFPATH}configure \ @@ -146,20 +148,20 @@ case "${HOSTNAME}" in ;; hama*) # --with-fdb5=$HOME/src/fdb \ -# --with-cmor=$HOME/local/cmor-3.6.1 \ CDOLIBS="--with-fftw3 \ --with-curl \ --with-szlib=/opt/local/lib/libaec \ - --with-eccodes=$HOME/local/eccodes-2.32.0 \ - --with-netcdf=$HOME/local/netcdf-c-4.9.2 \ - --with-hdf5=$HOME/local/hdf5-1.12.0 \ + --with-eccodes=/opt/local \ + --with-netcdf=/opt/local \ + --with-hdf5=/opt/local \ --with-cmor=$HOME/local/cmor-3.6.1 \ --with-libxml2=/opt/local \ --with-udunits2=/opt/local \ --with-ossp-uuid=/opt/local \ --with-proj=/opt/local/lib/proj9 \ --with-magics=/opt/local" - LDFLAGS="-Wl,-rpath,$HOME/local/eccodes-2.32.0/lib -Wl,-rpath,$HOME/src/fdb/lib" +# LDFLAGS="-Wl,-rpath,$HOME/local/eccodes-2.32.0/lib -Wl,-rpath,$HOME/src/fdb/lib" + LDFLAGS="" if test "$COMP" = intel ; then ${CONFPATH}configure \ @@ -354,12 +356,14 @@ case "${HOSTNAME}" in fi ;; # levante +# NETCDFPATH=/sw/spack-levante/netcdf-c-main-bdxvs5 +# HDF5PATH=/sw/spack-levante/hdf5-1.14.2-gxhi2f levante*) NETCDFPATH=/sw/spack-levante/netcdf-c-4.8.1-qk24yp HDF5PATH=/sw/spack-levante/hdf5-1.12.1-akf2kp UDUNITS2PATH=/sw/spack-levante/udunits-2.2.28-da6pla FFTW3PATH=/sw/spack-levante/fftw-3.3.10-fnfhvr - ECCODESPATH=/sw/spack-levante/eccodes-2.21.0-4ywkk4 + ECCODESPATH=/sw/spack-levante/eccodes-2.32.5-ly6tko MAGICSPATH=/sw/spack-levante/magics-4.9.3-z64bdu SZPATH=/sw/spack-levante/libaec-1.0.5-r5sdw5 #PROJPATH=/sw/spack-levante/proj-8.1.0-i6a6ah diff --git a/configure.ac b/configure.ac index a4b3764404a4792980536d8322ef8f9551d79643..10758c3928977333fe402cb0f5d42216399474fc 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ # libtool 2.4.2 AC_PREREQ([2.69]) -AC_INIT([cdo],[2.3.1],[https://mpimet.mpg.de/cdo]) +AC_INIT([cdo],[2.4.0],[https://mpimet.mpg.de/cdo]) AC_DEFINE_UNQUOTED(CDO, ["$PACKAGE_VERSION"], [CDO version]) diff --git a/doc/tex/Modules b/doc/tex/Modules index 681456d89ee8bbdae36580bc2d614478d08d8927..8cb6e0746403b927ee095e3035f2d44e797b4107 100644 --- a/doc/tex/Modules +++ b/doc/tex/Modules @@ -160,6 +160,7 @@ WindTrans Miscellaneous Rotuv Miscellaneous Mrotuvb Miscellaneous Mastrfu Miscellaneous +Pressure Miscellaneous Derivepar Miscellaneous Adisit Miscellaneous Rhopot Miscellaneous diff --git a/doc/tex/cdo.tex b/doc/tex/cdo.tex index dad49f026de3c8ee5c7c9ad5fe819043d52b4569..763cdedbe86ecf72a1b00f3ac83ccb7574ae299a 100644 --- a/doc/tex/cdo.tex +++ b/doc/tex/cdo.tex @@ -206,7 +206,7 @@ keepaspectratio]{cdo_libdep.pdf}}% \end{picture} \begin{flushright} -\large \textbf{Climate Data Operator \\ Version 2.3.1 \\ November 2023} +\large \textbf{Climate Data Operator \\ Version 2.4.0 \\ February 2024} \end{flushright} \vfill diff --git a/doc/tex/cdoprog.tex b/doc/tex/cdoprog.tex index 6e7733c4f748dcee0b6fe43f1d8b5e16e14b9455..23b7bf54dbc7e777ba51ce9c3af9be4d9202bcfa 100644 --- a/doc/tex/cdoprog.tex +++ b/doc/tex/cdoprog.tex @@ -14,7 +14,7 @@ \put(0,0.0){\line(1,0){3.95}} \end{picture} \begin{flushright} -{\small{Climate Data Operator \\ Version 2.3.1 \\ November 2023}} +{\small{Climate Data Operator \\ Version 2.4.0 \\ February 2024}} \end{flushright} \vspace*{0mm} diff --git a/doc/tex/makedoc b/doc/tex/makedoc index 43b1113384049f67248acd8d2b60491cd210a374..64d902a0b6df6001620578e0243a15d3e50cde9f 100755 --- a/doc/tex/makedoc +++ b/doc/tex/makedoc @@ -6,7 +6,8 @@ $prog = "CDO"; $longname = "Climate Data Operators"; $moddir = "mod"; $modules = "Modules"; -$help = "../../src/operator_help.h"; +$helphh = "../../src/operator_help.h"; +$helpcc = "../../src/operator_help.cc"; $catalog = "catalog.tex"; $abclist = "alphabetic_list.tex"; @oplist = (); @@ -17,7 +18,8 @@ $class = "cdo_class"; # open(README, ">../../OPERATORS"); open(CDOHTML, ">cdo_oper.html"); -open(HELPFILE, ">$help"); +open(HELPHH, ">$helphh"); +open(HELPCC, ">$helpcc"); open(TCFILE, ">$catalog"); open(ABCLIST, ">$abclist"); open(TROVER, ">$refover"); @@ -150,21 +152,27 @@ print TRCARD "\\vspace*{2mm}\n"; print TRCARD "\\subsection*{Operators}\n"; print TRCARD "\n"; # -print HELPFILE "// Automatically created with makedoc, don't edit!\n"; -print HELPFILE "\n"; -print HELPFILE "#ifndef OPERATOR_HELP_H\n"; -print HELPFILE "#define OPERATOR_HELP_H\n"; -print HELPFILE "\n"; -print HELPFILE "// clang-format off\n"; +print HELPHH "// Automatically created with makedoc, don't edit!\n"; +print HELPHH "\n"; +print HELPHH "#ifndef OPERATOR_HELP_H\n"; +print HELPHH "#define OPERATOR_HELP_H\n"; +print HELPHH "\n"; +print HELPHH "#include <vector>\n"; +print HELPHH "#include <string_view>\n"; +print HELPHH "\n"; +print HELPHH "typedef std::vector<std::string_view> CdoHelp;\n"; +print HELPHH "\n"; +# +print HELPCC "// Automatically created with makedoc, don't edit!\n"; +print HELPCC "\n"; +print HELPCC "#include \"operator_help.h\"\n"; +print HELPCC "\n"; +print HELPCC "// clang-format off\n"; # $help_print = 1; $oldchap = "oldchap"; $nline = 0; -print HELPFILE "\n"; -#print HELPFILE "#include <vector>\n"; -#print HELPFILE "#include <string>\n"; - while (<MOFILE>) { chomp; ($modulefile) = split(" "); @@ -315,10 +323,9 @@ while (<MOFILE>) { # print TRFILE "\n\n\\section{$chap}\n"; } - print HELPFILE "\n"; - print HELPFILE "static const char *${mname}Help[] = {\n"; -# print HELPFILE "static const std::vector<std::string> ${mname}Help = {\n"; -# print HELPFILE "static const std::string ${mname}Help[] = {\n"; + print HELPHH "extern const CdoHelp ${mname}Help;\n"; + print HELPCC "\n"; + print HELPCC "const CdoHelp ${mname}Help = {\n"; @hkeys = split(" ", $moperators); # print "$#hkeys @hkeys \n"; @@ -382,8 +389,8 @@ while (<MOFILE>) { print TRCARD "\\begin{tabular*}{$len1}{|>{\\columncolor{pcolor2}}l>{\\columncolor{pcolor1}}l|} \\hline\n"; } - print HELPFILE " \"NAME\",\n"; - print HELPFILE " \" "; + print HELPCC " \"NAME\",\n"; + print HELPCC " \" "; $maxlen = 0; $maxitem = ""; foreach $operator (@hkeys) { @@ -401,7 +408,7 @@ while (<MOFILE>) { $slen = 0; foreach $operator (@hkeys) { if ( $icount > 0 ) { - print HELPFILE ", "; + print HELPCC ", "; $slen += 2; } $norefoper = 0; @@ -413,24 +420,24 @@ while (<MOFILE>) { $len = length($operator); if ( $len + $slen > 76 ) { $slen = 0; - print HELPFILE "\",\n"; - print HELPFILE " \" "; + print HELPCC "\",\n"; + print HELPCC " \" "; } $slen += $len; - print HELPFILE "${operator}"; + print HELPCC "${operator}"; if ( $norefoper == 1 ) { $operator =~ s/^/-/; } $icount++; } - print HELPFILE " - "; + print HELPCC " - "; $len = length(${mtitle}); if ( $len + $slen > 76 ) { $slen = 0; - print HELPFILE "\",\n"; - print HELPFILE " \" "; + print HELPCC "\",\n"; + print HELPCC " \" "; } - print HELPFILE "${mtitle}\",\n"; + print HELPCC "${mtitle}\",\n"; undef @oper_title; undef @oper_parameter; @@ -530,13 +537,13 @@ while (<MOFILE>) { if ( $istart == 1 ) { $istart = 0; } } - print HELPFILE " \"\",\n"; - print HELPFILE " \"SYNOPSIS\",\n"; + print HELPCC " \"\",\n"; + print HELPCC " \"SYNOPSIS\",\n"; print TRFILE "\n\\subsection*{Synopsis}\n\n"; if ( $istart > 0 ) { $parameter = @oper_parameter[0]; - print HELPFILE " \" <operator>${parameter} ${marguments}\",\n"; + print HELPCC " \" <operator>${parameter} ${marguments}\",\n"; $parameter =~ s/_/\\_/g; print TRFILE "\\hspace*{8mm}{\$<\\!operator\\!>\$}\\textsl{$parameter} \\ \\texttt{$marguments}\n\n"; } @@ -546,7 +553,7 @@ while (<MOFILE>) { { $operator = @hkeys[$i]; $parameter = @oper_parameter[$i]; - printf HELPFILE (" \" %s%s %s\",\n", $operator, $parameter, $marguments); + printf HELPCC (" \" %s%s %s\",\n", $operator, $parameter, $marguments); $operatorx = $operator; $operatorx =~ s/_/\\_/g; $parameter =~ s/_/\\_/g; @@ -554,8 +561,8 @@ while (<MOFILE>) { } } - print HELPFILE " \"\",\n"; - print HELPFILE " \"DESCRIPTION\",\n"; + print HELPCC " \"\",\n"; + print HELPCC " \"DESCRIPTION\",\n"; print TRFILE "\n\\subsection*{Description}\n\n"; if ( $#moddeslines >= 0 ) { @@ -580,8 +587,8 @@ while (<MOFILE>) { } if ( $#hkeys > 0 ) { - print HELPFILE " \"\",\n"; - print HELPFILE " \"OPERATORS\",\n"; + print HELPCC " \"\",\n"; + print HELPCC " \"OPERATORS\",\n"; print TRFILE "\n\\subsection*{Operators}\n\n"; } else { @@ -642,7 +649,7 @@ while (<MOFILE>) { $operatorx = $operator; $operatorx =~ s/_/\\_/g; if ( $#hkeys > 0 ) { - printf HELPFILE (" \" %-*s%s\",\n", $maxlen, $operator, $otitle); + printf HELPCC (" \" %-*s%s\",\n", $maxlen, $operator, $otitle); if ( $xopercnt == 1 ) { print TRFILE "\\begin{defalist2}{\\textbf{$maxitem \\ }}\n"; } @@ -769,8 +776,8 @@ while (<MOFILE>) { } if ( $lblock == 1 ) { - print HELPFILE " \"\",\n"; - print HELPFILE " \"NAMELIST\",\n"; + print HELPCC " \"\",\n"; + print HELPCC " \"NAMELIST\",\n"; print TRFILE "\n\\subsection*{Namelist}\n\n"; begin_minipage(); @@ -818,8 +825,8 @@ while (<MOFILE>) { } } - print HELPFILE " \"\",\n"; - print HELPFILE " \"PARAMETER\",\n"; + print HELPCC " \"\",\n"; + print HELPCC " \"PARAMETER\",\n"; print TRFILE "\n\\subsection*{Parameter}\n\n"; begin_minipage(); @@ -833,7 +840,7 @@ while (<MOFILE>) { # if ( index("$kword", "\@ITEM") != -1 ) { if ( "$kword" eq "\@ITEM" ) { ($kopt, $value) = split(/\s*=\s*/, $line, 2); - printf HELPFILE (" \" %-*s ", $maxlen, $value); + printf HELPCC (" \" %-*s ", $maxlen, $value); $value =~ s/_/\\_/g; $value =~ s/</\$<\$/g; $value =~ s/>/\$>\$/g; @@ -846,9 +853,9 @@ while (<MOFILE>) { $hline =~ s/\@celsius/°C/og; $hline =~ s/\@href\{([^}]*)\}\{([^}]*)\}/\2/g; if ( $lines > 1 ) { - printf HELPFILE (" \" %-*s ", $maxlen, " "); + printf HELPCC (" \" %-*s ", $maxlen, " "); } - print HELPFILE "$hline\",\n"; + print HELPCC "$hline\",\n"; $line =~ s/^FLOAT/\\makebox[20mm][l]{\\textsf{\\small FLOAT}}/; $line =~ s/^INTEGER/\\makebox[20mm][l]{\\textsf{\\small INTEGER}}/; $line =~ s/^STRING/\\makebox[20mm][l]{\\textsf{\\small STRING}}/; @@ -904,8 +911,8 @@ while (<MOFILE>) { } } - print HELPFILE " \"\",\n"; - print HELPFILE " \"ENVIRONMENT\",\n"; + print HELPCC " \"\",\n"; + print HELPCC " \"ENVIRONMENT\",\n"; print TRFILE "\n\\subsection*{Environment}\n\n"; begin_minipage(); @@ -918,7 +925,7 @@ while (<MOFILE>) { # if ( index("$kword", "\@ITEM") != -1 ) { if ( "$kword" eq "\@ITEM" ) { ($kopt, $value) = split(/\s*=\s*/, $line, 2); - printf HELPFILE (" \" %-*s\",\n", $maxlen, $value); + printf HELPCC (" \" %-*s\",\n", $maxlen, $value); $value =~ s/_/\\_/g; print TRFILE "\\item[\\texttt{$value}\\ \\ \\hfill]\n"; } else { @@ -927,10 +934,10 @@ while (<MOFILE>) { $hline =~ s/\\cite//og; $hline =~ s/\@env\{([^}]*)\}/\1/og; # if ( $lines == 0 ) { -# print HELPFILE "$hline\",\n"; +# print HELPCC "$hline\",\n"; # } # else { - print HELPFILE " \" $hline\",\n"; + print HELPCC " \" $hline\",\n"; # } # $line = /\sFLOAT/XXX $line =~ s/^FLOAT/\\makebox[20mm][l]\\textsf{\\small FLOAT}/; @@ -968,8 +975,8 @@ while (<MOFILE>) { } if ( $lblock == 1 ) { - print HELPFILE " \"\",\n"; - print HELPFILE " \"NOTE\",\n"; + print HELPCC " \"\",\n"; + print HELPCC " \"NOTE\",\n"; print TRFILE "\n\\subsection*{Note}\n\n"; begin_minipage(); @@ -1022,34 +1029,39 @@ while (<MOFILE>) { # if ( $oper ne $operator ) { # $nop = $nop + 1; # if ( $nop == 1 ) { -# print HELPFILE " \"\",\n"; -# print HELPFILE " \"SEE ALSO\",\n"; +# print HELPCC " \"\",\n"; +# print HELPCC " \"SEE ALSO\",\n"; # } # if ( $linelen > 70 ) { # $linelen = 0; -# print HELPFILE ",\",\n"; +# print HELPCC ",\",\n"; # } # if ( $linelen == 0 ) { -# print HELPFILE " \" $oper"; +# print HELPCC " \" $oper"; # } # else { -# print HELPFILE ", $oper"; +# print HELPCC ", $oper"; # } # $linelen = $linelen + length($oper) + 2; # } # } # if ( $lineend == 0 && $nop > 0 ) { -# print HELPFILE "\",\n"; +# print HELPCC "\",\n"; # } # End -# print HELPFILE " \"\",\n"; -# print HELPFILE " \"\@End_${operator}\",\n"; +# print HELPCC " \"\",\n"; +# print HELPCC " \"\@End_${operator}\",\n"; + +# print HELPCC " \"ENDHELP\"\n"; + print HELPCC "};\n"; -# print HELPFILE " \"ENDHELP\"\n"; - print HELPFILE " nullptr\n"; - print HELPFILE "};\n"; +# print HELPCC "extern char const* const* ${mname}Help;\n"; + +# print HELPCC "\n"; +# print HELPCC "char const* const* ${mname}Help_get() { return ${mname}Help; }\n"; +# print HELPCC "\n"; print TCFILE "\\end{tabular*}\n"; print TCFILE "\\vspace{1mm}\n"; @@ -1093,11 +1105,14 @@ foreach my $line (sort(@oplist)){ print ABCLIST "\\end{longtable}\n"; print ABCLIST "\n"; -print HELPFILE "// clang-format on\n"; -print HELPFILE "\n"; -print HELPFILE "#endif\n"; +print HELPHH "\n"; +print HELPHH "#endif\n"; + +print HELPCC "\n"; +print HELPCC "// clang-format on\n"; +print HELPCC "\n"; -close(HELPFILE); +close(HELPCC); close(TRFILE); close(TCFILE); close(ABCLIST); @@ -1170,7 +1185,7 @@ sub print_description { $value =~ s/</\$<\$/og; $value =~ s/>/\$>\$/og; if ( $help_print == 1 ) { - printf HELPFILE (" \" %*s%s- ${hvalue}\",\n", $nspace, ""); + printf HELPCC (" \" %*s%s- ${hvalue}\",\n", $nspace, ""); } $value =~ s/_/\\_/g; print TRFILE "\\item $value\n"; @@ -1179,9 +1194,9 @@ sub print_description { if ( $help_print == 1 ) { $ntab = $noff - length($value); if ( $ntab < 0 ) { $ntab = 0 }; -# printf HELPFILE (" \" %*s%s%s%*s%s\"", $nspace, "", ${value}, $ntab, ""); - printf HELPFILE (" \" %*s%s${value}", $nspace, ""); - printf HELPFILE ("%*s%s\"", $ntab, ""); +# printf HELPCC (" \" %*s%s%s%*s%s\"", $nspace, "", ${value}, $ntab, ""); + printf HELPCC (" \" %*s%s${value}", $nspace, ""); + printf HELPCC ("%*s%s\"", $ntab, ""); } print TRFILE "\\item[{$value}\\ \\ \\hfill]\n"; } elsif ( "$kword" eq "\@BEGINMATH" ) { @@ -1296,7 +1311,7 @@ sub print_description { $ospace = $nspace; if ( $list == 1 ) {$ospace=0;} if ( $help_print == 1 ) { - printf HELPFILE (" \" %*s%s\",\n", $ospace, "", $docline); + printf HELPCC (" \" %*s%s\",\n", $ospace, "", $docline); } } } diff --git a/doc/tex/mod/Derivepar b/doc/tex/mod/Derivepar index 058c6fd0ea724c3fc43bd82168b24bd63b69bf89..b2fe80311174371aa1cdc08655470b0dd29c1f46 100644 --- a/doc/tex/mod/Derivepar +++ b/doc/tex/mod/Derivepar @@ -1,13 +1,14 @@ @BeginModule +@NewPage @Name = Derivepar @Title = Derived model parameters @Section = Miscellaneous @Arguments = infile outfile -@Operators = sealevelpressure gheight +@Operators = sealevelpressure gheight gheight_half @BeginDescription This module contains operators that calculate derived model parameters. These are currently the parameters -sea level pressure and geopotential height. All necessary input parameters are identified by their GRIB1 +sea level pressure and geopotential height. All necessary input variables are identified by their GRIB1 code number or the NetCDF CF standard name. Supported GRIB1 parameter tables are: WMO standard table number 2 and ECMWF local table number 128. @@ -35,10 +36,22 @@ are surface_air_pressure, surface_geopotential and air_temperature on full hybri @BeginOperator_gheight -@Title = Geopotential height +@Title = Geopotential height on full-levels @BeginDescription -This operator computes the geopotential height (geopotential_height) on full model levels in metres. +This operator computes the geopotential height (geopotential_height) on model full-levels in metres. +Required input fields are surface_air_pressure, surface_geopotential, specific_humidity and air_temperature +on full hybrid sigma pressure levels. Note, this procedure is an approximation, which doesn't take into +account the effects of e.g. cloud ice and water, rain and snow. +@EndDescription +@EndOperator + + +@BeginOperator_gheight_half +@Title = Geopotential height on half-levels + +@BeginDescription +This operator computes the geopotential height (geopotential_height) on model half-levels in metres. Required input fields are surface_air_pressure, surface_geopotential, specific_humidity and air_temperature on full hybrid sigma pressure levels. Note, this procedure is an approximation, which doesn't take into account the effects of e.g. cloud ice and water, rain and snow. diff --git a/doc/tex/mod/EcaCwd b/doc/tex/mod/EcaCwd index f7b037a74885e3ac545fd3c5854a8218db11eda6..c6d3670ce2b92950e70a1dde9788fb7c8f90f926 100644 --- a/doc/tex/mod/EcaCwd +++ b/doc/tex/mod/EcaCwd @@ -17,7 +17,8 @@ Parameter is a comma-separated list of "key=values" pairs. @BeginOperator_eca_cwd @Title = Consecutive wet days index per time period -@Parameter = [R] [N] [params] +@Parameter = [params] + @BeginDescription The operator counts over the entire time series. The date information of a timestep in @file{outfile} is the date of @@ -25,9 +26,10 @@ the last contributing timestep in @file{infile}. @EndDescription @EndOperator -@BeginOperator_eca_cwd +@BeginOperator_etccdi_cwd @Title = Consecutive wet days index per time period -@Parameter = [R] [N] [params] +@Parameter =[params] + @BeginDescription The default output frequency is yearly. Periods within overlapping years are accounted for the first year. diff --git a/doc/tex/mod/EcaHwfi b/doc/tex/mod/EcaHwfi index 3b889af46d7ab5956a6a7aedc5f73d470bf2e3be..b0be5868282ece170da7ba2676bac9dc861ab218 100644 --- a/doc/tex/mod/EcaHwfi +++ b/doc/tex/mod/EcaHwfi @@ -25,7 +25,8 @@ Parameter is a comma-separated list of "key=values" pairs. @BeginOperator_eca_hwfi @Title = Warm spell days index wrt 90th percentile of reference period -@Parameter = [nday] [params] +@Parameter = [params] + @BeginDescription The operator counts over the entire time series. The date information of a timestep in @file{outfile} is the date of @@ -33,9 +34,10 @@ the last contributing timestep in @file{infile}. @EndDescription @EndOperator -BeginOperator_etccdi_wsdi +@BeginOperator_etccdi_wsdi @Title = Warm Spell Duration Index -@Parameter = [nday] [params] +@Parameter = [params] + @BeginDescription The default output frequency is yearly. Periods within overlapping years are accounted for the first year. diff --git a/doc/tex/mod/Exprf b/doc/tex/mod/Exprf index 65132c8eb711d05499e27c2693a16866e76a1b0c..5dffe41d6c2afdb97dbcfc8f4fd143cef13f1541 100644 --- a/doc/tex/mod/Exprf +++ b/doc/tex/mod/Exprf @@ -124,7 +124,7 @@ Arc tangent function of y/x, using signs to determine quadrants Coordinates: -@BeginList gridarea(x) +@BeginList cthickness(x) @Item = clon(x) Longitude coordinate of x (available only if x has geographical coordinates) @Item = clat(x) diff --git a/doc/tex/mod/Gridcell b/doc/tex/mod/Gridcell index a1c953a7fd7fe97cb74e18c9532c71fc4e0a2eb0..5ed86efc7cf6efcebe9ca08e747e43464b5ddba0 100644 --- a/doc/tex/mod/Gridcell +++ b/doc/tex/mod/Gridcell @@ -8,8 +8,8 @@ @BeginDescription This module reads the grid cell area of the first grid from the input stream. If the grid cell area is missing it will be computed from the grid coordinates. The area of a grid cell is calculated using spherical triangles from -the coordinates of the center and the vertices. The base is a unit sphere which is scaled with the radius of the earth. -The default earth radius is 6371000 meter. This value can be changed with the environment variable PLANET_RADIUS. +the coordinates of the center and the vertices. The base is a unit sphere which is scaled with the radius of the planet. +The default planet radius is 6371000 meter. The parameter @var{radius} or the environment variable @env{PLANET_RADIUS} can be used to change the default. Depending on the chosen operator the grid cell area or weights are written to the output stream. @EndDescription @EndModule @@ -17,10 +17,11 @@ Depending on the chosen operator the grid cell area or weights are written to th @BeginOperator_gridarea @Title = Grid cell area +@Parameter = [radius] @BeginDescription Writes the grid cell area to the output stream. If the grid cell area have to -be computed it is scaled with the earth radius to square meters. +be computed it is scaled with the planet radius to square meters. @EndDescription @EndOperator @@ -32,6 +33,10 @@ Writes the grid cell area weights to the output stream. @EndDescription @EndOperator +@BeginParameter maxpoints +@Item = radius +FLOAT Planet radius in meter +@EndParameter @BeginEnvironment @Item = PLANET_RADIUS diff --git a/doc/tex/mod/Intlevel b/doc/tex/mod/Intlevel index a7e45bb07ad53dff1cdb91787a3a4245a11404d3..643a75c856fcf033ede96d83ba72a1ec65f0d890 100644 --- a/doc/tex/mod/Intlevel +++ b/doc/tex/mod/Intlevel @@ -8,7 +8,7 @@ @Operators = intlevel @BeginDescription -This operator performs a linear vertical interpolation of 3D variables. The target levels can be +This operator performs a linear vertical interpolation of 3D variables. The 1D target levels can be specified with the level parameter or read in via a Z-axis description file. @EndDescription @EndModule @@ -23,8 +23,10 @@ specified with the level parameter or read in via a Z-axis description file. @BeginParameter @Item = level FLOAT Comma-separated list of target levels -@Item = file +@Item = zaxisdescription STRING Path to a file containing a description of the Z-axis +@Item = zvarname +STRING Use zvarname as the vertical 3D source coordinate instead of the 1D coordinate variable @EndParameter diff --git a/doc/tex/mod/Pack b/doc/tex/mod/Pack index 6e93c4659225defd6b1e4093fc339fcd38017d14..05b27926ca7e2f9a25e307dd5c66503621de66dd 100644 --- a/doc/tex/mod/Pack +++ b/doc/tex/mod/Pack @@ -13,6 +13,7 @@ @BeginOperator_pack @Title = Pack data +@Parameter = [parameter] @BeginDescription Packing reduces the data volume by reducing the precision of the stored numbers. @@ -21,5 +22,14 @@ The operator @oper{pack} calculates the attributes @env{add_offset} and @env{sca The default data type for all variables is automatically changed to 16-bit integer. Use the CDO option -b to change the data type to a different integer precision, if needed. Missing values are automatically transformed to the current data type. + +Alternatively, the pack parameters @env{add_offset} and @env{scale_factor} can be read from a file for each variable. @EndDescription @EndOperator + +@BeginParameter filename +@Item = printparam +BOOL Print pack parameters to stdout for each variable +@Item = filename +STRING Read pack parameters from file for each variable[format: name=<> add_offset=<> scale_factor=<>] +@EndParameter diff --git a/doc/tex/mod/Pressure b/doc/tex/mod/Pressure new file mode 100644 index 0000000000000000000000000000000000000000..b712632879de54f64da4c19392ddcfcc853a592c --- /dev/null +++ b/doc/tex/mod/Pressure @@ -0,0 +1,86 @@ +@BeginModule +@NewPage +@Name = Pressure +@Title = Pressure on model levels +@Section = Miscellaneous +@Arguments = infile outfile +@Operators = pressure_half pressure delta_pressure + +@BeginDescription +This module contains operators to calculate the pressure on model levels. +To calculate the pressure on model levels, the a and b coefficients defining the model levels and +the surface pressure are required. The a and b coefficients are normally part of the model level data. +If not available, the surface pressure can be derived from the logarithm of the surface pressure. +The surface pressure is identified by the GRIB1 code number or NetCDF CF standard name. + +@BeginTable4 + @bold{Name} & @bold{Units} & @bold{GRIB1 code} & @bold{CF standard name} + log surface pressure & Pa & 152 & + surface pressure & Pa & 134 & surface_air_pressure +@EndTable + +@EndDescription +@EndModule + + +@BeginOperator_pressure_half +@Title = Pressure on half-levels + +@BeginDescription +This operator computes the pressure on model half-levels in pascal. +The model half-level pressure (p_half) is given by: + +@IfMan + + p_half = a + b ∗ sp +@EndifMan +@IfDoc +\begin{displaymath} + p_half = a + b \ast sp +\end{displaymath} +@EndifDoc + +with + a, b: coefficients defining the model levels + sp: surface pressure +@EndDescription +@EndOperator + + +@BeginOperator_pressure +@Title = Pressure on full-levels + +@BeginDescription +This operator computes the pressure on model full-levels in pascal. +The pressure on model full-levels (p_full) is in the middle of the layers defined by the model half-levels: + +@IfMan + p_full = (p_half_above + p_half_below) / 2 +@EndifMan +@IfDoc +\begin{displaymath} + p_full = \frac{p_half_above + p_half_below}{2} +\end{displaymath} +@EndifDoc + +@EndDescription +@EndOperator + + +@BeginOperator_delta_pressure +@Title = Pressure difference of half-levels + +@BeginDescription +This operator computes the pressure difference between to model half-levels. + +@IfMan + delta_p = p_half_below - p_half_above +@EndifMan +@IfDoc +\begin{displaymath} + delta_p = p_half_below - p_half_above +\end{displaymath} +@EndifDoc + +@EndDescription +@EndOperator diff --git a/doc/tex/mod/Vertint b/doc/tex/mod/Vertint index a834a9d4b130472a4b8435d2012f1f6a76b7ef9b..611cdb8e7563ac775172db6ed60cd4b9adaf7b7f 100644 --- a/doc/tex/mod/Vertint +++ b/doc/tex/mod/Vertint @@ -9,20 +9,21 @@ @BeginDescription Interpolates 3D variables on hybrid sigma pressure level to pressure or height levels. -The input file should contain the log. surface pressure or the surface pressure. +To calculate the pressure on model levels, the a and b coefficients defining the model levels and +the surface pressure are required. The a and b coefficients are normally part of the model level data. +If not available, the surface pressure can be derived from the logarithm of the surface pressure. To extrapolate the temperature, the surface geopotential is also needed. -It is assumed that the geopotential heights are located at the hybrid layer interfaces. -For the lowest layer of geopotential heights the surface geopotential is required. -The pressure, temperature, geopotential height, and surface geopotential are identified by -their GRIB1 code number or NetCDF CF standard name. +The geopotential height must be present at the hybrid layer interfaces (model half-layers)! +All needed variables are identified by their GRIB1 code number or NetCDF CF standard name. Supported parameter tables are: WMO standard table number 2 and ECMWF local table number 128. -@BeginTable - @bold{CF standard name} & @bold{Units} & @bold{GRIB 1 code} - surface_air_pressure & Pa & 134 - air_temperature & K & 130 - surface_geopotential & m2 s-2 & 129 - geopotential_height & m & 156 +@BeginTable4 + @bold{Name} & @bold{Units} & @bold{GRIB1 code} & @bold{CF standard name} + log surface pressure & Pa & 152 & + surface pressure & Pa & 134 & surface_air_pressure + air temperature & K & 130 & air_temperature + surface geopotential & m2 s-2 & 129 & surface_geopotential + geopotential height & m & 156 & geopotential_height @EndTable Use the alias @bold{ml2plx}/@bold{ml2hlx} or the environment variable @env{EXTRAPOLATE} to extrapolate diff --git a/doc/tex/mod/Wind b/doc/tex/mod/Wind index d8e693201e684c0146162fe45b0e69d02f91642b..28440bd93eb6be0c83dd537dd53c0bfb99df5722 100644 --- a/doc/tex/mod/Wind +++ b/doc/tex/mod/Wind @@ -72,8 +72,7 @@ names u and v or the code numbers 131 and 132. @BeginParameter gridtype @Item = gridtype -STRING Type of the grid: quadratic, linear (default: quadratic) -@C STRING Type of the grid: quadratic, linear, cubic (default: quadratic) +STRING Type of the grid: quadratic, linear, cubic (default: quadratic) @EndParameter diff --git a/libcdi b/libcdi index 395ab6995d195c9bd5f7f7d33d08b1da8f926806..d64b85168fad6fd7a8bebe3a12e386b0f8c6a41a 160000 --- a/libcdi +++ b/libcdi @@ -1 +1 @@ -Subproject commit 395ab6995d195c9bd5f7f7d33d08b1da8f926806 +Subproject commit d64b85168fad6fd7a8bebe3a12e386b0f8c6a41a diff --git a/scripts/cppcheck.sh b/scripts/cppcheck.sh index a5bb31025c17a90798785f93244c1b34da539ffb..6d3b1eef3632240e3023fca27c56a8014daa025e 100755 --- a/scripts/cppcheck.sh +++ b/scripts/cppcheck.sh @@ -22,7 +22,7 @@ echo $TOPDIR # set -x echo "" > ${LOG_FILE} dirname=$TOPDIR/src -cppcheck --std=c++17 --force --enable=all --inline-suppr --template='{file}:{line},{severity},{id},{message}' \ +cppcheck --std=c++20 --force --enable=all --inline-suppr --template='{file}:{line},{severity},{id},{message}' \ -I${TOPDIR}/build/gnu/src -I${TOPDIR}/libcdi/src \ -DHAVE_CONFIG_H \ "$dirname" >>${LOG_FILE} 2>&1 diff --git a/src/Adisit.cc b/src/Adisit.cc index 4f527786309f3210d153f94dd06cb835f08f8af4..a772ac61f8cd4796a29ce2a9e6d4e5b7dd4c5cd3 100644 --- a/src/Adisit.cc +++ b/src/Adisit.cc @@ -133,8 +133,8 @@ get_code(int vlistID1, int varID, const std::string &cname) auto varname = string_to_lower(cdo::inq_var_name(vlistID1, varID)); auto stdname = string_to_lower(cdo::inq_key_string(vlistID1, varID, CDI_KEY_STDNAME)); - if (varname == "s" || stdname == "sea_water_salinity") { code = 5; } - else if (varname == "t") { code = 2; } + if (varname == "s" || varname == "so" || stdname == "sea_water_salinity") { code = 5; } + else if (varname == "t" || varname == "to") { code = 2; } if (stdname == cname) code = 2; } @@ -236,8 +236,20 @@ configureOutput(const std::function<void(const int, const int)> &outputSettingFu return IOSettings{ streamID2, vlistID2, gridsize, nlevels, taxisID1, taxisID2, tisID2, saoID2 }; } -class ModuleAdisit +class Adisit : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Adisit", + .operators = { { "adisit", 0, 0, "", AdisitHelp }, { "adipot", 0, 0, "", AdisitHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Adisit> registration = RegisterEntry<Adisit>(module); + int ADISIT, ADIPOT; int thoID = -1, saoID = -1; CdoStreamID streamID1; @@ -258,16 +270,13 @@ class ModuleAdisit FieldVector tho, sao, tis; Varray<double> pressure; - int ADISIT; - public: void - init(void *process) + init() { - cdo_initialize(process); - ADISIT = cdo_operator_add("adisit", 0, 0, ""); - auto ADIPOT = cdo_operator_add("adipot", 0, 0, ""); + ADISIT = module.get_id("adisit"); + ADIPOT = module.get_id("adipot"); operatorID = cdo_operator_id(); @@ -278,7 +287,7 @@ public: std::string cname_ADISIT{ "sea_water_potential_temperature" }; std::string cname_ADIPOT{ "sea_water_temperature" }; - std::string cname = std::string{ (operatorID == ADISIT) ? cname_ADISIT : cname_ADIPOT }; + std::string cname = (operatorID == ADISIT) ? cname_ADISIT : cname_ADIPOT; for (int varID = 0; varID < nvars; ++varID) { @@ -335,8 +344,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - if (varID == thoID) cdo_read_record(streamID1, tho[levelID].vec_d.data(), &tho[levelID].nmiss); - if (varID == saoID) cdo_read_record(streamID1, sao[levelID].vec_d.data(), &sao[levelID].nmiss); + if (varID == thoID) cdo_read_record(streamID1, tho[levelID].vec_d.data(), &tho[levelID].numMissVals); + if (varID == saoID) cdo_read_record(streamID1, sao[levelID].vec_d.data(), &sao[levelID].numMissVals); if (varID == thoID) { @@ -376,19 +385,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Adisit(void *process) -{ - ModuleAdisit adisit; - - adisit.init(process); - adisit.run(); - adisit.close(); - - return nullptr; -} diff --git a/src/Afterburner.cc b/src/Afterburner.cc index 1ed82902d2f9e8bb8188af732addfa0ac7369d7e..29c38dfd5f5ebc58c3132dec590d2ace0a1acc02 100644 --- a/src/Afterburner.cc +++ b/src/Afterburner.cc @@ -62,7 +62,7 @@ static int ofiletype = -1; static int DataType = -1; static char *filename; -static const char **ifiles; +static std::vector<const char *> ifiles; static char *ifile = nullptr; static int ofileidx = 0; @@ -71,6 +71,7 @@ static int specGridID = -1; static int gaussGridID = -1; static int iVertID = -1; static int oVertID = -1; +static int oVertID_half = -1; static bool Lhybrid2pressure = false; @@ -112,7 +113,7 @@ FreeMean(struct Variable *vars) for (int code = 0; code < MaxCodes; ++code) if (vars[code].mean) { - Free(vars[code].mean); + free(vars[code].mean); vars[code].mean = nullptr; } } @@ -282,7 +283,7 @@ after_SwitchFile(AfterControl *globs) } static CdiDateTime -after_getDateTime(struct Date datetime) +after_getDateTime(const struct Date &datetime) { CdiDateTime cdiDateTime{}; cdiDateTime.date = cdiDate_encode(datetime.yr, datetime.mo, datetime.dy); @@ -376,8 +377,8 @@ static int num_recs = 0; static void * after_readTimestep(void *arg) { - int varID, gridID, zaxisID, levelID, timeID; - size_t nmiss; + int varID, gridID, zaxisID, levelID, timeType; + size_t numMissVals; auto rarg = (RARG *) arg; auto nrecs = rarg->nrecs; @@ -385,7 +386,7 @@ after_readTimestep(void *arg) auto vars = rarg->vars; auto globs = rarg->globs; - for (int code = 0; code < MaxCodes; ++code) vars[code].nmiss0 = 0; + for (int code = 0; code < MaxCodes; ++code) vars[code].numMissVals0 = 0; for (int recID = 0; recID < nrecs; ++recID) { @@ -397,7 +398,7 @@ after_readTimestep(void *arg) // Skip records containing unneeded codes if (!vars[code].needed0) continue; - vlistInqVar(globs->ivlistID, varID, &gridID, &zaxisID, &timeID); + vlistInqVar(globs->ivlistID, varID, &gridID, &zaxisID, &timeType); auto leveltype = zaxisInqType(zaxisID); @@ -433,14 +434,14 @@ after_readTimestep(void *arg) if (analysisData) { - streamReadRecord(globs->istreamID, globs->Field, &nmiss); - after_AnalysisAddRecord(globs, vars, code, gridID, zaxisID, levelID, nmiss); + streamReadRecord(globs->istreamID, globs->varray.data(), &numMissVals); + after_AnalysisAddRecord(globs, vars, code, gridID, zaxisID, levelID, numMissVals); } else { double *dataptr = after_get_dataptr(vars, code, gridID, zaxisID, levelID); - streamReadRecord(globs->istreamID, dataptr, &nmiss); - after_EchamAddRecord(globs, vars, code, gridID, zaxisID, levelID, nmiss); + streamReadRecord(globs->istreamID, dataptr, &numMissVals); + after_EchamAddRecord(globs, vars, code, gridID, zaxisID, levelID, numMissVals); } if (iVertID != -1 && oVertID != -1 && (vars[code].izaxisID == iVertID)) vars[code].ozaxisID = oVertID; @@ -499,7 +500,7 @@ after_setEndOfInterval(AfterControl &globs, int nrecs) static void after_moveTimestep(struct Variable *vars) { - for (int code = 0; code < MaxCodes; ++code) vars[code].nmiss = vars[code].nmiss0; + for (int code = 0; code < MaxCodes; ++code) vars[code].numMissVals = vars[code].numMissVals0; for (int code = 0; code < MaxCodes; ++code) if (vars[code].hybrid0) @@ -697,8 +698,8 @@ after_setLevel(AfterControl &globs) int numplevelDefault = sizeof(plevelDefault) / sizeof(plevelDefault[0]); int numhlevelDefault = sizeof(hlevelDefault) / sizeof(hlevelDefault[0]); - if (iVertID != -1) - if (zaxisInqType(iVertID) == ZAXIS_HYBRID && globs.Type > 20) Lhybrid2pressure = true; + int iLevelType = (iVertID != -1) ? zaxisInqType(iVertID) : -1; + if (iLevelType == ZAXIS_HYBRID && globs.Type > 20) Lhybrid2pressure = true; if (globs.Verbose) lprintf(stdout); @@ -733,13 +734,15 @@ after_setLevel(AfterControl &globs) { if (globs.Verbose) { - if (zaxisInqType(iVertID) == ZAXIS_HYBRID) + if (iLevelType == ZAXIS_HYBRID) fprintf(stdout, " All detected hybrid level selected:\n"); else fprintf(stdout, " All detected pressure level selected:\n"); } globs.NumLevelRequest = globs.NumLevelFound; for (int l = 0; l < globs.NumLevelRequest; ++l) globs.LevelRequest[l] = LevelFound[l]; + int maxLev = globs.NumLevelFound; + if (maxLev == (globs.numHalfLevels - 1)) globs.LevelRequest[maxLev] = globs.numHalfLevels; oVertID = iVertID; } } @@ -762,22 +765,14 @@ after_setLevel(AfterControl &globs) { if (Lhybrid2pressure) { - if (globs.unitsel == 0) - fprintf(stdout, " Selected pressure level:\n"); - else - fprintf(stdout, " Selected height level:\n"); + fprintf(stdout, " Selected %s level:\n", (globs.unitsel == 0) ? "pressure" : "height"); } else { - if (zaxisInqType(iVertID) == ZAXIS_HYBRID) + if (iLevelType == ZAXIS_HYBRID) fprintf(stdout, " Selected hybrid level:\n"); else - { - if (globs.unitsel == 0) - fprintf(stdout, " Selected pressure level:\n"); - else - fprintf(stdout, " Selected height level:\n"); - } + fprintf(stdout, " Selected %s level:\n", (globs.unitsel == 0) ? "pressure" : "height"); } } } @@ -857,11 +852,12 @@ after_defineLevel(const AfterControl &globs, struct Variable *vars) { if (iVertID == -1) break; - if (zaxisInqType(iVertID) == ZAXIS_HYBRID) + int iVertType = zaxisInqType(iVertID); + if (iVertType == ZAXIS_HYBRID || iVertType == ZAXIS_HYBRID_HALF) { if (oVertID == -1) { - if (globs.NumLevelRequest > globs.NumLevelFound) afterAbort("Too much level requested"); + if (globs.NumLevelRequest > globs.NumLevelFound) afterAbort("Too many level requested"); if (globs.NumLevelFound == globs.NumLevelRequest) { @@ -876,7 +872,17 @@ after_defineLevel(const AfterControl &globs, struct Variable *vars) { oVertID = zaxisCreate(ZAXIS_HYBRID, globs.NumLevelRequest); zaxisDefLevels(oVertID, globs.LevelRequest); - zaxisDefVct(oVertID, globs.nvct, globs.vct); + zaxisDefVct(oVertID, globs.nvct, globs.vct.data()); + } + } + + if (vars[GEOPOTHEIGHT].selected && oVertID_half == -1) + { + if (oVertID_half == -1 && globs.NumLevelRequest > 0) + { + oVertID_half = zaxisCreate(ZAXIS_HYBRID_HALF, globs.NumLevelRequest + 1); + zaxisDefLevels(oVertID_half, globs.LevelRequest); + zaxisDefVct(oVertID_half, globs.nvct, globs.vct.data()); } } @@ -884,10 +890,16 @@ after_defineLevel(const AfterControl &globs, struct Variable *vars) { if (vars[code].selected) { - if (vars[code].izaxisID != -1) - if (zaxisInqType(vars[code].izaxisID) == ZAXIS_HYBRID - && zaxisInqSize(vars[code].izaxisID) >= globs.NumLevelRequest) - vars[code].ozaxisID = oVertID; + int zaxisID = vars[code].izaxisID; + if (zaxisID != -1) + { + int zaxisType = zaxisInqType(zaxisID); + int numLevels = zaxisInqSize(zaxisID); + if ((zaxisType == ZAXIS_HYBRID || zaxisType == ZAXIS_HYBRID_HALF) && numLevels >= globs.NumLevelRequest) + { + vars[code].ozaxisID = (code == GEOPOTHEIGHT) ? oVertID_half : oVertID; + } + } } } } @@ -918,11 +930,12 @@ after_defineLevel(const AfterControl &globs, struct Variable *vars) { if (vars[code].selected) { - if (vars[code].izaxisID != -1) + int zaxisID = vars[code].izaxisID; + if (zaxisID != -1) { - int nlev = zaxisInqSize(vars[code].izaxisID); - if (zaxisInqType(vars[code].izaxisID) == zaxisInqType(iVertID) - && (nlev == globs.NumLevel || nlev == globs.NumLevel + 1) && nlev > 1) + int zaxisType = zaxisInqType(zaxisID); + int numLevels = zaxisInqSize(zaxisID); + if (zaxisType == zaxisInqType(iVertID) && (numLevels == globs.NumLevel || numLevels == globs.NumLevel + 1) && numLevels > 1) vars[code].ozaxisID = oVertID; } } @@ -1137,6 +1150,8 @@ after_parini(AfterControl &globs, struct Variable *vars) } namelist[i] = 0; + globs.Debug = scan_par(globs.Verbose, namelist, "debug", 0); + if (globs.Debug) { lprintf(stderr); @@ -1260,7 +1275,7 @@ after_precntl(AfterControl &globs, struct Variable *vars) { int vertfound = 0; int nhzaxis = 0; - int FieldDim = 0; + int gridSizeMax = 0; auto nvars = vlistNvars(globs.ivlistID); auto ngrids = vlistNgrids(globs.ivlistID); @@ -1281,7 +1296,7 @@ after_precntl(AfterControl &globs, struct Variable *vars) auto gridtype = gridInqType(gridID); int datasize = gridInqSize(gridID); - if (datasize > FieldDim) FieldDim = datasize; + if (datasize > gridSizeMax) gridSizeMax = datasize; if (gridtype == GRID_SPECTRAL && globs.Truncation == 0) { @@ -1314,6 +1329,7 @@ after_precntl(AfterControl &globs, struct Variable *vars) case 64: globs.Truncation = 42; break; case 48: globs.Truncation = 31; break; case 32: globs.Truncation = 21; break; + case 1: break; default: fprintf(stderr, "%d Gaussian latitudes not supported.\n", globs.Latitudes); } } @@ -1324,18 +1340,15 @@ after_precntl(AfterControl &globs, struct Variable *vars) auto zaxisID = vlistZaxis(globs.ivlistID, index); auto leveltype = zaxisInqType(zaxisID); auto numlevel = zaxisInqSize(zaxisID); - /* - printf("leveltype : %d %d\n", leveltype, zaxisInqSize(zaxisID)); - */ if (numlevel > 1) { - if (leveltype == ZAXIS_HYBRID || leveltype == ZAXIS_PRESSURE) + if (leveltype == ZAXIS_HYBRID || leveltype == ZAXIS_HYBRID_HALF || leveltype == ZAXIS_PRESSURE) { - if (leveltype == ZAXIS_HYBRID && globs.nvct == 0) + if ((leveltype == ZAXIS_HYBRID || leveltype == ZAXIS_HYBRID_HALF) && globs.nvct == 0) { nhzaxis++; int nvct = zaxisInqVctSize(zaxisID); - if (numlevel != (nvct / 2 - 1)) + if (numlevel != (nvct / 2 - 1) && numlevel != (nvct / 2)) { if (nvct == 0) { @@ -1345,8 +1358,10 @@ after_precntl(AfterControl &globs, struct Variable *vars) continue; } } - else if (leveltype == ZAXIS_HYBRID && globs.nvct == zaxisInqVctSize(zaxisID)) - continue; + else if ((leveltype == ZAXIS_HYBRID || leveltype == ZAXIS_HYBRID_HALF) && globs.nvct == zaxisInqVctSize(zaxisID)) + { + continue; + } if (iVertID != -1) cdo_warning("More than %d different vertical grid structure found!", vertfound); @@ -1359,29 +1374,35 @@ after_precntl(AfterControl &globs, struct Variable *vars) LevelFound.resize(globs.NumLevelFound); for (int l = 0; l < globs.NumLevelFound; ++l) LevelFound[l] = (int) zaxisInqLevel(zaxisID, l); - if (leveltype == ZAXIS_HYBRID) + if (leveltype == ZAXIS_HYBRID || leveltype == ZAXIS_HYBRID_HALF) { if (globs.nvct == 0) { if (zaxisInqVctSize(zaxisID)) { globs.nvct = zaxisInqVctSize(zaxisID); - - if (globs.vct == nullptr) + globs.numHalfLevels = globs.nvct / 2; + if ((int)globs.vct.size() != globs.nvct) { - globs.vct = (double *) Malloc(globs.nvct * sizeof(double)); - array_copy(globs.nvct, zaxisInqVctPtr(zaxisID), globs.vct); + globs.vct.resize(globs.nvct); + zaxisInqVct(zaxisID, globs.vct.data()); } } else { afterAbort("VCT not defined in inputfile!"); } } - if (numlevel != (globs.nvct / 2 - 1)) - afterAbort("Number of hybrid levels %d does not match VCT levels %d", numlevel, globs.nvct / 2 - 1); + if (numlevel == globs.numHalfLevels) + { + globs.NumLevelFound--; + } + else if (numlevel != (globs.numHalfLevels - 1)) + { + afterAbort("Number of hybrid levels %d does not match VCT levels %d", numlevel, globs.numHalfLevels - 1); + } if (globs.Debug) - for (int i = 0; i < globs.nvct / 2; ++i) - fprintf(stderr, " vct: %4d %10.4f %10.4f\n", i, globs.vct[i], globs.vct[i + globs.nvct / 2]); + for (int i = 0; i < globs.numHalfLevels; ++i) + fprintf(stderr, " vct: %4d %10.4f %10.4f\n", i, globs.vct[i], globs.vct[i + globs.numHalfLevels]); } if (leveltype == ZAXIS_PRESSURE) globs.AnalysisData = true; @@ -1424,7 +1445,7 @@ after_precntl(AfterControl &globs, struct Variable *vars) { if (modelInqNamePtr(modelID)) { - if (std::strncmp(modelInqNamePtr(modelID), "ECHAM5", 6) == 0) Source = S_ECHAM5; + if (std::strncmp(modelInqNamePtr(modelID), "ECHAM5", 6) == 0) Source = ECHAM5_Source; fprintf(stdout, "%s\n", modelInqNamePtr(modelID)); } else @@ -1434,8 +1455,8 @@ after_precntl(AfterControl &globs, struct Variable *vars) for (int varID = 0; varID < nvars; ++varID) { - int gridID, zaxisID, timeID; - vlistInqVar(globs.ivlistID, varID, &gridID, &zaxisID, &timeID); + int gridID, zaxisID, timeType; + vlistInqVar(globs.ivlistID, varID, &gridID, &zaxisID, &timeType); auto code = vlistInqVarCode(globs.ivlistID, varID); if (code <= 0 || code >= MaxCodes) { @@ -1458,9 +1479,9 @@ after_precntl(AfterControl &globs, struct Variable *vars) fprintf(stderr, "Code %3d Levels = %3d LevelType = %3d GridType = %3d\n", code, numlevel, leveltype, gridtype); } - if (globs.Debug) fprintf(stderr, "FieldDim = %d\n", FieldDim); + if (globs.Debug) fprintf(stderr, "FieldDim = %d\n", gridSizeMax); - globs.Field = (double *) Malloc(FieldDim * sizeof(double)); + globs.varray.resize(gridSizeMax); if (globs.Debug) for (int code = 0; code < MaxCodes; ++code) @@ -1606,7 +1627,8 @@ after_readVct(AfterControl &globs, const char *vctfile) } globs.nvct = nlines * 2; - globs.vct = (double *) Malloc(globs.nvct * sizeof(double)); + globs.numHalfLevels = globs.nvct / 2; + globs.vct.resize(globs.nvct); rewind(fp); @@ -1618,10 +1640,10 @@ after_readVct(AfterControl &globs, const char *vctfile) double va, vb; std::sscanf(line, "%d %lg %lg", &n, &va, &vb); globs.vct[i] = va; - globs.vct[i + globs.nvct / 2] = vb; + globs.vct[i + globs.numHalfLevels] = vb; i++; } - fprintf(stdout, " Read VCT with %d hybrid levels from file %s\n", globs.nvct / 2 - 1, vctfile); + fprintf(stdout, " Read VCT with %d hybrid levels from file %s\n", globs.numHalfLevels - 1, vctfile); std::fclose(fp); } @@ -1694,9 +1716,9 @@ after_processing(AfterControl &globs, struct Variable *vars) after_dimcalc(globs); - globs.rcoslat = (double *) Malloc(globs.Latitudes * sizeof(double)); - globs.coslat = (double *) Malloc(globs.Latitudes * sizeof(double)); - globs.DerivationFactor = (double *) Malloc(globs.Latitudes * sizeof(double)); + globs.rcoslat.resize(globs.Latitudes); + globs.coslat.resize(globs.Latitudes); + globs.derivationFactor.resize(globs.Latitudes); if (globs.Type < 50 && globs.AnalysisData) { @@ -1743,12 +1765,12 @@ after_processing(AfterControl &globs, struct Variable *vars) vars[GEOPOTENTIAL].needed |= globs.Type >= 30 || vars[SLP].comp || vars[GEOPOTHEIGHT].comp; } - /* if ( vars[U_WIND].needed || vars[V_WIND].needed ) */ + // if ( vars[U_WIND].needed || vars[V_WIND].needed ) if (vars[U_WIND].comp || vars[V_WIND].comp) { - globs.dv2uv_f1 = (double *) Malloc(globs.DimSP_half * sizeof(double)); - globs.dv2uv_f2 = (double *) Malloc(globs.DimSP_half * sizeof(double)); - geninx(globs.Truncation, globs.dv2uv_f1, globs.dv2uv_f2); + globs.dv2uv_f1.resize(globs.DimSP_half); + globs.dv2uv_f2.resize(globs.DimSP_half); + geninx(globs.Truncation, globs.dv2uv_f1.data(), globs.dv2uv_f2.data()); } /* --------- */ @@ -1770,17 +1792,27 @@ after_processing(AfterControl &globs, struct Variable *vars) streamClose(globs.istreamID); } -class ModuleAfterburner +class Afterburner : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Afterburner", + .operators = { { "after", AfterburnerHelp } }, + .aliases = { { "afterburner", "after" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Afterburner> registration = RegisterEntry<Afterburner>(module); + AfterControl globs = {}; struct Variable vars[MaxCodes + 5]; public: void - init(void *process) + init() { - cdo_initialize(process); - lstdout = !Options::silentMode; globs.Verbose = Options::cdoVerbose; @@ -1805,7 +1837,7 @@ public: { if (globs.Multi > 0) afterAbort("Namelist parameter MULTI works only with one inputfile"); - ifiles = (const char **) Malloc(globs.Nfiles * sizeof(char *)); + ifiles.resize(globs.Nfiles); for (int i = 0; i < globs.Nfiles; ++i) ifiles[i] = cdo_get_stream_name(--nfiles); for (int i = 0; i < globs.Nfiles; ++i) printf("files %d %s\n", i + 1, ifiles[i]); } @@ -1821,20 +1853,5 @@ public: close() { FreeMean(vars); - - free(ifile); - - cdo_finish(); } }; - -void * -Afterburner(void *process) -{ - ModuleAfterburner afterburner; - afterburner.init(process); - afterburner.run(); - afterburner.close(); - - return nullptr; -} diff --git a/src/Arith.cc b/src/Arith.cc index c78fea83ae0f3c8b714c911bfa4cf1cdde2b4693..68b8f6bffe48b4b3a8632a571090446af6653ab8 100644 --- a/src/Arith.cc +++ b/src/Arith.cc @@ -28,22 +28,7 @@ #include "cdo_fill.h" #include "field_functions.h" -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("add", FieldFunc_Add, 1, nullptr); - cdo_operator_add("sub", FieldFunc_Sub, 1, nullptr); - cdo_operator_add("mul", FieldFunc_Mul, 1, nullptr); - cdo_operator_add("div", FieldFunc_Div, 1, nullptr); - cdo_operator_add("min", FieldFunc_Min, 0, nullptr); - cdo_operator_add("max", FieldFunc_Max, 0, nullptr); - cdo_operator_add("atan2", FieldFunc_Atan2, 0, nullptr); - cdo_operator_add("setmiss", FieldFunc_Setmiss, 0, nullptr); - // clang-format on -} - -class ModuleArith +class Arith : public Process { enum class FillType { @@ -51,14 +36,34 @@ class ModuleArith TS, VAR, VARTS, - FILE + FULL_FILE + }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Arith", + .operators = { { "add", FieldFunc_Add, 1, ArithHelp }, + { "sub", FieldFunc_Sub, 1, ArithHelp }, + { "mul", FieldFunc_Mul, 1, ArithHelp }, + { "div", FieldFunc_Div, 1, ArithHelp }, + { "min", FieldFunc_Min, 0, ArithHelp }, + { "max", FieldFunc_Max, 0, ArithHelp }, + { "atan2", FieldFunc_Atan2, 0, ArithHelp }, + { "setmiss", FieldFunc_Setmiss, 0, ArithHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 2, 1, NoRestriction }, }; + inline static RegisterEntry<Arith> registration = RegisterEntry<Arith>(module); + FillType fillType{ FillType::NONE }; int nlevels2 = 1; int levelID2 = -1; - Varray2D<size_t> varnmiss; + Varray2D<size_t> varnumMissVals; Varray2D<double> vardata; - std::vector<size_t> varnmiss2; + std::vector<size_t> varnumMissVals2; Varray<double> vardata2; CdoStreamID streamID1; @@ -87,12 +92,8 @@ class ModuleArith public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); bool opercplx = cdo_operator_f2(operatorID); @@ -200,7 +201,7 @@ public: if (fillStream1x || fillType == FillType::VAR || fillType == FillType::VARTS) { vardata2.resize(gridsizemax * nlevels2); - varnmiss2.resize(nlevels2); + varnumMissVals2.resize(nlevels2); } if (Options::cdoVerbose) cdo_print("Number of timesteps: file1 %d, file2 %d", ntsteps1, ntsteps2); @@ -225,7 +226,7 @@ public: fieldx2 = &field1; } - if (fillType == FillType::TS) cdo_fill_ts(vlistID2x, vardata, varnmiss); + if (fillType == FillType::TS) cdo_fill_ts(vlistID2x, vardata, varnumMissVals); } auto streamsSwaped = (fillType == FillType::TS && vlistID1x != vlistID1); @@ -266,7 +267,7 @@ public: nrecs = cdo_stream_inq_timestep(streamID1, tsID); nrecs2 = 0; - if (tsID == 0 || fillType == FillType::NONE || fillType == FillType::FILE || fillType == FillType::VARTS) + if (tsID == 0 || fillType == FillType::NONE || fillType == FillType::FULL_FILE || fillType == FillType::VARTS) { nrecs2 = cdo_stream_inq_timestep(streamID2, tsID2); if (nrecs2 == 0) @@ -275,23 +276,21 @@ public: if (fillType == FillType::NONE && streamID2x == streamID2) { - fillType = FillType::FILE; + fillType = FillType::FULL_FILE; cdo_print("Filling up stream2 >%s< by copying all timesteps.", cdo_get_stream_name(1)); } - if (fillType == FillType::FILE) + if (fillType == FillType::FULL_FILE) { cdo_stream_close(streamID2); - if (cdo_assert_files_only() == false) cdo_abort("infile2 cannot be a pipe in fill mode!"); + if (stream_is_pipe(1)) cdo_abort("infile2 cannot be a pipe in fill mode!"); streamID2 = cdo_open_read(1); streamID2x = streamID2; vlistID2 = cdo_stream_inq_vlist(streamID2); - vlist_compare(vlistID1, vlistID2, CmpVlist::Dim); - tsID2 = 0; nrecs2 = cdo_stream_inq_timestep(streamID2, tsID2); if (nrecs2 == 0) cdo_abort("Empty input stream %s!", cdo_get_stream_name(1)); @@ -315,13 +314,13 @@ public: if (lread1) { cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, fieldx1->vec_d.data(), &fieldx1->nmiss); + cdo_read_record(streamID1, fieldx1->vec_d.data(), &fieldx1->numMissVals); if (fillStream1x) { auto gridsize = nwpv * varList1[varID].gridsize; array_copy(gridsize, fieldx1->vec_d.data(), &vardata2[0]); - varnmiss2[0] = fieldx1->nmiss; + varnumMissVals2[0] = fieldx1->numMissVals; } } @@ -329,13 +328,13 @@ public: auto varID2 = varID; - if (tsID == 0 || fillType == FillType::NONE || fillType == FillType::FILE || fillType == FillType::VARTS) + if (tsID == 0 || fillType == FillType::NONE || fillType == FillType::FULL_FILE || fillType == FillType::VARTS) { auto lstatus = (nlevels2 > 1) ? (varID == 0) : (recID == 0); if (lstatus || (fillType != FillType::VAR && fillType != FillType::VARTS)) { cdo_inq_record(streamID2, &varID2, &levelID2); - cdo_read_record(streamID2, fieldx2->vec_d.data(), &fieldx2->nmiss); + cdo_read_record(streamID2, fieldx2->vec_d.data(), &fieldx2->numMissVals); if (varID != varID2) cdo_abort("Internal error, varIDs of input streams differ!"); if (fillStream1x == false && levelID != levelID2) cdo_abort("Internal error, levelIDs of input streams differ!"); @@ -346,14 +345,14 @@ public: auto gridsize = nwpv * varList2[varID].gridsize; auto offset = gridsize * levelID; array_copy(gridsize, fieldx2->vec_d.data(), &vardata[varID][offset]); - varnmiss[varID][levelID] = fieldx2->nmiss; + varnumMissVals[varID][levelID] = fieldx2->numMissVals; } else if (lstatus && (fillType == FillType::VAR || fillType == FillType::VARTS)) { auto gridsize = nwpv * varList2[0].gridsize; auto offset = gridsize * levelID2; array_copy(gridsize, fieldx2->vec_d.data(), &vardata2[offset]); - varnmiss2[levelID2] = fieldx2->nmiss; + varnumMissVals2[levelID2] = fieldx2->numMissVals; } } else if (fillType == FillType::TS) @@ -361,14 +360,14 @@ public: auto gridsize = nwpv * varList2[varID2].gridsize; auto offset = gridsize * levelID; array_copy(gridsize, &vardata[varID][offset], fieldx2->vec_d.data()); - fieldx2->nmiss = varnmiss[varID][levelID]; + fieldx2->numMissVals = varnumMissVals[varID][levelID]; } if (fillStream1x) { auto gridsize = nwpv * varList1[0].gridsize; array_copy(gridsize, &vardata2[0], fieldx1->vec_d.data()); - fieldx1->nmiss = varnmiss2[0]; + fieldx1->numMissVals = varnumMissVals2[0]; } fieldx1->grid = varList1[varID].gridID; @@ -381,7 +380,7 @@ public: auto gridsize = nwpv * varList2[0].gridsize; auto offset = gridsize * levelID2; array_copy(gridsize, &vardata2[offset], fieldx2->vec_d.data()); - fieldx2->nmiss = varnmiss2[levelID2]; + fieldx2->numMissVals = varnumMissVals2[levelID2]; fieldx2->grid = varList2[0].gridID; fieldx2->missval = varList2[0].missval; fieldx2->nwpv = varList2[0].nwpv; @@ -399,7 +398,7 @@ public: field2_function(field1, field2, operfunc); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, field1.vec_d.data(), field1.nmiss); + cdo_write_record(streamID3, field1.vec_d.data(), field1.numMissVals); } tsID++; @@ -418,18 +417,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID3); - - cdo_finish(); } }; - -void * -Arith(void *process) -{ - ModuleArith arith; - arith.init(process); - arith.run(); - arith.close(); - - return nullptr; -} diff --git a/src/Arithc.cc b/src/Arithc.cc index 77997f4c243e39bf50d584728efabfc1baeb0c31..cb68f769e885a906505e11667406a0a469834b47 100644 --- a/src/Arithc.cc +++ b/src/Arithc.cc @@ -51,22 +51,26 @@ fill_vars(const VarList &varList, std::vector<bool> &vars) } } -static void -add_operators(void) +class Arithc : public Process { - // clang-format off - cdo_operator_add("addc", FieldFunc_Add, 1, "constant value"); - cdo_operator_add("subc", FieldFunc_Sub, 1, "constant value"); - cdo_operator_add("mulc", FieldFunc_Mul, 1, "constant value"); - cdo_operator_add("divc", FieldFunc_Div, 1, "constant value"); - cdo_operator_add("minc", FieldFunc_Min, 0, "constant value"); - cdo_operator_add("maxc", FieldFunc_Max, 0, "constant value"); - cdo_operator_add("mod", FieldFunc_Mod, 0, "divisor"); - // clang-format on -} +public: + using Process::Process; + inline static CdoModule module = { + .name = "Arithc", + .operators = { { "addc", FieldFunc_Add, 1, "constant value", ArithcHelp }, + { "subc", FieldFunc_Sub, 1, "constant value", ArithcHelp }, + { "mulc", FieldFunc_Mul, 1, "constant value", ArithcHelp }, + { "divc", FieldFunc_Div, 1, "constant value", ArithcHelp }, + { "minc", FieldFunc_Min, 0, "constant value", ArithcHelp }, + { "maxc", FieldFunc_Max, 0, "constant value", ArithcHelp }, + { "mod", FieldFunc_Mod, 0, "divisor", ArithcHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Arithc> registration = RegisterEntry<Arithc>(module); -class ModuleArithc -{ CdoStreamID streamID1; int taxisID1; @@ -82,12 +86,8 @@ class ModuleArithc public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); bool opercplx = cdo_operator_f2(operatorID); @@ -174,18 +174,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Arithc(void *process) -{ - ModuleArithc arithc; - arithc.init(process); - arithc.run(); - arithc.close(); - - return nullptr; -} diff --git a/src/Arithdays.cc b/src/Arithdays.cc index 593155cb1f53bbfba3370ce6a0c8ed11e603c006..be68aa8a89172879b4689609a791eb9e3a1ed82b 100644 --- a/src/Arithdays.cc +++ b/src/Arithdays.cc @@ -52,7 +52,7 @@ dayofyear(int calendar, const CdiDateTime &vDateTime) return doy; } -class ModuleArithdays +class Arithdays : public Process { enum { @@ -60,6 +60,23 @@ class ModuleArithdays Func_Year, }; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Arithdays", + .operators = { { "muldpm", FieldFunc_Mul, Func_Month, ArithdaysHelp }, + { "divdpm", FieldFunc_Div, Func_Month, ArithdaysHelp }, + { "muldpy", FieldFunc_Mul, Func_Year, ArithdaysHelp }, + { "divdpy", FieldFunc_Div, Func_Year, ArithdaysHelp }, + { "muldoy", FieldFunc_Mul, 0, ArithdaysHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Arithdays> registration = RegisterEntry<Arithdays>(module); + int MULDOY; + CdoStreamID streamID1; int taxisID1; @@ -74,20 +91,13 @@ class ModuleArithdays VarList varList1; Field field; - int MULDOY; - public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("muldpm", FieldFunc_Mul, Func_Month, nullptr); - cdo_operator_add("divdpm", FieldFunc_Div, Func_Month, nullptr); - cdo_operator_add("muldpy", FieldFunc_Mul, Func_Year, nullptr); - cdo_operator_add("divdpy", FieldFunc_Div, Func_Year, nullptr); - MULDOY = cdo_operator_add("muldoy", FieldFunc_Mul, 0, nullptr); +MULDOY = module.get_id("muldoy"); // clang-format on operatorID = cdo_operator_id(); @@ -159,17 +169,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Arithdays(void *process) -{ - ModuleArithdays arithdays; - arithdays.init(process); - arithdays.run(); - arithdays.close(); - return nullptr; -} diff --git a/src/Arithlat.cc b/src/Arithlat.cc index 4ddd75497e298511b54ea512474457b88e92c6e0..c4500d937aad4fd2cddcd0090b5cee77a57b3732 100644 --- a/src/Arithlat.cc +++ b/src/Arithlat.cc @@ -19,8 +19,23 @@ #include <mpim_grid.h> #include "field_functions.h" -class ModuleArithlat +class Arithlat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Arithlat", + // clang-format off + .operators = { { "mulcoslat", FieldFunc_Mul, 0, ArithlatHelp }, + { "divcoslat", FieldFunc_Div, 0, ArithlatHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Arithlat> registration = RegisterEntry<Arithlat>(module); + CdoStreamID streamID1; int taxisID1; @@ -35,22 +50,17 @@ class ModuleArithlat public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("mulcoslat", FieldFunc_Mul, 0, nullptr); - cdo_operator_add("divcoslat", FieldFunc_Div, 0, nullptr); - - const auto operatorID = cdo_operator_id(); + auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); operator_check_argc(0); streamID1 = cdo_open_read(0); - const auto vlistID1 = cdo_stream_inq_vlist(streamID1); - const auto vlistID2 = vlistDuplicate(vlistID1); + auto vlistID1 = cdo_stream_inq_vlist(streamID1); + auto vlistID2 = vlistDuplicate(vlistID1); taxisID1 = vlistInqTaxis(vlistID1); taxisID2 = taxisDuplicate(taxisID1); @@ -61,10 +71,11 @@ public: varList_init(varList1, vlistID1); - const auto gridsizemax = vlistGridsizeMax(vlistID1); + auto gridsizemax = vlistGridsizeMax(vlistID1); array = Varray<double>(gridsizemax); } + void run() { @@ -72,7 +83,7 @@ public: int tsID = 0; while (true) { - const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); if (nrecs == 0) break; cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -82,12 +93,12 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); auto gridID = varList1[varID].gridID; - const auto gridsize = varList1[varID].gridsize; - const auto missval = varList1[varID].missval; + auto gridsize = varList1[varID].gridsize; + auto missval = varList1[varID].missval; if (gridID != gridID0) { @@ -110,7 +121,7 @@ public: for (int i = 0; i < 10; ++i) cdo_print("coslat %3d %g", i + 1, scale[i]); } - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < gridsize; ++i) if (!DBL_IS_EQUAL(array[i], missval)) array[i] *= scale[i]; @@ -121,28 +132,17 @@ public: } cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); } tsID++; } } + void close() { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Arithlat(void *process) -{ - ModuleArithlat arithlat; - arithlat.init(process); - arithlat.run(); - arithlat.close(); - return nullptr; -} diff --git a/src/Bitrounding.cc b/src/Bitrounding.cc index c3b89d808eba0dec778f89edbb6012ccf9dad71e..cb0b2ae0ed2ab10dfadbec44f883a034cf93ad78 100644 --- a/src/Bitrounding.cc +++ b/src/Bitrounding.cc @@ -102,7 +102,7 @@ bitround(int nsb, size_t len, Varray<float> &v, float missval) constexpr uint32_t BIT_XPL_NBR_SGN_FLT = 23; - // BitRound interprets nsd as number of significant binary digits (bits) + // BitRound interprets nsb as number of significant binary digits (bits) uint32_t prc_bnr_xpl_rqr = nsb; uint32_t bit_xpl_nbr_zro = BIT_XPL_NBR_SGN_FLT - prc_bnr_xpl_rqr; @@ -157,7 +157,7 @@ get_parameter() KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -292,8 +292,19 @@ num_vars_have_numbits(const std::vector<int> &varsNumbits) return numVarsHaveNumbits; } -class ModuleBitrounding +class Bitrounding : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Bitrounding", + .operators = { { "bitrounding", BitroundingHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Bitrounding> registration = RegisterEntry<Bitrounding>(module); CdoStreamID streamID1; int taxisID1; @@ -317,12 +328,8 @@ class ModuleBitrounding public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("bitrounding", 0, 0, nullptr); - params = get_parameter(); if (Options::cdoVerbose) print_parameter(params); @@ -366,6 +373,7 @@ public: progress::init(); } + void run() { @@ -382,7 +390,7 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - auto fstatus = (ntsteps > 1) ? (tsID + (recID + 1.0) / nrecs) / ntsteps : 1.0; + auto fstatus = (ntsteps >= 0) ? (tsID + (recID + 1.0) / nrecs) / ntsteps : 1.0; if (!Options::cdoVerbose) progress::update(0, 1, fstatus); int varID, levelID; @@ -405,7 +413,7 @@ public: { int nsb = (varsNumbits[varID] != -1) ? varsNumbits[varID] : params.numBits; - if (field.nmiss == 0) + if (field.numMissVals == 0) { if (nsb == -1 && (tsID == 0 || params.numSteps == -1)) { @@ -424,7 +432,7 @@ public: if (nsb >= 1 && nsb <= 23) bitround(nsb, field.size, field.vec_f, var.missval); - if (nsb == -1 && field.nmiss > 0 && varsCheckMiss[varID]) + if (nsb == -1 && field.numMissVals > 0 && varsCheckMiss[varID]) { varsCheckMiss[varID] = false; cdo_warning("Missing values unsupported, bitrounding disabled for %s!", var.name); @@ -475,6 +483,7 @@ public: fprintf(stderr, "\n"); } } + void close() { @@ -482,16 +491,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - cdo_finish(); } }; - -void * -Bitrounding(void *process) -{ - ModuleBitrounding bitrounding; - bitrounding.init(process); - bitrounding.run(); - bitrounding.close(); - return nullptr; -} diff --git a/src/CDIread.cc b/src/CDIread.cc index 3e69d05160ad768f0c94a3c9f4c76ba596d6cb1d..1e211bdc4b53c05e5d28d116d089645760400571 100644 --- a/src/CDIread.cc +++ b/src/CDIread.cc @@ -28,8 +28,19 @@ print_stat(const char *sinfo, MemType memtype, int datatype, int filetype, off_t cdo_print("%s Read %.1f GB in %.1f seconds, total %.1f MB/s", sinfo, fileSize, tw, (tw > 0) ? 1024 * fileSize / tw : -1); } -class ModuleCDIread +class CDIread : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "CDIread", + .operators = { { "cdiread"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<CDIread> registration = RegisterEntry<CDIread>(module); MemType memtype = Options::CDO_Memtype; int filetype = -1, datatype = -1; char sinfo[64]; @@ -41,9 +52,8 @@ class ModuleCDIread public: void - init(void *process) + init() { - cdo_initialize(process); sinfo[0] = 0; @@ -100,15 +110,15 @@ public: auto gridsize = varList[varID].gridsize; nvalues += gridsize; - size_t nmiss; + size_t numMissVals; if (memtype == MemType::Float) { - cdo_read_record_f(streamID, farray.data(), &nmiss); + cdo_read_record_f(streamID, farray.data(), &numMissVals); dataSize += gridsize * 4; } else { - cdo_read_record(streamID, darray.data(), &nmiss); + cdo_read_record(streamID, darray.data(), &numMissVals); dataSize += gridsize * 8; } } @@ -135,16 +145,5 @@ public: void close() { - cdo_finish(); } }; -void * -CDIread(void *process) -{ - - ModuleCDIread cdiRead; - cdiRead.init(process); - cdiRead.run(); - cdiRead.close(); - return nullptr; -} diff --git a/src/CDItest.cc b/src/CDItest.cc index af10d800f2526c3c6c2f05ac9eab998d5bb1cf95..c734c2c092ffebcea3c8e22b2337ac9d7e216707 100644 --- a/src/CDItest.cc +++ b/src/CDItest.cc @@ -15,21 +15,32 @@ #include "cdo_timer.h" #include "process_int.h" -class ModuleCDItest +class CDItest : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "CDItest", + .operators = { { "ncopy"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<CDItest> registration = RegisterEntry<CDItest>(module); + int NCOPY; bool dataIsUnchanged; int max_copy; public: void - init(void *process) + init() { - cdo_initialize(process); dataIsUnchanged = false; // auto dataIsUnchanged = data_is_unchanged(); - auto NCOPY = cdo_operator_add("ncopy", 0, 0, nullptr); + NCOPY = module.get_id("ncopy"); (void) (NCOPY); // unused auto operatorID = cdo_operator_id(); @@ -108,18 +119,5 @@ public: void close() { - cdo_finish(); } }; - -void * -CDItest(void *process) -{ - ModuleCDItest cditest; - - cditest.init(process); - cditest.run(); - cditest.close(); - - return nullptr; -} diff --git a/src/CDIwrite.cc b/src/CDIwrite.cc index 70fc8e4c6551c21293d4cff90c9616c7ffc7ff15..15dac3d8549d4a70c4e1a10a3a2bfa09829b528d 100644 --- a/src/CDIwrite.cc +++ b/src/CDIwrite.cc @@ -93,7 +93,7 @@ get_parameter(void) KVList kvlist; // kvlist.name = cdo_module_name(); kvlist.name = "CDIwrite"; - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -127,8 +127,20 @@ verify_parameter(Params ¶ms) params.nsteps = std::max(params.nsteps, 1); } -class ModuleCDIwrite +class CDIwrite : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "CDIwrite", + .operators = { { "cdiwrite"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 1, NoRestriction }, + }; + inline static RegisterEntry<CDIwrite> registration = RegisterEntry<CDIwrite>(module); + MemType memtype = Options::CDO_Memtype; int filetype = -1, datatype = -1; char sinfo[64] = { 0 }; @@ -148,10 +160,8 @@ class ModuleCDIwrite public: void - init(void *process) + init() { - cdo_initialize(process); - if (Options::cdoVerbose) cdo_print("parameter: nruns/nvars/nlevs/nsteps/grid/varysteps"); params = get_parameter(); @@ -213,6 +223,7 @@ public: vlistDefNtsteps(vlistID, params.nsteps); } + void run() { @@ -296,20 +307,10 @@ public: if (params.nruns > 1) print_stat("(mean)", memtype, datatype, filetype, nvalues, dataSize, fileSize, runTimeSum / params.nruns); } + void close() { vlistDestroy(vlistID); - - cdo_finish(); } }; -void * -CDIwrite(void *process) -{ - ModuleCDIwrite cdiWrite; - cdiWrite.init(process); - cdiWrite.run(); - cdiWrite.close(); - return nullptr; -} diff --git a/src/CMOR.cc b/src/CMOR.cc index 64cc068784ec3f7aea4be12905441feb2c34e37c..2ca53f3c8466d0373efdbb02628afee88398544b 100644 --- a/src/CMOR.cc +++ b/src/CMOR.cc @@ -7,6 +7,7 @@ #include <cdi.h> #include "julian_date.h" +#include <stdlib.h> #include <signal.h> #include "process_int.h" @@ -15,7 +16,6 @@ #include "cdi_lockedIO.h" #include "cdo_options.h" #include "varray.h" -#include "dmemory.h" #ifdef HAVE_LIBCMOR #include <cassert> @@ -40,7 +40,7 @@ static void get_stringcode(int vlistID, int varID, char *varcodestring) { int varcode = vlistInqVarCode(vlistID, varID); - sprintf(varcodestring, "%03d", varcode); + std::snprintf(varcodestring, CDI_MAX_NAME, "%03d", varcode); } static int @@ -50,7 +50,7 @@ get_ifilevalue_code(int vlistID, const char *value, int nvars) if (code > 0 && code < 1000) { char newcode[4]; - sprintf(newcode, "%03d", code); + std::snprintf(newcode, sizeof(newcode), "%03d", code); for (int varID = 0; varID < nvars; ++varID) { char codestring[CDI_MAX_NAME]; @@ -95,10 +95,11 @@ removeDataset() getcwd(cwd, sizeof(cwd)); cwd[strlen(cwd)] = '\0'; int procID = getpid(); - char *dataset_path = (char *) Malloc((strlen(cwd) + strlen("/dataset.json") + floor(log10(abs(procID))) + 1 + 1) * sizeof(char)); - sprintf(dataset_path, "%s/dataset%d.json", cwd, procID); + size_t dataPathSize = strlen(cwd) + strlen("/dataset.json") + floor(log10(abs(procID))) + 1 + 1; + char *dataset_path = (char *) malloc(dataPathSize); + std::snprintf(dataset_path, dataPathSize, "%s/dataset%d.json", cwd, procID); remove(dataset_path); - Free(dataset_path); + free(dataset_path); } #endif @@ -233,7 +234,7 @@ free_array(char **tofree) free(tofree[i]); i++; } - Free(tofree); + free(tofree); } static void @@ -252,10 +253,10 @@ quote_replace(char **values, int nvalues, int i) static char ** parse_string_to_values(char *workfile, char *pline, int *nvalues, const char *keyword) { - char **values = (char **) Malloc(150 * sizeof(char *)); - while (isspace((int) *pline)) pline++; + char **values = (char **) malloc(150 * sizeof(char *)); + while (std::isspace((int) *pline)) pline++; size_t len = strlen(pline); - while (isspace((int) *(pline + (int) len))) len--; + while (std::isspace((int) *(pline + (int) len))) len--; *(pline + len) = 0; if ((int) len == 0) { handleError(workfile, 4, keyword); } *nvalues = 0; @@ -289,12 +290,12 @@ parse_string_to_values(char *workfile, char *pline, int *nvalues, const char *ke if (*(pline + i) == 0) { handleError(workfile, 6, pline); } } i++; - if (i != len && *(pline + i) != ',' && !isspace((int) *(pline + i)) && *(pline + i) != 0 && *(pline + i) != '\n') + if (i != len && *(pline + i) != ',' && !std::isspace((int) *(pline + i)) && *(pline + i) != 0 && *(pline + i) != '\n') { handleError(workfile, 11, pline); } } - else if (isspace((int) *(pline + i))) + else if (std::isspace((int) *(pline + i))) break; else if (*(pline + i) == '=') { @@ -512,7 +513,7 @@ static struct mapping * construct_var_mapping(int vlistID) { int nvars_max = vlistNvars(vlistID); - struct mapping *vars = (struct mapping *) Malloc((nvars_max + 1) * sizeof(struct mapping)); + struct mapping *vars = (struct mapping *) malloc((nvars_max + 1) * sizeof(struct mapping)); vars[0].cdi_varID = CDI_UNDEFID; vars[0].cmor_varID = CMOR_UNDEFID; vars[0].data = nullptr; @@ -523,8 +524,8 @@ construct_var_mapping(int vlistID) static void destruct_var_mapping(struct mapping vars[]) { - for (int i = 0; vars[i].cdi_varID != CDI_UNDEFID; ++i) Free(vars[i].data); - Free(vars); + for (int i = 0; vars[i].cdi_varID != CDI_UNDEFID; ++i) free(vars[i].data); + free(vars); } static struct mapping * @@ -599,7 +600,7 @@ check_for_charvars(KVList *cmorVarLine, const char * /*cn*/, char * /*miptabfreq kv_insert_vals(cmorVarLine, "code", unfilteredComma, true, true); else kv_insert_vals(cmorVarLine, "name", unfilteredComma, true, true); - Free(unfilteredComma); + free(unfilteredComma); if (Options::cdoVerbose) cdo_print("Successfully replaced identifier string with its values."); return cmorVarLine; } @@ -643,11 +644,11 @@ addcharvar(const KeyValues *charvars, int vlistID, const char *key, struct mappi if (Options::cdoVerbose) cdo_print("In merging variables to an axis:\n Spatial dimensions are already set. A fourth axis is created."); char ids[CDI_MAX_NAME]; - sprintf(ids, "%d", withnewcharaxis.inputKeys[0].varID); + std::snprintf(ids, CDI_MAX_NAME, "%d", withnewcharaxis.inputKeys[0].varID); for (int i = 1; i < charvars->nvalues; ++i) { char tempint[sizeof(int)]; - sprintf(tempint, "%d", withnewcharaxis.inputKeys[i].varID); + std::snprintf(tempint, sizeof(tempint), "%d", withnewcharaxis.inputKeys[i].varID); strcat(ids, ","); strcat(ids, tempint); } @@ -661,7 +662,7 @@ addcharvar(const KeyValues *charvars, int vlistID, const char *key, struct mappi "piped operators so the input file is not clear.", cdo_get_stream_name(0)); - const auto streamID2 = streamOpenRead(cdo_get_stream_name(0)); + auto streamID2 = streamOpenRead(cdo_get_stream_name(0)); if (ntsteps == -1) { ntsteps = 0; @@ -679,7 +680,7 @@ addcharvar(const KeyValues *charvars, int vlistID, const char *key, struct mappi withnewcharaxis.read_cmor_charvar(axissize, streamID2, oldgridsize); - var->data = Malloc(ntsteps * axissize[0] * axissize[1] * axissize[2] * sizeof(double)); + var->data = malloc(ntsteps * axissize[0] * axissize[1] * axissize[2] * sizeof(double)); for (int i = 0; i < ntsteps * axissize[0] * axissize[1] * axissize[2]; i++) { if (withnewcharaxis.output.datatype == 'd') @@ -887,9 +888,9 @@ static char * trim(char *s) { if (s == nullptr) return s; - while (*s != '\0' && (isspace(*s) || *s == '"')) s++; + while (*s != '\0' && (std::isspace(*s) || *s == '"')) s++; int n = strlen(s); - while (n > 0 && (isspace(s[n - 1]) || s[n - 1] == '"')) n--; + while (n > 0 && (std::isspace(s[n - 1]) || s[n - 1] == '"')) n--; s[n] = '\0'; return s; } @@ -932,7 +933,7 @@ parse_kv_file(KVList *kvl, const char *filename) const KeyValues *kvfromlist = kvl->search(kv.key.c_str()); if (kvfromlist) continue; - char **values = (char **) Malloc((kv.nvalues + 1) * sizeof(char *)); + char **values = (char **) malloc((kv.nvalues + 1) * sizeof(char *)); int k = 0; for (k = 0; k < kv.nvalues; k++) values[k] = strdup(kv.values[k].c_str()); @@ -969,7 +970,7 @@ check_compare_set(char **finalset, char *attribute, const char *attname, const c "specification '%s'.", attname, *finalset, attribute); cdo_print("Attribute '%s' = '%s'", attname, attribute); - Free(*finalset); + free(*finalset); *finalset = strdup(attribute); } } @@ -978,19 +979,19 @@ check_compare_set(char **finalset, char *attribute, const char *attname, const c static char * get_infile_attvalue(int vlistID, int varID, char *name, int type, int len) { - char *infile_attvalue = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); + char *infile_attvalue = (char *) malloc(CMOR_MAX_STRING); if (type == CDI_DATATYPE_INT32) { - int *values = (int *) Malloc(len * sizeof(int)); + int *values = (int *) malloc(len * sizeof(int)); cdiInqAttInt(vlistID, varID, name, len, &values[0]); - sprintf(infile_attvalue, "%i", values[0]); + std::snprintf(infile_attvalue, CMOR_MAX_STRING, "%i", values[0]); for (int l = 1; l < len; ++l) { char tempint[sizeof(values[l])]; - sprintf(tempint, "%i", values[l]); + std::snprintf(tempint, sizeof(values[l]), "%i", values[l]); strcat(infile_attvalue, tempint); } - Free(values); + free(values); } else if (type == CDI_DATATYPE_FLT32 || type == CDI_DATATYPE_FLT64) { @@ -1004,15 +1005,20 @@ get_infile_attvalue(int vlistID, int varID, char *name, int type, int len) char tempflt[64]; if (type == CDI_DATATYPE_FLT32) { - sprintf(tempflt, "%sf", double_to_att_str(Options::CDO_flt_digits, fltstr, sizeof(fltstr), attflt[i])); + std::snprintf(tempflt, sizeof(tempflt), "%sf", + double_to_att_str(Options::CDO_flt_digits, fltstr, sizeof(fltstr), attflt[i])); + } + else + { + std::snprintf(tempflt, sizeof(tempflt), "%s", + double_to_att_str(Options::CDO_dbl_digits, fltstr, sizeof(fltstr), attflt[i])); } - else { sprintf(tempflt, "%s", double_to_att_str(Options::CDO_dbl_digits, fltstr, sizeof(fltstr), attflt[i])); } if (i) strcat(infile_attvalue, tempflt); else - sprintf(infile_attvalue, "%s", tempflt); + std::snprintf(infile_attvalue, CMOR_MAX_STRING, "%s", tempflt); } - infile_attvalue[CMOR_MAX_STRING] = '\0'; + infile_attvalue[CMOR_MAX_STRING - 1] = '\0'; cdo_print("%s", infile_attvalue); } else @@ -1026,7 +1032,7 @@ get_infile_attvalue(int vlistID, int varID, char *name, int type, int len) static char * get_infile_attname(int vlistID, int varID, int natt, int *type, int *len) { - char *infile_attname = (char *) Malloc(CDI_MAX_NAME * sizeof(char)); + char *infile_attname = (char *) malloc(CDI_MAX_NAME); cdiInqAtt(vlistID, varID, natt, infile_attname, type, len); return infile_attname; } @@ -1042,7 +1048,7 @@ get_txtatt(int vlistID, int varID, const char *key) int type, len; char *infile_attname = get_infile_attname(vlistID, varID, i, &type, &len); if (strcmp(infile_attname, key) == 0) { returnvalue = get_infile_attvalue(vlistID, varID, infile_attname, type, len); } - Free(infile_attname); + free(infile_attname); } return returnvalue; } @@ -1072,7 +1078,7 @@ get_all_atts(KVList *kvl, int vlistID, const char **infileAttSpecLong, const cha { kv_insert_vals(kvl, infile_attname, get_infile_attvalue(vlistID, CDI_GLOBAL, infile_attname, type, len), false, false); } - Free(infile_attname); + free(infile_attname); } kv_insert_vals(kvl, "institution", (char *) institutInqLongnamePtr(vlistInqInstitut(vlistID)), false, false); @@ -1095,7 +1101,7 @@ add_globalhybrids(KVList *kvl, int vlistID) { char *att = get_txtatt(vlistID, CDI_GLOBAL, infileAttSpecLong[i]); if (att) kv_insert_vals(kvl, infileAttSpecShort[i], att, false, false); - if (att) Free(att); + if (att) free(att); i++; } @@ -1106,7 +1112,7 @@ add_globalhybrids(KVList *kvl, int vlistID) char *att = get_txtatt(vlistID, CDI_GLOBAL, infileAtt[i]); if (att) kv_insert_vals(kvl, infileAtt[i], att, false, false); i++; - if (att) Free(att); + if (att) free(att); } } const char *longAtt[] = { "required_time_units", @@ -1161,9 +1167,9 @@ check_attarray(KVList *kvl, const char **reqAtt, int vlistID) if (Options::cdoVerbose) cdo_print("Attribute (from infile) '%s' is '%s'. ", reqAtt[i], infileatt); const char *infileatts[] = { infileatt }; kvl->append(reqAtt[i], infileatts, 1); - Free(infileatt); + free(infileatt); } - else if (infileatt) { Free(infileatt); } + else if (infileatt) { free(infileatt); } return i; } else @@ -1184,11 +1190,11 @@ attErr(const char **reqAtt, int errnum) char errStr[CMOR_MAX_STRING]; int i = 1; - sprintf(errStr, - "ERROR! Attribute '%s' is required. Either it is missing, 'notSet', or the value is invalid.\n " - " Make sure that you have configured all following attributes:\n " - " %s", - reqAtt[errnum], reqAtt[0]); + std::snprintf(errStr, sizeof(errStr), + "ERROR! Attribute '%s' is required. Either it is missing, 'notSet', or the value is invalid.\n " + " Make sure that you have configured all following attributes:\n " + " %s", + reqAtt[errnum], reqAtt[0]); while (reqAtt[i]) { strcat(errStr, ", "); @@ -1228,12 +1234,12 @@ check_attr(KVList *kvl, char *project_id, int vlistID) if (!kv || kv->nvalues == 0 || kv->values[0] == "notSet") { const KeyValues *kv_model_id = kvl->search("model_id"); - char *references = (char *) Malloc(strlen(kv_model_id->values[0].c_str()) + 28); + char *references = (char *) malloc(strlen(kv_model_id->values[0].c_str()) + 28); std::strcpy(references, "No references available for "); strcat(references, kv_model_id->values[0].c_str()); cdo_print("Attribute 'references' is set to '%s' ", references); kv_insert_vals(kvl, "references", references, false, false); - Free(references); + free(references); } #endif /* Special check for CMIP or CORDEX projects */ @@ -1404,7 +1410,7 @@ check_mem(KVList *kvl, char *project_id) } } char member[CMOR_MAX_STRING]; - sprintf(member, "r%ldi%ldp%ld", indexvalues[0], indexvalues[1], indexvalues[2]); + std::snprintf(member, sizeof(member), "r%ldi%ldp%ld", indexvalues[0], indexvalues[1], indexvalues[2]); kv_insert_vals(kvl, "member", member, true, false); kv_insert_vals(kvl, "variant_label", member, true, false); indexint = 0; @@ -1487,7 +1493,7 @@ check_mem(KVList *kvl, char *project_id) } } char member[CMOR_MAX_STRING]; - sprintf(member, "r%ldi%ldp%ldf%ld", indexvalues[0], indexvalues[1], indexvalues[2], indexvalues[3]); + std::snprintf(member, sizeof(member), "r%ldi%ldp%ldf%ld", indexvalues[0], indexvalues[1], indexvalues[2], indexvalues[3]); kv_insert_vals(kvl, "member", member, true, false); kv_insert_vals(kvl, "variant_label", member, true, false); } @@ -1516,14 +1522,15 @@ read_config_files(KVList *kvl) getcwd(cwd, sizeof(cwd)); cwd[strlen(cwd)] = '\0'; const char *dotconfig = ".cdocmorinfo"; - char *workfile = (char *) Malloc((strlen(cwd) + strlen(dotconfig) + 2) * sizeof(char)); - sprintf(workfile, "%s/%s", cwd, dotconfig); + size_t workfileSize = (strlen(cwd) + strlen(dotconfig) + 2); + char *workfile = (char *) malloc(workfileSize); + std::snprintf(workfile, workfileSize, "%s/%s", cwd, dotconfig); if (Options::cdoVerbose) cdo_print("1.2. Try to parse default file: '%s'.", workfile); if (parse_kv_file(kvl, workfile) == 0 && Options::cdoVerbose) cdo_warning("Default file for keyword 'info': '%s' does not exist.", workfile); else if (Options::cdoVerbose) cdo_print("1.2. Successfully parsed default file: '%s'.", workfile); - Free(workfile); + free(workfile); if (i == 0) { @@ -1554,6 +1561,7 @@ in_list(const std::vector<std::string> &list, const char *needle, int num) static int get_netcdf_file_action(KVList *kvl, char *proj) { + (void) proj; char *chunk = kv_get_a_val(kvl, "om", "a"); if (chunk[0] == 'r') { @@ -1615,7 +1623,7 @@ get_cmor_exit_control(KVList *kvl) static char * get_calendar_ptr(int calendar) { - char *calendar_ptr = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); + char *calendar_ptr = (char *) malloc(CMOR_MAX_STRING); switch (calendar) { case CALENDAR_STANDARD: std::strcpy(calendar_ptr, "standard"); break; @@ -1624,7 +1632,7 @@ get_calendar_ptr(int calendar) case CALENDAR_360DAYS: std::strcpy(calendar_ptr, "360_day"); break; case CALENDAR_365DAYS: std::strcpy(calendar_ptr, "noleap"); break; case CALENDAR_366DAYS: std::strcpy(calendar_ptr, "all_leap"); break; - default: Free(calendar_ptr); return nullptr; + default: free(calendar_ptr); return nullptr; } return calendar_ptr; } @@ -1660,16 +1668,17 @@ get_calendar_int(char *calendar) static char * get_time_units(int taxisID) { - char *units = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); + char *units = (char *) malloc(CMOR_MAX_STRING); int timeunit = taxisInqTunit(taxisID); int year, month, day, hour, minute, second, ms; - const auto rDateTime = taxisInqRdatetime(taxisID); + auto rDateTime = taxisInqRdatetime(taxisID); cdiDate_decode(rDateTime.date, &year, &month, &day); cdiTime_decode(rDateTime.time, &hour, &minute, &second, &ms); if (timeunit == TUNIT_QUARTER || timeunit == TUNIT_30MINUTES) timeunit = TUNIT_MINUTE; if (timeunit == TUNIT_3HOURS || timeunit == TUNIT_6HOURS || timeunit == TUNIT_12HOURS) timeunit = TUNIT_HOUR; - sprintf(units, "%s since %d-%d-%d %02d:%02d:%02d", tunitNamePtr(timeunit), year, month, day, hour, minute, second); + std::snprintf(units, CMOR_MAX_STRING, "%s since %d-%d-%d %02d:%02d:%02d", tunitNamePtr(timeunit), year, month, day, hour, minute, + second); return units; } @@ -1792,7 +1801,7 @@ get_time_method(KVList *kvl, int vlistID, int varID, char *cmor_time_name, char time_method, varID); std::strcpy(cmor_time_name, "time \0"); } - Free(time_method); + free(time_method); } if (Options::cdoVerbose) cdo_print("Successfully determined time_axis = '%d'.", *time_axis); } @@ -1819,7 +1828,7 @@ get_branch_times(KVList *kvl, int calendar, char *time_units, char *project_id) char *btip = kv_get_a_val(kvl, "branch_time_in_parent", nullptr); char *btic = kv_get_a_val(kvl, "branch_time_in_child", nullptr); char *ptu = kv_get_a_val(kvl, "parent_time_units", nullptr); - double *branch_time = (double *) Malloc(2 * sizeof(double)); + double *branch_time = (double *) malloc(2 * sizeof(double)); branch_time[0] = 0.0; branch_time[1] = 0.0; @@ -1844,14 +1853,14 @@ get_branch_times(KVList *kvl, int calendar, char *time_units, char *project_id) } int parenttimeunit; - const auto parentsDateTime = get_taxis(ptu, &parenttimeunit); - const auto parentstartdate = julianDate_encode(calendar, parentsDateTime); - const auto parentbranchdate = julianDate_encode(calendar, branchDateTimes[0]); + auto parentsDateTime = get_taxis(ptu, &parenttimeunit); + auto parentstartdate = julianDate_encode(calendar, parentsDateTime); + auto parentbranchdate = julianDate_encode(calendar, branchDateTimes[0]); int childtimeunit; - const auto childsDateTime = get_taxis(time_units, &childtimeunit); - const auto childstartdate = julianDate_encode(calendar, childsDateTime); - const auto childbranchdate = julianDate_encode(calendar, branchDateTimes[1]); + auto childsDateTime = get_taxis(time_units, &childtimeunit); + auto childstartdate = julianDate_encode(calendar, childsDateTime); + auto childbranchdate = julianDate_encode(calendar, branchDateTimes[1]); /* If time unit is always "days since.." */ branch_time[0] = julianDate_to_seconds(julianDate_sub(parentbranchdate, parentstartdate)) / 86400; @@ -1942,8 +1951,9 @@ static const char * copyCV(char *directory) { const char *cvwithout = "CMIP6_CV_without_prefix.json"; - char *cvname = (char *) Malloc((strlen(directory) + strlen(cvwithout) + 2) * sizeof(char)); - sprintf(cvname, "%s/%s", directory, cvwithout); + size_t len = strlen(directory) + strlen(cvwithout) + 2; + char *cvname = (char *) malloc(len); + std::snprintf(cvname, len, "%s/%s", directory, cvwithout); if (Options::cdoVerbose) cdo_print("Check whether a CV without tracking prefix check exists."); if (file_exist((const char *) cvname, false, "CV", false)) return cvwithout; @@ -1952,7 +1962,8 @@ copyCV(char *directory) if (Options::cdoVerbose) cdo_print("Try to create a CV without tracking prefix check with program 'sed'."); char command[CDI_MAX_NAME]; - sprintf(command, "sed 's/\"hdl:21.14100\\/\\.\\*\"/\"\\^\\.*\"/' %s/CMIP6_CV.json >%s", directory, cvname); + std::snprintf(command, sizeof(command), "sed 's/\"hdl:21.14100\\/\\.\\*\"/\"\\^\\.*\"/' %s/CMIP6_CV.json >%s", directory, + cvname); int dir_err = system(command); if (dir_err != 0) { @@ -1961,7 +1972,7 @@ copyCV(char *directory) "This can be due to missing 'sed' program or missing write permissions. " "Continue with tracking prefix. " "Consider that the output tracking id needs to be registered as a PID."); - sprintf(cvname, "CMIP6_CV.json"); + std::snprintf(cvname, len, "CMIP6_CV.json"); return cvname; } if (Options::cdoVerbose) cdo_print("Successfully created a CV without tracking prefix check."); @@ -2007,15 +2018,15 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id char cordexDir[CDI_MAX_NAME]; char cordexFileTem[CDI_MAX_NAME]; - sprintf(cordexDir, "%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s", kv_get_a_val(kvl, "dr", "./"), project_id, - kv_get_a_val(kvl, "product", nullptr), kv_get_a_val(kvl, "CORDEX_domain", nullptr), - kv_get_a_val(kvl, "institute_id", nullptr), kv_get_a_val(kvl, "driving_model_id", nullptr), - kv_get_a_val(kvl, "experiment_id", nullptr), kv_get_a_val(kvl, "member", nullptr), - kv_get_a_val(kvl, "model_id", nullptr), kv_get_a_val(kvl, "rcm_version_id", nullptr), freq); - sprintf(cordexFileTem, "%s_%s_%s_%s_%s_%s_%s", kv_get_a_val(kvl, "CORDEX_domain", nullptr), - kv_get_a_val(kvl, "driving_model_id", nullptr), kv_get_a_val(kvl, "experiment_id", nullptr), - kv_get_a_val(kvl, "member", nullptr), kv_get_a_val(kvl, "model_id", nullptr), - kv_get_a_val(kvl, "rcm_version_id", nullptr), freq); + std::snprintf(cordexDir, CDI_MAX_NAME, "%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s", kv_get_a_val(kvl, "dr", "./"), project_id, + kv_get_a_val(kvl, "product", nullptr), kv_get_a_val(kvl, "CORDEX_domain", nullptr), + kv_get_a_val(kvl, "institute_id", nullptr), kv_get_a_val(kvl, "driving_model_id", nullptr), + kv_get_a_val(kvl, "experiment_id", nullptr), kv_get_a_val(kvl, "member", nullptr), + kv_get_a_val(kvl, "model_id", nullptr), kv_get_a_val(kvl, "rcm_version_id", nullptr), freq); + std::snprintf(cordexFileTem, CDI_MAX_NAME, "%s_%s_%s_%s_%s_%s_%s", kv_get_a_val(kvl, "CORDEX_domain", nullptr), + kv_get_a_val(kvl, "driving_model_id", nullptr), kv_get_a_val(kvl, "experiment_id", nullptr), + kv_get_a_val(kvl, "member", nullptr), kv_get_a_val(kvl, "model_id", nullptr), + kv_get_a_val(kvl, "rcm_version_id", nullptr), freq); kv_insert_vals(kvl, "dr", (char *) "./", true, false); kv_insert_vals(kvl, "cordexDir", cordexDir, true, false); @@ -2109,9 +2120,10 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id if (strcmp(kv_get_a_val(kvl, "kaa", "n"), "y") == 0) { char notincluded[2048]; - std::strcpy(notincluded, - "The following attributes are not included in the global attributes list.\n Reasons can be: 1. Attribute is " - "an internal keyword 2. No valaue is available 3. CMOR creates the attribute itself:\n "); + std::strcpy( + notincluded, + "The following attributes are not included in the global attributes list.\n Reasons can be: 1. Attribute is " + "an internal keyword 2. No valaue is available 3. CMOR creates the attribute itself:\n "); size_t inilen = strlen(notincluded); size_t strlens = inilen; for (auto &kv : *kvl) @@ -2149,15 +2161,15 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id char *filename = kv_get_a_val(kvl, "dj", nullptr); */ size_t cwdsize = 1024; - char *cwd = (char *) Malloc((cwdsize + 1) * sizeof(char)); + char *cwd = (char *) malloc(cwdsize + 1); getcwd(cwd, cwdsize); cwd[strlen(cwd)] = '\0'; int procID = getpid(); FILE *dataset_json; - char *dataset_path - = (char *) Malloc((strlen(cwd) + strlen("/dataset.json") + floor(log10(abs(procID))) + 1 + 1) * sizeof(char)); + size_t len = strlen(cwd) + strlen("/dataset.json") + floor(log10(abs(procID))) + 1 + 1; + char *dataset_path = (char *) malloc(len); - sprintf(dataset_path, "%s/dataset%d.json", cwd, procID); + std::snprintf(dataset_path, len, "%s/dataset%d.json", cwd, procID); dataset_json = std::fopen(dataset_path, "w+"); if (!dataset_json) cdo_abort("ERROR (infile: '%s')! In preparing cmor_dataset:\n Could not open a dataset file '%s' for cmor_dataset.", @@ -2173,7 +2185,7 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id { int linelen = strlen(kv.key.c_str()) + strlen(kv.values[0].c_str()) + 10; std::vector<char> line(linelen); - sprintf(line.data(), "\"%s\" : \"%s\",\n", kv.key.c_str(), kv.values[0].c_str()); + std::snprintf(line.data(), linelen, "\"%s\" : \"%s\",\n", kv.key.c_str(), kv.values[0].c_str()); fputs((const char *) line.data(), dataset_json); } } @@ -2204,7 +2216,7 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id { int linelen = strlen(allneeded[i]) + strlen(tmp) + 10; std::vector<char> line(linelen); - sprintf(line.data(), "\"%s\" : \"%s\",\n", allneeded[i], tmp); + std::snprintf(line.data(), linelen, "\"%s\" : \"%s\",\n", allneeded[i], tmp); fputs((const char *) line.data(), dataset_json); } i++; @@ -2213,8 +2225,8 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id char branch_time_in_parent[CMOR_MAX_STRING]; char branch_time_in_child[CMOR_MAX_STRING]; - sprintf(branch_time_in_parent, "%.12f", branch_times[0]); - sprintf(branch_time_in_child, "%.12f", branch_times[1]); + std::snprintf(branch_time_in_parent, CMOR_MAX_STRING, "%.12f", branch_times[0]); + std::snprintf(branch_time_in_child, CMOR_MAX_STRING, "%.12f", branch_times[1]); /* CMOR internal */ fputs("\"outpath\" : \"", dataset_json); @@ -2306,9 +2318,9 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id cmf = cmor_dataset_json(dataset_path); if (cmf != 0) cdo_abort("ERROR (infile: '%s')! Function cmor_dataset_json failed!", cdo_get_stream_name(0)); - Free(dataset_path); + free(dataset_path); removeDataset(); - /* Free(freq); */ + /* free(freq); */ } #else @@ -2319,8 +2331,8 @@ setup_dataset(KVList *kvl, CdoStreamID streamID, int *calendar, char *project_id "CMOR_VERSION_MINOR are not available.", cdo_get_stream_name(0)); #endif - Free(calendarptr); - Free(branch_times); + free(calendarptr); + free(branch_times); if (Options::cdoVerbose) cdo_print("6. Successfully finished cmor_setup and cmor_dataset."); } @@ -2342,10 +2354,10 @@ get_zcell_bounds(int zaxisID, double *zcell_bounds, double *levels, int zsize) { bool selfGenerated = false; double *lbounds; - lbounds = (double *) Malloc(zsize * sizeof(double)); + lbounds = (double *) malloc(zsize * sizeof(double)); zaxisInqLbounds(zaxisID, lbounds); double *ubounds; - ubounds = (double *) Malloc(zsize * sizeof(double)); + ubounds = (double *) malloc(zsize * sizeof(double)); zaxisInqUbounds(zaxisID, ubounds); if (!lbounds || !ubounds || std::pow((ubounds[1] - ubounds[0]), 2) < 0.001 || std::pow((lbounds[1] - lbounds[0]), 2) < 0.001) { @@ -2369,8 +2381,8 @@ get_zcell_bounds(int zaxisID, double *zcell_bounds, double *levels, int zsize) zcell_bounds[2 * zsize - 1] = levels[zsize - 1] + (levels[zsize - 1] - zcell_bounds[2 * zsize - 2]); selfGenerated = false; } - Free(lbounds); - Free(ubounds); + free(lbounds); + free(ubounds); return selfGenerated; } @@ -2384,7 +2396,7 @@ get_zhybrid_half(int zaxisID, double *p0, double *alev_val, double *b_val, doubl " to calculate the formula of a hybrid sigma pressure axis:" "\n p = ap + b *ps", cdo_get_stream_name(0)); - double *vct = (double *) Malloc(vctsize * sizeof(double)); + double *vct = (double *) malloc(vctsize * sizeof(double)); zaxisInqVct(zaxisID, vct); for (int i = 0; i < zsize; ++i) { @@ -2392,7 +2404,7 @@ get_zhybrid_half(int zaxisID, double *p0, double *alev_val, double *b_val, doubl b_val[i] = vct[zsize + i]; } for (int i = 0; i < zsize; ++i) { alev_val[i] = ap_val[i] / p0[0] + b_val[i]; } - Free(vct); + free(vct); } static void @@ -2406,7 +2418,7 @@ get_zhybrid(int zaxisID, double *p0, double *alev_val, double *alev_bnds, double " to calculate the formula of a hybrid sigma pressure axis or a hybrid height axis:" "\n p = ap + b * ps||orog", cdo_get_stream_name(0)); - double *vct = (double *) Malloc(vctsize * sizeof(double)); + double *vct = (double *) malloc(vctsize * sizeof(double)); zaxisInqVct(zaxisID, vct); for (int i = 0; i < (zsize + 1); ++i) { @@ -2421,7 +2433,7 @@ get_zhybrid(int zaxisID, double *p0, double *alev_val, double *alev_bnds, double alev_bnds[i] = ap_bnds[i] / p0[0] + b_bnds[i]; } alev_bnds[zsize] = ap_bnds[zsize] / p0[0] + b_bnds[zsize]; - Free(vct); + free(vct); } static size_t @@ -2438,28 +2450,28 @@ get_charvals_and_bnds(KVList *kvl, char *chardim, std::vector<std::string> &fval int *nofvals, int *nofbnds, char *cmor_name) { bool fivedim = true; - char *charvalstring = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); - sprintf(charvalstring, "char_axis_%s_%s", chardim, cmor_name); + char charvalstring[CMOR_MAX_STRING]; + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s_%s", chardim, cmor_name); fvalss = kv_get_vals(kvl, charvalstring, nofvals); if (!fvalss.size()) { - if (Options::cdoVerbose) cdo_print("Start to register char_axis_%s", chardim); - sprintf(charvalstring, "char_axis_%s", chardim); - fvalss = kv_get_vals(kvl, charvalstring, nofvals); - fivedim = false; + if (Options::cdoVerbose) cdo_print("Start to register char_axis_%s", chardim); + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s", chardim); + fvalss = kv_get_vals(kvl, charvalstring, nofvals); + fivedim = false; } else { - if (Options::cdoVerbose) cdo_print("Start to register char_axis_%s_%s", chardim, cmor_name); + if (Options::cdoVerbose) cdo_print("Start to register char_axis_%s_%s", chardim, cmor_name); } if (!fvalss.size()) cdo_warning("You specify variables to merge to an axis and the axis name but its values are missing!" "\n Specify its values via attribute 'char_axis_$name' in infofile."); if (fivedim) - sprintf(charvalstring, "char_axis_%s_%s_bounds", chardim, cmor_name); + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s_%s_bounds", chardim, cmor_name); else - sprintf(charvalstring, "char_axis_%s_bounds", chardim); + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s_bounds", chardim); fbndss = kv_get_vals(kvl, charvalstring, nofbnds); if (!fbndss.size()) if (Options::cdoVerbose) @@ -2468,17 +2480,15 @@ get_charvals_and_bnds(KVList *kvl, char *chardim, std::vector<std::string> &fval "\n Specify its bounds via attribute 'char_axis_$name_bounds' in infofile."); if (fivedim) - sprintf(charvalstring, "char_axis_%s_%s_units", chardim, cmor_name); + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s_%s_units", chardim, cmor_name); else - sprintf(charvalstring, "char_axis_%s_units", chardim); + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s_units", chardim); *funits = kv_get_a_val(kvl, charvalstring, ""); if (!*funits) if (Options::cdoVerbose) cdo_print("You specified variables to merge to an axis, the axis name and its values." "\n Note that units are required if the axis has digital values." "\n Specify its units via attribute 'char_axis_$name_units' in infofile."); - - Free(charvalstring); } static void @@ -2486,23 +2496,24 @@ register_char_axis(int numchar, const std::vector<std::string> &charvals, int *a { if (Options::cdoVerbose) cdo_print("Start to register a character axis."); size_t maxlen = get_strmaxlen(charvals, numchar); - void *charcmor = (void *) Malloc((numchar * maxlen + 1) * sizeof(char)); - sprintf((char *) charcmor, "%.*s", (int) strlen(charvals[0].c_str()), charvals[0].c_str()); + size_t len = numchar * maxlen + 1; + void *charcmor = (void *) malloc(len); + std::snprintf((char *) charcmor, len, "%.*s", (int) strlen(charvals[0].c_str()), charvals[0].c_str()); std::vector<char> blanks(maxlen); for (size_t i = 0; i < maxlen; ++i) blanks[i] = ' '; char tempb[CMOR_MAX_STRING]; - sprintf(tempb, "%.*s", (int) (maxlen - strlen(charvals[0].c_str())), blanks.data()); + std::snprintf(tempb, CMOR_MAX_STRING, "%.*s", (int) (maxlen - strlen(charvals[0].c_str())), blanks.data()); strcat((char *) charcmor, tempb); for (int i = 1; i < numchar; ++i) { strcat((char *) charcmor, charvals[i].c_str()); char tempblanks[CMOR_MAX_STRING]; - sprintf(tempblanks, "%.*s", (int) (maxlen - strlen(charvals[i].c_str())), blanks.data()); + std::snprintf(tempblanks, CMOR_MAX_STRING, "%.*s", (int) (maxlen - strlen(charvals[i].c_str())), blanks.data()); strcat((char *) charcmor, tempblanks); } int cmf = cmor_axis(new_axis_id(axis_ids), chardim, (char *) "", numchar, (void *) charcmor, 'c', NULL, maxlen, NULL); if (cmf != 0) cdo_abort("ERROR (infile: '%s')! Function cmor_axis failed!", cdo_get_stream_name(0)); - Free(charcmor); + free(charcmor); if (Options::cdoVerbose) cdo_print("Successfully registered a character axis."); } @@ -2510,6 +2521,8 @@ static void register_fourth_axis(KVList *kvl, int vlistID, int varID, char *varname, int *axis_ids, char *project_id, int miptab_freq, int *mergeIDs) { + (void) project_id; + (void) miptab_freq; char *fa = get_txtatt(vlistID, varID, "merge_axis"); char *chardimatt = kv_get_a_val(kvl, "ca", NULL); char *chardim = get_txtatt(vlistID, varID, "character_axis"); @@ -2546,7 +2559,7 @@ register_fourth_axis(KVList *kvl, int vlistID, int varID, char *varname, int *ax "values for this axis: '%d'.", cdo_get_stream_name(0), nvalues, chardim, nofvals); free_array(idss); - Free(fa); + free(fa); } else if (nofvals == zaxisInqSize(vlistInqVarZaxis(vlistID, varID))) { @@ -2567,7 +2580,7 @@ register_fourth_axis(KVList *kvl, int vlistID, int varID, char *varname, int *ax int i = 0; if (fbndss.size()) { - fbnds = (double *) Malloc(nofbnds * sizeof(double)); + fbnds = (double *) malloc(nofbnds * sizeof(double)); for (i = 0; i < nofbnds; ++i) { int scanreturn = std::sscanf(fbndss[i].c_str(), "%lf", &fbnds[i]); @@ -2585,7 +2598,7 @@ register_fourth_axis(KVList *kvl, int vlistID, int varID, char *varname, int *ax i = 0; if (nofvals > 0) { - fvals = (double *) Malloc(nofvals * sizeof(double)); + fvals = (double *) malloc(nofvals * sizeof(double)); for (i = 0; i < nofvals; ++i) { int scanreturn = std::sscanf(fvalss[i].c_str(), "%lf", &fvals[i]); @@ -2611,9 +2624,9 @@ register_fourth_axis(KVList *kvl, int vlistID, int varID, char *varname, int *ax chardim); } else { register_char_axis(nofvals, fvalss, axis_ids, chardim); } - if (fvals) Free(fvals); - if (fbnds) Free(fbnds); - Free(chardim); + if (fvals) free(fvals); + if (fbnds) free(fbnds); + free(chardim); } } else if (Options::cdoVerbose) @@ -2643,12 +2656,12 @@ registerPsid(struct mapping vars[], int psindex, int vlistID) if (vlistInqVarDatatype(vlistID, psindex) == CDI_DATATYPE_FLT64) { var->datatype = 'd'; - var->data = Malloc(gridsize * sizeof(double)); + var->data = malloc(gridsize * sizeof(double)); } else { var->datatype = 'f'; - var->data = Malloc(gridsize * sizeof(float)); + var->data = malloc(gridsize * sizeof(float)); } int psID = getRegisteredPsid(vars, psindex); if (Options::cdoVerbose) cdo_print("9. Successfully registered surface pressure '%d'.", psID); @@ -2681,12 +2694,12 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, if (zsize > 1) { - levels = (double *) Malloc(zsize * sizeof(double)); + levels = (double *) malloc(zsize * sizeof(double)); zaxisInqLevels(zaxisID, levels); double *zcell_bounds; - zcell_bounds = (double *) Malloc(2 * zsize * sizeof(double)); + zcell_bounds = (double *) malloc(2 * zsize * sizeof(double)); bool selfGenerated = get_zcell_bounds(zaxisID, zcell_bounds, levels, zsize); - char *zaxisname = (char *) Malloc(CDI_MAX_NAME * sizeof(char)); + char zaxisname[CDI_MAX_NAME]; length = CDI_MAX_NAME; cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, zaxisname, &length); if (zaxisInqType(zaxisID) == ZAXIS_PRESSURE) @@ -2761,24 +2774,24 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, int vctsize = zaxisInqVctSize(zaxisID); if (2 * zsize == vctsize) zaxistype = ZAXIS_HYBRID_HALF; double *alev_val, *alev_bnds = nullptr, *ap_val, *ap_bnds = nullptr, *b_val, *b_bnds = nullptr; - double *p0 = (double *) Malloc(sizeof(double)); + double *p0 = (double *) malloc(sizeof(double)); p0[0] = 101325.0; if (strcmp(zaxis, "hybrid_height") == 0) p0[0] = 1; if (zaxistype == ZAXIS_HYBRID) { - alev_val = (double *) Malloc(zsize * sizeof(double)); - alev_bnds = (double *) Malloc((zsize + 1) * sizeof(double)); - ap_val = (double *) Malloc(zsize * sizeof(double)); - ap_bnds = (double *) Malloc((zsize + 1) * sizeof(double)); - b_val = (double *) Malloc(zsize * sizeof(double)); - b_bnds = (double *) Malloc((zsize + 1) * sizeof(double)); + alev_val = (double *) malloc(zsize * sizeof(double)); + alev_bnds = (double *) malloc((zsize + 1) * sizeof(double)); + ap_val = (double *) malloc(zsize * sizeof(double)); + ap_bnds = (double *) malloc((zsize + 1) * sizeof(double)); + b_val = (double *) malloc(zsize * sizeof(double)); + b_bnds = (double *) malloc((zsize + 1) * sizeof(double)); } else { - alev_val = (double *) Malloc(zsize * sizeof(double)); - ap_val = (double *) Malloc(zsize * sizeof(double)); - b_val = (double *) Malloc(zsize * sizeof(double)); + alev_val = (double *) malloc(zsize * sizeof(double)); + ap_val = (double *) malloc(zsize * sizeof(double)); + b_val = (double *) malloc(zsize * sizeof(double)); } char *mtproof = kv_get_a_val(kvl, "mtproof", nullptr); @@ -2829,7 +2842,7 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, int tsID = 0; - const auto streamID2 = streamOpenRead(cdo_get_stream_name(0)); + auto streamID2 = streamOpenRead(cdo_get_stream_name(0)); int vlistID2 = streamInqVlist(streamID2); psindex = getVarIDToMap(vlistID2, vlistNvars(vlistID2), "name", "orog"); if (vlistInqVarDatatype(vlistID2, psindex) == CDI_DATATYPE_FLT64) orogtype = 'd'; @@ -2839,9 +2852,9 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, Varray<double> buffer(gridsize); if (vlistInqVarDatatype(vlistID2, psindex) == CDI_DATATYPE_FLT64) - orogdata = Malloc(gridsize * sizeof(double)); + orogdata = malloc(gridsize * sizeof(double)); else - orogdata = Malloc(gridsize * sizeof(float)); + orogdata = malloc(gridsize * sizeof(float)); while (true) { @@ -2851,12 +2864,12 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, while (nrecs--) { int varIDrw, levelIDrw; - size_t nmiss; + size_t numMissVals; streamInqRecord(streamID2, &varIDrw, &levelIDrw); if (varIDrw == psindex) { cdo_print("read the record"); - streamReadRecord(streamID2, buffer.data(), &nmiss); + streamReadRecord(streamID2, buffer.data(), &numMissVals); for (size_t i = 0; i < gridsize; ++i) { if (vlistInqVarDatatype(vlistID2, psindex) == CDI_DATATYPE_FLT64) @@ -2888,7 +2901,7 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, int lev_id = axis_ids[count_axis_ids(axis_ids) - 1]; int lev_id_array[2]; lev_id_array[0] = lev_id; - int hharray[count_axis_ids(axis_ids) - 2]; + std::vector<int> hharray(count_axis_ids(axis_ids) - 2); for (int i = 0; i < count_axis_ids(axis_ids) - 2; i++) hharray[i] = axis_ids[i + 1]; if (zaxistype == ZAXIS_HYBRID) @@ -2908,7 +2921,7 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, (void *) b_bnds); if (strcmp(zaxis, "hybrid_height") == 0) { - cmf = cmor_zfactor(zfactor_id, lev_id, (char *) "orog", (char *) "m", count_axis_ids(axis_ids) - 2, hharray, + cmf = cmor_zfactor(zfactor_id, lev_id, (char *) "orog", (char *) "m", count_axis_ids(axis_ids) - 2, hharray.data(), orogtype, (void *) orogdata, nullptr); } else if (time_method[0] == 'p') @@ -2949,15 +2962,15 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, cmf = cmor_zfactor(zfactor_id, lev_id, (char *) "ps", (char *) "Pa", count_axis_ids(axis_ids) - 1, axis_ids, vars[psID].datatype, nullptr, nullptr); } - Free(alev_val); - Free(ap_val); - Free(b_val); + free(alev_val); + free(ap_val); + free(b_val); if (zaxistype == ZAXIS_HYBRID) { - if (strcmp(zaxis, "hybrid_height") == 0) Free(orogdata); - Free(ap_bnds); - Free(alev_bnds); - Free(b_bnds); + if (strcmp(zaxis, "hybrid_height") == 0) free(orogdata); + free(ap_bnds); + free(alev_bnds); + free(b_bnds); } } else if (zaxisInqType(zaxisID) == ZAXIS_DEPTH_BELOW_SEA || zaxisInqType(zaxisID) == ZAXIS_DEPTH_BELOW_LAND) @@ -3027,13 +3040,12 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, cdo_abort("ERROR (infile: '%s')! In registration of a vertical axis:\n Z-axis type %d with name '%s' not yet " "enabled.", cdo_get_stream_name(0), zaxisInqType(zaxisID), zaxisname); - Free(zaxisname); } else cdo_abort("ERROR (infile: '%s')! In registration of a vertical axis:\n Invalid Z-axis type %d . ", cdo_get_stream_name(0), zaxisInqType(zaxisID)); - Free(zcell_bounds); - Free(levels); + free(zcell_bounds); + free(levels); } else if (zsize == 1 && strcmp(zaxis, "notSet") != 0) @@ -3047,11 +3059,11 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, char *szc_value = kv_get_a_val(kvl, (const char *) zaxis, nullptr); if (szc_value) { - levels = (double *) Malloc(sizeof(double)); + levels = (double *) malloc(sizeof(double)); levels[0] = (double) atof(szc_value); - char *szc_key = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); - sprintf(szc_key, "%s_bounds", zaxis); + char szc_key[CMOR_MAX_STRING]; + std::snprintf(szc_key, CMOR_MAX_STRING, "%s_bounds", zaxis); int numchar = 0; std::vector<std::string> szc_bndss = kv_get_vals(kvl, szc_key, &numchar); @@ -3067,7 +3079,7 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, cdo_abort("ERROR (infile: '%s')! Internal error.", cdo_get_stream_name(0)); } - sprintf(szc_key, "%s_units", zaxis); + std::snprintf(szc_key, CMOR_MAX_STRING, "%s_units", zaxis); char *szcunits = kv_get_a_val(kvl, (const char *) szc_key, "m"); if (Options::cdoVerbose) @@ -3076,7 +3088,7 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, cmf = cmor_axis(new_axis_id(axis_ids), zaxis, (char *) szcunits, zsize, (void *) levels, 'd', szc_bnds, 2, nullptr); else cmf = cmor_axis(new_axis_id(axis_ids), zaxis, (char *) szcunits, zsize, (void *) levels, 'd', nullptr, 0, nullptr); - Free(levels); + free(levels); } else cdo_print("You specified z_axis='%s'.\n No value has been specified, axis will be created with the " @@ -3086,7 +3098,7 @@ register_z_axis(KVList *kvl, int vlistID, int varID, int zaxisID, char *varname, else cdo_print("Vertical axis is either default and scalar or not available."); - Free(chardim); + free(chardim); if (cmf != 0) cdo_abort("ERROR (infile: '%s')! Function cmor_axis failed!", cdo_get_stream_name(0)); } @@ -3100,14 +3112,14 @@ dimension.\n"); int varndims, varnattsp; int *vardimids; - char *varname = Malloc(36 * sizeof(char)); - char *dimname = Malloc(36 * sizeof(char)); + char *varname = malloc(36); + char *dimname = malloc(36); size_t dimlength, dimstrlength; nc_open(filename, NC_NOWRITE, &nc_file_id); nc_inq(nc_file_id, &nfiledims, &nvars, &ngatts, &unlimdimid); - vardimids = Malloc(nfiledims * sizeof(int)); + vardimids = malloc(nfiledims * sizeof(int)); void *final_chardim; for ( int i = 0; i < nvars; i++ ) { @@ -3117,15 +3129,15 @@ dimension.\n"); nc_inq_dim(nc_file_id, vardimids[1], dimname, &dimstrlength); nc_inq_dim(nc_file_id, vardimids[0], dimname, &dimlength); - final_chardim = (void *)Malloc(dimstrlength * dimlength *sizeof(char)); + final_chardim = (void *)malloc(dimstrlength * dimlength *sizeof(char)); nc_get_var(nc_file_id, i, final_chardim); } } nc_close(nc_file_id); cmor_axis(new_axis_id(axis_ids), dimname, "", dimlength, final_chardim, 'c', nullptr, dimstrlength, nullptr); - Free(varname); - Free(dimname); - Free(vardimids); + free(varname); + free(dimname); + free(vardimids); } */ static void @@ -3274,11 +3286,11 @@ get_cmor_table(KVList *kvl, char *project_id) char *mip_table_dir = kv_get_a_val(kvl, "mip_table_dir", nullptr); #if (CMOR_VERSION_MAJOR == 2) if (mip_table_dir[strlen(mip_table_dir) - 1] == '/') - sprintf(gridtable, "%s%s_grids", mip_table_dir, project_id); + std::snprintf(gridtable, CMOR_MAX_STRING, "%s%s_grids", mip_table_dir, project_id); else - sprintf(gridtable, "%s/%s_grids", mip_table_dir, project_id); + std::snprintf(gridtable, CMOR_MAX_STRING, "%s/%s_grids", mip_table_dir, project_id); #elif (CMOR_VERSION_MAJOR == 3) - sprintf(gridtable, "%s/%s_grids.json", mip_table_dir, project_id); + std::snprintf(gridtable, CMOR_MAX_STRING, "%s/%s_grids.json", mip_table_dir, project_id); #endif if (file_exist(gridtable, false, "Cmor-grid_table", false)) { @@ -3470,10 +3482,10 @@ register_projection(int *grid_ids, int projID, double *ycoord_vals, double *xcoo int pynbounds; int pylength = gridInqYsize(projID); int pxlength = gridInqXsize(projID); - double *pxcoord_vals = (double *) Malloc(pxlength * sizeof(double)); - double *pycoord_vals = (double *) Malloc(pylength * sizeof(double)); - double *pxcell_bounds = (double *) Malloc(2 * pxlength * sizeof(double)); - double *pycell_bounds = (double *) Malloc(2 * pylength * sizeof(double)); + double *pxcoord_vals = (double *) malloc(pxlength * sizeof(double)); + double *pycoord_vals = (double *) malloc(pylength * sizeof(double)); + double *pxcell_bounds = (double *) malloc(2 * pxlength * sizeof(double)); + double *pycell_bounds = (double *) malloc(2 * pylength * sizeof(double)); inquire_vals_and_bounds(projID, &pxnbounds, &pynbounds, pxcoord_vals, pycoord_vals, pxcell_bounds, pycell_bounds); check_and_gen_bounds(projID, pxnbounds, pxlength, pxcoord_vals, pxcell_bounds, 1); check_and_gen_bounds(projID, pynbounds, pylength, pycoord_vals, pycell_bounds, 0); @@ -3622,7 +3634,7 @@ register_projection(int *grid_ids, int projID, double *ycoord_vals, double *xcoo "set to 0.0 by default in case they are not given.", p_len, natts); - parameter_values = (double *) Malloc(p_len * sizeof(double)); + parameter_values = (double *) malloc(p_len * sizeof(double)); for (int i = 0; i < p_len; ++i) parameter_values[i] = 0.0; for (int iatt = 0; iatt < natts; ++iatt) @@ -3694,8 +3706,8 @@ register_projection(int *grid_ids, int projID, double *ycoord_vals, double *xcoo else if (projtype == CDI_PROJ_LCC) { memcpy(u_cmor, " \0 \0 \0 \0", 4 * l_u_cmor); - double *xii = (double *) Malloc(xlength * sizeof(double)); - double *yii = (double *) Malloc(ylength * sizeof(double)); + double *xii = (double *) malloc(xlength * sizeof(double)); + double *yii = (double *) malloc(ylength * sizeof(double)); for (int i = 0; i < xlength; ++i) xii[i] = (double) i; for (int i = 0; i < ylength; ++i) yii[i] = (double) i; cmf = cmor_axis(&grid_axis[0], (char *) "x", (char *) "m", ylength, (void *) yii, 'd', 0, 0, nullptr); @@ -3708,8 +3720,8 @@ register_projection(int *grid_ids, int projID, double *ycoord_vals, double *xcoo #elif (CMOR_VERSION_MAJOR == 3) cmf = cmor_set_grid_mapping(grid_ids[0], mapping, p_len, p_lcc_cmor, l_p_lcc, parameter_values, u_cmor, l_u_cmor); #endif - Free(xii); - Free(yii); + free(xii); + free(yii); } else if (projtype == CDI_PROJ_STERE) { @@ -3728,11 +3740,11 @@ register_projection(int *grid_ids, int projID, double *ycoord_vals, double *xcoo #endif } - Free(parameter_values); - Free(pxcell_bounds); - Free(pycell_bounds); - Free(pxcoord_vals); - Free(pycoord_vals); + free(parameter_values); + free(pxcell_bounds); + free(pycell_bounds); + free(pxcoord_vals); + free(pycoord_vals); if (cmf != 0) cdo_abort("ERROR (infile: '%s')! Function cmor_axis or cmor_set_grid_mapping failed!", cdo_get_stream_name(0)); } @@ -3779,10 +3791,10 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, if (type == GRID_GAUSSIAN || type == GRID_LONLAT) { grid_ids[0] = 0; - xcoord_vals = (double *) Malloc(xlength * sizeof(double)); - ycoord_vals = (double *) Malloc(ylength * sizeof(double)); - xcell_bounds = (double *) Malloc(2 * xlength * sizeof(double)); - ycell_bounds = (double *) Malloc(2 * ylength * sizeof(double)); + xcoord_vals = (double *) malloc(xlength * sizeof(double)); + ycoord_vals = (double *) malloc(ylength * sizeof(double)); + xcell_bounds = (double *) malloc(2 * xlength * sizeof(double)); + ycell_bounds = (double *) malloc(2 * ylength * sizeof(double)); inquire_vals_and_bounds(gridID, &xnbounds, &ynbounds, xcoord_vals, ycoord_vals, xcell_bounds, ycell_bounds); check_and_gen_bounds(gridID, xnbounds, xlength, xcoord_vals, xcell_bounds, 1); @@ -3795,28 +3807,28 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, cmf = cmor_axis(new_axis_id(axis_ids), (char *) "longitude", (char *) "degrees_east", xlength, (void *) xcoord_vals, 'd', (void *) xcell_bounds, 2, nullptr); - Free(xcell_bounds); - Free(ycell_bounds); - Free(xcoord_vals); - Free(ycoord_vals); + free(xcell_bounds); + free(ycell_bounds); + free(xcoord_vals); + free(ycoord_vals); } else if (type == GRID_UNSTRUCTURED) { int nvertex = gridInqNvertex(gridID); - xcoord_vals = (double *) Malloc(totalsize * sizeof(double)); - ycoord_vals = (double *) Malloc(totalsize * sizeof(double)); + xcoord_vals = (double *) malloc(totalsize * sizeof(double)); + ycoord_vals = (double *) malloc(totalsize * sizeof(double)); /* maximal 4 gridbounds per gridcell permitted */ if (nvertex) { - xcell_bounds = (double *) Malloc(nvertex * totalsize * sizeof(double)); - ycell_bounds = (double *) Malloc(nvertex * totalsize * sizeof(double)); + xcell_bounds = (double *) malloc(nvertex * totalsize * sizeof(double)); + ycell_bounds = (double *) malloc(nvertex * totalsize * sizeof(double)); } inquire_vals_and_bounds(gridID, &xnbounds, &ynbounds, xcoord_vals, ycoord_vals, xcell_bounds, ycell_bounds); /* In a projection, this is done by setting mapping parameter */ if (strcmp(movelons, "y") == 0) move_lons(xcoord_vals, xcell_bounds, totalsize, nvertex * totalsize, xnbounds); int grid_axis[2]; double *coord_vals; - coord_vals = (double *) Malloc(xlength * sizeof(double)); + coord_vals = (double *) malloc(xlength * sizeof(double)); for (int j = 0; j < xlength; ++j) coord_vals[j] = (double) j; if (strcmp(chardim, "site") == 0) { @@ -3832,19 +3844,19 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, cmf = cmor_grid(&grid_ids[0], 1, grid_axis, 'd', (void *) ycoord_vals, (void *) xcoord_vals, nvertex, (void *) ycell_bounds, (void *) xcell_bounds); } - Free(coord_vals); - Free(xcoord_vals); - Free(ycoord_vals); - if (xcell_bounds) Free(xcell_bounds); - if (ycell_bounds) Free(ycell_bounds); + free(coord_vals); + free(xcoord_vals); + free(ycoord_vals); + if (xcell_bounds) free(xcell_bounds); + if (ycell_bounds) free(ycell_bounds); } else if (type == GRID_CURVILINEAR) { - xcoord_vals = (double *) Malloc(totalsize * sizeof(double)); - ycoord_vals = (double *) Malloc(totalsize * sizeof(double)); + xcoord_vals = (double *) malloc(totalsize * sizeof(double)); + ycoord_vals = (double *) malloc(totalsize * sizeof(double)); /* maximal 4 gridbounds per gridcell permitted */ - xcell_bounds = (double *) Malloc(4 * totalsize * sizeof(double)); - ycell_bounds = (double *) Malloc(4 * totalsize * sizeof(double)); + xcell_bounds = (double *) malloc(4 * totalsize * sizeof(double)); + ycell_bounds = (double *) malloc(4 * totalsize * sizeof(double)); inquire_vals_and_bounds(gridID, &xnbounds, &ynbounds, xcoord_vals, ycoord_vals, xcell_bounds, ycell_bounds); /* In a projection, this is done by setting mapping parameter */ if (strcmp(movelons, "y") == 0) move_lons(xcoord_vals, xcell_bounds, totalsize, 4 * totalsize, xnbounds); @@ -3856,20 +3868,20 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, { double *xncoord_vals; double *yncoord_vals; - xncoord_vals = (double *) Malloc(xlength * sizeof(double)); - yncoord_vals = (double *) Malloc(ylength * sizeof(double)); + xncoord_vals = (double *) malloc(xlength * sizeof(double)); + yncoord_vals = (double *) malloc(ylength * sizeof(double)); for (int j = 0; j < ylength; ++j) yncoord_vals[j] = (double) j; for (int j = 0; j < xlength; ++j) xncoord_vals[j] = (double) j; cmf = cmor_axis(&grid_axis[0], (char *) "j_index", (char *) "1", ylength, (void *) yncoord_vals, 'd', 0, 0, nullptr); cmf = cmor_axis(&grid_axis[1], (char *) "i_index", (char *) "1", xlength, (void *) xncoord_vals, 'd', 0, 0, nullptr); cmf = cmor_grid(&grid_ids[0], 2, grid_axis, 'd', (void *) ycoord_vals, (void *) xcoord_vals, 4, (void *) ycell_bounds, (void *) xcell_bounds); - Free(xncoord_vals); - Free(yncoord_vals); - Free(xcoord_vals); - Free(ycoord_vals); - Free(xcell_bounds); - Free(ycell_bounds); + free(xncoord_vals); + free(yncoord_vals); + free(xcoord_vals); + free(ycoord_vals); + free(xcell_bounds); + free(ycell_bounds); } /*else { @@ -3890,15 +3902,15 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, if (Options::cdoVerbose) cdo_print("Start to define a character axis '%s' instead of a grid axis'.", chardim); grid_ids[0] = 0; int numchar = 0; - char *charvalstring = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); - sprintf(charvalstring, "char_axis_%s_%s", chardim, cmor_name); + char charvalstring[CMOR_MAX_STRING]; + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s_%s", chardim, cmor_name); std::vector<std::string> charvals = kv_get_vals(kvl, charvalstring, &numchar); if (numchar == 0) { - sprintf(charvalstring, "char_axis_%s", chardim); + std::snprintf(charvalstring, CMOR_MAX_STRING, "char_axis_%s", chardim); charvals = kv_get_vals(kvl, charvalstring, &numchar); } - Free(charvalstring); + if ((xlength > 0 && xlength != numchar) && (ylength > 0 && ylength != numchar)) cdo_abort( "ERROR (infile: '%s')! In registration of a character coordinate as substitution for a horizontal axis:\n " @@ -3933,8 +3945,8 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, if ((dimstrlen = gridInqXIsc(gridID))) { std::vector<std::string> xcharspp; - char **xchars = (char **) Malloc((xlength + 1) * sizeof(char *)); - for (int i = 0; i < xlength; ++i) xchars[i] = (char *) Malloc((dimstrlen + 1) * sizeof(char)); + char **xchars = (char **) malloc((xlength + 1) * sizeof(char *)); + for (int i = 0; i < xlength; ++i) xchars[i] = (char *) malloc(dimstrlen + 1); gridInqXCvals(gridID, xchars); for (int j = 0; j < xlength; ++j) xchars[j][dimstrlen] = 0; xchars[xlength] = nullptr; @@ -3948,8 +3960,8 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, if ((dimstrlen = gridInqYIsc(gridID))) { std::vector<std::string> ycharspp; - char **ychars = (char **) Malloc((ylength + 1) * sizeof(char)); - for (int i = 0; i < ylength; ++i) ychars[i] = (char *) Malloc((dimstrlen + 1) * sizeof(char)); + char **ychars = (char **) malloc((ylength + 1) * sizeof(char *)); + for (int i = 0; i < ylength; ++i) ychars[i] = (char *) malloc(dimstrlen + 1); gridInqYCvals(gridID, ychars); for (int j = 0; j < ylength; ++j) ychars[j][dimstrlen] = 0; ychars[ylength] = nullptr; @@ -3975,15 +3987,15 @@ register_grid(KVList *kvl, int vlistID, int varID, int *axis_ids, int *grid_ids, if (projtype != CDI_UNDEFID) { register_projection(grid_ids, projID, ycoord_vals, xcoord_vals, ycell_bounds, xcell_bounds, xlength, ylength, projtype); - Free(xcoord_vals); - Free(ycoord_vals); - Free(xcell_bounds); - Free(ycell_bounds); + free(xcoord_vals); + free(ycoord_vals); + free(xcell_bounds); + free(ycell_bounds); } } else grid_ids[0] = 0; - Free(chardim); + free(chardim); if (cmf != 0) cdo_abort("ERROR (infile: '%s')! Function cmor_axis failed!", cdo_get_stream_name(0)); } @@ -3996,7 +4008,7 @@ register_variable(KVList *kvl, int vlistID, int varID, int *axis_ids, struct map char *origname = get_txtatt(vlistID, varID, "original_name"); char *history = get_txtatt(vlistID, varID, "history"); char *varcom = get_txtatt(vlistID, varID, "variable_comment"); - char *units = (char *) Malloc(CDI_MAX_NAME * sizeof(char)); + char *units = (char *) malloc(CDI_MAX_NAME); vlistInqVarUnits(vlistID, varID, units); char *attunits = kv_get_a_val(kvl, "u", nullptr); char *attp = kv_get_a_val(kvl, "p", nullptr); @@ -4008,13 +4020,13 @@ register_variable(KVList *kvl, int vlistID, int varID, int *axis_ids, struct map check_compare_set(&origname, attorigname, "original_name", ""); if (strcmp(origname, "") == 0 || strstr(origname, "var")) { - Free(origname); + free(origname); origname = nullptr; } check_compare_set(&varcom, attvarcom, "variable_comment", ""); if (strcmp(varcom, "") == 0) { - Free(varcom); + free(varcom); varcom = nullptr; } if (Options::cdoVerbose) @@ -4033,7 +4045,7 @@ register_variable(KVList *kvl, int vlistID, int varID, int *axis_ids, struct map { var->charvars = 0; var->datatype = 'd'; - var->data = Malloc(gridsize * zsize * sizeof(double)); + var->data = malloc(gridsize * zsize * sizeof(double)); } *(double *) missing_value = vlistInqVarMissval(vlistID, varID); } @@ -4043,7 +4055,7 @@ register_variable(KVList *kvl, int vlistID, int varID, int *axis_ids, struct map { var->charvars = 0; var->datatype = 'f'; - var->data = Malloc(gridsize * zsize * sizeof(float)); + var->data = malloc(gridsize * zsize * sizeof(float)); } *(float *) missing_value = vlistInqVarMissval(vlistID, varID); } @@ -4083,11 +4095,11 @@ register_variable(KVList *kvl, int vlistID, int varID, int *axis_ids, struct map if (Options::cdoVerbose) cdo_print("8.5.3. Successfully set deflate for variable '%s'.", name); } #endif - if (positive) Free(positive); - if (origname) Free(origname); - if (history) Free(history); - if (units) Free(units); - if (varcom) Free(varcom); + if (positive) free(positive); + if (origname) free(origname); + if (history) free(history); + if (units) free(units); + if (varcom) free(varcom); } static void @@ -4314,13 +4326,13 @@ register_all_dimensions(KVList *kvl, CdoStreamID streamID, struct mapping vars[] if (vlistInqVarDatatype(vlistID, mergeIDs[mergeID]) == CDI_DATATYPE_FLT64) { var->datatype = 'd'; - var->data = Malloc(gridInqSize(vlistInqVarGrid(vlistID, mergeIDs[mergeID])) + var->data = malloc(gridInqSize(vlistInqVarGrid(vlistID, mergeIDs[mergeID])) * zaxisInqSize(vlistInqVarZaxis(vlistID, mergeIDs[mergeID])) * sizeof(double)); } else { var->datatype = 'f'; - var->data = Malloc(gridInqSize(vlistInqVarGrid(vlistID, mergeIDs[mergeID])) + var->data = malloc(gridInqSize(vlistInqVarGrid(vlistID, mergeIDs[mergeID])) * zaxisInqSize(vlistInqVarZaxis(vlistID, mergeIDs[mergeID])) * sizeof(float)); } } @@ -4347,7 +4359,7 @@ register_all_dimensions(KVList *kvl, CdoStreamID streamID, struct mapping vars[] static char * get_frequency(/*KVList *kvl,*/ int vlistID, int miptab_freq) { - char *frequency = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); + char *frequency = (char *) malloc(CMOR_MAX_STRING); std::strcpy(frequency, "no"); int ntsteps = vlistNtsteps(vlistID); int reccounter = 0; @@ -4668,7 +4680,7 @@ get_time_bounds(KVList *kvl, int taxisID, int ifreq, JulianDate ref_date, Julian double *time_bnds, int time_axis, int /*vlistID*/) { double time_val = julianDate_to_seconds(julianDate_sub(jtime_val, ref_date)) / tunitsec; - const auto vDateTime = taxisInqVdatetime(taxisID); + auto vDateTime = taxisInqVdatetime(taxisID); auto vDateTimeCorr = vDateTime; CdiDateTime vDateTime0b{}; CdiDateTime vDateTime1b{}; @@ -4905,7 +4917,7 @@ read_record(CdoStreamID streamID, struct mapping vars[], int vlistID) int gridID = vlistInqVarGrid(vlistID, varID); int type = gridInqType(gridID); auto gridsize = gridInqSize(gridID); - double *buffer = (double *) Malloc(gridsize * sizeof(double)); + double *buffer = (double *) malloc(gridsize * sizeof(double)); struct mapping *var = map_var(varID, vars); if (var && var->charvars != 1) @@ -4914,8 +4926,8 @@ read_record(CdoStreamID streamID, struct mapping vars[], int vlistID) int ztype = zaxisInqType(zaxisID); /* int latdim = gridInqYsize(gridID); */ int levdim = zaxisInqSize(zaxisID); - size_t nmiss; - cdo_read_record(streamID, buffer, &nmiss); + size_t numMissVals; + cdo_read_record(streamID, buffer, &numMissVals); for (size_t i = 0; i < gridsize; ++i) { // Wrong: (lat x basin, lev ) gridsize * levelID + i @@ -4942,7 +4954,7 @@ read_record(CdoStreamID streamID, struct mapping vars[], int vlistID) else { ((double *) var->data)[newIndex] = (double) buffer[i]; } } } - Free(buffer); + free(buffer); } static int @@ -5064,7 +5076,7 @@ check_append_and_size(KVList *kvl, int /*vlistID*/, char *testIn, int ifreq, int CdiStreamID streamID2 = streamOpenRead(cdo_get_stream_name(0)); int vlistID2 = streamInqVlist(streamID2); int taxisID2 = vlistInqTaxis(vlistID2); - const auto vDateTime2 = taxisInqVdatetime(taxisID2); + auto vDateTime2 = taxisInqVdatetime(taxisID2); auto firstdate = julianDate_encode(calendar, vDateTime2); int fyear, fmonth, dummy; @@ -5176,7 +5188,7 @@ check_append_and_size(KVList *kvl, int /*vlistID*/, char *testIn, int ifreq, int static char * use_chunk_des_files(KVList *kvl, int vlistID, int /*var_id*/, char *chunk_des_file, int ifreq, int calendar) { - char *chunk_file = (char *) Malloc(4096 * sizeof(char)); + char *chunk_file = (char *) malloc(4096); if (file_exist(chunk_des_file, false, "chunk_description", false)) { auto *fp = std::fopen(chunk_des_file, "r"); @@ -5248,14 +5260,14 @@ static char ** get_chunk_des_files(KVList *kvl, struct mapping vars[], char *miptab_freqptr, int nreq, int vlistID, char *charname, char *project_id) { - char **chunk_des_files = (char **) Malloc((nreq + 1) * sizeof(char *)); + char **chunk_des_files = (char **) malloc((nreq + 1) * sizeof(char *)); chunk_des_files[nreq] = nullptr; char trunk[CMOR_MAX_STRING]; if (strcmp(project_id, "CMIP6") == 0) - sprintf(trunk, "%s_", kv_get_a_val(kvl, "source_id", "")); + std::snprintf(trunk, CMOR_MAX_STRING, "%s_", kv_get_a_val(kvl, "source_id", "")); else - sprintf(trunk, "%s_", kv_get_a_val(kvl, "model_id", "")); + std::snprintf(trunk, CMOR_MAX_STRING, "%s_", kv_get_a_val(kvl, "model_id", "")); const char *description_atts[] = { "experiment_id", "member", "sub_experiment_id", nullptr }; std::strcpy(trunk, miptab_freqptr); for (int i = 0; description_atts[i]; ++i) @@ -5266,14 +5278,13 @@ get_chunk_des_files(KVList *kvl, struct mapping vars[], char *miptab_freqptr, in for (int j = 0; vars[j].cmor_varID != CMOR_UNDEFID; ++j) { - char *name = (char *) Malloc(CDI_MAX_NAME * sizeof(char)); + char name[CDI_MAX_NAME]; if (charname) std::strcpy(name, charname); else vlistInqVarName(vlistID, vars[j].cdi_varID, name); - chunk_des_files[j] = (char *) Malloc(CMOR_MAX_STRING * sizeof(char)); - sprintf(chunk_des_files[j], ".CHUNK_FILE_%s_%s.txt", name, trunk); - Free(name); + chunk_des_files[j] = (char *) malloc(CMOR_MAX_STRING); + std::snprintf(chunk_des_files[j], CMOR_MAX_STRING, ".CHUNK_FILE_%s_%s.txt", name, trunk); } return chunk_des_files; } @@ -5286,7 +5297,7 @@ get_chunk_files(KVList *kvl, struct mapping vars[], int vlistID, int ifreq, int for (i = 0; vars[i].cmor_varID != CMOR_UNDEFID; ++i) ; if (mergeIDs[0] != CMOR_UNDEFID) i = 1; - char **chunk_files = (char **) Malloc((i + 1) * sizeof(char *)); + char **chunk_files = (char **) malloc((i + 1) * sizeof(char *)); chunk_files[i] = nullptr; if (Options::cdoVerbose) cdo_print("10.2.1. Start to validate append mode."); @@ -5380,9 +5391,9 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi if (Options::cdoVerbose) cdo_print("10. Start to write variables via cmor_write."); if (Options::cdoVerbose) cdo_print("10.1. Start to get frequency."); int time_unit; - const auto sDateTime = get_taxis(kv_get_a_val(kvl, "rtu", nullptr), &time_unit); + auto sDateTime = get_taxis(kv_get_a_val(kvl, "rtu", nullptr), &time_unit); int tunitsec = get_tunitsec(time_unit); - const auto ref_date = julianDate_encode(calendar, sDateTime); + auto ref_date = julianDate_encode(calendar, sDateTime); char *frequency = nullptr; if (time_axis != 4) { @@ -5420,7 +5431,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi { int number = 0; for (number = 0; vars[number].cmor_varID != CMOR_UNDEFID; number++) - chunk_files = (char **) Malloc((number + 1) * sizeof(char *)); + chunk_files = (char **) malloc((number + 1) * sizeof(char *)); empty_array(vars, &chunk_files); } if (ifreq == 7) cdo_print("10.2. Append mode not possible for frequency '%s'. Switch to replace mode.", frequency); @@ -5431,7 +5442,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi while (chunk_files[i]) { char command[CDI_MAX_NAME]; - sprintf(command, "cp %s %s.save", chunk_files[i], chunk_files[i]); + std::snprintf(command, CDI_MAX_NAME, "cp %s %s.save", chunk_files[i], chunk_files[i]); int dir_err = system(command); if (dir_err != 0) cdo_warning("Could not create a .save file out of the previous chunk '%s'.", chunk_files[i]); i++; @@ -5448,7 +5459,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi if (Options::cdoVerbose) cdo_print("10.3. Start to get auxiliary variables."); zaxisID = vlistInqVarZaxis(vlistID, vars[i].cdi_varID); zsize = zaxisInqSize(zaxisID); - charname = (char *) Malloc(CDI_MAX_NAME * sizeof(char)); + charname = (char *) malloc(CDI_MAX_NAME * sizeof(char)); vlistInqVarName(vlistID, vars[i].cdi_varID, charname); cdo_stream_close(streamID); @@ -5472,12 +5483,11 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi if (mergeIDs[0] != CMOR_UNDEFID) { while (mergeIDs[fsize] != CMOR_UNDEFID) fsize++; - ; if (Options::cdoVerbose) cdo_print("10.3. '%d' Variables will be merged.", fsize); zaxisID = vlistInqVarZaxis(vlistID, mergeIDs[0]); zsize = zaxisInqSize(zaxisID); - mergeIdx = (int *) Malloc(fsize * sizeof(int)); + mergeIdx = (int *) malloc(fsize * sizeof(int)); mergeIdx[0] = -1; for (int j = 0; j < fsize; j++) { @@ -5509,9 +5519,9 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi { void *dataslice; if (vars[mergeIdx[0]].datatype == 'd') - dataslice = (void *) Malloc(gridsize * zsize * fsize * sizeof(double)); + dataslice = (void *) malloc(gridsize * zsize * fsize * sizeof(double)); else - dataslice = (void *) Malloc(gridsize * zsize * fsize * sizeof(float)); + dataslice = (void *) malloc(gridsize * zsize * fsize * sizeof(float)); for (i = 0; i < fsize; i++) { @@ -5539,7 +5549,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi cmf = cmor_write(vars[mergeIdx[0]].cmor_varID, dataslice, vars[mergeIdx[0]].datatype, chunk_files[0], 1, &time_val, time_bndsp, NULL); #endif - Free(dataslice); + free(dataslice); } for (i = 0; vars[i].cmor_varID != CMOR_UNDEFID; ++i) { @@ -5554,13 +5564,13 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi void *dataslice; if (vars[i].datatype == 'd') { - dataslice = (void *) Malloc(gridsize * zsize * sizeof(double)); + dataslice = (void *) malloc(gridsize * zsize * sizeof(double)); for (int j = 0; j < (int) gridsize * zsize; ++j) ((double *) dataslice)[j] = ((double *) vars[i].data)[(tsID - 1) * gridsize * zsize + j]; } else { - dataslice = (void *) Malloc(gridsize * zsize * sizeof(float)); + dataslice = (void *) malloc(gridsize * zsize * sizeof(float)); for (int j = 0; j < (int) gridsize * zsize; ++j) ((float *) dataslice)[j] = ((float *) vars[i].data)[(tsID - 1) * gridsize * zsize + j]; } @@ -5570,7 +5580,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi cmf = cmor_write(vars[i].cmor_varID, dataslice, vars[i].datatype, chunk_files[i], 1, &time_val, time_bndsp, nullptr); #endif - Free(dataslice); + free(dataslice); } else if (vars[i].cdi_varID != mergeIDs[0]) { @@ -5634,16 +5644,16 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi status = nc_get_att_text(ncid, NC_GLOBAL, "tracking_id", prelim); char *prefixCordex = strdup("hdl:21.14103/"); int lengthCombi = strlen(prelim) + strlen(prefixCordex); - char *track = (char *) Malloc(lengthCombi * sizeof(char)); - sprintf(track, "%s%s", prefixCordex, prelim); + char *track = (char *) malloc(lengthCombi); + std::snprintf(track, lengthCombi, "%s%s", prefixCordex, prelim); status = nc_put_att_text(ncid, NC_GLOBAL, "tracking_id", (size_t) lengthCombi, (const char *) track); status = nc_enddef(ncid); status = nc_close(ncid); if (status != NC_NOERR) cdo_abort("ERROR (infile: '%s')! Could not set a prefix for tracking_id", cdo_get_stream_name(0)); if (Options::cdoVerbose) cdo_print("11.1. Successfully set a prefix for tracking_id."); - Free(track); - Free(prefixCordex); + free(track); + free(prefixCordex); } } #endif @@ -5656,7 +5666,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi char *prelim = get_txtatt(vlistIDF, CDI_GLOBAL, "tracking_id"); char *prefixCordex = strdup("21.14103/"); size_t lengthCombi = (size_t) (strlen(prelim) + strlen(prefixCordex)); - char *track = (char *) Malloc( lengthCombi *sizeof(char)); + char *track = (char *) malloc( lengthCombi *sizeof(char)); sprintf(track, "%s%s", prefixCordex, prelim); cdiDefAttTxt(vlistIDF, CDI_GLOBAL, "tracking_id", lengthCombi, (const char *)track); streamClose(streamIDF); @@ -5721,52 +5731,52 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi smon1[2] = '\0'; smon2[2] = '\0'; if (atol(smon1) != 1) - sprintf(smon1, "%02ld", atol(smon1) - 1); + std::snprintf(smon1, sizeof(smon1), "%02ld", atol(smon1) - 1); else { char syr[5]; strncpy(syr, &timename[1], 4); syr[4] = '\0'; - sprintf(syr, "%04ld", atol(syr) - 1); + std::snprintf(syr, sizeof(syr), "%04ld", atol(syr) - 1); strncpy(&timename[1], syr, 4); - sprintf(smon1, "12"); + std::snprintf(smon1, sizeof(smon1), "12"); } if (atol(smon2) != 1) - sprintf(smon2, "%02ld", atol(smon2) + 1); + std::snprintf(smon2, sizeof(smon2), "%02ld", atol(smon2) + 1); else { char syr[12]; strncpy(syr, &timename[8], 4); syr[4] = '\0'; - sprintf(syr, "%04ld", atol(syr) - 1); + std::snprintf(syr, sizeof(syr), "%04ld", atol(syr) - 1); strncpy(&timename[8], syr, 4); - sprintf(smon2, "12"); + std::snprintf(smon2, sizeof(smon2), "12"); } strncpy(&timename[5], smon1, 2); strncpy(&timename[12], smon2, 2); } int cmdlen = 11 + strlen(kv_get_a_val(kvl, "cordexDir", nullptr)) + strlen(varname); - char command1[cmdlen]; - std::snprintf(command1, cmdlen, "mkdir -p %s/%s", kv_get_a_val(kvl, "cordexDir", nullptr), varname); + std::vector<char> command1(cmdlen); + std::snprintf(command1.data(), cmdlen, "mkdir -p %s/%s", kv_get_a_val(kvl, "cordexDir", nullptr), varname); - int dir_err = system(command1); + int dir_err = system(command1.data()); if (dir_err != 0) { cdo_warning("Could not create CORDEX compliant path for output files of cdo cmor. Files are created " "in current working directory."); } - sprintf(cordex_file_name, "%s/%s/%s_%s%s", kv_get_a_val(kvl, "cordexDir", nullptr), varname, varname, - kv_get_a_val(kvl, "cordexFileTem", nullptr), timename); + std::snprintf(cordex_file_name, CMOR_MAX_STRING, "%s/%s/%s_%s%s", kv_get_a_val(kvl, "cordexDir", nullptr), varname, + varname, kv_get_a_val(kvl, "cordexFileTem", nullptr), timename); cmdlen = 5 + strlen(file_name) + strlen(cordex_file_name); - char command2[cmdlen]; + std::vector<char> command2(cmdlen); - sprintf(command2, "mv %s %s", file_name, cordex_file_name); - dir_err = system(command2); + std::snprintf(command2.data(), cmdlen, "mv %s %s", file_name, cordex_file_name); + dir_err = system(command2.data()); if (dir_err != 0) { cdo_warning("Could not move cdo cmor output file to CORDEX compliant path."); @@ -5789,8 +5799,8 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi { char newname[CDI_MAX_NAME], oldmember[CDI_MAX_NAME], newmember[CDI_MAX_NAME], chunkpath[CDI_MAX_NAME], oldchunkpath[CDI_MAX_NAME]; - sprintf(oldmember, "r%ldi", atol(realization)); - sprintf(newmember, "r%si", realization); + std::snprintf(oldmember, CDI_MAX_NAME, "r%ldi", atol(realization)); + std::snprintf(newmember, CDI_MAX_NAME, "r%si", realization); char *startcmp = file_name; int startpattern = 0, lastSlash = 0; @@ -5808,10 +5818,10 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi chunkpath[startpattern + strlen(newmember) - patternlength] = '\0'; startcmp += patternlength; startpattern += patternlength; - sprintf(newname, "%s%s%s", chunkpath, newmember, startcmp); + std::snprintf(newname, CDI_MAX_NAME, "%s%s%s", chunkpath, newmember, startcmp); if (!oldchunkcopied) { - sprintf(oldchunkpath, "%s%s", chunkpath, oldmember); + std::snprintf(oldchunkpath, CDI_MAX_NAME, "%s%s", chunkpath, oldmember); oldchunkcopied = true; } std::strcpy(chunkpath, newname); @@ -5829,7 +5839,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi std::strcpy(chunkpath, newname); chunkpath[lastSlash] = '\0'; char command[CDI_MAX_NAME]; - sprintf(command, "mkdir -p %s; mv %s %s;", chunkpath, file_name, newname); + std::snprintf(command, CDI_MAX_NAME, "mkdir -p %s; mv %s %s;", chunkpath, file_name, newname); int dir_err = system(command); if (dir_err != 0) @@ -5844,7 +5854,7 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi if (Options::silentMode) cdo_warning(" File stored in: '%s' with cmor!", newname); } - sprintf(command, "rmdir %s*;", oldchunkpath); + std::snprintf(command, CDI_MAX_NAME, "rmdir %s*;", oldchunkpath); if (Options::cdoVerbose) cdo_print("Start to remove wrong data path (r1 instead of r0*)."); dir_err = system(command); if (dir_err != 0) @@ -5878,11 +5888,11 @@ write_variables(KVList *kvl, CdoStreamID streamID, struct mapping vars[], int mi } } if (cmf != 0) cdo_abort("ERROR (infile: '%s')! Function cmor_close_variable failed!", cdo_get_stream_name(0)); - if (mergeIDs[0] != CMOR_UNDEFID) Free(mergeIdx); - if (frequency) Free(frequency); + if (mergeIDs[0] != CMOR_UNDEFID) free(mergeIdx); + if (frequency) free(frequency); if (chunk_files) free_array(chunk_files); if (chunkdf) free_array(chunkdf); - if (charname) Free(charname); + if (charname) free(charname); cdo_stream_close(newstreamID); if (Options::cdoVerbose) cdo_print("11. Successfully closed files and freed allocated memory."); } @@ -5929,8 +5939,9 @@ read_maptab(KVList *kvl, CdoStreamID streamID, char *miptabfreq, struct mapping if (maptab && maptabdir) if (maptab[0] != '/') { - maptabbuild = (char *) Malloc((strlen(maptab) + strlen(maptabdir) + 2) * sizeof(char)); - sprintf(maptabbuild, "%s/%s", maptabdir, maptab); + size_t len = (strlen(maptab) + strlen(maptabdir) + 2); + maptabbuild = (char *) malloc(len); + std::snprintf(maptabbuild, len, "%s/%s", maptabdir, maptab); } if (maptab) { @@ -6038,16 +6049,16 @@ read_maptab(KVList *kvl, CdoStreamID streamID, char *miptabfreq, struct mapping /***/ kv_insert_vals(kvl, "mtproof", maptab, true, false); cdo_print("Mapping Table = '%s'.", maptab); - if (maptabbuild) Free(maptabbuild); + if (maptabbuild) free(maptabbuild); } else if (Options::cdoVerbose) cdo_print("5. No mapping table found."); } static void -replace_key(KVList *kvl, KeyValues kv, const char *newkey) +replace_key(KVList *kvl, const KeyValues &kv, const char *newkey) { - char **values = (char **) Malloc((kv.nvalues + 1) * sizeof(char *)); + char **values = (char **) malloc((kv.nvalues + 1) * sizeof(char *)); int k = 0; for (k = 0; k < kv.nvalues; k++) values[k] = strdup(kv.values[k].c_str()); values[kv.nvalues] = nullptr; @@ -6057,10 +6068,11 @@ replace_key(KVList *kvl, KeyValues kv, const char *newkey) } static void -parse_cmdline(KVList *kvl, std::vector<std::string> ¶ms, int nparams, const char *ventry) +parse_cmdline(KVList *kvl, std::vector<std::string> ¶ms, const char *ventry) { + (void) ventry; /* Already set params++ in main function */ - if (kvl->parse_arguments(nparams - 1, params) != 0) + if (kvl->parse_arguments(params) != 0) cdo_abort("ERROR (infile: '%s')! Could not parse command line.", cdo_get_stream_name(0)); std::vector<KeyValues> keystorm, keystosubs; @@ -6087,7 +6099,7 @@ parse_cmdline(KVList *kvl, std::vector<std::string> ¶ms, int nparams, const static char * get_mip_table(char *params, KVList *kvl, char *project_id, bool print) { - char *miptab; + char *miptab = nullptr; if (print && Options::cdoVerbose) cdo_print("2.2. Start to find a MIP table file."); if (!params) cdo_abort("ERROR (infile: '%s')! First parameter not passed. A MIP table file is required.", cdo_get_stream_name(0)); if (file_exist(params, false, "MIP table", print)) @@ -6132,13 +6144,15 @@ get_mip_table(char *params, KVList *kvl, char *project_id, bool print) { #if (CMOR_VERSION_MAJOR == 2) { - miptab = (char *) Malloc((strlen(miptabdir) + strlen(project_id) + strlen(params) + 3) * sizeof(char)); - sprintf(miptab, "%s/%s_%s", miptabdir, project_id, params); + size_t len = (strlen(miptabdir) + strlen(project_id) + strlen(params) + 3); + miptab = (char *) malloc(len); + std::snprintf(miptab, len, "%s/%s_%s", miptabdir, project_id, params); } #elif (CMOR_VERSION_MAJOR == 3) { - miptab = (char *) Malloc((strlen(miptabdir) + strlen(project_id) + strlen(params) + 8) * sizeof(char)); - sprintf(miptab, "%s/%s_%s.json", miptabdir, project_id, params); + size_t len = (strlen(miptabdir) + strlen(project_id) + strlen(params) + 8); + miptab = (char *) malloc(len); + std::snprintf(miptab, len, "%s/%s_%s.json", miptabdir, project_id, params); } #endif file_exist(miptab, true, "MIP table", print); @@ -6316,7 +6330,7 @@ cmor_load_and_set_table(KVList *kvl, char *param0, char *project_id, char **mip_ { int table_id = 0, cmf = 0; #if (CMOR_VERSION_MAJOR == 3) - Free(*mip_table); + free(*mip_table); *mip_table = get_mip_table(param0, kvl, project_id, false); #endif cmf = cmor_load_table(*mip_table, &table_id); @@ -6328,8 +6342,19 @@ cmor_load_and_set_table(KVList *kvl, char *param0, char *project_id, char **mip_ #endif -class ModuleCMOR +class CMOR : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "CMOR", + .operators = { { "cmor", CMORHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<CMOR> registration = RegisterEntry<CMOR>(module); #ifdef HAVE_LIBCMOR CdoStreamID streamID; @@ -6338,22 +6363,19 @@ class ModuleCMOR int miptab_freq; - char *project_id; - char *miptab_freqptr; - char *miptableInput; - char *mip_table; + char *project_id = nullptr; + char *miptab_freqptr = nullptr; + char *miptableInput = nullptr; + char *mip_table = nullptr; - struct mapping *vars; + struct mapping *vars = nullptr; #endif public: void - init(void *process) + init() { - cdo_initialize(process); - #ifndef HAVE_LIBCMOR - cdo_abort("CMOR support not compiled in!"); #else int nparams = cdo_operator_argc(); @@ -6367,7 +6389,7 @@ public: /* Define cmdline list and read cmdline */ const char *pmlistHelper[] = { "cmdline" }; - parse_cmdline(&kvl, params, nparams, pmlistHelper[0]); + parse_cmdline(&kvl, params, pmlistHelper[0]); /* Check whether a command line mapping is active */ check_cmdline_mapping(&kvl); @@ -6384,7 +6406,7 @@ public: std::vector<char> miptemp(lenmt); strncpy(miptemp.data(), mip_table, lenmt); miptemp[strlen(mip_table) - 5] = '\0'; - Free(mip_table); + free(mip_table); mip_table = strdup(miptemp.data()); #endif miptab_freq = get_miptab_freq(mip_table, project_id); @@ -6402,6 +6424,7 @@ public: if (Options::cdoVerbose) cdo_print("3. Successfully opened infile '%s'.", cdo_get_stream_name(0)); #endif } + void run() { @@ -6437,30 +6460,20 @@ public: write_variables(&kvl, streamID, vars, miptab_freq, time_axis, calendar, miptab_freqptr, project_id, mergeIDs); #endif } + void close() { #ifdef HAVE_LIBCMOR destruct_var_mapping(vars); - Free(mip_table); - Free(project_id); - Free(miptab_freqptr); - /* Free(miptableInput); */ - cdo_finish(); + free(mip_table); + free(project_id); + free(miptab_freqptr); + /* free(miptableInput); */ #endif } }; -void * -CMOR(void *process) -{ - ModuleCMOR cmor; - cmor.init(process); - cmor.run(); - cmor.close(); - - return 0; -} /* * Local Variables: * c-file-style: "Java" diff --git a/src/CMOR_lite.cc b/src/CMOR_lite.cc index 9bb7f15275c910fd6c7795ad17523abe958cb6d7..e2e2e5bea71ce3dd6316f59697212707613a4e56 100644 --- a/src/CMOR_lite.cc +++ b/src/CMOR_lite.cc @@ -148,8 +148,8 @@ cmor_check_prep(CmorVar &var, long gridsize, double missval, const double *const static void apply_cmor_list(PMList &pmlist, int nvars, int vlistID2, std::vector<CmorVar> &vars) { - const std::vector<std::string> hentry = { "Header" }; - const std::vector<std::string> ventry = { "variable_entry", "parameter" }; + static const std::vector<std::string> hentry = { "Header" }; + static const std::vector<std::string> ventry = { "variable_entry", "parameter" }; // search for global missing value auto hasMissvals = false; @@ -285,8 +285,20 @@ apply_cmor_list(PMList &pmlist, int nvars, int vlistID2, std::vector<CmorVar> &v } } -class ModuleCMOR_lite +class CMOR_lite : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "CMOR_lite", + .operators = { { "cmorlite", 0, 0, "parameter table name", CMORliteHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<CMOR_lite>(module); + bool deleteVars = false; Varray<double> array; @@ -304,15 +316,12 @@ class ModuleCMOR_lite public: void - init(void *process) + init() { - cdo_initialize(process); Options::CMOR_Mode = 1; if (Options::CMOR_Mode) cdiDefGlobal("CMOR_MODE", Options::CMOR_Mode); - cdo_operator_add("cmorlite", 0, 0, "parameter table name"); - auto operatorID = cdo_operator_id(); operator_input_arg(cdo_operator_enter(operatorID)); @@ -408,6 +417,7 @@ public: if (vlistNumber(vlistID1) != CDI_REAL) gridsizemax *= 2; array = Varray<double>(gridsizemax); } + void run() { @@ -445,14 +455,14 @@ public: cdo_def_record(streamID2, varID2, levelID2); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); auto missval = varList2[varID2].missval; auto gridsize = varList2[varID2].gridsize; if (varList2[varID2].nwpv != CDI_REAL) gridsize *= 2; - if (nmiss && var.changemissval) + if (numMissVals && var.changemissval) { for (size_t i = 0; i < gridsize; ++i) { @@ -489,7 +499,7 @@ public: } #endif - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); cmor_check_prep(var, gridsize, missval, array.data()); } @@ -499,6 +509,7 @@ public: tsID++; } } + void close() { @@ -511,17 +522,5 @@ public: cdo_convert_destroy(); #endif - - cdo_finish(); } }; - -void * -CMOR_lite(void *process) -{ - ModuleCMOR_lite lite; - lite.init(process); - lite.run(); - lite.close(); - return 0; -} diff --git a/src/CMOR_table.cc b/src/CMOR_table.cc index 17fcce056cfb6235048ded1475122c1a8882400d..30f4d9f9dbe4da3e573824c7e24376e549ef5997 100644 --- a/src/CMOR_table.cc +++ b/src/CMOR_table.cc @@ -106,21 +106,31 @@ conv_cmor_table(const PMList &pmlist) } } -class ModuleCMOR_table +class CMOR_table : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "CMOR_table", + .operators = { { "dump_cmor_table"}, { "conv_cmor_table"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 0, NoRestriction }, + }; + inline static RegisterEntry<CMOR_table> registration = RegisterEntry<CMOR_table>(module); + int DUMP_CMOR_TABLE, CONV_CMOR_TABLE; FILE *fp; const char *filename; int operatorID; - int DUMP_CMOR_TABLE, CONV_CMOR_TABLE; public: void - init(void *process) + init() { - cdo_initialize(process); - DUMP_CMOR_TABLE = cdo_operator_add("dump_cmor_table", 0, 0, nullptr); - CONV_CMOR_TABLE = cdo_operator_add("conv_cmor_table", 0, 0, nullptr); + DUMP_CMOR_TABLE = module.get_id("dump_cmor_table"); + CONV_CMOR_TABLE = module.get_id("conv_cmor_table"); operatorID = cdo_operator_id(); @@ -147,16 +157,5 @@ public: void close() { - cdo_finish(); } }; - -void * -CMOR_table(void *process) -{ - ModuleCMOR_table cmor_table; - cmor_table.init(process); - cmor_table.run(); - cmor_table.close(); - return nullptr; -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0385ad05cab6b6913587002f305c0e57ad493dae --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,537 @@ +list( APPEND cdolib_src_files + after_dvtrans.cc + after_fctrans.cc + after_namelist.cc + after_sptrans.cc + afterburner.h + afterburnerlib.cc + arithmetic.h + bitinformation.cc + bitinformation.h + cdi_lockedIO.cc + cdi_lockedIO.h + cdi_uuid.h + cdoStream.cc + cdoStream.h + cdo_cdi_wrapper.cc + cdo_cdi_wrapper.h + cdo_cmor.h + cdo_default_values.cc + cdo_default_values.h + cdo_features.cc + cdo_features.h + cdo_fctrans.cc + cdo_fctrans.h + cdo_fft.cc + cdo_fft.h + cdo_fftw3.cc + cdo_fftw3.h + cdo_fill.cc + cdo_fill.h + cdo_getopt.cc + cdo_getopt.h + cdo_history.cc + cdo_history.h + cdo_math.cc + cdo_math.h + cdo_module.cc + cdo_module.h + cdo_options.cc + cdo_options.h + cdo_output.cc + cdo_output.h + cdo_pthread.cc + cdo_pthread.h + cdo_query.cc + cdo_query.h + cdo_read.cc + cdo_rlimit.cc + cdo_rlimit.h + cdo_season.cc + cdo_season.h + cdo_syntax_error.cc + cdo_syntax_error.h + cdo_node_attach_exception.h + cdo_exception.h + cdo_task.cc + cdo_task.h + cdo_timer.h + cdo_varlist.cc + cdo_varlist.h + cdo_vlist.cc + cdo_vlist.h + cdo_zaxis.cc + cdo_zaxis.h + cf_interface.h + cfortran.h + cfortran.h + cimdOmp.cc + cimdOmp.h + cmortable_parser.cc + color.cc + color.h + commandline.cc + commandline.h + compare.h + const.h + constants.cc + constants.h + convert_units.cc + convert_units.h + cthread_debug.cc + cthread_debug.h + custom_modules.cc + custom_modules.h + dcw_reader.cc + dcw_reader.h + datarangelist.h + datetime.cc + datetime.h + dmemory.h + ecacore.cc + ecacore.h + ecautil.cc + ecautil.h + eigen_solution.cc + eigen_solution.h + expr.cc + expr.h + expr_fun.cc + expr_fun.h + expr_lex.cc + expr_yacc.cc + expr_yacc.hh + factory.h + factory.cc + field.cc + field.h + field_functions.h + field2.cc + field2_complex.cc + fieldc.cc + fieldc_complex.cc + field_memory.cc + field_meridional.cc + field_zonal.cc + field_vinterp.cc + field_vinterp.h + fileStream.cc + fileStream.h + fill_1d.cc + fill_1d.h + eof_mode.cc + eof_mode.h + gaussian_latitudes.c + gaussian_latitudes.h + getMemorySize.c + getRSS.c + grid_area.cc + grid_define.cc + grid_define.h + grid_from_name.cc + grid_gme.cc + grid_icosphere.cc + grid_point_search.cc + grid_point_search.h + grid_print.cc + grid_read.cc + grid_read_pingo.cc + grid_read_pingo.h + griddes.cc + griddes.h + griddes_h5.cc + griddes_nc.cc + hetaeta.cc + hetaeta.h + institution.cc + institution.h + interpol.cc + interpol.h + knn_weights.h + libncl.h + listbuffer.h + mapping.cc + mapping.h + matrix_view.h + merge_axis.cc + merge_axis.h + module_info.cc + module_info.h + modules.cc + modules.h + mpim_grid/grid_convert.h + mpim_grid/grid_proj.cc + mpim_grid/grid_proj.h + mpim_grid/grid_rot.cc + mpim_grid/grid_rot.h + mpim_grid/grid_healpix.cc + mpim_grid/grid_healpix.h + mpim_grid/gridreference.cc + mpim_grid/gridreference.h + mpim_grid/mpim_grid.cc + mpim_grid/mpim_grid.h + mpmo.cc + mpmo.h + mpmo_color.cc + mpmo_color.h + namelist.cc + namelist.h + nanoflann.hpp + operator_help.cc + operator_help.h + par_io.cc + par_io.h + param_conversion.cc + param_conversion.h + parse_literals.cc + parse_literals.h + percentiles.cc + percentiles.h + percentiles_hist.cc + percentiles_hist.h + pipe.cc + pipe.h + pipeStream.cc + pipeStream.h + pmlist.cc + pmlist.h + printinfo.cc + printinfo.h + process.cc + process.h + processManager.cc + processManager.h + parser.h + parser.cc + node.cc + node.h + process_int.cc + process_int.h + progress.cc + progress.h + pthread_debug.cc + pthread_debug.h + region.h + region.cc + remap.h + remap_bicubic.cc + remap_bilinear.cc + remap_cell_search.cc + remap_conserv.cc + remap_conserv_scrip.cc + remap_distwgt.cc + remap_grid_cell_search.cc + remap_grid_cell_search.h + remap_point_search.cc + remap_scrip_io.cc + remap_search_latbins.cc + remap_search_reg2d.cc + remap_store_link.cc + remap_store_link.h + remap_store_link_cnsrv.cc + remap_store_link_cnsrv.h + remap_utils.cc + remap_utils.h + remap_vars.cc + remap_vars.h + remaplib.cc + remapsort.cc + selboxinfo.h + sellist.cc + sellist.h + specspace.cc + specspace.h + statistic.cc + statistic.h + stdnametable.cc + stdnametable.h + table.cc + table.h + timer.cc + timer.h + transform.h + util_fileextensions.cc + util_fileextensions.h + util_files.cc + util_files.h + util_string.cc + util_string.h + util_wildcards.cc + util_wildcards.h + util_date.h + varray.cc + varray.h + vector3d.h + verifygrid.h + vertical_interp.cc + vertical_interp.h + vertint_util.h + vertint_util.cc + zaxis_print.cc +) + +list( APPEND cdolib_src_files + json/jsmn.h + json/jsmn.c +) + +list( APPEND cdolib_src_files + kdtreelib/kdtree.h + kdtreelib/kdtree_cartesian.cc + kdtreelib/kdtree_common.cc + kdtreelib/kdtree_spherical.cc + kdtreelib/qsort.cc + kdtreelib/pmergesort.cc + kdtreelib/pqueue.cc + kdtreelib/pqueue.h +) + +list( APPEND cdolib_src_files + etopo.dat temp.dat mask.dat +) + +add_library(cdolib + ${cdolib_src_files} +) + +include_directories("${PROJECT_SOURCE_DIR}/src/mpim_grid" + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/libcdi/src" +) + +target_compile_definitions(cdolib PUBLIC HAVE_CONFIG_H restrict= CDI_SIZE_TYPE=size_t YAC_FOR_CDO) + + +list( APPEND cdo_src_files + cdo.cc +) + +list( APPEND cdo_src_files + Adisit.cc + Afterburner.cc + Arith.cc + Arithc.cc + Arithdays.cc + Arithlat.cc + Bitrounding.cc + Cat.cc + CDIread.cc + CDItest.cc + CDIwrite.cc + Change.cc + Change_e5slm.cc + Cloudlayer.cc + CMOR.cc + CMOR_lite.cc + CMOR_table.cc + Collgrid.cc + Command.cc + Comp.cc + Compc.cc + Complextorect.cc + Cond.cc + Cond2.cc + Condc.cc + Consecstat.cc + Copy.cc + DCW_util.cc + Dayarith.cc + Deltat.cc + Deltime.cc + Depth.cc + Derivepar.cc + Detrend.cc + Diff.cc + Distgrid.cc + Duplicate.cc + EOFs.cc + Eof3d.cc + EcaIndices.cc + EcaEtccdi.cc + Echam5ini.cc + Enlarge.cc + Enlargegrid.cc + Ensstat.cc + Ensstat3.cc + Ensval.cc + Eofcoeff.cc + Eofcoeff3d.cc + EstFreq.cc + Exprf.cc + FC.cc + Filedes.cc + Fillmiss.cc + Filter.cc + Fldrms.cc + Fldstat.cc + Fldstat2.cc + Fourier.cc + Gengrid.cc + Getgridcell.cc + Gradsdes.cc + Gridboxstat.cc + Gridcell.cc + Gridsearch.cc + Harmonic.cc + Healpix.cc + Hi.cc + Histogram.cc + Importamsr.cc + Importbinary.cc + Importcmsaf.cc + Importobs.cc + Importfv3grid.cc + Info.cc + Input.cc + Intgrid.cc + Intgridtraj.cc + Intlevel.cc + Intlevel3d.cc + Intntime.cc + Inttime.cc + Intyear.cc + Invert.cc + Invertlev.cc + Lic.cc + Longinfo.cc + MapReduce.cc + Maskbox.cc + Mastrfu.cc + Math.cc + Merge.cc + Mergegrid.cc + Mergetime.cc + Merstat.cc + Monarith.cc + Mrotuv.cc + Mrotuvb.cc + NCL_wind.cc + Ninfo.cc + Nmldump.cc + Output.cc + Outputgmt.cc + Pack.cc + Pardup.cc + Pinfo.cc + Pressure.cc + Query.cc + Recttocomplex.cc + Regres.cc + Remapeta.cc + Remapgrid.cc + Remapweights.cc + Remapstat.cc + Replace.cc + Replacevalues.cc + Rhopot.cc + Rotuv.cc + Runpctl.cc + Runstat.cc + Samplegrid.cc + Samplegridicon.cc + Seascount.cc + Seaspctl.cc + Seasstat.cc + Seasmonstat.cc + Selbox.cc + Selgridcell.cc + Select.cc + Selmulti.cc + Seloperator.cc + Selrec.cc + Selregion.cc + Selsurface.cc + Seltime.cc + Selvar.cc + Selyearidx.cc + Set.cc + Setattribute.cc + Setbox.cc + Setgrid.cc + Setgridcell.cc + Sethalo.cc + Setmiss.cc + Setpartab.cc + Setrcaname.cc + Settime.cc + Setzaxis.cc + Shiftxy.cc + Showinfo.cc + Showattribute.h + Showattribute.cc + Sinfo.cc + Smooth.cc + Sort.cc + Sorttimestamp.cc + Specinfo.cc + Spectral.cc + Spectrum.cc + Split.cc + Splitdate.cc + Splitrec.cc + Splittime.cc + Splityear.cc + Tee.cc + Test.cc + Tests.cc + Timcount.cc + Timcumsum.cc + Timfillmiss.cc + Timpctl.cc + Timselpctl.cc + Timselstat.cc + Timsort.cc + Timstat.cc + Timstat2.cc + Timstat3.cc + Tinfo.cc + Tocomplex.cc + Transpose.cc + Trend.cc + Trendarith.cc + Tstepcount.cc + Unpack.cc + Vargen.cc + Varrms.cc + Varsstat.cc + Vertfillmiss.cc + Vertintap.cc + Vertintgh.cc + Vertintml.cc + Vertintzs.cc + Vertstat.cc + Vertcum.cc + Vertwind.cc + Verifygrid.cc + Verifyweights.cc + Wct.cc + Wind.cc + WindTrans.cc + Writegrid.cc + Writerandom.cc + XTimstat.cc + Yeararith.cc + Yearmonstat.cc + Ydayarith.cc + Ydaypctl.cc + Ydaystat.cc + Ydrunpctl.cc + Ydrunstat.cc + Yhourarith.cc + Yhourstat.cc + Ymonarith.cc + Ymoncomp.cc + Ymonpctl.cc + Ymonstat.cc + Yseaspctl.cc + Yseasstat.cc + Zonstat.cc +) + +add_executable(cdo + ${cdo_src_files} +) + +target_compile_definitions(cdo PUBLIC HAVE_CONFIG_H restrict= CDI_SIZE_TYPE=size_t YAC_FOR_CDO) + +target_link_libraries(cdo PUBLIC cdilib cdolib yac gradsdes healpix ) diff --git a/src/Cat.cc b/src/Cat.cc index 6fec6b9fb1c048daaaec604aec6d8cfcfcf9d97c..aff6e36a3831951e4b697b006c4834f8eb522fa6 100644 --- a/src/Cat.cc +++ b/src/Cat.cc @@ -21,13 +21,26 @@ #include "progress.h" #include "cdo_options.h" -class ModuleCat +class Cat : public Process { enum class StreamMode { APPEND, CREATE }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Cat", + .operators = { { "cat", CopyHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Cat> registration = RegisterEntry<Cat>(module); + StreamMode streamMode = StreamMode::APPEND; bool hasConstVars = true; bool dataIsUnchanged = false; @@ -40,10 +53,8 @@ class ModuleCat public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); dataIsUnchanged = data_is_unchanged(); @@ -53,6 +64,7 @@ public: progress::init(); } + void run() { @@ -74,8 +86,8 @@ public: auto ntsteps = vlistNtsteps(vlistID1); if (ntsteps == 1 && varList_numVaryingVars(varList1) == 0) ntsteps = 0; - bool file_exists = Options::cdoOverwriteMode ? false : FileUtils::file_exists(cdo_get_stream_name(nfiles)); - if (file_exists) + std::string ofilename = cdo_get_stream_name(nfiles); + if (!Options::cdoOverwriteMode && FileUtils::file_exists(ofilename)) { streamID2 = cdo_open_append(nfiles); @@ -91,7 +103,7 @@ public: } else { - if (Options::cdoVerbose) cdo_print("Output file doesn't exist, creating: %s", cdo_get_stream_name(nfiles)); + if (Options::cdoVerbose) cdo_print("Output file doesn't exist, creating: %s", ofilename); streamMode = StreamMode::CREATE; streamID2 = cdo_open_write(nfiles); @@ -152,6 +164,7 @@ public: if (Options::cdoVerbose) cdo_print("Processed file: %s %.2f seconds", cdo_get_stream_name(indf), timer.elapsed()); } } + void close() { @@ -162,17 +175,5 @@ public: vlistDestroy(vlistID2); taxisDestroy(taxisID2); } - - cdo_finish(); } }; -void * -Cat(void *process) -{ - ModuleCat cat; - cat.init(process); - cat.run(); - cat.close(); - - return nullptr; -} diff --git a/src/Change.cc b/src/Change.cc index eda2638c079d39ed73e8719b3a805ed857e8c718..c505b6f7cafeaf82e3d7d4aa1d1df61ddfe03ea9 100644 --- a/src/Change.cc +++ b/src/Change.cc @@ -301,8 +301,29 @@ changeLtype(int vlistID2, int nch, const std::vector<int> &chltypes) } } -class ModuleChange +class Change : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Change", + .operators = { { "chcode", 0, 0, "pairs of old and new code numbers", ChangeHelp }, + { "chtabnum", 0, 0, "pairs of old and new GRIB1 table numbers", ChangeHelp }, + { "chparam", 0, 0, "pairs of old and new parameter identifiers", ChangeHelp }, + { "chname", 0, 0, "pairs of old and new variable names", ChangeHelp }, + { "chunit", 0, 0, "pairs of old and new variable units", ChangeHelp }, + { "chlevel", 0, 0, "pairs of old and new levels", ChangeHelp }, + { "chlevelc", 0, 0, "code number, old and new level", ChangeHelp }, + { "chlevelv", 0, 0, "variable name, old and new level", ChangeHelp }, + { "chltype", 0, 0, "pairs of old and new level type", ChangeHelp } }, + .aliases = { { "chvar", "chname" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Change> registration = RegisterEntry<Change>(module); + + int CHCODE, CHTABNUM, CHPARAM, CHNAME, CHUNIT, CHLEVEL, CHLEVELC, CHLEVELV, CHLTYPE; const char *chname = nullptr; int chcode = 0; std::vector<const char *> chnames; @@ -320,21 +341,17 @@ class ModuleChange public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - auto CHCODE = cdo_operator_add("chcode", 0, 0, "pairs of old and new code numbers"); - auto CHTABNUM = cdo_operator_add("chtabnum", 0, 0, "pairs of old and new GRIB1 table numbers"); - auto CHPARAM = cdo_operator_add("chparam", 0, 0, "pairs of old and new parameter identifiers"); - auto CHNAME = cdo_operator_add("chname", 0, 0, "pairs of old and new variable names"); - auto CHUNIT = cdo_operator_add("chunit", 0, 0, "pairs of old and new variable units"); - auto CHLEVEL = cdo_operator_add("chlevel", 0, 0, "pairs of old and new levels"); - auto CHLEVELC = cdo_operator_add("chlevelc", 0, 0, "code number, old and new level"); - auto CHLEVELV = cdo_operator_add("chlevelv", 0, 0, "variable name, old and new level"); - auto CHLTYPE = cdo_operator_add("chltype", 0, 0, "pairs of old and new type"); - // clang-format on + CHCODE = module.get_id("chcode"); + CHTABNUM = module.get_id("chtabnum"); + CHPARAM = module.get_id("chparam"); + CHNAME = module.get_id("chname"); + CHUNIT = module.get_id("chunit"); + CHLEVEL = module.get_id("chlevel"); + CHLEVELC = module.get_id("chlevelc"); + CHLEVELV = module.get_id("chlevelv"); + CHLTYPE = module.get_id("chltype"); auto operatorID = cdo_operator_id(); @@ -411,6 +428,7 @@ public: streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); } + void run() { @@ -437,24 +455,11 @@ public: tsID++; } } + void close() { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Change(void *process) -{ - ModuleChange change; - - change.init(process); - change.run(); - change.close(); - - return nullptr; -} diff --git a/src/Change_e5slm.cc b/src/Change_e5slm.cc index 0106913387cbb67626b30a6bb23abc50c45eda8a..f0a07d1d2797bea68ce6fecfdfa38497e887636f 100644 --- a/src/Change_e5slm.cc +++ b/src/Change_e5slm.cc @@ -16,11 +16,22 @@ #include "process_int.h" #include "cdi_lockedIO.h" -class ModuleChange_e5slm +class Change_e5slm : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Change_e5slm", + .operators = { { "change_e5slm"}, { "change_e5lsm"}, { "change_e5mask"} }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Change_e5slm> registration = RegisterEntry<Change_e5slm>(module); int nrecs; int varID, levelID; - size_t nmiss; + size_t numMissVals; CdoStreamID streamID1; int taxisID1; @@ -38,9 +49,8 @@ class ModuleChange_e5slm public: void - init(void *process) + init() { - cdo_initialize(process); streamID1 = cdo_open_read(0); @@ -72,9 +82,9 @@ public: streamInqTimestep(streamIDslm, 0); streamInqRecord(streamIDslm, &varID, &levelID); - streamReadRecord(streamIDslm, cland.data(), &nmiss); + streamReadRecord(streamIDslm, cland.data(), &numMissVals); - if (nmiss) cdo_abort("SLM with missing values are unsupported!"); + if (numMissVals) cdo_abort("SLM with missing values are unsupported!"); const auto mm = varray_min_max(cland); if (mm.min < 0 || mm.max > 1) cdo_warning("Values of SLM out of bounds! (minval=%g, maxval=%g)", mm.min, mm.max); @@ -126,7 +136,7 @@ public: for (int recID = 0; recID < nrecs; ++recID) { cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, array.data(), &nmiss); + cdo_read_record(streamID1, array.data(), &numMissVals); auto code = codes[varID]; if (code == 172) @@ -154,7 +164,7 @@ public: } cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); } tsID++; @@ -165,17 +175,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Change_e5slm(void *process) -{ - ModuleChange_e5slm change_e5slm; - change_e5slm.init(process); - change_e5slm.run(); - change_e5slm.close(); - return nullptr; -} diff --git a/src/Cloudlayer.cc b/src/Cloudlayer.cc index 3b23f08064ae76510ab81a46a476ae219d15ea8d..25cf9c84304a83537742cd34d278acc1fbe78b6e 100644 --- a/src/Cloudlayer.cc +++ b/src/Cloudlayer.cc @@ -86,8 +86,19 @@ pl_index(long &maxLevIndex, long &minLevIndex, double pmax, double pmin, long nl } } -class ModuleCloudlayer +class Cloudlayer : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Cloudlayer", + .operators = { { "cloudlayer"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Cloudlayer> registration = RegisterEntry<Cloudlayer>(module); static const int NumVars = 3; int gridID, zaxisID; bool zrev = false; @@ -114,9 +125,8 @@ class ModuleCloudlayer public: void - init(void *process) + init() { - cdo_initialize(process); if (cdo_operator_argc() > 0) { @@ -291,9 +301,9 @@ public: if (varID == aclcacID) { - size_t nmiss; - cdo_read_record(streamID1, aclcac.data() + offset, &nmiss); - if (nmiss != 0) cdo_abort("Missing values unsupported!"); + size_t numMissVals; + cdo_read_record(streamID1, aclcac.data() + offset, &numMissVals); + if (numMissVals != 0) cdo_abort("Missing values unsupported!"); } } @@ -309,10 +319,10 @@ public: for (int varID = 0; varID < nvars2; ++varID) { - auto nmiss = varray_num_mv(gridsize, cloud[varID], missval); + auto numMissVals = varray_num_mv(gridsize, cloud[varID], missval); cdo_def_record(streamID2, varID, 0); - cdo_write_record(streamID2, cloud[varID].data(), nmiss); + cdo_write_record(streamID2, cloud[varID].data(), numMissVals); } tsID++; @@ -325,18 +335,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -Cloudlayer(void *process) -{ - ModuleCloudlayer cloudlayer; - - cloudlayer.init(process); - cloudlayer.run(); - cloudlayer.close(); - - return nullptr; -} diff --git a/src/Collgrid.cc b/src/Collgrid.cc index 2386dba50e02d9a7afc59d8fd6dea8e5b2159764..c8121c5eaf19b9455538d19088e40356333fdb2c 100644 --- a/src/Collgrid.cc +++ b/src/Collgrid.cc @@ -5,8 +5,6 @@ */ -#include <algorithm> // sort - #include <cdi.h> #include "cdo_rlimit.h" @@ -41,12 +39,6 @@ struct xyinfoType int id = -1; }; -static bool -cmpx(const xyinfoType &a, const xyinfoType &b) -{ - return (a.x < b.x); -} - static bool cmpxy_lt(const xyinfoType &a, const xyinfoType &b) { @@ -138,14 +130,13 @@ gen_coll_grid(int ngrids, int nfiles, std::vector<CollgridInfo> &collgridInfo, i if (isRegular) { - std::sort(xyinfo.begin(), xyinfo.end(), cmpx); + ranges::sort(xyinfo, {}, &xyinfoType::x); if (Options::cdoVerbose) for (int fileID = 0; fileID < nfiles; ++fileID) printf("2 %d %g %g \n", xyinfo[fileID].id, xyinfo[fileID].x, xyinfo[fileID].y); - auto cmpxy = isSouthNorth ? cmpxy_lt : cmpxy_gt; - std::sort(xyinfo.begin(), xyinfo.end(), cmpxy); + ranges::sort(xyinfo, isSouthNorth ? cmpxy_lt : cmpxy_gt); if (Options::cdoVerbose) for (int fileID = 0; fileID < nfiles; ++fileID) @@ -430,8 +421,20 @@ select_vars(const std::vector<bool> &selectedVars, int vlistID1, const VarList & if (numVars == 0) cdo_abort("No variables selected!"); } -class ModuleCollgrid +class Collgrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Collgrid", + .operators = { { "collgrid", CollgridHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Collgrid> registration = RegisterEntry<Collgrid>(module); + int nxblocks = -1; CdoStreamID streamID1; @@ -454,10 +457,8 @@ class ModuleCollgrid public: void - init(void *process) + init() { - cdo_initialize(process); - nfiles = cdo_stream_cnt() - 1; std::string ofilename = cdo_get_stream_name(nfiles); @@ -482,7 +483,8 @@ public: vlistClearFlag(vlistID1); // check that the contents is always the same - for (int fileID = 1; fileID < nfiles; ++fileID) vlist_compare(vlistID1, collgridInfo[fileID].vlistID, CmpVlist::Name | CmpVlist::NumLevels); + for (int fileID = 1; fileID < nfiles; ++fileID) + vlist_compare(vlistID1, collgridInfo[fileID].vlistID, CmpVlist::Name | CmpVlist::NumLevels); auto nsel = cdo_operator_argc(); int noff = 0; @@ -615,8 +617,8 @@ public: { auto patchSize = collgridInfo[fileID].varList[varID].gridsize; if (cellIndex.size() < patchSize) cellIndex.resize(patchSize); - size_t nmiss; - cdo_read_record(collgridInfo[fileID].streamID, cellIndex.data(), &nmiss); + size_t numMissVals; + cdo_read_record(collgridInfo[fileID].streamID, cellIndex.data(), &numMissVals); for (size_t i = 0; i < patchSize; ++i) collgridInfo[fileID].cellIndex[gindex][i] = std::lround(cellIndex[i]) - 1; } @@ -665,18 +667,5 @@ public: for (int fileID = 0; fileID < nfiles; ++fileID) cdo_stream_close(collgridInfo[fileID].streamID); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Collgrid(void *process) -{ - ModuleCollgrid collgrid; - collgrid.init(process); - collgrid.run(); - collgrid.close(); - - return nullptr; -} diff --git a/src/Command.cc b/src/Command.cc index c6ef001a2885e968d84b9507e4addc3c789537e2..508744c9654aa9012ef850c3a40f17cd8d5789ca 100644 --- a/src/Command.cc +++ b/src/Command.cc @@ -160,13 +160,13 @@ com_stat(const std::string &arg) auto levelID = (nlevels > 1) ? gl_levelID : 0; - size_t nmiss; - streamReadVarSlice(gl_streamID, gl_varID, levelID, gl_data.data(), &nmiss); + size_t numMissVals; + streamReadVarSlice(gl_streamID, gl_varID, levelID, gl_data.data(), &numMissVals); auto mmm = varray_min_max_mean_mv(gridsize, gl_data, missval); - fprintf(stdout, "%s: z=%d t=%d size=%zu nmiss=%zu min=%.5g mean=%.5g max=%.5g [%.2fs]\n", name, levelID + 1, tsID + 1, - gridsize, nmiss, mmm.min, mmm.mean, mmm.max, stepTimer.elapsed()); + fprintf(stdout, "%s: z=%d t=%d size=%zu numMissVals=%zu min=%.5g mean=%.5g max=%.5g [%.2fs]\n", name, levelID + 1, tsID + 1, + gridsize, numMissVals, mmm.min, mmm.mean, mmm.max, stepTimer.elapsed()); } } @@ -389,9 +389,9 @@ execute_line(const std::string &line) // Isolate the command word. int i = 0; - while (line[i] && isspace(line[i])) i++; + while (line[i] && std::isspace(line[i])) i++; int pos = i; - while (line[i] && !isspace(line[i])) i++; + while (line[i] && !std::isspace(line[i])) i++; int count = i; auto word = line.substr(pos, count); @@ -403,7 +403,7 @@ execute_line(const std::string &line) return -1; } // Get argument to command, if any. - while (isspace(line[i])) i++; + while (std::isspace(line[i])) i++; pos = i; auto args = line.substr(pos); @@ -446,9 +446,9 @@ peakRSS_string() } static void -read_line(const std::string &prompt, std::string &line) +read_line(const std::string &p_prompt, std::string &line) { - fputs(prompt.c_str(), stdout); + fputs(p_prompt.c_str(), stdout); if (Options::cdoVerbose) { fputs(" [", stdout); @@ -499,13 +499,24 @@ run_demo() } } -class ModuleCommand +class Command : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Command", + .operators = { { "command"}, { "com"}, { "cmd"} }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Command> registration = RegisterEntry<Command>(module); + public: void - init(void *process) + init() { - cdo_initialize(process); if (cdo_operator_argc() == 1) { @@ -528,11 +539,11 @@ public: else { // Loop reading and executing lines until the user quits. - const std::string prompt = "cdo cmd"; + const std::string custom_prompt = "cdo cmd"; while (!Done) { std::string line; - read_line(prompt, line); + read_line(custom_prompt, line); execute_line(trim(line)); } } @@ -541,17 +552,5 @@ public: close() { streamClose(gl_streamID); - cdo_finish(); } }; - -void * -Command(void *process) -{ - ModuleCommand command; - command.init(process); - command.run(); - command.close(); - - return nullptr; -} diff --git a/src/Comp.cc b/src/Comp.cc index 44b5ab021cf994a8cbbee738677f88c56d7241f4..47069a33e792293239f5cbd88d16d8664505c7a2 100644 --- a/src/Comp.cc +++ b/src/Comp.cc @@ -43,7 +43,7 @@ static auto func_comp } }; -class ModuleComp +class Comp : public Process { enum { @@ -51,6 +51,23 @@ class ModuleComp FILL_TS, FILL_REC }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Comp", + .operators = { { "eq", FieldFunc_EQ, 0, CompHelp }, + { "ne", FieldFunc_NE, 0, CompHelp }, + { "le", FieldFunc_LE, 0, CompHelp }, + { "lt", FieldFunc_LT, 0, CompHelp }, + { "ge", FieldFunc_GE, 0, CompHelp }, + { "gt", FieldFunc_GT, 0, CompHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Comp> registration = RegisterEntry<Comp>(module); int filltype = FILL_NONE; Varray2D<double> vardata; @@ -71,16 +88,8 @@ class ModuleComp public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("eq", FieldFunc_EQ, 0, nullptr); - cdo_operator_add("ne", FieldFunc_NE, 0, nullptr); - cdo_operator_add("le", FieldFunc_LE, 0, nullptr); - cdo_operator_add("lt", FieldFunc_LT, 0, nullptr); - cdo_operator_add("ge", FieldFunc_GE, 0, nullptr); - cdo_operator_add("gt", FieldFunc_GT, 0, nullptr); auto operatorID = cdo_operator_id(); operFunc = cdo_operator_f1(operatorID); @@ -192,17 +201,17 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - size_t nmiss1 = 0, nmiss2 = 0; + size_t numMissVals1 = 0, numMissVals2 = 0; int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, arrayx1, &nmiss1); + cdo_read_record(streamID1, arrayx1, &numMissVals1); if (tsID == 0 || filltype == FILL_NONE) { if (recID == 0 || filltype != FILL_REC) { cdo_inq_record(streamID2, &varID, &levelID); - cdo_read_record(streamID2, arrayx2, &nmiss2); + cdo_read_record(streamID2, arrayx2, &numMissVals2); } if (filltype == FILL_TS) @@ -245,10 +254,10 @@ public: } } - if (nmiss1 > 0) cdo_check_missval(missval1, varList1[varID].name); - // if (nmiss2 > 0) cdo_check_missval(missval2, varList2[varID].name); + if (numMissVals1 > 0) cdo_check_missval(missval1, varList1[varID].name); + // if (numMissVals2 > 0) cdo_check_missval(missval2, varList2[varID].name); - auto hasMissvals = (nmiss1 > 0 || nmiss2 > 0); + auto hasMissvals = (numMissVals1 > 0 || numMissVals2 > 0); // clang-format off if (operFunc == FieldFunc_EQ) func_comp(hasMissvals, ngp, missval1, missval2, vaIn1, vaIn2, vaOut, binary_op_EQ); else if (operFunc == FieldFunc_NE) func_comp(hasMissvals, ngp, missval1, missval2, vaIn1, vaIn2, vaOut, binary_op_NE); @@ -259,9 +268,9 @@ public: else cdo_abort("Operator not implemented!"); // clang-format on - auto nmissOut = varray_num_mv(ngp, vaOut, missval1); + auto numMissValsOut = varray_num_mv(ngp, vaOut, missval1); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, vaOut.data(), nmissOut); + cdo_write_record(streamID3, vaOut.data(), numMissValsOut); } tsID++; @@ -274,18 +283,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Comp(void *process) -{ - ModuleComp comp; - comp.init(process); - comp.run(); - comp.close(); - - return nullptr; -} diff --git a/src/Compc.cc b/src/Compc.cc index 55d5f65fb55383f62929eba5319eab702b94202a..a6748e42a3bb00461976f5fa41147f73b5f9e5c3 100644 --- a/src/Compc.cc +++ b/src/Compc.cc @@ -28,8 +28,7 @@ static auto func_compc = [](auto hasMissvals, auto n, auto mv, auto &v, const au { auto constantIsMissval = dbl_is_equal(cVal, mv); if (std::isnan(mv)) - for (size_t i = 0; i < n; ++i) - v[i] = (dbl_is_equal(v[i], mv) || constantIsMissval) ? mv : binary_operator(v[i], cVal); + for (size_t i = 0; i < n; ++i) v[i] = (dbl_is_equal(v[i], mv) || constantIsMissval) ? mv : binary_operator(v[i], cVal); else for (size_t i = 0; i < n; ++i) v[i] = (is_equal(v[i], mv) || constantIsMissval) ? mv : binary_operator(v[i], cVal); } @@ -63,19 +62,24 @@ comp_function(Field &field, int operFunc, bool hasMissvals, double rconst) comp_function(operFunc, hasMissvals, field.size, field.missval, field.vec_d, rconst); } -static void -add_operators(void) -{ - cdo_operator_add("eqc", FieldFunc_EQ, 0, nullptr); - cdo_operator_add("nec", FieldFunc_NE, 0, nullptr); - cdo_operator_add("lec", FieldFunc_LE, 0, nullptr); - cdo_operator_add("ltc", FieldFunc_LT, 0, nullptr); - cdo_operator_add("gec", FieldFunc_GE, 0, nullptr); - cdo_operator_add("gtc", FieldFunc_GT, 0, nullptr); -} - -class ModuleCompc +class Compc : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Compc", + .operators = { { "eqc", FieldFunc_EQ, 0, CompcHelp }, + { "nec", FieldFunc_NE, 0, CompcHelp }, + { "lec", FieldFunc_LE, 0, CompcHelp }, + { "ltc", FieldFunc_LT, 0, CompcHelp }, + { "gec", FieldFunc_GE, 0, CompcHelp }, + { "gtc", FieldFunc_GT, 0, CompcHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Compc> registration = RegisterEntry<Compc>(module); CdoStreamID streamID1; int taxisID1; @@ -89,11 +93,8 @@ class ModuleCompc public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operFunc = cdo_operator_f1(operatorID); @@ -142,10 +143,10 @@ public: cdo_read_record(streamID1, field); auto missval = field.missval; - auto nmiss = field.nmiss; - auto hasMissvals = (nmiss > 0 || dbl_is_equal(rconst, missval)); + auto numMissVals = field.numMissVals; + auto hasMissvals = (numMissVals > 0 || dbl_is_equal(rconst, missval)); - if (nmiss > 0) cdo_check_missval(missval, varList[varID].name); + if (numMissVals > 0) cdo_check_missval(missval, varList[varID].name); comp_function(field, operFunc, hasMissvals, rconst); @@ -164,18 +165,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Compc(void *process) -{ - ModuleCompc compc; - compc.init(process); - compc.run(); - compc.close(); - - return nullptr; -} diff --git a/src/Complextorect.cc b/src/Complextorect.cc index 413b1c2a016a4609e20880456e8e4ff922eeb2cd..ffd26b59c0015974b80cad22e58598c64b44b34f 100644 --- a/src/Complextorect.cc +++ b/src/Complextorect.cc @@ -10,8 +10,20 @@ #include "arithmetic.h" #include "process_int.h" -class ModuleComplextorect +class Complextorect : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Complextorect", + .operators = { { "complextorect"}, { "complextopol"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_COMP, // Allowed number type + .constraints = { 1, 2, OnlyFirst }, + }; + inline static RegisterEntry<Complextorect> registration = RegisterEntry<Complextorect>(module); + int COMPLEXTORECT, COMPLEXTOPOL; CdoStreamID streamID1; int taxisID1; @@ -31,16 +43,13 @@ class ModuleComplextorect Varray<double> array3; VarList varList1; - int COMPLEXTORECT, COMPLEXTOPOL; - public: void - init(void *process) + init() { - cdo_initialize(process); - COMPLEXTORECT = cdo_operator_add("complextorect", 0, 0, nullptr); - COMPLEXTOPOL = cdo_operator_add("complextopol", 0, 0, nullptr); + COMPLEXTORECT = module.get_id("complextorect"); + COMPLEXTOPOL = module.get_id("complextopol"); operatorID = cdo_operator_id(); @@ -104,8 +113,8 @@ public: auto gridsize = varList1[varID].gridsize; - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); auto is_EQ = dbl_is_equal; auto missval1 = varList1[varID].missval; @@ -130,8 +139,8 @@ public: } } - cdo_write_record(streamID2, array2.data(), nmiss); - cdo_write_record(streamID3, array3.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); + cdo_write_record(streamID3, array3.data(), numMissVals); } tsID++; @@ -147,17 +156,5 @@ public: vlistDestroy(vlistID2); vlistDestroy(vlistID3); - - cdo_finish(); } }; -void * -Complextorect(void *process) -{ - ModuleComplextorect complextorect; - complextorect.init(process); - complextorect.run(); - complextorect.close(); - - return nullptr; -} diff --git a/src/Cond.cc b/src/Cond.cc index 1ef590626f50c132b42c57e3166763c8243cec93..cffc7beb029d2e2b7f747fcc37623752715f5d19 100644 --- a/src/Cond.cc +++ b/src/Cond.cc @@ -37,7 +37,7 @@ operator_IFNOTTHEN(size_t n, double mv1, double mv2, const Varray<double> &vIn1, for (size_t i = 0; i < n; ++i) vOut[i] = (!is_equal(vIn1[i], mv1) && is_equal(vIn1[i], 0.0)) ? vIn2[i] : mv2; } -class ModuleCond +class Cond : public Process { enum { @@ -45,9 +45,22 @@ class ModuleCond FILL_TS, FILL_REC }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Cond", + .operators = { { "ifthen", CondHelp }, { "ifnotthen", CondHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Cond> registration = RegisterEntry<Cond>(module); + int IFTHEN, IFNOTTHEN; int filltype = FILL_NONE; double missval1 = -9.E33; - Varray2D<size_t> varnmiss1; + Varray2D<size_t> varnumMissVals1; Varray2D<double> vardata1; CdoStreamID streamID1; @@ -62,17 +75,15 @@ class ModuleCond VarList varList1, varList2; Varray<double> vaIn1, vaIn2, vaOut; - int IFTHEN, IFNOTTHEN; public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - IFTHEN = cdo_operator_add("ifthen", 0, 0, nullptr); - IFNOTTHEN = cdo_operator_add("ifnotthen", 0, 0, nullptr); +IFTHEN = module.get_id("ifthen"); +IFNOTTHEN = module.get_id("ifnotthen"); // clang-format on operatorID = cdo_operator_id(); @@ -127,7 +138,7 @@ public: filltype = FILL_TS; cdo_print("Filling up stream1 >%s< by copying the first timestep.", cdo_get_stream_name(0)); - cdo_fill_ts(vlistID1, vardata1, varnmiss1); + cdo_fill_ts(vlistID1, vardata1, varnumMissVals1); } } } @@ -154,36 +165,36 @@ public: { int varID, levelID; cdo_inq_record(streamID2, &varID, &levelID); - size_t nmiss1 = 0, nmiss2; - cdo_read_record(streamID2, &vaIn2[0], &nmiss2); + size_t numMissVals1 = 0, numMissVals2; + cdo_read_record(streamID2, &vaIn2[0], &numMissVals2); if (tsID == 0 || filltype == FILL_NONE) { if (recID == 0 || filltype != FILL_REC) { cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, &vaIn1[0], &nmiss1); + cdo_read_record(streamID1, &vaIn1[0], &numMissVals1); } if (filltype == FILL_TS) { auto offset = varList1[varID].gridsize * levelID; array_copy(varList1[varID].gridsize, &vaIn1[0], &vardata1[varID][offset]); - varnmiss1[varID][levelID] = nmiss1; + varnumMissVals1[varID][levelID] = numMissVals1; } } else if (filltype == FILL_TS) { auto offset = varList1[varID].gridsize * levelID; array_copy(varList1[varID].gridsize, &vardata1[varID][offset], &vaIn1[0]); - nmiss1 = varnmiss1[varID][levelID]; + numMissVals1 = varnumMissVals1[varID][levelID]; } auto ngp = varList2[varID].gridsize; auto missval2 = varList2[varID].missval; if (recID == 0 || filltype != FILL_REC) missval1 = varList1[varID].missval; - if (nmiss1 > 0) cdo_check_missval(missval1, varList1[varID].name); + if (numMissVals1 > 0) cdo_check_missval(missval1, varList1[varID].name); // clang-format off if (operatorID == IFTHEN) operator_IFTHEN(ngp, missval1, missval2, vaIn1, vaIn2, vaOut); @@ -191,9 +202,9 @@ public: else cdo_abort("Operator not implemented!"); // clang-format on - auto nmiss3 = varray_num_mv(ngp, vaOut, missval2); + auto numMissVals3 = varray_num_mv(ngp, vaOut, missval2); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, vaOut.data(), nmiss3); + cdo_write_record(streamID3, vaOut.data(), numMissVals3); } tsID++; @@ -206,18 +217,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Cond(void *process) -{ - ModuleCond cond; - cond.init(process); - cond.run(); - cond.close(); - - return nullptr; -} diff --git a/src/Cond2.cc b/src/Cond2.cc index c823d91a8f1adcd00d4d3f03a0d8454f15b120dd..ca1ffa20ef45d3fdbf43e0450204c2995fe62de1 100644 --- a/src/Cond2.cc +++ b/src/Cond2.cc @@ -18,7 +18,7 @@ #include "cdo_vlist.h" #include "cdo_fill.h" -class ModuleCond2 +class Cond2 : public Process { enum { @@ -27,10 +27,22 @@ class ModuleCond2 FILL_REC }; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Cond2", + .operators = { { "ifthenelse", Cond2Help } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Cond2> registration = RegisterEntry<Cond2>(module); + int filltype = FILL_NONE; double missval1 = -9.E33; - size_t nmiss1 = 0; - Varray2D<size_t> varnmiss1; + size_t numMissVals1 = 0; + Varray2D<size_t> varnumMissVals1; Varray2D<double> vardata1; CdoStreamID streamID1; @@ -45,11 +57,8 @@ class ModuleCond2 public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("ifthenelse", 0, 0, nullptr); operator_check_argc(0); @@ -107,7 +116,7 @@ public: filltype = FILL_TS; cdo_print("Filling up stream1 >%s< by copying the first timestep.", cdo_get_stream_name(0)); - cdo_fill_ts(vlistID1, vardata1, varnmiss1); + cdo_fill_ts(vlistID1, vardata1, varnumMissVals1); } } } @@ -137,18 +146,18 @@ public: { int varID, levelID; cdo_inq_record(streamID2, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID2, &array2[0], &nmiss); + size_t numMissVals; + cdo_read_record(streamID2, &array2[0], &numMissVals); cdo_inq_record(streamID3, &varID, &levelID); - cdo_read_record(streamID3, &array3[0], &nmiss); + cdo_read_record(streamID3, &array3[0], &numMissVals); if (tsID == 0 || filltype == FILL_NONE) { if (recID == 0 || filltype != FILL_REC) { cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, &array1[0], &nmiss1); + cdo_read_record(streamID1, &array1[0], &numMissVals1); } if (filltype == FILL_TS) @@ -156,7 +165,7 @@ public: auto gridsize = varList1[varID].gridsize; auto offset = gridsize * levelID; array_copy(gridsize, &array1[0], &vardata1[varID][offset]); - varnmiss1[varID][levelID] = nmiss1; + varnumMissVals1[varID][levelID] = numMissVals1; } } else if (filltype == FILL_TS) @@ -164,21 +173,21 @@ public: auto gridsize = varList1[varID].gridsize; auto offset = gridsize * levelID; array_copy(gridsize, &vardata1[varID][offset], &array1[0]); - nmiss1 = varnmiss1[varID][levelID]; + numMissVals1 = varnumMissVals1[varID][levelID]; } auto gridsize = varList2[varID].gridsize; auto missval2 = varList2[varID].missval; if (recID == 0 || filltype != FILL_REC) missval1 = varList1[varID].missval; - if (nmiss1 > 0) cdo_check_missval(missval1, varList1[varID].name); + if (numMissVals1 > 0) cdo_check_missval(missval1, varList1[varID].name); for (size_t i = 0; i < gridsize; ++i) array4[i] = DBL_IS_EQUAL(array1[i], missval1) ? missval2 : !DBL_IS_EQUAL(array1[i], 0.) ? array2[i] : array3[i]; - nmiss = varray_num_mv(gridsize, array4, missval2); + numMissVals = varray_num_mv(gridsize, array4, missval2); cdo_def_record(streamID4, varID, levelID); - cdo_write_record(streamID4, array4.data(), nmiss); + cdo_write_record(streamID4, array4.data(), numMissVals); } tsID++; @@ -192,18 +201,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Cond2(void *process) -{ - ModuleCond2 cond2; - cond2.init(process); - cond2.run(); - cond2.close(); - - return nullptr; -} diff --git a/src/Condc.cc b/src/Condc.cc index 009c168aaf17b5c5ee64d4c82a3a3e74dddc4c42..3acc2e29d9a5baeb3b50c09155d52a141ae7f23a 100644 --- a/src/Condc.cc +++ b/src/Condc.cc @@ -40,8 +40,20 @@ operator_IFNOTTHENC(size_t n, T mv, Varray<T> &v, T cVal) for (size_t i = 0; i < n; ++i) v[i] = (!is_equal(v[i], mv) && is_equal(v[i], nullVal)) ? cVal : mv; } -class ModuleCondc +class Condc : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Condc", + .operators = { { "ifthenc", CondcHelp }, { "ifnotthenc", CondcHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Condc> registration = RegisterEntry<Condc>(module); + int IFTHENC, IFNOTTHENC; CdoStreamID streamID1; int taxisID1; @@ -53,17 +65,14 @@ class ModuleCondc VarList varList; - int IFTHENC, IFNOTTHENC; - public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - IFTHENC = cdo_operator_add("ifthenc", 0, 0, nullptr); - IFNOTTHENC = cdo_operator_add("ifnotthenc", 0, 0, nullptr); +IFTHENC = module.get_id("ifthenc"); +IFNOTTHENC = module.get_id("ifnotthenc"); // clang-format on operatorID = cdo_operator_id(); @@ -112,8 +121,8 @@ public: auto missval = field.missval; auto ngp = field.size; - auto nmiss = field.nmiss; - if (nmiss > 0) cdo_check_missval(missval, varList[varID].name); + auto numMissVals = field.numMissVals; + if (numMissVals > 0) cdo_check_missval(missval, varList[varID].name); // clang-format off if (field.memType == MemType::Float) @@ -130,7 +139,7 @@ public: } // clang-format on - if (nmiss > 0) field_num_mv(field); + if (numMissVals > 0) field_num_mv(field); cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, field); @@ -145,18 +154,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Condc(void *process) -{ - ModuleCondc condc; - condc.init(process); - condc.run(); - condc.close(); - - return nullptr; -} diff --git a/src/Consecstat.cc b/src/Consecstat.cc index ac12479b9f7654121ef29290bc3e3f1fae5023c9..0739b689ed42b61cb9b114a83dc04f862aee07f6 100644 --- a/src/Consecstat.cc +++ b/src/Consecstat.cc @@ -51,7 +51,7 @@ selEndOfPeriod(Field &periods, const Field &history, const Field ¤t, int i if (!isLastTimestep) { - if (current.nmiss || history.nmiss) + if (current.numMissVals || history.numMissVals) { #ifdef _OPENMP #pragma omp parallel for default(shared) @@ -79,7 +79,7 @@ selEndOfPeriod(Field &periods, const Field &history, const Field ¤t, int i } else { - if (current.nmiss) + if (current.numMissVals) { #ifdef _OPENMP #pragma omp parallel for default(shared) @@ -99,11 +99,22 @@ selEndOfPeriod(Field &periods, const Field &history, const Field ¤t, int i } } - periods.nmiss = varray_num_mv(len, parray, pmissval); + periods.numMissVals = varray_num_mv(len, parray, pmissval); } -class ModuleConsecstat +class Consecstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Consecstat", + .operators = { { "consects", CONSECTS, 0, ConsecstatHelp }, { "consecsum", CONSECSUM, 0, "refval", ConsecstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Consecstat> registration = RegisterEntry<Consecstat>(module); CdiDateTime vDateTime{}; CdiDateTime histDateTime{}; double refval = 0.0; @@ -126,11 +137,8 @@ class ModuleConsecstat public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("consecsum", CONSECSUM, 0, "refval"); - cdo_operator_add("consects", CONSECTS, 0, nullptr); operatorID = cdo_operator_id(); if (operatorID == CONSECSUM) @@ -193,7 +201,7 @@ public: { int varID, levelID; cdo_inq_record(istreamID, &varID, &levelID); - cdo_read_record(istreamID, field.vec_d.data(), &field.nmiss); + cdo_read_record(istreamID, field.vec_d.data(), &field.numMissVals); field.grid = varList[varID].gridID; field.size = varList[varID].gridsize; field.missval = varList[varID].missval; @@ -204,14 +212,14 @@ public: { case CONSECSUM: cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, vars[varID][levelID].vec_d.data(), vars[varID][levelID].nmiss); + cdo_write_record(ostreamID, vars[varID][levelID].vec_d.data(), vars[varID][levelID].numMissVals); break; case CONSECTS: if (itsID != 0) { selEndOfPeriod(periods[varID][levelID], hist[varID][levelID], vars[varID][levelID], false); cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, periods[varID][levelID].vec_d.data(), periods[varID][levelID].nmiss); + cdo_write_record(ostreamID, periods[varID][levelID].vec_d.data(), periods[varID][levelID].numMissVals); } #ifdef _OPENMP #pragma omp parallel for default(shared) schedule(static) @@ -242,7 +250,7 @@ public: { selEndOfPeriod(periods[varID][levelID], hist[varID][levelID], vars[varID][levelID], true); cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, periods[varID][levelID].vec_d.data(), periods[varID][levelID].nmiss); + cdo_write_record(ostreamID, periods[varID][levelID].vec_d.data(), periods[varID][levelID].numMissVals); } } } @@ -252,18 +260,5 @@ public: { cdo_stream_close(istreamID); cdo_stream_close(ostreamID); - - cdo_finish(); } }; -void * -Consecstat(void *process) -{ - ModuleConsecstat consecstat; - - consecstat.init(process); - consecstat.run(); - consecstat.close(); - - return nullptr; -} diff --git a/src/Copy.cc b/src/Copy.cc index 658162b59372df3ee14bb5de8d708aba8702a6f5..acfe478e5346da4a9efe681a47bc432dd7b04593 100644 --- a/src/Copy.cc +++ b/src/Copy.cc @@ -27,7 +27,7 @@ is_fdb_stream(const std::string &filename) bool is_fdb_copy(bool dataIsUnchanged, int nfiles) { - bool isFdbCopy = false; + auto isFdbCopy = false; if (dataIsUnchanged) { @@ -38,8 +38,25 @@ is_fdb_copy(bool dataIsUnchanged, int nfiles) return isFdbCopy; } -class ModuleCopy +class Copy : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Copy", + // clang-format off + .operators = { { "copy", CopyHelp }, + { "clone", CopyHelp }, + { "szip", CopyHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Copy>(module); + + int CLONE, SZIP; bool hasConstantFields = true; CdoStreamID streamID2 = CDO_STREAM_UNDEF; @@ -54,21 +71,14 @@ class ModuleCopy int operatorID; - int CLONE, SZIP; - public: void - init(void *process) + init() { - cdo_initialize(process); - dataIsUnchanged = data_is_unchanged(); - // clang-format off - cdo_operator_add("copy", 0, 0, nullptr); - CLONE = cdo_operator_add("clone", 0, 0, nullptr); - SZIP = cdo_operator_add("szip", 0, 0, nullptr); - // clang-format on + CLONE = module.get_id("clone"); + SZIP = module.get_id("szip"); operatorID = cdo_operator_id(); if (operatorID == SZIP) @@ -86,10 +96,10 @@ public: progress::init(); } + void run() { - int tsID2 = 0; for (int indf = 0; indf < nfiles; ++indf) { @@ -140,7 +150,7 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - double fstatus = indf + ((ntsteps > 1) ? (tsID1 + (recID + 1.0) / nrecs) / ntsteps : 1.0); + double fstatus = indf + ((ntsteps >= 0) ? (tsID1 + (recID + 1.0) / nrecs) / ntsteps : 1.0); if (!Options::cdoVerbose) progress::update(0, 1, fstatus / nfiles); int varID, levelID; @@ -174,20 +184,8 @@ public: void close() { - cdo_stream_close(streamID2); if (vlistID2 != CDI_UNDEFID) vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -Copy(void *process) -{ - ModuleCopy copy; - copy.init(process); - copy.run(); - copy.close(); - return nullptr; -} diff --git a/src/DCW_util.cc b/src/DCW_util.cc index 04f3600668af41616b93b60f41ea79cc8c98992f..55b9101b974440c46c18dbfc59676b6d71b1dca1 100644 --- a/src/DCW_util.cc +++ b/src/DCW_util.cc @@ -32,16 +32,26 @@ print_polygons(DCW_Lists &dcw_lists, const std::string &codeNames) dcw_print_polygons(dcw_lists, codeList); } -class ModuleDCW_util +class DCW_util : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "DCW_util", + .operators = { { "dcw"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 0, NoRestriction }, + }; + inline static RegisterEntry<DCW_util> registration = RegisterEntry<DCW_util>(module); int argc = 0; DCW_Lists dcw_lists; public: void - init(void *process) + init() { - cdo_initialize(process); if (dcw_load_lists(dcw_lists)) cdo_abort("dcw_load_lists() failed!"); @@ -74,17 +84,5 @@ public: void close() { - cdo_finish(); } }; - -void * -DCW_util(void *process) -{ - ModuleDCW_util dcw_util; - dcw_util.init(process); - dcw_util.run(); - dcw_util.close(); - - return nullptr; -} diff --git a/src/Dayarith.cc b/src/Dayarith.cc index dc15696607ecd96a4c3b16505087ec4961f0a7de..2466d0c73f9623019553b111fbf87ce68095d2a1 100644 --- a/src/Dayarith.cc +++ b/src/Dayarith.cc @@ -20,17 +20,22 @@ #include "cdo_vlist.h" #include "field_functions.h" -static void -add_operators(void) -{ - cdo_operator_add("dayadd", FieldFunc_Add, 0, nullptr); - cdo_operator_add("daysub", FieldFunc_Sub, 0, nullptr); - cdo_operator_add("daymul", FieldFunc_Mul, 0, nullptr); - cdo_operator_add("daydiv", FieldFunc_Div, 0, nullptr); -} - -class ModuleDayarith +class Dayarith : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Dayarith", + .operators = { { "dayadd", FieldFunc_Add, 0, DayarithHelp }, + { "daysub", FieldFunc_Sub, 0, DayarithHelp }, + { "daymul", FieldFunc_Mul, 0, DayarithHelp }, + { "daydiv", FieldFunc_Div, 0, DayarithHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Dayarith> registration = RegisterEntry<Dayarith>(module); CdoStreamID streamID1; int taxisID1; @@ -48,11 +53,8 @@ class ModuleDayarith public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -150,18 +152,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Dayarith(void *process) -{ - ModuleDayarith dayarith; - dayarith.init(process); - dayarith.run(); - dayarith.close(); - - return nullptr; -} diff --git a/src/Deltat.cc b/src/Deltat.cc index 2e9262eb1590d0e4cdf8d10e70e2f20395dae34f..2f2533aefd4726ae36ce74ababedd9de89c8cdce 100644 --- a/src/Deltat.cc +++ b/src/Deltat.cc @@ -51,14 +51,14 @@ field_deltat(const Field &field0, const Field &field1, Field &field2, double fac { if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); - if (field1.nmiss || field0.nmiss) + if (field1.numMissVals || field0.numMissVals) { if (field1.memType == MemType::Float) varray_deltat(field1.size, field0.vec_f, field1.vec_f, field2.vec_f, factor, field1.missval); else varray_deltat(field1.size, field0.vec_d, field1.vec_d, field2.vec_d, factor, field1.missval); - field2.nmiss = field_num_mv(field2); + field2.numMissVals = field_num_mv(field2); } else { @@ -69,8 +69,19 @@ field_deltat(const Field &field0, const Field &field1, Field &field2, double fac } } -class ModuleDeltat +class Deltat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Deltat", + .operators = { { "deltat", DeltatHelp }, { "timederivative", 0, 1, DeltatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Deltat> registration = RegisterEntry<Deltat>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -85,13 +96,10 @@ class ModuleDeltat public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("deltat", 0, 0, nullptr); - cdo_operator_add("timederivative", 0, 1, nullptr); // clang-format on auto operatorID = cdo_operator_id(); @@ -174,17 +182,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Deltat(void *process) -{ - ModuleDeltat deltat; - deltat.init(process); - deltat.run(); - deltat.close(); - - return nullptr; -} diff --git a/src/Deltime.cc b/src/Deltime.cc index 4cefb5136c2d732845f145e510b9b6663c70e3fd..8369959cb2e4ee299d2bc7a95ee53060b3488e52 100644 --- a/src/Deltime.cc +++ b/src/Deltime.cc @@ -13,8 +13,20 @@ constexpr const char *cmons[] = { "", "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; -class ModuleDeltime +class Deltime : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Deltime", + .operators = { { "delday"}, { "del29feb"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Deltime> registration = RegisterEntry<Deltime>(module); + int DELDAY, DEL29FEB; int dday, dmon; CdoStreamID streamID1; @@ -33,15 +45,14 @@ class ModuleDeltime public: void - init(void *process) + init() { - cdo_initialize(process); dataIsUnchanged = data_is_unchanged(); // clang-format off - auto DELDAY = cdo_operator_add("delday", 0, 0, nullptr); - auto DEL29FEB = cdo_operator_add("del29feb", 0, 0, nullptr); +DELDAY = module.get_id("delday"); +DEL29FEB = module.get_id("del29feb"); // clang-format on (void) (DELDAY); // unused @@ -149,19 +160,5 @@ public: if (nfound == 0) cdo_warning("Day %d%s not found!", dday, cmons[dmon]); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Deltime(void *process) -{ - ModuleDeltime deltime; - - deltime.init(process); - deltime.run(); - deltime.close(); - - return nullptr; -} diff --git a/src/Depth.cc b/src/Depth.cc index a3f4de270f97caea2e9b703531c09f313635d039..6cf1bd3cc1fc2ec2b4eb1f821b30a5211f4b1621 100644 --- a/src/Depth.cc +++ b/src/Depth.cc @@ -23,7 +23,7 @@ static void calc_full_depth(size_t gridsize, size_t nlevels, const Varray<T> &thick_c, const Varray<T> &stretch_c, const Varray<T> &zos, Varray<T> &fullDepth) { - varray_fill(gridsize, fullDepth, 0.0); + ranges::fill_n(fullDepth.begin(), gridsize, 0.0); for (size_t k = 1; k < nlevels; ++k) { @@ -53,8 +53,20 @@ calc_full_depth(const Field3D &thick_c, const Field3D &stretch_c, const Field3D calc_full_depth(gridsize, nlevels, thick_c.vec_d, stretch_c.vec_d, zos.vec_d, fullDepth.vec_d); } -class ModuleDepth +class Depth : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Depth", + .operators = { { "zsdepth"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Depth> registration = RegisterEntry<Depth>(module); + CdoStreamID streamID1; int taxisID1; @@ -70,12 +82,8 @@ class ModuleDepth public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("zsdepth", 0, 0, nullptr); - streamID1 = cdo_open_read(0); auto vlistID1 = cdo_stream_inq_vlist(streamID1); @@ -94,10 +102,10 @@ public: auto varname = string_to_lower(varList1[varID].name); // clang-format off - if (varname == "prism_thick_c") thickID = varID; - else if (varname == "stretch_c") stretchID = varID; - else if (varname == "zos") zosID = varID; - else if (varname == "draftave") draftaveID = varID; + if (varname == "prism_thick_c") thickID = varID; + else if (varname == "stretch_c") stretchID = varID; + else if (varname == "zos") zosID = varID; + else if (varname == "draftave") draftaveID = varID; // clang-format on } @@ -105,11 +113,10 @@ public: { cdo_print("Found:"); // clang-format off - - if (-1 != thickID) cdo_print(" %s -> %s", "prism thickness at cells", varList1[thickID].name); - if (-1 != stretchID) cdo_print(" %s -> %s", "zstar surface stretch at cell center", varList1[stretchID].name); - if (-1 != zosID) cdo_print(" %s -> %s", "zstar sfc elevation at cell center", varList1[zosID].name); - if (-1 != draftaveID) cdo_print(" %s -> %s", "draftave", varList1[draftaveID].name); + if (-1 != thickID) cdo_print(" %s -> %s", "prism thickness at cells", varList1[thickID].name); + if (-1 != stretchID) cdo_print(" %s -> %s", "zstar surface stretch at cell center", varList1[stretchID].name); + if (-1 != zosID) cdo_print(" %s -> %s", "zstar sfc elevation at cell center", varList1[zosID].name); + if (-1 != draftaveID) cdo_print(" %s -> %s", "draftave", varList1[draftaveID].name); // clang-format on } @@ -146,6 +153,7 @@ public: streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); } + void run() { @@ -162,9 +170,9 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, vardata1[varID], levelID, &nmiss); - if (nmiss) cdo_abort("Missing values unsupported!"); + size_t numMissVals; + cdo_read_record(streamID1, vardata1[varID], levelID, &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported!"); } if (-1 != draftaveID) field2_add(vardata1[zosID], vardata1[draftaveID]); @@ -179,23 +187,11 @@ public: tsID++; } } + void close() { - cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Depth(void *process) -{ - ModuleDepth depth; - depth.init(process); - depth.run(); - depth.close(); - return nullptr; -} diff --git a/src/Derivepar.cc b/src/Derivepar.cc index 33a3caa19a4add1383bc77709c992ad93bf333ad..6c9b8ec849740d501a9b48ec22503f213e4a6ae8 100644 --- a/src/Derivepar.cc +++ b/src/Derivepar.cc @@ -8,7 +8,8 @@ /* This module contains the following operators: - Derivepar gheight Geopotential height + Derivepar gheight Geopotential height on full-levels + Derivepar gheight_half Geopotential height on half-levels Derivepar sealevelpressure Sea level pressure */ @@ -22,10 +23,8 @@ #include "cdo_zaxis.h" #include "cdo_options.h" -void geopot_height_halflevel(double *gheight, const double *const ta_fl, const double *const hus_fl, const double *const p_hl, - long ngp, long nlev); -void geopot_height_fulllevel(double *gheight, const double *const ta_fl, const double *const hus_fl, const double *const p_hl, - long ngp, long nlev); +void geopot_height_half(double *gheight, const double *ta_fl, const double *hus_fl, const double *p_hl, long ngp, long nlev); +void geopot_height_full(double *gheight, const double *ta_fl, const double *hus_fl, const double *p_hl, long ngp, long nlev); static void check_range_var2d(int stepNum, const Varray<double> &var2d, double rMin, double rMax, const char *varname) @@ -58,8 +57,21 @@ check_range_var3d(int stepNum, int nlevels, size_t gridsize, const Varray<double } } -class ModuleDerivepar +class Derivepar : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Derivepar", + .operators = { { "gheight", DeriveparHelp }, { "gheight_half", DeriveparHelp }, { "sealevelpressure", DeriveparHelp } }, + .aliases = { { "gheight_full", "gheight" }, { "gheighthalf", "gheight_half" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Derivepar>(module); + + int GHEIGHT_FULL, GHEIGHT_HALF, SEALEVELPRESSURE; int surfaceID = -1; int presID = -1; @@ -73,35 +85,33 @@ class ModuleDerivepar size_t gridsize; VarIDs varIDs; int zaxisID_ML = -1; - int numHybridLevels = 0, numFullLevels = 0, numHalfLevels = 0; + int numHybridLevels = 0; + int numFullLevels = 0; + int numHalfLevels = 0; Varray<double> array; Varray<double> sgeopot; Varray<double> ps; Varray<double> temp; - Varray<double> hum, gheight; + Varray<double> hum; + Varray<double> gheight; Varray<double> halfPress; - Varray<double> fullPress, sealevelpressure; + Varray<double> fullPress; + Varray<double> sealevelpressure; Varray<double> vct; VarList varList1; int operatorID; - int GHEIGHT, GHEIGHTHALF, SEALEVELPRESSURE; - public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - GHEIGHT = cdo_operator_add("gheight", 0, 0, nullptr); - GHEIGHTHALF = cdo_operator_add("gheighthalf", 0, 0, nullptr); - SEALEVELPRESSURE = cdo_operator_add("sealevelpressure", 0, 0, nullptr); - // clang-format on + GHEIGHT_FULL = module.get_id("gheight"); + GHEIGHT_HALF = module.get_id("gheight_half"); + SEALEVELPRESSURE = module.get_id("sealevelpressure"); operatorID = cdo_operator_id(); @@ -119,7 +129,12 @@ public: int vctSize = vct.size(); if (Options::cdoVerbose) - for (int i = 0; i < vctSize / 2; ++i) cdo_print("vct: %5d %25.17f %25.17f", i, vct[i], vct[vctSize / 2 + i]); + { + auto numAB = vctSize / 2; + for (int i = 0; i < 10; ++i) cdo_print("vct: %5d %25.17f %25.17f", i, vct[i], vct[numAB + i]); + cdo_print("vct: ..."); + for (int i = numAB - 10; i < numAB; ++i) cdo_print("vct: %5d %25.17f %25.17f", i, vct[i], vct[numAB + i]); + } if (zaxisID_ML == -1) cdo_abort("No 3D variable with hybrid sigma pressure coordinate found!"); @@ -134,13 +149,13 @@ public: { cdo_print("Found:"); // clang-format off - if (-1 != varIDs.humID) cdo_print(" %s -> %s", var_stdname(specific_humidity), varList1[varIDs.humID].name); - if (-1 != varIDs.tempID) cdo_print(" %s -> %s", var_stdname(air_temperature), varList1[varIDs.tempID].name); - if (-1 != varIDs.psID) cdo_print(" %s -> %s", var_stdname(surface_air_pressure), varList1[varIDs.psID].name); - if (-1 != varIDs.lnpsID) cdo_print(" LOG(%s) -> %s", var_stdname(surface_air_pressure), varList1[varIDs.lnpsID].name); - if (-1 != varIDs.sgeopotID) cdo_print(" %s -> %s", var_stdname(surface_geopotential), varList1[varIDs.sgeopotID].name); - if (-1 != varIDs.geopotID) cdo_print(" %s -> %s", var_stdname(geopotential), varList1[varIDs.geopotID].name); - if (-1 != varIDs.gheightID) cdo_print(" %s -> %s", var_stdname(geopotential_height), varList1[varIDs.gheightID].name); + if (-1 != varIDs.humID) cdo_print(" %s -> %s", var_stdname(specific_humidity), varList1[varIDs.humID].name); + if (-1 != varIDs.tempID) cdo_print(" %s -> %s", var_stdname(air_temperature), varList1[varIDs.tempID].name); + if (-1 != varIDs.psID) cdo_print(" %s -> %s", var_stdname(surface_air_pressure), varList1[varIDs.psID].name); + if (-1 != varIDs.lnpsID) cdo_print(" LOG(%s) -> %s", var_stdname(surface_air_pressure), varList1[varIDs.lnpsID].name); + if (-1 != varIDs.sgeopotID) cdo_print(" %s -> %s", var_stdname(surface_geopotential), varList1[varIDs.sgeopotID].name); + if (-1 != varIDs.geopotID) cdo_print(" %s -> %s", var_stdname(geopotential), varList1[varIDs.geopotID].name); + if (-1 != varIDs.gheightID) cdo_print(" %s -> %s", var_stdname(geopotential_height), varList1[varIDs.gheightID].name); // clang-format on } @@ -151,22 +166,22 @@ public: for (int varID = 0; varID < nvars; ++varID) { - auto gridID = varList1[varID].gridID; - auto zaxisID = varList1[varID].zaxisID; - if (operatorID == SEALEVELPRESSURE) varIDs.humID = -1; - if (gridInqType(gridID) == GRID_SPECTRAL && zaxisInqType(zaxisID) == ZAXIS_HYBRID) + const auto &var = varList1[varID]; + if (var.gridType == GRID_SPECTRAL && var.zaxisType == ZAXIS_HYBRID) cdo_abort("Spectral data on model level unsupported!"); - if (gridInqType(gridID) == GRID_SPECTRAL) cdo_abort("Spectral data unsupported!"); + if (var.gridType == GRID_SPECTRAL) cdo_abort("Spectral data unsupported!"); } + array = Varray<double>(gridsize); sgeopot = Varray<double>(gridsize); ps = Varray<double>(gridsize); temp = Varray<double>(gridsize * numFullLevels); halfPress = Varray<double>(gridsize * (numFullLevels + 1)); - if (operatorID == GHEIGHT || operatorID == GHEIGHTHALF) + + if (operatorID == GHEIGHT_FULL || operatorID == GHEIGHT_HALF) { if (varIDs.humID == -1) cdo_warning("%s not found - using algorithm without %s!", var_stdname(specific_humidity), var_stdname(specific_humidity)); @@ -191,7 +206,7 @@ public: else cdo_print("%s not found - using bottom layer of %s!", var_stdname(surface_geopotential), var_stdname(geopotential)); - varray_fill(sgeopot, 0.0); + ranges::fill(sgeopot, 0.0); } presID = varIDs.lnpsID; @@ -218,12 +233,12 @@ public: int var_id = -1; int varID = -1; - if (operatorID == GHEIGHT) + if (operatorID == GHEIGHT_FULL) { var_id = geopotential_height; varID = vlistDefVar(vlistID2, gridID0, zaxisID_ML, TIME_VARYING); } - else if (operatorID == GHEIGHTHALF) + else if (operatorID == GHEIGHT_HALF) { auto zaxisID_ML_Half = zaxisCreate(ZAXIS_HYBRID_HALF, numHalfLevels); zaxisDefVct(zaxisID_ML_Half, 2 * numHalfLevels, vct.data()); @@ -254,6 +269,7 @@ public: streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); } + void run() { @@ -270,8 +286,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); auto offset = gridsize * levelID; @@ -309,28 +325,17 @@ public: if (varIDs.humID != -1) check_range_var3d(tsID + 1, varList1[varIDs.humID].nlevels, gridsize, hum, -0.1, MAX_Q, "Humidity"); - if (operatorID == GHEIGHT || operatorID == GHEIGHTHALF) + if (operatorID == GHEIGHT_FULL || operatorID == GHEIGHT_HALF) { vct_to_hybrid_pressure((double *) nullptr, halfPress.data(), vct.data(), ps.data(), numFullLevels, gridsize); array_copy(gridsize, sgeopot.data(), gheight.data() + gridsize * numFullLevels); - if (operatorID == GHEIGHT) - geopot_height_fulllevel(gheight.data(), temp.data(), hum.data(), halfPress.data(), gridsize, numFullLevels); + if (operatorID == GHEIGHT_FULL) + geopot_height_full(gheight.data(), temp.data(), hum.data(), halfPress.data(), gridsize, numFullLevels); else - geopot_height_halflevel(gheight.data(), temp.data(), hum.data(), halfPress.data(), gridsize, numFullLevels); - - int varID = 0; - auto nlevels = (operatorID == GHEIGHT) ? numFullLevels : numHalfLevels; - for (int levelID = 0; levelID < nlevels; ++levelID) - { - cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, gheight.data() + levelID * gridsize, 0); - } - } - else if (operatorID == GHEIGHTHALF) - { + geopot_height_half(gheight.data(), temp.data(), hum.data(), halfPress.data(), gridsize, numFullLevels); int varID = 0; - auto nlevels = numHalfLevels; + auto nlevels = (operatorID == GHEIGHT_FULL) ? numFullLevels : numHalfLevels; for (int levelID = 0; levelID < nlevels; ++levelID) { cdo_def_record(streamID2, varID, levelID); @@ -341,9 +346,8 @@ public: { vct_to_hybrid_pressure(fullPress.data(), halfPress.data(), vct.data(), ps.data(), numFullLevels, gridsize); - extrapolate_P(sealevelpressure.data(), &halfPress[gridsize * (numFullLevels)], - &fullPress[gridsize * (numFullLevels - 1)], sgeopot.data(), &temp[gridsize * (numFullLevels - 1)], - gridsize); + extrapolate_P(sealevelpressure.data(), &halfPress[gridsize * numFullLevels], &fullPress[gridsize * (numFullLevels - 1)], + sgeopot.data(), &temp[gridsize * (numFullLevels - 1)], gridsize); cdo_def_record(streamID2, 0, 0); cdo_write_record(streamID2, sealevelpressure.data(), 0); @@ -354,25 +358,13 @@ public: tsID++; } } + void close() { - cdo_stream_close(streamID2); cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Derivepar(void *process) -{ - ModuleDerivepar derivepar; - derivepar.init(process); - derivepar.run(); - derivepar.close(); - return nullptr; -} diff --git a/src/Detrend.cc b/src/Detrend.cc index 483e14e7b0149f4641dbcfac322deb3b544fda47..e2bf9f6c01aad82f129eccc45f561d0b901dc2ee 100644 --- a/src/Detrend.cc +++ b/src/Detrend.cc @@ -57,10 +57,7 @@ detrend(long nts, const Varray<double> &deltaTS0, double missval1, const Varray< work2 = SUBM(DIVM(sumx, n), MULM(DIVM(sumj, n), work1)); } - auto detrend_kernel = [&](auto j, auto is_EQ) - { - return SUBM(array1[j], ADDM(work2, MULM(work1, deltaTS0[j]))); - }; + auto detrend_kernel = [&](auto j, auto is_EQ) { return SUBM(array1[j], ADDM(work2, MULM(work1, deltaTS0[j]))); }; if (std::isnan(missval1)) for (long j = 0; j < nts; ++j) array2[j] = detrend_kernel(j, dbl_is_equal); @@ -93,7 +90,7 @@ detrendGetParameter(bool &tstepIsEqual) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -111,8 +108,20 @@ detrendGetParameter(bool &tstepIsEqual) } } -class ModuleDetrend +class Detrend : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Detrend", + .operators = { { "detrend", DetrendHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Detrend> registration = RegisterEntry<Detrend>(module); + int varID, levelID; DateTimeList dtlist; @@ -131,10 +140,8 @@ class ModuleDetrend public: void - init(void *process) + init() { - cdo_initialize(process); - detrendGetParameter(tstepIsEqual); streamID1 = cdo_open_read(0); @@ -250,18 +257,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Detrend(void *process) -{ - ModuleDetrend detrend; - detrend.init(process); - detrend.run(); - detrend.close(); - - return nullptr; -} diff --git a/src/Diff.cc b/src/Diff.cc index 3ff274dca6c3af8695e60354cbe93a9934753786..fc14ca99dd1f0064c93c4a1c7bda710b2ea31cff 100644 --- a/src/Diff.cc +++ b/src/Diff.cc @@ -75,7 +75,7 @@ static DiffParam diff(size_t gridsize, const Field &field1, const Field &field2) { DiffParam diffParam; - auto hasMissvals = (field1.nmiss || field2.nmiss); + auto hasMissvals = (field1.numMissVals || field2.numMissVals); if (hasMissvals) { if (memtype_is_float_float(field1.memType, field2.memType)) @@ -141,7 +141,7 @@ diff_get_parameter(double &abslim, double &abslim2, double &rellim, int &mapflag KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -169,8 +169,24 @@ diff_get_parameter(double &abslim, double &abslim2, double &rellim, int &mapflag } } -class ModuleDiff +class Diff : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Diff", + .operators = { { "diff", DiffHelp }, + { "diffp", DiffHelp }, + { "diffn", DiffHelp }, + { "diffc", DiffHelp } }, + .aliases = { { "diffv", "diffn" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 2, 0, NoRestriction }, + }; + inline static RegisterEntry<Diff> registration = RegisterEntry<Diff>(module); + + int DIFF, DIFFP, DIFFN, DIFFC; bool printHeader = true; int varID1, varID2 = -1; int levelID; @@ -188,21 +204,14 @@ class ModuleDiff std::map<int, int> mapOfVarIDs; VarList varList1, varList2; - Field field1, field2; - - int DIFF, DIFFP, DIFFN, DIFFC; - public: void - init(void *process) + init() { - - cdo_initialize(process); - - DIFF = cdo_operator_add("diff", 0, 0, nullptr); - DIFFP = cdo_operator_add("diffp", 0, 0, nullptr); - DIFFN = cdo_operator_add("diffn", 0, 0, nullptr); - DIFFC = cdo_operator_add("diffc", 0, 0, nullptr); + DIFF = module.get_id("diff"); + DIFFP = module.get_id("diffp"); + DIFFN = module.get_id("diffn"); + DIFFC = module.get_id("diffc"); operatorID = cdo_operator_id(); @@ -236,6 +245,7 @@ public: void run() { + Field field1, field2; int nrecs, nrecs2; int indg = 0; @@ -282,22 +292,23 @@ public: indg += 1; - auto gridsize = varList1[varID1].gridsize; + const auto &var1 = varList1[varID1]; + const auto &var2 = varList2[varID2]; // checkrel = gridInqType(gridID) != GRID_SPECTRAL; auto checkrel = true; - cdiParamToString(varList1[varID1].param, paramstr, sizeof(paramstr)); + cdiParamToString(var1.param, paramstr, sizeof(paramstr)); - field1.init(varList1[varID1]); + field1.init(var1); cdo_read_record(streamID1, field1); - if (varList1[varID1].nwpv == CDI_COMP) use_real_part(gridsize, field1); + if (var1.nwpv == CDI_COMP) use_real_part(var1.gridsize, field1); - field2.init(varList2[varID2]); + field2.init(var2); cdo_read_record(streamID2, field2); - if (varList2[varID2].nwpv == CDI_COMP) use_real_part(gridsize, field2); + if (var2.nwpv == CDI_COMP) use_real_part(var1.gridsize, field2); - auto dp = diff(gridsize, field1, field2); + auto dp = diff(var1.gridsize, field1, field2); if (!Options::silentMode || Options::cdoVerbose) { @@ -328,8 +339,8 @@ public: fprintf(stdout, "%s %s ", vdateString.c_str(), vtimeString.c_str()); reset_text_color(stdout); set_text_color(stdout, GREEN); - fprintf(stdout, "%7g ", cdo_zaxis_inq_level(varList1[varID1].zaxisID, levelID)); - fprintf(stdout, "%8zu %7zu ", gridsize, std::max(field1.nmiss, field2.nmiss)); + fprintf(stdout, "%7g ", cdo_zaxis_inq_level(var1.zaxisID, levelID)); + fprintf(stdout, "%8zu %7zu ", var1.gridsize, std::max(field1.numMissVals, field2.numMissVals)); fprintf(stdout, "%7zu ", dp.ndiff); reset_text_color(stdout); @@ -342,11 +353,11 @@ public: set_text_color(stdout, BRIGHT, GREEN); if (operatorID == DIFFN) - fprintf(stdout, "%-11s", varList1[varID1].name.c_str()); + fprintf(stdout, "%-11s", var1.name.c_str()); else if (operatorID == DIFF || operatorID == DIFFP) fprintf(stdout, "%-11s", paramstr); else if (operatorID == DIFFC) - fprintf(stdout, "%4d", varList1[varID1].code); + fprintf(stdout, "%4d", var1.code); reset_text_color(stdout); fprintf(stdout, "\n"); @@ -392,18 +403,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Diff(void *process) -{ - ModuleDiff diff; - diff.init(process); - diff.run(); - diff.close(); - - return nullptr; -} diff --git a/src/Distgrid.cc b/src/Distgrid.cc index 3c231457c9ae7a2f853043122c9ae8c6514e91a4..7ad8d106a8933c70adf234af58b73c89cab57b98 100644 --- a/src/Distgrid.cc +++ b/src/Distgrid.cc @@ -334,8 +334,19 @@ dist_cells(const Field &field1, Field &field2, const DistgridInfo &distgridInfo) for (size_t i = 0; i < gridsize; ++i) field2.vec_d[i] = field1.vec_d[cellidx[i]]; } -class ModuleDistgrid +class Distgrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Distgrid", + .operators = { { "distgrid", DistgridHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Distgrid> registration = RegisterEntry<Distgrid>(module); size_t MaxBlocks = 99999; int gridID1; int gridtype = -1; @@ -354,12 +365,8 @@ class ModuleDistgrid public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); - operator_input_arg("nxblocks, [nyblocks]"); if (cdo_operator_argc() < 1) cdo_abort("Too few arguments!"); if (cdo_operator_argc() > 2) cdo_abort("Too many arguments!"); @@ -471,7 +478,7 @@ public: for (size_t index = 0; index < nsplit; ++index) { - auto fileName = cdo_get_obase() + string_format("%05ld", (long)index); + auto fileName = cdo_get_obase() + string_format("%05ld", (long) index); if (fileSuffix.size() > 0) fileName += fileSuffix; streamIDs[index] = cdo_open_write(fileName.c_str()); @@ -525,7 +532,7 @@ public: else dist_cells(field1, field2, distgridInfo[0][index]); - if (field1.nmiss) field_num_mv(field2); + if (field1.numMissVals) field_num_mv(field2); cdo_def_record(streamIDs[index], varID, levelID); cdo_write_record(streamIDs[index], field2); @@ -546,18 +553,5 @@ public: for (int i = 0; i < ngrids; ++i) for (size_t index = 0; index < nsplit; ++index) gridDestroy(distgridInfo[i][index].gridID); - - cdo_finish(); } }; - -void * -Distgrid(void *process) -{ - ModuleDistgrid distrid; - distrid.init(process); - distrid.run(); - distrid.close(); - - return nullptr; -} diff --git a/src/Duplicate.cc b/src/Duplicate.cc index 4d1d835fee86d66737dd158f9d47962b1100cb35..0c26b8ba2190ecf586571006fbb19878d9d9139b 100644 --- a/src/Duplicate.cc +++ b/src/Duplicate.cc @@ -13,8 +13,19 @@ #include "param_conversion.h" #include "field_functions.h" -class ModuleDuplicate +class Duplicate : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Duplicate", + .operators = { { "duplicate", DuplicateHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Duplicate> registration = RegisterEntry<Duplicate>(module); FieldVector3D vars; std::vector<CdiDateTime> vDateTimes; @@ -32,9 +43,8 @@ class ModuleDuplicate public: void - init(void *process) + init() { - cdo_initialize(process); if (cdo_operator_argc() > 1) cdo_abort("Too many arguments!"); @@ -132,17 +142,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - cdo_finish(); } }; - -void * -Duplicate(void *process) -{ - ModuleDuplicate duplicate; - duplicate.init(process); - duplicate.run(); - duplicate.close(); - - return nullptr; -} diff --git a/src/EOFs.cc b/src/EOFs.cc index be4f982dc546a255e6fecd09fa938a2464d96a74..49e0a841fb688935a7818e73dcf8387ff8017ec6 100644 --- a/src/EOFs.cc +++ b/src/EOFs.cc @@ -95,7 +95,7 @@ scale_eigvec_time(Varray<double> &out, int tsID, int nts, size_t npack, const st } } -class ModuleEOFs +class EOFs : public Process { enum { @@ -104,6 +104,20 @@ class ModuleEOFs EOF_SPATIAL }; +public: + using Process::Process; + inline static CdoModule module = { + .name = "EOFs", + .operators = { { "eof", EOF_, 0, EOFsHelp }, + { "eofspatial", EOF_SPATIAL, 0, EOFsHelp }, + { "eoftime", EOF_TIME, 0, EOFsHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 2, OnlyFirst }, + }; + inline static RegisterEntry<EOFs> registration = RegisterEntry<EOFs>(module); + struct eofdata_t { bool init = false; @@ -113,7 +127,7 @@ class ModuleEOFs Varray2D<double> data; }; - size_t nmiss = 0; + size_t numMissVals = 0; int varID, levelID; int nts = 1; int grid_space = 0, time_space = 0; @@ -152,14 +166,10 @@ class ModuleEOFs public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("eof", EOF_, 0, nullptr); - cdo_operator_add("eoftime", EOF_TIME, 0, nullptr); - cdo_operator_add("eofspatial", EOF_SPATIAL, 0, nullptr); // clang-format on auto operatorID = cdo_operator_id(); @@ -302,7 +312,7 @@ public: for (int recID = 0; recID < nrecs; ++recID) { cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, in.data(), &nmiss); + cdo_read_record(streamID1, in.data(), &numMissVals); auto gridsize = varList1[varID].gridsize; auto missval = varList1[varID].missval; @@ -520,17 +530,17 @@ public: else if (time_space) scale_eigvec_time(out, tsID, nts, npack, pack, weights, covar, data, missval, sum_w); - nmiss = varray_num_mv(gridsize, out, missval); + numMissVals = varray_num_mv(gridsize, out, missval); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, out.data(), nmiss); + cdo_write_record(streamID3, out.data(), numMissVals); } // loop n_eig auto eig_val = eofdata[varID][levelID].eig_val.data(); - nmiss = (DBL_IS_EQUAL(eig_val[tsID], missval)) ? 1 : 0; + numMissVals = (DBL_IS_EQUAL(eig_val[tsID], missval)) ? 1 : 0; cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, &eig_val[tsID], nmiss); + cdo_write_record(streamID2, &eig_val[tsID], numMissVals); } // loop nlevs } // loop nvars } @@ -549,18 +559,5 @@ public: // taxisDestroy(taxisID2); // taxisDestroy(taxisID3); - cdo_finish(); } }; - -void * -EOFs(void *process) -{ - ModuleEOFs eofs; - - eofs.init(process); - eofs.run(); - eofs.close(); - - return nullptr; -} diff --git a/src/EcaEtccdi.cc b/src/EcaEtccdi.cc index 8e41b29981c967cfe7a97d246486a43bcd96af32..401b7eb1a2e043e1d4686a8792ac7b337d109f2b 100644 --- a/src/EcaEtccdi.cc +++ b/src/EcaEtccdi.cc @@ -111,7 +111,7 @@ writeTimesteps(int MaxMonths, int recentYear, FieldVector3D &cei, int frequency, fieldc_div(cei[loopmonth - 2][0][levelIDo], (double) (tempdpm[loopmonth - 2] / 100.0)); cdo_def_record(streamID4, varIDo, levelIDo); - cdo_write_record(streamID4, cei[loopmonth - 2][0][levelIDo].vec_d.data(), cei[loopmonth - 2][0][levelIDo].nmiss); + cdo_write_record(streamID4, cei[loopmonth - 2][0][levelIDo].vec_d.data(), cei[loopmonth - 2][0][levelIDo].numMissVals); } (*otsID)++; } @@ -127,7 +127,7 @@ writeTimesteps(int MaxMonths, int recentYear, FieldVector3D &cei, int frequency, if (func2 == FieldFunc_Avg) fieldc_div(cei[0][0][levelIDo], (double) (tempdpy / 100.0)); cdo_def_record(streamID4, varIDo, levelIDo); - cdo_write_record(streamID4, cei[0][0][levelIDo].vec_d.data(), cei[0][0][levelIDo].nmiss); + cdo_write_record(streamID4, cei[0][0][levelIDo].vec_d.data(), cei[0][0][levelIDo].numMissVals); } (*otsID)++; } @@ -189,7 +189,7 @@ calculateOuterPeriod(Field &field, int MaxMonths, int recentYear, int endOfCalc, for (int recID = 0; recID < nrecs; ++recID) { streamInqRecord(cdiStream, &varID, &levelID); - streamReadRecord(cdiStream, field.vec_d.data(), &field.nmiss); + streamReadRecord(cdiStream, field.vec_d.data(), &field.numMissVals); Field &pctls = varsPtemp[dayOfYear][0][levelID]; if (selection == func_selle) @@ -364,7 +364,7 @@ etccdi_op(ETCCDI_REQUEST &request) int varID, levelID; cdo_inq_record(streamID2, &varID, &levelID); cdo_read_record(streamID2, vars2[dayOfYear][varID][levelID]); - varsPtemp[dayOfYear][varID][levelID].nmiss = vars2[dayOfYear][varID][levelID].nmiss; + varsPtemp[dayOfYear][varID][levelID].numMissVals = vars2[dayOfYear][varID][levelID].numMissVals; } for (int recID = 0; recID < nrecs; ++recID) @@ -705,7 +705,7 @@ etccdi_op(ETCCDI_REQUEST &request) cdo_def_record(streamID4, varIDo, levelIDo); cdo_write_record( streamID4, cei[(bootsyear - request.startboot) * MaxMonths + (month - 2)][varIDo][levelIDo].vec_d.data(), - cei[(bootsyear - request.startboot) * MaxMonths + (month - 2)][varIDo][levelIDo].nmiss); + cei[(bootsyear - request.startboot) * MaxMonths + (month - 2)][varIDo][levelIDo].numMissVals); } otsID++; } @@ -722,7 +722,7 @@ etccdi_op(ETCCDI_REQUEST &request) cdo_def_record(streamID4, varIDo, levelIDo); cdo_write_record(streamID4, cei[(bootsyear - request.startboot) * MaxMonths][varIDo][levelIDo].vec_d.data(), - cei[(bootsyear - request.startboot) * MaxMonths][varIDo][levelIDo].nmiss); + cei[(bootsyear - request.startboot) * MaxMonths][varIDo][levelIDo].numMissVals); } otsID++; } @@ -784,30 +784,42 @@ etccdi_op(ETCCDI_REQUEST &request) cdo_stream_close(streamID1); } -class ModuleEcaEtccdi +class EcaEtccdi : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "EcaEtccdi", + .operators = { { "etccdi_tx90p", func_selge, CMP_DATE, EcaEtccdiHelp }, + { "etccdi_tx10p", func_selle, CMP_DATE, EcaEtccdiHelp }, + { "etccdi_tn90p", func_selge, CMP_DATE, EcaEtccdiHelp }, + { "etccdi_tn10p", func_selle, CMP_DATE, EcaEtccdiHelp }, + { "etccdi_r95p", func_selge, CMP_DATE, EcaEtccdiHelp }, + { "etccdi_r99p", func_selge, CMP_DATE, EcaEtccdiHelp }, + { "etccdi", 0, CMP_DATE, EcaEtccdiHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, FilesOnly }, + }; + inline static RegisterEntry<EcaEtccdi> registration = RegisterEntry<EcaEtccdi>(module); + int ETCCDI_TX90P, ETCCDI_R99P, ETCCDI_R95P, ETCCDI_TX10P, ETCCDI_TN90P, ETCCDI_TN10P; ETCCDI_REQUEST request; public: void - init(void *process) + init() { - cdo_initialize(process); if (cdo_operator_argc() < 3) cdo_abort("Too few arguments!"); if (cdo_operator_argc() > 4) cdo_abort("Too many arguments!"); - int ETCCDI_TX90P, ETCCDI_R99P, ETCCDI_R95P, ETCCDI_TX10P, ETCCDI_TN90P, ETCCDI_TN10P; - - ETCCDI_TX90P = cdo_operator_add("etccdi_tx90p", func_selge, CMP_DATE, nullptr); - ETCCDI_R99P = cdo_operator_add("etccdi_r99p", func_selge, CMP_DATE, nullptr); - ETCCDI_R95P = cdo_operator_add("etccdi_r95p", func_selge, CMP_DATE, nullptr); - ETCCDI_TX10P = cdo_operator_add("etccdi_tx10p", func_selle, CMP_DATE, nullptr); - ETCCDI_TN90P = cdo_operator_add("etccdi_tn90p", func_selge, CMP_DATE, nullptr); - ETCCDI_TN10P = cdo_operator_add("etccdi_tn10p", func_selle, CMP_DATE, nullptr); - cdo_operator_add("etccdi", 0, CMP_DATE, nullptr); - - + ETCCDI_TX90P = module.get_id("etccdi_tx90p"); + ETCCDI_R99P = module.get_id("etccdi_r99p"); + ETCCDI_R95P = module.get_id("etccdi_r95p"); + ETCCDI_TX10P = module.get_id("etccdi_tx10p"); + ETCCDI_TN90P = module.get_id("etccdi_tn90p"); + ETCCDI_TN10P = module.get_id("etccdi_tn10p"); request.ndates = parameter_to_int(cdo_operator_argv(0)); request.startboot = parameter_to_int(cdo_operator_argv(1)); @@ -896,17 +908,5 @@ public: void close() { - cdo_finish(); } }; - -void * -EcaEtccdi(void *process) -{ - ModuleEcaEtccdi ecaEtccdi; - ecaEtccdi.init(process); - ecaEtccdi.run(); - ecaEtccdi.close(); - - return nullptr; -} diff --git a/src/EcaIndices.cc b/src/EcaIndices.cc index f2473967cbd8705ca0fddab53789e192bae56943..a034e378b6468821294011274d3a6450e6b70874 100644 --- a/src/EcaIndices.cc +++ b/src/EcaIndices.cc @@ -318,7 +318,6 @@ static const char HURR_LONGNAME2[] = "Greatest number of consecutive hurricane /* ECA temperature indices */ - static void set_default_compare_type(int &compare_type) { @@ -329,7 +328,7 @@ static void set_compare_type_from_params(int &compare_type, const std::vector<std::string> ¶ms) { KVList kvlist; - if (kvlist.parse_arguments(1, params) != 0) cdo_abort("Argument parse error!"); + if (kvlist.parse_arguments(params) != 0) cdo_abort("Argument parse error!"); auto kv = kvlist.search("freq"); if (kv && kv->nvalues > 0) { @@ -345,55 +344,86 @@ set_compare_type_from_params(int &compare_type, const std::vector<std::string> & template <typename Request> class EcaIndices : public Process { + protected: - EcaIndices(std::function<void(Request p_request)> p_eca_func) : eca_func(p_eca_func) {} + EcaIndices(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments, const CdoModule &p_module, + std::function<void(Request p_request)> p_eca_func) + : Process(p_ID, p_operatorName, p_arguments, p_module), eca_func(p_eca_func) + { + } std::function<void(Request p_request)> eca_func; Request request; - virtual void init(void *process) = 0; + virtual void init() = 0; public: - // clang-format off - void run() { + void + run() + { assert(request.compare_type != -1); - eca_func(request); } - void close() { cdo_finish(); } - // clang-format on + eca_func(request); + } + + void + close() + { + } }; class EcaIndices1 : public EcaIndices<ECA_REQUEST_1> { public: - EcaIndices1() : EcaIndices<ECA_REQUEST_1>(eca1) {} + EcaIndices1(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments, const CdoModule &p_module) + : EcaIndices<ECA_REQUEST_1>(p_ID, p_operatorName, p_arguments, p_module, eca1) + { + } }; class EcaIndices2 : public EcaIndices<ECA_REQUEST_2> { public: - EcaIndices2() : EcaIndices<ECA_REQUEST_2>(eca2) {} + EcaIndices2(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments, const CdoModule &p_module) + : EcaIndices<ECA_REQUEST_2>(p_ID, p_operatorName, p_arguments, p_module, eca2) + { + } }; class EcaIndices3 : public EcaIndices<ECA_REQUEST_3> { public: - EcaIndices3() : EcaIndices<ECA_REQUEST_3>(eca3) {} + EcaIndices3(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments, const CdoModule &p_module) + : EcaIndices<ECA_REQUEST_3>(p_ID, p_operatorName, p_arguments, p_module, eca3) + { + } }; class EcaIndices4 : public EcaIndices<ECA_REQUEST_4> { public: - EcaIndices4() : EcaIndices<ECA_REQUEST_4>(eca4) {} + EcaIndices4(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments, const CdoModule &p_module) + : EcaIndices<ECA_REQUEST_4>(p_ID, p_operatorName, p_arguments, p_module, eca4) + { + } }; -class ModuleEcaCfd : public EcaIndices1 +class EcaCfd : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaCfd", + .operators = { { "eca_cfd", 0, CMP_DATE, EcaCfdHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaCfd> registration = RegisterEntry<EcaCfd>(module); int ndays = 5; public: void - init(void *process) override + init() override { - cdo_initialize(process); - cdo_operator_add("eca_cfd", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 2) cdo_abort("Too many arguments!"); @@ -410,8 +440,8 @@ public: char cfd_longname2[1024]; char cfd_name2[1024]; - sprintf(cfd_longname2, CFD_LONGNAME2, ndays); - sprintf(cfd_name2, CFD_NAME2, ndays); + std::snprintf(cfd_longname2, sizeof(cfd_longname2), CFD_LONGNAME2, ndays); + std::snprintf(cfd_name2, sizeof(cfd_name2), CFD_NAME2, ndays); request.var1.name = CFD_NAME; request.var1.longname = CFD_LONGNAME; @@ -429,27 +459,26 @@ public: } }; -void * -EcaCfd(void *process) -{ - ModuleEcaCfd ecacfg; - ecacfg.init(process); - ecacfg.run(); - ecacfg.close(); - return nullptr; -} - -class ModuleEcaCsu : public EcaIndices1 +class EcaCsu : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaCsu", + .operators = { { "eca_csu", 0, CMP_DATE, EcaCsuHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaCsu> registration = RegisterEntry<EcaCsu>(module); double argT = 25.0; int ndays = 5; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_csu", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 3) cdo_abort("Too many arguments!"); @@ -467,8 +496,8 @@ public: char csu_longname2[1024]; char csu_name2[1024]; - sprintf(csu_longname2, CSU_LONGNAME2, ndays); - sprintf(csu_name2, CSU_NAME2, ndays); + std::snprintf(csu_longname2, sizeof(csu_longname2), CSU_LONGNAME2, ndays); + std::snprintf(csu_name2, sizeof(csu_name2), CSU_NAME2, ndays); request.var1.name = CSU_NAME; request.var1.longname = CSU_LONGNAME; @@ -486,28 +515,27 @@ public: } }; -void * -EcaCsu(void *process) -{ - ModuleEcaCsu ecacsu; - ecacsu.init(process); - ecacsu.run(); - ecacsu.close(); - return nullptr; -} - -class ModuleEcaCwdi : public EcaIndices2 +class EcaCwdi : public EcaIndices2 { +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaCwdi", + .operators = { { "eca_cwdi", 0, CMP_DATE, EcaCwdiHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaCwdi> registration = RegisterEntry<EcaCwdi>(module); int argN = 6; double argT = 5.0; char longname[sizeof(CWDI_LONGNAME) + 80]; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_cwdi", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 2) @@ -526,7 +554,7 @@ public: argN = parameter_to_int(cdo_operator_argv(0)); } - sprintf(longname, CWDI_LONGNAME, argN, argT); + std::snprintf(longname, sizeof(longname), CWDI_LONGNAME, argN, argT); request.var1.name = CWDI_NAME; request.var1.longname = longname; @@ -547,29 +575,29 @@ public: } }; -void * -EcaCwdi(void *process) -{ - ModuleEcaCwdi ecacsu; - ecacsu.init(process); - ecacsu.run(); - ecacsu.close(); - return nullptr; -} - -class ModuleEcaCwfi : public EcaIndices2 +class EcaCwfi : public EcaIndices2 { +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaCwfi", + .operators = { { "eca_cwfi", 0, CMP_DATE, EcaCwfiHelp }, { "etccdi_csdi", 0, CMP_YEAR, EcaCwfiHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaCwfi> registration = RegisterEntry<EcaCwfi>(module); + int ECA_CWFI, ETCCDI_CSDI; int argN = 6; char longname[sizeof(CWFI_LONGNAME) + 40]; public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_CWFI, ETCCDI_CSDI; - ECA_CWFI = cdo_operator_add("eca_cwfi", 0, CMP_DATE, nullptr); - ETCCDI_CSDI = cdo_operator_add("etccdi_csdi", 0, CMP_YEAR, nullptr); + ECA_CWFI = module.get_id("eca_cwfi"); + ETCCDI_CSDI = module.get_id("etccdi_csdi"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 1) @@ -586,7 +614,7 @@ public: if (ECA_CWFI == cdo_operator_id()) { - sprintf(longname, CWFI_LONGNAME, argN); + std::snprintf(longname, sizeof(longname), CWFI_LONGNAME, argN); request.var1.name = CWFI_NAME; request.var1.longname = longname; request.var1.units = CWFI_UNITS; @@ -613,25 +641,25 @@ public: } }; -void * -EcaCwfi(void *process) +class EcaEtr : public EcaIndices3 { - ModuleEcaCwfi eca; - eca.init(process); - eca.run(); - eca.close(); - return nullptr; -} +public: + using EcaIndices3::EcaIndices3; + inline static CdoModule module = { + .name = "EcaEtr", + .operators = { { "eca_etr", 0, CMP_DATE, EcaEtrHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaEtr> registration = RegisterEntry<EcaEtr>(module); -class ModuleEcaEtr : public EcaIndices3 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_etr", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.name = ETR_NAME; @@ -643,26 +671,27 @@ public: } }; -void * -EcaEtr(void *process) +class EcaFd : public EcaIndices1 { - ModuleEcaEtr eca; - eca.init(process); - eca.run(); - eca.close(); - return nullptr; -} +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaFd", + .operators = { { "eca_fd", 0, CMP_DATE, EcaFdHelp }, { "etccdi_fd", 0, CMP_YEAR, EcaFdHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaFd> registration = RegisterEntry<EcaFd>(module); + int ECA_FD, ETCCDI_FD; -class ModuleEcaFd : public EcaIndices1 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_FD, ETCCDI_FD; - ECA_FD = cdo_operator_add("eca_fd", 0, CMP_DATE, nullptr); - ETCCDI_FD = cdo_operator_add("etccdi_fd", 0, CMP_YEAR, nullptr); + ECA_FD = module.get_id("eca_fd"); + ETCCDI_FD = module.get_id("etccdi_fd"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -692,16 +721,6 @@ public: } }; -void * -EcaFd(void *process) -{ - ModuleEcaFd eca; - eca.init(process); - eca.run(); - eca.close(); - return nullptr; -} - /* * Definition of GSL: (Thermal) Growing Season Length start at the first span * of at least 6 (argN) days with T > 5.0°C (argT) in first half of the year @@ -711,8 +730,19 @@ EcaFd(void *process) * december, whereas for the southern hemisphere is goes from july to june! * Hence, at least 18 Month of data is needed for computing the gsl of the whole earth. */ -class ModuleEcaGsl : public EcaIndices4 +class EcaGsl : public EcaIndices4 { +public: + using EcaIndices4::EcaIndices4; + inline static CdoModule module = { + .name = "EcaGsl", + .operators = { { "eca_gsl", 0, CMP_YEAR, EcaGslHelp }, { "etccdi_gsl", EcaGslHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaGsl> registration = RegisterEntry<EcaGsl>(module); int argN = 6; double argT = 5.0; double minLandFraction = 0.5; @@ -720,17 +750,15 @@ class ModuleEcaGsl : public EcaIndices4 public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_gsl", 0, CMP_YEAR, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) argN = parameter_to_int(cdo_operator_argv(0)); if (cdo_operator_argc() > 1) argT = parameter_to_double(cdo_operator_argv(1)); if (cdo_operator_argc() > 2) minLandFraction = parameter_to_double(cdo_operator_argv(2)); - sprintf(longname, GSL_LONGNAME, argN, argT, argN, argT); + std::snprintf(longname, sizeof(longname), GSL_LONGNAME, argN, argT, argN, argT); request.name = GSL_NAME; request.longname = longname; @@ -748,29 +776,27 @@ public: } }; -void * -EcaGsl(void *process) -{ - ModuleEcaGsl ecaGsl; - ecaGsl.init(process); - ecaGsl.run(); - ecaGsl.close(); - - return nullptr; -} - -class ModuleEcaHd : public EcaIndices1 +class EcaHd : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaHd", + .operators = { { "eca_hd", 0, CMP_DATE, EcaHdHelp }, { "etccdi_hd", EcaHdHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaHd> registration = RegisterEntry<EcaHd>(module); double argX = 17.0; double argA = 17.0; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_hd", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -792,28 +818,27 @@ public: } }; -void * -EcaHd(void *process) -{ - ModuleEcaHd ecaHd; - ecaHd.init(process); - ecaHd.run(); - ecaHd.close(); - return nullptr; -} - -class ModuleEcaHwdi : public EcaIndices2 +class EcaHwdi : public EcaIndices2 { +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaHwdi", + .operators = { { "eca_hwdi", 0, CMP_DATE, EcaHwdiHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaHwdi> registration = RegisterEntry<EcaHwdi>(module); int argN = 6; double argT = 5.0; char longname[sizeof(HWDI_LONGNAME) + 80]; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_hwdi", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 2) @@ -830,7 +855,7 @@ public: if (cdo_operator_argc() > 1) argT = parameter_to_double(cdo_operator_argv(1)); } - sprintf(longname, HWDI_LONGNAME, argN, argT); + std::snprintf(longname, sizeof(longname), HWDI_LONGNAME, argN, argT); request.var1.name = HWDI_NAME; request.var1.longname = longname; @@ -851,29 +876,29 @@ public: } }; -void * -EcaHwdi(void *process) -{ - ModuleEcaHwdi ecaHwdi; - ecaHwdi.init(process); - ecaHwdi.run(); - ecaHwdi.close(); - return nullptr; -} - -class ModuleEcaHwfi : public EcaIndices2 +class EcaHwfi : public EcaIndices2 { +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaHwfi", + .operators = { { "eca_hwfi", 0, CMP_DATE, EcaHwfiHelp }, { "etccdi_wsdi", 0, CMP_YEAR, EcaHwfiHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaHwfi> registration = RegisterEntry<EcaHwfi>(module); + int ECA_HWFI, ETCCDI_WSDI; int argN = 6; char longname[sizeof(HWFI_LONGNAME) + 40]; public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_HWFI, ETCCDI_WSDI; - ECA_HWFI = cdo_operator_add("eca_hwfi", 0, CMP_DATE, nullptr); - ETCCDI_WSDI = cdo_operator_add("etccdi_wsdi", 0, CMP_YEAR, nullptr); + ECA_HWFI = module.get_id("eca_hwfi"); + ETCCDI_WSDI = module.get_id("etccdi_wsdi"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 1) @@ -890,7 +915,7 @@ public: if (ECA_HWFI == cdo_operator_id()) { - sprintf(longname, HWFI_LONGNAME, argN); + std::snprintf(longname, sizeof(longname), HWFI_LONGNAME, argN); request.var1.name = HWFI_NAME; request.var1.longname = longname; request.var1.units = HWFI_UNITS; @@ -917,27 +942,28 @@ public: } }; -void * -EcaHwfi(void *process) +class EcaId : public EcaIndices1 { - ModuleEcaHwfi ecaHwfi; - ecaHwfi.init(process); - ecaHwfi.run(); - ecaHwfi.close(); - return nullptr; -} +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaId", + .operators = { { "eca_id", 0, CMP_DATE, EcaIdHelp }, { "etccdi_id", 0, CMP_YEAR, EcaIdHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaId> registration = RegisterEntry<EcaId>(module); + int ECA_ID, ETCCDI_ID; -class ModuleEcaId : public EcaIndices1 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_ID, ETCCDI_ID; - ECA_ID = cdo_operator_add("eca_id", 0, CMP_DATE, nullptr); - ETCCDI_ID = cdo_operator_add("etccdi_id", 0, CMP_YEAR, nullptr); + ECA_ID = module.get_id("eca_id"); + ETCCDI_ID = module.get_id("etccdi_id"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -966,30 +992,30 @@ public: } }; -void * -EcaId(void *process) -{ - ModuleEcaId ecaId; - ecaId.init(process); - ecaId.run(); - ecaId.close(); - return nullptr; -} - -class ModuleEcaSu : public EcaIndices1 +class EcaSu : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaSu", + .operators = { { "eca_su", 0, CMP_DATE, EcaSuHelp }, { "etccdi_su", 0, CMP_YEAR, EcaSuHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaSu> registration = RegisterEntry<EcaSu>(module); + int ECA_SU, ETCCDI_SU; double argT = 25.0; char longname[sizeof(SU_LONGNAME) + 40]; public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_SU = 0, ETCCDI_SU = 0; - ECA_SU = cdo_operator_add("eca_su", 0, CMP_DATE, nullptr); - ETCCDI_SU = cdo_operator_add("etccdi_su", 0, CMP_YEAR, nullptr); + ECA_SU = module.get_id("eca_su"); + ETCCDI_SU = module.get_id("etccdi_su"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) argT = parameter_to_double(cdo_operator_argv(0)); if (cdo_operator_argc() > 1) @@ -1001,7 +1027,7 @@ public: if (ECA_SU == cdo_operator_id()) { - sprintf(longname, SU_LONGNAME, argT); + std::snprintf(longname, sizeof(longname), SU_LONGNAME, argT); request.var1.name = SU_NAME; request.var1.longname = longname; request.var1.refdate = ECA_refdate; @@ -1020,25 +1046,25 @@ public: } }; -void * -EcaSu(void *process) +class EcaTg10p : public EcaIndices2 { - ModuleEcaSu ecaSu; - ecaSu.init(process); - ecaSu.run(); - ecaSu.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaTg10p", + .operators = { { "eca_tg10p", 0, CMP_DATE, EcaTg10pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaTg10p> registration = RegisterEntry<EcaTg10p>(module); -class ModuleEcaTg10p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_tg10p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = TG10P_NAME; @@ -1051,25 +1077,25 @@ public: } }; -void * -EcaTg10p(void *process) +class EcaTg90p : public EcaIndices2 { - ModuleEcaTg10p ecatg10p; - ecatg10p.init(process); - ecatg10p.run(); - ecatg10p.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaTg90p", + .operators = { { "eca_tg90p", 0, CMP_DATE, EcaTg90pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaTg90p> registration = RegisterEntry<EcaTg90p>(module); -class ModuleEcaTg90p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_tg90p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = TG90P_NAME; @@ -1082,25 +1108,25 @@ public: } }; -void * -EcaTg90p(void *process) +class EcaTn10p : public EcaIndices2 { - ModuleEcaTg90p ecatg90p; - ecatg90p.init(process); - ecatg90p.run(); - ecatg90p.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaTn10p", + .operators = { { "eca_tn10p", 0, CMP_DATE, EcaTn10pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaTn10p> registration = RegisterEntry<EcaTn10p>(module); -class ModuleEcaTn10p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_tn10p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = TN10P_NAME; @@ -1112,25 +1138,26 @@ public: request.var1.epilog = PERCENT_OF_TIME; } }; -void * -EcaTn10p(void *process) -{ - ModuleEcaTn10p ecatn10p; - ecatn10p.init(process); - ecatn10p.run(); - ecatn10p.close(); - return nullptr; -} -class ModuleEcaTn90p : public EcaIndices2 +class EcaTn90p : public EcaIndices2 { +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaTn90p", + .operators = { { "eca_tn90p", 0, CMP_DATE, EcaTn90pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaTn90p> registration = RegisterEntry<EcaTn90p>(module); + public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_tn90p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = TN90P_NAME; @@ -1143,31 +1170,31 @@ public: } }; -void * -EcaTn90p(void *process) -{ - ModuleEcaTn90p ecatn90p; - ecatn90p.init(process); - ecatn90p.run(); - ecatn90p.close(); - return nullptr; -} - -class ModuleEcaTr : public EcaIndices1 +class EcaTr : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaTr", + .operators = { { "eca_tr", 0, CMP_DATE, EcaTrHelp }, { "etccdi_tr", 0, CMP_YEAR, EcaTrHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaTr> registration = RegisterEntry<EcaTr>(module); + int ECA_TR, ETCCDI_TR; double argT = 20.0; char longname[1024]; public: void - init(void *process) + init() { - cdo_initialize(process); set_default_compare_type(request.compare_type); - int ECA_TR = 0, ETCCDI_TR = 0; - ECA_TR = cdo_operator_add("eca_tr", 0, CMP_DATE, nullptr); - ETCCDI_TR = cdo_operator_add("etccdi_tr", 0, CMP_YEAR, nullptr); + ECA_TR = module.get_id("eca_tr"); + ETCCDI_TR = module.get_id("etccdi_tr"); if (cdo_operator_argc() > 0) argT = parameter_to_double(cdo_operator_argv(0)); if (cdo_operator_argc() > 1) { @@ -1178,7 +1205,7 @@ public: if (ECA_TR == cdo_operator_id()) { - sprintf(longname, TR_LONGNAME, argT); + std::snprintf(longname, sizeof(longname), TR_LONGNAME, argT); request.var1.name = TR_NAME; request.var1.longname = longname; request.var1.units = TR_UNITS; @@ -1198,25 +1225,25 @@ public: } }; -void * -EcaTr(void *process) +class EcaTx10p : public EcaIndices2 { - ModuleEcaTr ecaTr; - ecaTr.init(process); - ecaTr.run(); - ecaTr.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaTx10p", + .operators = { { "eca_tx10p", 0, CMP_DATE, EcaTx10pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaTx10p> registration = RegisterEntry<EcaTx10p>(module); -class ModuleEcaTx10p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_tx10p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = TX10P_NAME; @@ -1229,32 +1256,30 @@ public: } }; -void * -EcaTx10p(void *process) +class EcaTx90p : public EcaIndices2 { - ModuleEcaTx10p ecaTx10p; - - ecaTx10p.init(process); - ecaTx10p.run(); - ecaTx10p.close(); - - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaTx90p", + .operators = { { "eca_tx90p", 0, CMP_DATE, EcaTx90pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaTx90p> registration = RegisterEntry<EcaTx90p>(module); -class ModuleEcaTx90p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_tx90p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) { if ('m' == cdo_operator_argv(0)[0]) - cdo_operator_add("eca_tx90p", 0, CMP_MONTH, nullptr); // monthly mode + request.compare_type = CMP_MONTH; else cdo_warning("Parameter value '%s' is invalid. The only valid value is " "'m' indicating monthly mode. Operating in yearly mode now.", @@ -1271,20 +1296,22 @@ public: } }; -void * -EcaTx90p(void *process) -{ - ModuleEcaTx90p ecaTx90p; - ecaTx90p.init(process); - ecaTx90p.run(); - ecaTx90p.close(); - return nullptr; -} - // ECA precipitation indices -class ModuleEcaCdd : public EcaIndices1 +class EcaCdd : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaCdd", + .operators = { { "eca_cdd", 0, CMP_DATE, EcaCddHelp }, { "etccdi_cdd", 0, CMP_YEAR, EcaCddHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaCdd> registration = RegisterEntry<EcaCdd>(module); + int ECA_CDD, ETCCDI_CDD; double threshold = 1; int ndays = 5; char cdd_longname[1024]; @@ -1293,13 +1320,11 @@ class ModuleEcaCdd : public EcaIndices1 public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_CDD = 0, ETCCDI_CDD = 0; - ECA_CDD = cdo_operator_add("eca_cdd", 0, CMP_DATE, nullptr); - ETCCDI_CDD = cdo_operator_add("etccdi_cdd", 0, CMP_YEAR, nullptr); + ECA_CDD = module.get_id("eca_cdd"); + ETCCDI_CDD = module.get_id("etccdi_cdd"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 3) @@ -1316,9 +1341,9 @@ public: if (cdo_operator_argc() == 2) ndays = parameter_to_int(cdo_operator_argv(1)); } - sprintf(cdd_longname, CDD_LONGNAME, threshold); - sprintf(cdd_longname2, CDD_LONGNAME2, ndays); - sprintf(cdd_name2, CDD_NAME2, ndays); + std::snprintf(cdd_longname, sizeof(cdd_longname), CDD_LONGNAME, threshold); + std::snprintf(cdd_longname2, sizeof(cdd_longname2), CDD_LONGNAME2, ndays); + std::snprintf(cdd_name2, sizeof(cdd_name2), CDD_NAME2, ndays); if (ECA_CDD == cdo_operator_id()) { @@ -1348,18 +1373,21 @@ public: } }; -void * -EcaCdd(void *process) -{ - ModuleEcaCdd ecaCdd; - ecaCdd.init(process); - ecaCdd.run(); - ecaCdd.close(); - return nullptr; -} - -class ModuleEcaCwd : public EcaIndices1 +class EcaCwd : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaCwd", + .operators = { { "eca_cwd", 0, CMP_DATE, EcaCwdHelp }, { "etccdi_cwd", 0, CMP_YEAR, EcaCwdHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaCwd> registration = RegisterEntry<EcaCwd>(module); + + int ECA_CWD, ETCCDI_CWD; double threshold = 1; int ndays = 5; char cwd_longname[1024]; @@ -1368,13 +1396,11 @@ class ModuleEcaCwd : public EcaIndices1 public: void - init(void *process) + init() { - cdo_initialize(process); + ECA_CWD = module.get_id("eca_cwd"); + ETCCDI_CWD = module.get_id("etccdi_cwd"); - int ECA_CWD = 0, ETCCDI_CWD = 0; - ECA_CWD = cdo_operator_add("eca_cwd", 0, CMP_DATE, nullptr); - ETCCDI_CWD = cdo_operator_add("etccdi_cwd", 0, CMP_YEAR, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 3) @@ -1391,9 +1417,9 @@ public: if (cdo_operator_argc() == 2) ndays = parameter_to_int(cdo_operator_argv(1)); } - sprintf(cwd_longname, CWD_LONGNAME, threshold); - sprintf(cwd_longname2, CWD_LONGNAME2, ndays); - sprintf(cwd_name2, CWD_NAME2, ndays); + std::snprintf(cwd_longname, sizeof(cwd_longname), CWD_LONGNAME, threshold); + std::snprintf(cwd_longname2, sizeof(cwd_longname2), CWD_LONGNAME2, ndays); + std::snprintf(cwd_name2, sizeof(cwd_name2), CWD_NAME2, ndays); if (ECA_CWD == cdo_operator_id()) { @@ -1422,34 +1448,39 @@ public: } }; -void * -EcaCwd(void *process) -{ - ModuleEcaCwd ecaCwd; - ecaCwd.init(process); - ecaCwd.run(); - ecaCwd.close(); - return nullptr; -} - -class ModuleEcaPd : public EcaIndices1 +class EcaPd : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaPd", + .operators = { { "eca_pd", 0, CMP_DATE, EcaPdHelp }, + { "eca_r10mm", 0, CMP_DATE, EcaPdHelp }, + { "eca_r20mm", 0, CMP_DATE, EcaPdHelp }, + { "etccdi_r1mm", 0, CMP_DATE, EcaPdHelp }, + { "etccdi_r10mm", 0, CMP_DATE, EcaPdHelp }, + { "etccdi_r20mm", 0, CMP_DATE, EcaPdHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaPd> registration = RegisterEntry<EcaPd>(module); + int ECA_PD, ETCCDI_R1MM, ECA_R10MM, ETCCDI_R10MM, ECA_R20MM, ETCCDI_R20MM; char lnamebuffer[1024]; double threshold = 0; public: void - init(void *process) + init() { - cdo_initialize(process); - // clang-format off - auto ECA_PD = cdo_operator_add("eca_pd", 0, CMP_DATE, nullptr); - auto ETCCDI_R1MM = cdo_operator_add("etccdi_r1mm", 0, CMP_DATE, nullptr); - auto ECA_R10MM = cdo_operator_add("eca_r10mm", 0, CMP_DATE, nullptr); - auto ETCCDI_R10MM = cdo_operator_add("etccdi_r10mm", 0, CMP_DATE, nullptr); - auto ECA_R20MM = cdo_operator_add("eca_r20mm", 0, CMP_DATE, nullptr); - auto ETCCDI_R20MM = cdo_operator_add("etccdi_r20mm", 0, CMP_DATE, nullptr); - // clang-format on + ECA_PD = module.get_id("eca_pd"); + ETCCDI_R1MM = module.get_id("etccdi_r1mm"); + ECA_R10MM = module.get_id("eca_r10mm"); + ETCCDI_R10MM = module.get_id("etccdi_r10mm"); + ECA_R20MM = module.get_id("eca_r20mm"); + ETCCDI_R20MM = module.get_id("etccdi_r20mm"); + set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -1459,7 +1490,7 @@ public: if (strstr(cdo_operator_argv(0).c_str(), "=") || cdo_operator_argc() > 1) { if (cdo_operator_argc() > 1) params = std::vector<std::string>(params.begin() + 1, params.end()); - if (kvlist.parse_arguments(1, params) != 0) cdo_abort("Argument parse error!"); + if (kvlist.parse_arguments(params) != 0) cdo_abort("Argument parse error!"); auto kv = kvlist.search("freq"); if (kv && kv->nvalues > 0) { @@ -1482,7 +1513,7 @@ public: if (cdo_operator_argc() < 1) cdo_abort("Too few arguments!"); if (cdo_operator_argc() > 2) cdo_abort("Too many arguments!"); threshold = parameter_to_double(cdo_operator_argv(0)); - sprintf(lnamebuffer, PD_LONGNAME, threshold); + std::snprintf(lnamebuffer, sizeof(lnamebuffer), PD_LONGNAME, threshold); request.var1.name = PD_NAME; request.var1.longname = lnamebuffer; request.var1.units = PD_UNITS; @@ -1541,25 +1572,25 @@ public: } }; -void * -EcaPd(void *process) +class EcaR75p : public EcaIndices2 { - ModuleEcaPd ecaPd; - ecaPd.init(process); - ecaPd.run(); - ecaPd.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR75p", + .operators = { { "eca_r75p", 0, CMP_DATE, EcaR75pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR75p> registration = RegisterEntry<EcaR75p>(module); -class ModuleEcaR75p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r75p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R75P_NAME; @@ -1573,25 +1604,25 @@ public: } }; -void * -EcaR75p(void *process) +class EcaR75ptot : public EcaIndices2 { - ModuleEcaR75p ecaR75p; - ecaR75p.init(process); - ecaR75p.run(); - ecaR75p.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR75ptot", + .operators = { { "eca_r75ptot", 0, CMP_DATE, EcaR75ptotHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR75ptot> registration = RegisterEntry<EcaR75ptot>(module); -class ModuleEcaR75ptot : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r75ptot", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R75PTOT_NAME; @@ -1605,25 +1636,25 @@ public: } }; -void * -EcaR75ptot(void *process) +class EcaR90p : public EcaIndices2 { - ModuleEcaR75ptot ecaR75ptot; - ecaR75ptot.init(process); - ecaR75ptot.run(); - ecaR75ptot.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR90p", + .operators = { { "eca_r90p", 0, CMP_DATE, EcaR90pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR90p> registration = RegisterEntry<EcaR90p>(module); -class ModuleEcaR90p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r90p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R90P_NAME; @@ -1637,24 +1668,25 @@ public: } }; -void * -EcaR90p(void *process) -{ - ModuleEcaR90p ecaR90p; - ecaR90p.init(process); - ecaR90p.run(); - ecaR90p.close(); - return nullptr; -} -class ModuleEcaR95p : public EcaIndices2 +class EcaR95p : public EcaIndices2 { +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR95p", + .operators = { { "eca_r95p", 0, CMP_DATE, EcaR95pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR95p> registration = RegisterEntry<EcaR95p>(module); + public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r95p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R95P_NAME; @@ -1668,25 +1700,25 @@ public: } }; -void * -EcaR95p(void *process) +class EcaR90ptot : public EcaIndices2 { - ModuleEcaR95p ecaR95p; - ecaR95p.init(process); - ecaR95p.run(); - ecaR95p.close(); - return nullptr; -}; +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR90ptot", + .operators = { { "eca_r90ptot", 0, CMP_DATE, EcaR90ptotHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR90ptot> registration = RegisterEntry<EcaR90ptot>(module); -class ModuleEcaR90ptot : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r90ptot", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R90PTOT_NAME; @@ -1700,57 +1732,56 @@ public: } }; -void * -EcaR90ptot(void *process) -{ - ModuleEcaR90ptot ecaR90ptot; - ecaR90ptot.init(process); - ecaR90ptot.run(); - ecaR90ptot.close(); - return nullptr; -} - -//class ModuleEcaR96p : public EcaIndices2 +// class ModuleEcaR96p : public EcaIndices2 //{ -//public: -// void -// init(void *process) -// { -// cdo_initialize(process); -// -// cdo_operator_add("eca_r95p", 0, CMP_DATE, nullptr); -// set_default_compare_type(request.compare_type); +// public: +// void +// init() +// { +// // +// cdo_operator_add("eca_r95p", 0, CMP_DATE, nullptr); +// set_default_compare_type(request.compare_type); // -// request.var1.name = R95P_NAME; -// request.var1.longname = R95P_LONGNAME; -// request.var1.refdate = ECA_refdate; -// request.var1.units = R95P_UNITS; -// request.var1.f1 = vfarselgec; -// request.var1.f3 = vfarselgt; -// request.var1.f4 = vfarnum; -// request.var1.epilog = PERCENT_OF_TIME; -// } -//}; +// request.var1.name = R95P_NAME; +// request.var1.longname = R95P_LONGNAME; +// request.var1.refdate = ECA_refdate; +// request.var1.units = R95P_UNITS; +// request.var1.f1 = vfarselgec; +// request.var1.f3 = vfarselgt; +// request.var1.f4 = vfarnum; +// request.var1.epilog = PERCENT_OF_TIME; +// } +// }; // -//void * -//EcaR96p(void *process) +// void * +// EcaR96p(void *process) //{ -// ModuleEcaR96p ecaR96p; -// ecaR96p.init(process); -// ecaR96p.run(); -// ecaR96p.close(); -// return nullptr; -//} - -class ModuleEcaR95ptot : public EcaIndices2 +// ModuleEcaR96p ecaR96p; +// ecaR96p.init(process); +// ecaR96p.run(); +// ecaR96p.close(); +// return nullptr; +// } + +class EcaR95ptot : public EcaIndices2 { +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR95ptot", + .operators = { { "eca_r95ptot", 0, CMP_DATE, EcaR95ptotHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR95ptot> registration = RegisterEntry<EcaR95ptot>(module); + public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r95ptot", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R95PTOT_NAME; @@ -1764,25 +1795,25 @@ public: } }; -void * -EcaR95ptot(void *process) +class EcaR99p : public EcaIndices2 { - ModuleEcaR95ptot ecaR95ptot; - ecaR95ptot.init(process); - ecaR95ptot.run(); - ecaR95ptot.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR99p", + .operators = { { "eca_r99p", 0, CMP_DATE, EcaR99pHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR99p> registration = RegisterEntry<EcaR99p>(module); -class ModuleEcaR99p : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r99p", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R99P_NAME; @@ -1796,25 +1827,25 @@ public: } }; -void * -EcaR99p(void *process) +class EcaR99ptot : public EcaIndices2 { - ModuleEcaR99p ecaR99p; - ecaR99p.init(process); - ecaR99p.run(); - ecaR99p.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "EcaR99ptot", + .operators = { { "eca_r99ptot", 0, CMP_DATE, EcaR99ptotHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaR99ptot> registration = RegisterEntry<EcaR99ptot>(module); -class ModuleEcaR99ptot : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("eca_r99ptot", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = R99PTOT_NAME; @@ -1827,28 +1858,27 @@ public: } }; -void * -EcaR99ptot(void *process) -{ - ModuleEcaR99ptot ecaR99ptot; - ecaR99ptot.init(process); - ecaR99ptot.run(); - ecaR99ptot.close(); - return nullptr; -} - -class ModuleEcaRr1 : public EcaIndices1 +class EcaRr1 : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaRr1", + .operators = { { "eca_rr1", 0, CMP_DATE, EcaRr1Help } }, + .aliases = { { "eca_r1mm", "eca_rr1" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaRr1> registration = RegisterEntry<EcaRr1>(module); char longname[1024]; public: void - init(void *process) + init() { double threshold = 1; - cdo_initialize(process); - cdo_operator_add("eca_rr1", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 2) @@ -1864,7 +1894,7 @@ public: if (cdo_operator_argc() == 1) threshold = parameter_to_double(cdo_operator_argv(0)); } - sprintf(longname, RR1_LONGNAME, threshold); + std::snprintf(longname, sizeof(longname), RR1_LONGNAME, threshold); request.var1.name = RR1_NAME; request.var1.longname = longname; @@ -1875,27 +1905,30 @@ public: } }; -void * -EcaRr1(void *process) +class EcaRx1day : public EcaIndices1 { - ModuleEcaRr1 ecaRr1; - ecaRr1.init(process); - ecaRr1.run(); - ecaRr1.close(); - return nullptr; -} +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaRx1day", + .operators = { { "eca_rx1day", 0, CMP_DATE, EcaRx1dayHelp }, + { "etccdi_rx1day", 0, CMP_YEAR, EcaRx1dayHelp }, + { "etccdi_rx1daymon", EcaRx1dayHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaRx1day> registration = RegisterEntry<EcaRx1day>(module); + int ECA_RX1DAY, ETCCDI_RX1DAY; -class ModuleEcaRx1day : public EcaIndices1 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_RX1DAY, ETCCDI_RX1DAY; - ECA_RX1DAY = cdo_operator_add("eca_rx1day", 0, CMP_DATE, nullptr); - ETCCDI_RX1DAY = cdo_operator_add("etccdi_rx1day", 0, CMP_YEAR, nullptr); + ECA_RX1DAY = module.get_id("eca_rx1day"); + ETCCDI_RX1DAY = module.get_id("etccdi_rx1day"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -1922,31 +1955,32 @@ public: } }; -void * -EcaRx1day(void *process) -{ - ModuleEcaRx1day ecaRx1day; - ecaRx1day.init(process); - ecaRx1day.run(); - ecaRx1day.close(); - return nullptr; -} - -class ModuleEcaRx5day : public EcaIndices1 +class EcaRx5day : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaRx5day", + .operators = { { "eca_rx5day", 0, CMP_DATE, EcaRx5dayHelp }, + { "etccdi_rx5day", 0, CMP_YEAR, EcaRx5dayHelp }, + { "etccdi_rx5daymon", EcaRx5dayHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaRx5day> registration = RegisterEntry<EcaRx5day>(module); + int ECA_RX5DAY, ETCCDI_RX5DAY; char longname2[sizeof(RX5DAY_LONGNAME2) + 40]; public: void - init(void *process) + init() { double argX = 50.0; - cdo_initialize(process); - - int ECA_RX5DAY, ETCCDI_RX5DAY; - ECA_RX5DAY = cdo_operator_add("eca_rx5day", 0, CMP_DATE, nullptr); - ETCCDI_RX5DAY = cdo_operator_add("etccdi_rx5day", 0, CMP_YEAR, nullptr); + ECA_RX5DAY = module.get_id("eca_rx5day"); + ETCCDI_RX5DAY = module.get_id("etccdi_rx5day"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 1) { @@ -1956,7 +1990,7 @@ public: set_compare_type_from_params(request.compare_type, params); } - sprintf(longname2, RX5DAY_LONGNAME2, argX); + std::snprintf(longname2, sizeof(longname2), RX5DAY_LONGNAME2, argX); if (ECA_RX5DAY == cdo_operator_id()) { @@ -1982,29 +2016,29 @@ public: } }; -void * -EcaRx5day(void *process) -{ - ModuleEcaRx5day ecaRx5day; - ecaRx5day.init(process); - ecaRx5day.run(); - ecaRx5day.close(); - return nullptr; -} - -class ModuleEcaSdii : public EcaIndices1 +class EcaSdii : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "EcaSdii", + .operators = { { "eca_sdii", 0, CMP_DATE, EcaSdiiHelp }, { "etccdi_sdii", 0, CMP_DATE, EcaSdiiHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EcaSdii> registration = RegisterEntry<EcaSdii>(module); + int ECA_SDII, ETCCDI_SDII; char longname[1024]; double threshold = 1; public: void - init(void *process) + init() { - cdo_initialize(process); - int ECA_SDII, ETCCDI_SDII; - ECA_SDII = cdo_operator_add("eca_sdii", 0, CMP_DATE, nullptr); - ETCCDI_SDII = cdo_operator_add("etccdi_sdii", 0, CMP_DATE, nullptr); + ECA_SDII = module.get_id("eca_sdii"); + ETCCDI_SDII = module.get_id("etccdi_sdii"); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 2) cdo_abort("Too many arguments!"); @@ -2023,7 +2057,7 @@ public: if (ECA_SDII == cdo_operator_id()) { - sprintf(longname, SDII_LONGNAME, threshold); + std::snprintf(longname, sizeof(longname), SDII_LONGNAME, threshold); request.var1.name = SDII_NAME; request.var1.longname = longname; request.var1.units = SDII_UNITS; @@ -2042,24 +2076,24 @@ public: } }; -void * -EcaSdii(void *process) +class Fdns : public EcaIndices2 { - ModuleEcaSdii sdii; - sdii.init(process); - sdii.run(); - sdii.close(); - return nullptr; -} +public: + using EcaIndices2::EcaIndices2; + inline static CdoModule module = { + .name = "Fdns", + .operators = { { "fdns", 0, CMP_DATE, FdnsHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Fdns> registration = RegisterEntry<Fdns>(module); -class ModuleFdns : public EcaIndices2 -{ public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("fdns", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); request.var1.name = FDNS_NAME; @@ -2075,27 +2109,26 @@ public: } }; -void * -Fdns(void *process) -{ - ModuleFdns fdns; - fdns.init(process); - fdns.run(); - fdns.close(); - return nullptr; -} - -class ModuleStrwin : public EcaIndices1 +class Strwin : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "Strwin", + .operators = { { "strwin", 0, CMP_DATE, StrwinHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Strwin> registration = RegisterEntry<Strwin>(module); double maxWind = 10.5; char longname[sizeof(STRWIN_LONGNAME) + 40]; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("strwin", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 2) @@ -2111,7 +2144,7 @@ public: if (cdo_operator_argc() > 0) maxWind = parameter_to_double(cdo_operator_argv(0)); } - sprintf(longname, STRWIN_LONGNAME, maxWind); + std::snprintf(longname, sizeof(longname), STRWIN_LONGNAME, maxWind); request.var1.name = STRWIN_NAME; request.var1.longname = longname; @@ -2130,26 +2163,25 @@ public: } }; -void * -Strwin(void *process) -{ - ModuleStrwin strwin; - strwin.init(process); - strwin.run(); - strwin.close(); - return nullptr; -} - -class ModuleStrbre : public EcaIndices1 +class Strbre : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "Strbre", + .operators = { { "strbre", 0, CMP_DATE, StrbreHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Strbre> registration = RegisterEntry<Strbre>(module); double maxWind = 10.5; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("strbre", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -2175,26 +2207,25 @@ public: } }; -void * -Strbre(void *process) -{ - ModuleStrbre strbre; - strbre.init(process); - strbre.run(); - strbre.close(); - return nullptr; -} - -class ModuleStrgal : public EcaIndices1 +class Strgal : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "Strgal", + .operators = { { "strgal", 0, CMP_DATE, StrgalHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Strgal> registration = RegisterEntry<Strgal>(module); double maxWind = 20.5; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("strgal", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -2219,26 +2250,26 @@ public: request.var2.h3 = field2_max; } }; -void * -Strgal(void *process) -{ - ModuleStrgal strgal; - strgal.init(process); - strgal.run(); - strgal.close(); - return nullptr; -} -class ModuleHurr : public EcaIndices1 +class Hurr : public EcaIndices1 { +public: + using EcaIndices1::EcaIndices1; + inline static CdoModule module = { + .name = "Hurr", + .operators = { { "hurr", 0, CMP_DATE, HurrHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Hurr> registration = RegisterEntry<Hurr>(module); double maxWind = 32.5; public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("hurr", 0, CMP_DATE, nullptr); set_default_compare_type(request.compare_type); if (cdo_operator_argc() > 0) @@ -2263,13 +2294,3 @@ public: request.var2.h3 = field2_max; } }; - -void * -Hurr(void *process) -{ - ModuleHurr hurr; - hurr.init(process); - hurr.run(); - hurr.close(); - return nullptr; -} diff --git a/src/Echam5ini.cc b/src/Echam5ini.cc index 12c5cebd7f6be48d95a29715026d9723ab98b885..acca9422effad4776cee5fcc3eb1fb3d1c380268 100644 --- a/src/Echam5ini.cc +++ b/src/Echam5ini.cc @@ -609,13 +609,14 @@ export_e5ml(const char *filename, const std::vector<VAR> &vars, int nvars, int v #endif } -class ModuleEcham5ini +class Echam5ini : public Process { + using Process::Process; + +public: void ex_e5ml() { - std::string name, longname, units; - auto streamID1 = cdo_open_read(0); auto vlistID1 = cdo_stream_inq_vlist(streamID1); @@ -631,9 +632,9 @@ class ModuleEcham5ini for (int varID = 0; varID < nvars; ++varID) { auto code = varList1[varID].code; - name = varList1[varID].name; - longname = varList1[varID].longname; - units = varList1[varID].units; + auto &name = varList1[varID].name; + auto &longname = varList1[varID].longname; + auto &units = varList1[varID].units; if (code < 0) code = 0; if (name.substr(0, 3) == "var") @@ -714,8 +715,8 @@ class ModuleEcham5ini cdo_inq_record(streamID1, &varID, &levelID); auto gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID)); - size_t nmiss; - cdo_read_record(streamID1, vars[varID].ptr + levelID * gridsize, &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, vars[varID].ptr + levelID * gridsize, &numMissVals); } cdo_stream_close(streamID1); @@ -781,49 +782,56 @@ class ModuleEcham5ini vlistDestroy(vlistID2); } - int operatorID; - int EXPORT_E5ML, IMPORT_E5ML; - -public: void - init(void *process) + init() { - cdo_initialize(process); - - IMPORT_E5ML = cdo_operator_add("import_e5ml", 0, 0, nullptr); - EXPORT_E5ML = cdo_operator_add("export_e5ml", 0, 0, nullptr); - - operatorID = cdo_operator_id(); } - void - run() + close() { - if (operatorID == EXPORT_E5ML && process_self().m_ID != 0) cdo_abort("This operator can't be linked with other operators!"); - - if (operatorID == IMPORT_E5ML) { im_e5ml(); } - else if (operatorID == EXPORT_E5ML) - { - ex_e5ml(); - } + // vlistDestroy(vlistID2); } +}; + +class Echam5ini_import : public Echam5ini +{ +public: + using Echam5ini::Echam5ini; + inline static CdoModule module = { + .name = "Echam5ini", + .operators = { { "import_e5ml"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Echam5ini_import> registration = RegisterEntry<Echam5ini_import>(module); +public: void - close() + run() { - // vlistDestroy(vlistID2); - - cdo_finish(); + im_e5ml(); } }; - -void * -Echam5ini(void *process) +class Echam5ini_export : public Echam5ini { - ModuleEcham5ini echam5ini; - echam5ini.init(process); - echam5ini.run(); - echam5ini.close(); +public: + using Echam5ini::Echam5ini; + inline static CdoModule module = { + .name = "Echam5ini", + .operators = { { "import_e5ml"}, { "export_e5ml"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, OnlyFirst }, + }; + inline static RegisterEntry<Echam5ini_export> registration = RegisterEntry<Echam5ini_export>(module); - return nullptr; -} +public: + void + run() + { + ex_e5ml(); + } +}; diff --git a/src/Enlarge.cc b/src/Enlarge.cc index e654cf0050a674eaa339c1e83be79ab31225f92e..f9fbf7836798ebebd0b8298bde80f681a00593d2 100644 --- a/src/Enlarge.cc +++ b/src/Enlarge.cc @@ -17,8 +17,19 @@ #include "process_int.h" #include "griddes.h" -class ModuleEnlarge +class Enlarge : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Enlarge", + .operators = { { "enlarge", EnlargeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Enlarge> registration = RegisterEntry<Enlarge>(module); bool linfo = true; CdoStreamID streamID1; @@ -39,9 +50,8 @@ class ModuleEnlarge public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(1); @@ -90,8 +100,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); auto missval = vlistInqVarMissval(vlistID1, varID); auto gridID1 = vlistInqVarGrid(vlistID1, varID); @@ -113,7 +123,7 @@ public: for (size_t iy = 0; iy < ysize2; iy++) for (size_t ix = 0; ix < xsize2; ix++) array2[ix + iy * xsize2] = array1[iy]; - if (nmiss) nmiss *= xsize2; + if (numMissVals) numMissVals *= xsize2; } else if (ysize1 == 1 && xsize1 == xsize2 && xsize1 * ysize1 == gridsize1) { @@ -126,18 +136,18 @@ public: for (size_t iy = 0; iy < ysize2; iy++) for (size_t ix = 0; ix < xsize2; ix++) array2[ix + iy * xsize2] = array1[ix]; - if (nmiss) nmiss *= ysize2; + if (numMissVals) numMissVals *= ysize2; } else { varray_copy(gridsize1, array1, array2); for (size_t i = gridsize1; i < gridsize2; ++i) array2[i] = array1[gridsize1 - 1]; - if (nmiss && DBL_IS_EQUAL(array1[gridsize1 - 1], missval)) nmiss += (gridsize2 - gridsize1); + if (numMissVals && DBL_IS_EQUAL(array1[gridsize1 - 1], missval)) numMissVals += (gridsize2 - gridsize1); } cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } tsID++; @@ -150,17 +160,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Enlarge(void *process) -{ - ModuleEnlarge enlarge; - enlarge.init(process); - enlarge.run(); - enlarge.close(); - return nullptr; -} diff --git a/src/Enlargegrid.cc b/src/Enlargegrid.cc index 26673841c6faa450791949eca4e91b9ea8d6a3a5..070e57194c6ed0a065c65d1e3ed1d9f0892ada61 100644 --- a/src/Enlargegrid.cc +++ b/src/Enlargegrid.cc @@ -105,8 +105,19 @@ genGridIndex(int gridID1, int gridID2, std::vector<long> &index) cdo_abort("Unsupported grid type: %s", gridNamePtr(gridtype1)); } -class ModuleEnlargegrid +class Enlargegrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Enlargegrid", + .operators = { { "enlargegrid"} }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Enlargegrid> registration = RegisterEntry<Enlargegrid>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -125,9 +136,8 @@ class ModuleEnlargegrid public: void - init(void *process) + init() { - cdo_initialize(process); operator_input_arg("grid description file or name"); if (cdo_operator_argc() < 1) cdo_abort("Too few arguments!"); @@ -185,8 +195,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); auto missval1 = vlistInqVarMissval(vlistID1, varID); @@ -194,9 +204,9 @@ public: for (size_t i = 0; i < gridsize1; ++i) if (gindex[i] >= 0) array2[gindex[i]] = array1[i]; - nmiss = varray_num_mv(gridsize2, array2, missval1); + numMissVals = varray_num_mv(gridsize2, array2, missval1); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } tsID++; @@ -208,18 +218,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Enlargegrid(void *process) -{ - ModuleEnlargegrid enlargegrid; - enlargegrid.init(process); - enlargegrid.run(); - enlargegrid.close(); - - return nullptr; -} diff --git a/src/Ensstat.cc b/src/Ensstat.cc index 62e911db5966abc1636ad6d6c479a9a075cdcc9e..6db973f17a0e45fc48a4352fd2f02b6873236646 100644 --- a/src/Ensstat.cc +++ b/src/Ensstat.cc @@ -78,7 +78,7 @@ ensstat_func(void *ensarg) auto hasMissvals = false; for (int fileID = 0; fileID < nfiles; ++fileID) - if (ef[fileID].field[t].nmiss > 0) hasMissvals = true; + if (ef[fileID].field[t].numMissVals > 0) hasMissvals = true; auto varID = arg->varID[t]; auto gridsize = ef[0].varList[varID].gridsize; @@ -95,7 +95,7 @@ ensstat_func(void *ensarg) auto &field = fields[ompthID]; field.missval = missval; - field.nmiss = 0; + field.numMissVals = 0; if (memType == MemType::Float) for (int fileID = 0; fileID < nfiles; ++fileID) field.vec_d[fileID] = ef[fileID].field[t].vec_f[i]; else @@ -107,7 +107,7 @@ ensstat_func(void *ensarg) if (dbl_is_equal(field.vec_d[fileID], ef[fileID].missval[t])) { field.vec_d[fileID] = missval; - field.nmiss++; + field.numMissVals++; } } @@ -115,13 +115,13 @@ ensstat_func(void *ensarg) if (dbl_is_equal(array2[i], field.missval)) atomicNumMiss++; - if (withCountData) count2[i] = nfiles - field.nmiss; + if (withCountData) count2[i] = nfiles - field.numMissVals; } - size_t nmiss = atomicNumMiss; + size_t numMissVals = atomicNumMiss; cdo_def_record(arg->streamID2, arg->varID[t], arg->levelID[t]); - cdo_write_record(arg->streamID2, array2, nmiss); + cdo_write_record(arg->streamID2, array2, numMissVals); if (withCountData) { @@ -132,29 +132,32 @@ ensstat_func(void *ensarg) return nullptr; } -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("ensrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("ensmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("ensmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("enssum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("ensmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("ensavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("ensstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("ensstd1", FieldFunc_Std1, 0, nullptr); - cdo_operator_add("ensvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("ensvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("ensskew", FieldFunc_Skew, 0, nullptr); - cdo_operator_add("enskurt", FieldFunc_Kurt, 0, nullptr); - cdo_operator_add("ensmedian", FieldFunc_Median, 0, nullptr); - cdo_operator_add("enspctl", FieldFunc_Pctl, 0, nullptr); - // clang-format on -} - -class ModuleEnsstat +class Ensstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ensstat", + .operators = { { "ensrange", FieldFunc_Range, 0, EnsstatHelp }, + { "ensmin", FieldFunc_Min, 0, EnsstatHelp }, + { "ensmax", FieldFunc_Max, 0, EnsstatHelp }, + { "enssum", FieldFunc_Sum, 0, EnsstatHelp }, + { "ensmean", FieldFunc_Mean, 0, EnsstatHelp }, + { "ensavg", FieldFunc_Avg, 0, EnsstatHelp }, + { "ensvar", FieldFunc_Var, 0, EnsstatHelp }, + { "ensvar1", FieldFunc_Var1, 0, EnsstatHelp }, + { "ensstd", FieldFunc_Std, 0, EnsstatHelp }, + { "ensstd1", FieldFunc_Std1, 0, EnsstatHelp }, + { "ensskew", FieldFunc_Skew, 0, EnsstatHelp }, + { "enskurt", FieldFunc_Kurt, 0, EnsstatHelp }, + { "ensmedian", FieldFunc_Median, 0, EnsstatHelp }, + { "enspctl", FieldFunc_Pctl, 0, EnsstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Ensstat> registration = RegisterEntry<Ensstat>(module); cdo::Task task; int nrecs0; @@ -175,11 +178,8 @@ class ModuleEnsstat public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); auto operatorID = cdo_operator_id(); auto operfunc = cdo_operator_f1(operatorID); @@ -338,10 +338,7 @@ public: task.start(ensstat_func, &ensstatArg); t = !t; } - else - { - ensstat_func(&ensstatArg); - } + else { ensstat_func(&ensstatArg); } } if (Options::CDO_task) task.wait(); @@ -360,18 +357,5 @@ public: for (int fileID = 0; fileID < nfiles; ++fileID) cdo_stream_close(ef[fileID].streamID); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Ensstat(void *process) -{ - ModuleEnsstat ensstat; - ensstat.init(process); - ensstat.run(); - ensstat.close(); - - return nullptr; -} diff --git a/src/Ensstat3.cc b/src/Ensstat3.cc index e484d0267108870ed2ff062ddcfaba3056f65236..08dad8cb093b0b2babaca08b5020f56df68e3c83 100644 --- a/src/Ensstat3.cc +++ b/src/Ensstat3.cc @@ -69,11 +69,30 @@ roc_curve_integrate(const Varray2D<double> &roc, int n) return area - 0.5; } -class ModuleEnsstat3 +class Ensstat3 : public Process { + enum + { + func_roc, + func_rank + }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ensstat3", + .operators = { { "ensrkhistspace", func_rank, space_data, Ensstat2Help }, + { "ensrkhisttime", func_rank, time_data, Ensstat2Help }, + { "ensroc", func_roc, 0, Ensstat2Help } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Ensstat3> registration = RegisterEntry<Ensstat3>(module); int j; int nrecs = 0, nrecs0; - size_t nmiss = 0; + size_t numMissVals = 0; int chksum = 0; // for check of histogram population int levelID, varID, binID = 0; int gridID, gridID2; @@ -87,12 +106,6 @@ class ModuleEnsstat3 int vlistID; }; - enum - { - func_roc, - func_rank - }; - std::vector<ens_file_t> ef; int nfiles; int operfunc; @@ -119,14 +132,10 @@ class ModuleEnsstat3 public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("ensroc", func_roc, 0, nullptr); - cdo_operator_add("ensrkhistspace", func_rank, space_data, nullptr); - cdo_operator_add("ensrkhisttime", func_rank, time_data, nullptr); // clang-format on auto operatorID = cdo_operator_id(); @@ -299,20 +308,20 @@ public: for (int recID = 0; recID < nrecs0; ++recID) { #ifdef _OPENMP -#pragma omp parallel for default(none) shared(ef, nfiles) private(nmiss) lastprivate(varID, levelID) +#pragma omp parallel for default(none) shared(ef, nfiles) private(numMissVals) lastprivate(varID, levelID) #endif for (int fileID = 0; fileID < nfiles; ++fileID) { auto streamID = ef[fileID].streamID; cdo_inq_record(streamID, &varID, &levelID); - cdo_read_record(streamID, ef[fileID].array.data(), &nmiss); + cdo_read_record(streamID, ef[fileID].array.data(), &numMissVals); } gridID = vlistInqVarGrid(vlistID1, varID); gridsize = gridInqSize(gridID); auto missval = vlistInqVarMissval(vlistID1, varID); - nmiss = 0; + numMissVals = 0; if (datafunc == TIME && operfunc == func_rank) for (binID = 0; binID < nfiles; binID++) array2[binID][0] = 0; @@ -324,7 +333,7 @@ public: auto ompthID = cdo_omp_get_thread_num(); field[ompthID].missval = missval; - field[ompthID].nmiss = 0; + field[ompthID].numMissVals = 0; have_miss = 0; for (int fileID = 0; fileID < nfiles; ++fileID) { @@ -422,7 +431,7 @@ public: double val = (double) array2[binID][0]; // fprintf(stderr,"%i ",(int)val); cdo_def_record(streamID2, varIDs2[varID], binID); - cdo_write_record(streamID2, &val, nmiss); + cdo_write_record(streamID2, &val, numMissVals); } // fprintf(stderr,"\n"); } @@ -465,7 +474,7 @@ public: for (int i = 0; i < osize; ++i) tmpdoub[i] = (double) array2[binID][i]; cdo_def_record(streamID2, varIDs2[varID], binID); - cdo_write_record(streamID2, tmpdoub.data(), nmiss); + cdo_write_record(streamID2, tmpdoub.data(), numMissVals); } } else if (operfunc == func_roc) @@ -498,18 +507,5 @@ public: for (int fileID = 0; fileID < nfiles; ++fileID) cdo_stream_close(ef[fileID].streamID); if (operfunc != func_roc) cdo_stream_close(streamID2); - - cdo_finish(); } }; -void * -Ensstat3(void *process) -{ - ModuleEnsstat3 ensstat3; - - ensstat3.init(process); - ensstat3.run(); - ensstat3.close(); - - return nullptr; -} diff --git a/src/Ensval.cc b/src/Ensval.cc index 47e04fb71e3f1c1fdedebc7f05ab69d6727234e9..7732a4f431e677d5d802e1dc3f36f74bfab0a865 100644 --- a/src/Ensval.cc +++ b/src/Ensval.cc @@ -15,8 +15,6 @@ Score for Ensemble Prediction Systems, in: Weather and Forecasting (15) pp. 559-570 */ -#include <algorithm> // sort - #include <cdi.h> #include "process_int.h" @@ -47,11 +45,22 @@ enum RESTYPE_CRPS CRPS_POT }; -class ModuleEnsval +class Ensval : public Process { - int k; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ensval", + .operators = { { "enscrps", CRPS, 0, EnsvalHelp }, { "ensbrs", BRS, 0, EnsvalHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, OBASE, NoRestriction }, + }; + inline static RegisterEntry<Ensval> registration = RegisterEntry<Ensval>(module); + int nrecs = 0, nostreams = 0, ngrids; - size_t nmiss; + size_t numMissVals; int levelID = -1, varID = -1; size_t gridsize = 0; int vlistID; @@ -98,13 +107,8 @@ class ModuleEnsval public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("enscrps", CRPS, 0, nullptr); - cdo_operator_add("ensbrs", BRS, 0, nullptr); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -208,8 +212,7 @@ public: auto ofilename = ofilebase + string_format(".%s", typeSuffix); if (ofilename.size() > 0) ofilename += fileSuffix; - if (!Options::cdoOverwriteMode && FileUtils::file_exists(ofilename) - && !FileUtils::user_file_overwrite(ofilename)) + if (!Options::cdoOverwriteMode && FileUtils::file_exists(ofilename) && !FileUtils::user_file_overwrite(ofilename)) cdo_abort("Outputfile %s already exists!", ofilename); streamID2[stream] = cdo_open_write(ofilename.c_str()); @@ -228,6 +231,7 @@ public: varList_init(varList1, vlistID1); } + void run() { @@ -265,7 +269,7 @@ public: ef[fileID].array.resize(gridsize); - cdo_read_record(streamID, ef[fileID].array.data(), &nmiss); + cdo_read_record(streamID, ef[fileID].array.data(), &numMissVals); } // xsize = gridInqXsize(gridID); @@ -280,11 +284,11 @@ public: else */ { - varray_fill(weights, 1.0 / gridsize); + ranges::fill(weights, 1.0 / gridsize); sum_weights = 1.0; } - nmiss = 0; + numMissVals = 0; heavyside0 = 0; heavysideN = 0; @@ -308,7 +312,7 @@ public: } auto &x = val; - std::sort(x.begin(), x.end()); // Sort The Ensemble Array to ascending order + ranges::sort(x); // Sort The Ensemble Array to ascending order // only process if no missing value in ensemble if (!have_miss && operfunc == CRPS) @@ -326,7 +330,7 @@ public: } // Loop start at zero ==> 1st ensemble (c-indexing) - for (k = 0; k < nens - 1; ++k) + for (int k = 0; k < nens - 1; ++k) { // Cumulate alpha and beta if (xa > x[k + 1]) // left of heavyside alpha[k + 1] += (x[k + 1] - x[k]) * weights[i]; @@ -349,7 +353,7 @@ public: else if (x[nens - 1] < brs_thresh) brs_g[nens] += weights[i]; else - for (k = 0; k < nens - 1; ++k) + for (int k = 0; k < nens - 1; ++k) { if (x[k + 1] >= brs_thresh && brs_thresh >= x[k]) { @@ -366,7 +370,7 @@ public: else if (x[nens - 1] < xa) brs_o[nens] += weights[i]; else - for (k = 0; k < nens - 1; ++k) + for (int k = 0; k < nens - 1; ++k) { if (x[k + 1] >= xa && xa >= x[k]) { @@ -389,7 +393,7 @@ public: crps = g * ((1. - o) * p * p + o * (1. - p) * (1. - p)); // Middle Bins - for (k = 1; k < nens; ++k) + for (int k = 1; k < nens; ++k) { p = (double) k / (double) nens; @@ -430,7 +434,7 @@ public: brs_uncty = 0; double gsum = 0, obar = 0, osum = 0; - for (k = 0; k <= nens; ++k) + for (int k = 0; k <= nens; ++k) { obar += brs_g[k] * brs_o[k]; gsum += brs_g[k]; @@ -446,7 +450,7 @@ public: double o = 0, p = 0, g = 0; brs_uncty = obar * (1 - obar); - for (k = 0; k <= nens; ++k) + for (int k = 0; k <= nens; ++k) { g = brs_g[k]; @@ -489,14 +493,14 @@ public: switch (operfunc) { case (CRPS): - varray_fill(alpha, 0.0); - varray_fill(beta, 0.0); + ranges::fill(alpha, 0.0); + ranges::fill(beta, 0.0); heavyside0 = 0; heavysideN = 0; break; case (BRS): - varray_fill(brs_o, 0.0); - varray_fill(brs_g, 0.0); + ranges::fill(brs_o, 0.0); + ranges::fill(brs_g, 0.0); break; } } // for ( int recID = 0; recID < nrecs; recID++ ) @@ -504,6 +508,7 @@ public: } while (nrecs); } + void close() { @@ -522,19 +527,5 @@ public: } gridDestroy(gridID2); - - cdo_finish(); } }; - -void * -Ensval(void *process) -{ - ModuleEnsval ensval; - - ensval.init(process); - ensval.run(); - ensval.close(); - - return nullptr; -} diff --git a/src/Eof3d.cc b/src/Eof3d.cc index 72b092b408d3bb963add26a6af04f470d5227e23..3ba52a16ece8156b6f78276860e2805cd42318ac 100644 --- a/src/Eof3d.cc +++ b/src/Eof3d.cc @@ -37,7 +37,7 @@ // NO MISSING VALUE SUPPORT ADDED SO FAR -class ModuleEOF3d +class EOF3d : public Process { enum { @@ -46,10 +46,24 @@ class ModuleEOF3d EOF3D_SPATIAL }; +public: + using Process::Process; + inline static CdoModule module = { + .name = "EOF3d", + .operators = { { "eof3d", EOF3D_, 0, EOFsHelp }, + { "eof3dspatial", EOF3D_SPATIAL, 0, EOFsHelp }, + { "eof3dtime", EOF3D_TIME, 0, EOFsHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 2, OnlyFirst }, + }; + inline static RegisterEntry<EOF3d> registration = RegisterEntry<EOF3d>(module); + size_t temp_size = 0, npack = 0; int varID, levelID; bool missval_warning = false; - size_t nmiss; + size_t numMissVals; int ngrids; int calendar = CALENDAR_STANDARD; @@ -86,15 +100,10 @@ class ModuleEOF3d public: void - init(void *process) + init() { - cdo_initialize(process); - // clang-format off - cdo_operator_add("eof3d", EOF3D_, 0, nullptr); - cdo_operator_add("eof3dtime", EOF3D_TIME, 0, nullptr); - cdo_operator_add("eof3dspatial", EOF3D_SPATIAL, 0, nullptr); // clang-format on const auto operatorID = cdo_operator_id(); @@ -225,7 +234,7 @@ public: const auto gridsize = varList1[varID].gridsize; const auto missval = varList1[varID].missval; - cdo_read_record(streamID1, in.data(), &nmiss); + cdo_read_record(streamID1, in.data(), &numMissVals); const auto offset = gridsize * levelID; for (size_t i = 0; i < gridsize; ++i) @@ -440,16 +449,16 @@ public: const auto offset = levelID * gridsizemax; if (tsID < n_eig) { - nmiss = array_num_mv(gridsizemax, &eigenvectors[varID][tsID][offset], missval); + numMissVals = array_num_mv(gridsizemax, &eigenvectors[varID][tsID][offset], missval); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, &eigenvectors[varID][tsID][offset], nmiss); + cdo_write_record(streamID3, &eigenvectors[varID][tsID][offset], numMissVals); } } - nmiss = (DBL_IS_EQUAL(eigenvalues[varID][tsID][0], missval)) ? 1 : 0; + numMissVals = (DBL_IS_EQUAL(eigenvalues[varID][tsID][0], missval)) ? 1 : 0; cdo_def_record(streamID2, varID, 0); - cdo_write_record(streamID2, eigenvalues[varID][tsID].data(), nmiss); + cdo_write_record(streamID2, eigenvalues[varID][tsID].data(), numMissVals); } // for ( varID = 0; ... ) } // for ( tsID = 0; ... ) } @@ -460,17 +469,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -EOF3d(void *process) -{ - ModuleEOF3d eof3d; - eof3d.init(process); - eof3d.run(); - eof3d.close(); - return nullptr; -} diff --git a/src/Eofcoeff.cc b/src/Eofcoeff.cc index 5d9c405c7b8c794614c82d53ef5e8392f375c90f..0488508dbbe567a306a636477c5fafdbdc32d0c2 100644 --- a/src/Eofcoeff.cc +++ b/src/Eofcoeff.cc @@ -21,12 +21,24 @@ // NO MISSING VALUE SUPPORT ADDED SO FAR -class ModuleEofcoeff +class Eofcoeff : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Eofcoeff", + .operators = { { "eofcoeff", EofcoeffHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Eofcoeff> registration = RegisterEntry<Eofcoeff>(module); + double missval1 = -999, missval2; int varID, levelID; int nrecs; - size_t nmiss; + size_t numMissVals; CdoStreamID streamID1; CdoStreamID streamID2; @@ -52,15 +64,8 @@ class ModuleEofcoeff public: void - init(void *process) + init() { - - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); - - cdo_operator_add("eofcoeff", 0, 0, nullptr); - streamID1 = cdo_open_read(0); streamID2 = cdo_open_read(1); @@ -93,6 +98,7 @@ public: eofID = 0; } + void run() { @@ -109,13 +115,13 @@ public: eof[varID][levelID][eofID].grid = gridID1; eof[varID][levelID][eofID].missval = missval1; eof[varID][levelID][eofID].resize(gridsize); - varray_fill(gridsize, eof[varID][levelID][eofID].vec_d, missval1); + ranges::fill(eof[varID][levelID][eofID].vec_d, missval1); if (varID >= nvars) cdo_abort("Internal error - varID >= nvars"); if (levelID >= nlevs) cdo_abort("Internal error - levelID >= nlevs"); - cdo_read_record(streamID1, eof[varID][levelID][eofID].vec_d.data(), &nmiss); - eof[varID][levelID][eofID].nmiss = nmiss; + cdo_read_record(streamID1, eof[varID][levelID][eofID].vec_d.data(), &numMissVals); + eof[varID][levelID][eofID].numMissVals = numMissVals; } eofID++; } @@ -159,7 +165,7 @@ public: in.resize(gridsize); in.grid = gridID1; out.missval = missval1; - out.nmiss = 0; + out.numMissVals = 0; out.resize(1); int tsID = 0; @@ -179,7 +185,7 @@ public: { cdo_inq_record(streamID2, &varID, &levelID); missval2 = vlistInqVarMissval(vlistID2, varID); - cdo_read_record(streamID2, in.vec_d.data(), &in.nmiss); + cdo_read_record(streamID2, in.vec_d.data(), &in.numMissVals); for (eofID = 0; eofID < neof; eofID++) { @@ -197,16 +203,16 @@ public: } } if (!DBL_IS_EQUAL(out.vec_d[0], 0.)) - nmiss = 0; + numMissVals = 0; else { - nmiss = 1; + numMissVals = 1; out.vec_d[0] = missval2; } cdo_def_record(streamIDs[eofID], varID, levelID); // fprintf(stderr, "%d %d %d %d %d %g\n", streamIDs[eofID],tsID, recID, varID, levelID,*out.vec_d.data()); - cdo_write_record(streamIDs[eofID], out.vec_d.data(), nmiss); + cdo_write_record(streamIDs[eofID], out.vec_d.data(), numMissVals); } if (varID >= nvars) cdo_abort("Internal error - varID >= nvars"); if (levelID >= nlevs) cdo_abort("Internal error - levelID >= nlevs"); @@ -215,6 +221,7 @@ public: tsID++; } } + void close() { @@ -222,19 +229,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Eofcoeff(void *process) -{ - ModuleEofcoeff eofcoeff; - - eofcoeff.init(process); - eofcoeff.run(); - eofcoeff.close(); - - return nullptr; -} diff --git a/src/Eofcoeff3d.cc b/src/Eofcoeff3d.cc index 5f1ba279f62dd68b65aa9d7e2a03fd91dcfd1d81..0768bf594337954a7935fab09cb7b3e35fc33f2d 100644 --- a/src/Eofcoeff3d.cc +++ b/src/Eofcoeff3d.cc @@ -21,12 +21,24 @@ // NO MISSING VALUE SUPPORT ADDED SO FAR -class ModuleEofcoeff3d +class Eofcoeff3d : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Eofcoeff3d", + .operators = { { "eofcoeff3d", EofcoeffHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Eofcoeff3d> registration = RegisterEntry<Eofcoeff3d>(module); + double missval1 = -999, missval2 = -999; int varID, levelID; int nrecs; - size_t nmiss; + size_t numMissVals; CdoStreamID streamID1; CdoStreamID streamID2; @@ -53,14 +65,8 @@ class ModuleEofcoeff3d public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); - - cdo_operator_add("eofcoeff3d", 0, 0, nullptr); - streamID1 = cdo_open_read(0); streamID2 = cdo_open_read(1); @@ -106,13 +112,13 @@ public: eof[varID][levelID][eofID].grid = gridID1; eof[varID][levelID][eofID].missval = missval1; eof[varID][levelID][eofID].resize(gridsize); - varray_fill(gridsize, eof[varID][levelID][eofID].vec_d, missval1); + ranges::fill(eof[varID][levelID][eofID].vec_d, missval1); if (varID >= nvars) cdo_abort("Internal error - varID >= nvars"); if (levelID >= nlevs) cdo_abort("Internal error - levelID >= nlevs"); - cdo_read_record(streamID1, eof[varID][levelID][eofID].vec_d.data(), &nmiss); - eof[varID][levelID][eofID].nmiss = nmiss; + cdo_read_record(streamID1, eof[varID][levelID][eofID].vec_d.data(), &numMissVals); + eof[varID][levelID][eofID].numMissVals = numMissVals; } eofID++; } @@ -121,7 +127,7 @@ public: if (Options::cdoVerbose) cdo_print("%s contains %i eof's", cdo_get_stream_name(0), neof); // Create 1x1 Grid for output - const auto gridID3 = gridCreate(GRID_LONLAT, 1); + auto gridID3 = gridCreate(GRID_LONLAT, 1); gridDefXsize(gridID3, 1); gridDefYsize(gridID3, 1); double xvals = 0, yvals = 0; @@ -129,7 +135,7 @@ public: gridDefYvals(gridID3, &yvals); double zvals = 0.; - const auto zaxisID3 = zaxisCreate(ZAXIS_GENERIC, 1); + auto zaxisID3 = zaxisCreate(ZAXIS_GENERIC, 1); zaxisDefLevels(zaxisID3, &zvals); cdiDefKeyString(zaxisID3, CDI_GLOBAL, CDI_KEY_NAME, "zaxis_Reduced"); cdiDefKeyString(zaxisID3, CDI_GLOBAL, CDI_KEY_LONGNAME, @@ -137,12 +143,12 @@ public: // Create var-list and time-axis for output - const auto vlistID3 = vlistDuplicate(vlistID2); + auto vlistID3 = vlistDuplicate(vlistID2); - const auto ngrids = vlistNgrids(vlistID3); + auto ngrids = vlistNgrids(vlistID3); for (int i = 0; i < ngrids; ++i) vlistChangeGridIndex(vlistID3, i, gridID3); - const auto nzaxis = vlistNzaxis(vlistID3); + auto nzaxis = vlistNzaxis(vlistID3); for (int i = 0; i < nzaxis; ++i) vlistChangeZaxisIndex(vlistID3, i, zaxisID3); vlistDefTaxis(vlistID3, taxisID3); @@ -175,7 +181,7 @@ public: for (eofID = 0; eofID < neof; eofID++) { out[varID][eofID].missval = missval1; - out[varID][eofID].nmiss = 0; + out[varID][eofID].numMissVals = 0; out[varID][eofID].resize(1); } } @@ -199,14 +205,14 @@ public: for (int recID = 0; recID < nrecs; ++recID) { cdo_inq_record(streamID2, &varID, &levelID); - cdo_read_record(streamID2, in.vec_d.data(), &in.nmiss); + cdo_read_record(streamID2, in.vec_d.data(), &in.numMissVals); missval2 = vlistInqVarMissval(vlistID2, varID); for (eofID = 0; eofID < neof; eofID++) { if (recID == 0) cdo_def_timestep(streamIDs[eofID], tsID); - nmiss = 0; + numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) { if (!DBL_IS_EQUAL(in.vec_d[i], missval2) && !DBL_IS_EQUAL(eof[varID][levelID][eofID].vec_d[i], missval1)) @@ -215,11 +221,11 @@ public: out[varID][eofID].vec_d[0] += in.vec_d[i] * eof[varID][levelID][eofID].vec_d[i]; } else - nmiss += 1; + numMissVals += 1; } /* - if ( nmiss ) { - out[varID][eofID].nmiss=1; + if ( numMissVals ) { + out[varID][eofID].numMissVals=1; out[varID][eofID].vec_d[0] = missval2; } */ @@ -234,7 +240,7 @@ public: for (varID = 0; varID < nvars; ++varID) { cdo_def_record(streamIDs[eofID], varID, 0); - cdo_write_record(streamIDs[eofID], out[varID][eofID].vec_d.data(), out[varID][eofID].nmiss); + cdo_write_record(streamIDs[eofID], out[varID][eofID].vec_d.data(), out[varID][eofID].numMissVals); } } @@ -249,18 +255,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Eofcoeff3d(void *process) -{ - ModuleEofcoeff3d eofcoeff3d; - eofcoeff3d.init(process); - eofcoeff3d.run(); - eofcoeff3d.close(); - - return nullptr; -} diff --git a/src/EstFreq.cc b/src/EstFreq.cc index 6cfc112e03135551170003dd1ce5e5fdef357dec..022bc532a5ece867ed60f2ccce93456d2d15ad0e 100644 --- a/src/EstFreq.cc +++ b/src/EstFreq.cc @@ -10,8 +10,19 @@ #include "process_int.h" #include "cdo_options.h" -class ModuleEstFreq +class EstFreq : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "EstFreq", + .operators = { { "estfreq"} }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<EstFreq> registration = RegisterEntry<EstFreq>(module); int tsID = 0; int fyear = 0, lyear, fmonth = 0, lmonth, dummy; int step_per_year = 0, currentyear, currentmon; @@ -34,11 +45,9 @@ class ModuleEstFreq public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); dataIsUnchanged = data_is_unchanged(); @@ -166,17 +175,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -EstFreq(void *process) -{ - ModuleEstFreq estFreq; - estFreq.init(process); - estFreq.run(); - estFreq.close(); - return nullptr; -} diff --git a/src/Exprf.cc b/src/Exprf.cc index 822d604f3f4e81d3de5bda180c802c166d7d77b2..3ed3617b63a6ddbcb60e511e7cd68b2ca6e1b550 100644 --- a/src/Exprf.cc +++ b/src/Exprf.cc @@ -72,7 +72,7 @@ exprs_from_file(const std::vector<std::string> &exprArgv) return buffer.str(); } -#define MAX_PARAMS 4096 +constexpr int MaxParams = 4096; static std::size_t replace_all(std::string &inout, const std::string &what, const std::string &with) @@ -160,7 +160,7 @@ params_init(std::vector<ParamEntry> ¶ms, const VarList &varList, int vlistID static void params_delete(const std::vector<ParamEntry> ¶ms) { - for (int varID = 0; varID < MAX_PARAMS; ++varID) + for (int varID = 0; varID < MaxParams; ++varID) { if (params[varID].data) delete[] params[varID].data; } @@ -256,8 +256,8 @@ parse_param_init(ParseParamType &parseArg, int vlistID, int pointID, int zonalID auto nzaxis = vlistNzaxis(vlistID); auto maxCoords = ngrids * 5 + nzaxis * 3; - parseArg.maxparams = MAX_PARAMS; - parseArg.params.resize(MAX_PARAMS); + parseArg.maxparams = MaxParams; + parseArg.params.resize(MaxParams); parseArg.nparams = nvars; parseArg.cnparams = nvars; parseArg.nvars1 = nvars; @@ -327,19 +327,23 @@ set_date_and_time(ParamEntry &varts, int calendar, int tsID, const CdiDateTime & varts.data[CoordIndex::DPY] = days_per_year(calendar, year); } -static void -addOperators(void) +class Exprf : public Process { - // clang-format off - cdo_operator_add("expr", 1, 1, "expressions"); - cdo_operator_add("exprf", 1, 0, "expr script filename"); - cdo_operator_add("aexpr", 0, 1, "expressions"); - cdo_operator_add("aexprf", 0, 0, "expr script filename"); - // clang-format on -} +public: + using Process::Process; + inline static CdoModule module = { + .name = "Exprf", + .operators = { { "expr", 1, 1, "expressions", ExprHelp }, + { "exprf", 1, 0, "exprscriptfilename", ExprHelp }, + { "aexpr", 0, 1, "expressions", ExprHelp }, + { "aexprf", 0, 0, "exprscriptfilename", ExprHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Exprf> registration = RegisterEntry<Exprf>(module); -class ModuleExprf -{ CdoStreamID streamID1; CdoStreamID streamID2; @@ -366,12 +370,8 @@ class ModuleExprf public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); - auto operatorID = cdo_operator_id(); bool replacesVariables = cdo_operator_f1(operatorID); bool readsCommandLine = cdo_operator_f2(operatorID); @@ -564,7 +564,7 @@ public: } else if (coord == 'd') { - varray_fill(nlev, cdata, 1.0); + ranges::fill(cdata, 1.0); if (zaxisInqLbounds(zaxisID, nullptr) && zaxisInqUbounds(zaxisID, nullptr)) { std::vector<double> lbounds(nlev), ubounds(nlev); @@ -646,7 +646,7 @@ public: // for (int varID = 0; varID < nvars1; ++varID) printf(">>> %s %d\n", params[varID].name.c_str(), params[varID].isValid); for (int varID = 0; varID < nvars1; ++varID) params[varID].isValid = true; for (int varID = 0; varID < nvars1; ++varID) - if (tsID == 0 || params[varID].steptype != TIME_CONSTANT) params[varID].nmiss = 0; + if (tsID == 0 || params[varID].steptype != TIME_CONSTANT) params[varID].numMissVals = 0; for (int recID = 0; recID < nrecs; ++recID) { @@ -656,11 +656,11 @@ public: { auto offset = params[varID].ngp * levelID; auto vardata = params[varID].data + offset; - size_t nmiss; - cdo_read_record(streamID1, vardata, &nmiss); - params[varID].nmiss += nmiss; + size_t numMissVals; + cdo_read_record(streamID1, vardata, &numMissVals); + params[varID].numMissVals += numMissVals; - if (nmiss > 0) cdo_check_missval(params[varID].missval, params[varID].name); + if (numMissVals > 0) cdo_check_missval(params[varID].missval, params[varID].name); } } @@ -669,8 +669,9 @@ public: auto pidx = varIDmap[varID]; if (pidx < nvars1) continue; - params[pidx].nmiss = 0; - varray_fill(params[pidx].ngp * params[pidx].nlev, params[pidx].data, 0.0); + auto ¶m = params[pidx]; + param.numMissVals = 0; + ranges::fill_n(param.data, param.ngp * param.nlev, 0.0); } parseArg.cnparams = vartsID + 1; @@ -698,9 +699,9 @@ public: { auto offset = ngp * levelID; double *vardata = params[pidx].data + offset; - auto nmiss = array_num_mv(ngp, vardata, missval); + auto numMissVals = array_num_mv(ngp, vardata, missval); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, vardata, nmiss); + cdo_write_record(streamID2, vardata, numMissVals); } } @@ -720,18 +721,5 @@ public: gridDestroy(pointID); if (zonalID != -1) gridDestroy(zonalID); - - cdo_finish(); } }; - -void * -Exprf(void *process) -{ - ModuleExprf expr; - expr.init(process); - expr.run(); - expr.close(); - - return nullptr; -} diff --git a/src/FC.cc b/src/FC.cc index 4e52c0ef23e527139315eec23b019c5fbb94f876..c9d9725d9bc3c501e0978605415903d209bc349d 100644 --- a/src/FC.cc +++ b/src/FC.cc @@ -47,8 +47,25 @@ vlistGetFirstReg2DGrid(int vlistID) return -1; } -class ModuleFC +class FC : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "FC", + .operators = { { "fc2sp"}, + { "sp2fc"}, + { "fc2gp"}, + { "gp2fc"}, + { "fourier2grid", 1, 0, nullptr}, + { "grid2fourier", 1, 0, nullptr} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<FC> registration = RegisterEntry<FC>(module); + int FC2SP, SP2FC, FC2GP, GP2FC, GRID2FOURIER, FOURIER2GRID; int gridID1 = -1, gridID2 = -1; size_t nlon = 0, nlat = 0; int ntr = 0; @@ -73,24 +90,21 @@ class ModuleFC FC_Transformation fcTrans; SP_Transformation spTrans; - int FC2SP, SP2FC, FC2GP, GP2FC, GRID2FOURIER, FOURIER2GRID; - public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); dataIsUnchanged = data_is_unchanged(); - FC2SP = cdo_operator_add("fc2sp", 0, 0, nullptr); - SP2FC = cdo_operator_add("sp2fc", 0, 0, nullptr); - FC2GP = cdo_operator_add("fc2gp", 0, 0, nullptr); - GP2FC = cdo_operator_add("gp2fc", 0, 0, nullptr); - GRID2FOURIER = cdo_operator_add("grid2fourier", 1, 0, nullptr); - FOURIER2GRID = cdo_operator_add("fourier2grid", 1, 0, nullptr); + FC2SP = module.get_id("fc2sp"); + SP2FC = module.get_id("sp2fc"); + FC2GP = module.get_id("fc2gp"); + GP2FC = module.get_id("gp2fc"); + GRID2FOURIER = module.get_id("grid2fourier"); + FOURIER2GRID = module.get_id("fourier2grid"); operatorID = cdo_operator_id(); auto operfunc = cdo_operator_f1(operatorID); @@ -313,9 +327,9 @@ public: if (vars[varID]) { - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); - if (nmiss) cdo_abort("Missing values unsupported for spectral/fourier data!"); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported for spectral/fourier data!"); gridID1 = vlistInqVarGrid(vlistID1, varID); if (operatorID == FC2SP) @@ -331,7 +345,7 @@ public: else if (operatorID == GRID2FOURIER) grid2fourier(gridID1, array1, gridID2, array2); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } else { @@ -339,9 +353,9 @@ public: if (dataIsUnchanged) { cdo_copy_record(streamID2, streamID1); } else { - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); - cdo_write_record(streamID2, array1.data(), nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); + cdo_write_record(streamID2, array1.data(), numMissVals); } } } @@ -355,19 +369,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -FC(void *process) -{ - ModuleFC fc; - - fc.init(process); - fc.run(); - fc.close(); - - return nullptr; -} diff --git a/src/Filedes.cc b/src/Filedes.cc index a2c01833c06b717682114f5a74cb49923733394d..7fedd603db48426419d963049e7a9222a268f79b 100644 --- a/src/Filedes.cc +++ b/src/Filedes.cc @@ -305,8 +305,30 @@ filedes(CdoStreamID streamID) printf("\n"); } -class ModuleFiledes +class Filedes : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Filedes", + .operators = { { "filedes", FiledesHelp }, + { "griddes", FiledesHelp }, + { "griddes2", FiledesHelp }, + { "zaxisdes", FiledesHelp }, + { "vct", FiledesHelp }, + { "vct2", FiledesHelp }, + { "codetab", FiledesHelp }, + { "vlist", FiledesHelp }, + { "partab", FiledesHelp }, + { "partab2", FiledesHelp }, + { "spartab", FiledesHelp } }, + .aliases = { { "vardes", "codetab" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Filedes> registration = RegisterEntry<Filedes>(module); + int GRIDDES, GRIDDES2, ZAXISDES, VCT, VCT2, CODETAB, FILEDES, VLIST, SPARTAB, PARTAB, PARTAB2; int operatorID; CdoStreamID streamID; @@ -315,26 +337,23 @@ class ModuleFiledes VarList varList; - int GRIDDES, GRIDDES2, ZAXISDES, VCT, VCT2, CODETAB, FILEDES, VLIST, SPARTAB, PARTAB, PARTAB2; - public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - GRIDDES = cdo_operator_add("griddes", 0, 0, nullptr); - GRIDDES2 = cdo_operator_add("griddes2", 0, 0, nullptr); - ZAXISDES = cdo_operator_add("zaxisdes", 0, 0, nullptr); - VCT = cdo_operator_add("vct", 0, 0, nullptr); - VCT2 = cdo_operator_add("vct2", 0, 0, nullptr); - CODETAB = cdo_operator_add("codetab", 0, 0, nullptr); - FILEDES = cdo_operator_add("filedes", 0, 0, nullptr); - VLIST = cdo_operator_add("vlist", 0, 0, nullptr); - SPARTAB = cdo_operator_add("spartab", 0, 0, nullptr); - PARTAB = cdo_operator_add("partab", 0, 0, nullptr); - PARTAB2 = cdo_operator_add("partab2", 0, 0, nullptr); +GRIDDES = module.get_id("griddes"); +GRIDDES2 = module.get_id("griddes2"); +ZAXISDES = module.get_id("zaxisdes"); +VCT = module.get_id("vct"); +VCT2 = module.get_id("vct2"); +CODETAB = module.get_id("codetab"); +FILEDES = module.get_id("filedes"); +VLIST = module.get_id("vlist"); +SPARTAB = module.get_id("spartab"); +PARTAB = module.get_id("partab"); +PARTAB2 = module.get_id("partab2"); // clang-format on operatorID = cdo_operator_id(); @@ -386,19 +405,5 @@ public: cdo_stream_close(streamID); if (!cdo::stdoutIsTerminal) Options::silentMode = true; - - cdo_finish(); } }; - -void * -Filedes(void *process) -{ - ModuleFiledes filedes; - - filedes.init(process); - filedes.run(); - filedes.close(); - - return nullptr; -} diff --git a/src/Fillmiss.cc b/src/Fillmiss.cc index 94b037f42eb2e4bd5eda07bfffa7a6d731241c84..0eac20c544104b65a9aa96b7749d4174ede5fb46 100644 --- a/src/Fillmiss.cc +++ b/src/Fillmiss.cc @@ -281,12 +281,12 @@ fillmiss_one_step(Field &field1, Field &field2, int maxfill) template <typename T> void -setmisstodis(size_t nmiss, int gridID, Varray<T> &vIn, Varray<T> &vOut, T missval, int numNeighbors) +setmisstodis(size_t numMissVals, int gridID, Varray<T> &vIn, Varray<T> &vOut, T missval, int numNeighbors) { auto gridID0 = gridID; auto gridsize = gridInqSize(gridID); - auto nvals = gridsize - nmiss; + auto nvals = gridsize - numMissVals; gridID = generate_full_point_grid(gridID); if (!gridHasCoordinates(gridID)) cdo_abort("Cell center coordinates missing!"); @@ -307,7 +307,7 @@ setmisstodis(size_t nmiss, int gridID, Varray<T> &vIn, Varray<T> &vOut, T missva cdo_grid_to_radian(gridID, CDI_XAXIS, xvals, "grid center lon"); cdo_grid_to_radian(gridID, CDI_YAXIS, yvals, "grid center lat"); - std::vector<size_t> mindex(nmiss, 1), vindex(nvals, 1); + std::vector<size_t> mindex(numMissVals, 1), vindex(nvals, 1); Varray<double> lons(nvals), lats(nvals); size_t nv = 0, nm = 0; @@ -340,7 +340,7 @@ setmisstodis(size_t nmiss, int gridID, Varray<T> &vIn, Varray<T> &vOut, T missva GridPointSearch gps; - if (nmiss) + if (numMissVals) { auto xIsCyclic = false; size_t dims[2] = { nvals, 0 }; @@ -359,10 +359,10 @@ setmisstodis(size_t nmiss, int gridID, Varray<T> &vIn, Varray<T> &vOut, T missva #ifdef _OPENMP #pragma omp parallel for default(shared) schedule(static) #endif - for (size_t i = 0; i < nmiss; ++i) + for (size_t i = 0; i < numMissVals; ++i) { atomicCount++; - if (cdo_omp_get_thread_num() == 0) progress::update(0, 1, (double) atomicCount / nmiss); + if (cdo_omp_get_thread_num() == 0) progress::update(0, 1, (double) atomicCount / numMissVals); auto ompthID = cdo_omp_get_thread_num(); @@ -373,7 +373,8 @@ setmisstodis(size_t nmiss, int gridID, Varray<T> &vIn, Varray<T> &vOut, T missva if (nadds) { double result = 0.0; - for (size_t n = 0; n < nadds; ++n) result += vIn[vindex[knnWeights[ompthID].m_indices[n]]] * knnWeights[ompthID].m_dist[n]; + for (size_t n = 0; n < nadds; ++n) + result += vIn[vindex[knnWeights[ompthID].m_indices[n]]] * knnWeights[ompthID].m_dist[n]; vOut[mindex[i]] = result; } } @@ -393,13 +394,28 @@ setmisstodis(Field &field1, Field &field2, int numNeighbors) if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); if (field1.memType == MemType::Float) - setmisstodis(field1.nmiss, field1.grid, field1.vec_f, field2.vec_f, (float) field1.missval, numNeighbors); + setmisstodis(field1.numMissVals, field1.grid, field1.vec_f, field2.vec_f, (float) field1.missval, numNeighbors); else - setmisstodis(field1.nmiss, field1.grid, field1.vec_d, field2.vec_d, field1.missval, numNeighbors); + setmisstodis(field1.numMissVals, field1.grid, field1.vec_d, field2.vec_d, field1.missval, numNeighbors); } -class ModuleFillmiss +class Fillmiss : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Fillmiss", + .operators = { { "fillmiss", 0, 0, "nfill"}, + { "fillmiss2", 0, 0, "nfill"}, + { "setmisstonn", 0, 0, "", SetmissHelp }, + { "setmisstodis", 0, 0, "numberofneighbors", SetmissHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Fillmiss> registration = RegisterEntry<Fillmiss>(module); + int FILLMISS, FILLMISS2, SETMISSTONN, SETMISSTODIS; CdoStreamID streamID1; CdoStreamID streamID2; @@ -413,19 +429,17 @@ class ModuleFillmiss Field field1, field2; void (*fill_method)(Field &, Field &, int) = &setmisstodis; - int FILLMISS, FILLMISS2, SETMISSTONN, SETMISSTODIS; public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - FILLMISS = cdo_operator_add("fillmiss" , 0, 0, "nfill"); - FILLMISS2 = cdo_operator_add("fillmiss2" , 0, 0, "nfill"); - SETMISSTONN = cdo_operator_add("setmisstonn" , 0, 0, ""); - SETMISSTODIS = cdo_operator_add("setmisstodis" , 0, 0, "number of neighbors"); +FILLMISS = module.get_id("fillmiss"); +FILLMISS2 = module.get_id("fillmiss2"); +SETMISSTONN = module.get_id("setmisstonn"); +SETMISSTODIS = module.get_id("setmisstodis"); operatorID = cdo_operator_id(); @@ -484,19 +498,18 @@ public: cdo_def_record(streamID2, varID, levelID); - if (field1.nmiss == 0 || field1.nmiss == varList1[varID].gridsize) { cdo_write_record(streamID2, field1); } + if (field1.numMissVals == 0 || field1.numMissVals == varList1[varID].gridsize) { cdo_write_record(streamID2, field1); } else { auto gridtype = gridInqType(varList1[varID].gridID); - if ((operatorID == FILLMISS || operatorID == FILLMISS2) - && (gridtype == GRID_GME || gridtype == GRID_UNSTRUCTURED)) + if ((operatorID == FILLMISS || operatorID == FILLMISS2) && (gridtype == GRID_GME || gridtype == GRID_UNSTRUCTURED)) cdo_abort("%s data unsupported!", gridNamePtr(gridtype)); field2.init(varList1[varID]); fill_method(field1, field2, nfill); - field2.nmiss = field_num_mv(field2); + field2.numMissVals = field_num_mv(field2); cdo_write_record(streamID2, field2); } @@ -511,18 +524,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Fillmiss(void *process) -{ - ModuleFillmiss fillmiss; - fillmiss.init(process); - fillmiss.run(); - fillmiss.close(); - - return nullptr; -} diff --git a/src/Filter.cc b/src/Filter.cc index f8188eeb68a4cbea5af792e3eeb3dd9978727005..f0510deb05475dc3633c86f94e9701bac37783a6 100644 --- a/src/Filter.cc +++ b/src/Filter.cc @@ -20,6 +20,8 @@ #ifdef HAVE_LIBFFTW3 #include <fftw3.h> +#include <mutex> +static std::mutex fftwMutex; #endif #include "cdi.h" @@ -34,6 +36,36 @@ #include "cimdOmp.h" #include "field_functions.h" +size_t +vars_numArrays(const FieldVector3D &vars) +{ + size_t numArrays{ 0 }; + for (size_t i = 0; i < vars[0].size(); ++i) + { + for (size_t j = 0; j < vars[0][i].size(); ++j) numArrays++; + } + + return numArrays; +} + +size_t +vars_allocatedMem(const FieldVector3D &vars) +{ + size_t allocatedMem{ 0 }; + for (size_t i = 0; i < vars[0].size(); ++i) + { + for (size_t j = 0; j < vars[0][i].size(); ++j) + { + if (vars[0][i][j].memType == MemType::Float) + allocatedMem += vars[0][i][j].vec_f.size() * 4; + else + allocatedMem += vars[0][i][j].vec_d.size() * 8; + } + } + + return allocatedMem; +} + static void create_fmasc(int nts, double fdata, double fmin, double fmax, std::vector<int> &fmasc) { @@ -88,7 +120,7 @@ struct FilterMemory #endif }; -class ModuleFilter +class Filter : public Process { enum { @@ -97,6 +129,22 @@ class ModuleFilter LOWPASS }; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Filter", + // clang-format off + .operators = { { "bandpass", BANDPASS, 0, FilterHelp }, + { "highpass", HIGHPASS, 0, FilterHelp }, + { "lowpass", LOWPASS, 0, FilterHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Filter> registration = RegisterEntry<Filter>(module); + std::vector<std::string> tunits; std::vector<int> iunits; int year0, month0, day0; @@ -113,8 +161,6 @@ class ModuleFilter int vlistID1; int vlistID2; - FieldVector3D vars; - VarList varList; bool useFFTW = false; @@ -125,17 +171,11 @@ class ModuleFilter public: void - init(void *process) + init() { tunits = { "second", "minute", "hour", "day", "month", "year" }; iunits = { 31536000, 525600, 8760, 365, 12, 1 }; - cdo_initialize(process); - - cdo_operator_add("bandpass", BANDPASS, 0, nullptr); - cdo_operator_add("highpass", HIGHPASS, 0, nullptr); - cdo_operator_add("lowpass", LOWPASS, 0, nullptr); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -166,9 +206,12 @@ public: nvars = vlistNvars(vlistID1); } + void run() { + FieldVector3D vars; + int tsID = 0; while (true) { @@ -189,7 +232,7 @@ public: auto &field = vars[tsID][varID][levelID]; field.init(varList[varID]); cdo_read_record(streamID1, field); - if (field.nmiss) cdo_abort("Missing value support for operators in module Filter not added yet!"); + if (field.numMissVals) cdo_abort("Missing value support for operators in module Filter not added yet!"); } // get and check time increment @@ -235,6 +278,11 @@ public: auto nts = tsID; if (nts <= 1) cdo_abort("Number of time steps <= 1!"); + auto numArrays = vars_numArrays(vars); + auto allocatedMem = vars_allocatedMem(vars) * nts; + if (Options::cdoVerbose) + cdo_print("Allocate %zu array%s over %zu steps: size=%zu Bytes", numArrays, numArrays > 1 ? "s" : "", nts, allocatedMem); + std::vector<FilterMemory> fourierMemory(Threading::ompNumThreads); if (useFFTW) @@ -244,6 +292,7 @@ public: { fm.in_fft = fftw_alloc_complex(nts); fm.out_fft = fftw_alloc_complex(nts); + std::scoped_lock lock(fftwMutex); fm.p_T2S = fftw_plan_dft_1d(nts, fm.in_fft, fm.out_fft, 1, FFTW_ESTIMATE); fm.p_S2T = fftw_plan_dft_1d(nts, fm.out_fft, fm.in_fft, -1, FFTW_ESTIMATE); } @@ -294,9 +343,8 @@ public: for (int varID = 0; varID < nvars; ++varID) { - auto fieldMemType = varList[varID].memType; - auto gridsize = varList[varID].gridsize; - for (int levelID = 0; levelID < varList[varID].nlevels; ++levelID) + const auto &var = varList[varID]; + for (int levelID = 0; levelID < var.nlevels; ++levelID) { if (useFFTW) { @@ -304,12 +352,12 @@ public: #ifdef _OPENMP #pragma omp parallel for default(shared) schedule(static) #endif - for (size_t i = 0; i < gridsize; ++i) + for (size_t i = 0; i < var.gridsize; ++i) { auto ompthID = cdo_omp_get_thread_num(); auto &fm = fourierMemory[ompthID]; - if (fieldMemType == MemType::Float) + if (var.memType == MemType::Float) for (int t = 0; t < nts; ++t) { fm.in_fft[t][0] = vars[t][varID][levelID].vec_f[i]; @@ -324,7 +372,7 @@ public: filter_fftw(nts, fmasc, fm.out_fft, &fm.p_T2S, &fm.p_S2T); - if (fieldMemType == MemType::Float) + if (var.memType == MemType::Float) for (int t = 0; t < nts; ++t) vars[t][varID][levelID].vec_f[i] = fm.in_fft[t][0] / nts; else for (int t = 0; t < nts; ++t) vars[t][varID][levelID].vec_d[i] = fm.in_fft[t][0] / nts; @@ -336,21 +384,21 @@ public: #ifdef _OPENMP #pragma omp parallel for default(shared) schedule(static) #endif - for (size_t i = 0; i < gridsize; ++i) + for (size_t i = 0; i < var.gridsize; ++i) { auto ompthID = cdo_omp_get_thread_num(); auto &fm = fourierMemory[ompthID]; - if (fieldMemType == MemType::Float) + if (var.memType == MemType::Float) for (int t = 0; t < nts; ++t) fm.real[t] = vars[t][varID][levelID].vec_f[i]; else for (int t = 0; t < nts; ++t) fm.real[t] = vars[t][varID][levelID].vec_d[i]; - varray_fill(fm.imag, 0.0); + ranges::fill(fm.imag, 0.0); filter_intrinsic(nts, fmasc, fm.real.data(), fm.imag.data()); - if (fieldMemType == MemType::Float) + if (var.memType == MemType::Float) for (int t = 0; t < nts; ++t) vars[t][varID][levelID].vec_f[i] = fm.real[t]; else for (int t = 0; t < nts; ++t) vars[t][varID][levelID].vec_d[i] = fm.real[t]; @@ -366,6 +414,7 @@ public: { fftw_free(fm.in_fft); fftw_free(fm.out_fft); + std::scoped_lock lock(fftwMutex); fftw_destroy_plan(fm.p_T2S); fftw_destroy_plan(fm.p_S2T); } @@ -383,7 +432,8 @@ public: for (int varID = 0; varID < nvars; ++varID) { - for (int levelID = 0; levelID < varList[varID].nlevels; ++levelID) + const auto &var = varList[varID]; + for (int levelID = 0; levelID < var.nlevels; ++levelID) { auto &field = vars[tsID][varID][levelID]; if (field.hasData()) @@ -401,17 +451,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Filter(void *process) -{ - ModuleFilter filter; - filter.init(process); - filter.run(); - filter.close(); - return nullptr; -} diff --git a/src/Fldrms.cc b/src/Fldrms.cc index 679fcd0e2a55109416fa5cc1c7ddae3d2d4e0ab4..1a55061754705827b6b8751347318921f426d598 100644 --- a/src/Fldrms.cc +++ b/src/Fldrms.cc @@ -16,8 +16,19 @@ #include <mpim_grid.h> #include "field_functions.h" -class ModuleFldrms +class Fldrms : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Fldrms", + .operators = { { "fldrms"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Fldrms> registration = RegisterEntry<Fldrms>(module); int lastgrid = -1; CdoStreamID streamID1; @@ -34,9 +45,8 @@ class ModuleFldrms public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -113,9 +123,9 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(streamID1, field1.vec_d.data(), &field1.numMissVals); cdo_inq_record(streamID2, &varID, &levelID); - cdo_read_record(streamID2, field2.vec_d.data(), &field2.nmiss); + cdo_read_record(streamID2, field2.vec_d.data(), &field2.numMissVals); field1.grid = varList1[varID].gridID; field2.grid = varList2[varID].gridID; @@ -140,7 +150,7 @@ public: field_rms(field1, field2, field3); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, field3.vec_d.data(), field3.nmiss); + cdo_write_record(streamID3, field3.vec_d.data(), field3.numMissVals); } tsID++; @@ -152,17 +162,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Fldrms(void *process) -{ - ModuleFldrms fldrms; - fldrms.init(process); - fldrms.run(); - fldrms.close(); - return nullptr; -} diff --git a/src/Fldstat.cc b/src/Fldstat.cc index 3268b2a96b75979d0a9ae33161edaacf8cc25060..c58068d282bbeb4b411bbca4d8c333fe92bf7d49 100644 --- a/src/Fldstat.cc +++ b/src/Fldstat.cc @@ -37,7 +37,7 @@ void gridcell_areas(int gridID, Varray<double> &array); template <typename T> static void -print_location_LL(int operfunc, const CdoVar &var, int levelID, double sglval, const Varray<T> &fieldvec, CdiDateTime vDateTime) +print_location_LL(int operfunc, const CdoVar &var, int levelID, double sglval, const Varray<T> &v, CdiDateTime vDateTime) { static auto printHeader = true; const char *funcName = (operfunc == FieldFunc_Min) ? "Minval" : "Maxval"; @@ -51,7 +51,7 @@ print_location_LL(int operfunc, const CdoVar &var, int levelID, double sglval, c T value = sglval; for (size_t ij = 0; ij < var.gridsize; ++ij) { - if (dbl_is_equal(fieldvec[ij], value)) + if (dbl_is_equal(v[ij], value)) { auto j = ij / nlon; auto i = ij - j * nlon; @@ -71,18 +71,31 @@ print_location_LL(int operfunc, const CdoVar &var, int levelID, double sglval, c } } +static void +print_location_LL(int operfunc, const CdoVar &var, int levelID, double sglval, const Field &field, CdiDateTime vDateTime) +{ + if (field.memType == MemType::Float) + print_location_LL(operfunc, var, levelID, sglval, field.vec_f, vDateTime); + else + print_location_LL(operfunc, var, levelID, sglval, field.vec_d, vDateTime); +} + template <typename T> static void -field_mul_weights(size_t len, Varray<T> &v1, const Varray<double> &v2, size_t nmiss, T missval) +field_mul_weights(Varray<T> &v1, const Varray<double> &v2, size_t numMissVals, T missval) { - if (nmiss) + assert(v1.size() > 0); + assert(v2.size() == v1.size()); + + auto gridSize = v1.size(); + if (numMissVals) { - for (size_t i = 0; i < len; ++i) + for (size_t i = 0; i < gridSize; ++i) if (!dbl_is_equal(v1[i], missval)) v1[i] *= v2[i]; } else { - for (size_t i = 0; i < len; ++i) v1[i] *= v2[i]; + for (size_t i = 0; i < gridSize; ++i) v1[i] *= v2[i]; } } @@ -90,9 +103,9 @@ static void field_mul_weights(Field &field) { if (field.memType == MemType::Float) - field_mul_weights(field.size, field.vec_f, field.weightv, field.nmiss, (float) field.missval); + field_mul_weights(field.vec_f, field.weightv, field.numMissVals, (float) field.missval); else - field_mul_weights(field.size, field.vec_d, field.weightv, field.nmiss, field.missval); + field_mul_weights(field.vec_d, field.weightv, field.numMissVals, field.missval); } static void @@ -154,7 +167,7 @@ fldstatGetParameter(bool &useWeights) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -172,8 +185,68 @@ fldstatGetParameter(bool &useWeights) } } -class ModuleFldstat +static int +get_gridcell_weights(Field &field, bool useWeights, bool doPrintWarning, int ngrids, std::string &varName) +{ + auto gridSize = field.size; + field.weightv.resize(gridSize); + if (!useWeights) + { + cdo_print("Using constant grid cell area weights!"); + ranges::fill(field.weightv, 1.0); + } + + field.weightv[0] = 1; + if (useWeights && field.size > 1) + { + auto wstatus = (gridcell_weights(field.grid, field.weightv) != 0); + if (wstatus && doPrintWarning) printWeightsWarning(ngrids, varName); + } + + return field.grid; +} + +static int +get_gridcell_areas(Field &field) +{ + auto gridSize = field.size; + field.weightv.resize(gridSize); + + gridcell_areas(field.grid, field.weightv); + + return field.grid; +} + +class Fldstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Fldstat", + .operators = { { "fldrange", FieldFunc_Range, 0, FldstatHelp }, + { "fldmin", FieldFunc_Min, 0, FldstatHelp }, + { "fldmax", FieldFunc_Max, 0, FldstatHelp }, + { "fldsum", FieldFunc_Sum, 0, FldstatHelp }, + { "fldint", FieldFunc_Sum, 0, FldstatHelp }, + { "fldmean", FieldFunc_Meanw, 1, FldstatHelp }, + { "fldavg", FieldFunc_Avgw, 1, FldstatHelp }, + { "fldstd", FieldFunc_Stdw, 1, FldstatHelp }, + { "fldstd1", FieldFunc_Std1w, 1, FldstatHelp }, + { "fldvar", FieldFunc_Varw, 1, FldstatHelp }, + { "fldvar1", FieldFunc_Var1w, 1, FldstatHelp }, + { "fldskew", FieldFunc_Skew, 0, FldstatHelp }, + { "fldkurt", FieldFunc_Kurt, 0, FldstatHelp }, + { "fldmedian", FieldFunc_Median, 0, FldstatHelp }, + { "fldcount", FieldFunc_Count, 0, FldstatHelp }, + { "fldpctl", FieldFunc_Pctl, 0, FldstatHelp } }, + .aliases = { { "globavg", "fldavg" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Fldstat> registration = RegisterEntry<Fldstat>(module); + + int FLDINT; CdoStreamID streamID1; CdoStreamID streamID2; @@ -198,28 +271,9 @@ class ModuleFldstat public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - cdo_operator_add("fldrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("fldmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("fldmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("fldsum", FieldFunc_Sum, 0, nullptr); - auto FLDINT = cdo_operator_add("fldint", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("fldmean", FieldFunc_Meanw, 1, nullptr); - cdo_operator_add("fldavg", FieldFunc_Avgw, 1, nullptr); - cdo_operator_add("fldstd", FieldFunc_Stdw, 1, nullptr); - cdo_operator_add("fldstd1", FieldFunc_Std1w, 1, nullptr); - cdo_operator_add("fldvar", FieldFunc_Varw, 1, nullptr); - cdo_operator_add("fldvar1", FieldFunc_Var1w, 1, nullptr); - cdo_operator_add("fldskew", FieldFunc_Skew, 0, nullptr); - cdo_operator_add("fldkurt", FieldFunc_Kurt, 0, nullptr); - cdo_operator_add("fldmedian", FieldFunc_Median, 0, nullptr); - cdo_operator_add("fldcount", FieldFunc_Count, 0, nullptr); - cdo_operator_add("fldpctl", FieldFunc_Pctl, 0, nullptr); - // clang-format on + FLDINT = module.get_id("fldint"); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -234,14 +288,8 @@ public: operator_input_arg("percentile number"); pn = parameter_to_double(cdo_operator_argv(0)); } - else if (needWeights) - { - fldstatGetParameter(useWeights); - } - else - { - operator_check_argc(0); - } + else if (needWeights) { fldstatGetParameter(useWeights); } + else { operator_check_argc(0); } streamID1 = cdo_open_read(0); @@ -268,17 +316,6 @@ public: cdo_def_vlist(streamID2, vlistID2); - auto gridsizemax = vlistGridsizeMax(vlistID1); - - if (needWeights || needCellarea) - { - field.weightv.resize(gridsizemax); - if (needWeights && !useWeights) - { - cdo_print("Using constant grid cell area weights!"); - for (size_t i = 0; i < gridsizemax; ++i) field.weightv[i] = 1.0; - } - } varList_init(varList1, vlistID1); ntsteps = vlistNtsteps(vlistID1); @@ -303,7 +340,7 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - double fstatus = (ntsteps > 1) ? (tsID + (recID + 1.0) / nrecs) / ntsteps : 1.0; + double fstatus = (ntsteps > 1) ? ((tsID + (recID + 1.0) / nrecs) / ntsteps) : 1.0; if (!Options::cdoVerbose && tsID > 0) progress::update(0, 1, fstatus); int varID, levelID; @@ -312,39 +349,20 @@ public: field.init(var); cdo_read_record(streamID1, field); - if (needWeights && field.grid != lastgrid) - { - lastgrid = field.grid; - field.weightv[0] = 1; - if (useWeights && field.size > 1) - { - auto wstatus = (gridcell_weights(field.grid, field.weightv) != 0); - if (wstatus && tsID == 0 && levelID == 0) printWeightsWarning(ngrids, var.name); - } - } - - if (needCellarea && field.grid != lastgrid) - { - lastgrid = field.grid; - gridcell_areas(field.grid, field.weightv); - } + auto doPrintWarning = (tsID == 0 && levelID == 0); + if (needWeights && field.grid != lastgrid) lastgrid = get_gridcell_weights(field, useWeights, doPrintWarning, ngrids, var.name); + else if (needCellarea && field.grid != lastgrid) lastgrid = get_gridcell_areas(field); if (needCellarea) field_mul_weights(field); auto singleValue = (operfunc == FieldFunc_Pctl) ? field_pctl(field, pn) : field_function(field, operfunc); - if (Options::cdoVerbose && isMinMaxFunc) - { - if (field.memType == MemType::Float) - print_location_LL(operfunc, var, levelID, singleValue, field.vec_f, vDateTime); - else - print_location_LL(operfunc, var, levelID, singleValue, field.vec_d, vDateTime); - } + if (Options::cdoVerbose && isMinMaxFunc) { print_location_LL(operfunc, var, levelID, singleValue, field, vDateTime); } - size_t nmiss = dbl_is_equal(singleValue, field.missval); + size_t numMissVals = dbl_is_equal(singleValue, field.missval); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, &singleValue, nmiss); + cdo_write_record(streamID2, &singleValue, numMissVals); } tsID++; @@ -360,18 +378,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Fldstat(void *process) -{ - ModuleFldstat fldstat; - fldstat.init(process); - fldstat.run(); - fldstat.close(); - - return nullptr; -} diff --git a/src/Fldstat2.cc b/src/Fldstat2.cc index f5f62b8115f9825738ed85d7ed9a3179382bf1f8..bb643b758dea4ac811e89b47fafa07b6e2797f5a 100644 --- a/src/Fldstat2.cc +++ b/src/Fldstat2.cc @@ -122,8 +122,19 @@ covariance(const Field &field1, const Field &field2, const Varray<double> &weigh return covariance(field1.vec_d, field2.vec_d, weight, field1.missval, field2.missval, field1.size); } -class ModuleFldstat2 +class Fldstat2 : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Fldstat2", + .operators = { { "fldcor", FieldFunc_Cor, 0, FldcorHelp }, { "fldcovar", FieldFunc_Covar, 0, FldcovarHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Fldstat2> registration = RegisterEntry<Fldstat2>(module); int operfunc; CdoStreamID streamID1; @@ -143,13 +154,10 @@ class ModuleFldstat2 public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("fldcor", FieldFunc_Cor, 0, nullptr); - cdo_operator_add("fldcovar", FieldFunc_Covar, 0, nullptr); // clang-format on auto operatorID = cdo_operator_id(); @@ -234,10 +242,10 @@ public: else if (operfunc == FieldFunc_Covar) sglval = covariance(field1, field2, weight); - auto nmiss3 = DBL_IS_EQUAL(sglval, varList1[varID].missval) ? 1 : 0; + auto numMissVals3 = DBL_IS_EQUAL(sglval, varList1[varID].missval) ? 1 : 0; cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, &sglval, nmiss3); + cdo_write_record(streamID3, &sglval, numMissVals3); } tsID++; @@ -250,18 +258,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Fldstat2(void *process) -{ - ModuleFldstat2 fldstat2; - fldstat2.init(process); - fldstat2.run(); - fldstat2.close(); - - return nullptr; -} diff --git a/src/Fourier.cc b/src/Fourier.cc index a7a056be3210500dd77608ee40322359d57cf79d..be138003cda37a853633fe6a922c0a60b740e20d 100644 --- a/src/Fourier.cc +++ b/src/Fourier.cc @@ -11,6 +11,8 @@ #ifdef HAVE_LIBFFTW3 #include <fftw3.h> +#include <mutex> +static std::mutex fftwMutex; #endif #include <cdi.h> @@ -132,8 +134,20 @@ fourier_intrinsic(int sign, int varID, int levelID, int nts, size_t gridsize, do } } -class ModuleFourier +class Fourier : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Fourier", + .operators = { { "fourier", FourierHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_COMP, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Fourier> registration = RegisterEntry<Fourier>(module); + size_t nalloc = 0; CdoStreamID streamID1; @@ -154,10 +168,8 @@ class ModuleFourier public: void - init(void *process) + init() { - cdo_initialize(process); - if (Options::Use_FFTW) { #ifdef HAVE_LIBFFTW3 @@ -189,6 +201,7 @@ public: nvars = vlistNvars(vlistID1); } + void run() { @@ -216,9 +229,9 @@ public: cdo_inq_record(streamID1, &varID, &levelID); auto gridsize = varList[varID].gridsize; vars[tsID][varID][levelID].resize(2 * gridsize); - size_t nmiss; - cdo_read_record(streamID1, vars[tsID][varID][levelID].vec_d.data(), &nmiss); - vars[tsID][varID][levelID].nmiss = nmiss; + size_t numMissVals; + cdo_read_record(streamID1, vars[tsID][varID][levelID].vec_d.data(), &numMissVals); + vars[tsID][varID][levelID].numMissVals = numMissVals; } tsID++; @@ -235,6 +248,7 @@ public: { fm.in_fft = fftw_alloc_complex(nts); fm.out_fft = fftw_alloc_complex(nts); + std::scoped_lock lock(fftwMutex); fm.plan = fftw_plan_dft_1d(nts, fm.in_fft, fm.out_fft, sign, FFTW_ESTIMATE); } if (Options::cdoVerbose) fftw_print_plan(fourierMemory[0].plan); @@ -273,6 +287,7 @@ public: { fftw_free(fm.in_fft); fftw_free(fm.out_fft); + std::scoped_lock lock(fftwMutex); fftw_destroy_plan(fm.plan); } fftw_cleanup(); @@ -291,32 +306,19 @@ public: { if (!vars[tsID][varID][levelID].empty()) { - auto nmiss = vars[tsID][varID][levelID].nmiss; + auto numMissVals = vars[tsID][varID][levelID].numMissVals; cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, vars[tsID][varID][levelID].vec_d.data(), nmiss); + cdo_write_record(streamID2, vars[tsID][varID][levelID].vec_d.data(), numMissVals); } } } } } + void close() { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Fourier(void *process) -{ - ModuleFourier furier; - - furier.init(process); - furier.run(); - furier.close(); - - return nullptr; -} diff --git a/src/Gengrid.cc b/src/Gengrid.cc index 2556005d561ccbcb6f4bfece101b727f60c5f27f..a71350c173f216b40cb2dc504ab53e92b4a8ecd8 100644 --- a/src/Gengrid.cc +++ b/src/Gengrid.cc @@ -16,10 +16,21 @@ #include "process_int.h" #include "cdo_zaxis.h" -class ModuleGengrid +class Gengrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Gengrid", + .operators = { { "gengrid"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Gengrid> registration = RegisterEntry<Gengrid>(module); int varID, levelID; - size_t nmiss1, nmiss2; + size_t numMissVals1, numMissVals2; double missval = 0; CdoStreamID streamID3; @@ -29,9 +40,8 @@ class ModuleGengrid public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -57,16 +67,16 @@ public: cdo_stream_inq_timestep(streamID2, 0); cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, array1.data(), &nmiss1); + cdo_read_record(streamID1, array1.data(), &numMissVals1); cdo_inq_record(streamID2, &varID, &levelID); - cdo_read_record(streamID2, array2.data(), &nmiss2); + cdo_read_record(streamID2, array2.data(), &numMissVals2); auto datatype = vlistInqVarDatatype(vlistID1, 0); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - if (nmiss1 || nmiss2) cdo_abort("Missing values unsupported!"); + if (numMissVals1 || numMissVals2) cdo_abort("Missing values unsupported!"); auto gridID3 = gridCreate(GRID_CURVILINEAR, gridsize); @@ -128,19 +138,5 @@ public: close() { cdo_stream_close(streamID3); - - cdo_finish(); } }; - -void * -Gengrid(void *process) -{ - ModuleGengrid gengrid; - - gengrid.init(process); - gengrid.run(); - gengrid.close(); - - return nullptr; -} diff --git a/src/Getgridcell.cc b/src/Getgridcell.cc index 00bbf7742551b45712ab2ed985f13501ad459f50..bc5f591a7db9b573588461822b6aefcbca6ec928 100644 --- a/src/Getgridcell.cc +++ b/src/Getgridcell.cc @@ -81,7 +81,7 @@ get_parameter() KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -118,20 +118,28 @@ check_radius_range(double radius, const char *name) if (radius < 0.0 || radius > 180.0) cdo_abort("%s=%g out of bounds (0-180 deg)!", name, radius); } -class ModuleGetgridcell +class Getgridcell : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Getgridcell", + .operators = { { "gridcellindex", 0, 0, "lon/lat coordinate of a single cell", GetgridcellHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Getgridcell> registration = RegisterEntry<Getgridcell>(module); + CdoStreamID streamID1; GridPoint gridPoint; int gridID1; public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("gridcellindex", 0, 0, "lon/lat coordinate of a single cell"); - gridPoint = get_parameter(); check_radius_range(gridPoint.radius, "radius"); @@ -167,18 +175,5 @@ public: close() { cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Getgridcell(void *process) -{ - ModuleGetgridcell getgridcell; - getgridcell.init(process); - getgridcell.run(); - getgridcell.close(); - - return nullptr; -} diff --git a/src/Gradsdes.cc b/src/Gradsdes.cc index d5ea7dff1d78ce302f5589c23c3ec18244a21c7c..a0836343dc211526be4afc301db1a2ad366be20c 100644 --- a/src/Gradsdes.cc +++ b/src/Gradsdes.cc @@ -213,7 +213,7 @@ flt2ibm(float x, unsigned char *ibm) #define Put4Byte(buf, cnt, ival) \ ((buf[cnt++] = (ival) >> 24), (buf[cnt++] = (ival) >> 16), (buf[cnt++] = (ival) >> 8), (buf[cnt++] = (ival))) -#define PutInt(buf, cnt, ival) ((ival < 0) ? Put4Byte(buf, cnt, 0x7fffffff - ival + 1) : Put4Byte(buf, cnt, ival)) +#define PutInt(buf, cnt, ival) ((ival < 0) ? Put4Byte(buf, cnt, 0x7fffffffU - ival + 1) : Put4Byte(buf, cnt, ival)) static void dumpmap() @@ -222,7 +222,6 @@ dumpmap() unsigned char vermap; unsigned char mrec[512]; int swpflg = 0; - int i; int nrecords = 0; struct gaindx indx; struct gaindxb indxb; @@ -268,7 +267,7 @@ dumpmap() if (indx.hinum > 0) { indx.hipnt = new int[indx.hinum]; - for (i = 0; i < indx.hinum; ++i) + for (int i = 0; i < indx.hinum; ++i) { nbytes = fread(mrec, sizeof(unsigned char), 4, mapfp); indx.hipnt[i] = GET_UINT4(mrec[0], mrec[1], mrec[2], mrec[3]); @@ -281,18 +280,18 @@ dumpmap() } if (indx.intnum > 0) { - indx.intpnt = new int [indx.intnum]; - for (i = 0; i < indx.intnum; ++i) + indx.intpnt = new int[indx.intnum]; + for (int i = 0; i < indx.intnum; ++i) { nbytes = fread(mrec, sizeof(unsigned char), 4, mapfp); indx.intpnt[i] = GET_UINT4(mrec[0], mrec[1], mrec[2], mrec[3]); - if (indx.intpnt[i] < 0) indx.intpnt[i] = 0x7fffffff - indx.intpnt[i] + 1; + if (indx.intpnt[i] < 0) indx.intpnt[i] = 0x7fffffffU - indx.intpnt[i] + 1; } } if (indx.fltnum > 0) { indx.fltpnt = new float[indx.fltnum]; - for (i = 0; i < indx.fltnum; ++i) + for (int i = 0; i < indx.fltnum; ++i) { nbytes = fread(urec, sizeof(unsigned char), 4, mapfp); indx.fltpnt[i] = ibm2flt(urec); @@ -349,11 +348,11 @@ dumpmap() std::fclose(mapfp); printf("hinum: %d\n", indx.hinum); - for (i = 0; i < indx.hinum; ++i) printf("%3d %5d\n", i + 1, indx.hipnt[i]); + for (int i = 0; i < indx.hinum; ++i) printf("%3d %5d\n", i + 1, indx.hipnt[i]); printf("\n"); printf("hfnum: %d\n", indx.hfnum); - for (i = 0; i < indx.hfnum; ++i) printf("%3d %g\n", i + 1, indx.hfpnt[i]); + for (int i = 0; i < indx.hfnum; ++i) printf("%3d %g\n", i + 1, indx.hfpnt[i]); printf("\n"); @@ -362,36 +361,36 @@ dumpmap() if (indx.intnum == indx.fltnum) { printf("num: %d\n", indx.intnum); - for (i = 0; i < indx.intnum / 3; ++i) + for (int i = 0; i < indx.intnum / 3; ++i) printf("%3d %8d %6d %4d %8g %10g %8g\n", i + 1, indx.intpnt[i * 3], indx.intpnt[i * 3 + 1], indx.intpnt[i * 3 + 2], indx.fltpnt[i * 3], indx.fltpnt[i * 3 + 1], indx.fltpnt[i * 3 + 2]); } else if (indx.intnum == nrecords && indx.fltnum == nrecords * 3 && indxb.bignum == nrecords * 2) { printf("nrecords: %d\n", nrecords); - for (i = 0; i < nrecords; ++i) + for (int i = 0; i < nrecords; ++i) printf("%3d %8zd %6zd %4d %8g %10g %8g\n", i + 1, (size_t) indxb.bigpnt[i * 2], (size_t) indxb.bigpnt[i * 2 + 1], indx.intpnt[i], indx.fltpnt[i * 3], indx.fltpnt[i * 3 + 1], indx.fltpnt[i * 3 + 2]); } else { printf("intnum: %d\n", indx.intnum); - for (i = 0; i < indx.intnum; ++i) printf("%3d %d\n", i + 1, indx.intpnt[i]); + for (int i = 0; i < indx.intnum; ++i) printf("%3d %d\n", i + 1, indx.intpnt[i]); printf("\n"); printf("fltnum: %d\n", indx.fltnum); - for (i = 0; i < indx.fltnum; ++i) printf("%3d %g\n", i + 1, indx.fltpnt[i]); + for (int i = 0; i < indx.fltnum; ++i) printf("%3d %g\n", i + 1, indx.fltpnt[i]); printf("\n"); printf("bignum: %d\n", indxb.bignum); - for (i = 0; i < indxb.bignum; ++i) printf("%3d %zd\n", i + 1, (size_t) indxb.bigpnt[i]); + for (int i = 0; i < indxb.bignum; ++i) printf("%3d %zd\n", i + 1, (size_t) indxb.bigpnt[i]); } } static void ctl_xydef(FILE *gdp, int gridID, bool *yrev) { - int i, j; + int j; *yrev = false; @@ -423,7 +422,7 @@ ctl_xydef(FILE *gdp, int gridID, bool *yrev) Varray<double> xvals(xsize * ysize), yvals(xsize * ysize); gridInqXvals(gridID, xvals.data()); gridInqYvals(gridID, yvals.data()); - for (i = 0; i < xsize * ysize; ++i) + for (int i = 0; i < xsize * ysize; ++i) { if (xvals[i] > 180) xvals[i] -= 360; if (xvals[i] < xmin) xmin = xvals[i]; @@ -438,7 +437,7 @@ ctl_xydef(FILE *gdp, int gridID, bool *yrev) yrange = ((int) (ymax + 1.5)) - yfirst; ni = sizeof(inc) / sizeof(inc[0]); - for (i = 0; i < ni; ++i) + for (int i = 0; i < ni; ++i) { xinc = yinc = inc[i]; nx = 1 + (int) (xrange / xinc); @@ -463,7 +462,7 @@ ctl_xydef(FILE *gdp, int gridID, bool *yrev) gridInqXvals(gridID, xvals.data()); fprintf(gdp, "XDEF %d LEVELS ", xsize); j = 0; - for (i = 0; i < xsize; ++i) + for (int i = 0; i < xsize; ++i) { fprintf(gdp, "%7.3f ", xvals[i]); j++; @@ -500,7 +499,7 @@ ctl_xydef(FILE *gdp, int gridID, bool *yrev) if (yvals[0] > yvals[ysize - 1]) { *yrev = true; - for (i = ysize - 1; i >= 0; i--) + for (int i = ysize - 1; i >= 0; i--) { fprintf(gdp, "%7.3f ", yvals[i]); j++; @@ -514,7 +513,7 @@ ctl_xydef(FILE *gdp, int gridID, bool *yrev) } else { - for (i = 0; i < ysize; ++i) + for (int i = 0; i < ysize; ++i) { fprintf(gdp, "%7.3f ", yvals[i]); j++; @@ -546,7 +545,7 @@ ctl_xydef(FILE *gdp, int gridID, bool *yrev) static void ctl_zdef(FILE *gdp, int vlistID, bool *zrev) { - int i, j, index; + int j; int zaxisIDmax = -1; int zaxisID, nlev; double levinc = 0; @@ -555,7 +554,7 @@ ctl_zdef(FILE *gdp, int vlistID, bool *zrev) int nzaxis = vlistNzaxis(vlistID); int nlevmax = 0; - for (index = 0; index < nzaxis; ++index) + for (int index = 0; index < nzaxis; ++index) { zaxisID = vlistZaxis(vlistID, index); nlev = zaxisInqSize(zaxisID); @@ -578,7 +577,7 @@ ctl_zdef(FILE *gdp, int vlistID, bool *zrev) if (IS_EQUAL(levinc, 1)) *zrev = false; - for (i = 1; i < nlevmax; ++i) + for (int i = 1; i < nlevmax; ++i) { if (is_not_equal(levinc, (levels[i] - levels[i - 1]))) { @@ -597,7 +596,7 @@ ctl_zdef(FILE *gdp, int vlistID, bool *zrev) /* zrev not needed !!! if ( *zrev ) { - for ( i = nlevmax-1; i >=0 ; i-- ) + for (i = nlevmax-1; i >= 0; i--) { if ( lplev ) fprintf(gdp, "%g ", levels[i]/100); else fprintf(gdp, "%d ", (int) levels[i]); @@ -613,7 +612,7 @@ ctl_zdef(FILE *gdp, int vlistID, bool *zrev) else */ { - for (i = 0; i < nlevmax; ++i) + for (int i = 0; i < nlevmax; ++i) { if (lplev) fprintf(gdp, "%g ", levels[i] / 100); @@ -754,10 +753,8 @@ ctl_vars(FILE *gdp, int filetype, int vlistID, const VarList &varList, int nvars static void write_map_grib1(const char *ctlfile, int map_version, int nrecords, int *intnum, float *fltnum, off_t *bignum) { - int i; struct gaindx indx; struct gaindxb indxb; - int hinum[5]; memset(&indx, 0, sizeof(struct gaindx)); @@ -786,6 +783,7 @@ write_map_grib1(const char *ctlfile, int map_version, int nrecords, int *intnum, indx.fltpnt = nullptr; indxb.bigpnt = nullptr; + int hinum[5]; hinum[0] = map_version; hinum[1] = 1; hinum[2] = nrecords; @@ -794,7 +792,7 @@ write_map_grib1(const char *ctlfile, int map_version, int nrecords, int *intnum, if (map_version == 2) { - int nb, bcnt, rc, j; + int nb, bcnt, rc; float fdum; unsigned char ibmfloat[4]; @@ -827,35 +825,35 @@ write_map_grib1(const char *ctlfile, int map_version, int nrecords, int *intnum, Put1Byte(map, bcnt, 0); /* initial second */ if (indx.hinum) - for (i = 0; i < indx.hinum; ++i) Put4Byte(map, bcnt, hinum[i]); + for (int i = 0; i < indx.hinum; ++i) Put4Byte(map, bcnt, hinum[i]); if (indx.hfnum) { /* blank for now */ } - for (i = 0; i < nrecords; ++i) + for (int i = 0; i < nrecords; ++i) { PutInt(map, bcnt, (int) bignum[i * 2]); PutInt(map, bcnt, (int) bignum[i * 2 + 1]); PutInt(map, bcnt, intnum[i]); } - for (i = 0; i < indx.fltnum; ++i) + for (int i = 0; i < indx.fltnum; ++i) { fdum = fltnum[i]; rc = flt2ibm(fdum, ibmfloat); if (rc < 0) cdo_abort("overflow in IBM float conversion"); - for (j = 0; j < 4; ++j) map[bcnt++] = ibmfloat[j]; + for (int j = 0; j < 4; ++j) map[bcnt++] = ibmfloat[j]; } /* write out the factors for converting from grid to absolute time */ - for (i = 0; i < 8; ++i) + for (int i = 0; i < 8; ++i) { fdum = 0; rc = flt2ibm(fdum, ibmfloat); if (rc < 0) cdo_abort("overflow in IBM float conversion"); - for (j = 0; j < 4; ++j) map[bcnt++] = ibmfloat[j]; + for (int j = 0; j < 4; ++j) map[bcnt++] = ibmfloat[j]; } fwrite(map, 1, bcnt, mapfp); @@ -869,7 +867,7 @@ write_map_grib1(const char *ctlfile, int map_version, int nrecords, int *intnum, if (map_version == 1) { std::vector<int> intnumbuf(indx.intnum); - for (i = 0; i < nrecords; ++i) + for (int i = 0; i < nrecords; ++i) { intnumbuf[i * 3 + 0] = (int) bignum[i * 2]; intnumbuf[i * 3 + 1] = (int) bignum[i * 2 + 1]; @@ -897,8 +895,21 @@ void write_map_grib2(const char *ctlfile, int map_version, int nrecords, int } */ -class ModuleGradsdes +class Gradsdes : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Gradsdes", + .operators = { { "gradsdes", GradsdesHelp }, { "dumpmap", GradsdesHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, FilesOnly }, + }; + inline static RegisterEntry<Gradsdes> registration = RegisterEntry<Gradsdes>(module); + + int GRADSDES, DUMPMAP; int gridID = -1; int gridtype = -1; int index; @@ -948,8 +959,6 @@ class ModuleGradsdes char *ctlfile; const char *datfile; - int GRADSDES, DUMPMAP; - void _run(int &tsID) { @@ -1059,8 +1068,8 @@ class ModuleGradsdes cdo_inq_record(streamID, &varID, &levelID); if (vars[varID] == true) { - size_t nmiss; - cdo_read_record(streamID, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID, array.data(), &numMissVals); index = (tsID * nrecsout + recoffset[varID] + levelID); @@ -1088,14 +1097,10 @@ class ModuleGradsdes public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - GRADSDES = cdo_operator_add("gradsdes", 0, 0, nullptr); - DUMPMAP = cdo_operator_add("dumpmap", 0, 0, nullptr); - // clang-format on + GRADSDES = module.get_id("gradsdes"); + DUMPMAP = module.get_id("dumpmap"); (void) (GRADSDES); // unused @@ -1305,6 +1310,8 @@ public: void run() { + if (operatorID == DUMPMAP) return; + int tsID = 0; _run(tsID); @@ -1339,8 +1346,7 @@ public: int xsize = gridInqXsize(gridID); int ysize = gridInqYsize(gridID); - int res = 0; - if (gridtype == GRID_GAUSSIAN) res = nlat_to_ntr(ysize); + int res = (gridtype == GRID_GAUSSIAN) ? nlat_to_ntr(ysize) : 0; if (res) fprintf(gdp, "TITLE %s T%d grid\n", datfile, res); @@ -1373,25 +1379,11 @@ public: void close() { - if (operatorID != DUMPMAP) - { - cdo_stream_close(streamID); + if (operatorID == DUMPMAP) return; - if (ctlfile) delete[] ctlfile; - if (idxfile) delete[] idxfile; - } + cdo_stream_close(streamID); - cdo_finish(); + if (ctlfile) delete[] ctlfile; + if (idxfile) delete[] idxfile; } }; - -void * -Gradsdes(void *process) -{ - ModuleGradsdes gradsdes; - gradsdes.init(process); - gradsdes.run(); - gradsdes.close(); - - return nullptr; -} diff --git a/src/Gridboxstat.cc b/src/Gridboxstat.cc index dd3ccb050deb08f2a573c2cb9bc612c783d7b956..163c26bdc039c78be98d278530e9624fcd8cd036 100644 --- a/src/Gridboxstat.cc +++ b/src/Gridboxstat.cc @@ -216,23 +216,12 @@ gen_boxgrid(int gridID1, size_t xinc, size_t yinc) gridDefXsize(gridID2, nlon2); gridDefYsize(gridID2, nlat2); } - else - { - cdo_abort("Unsupported grid: %s", gridNamePtr(gridtype)); - } + else { cdo_abort("Unsupported grid: %s", gridNamePtr(gridtype)); } if (gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT) { gen_boxgrid_reg2D(gridID1, xinc, yinc, gridID2); } - else if (gridtype == GRID_GENERIC) - { - } - else if (gridtype == GRID_CURVILINEAR) - { - gen_boxgrid_curv2D(gridID1, xinc, yinc, gridID2); - } - else - { - cdo_abort("Unsupported grid: %s", gridNamePtr(gridtype)); - } + else if (gridtype == GRID_GENERIC) {} + else if (gridtype == GRID_CURVILINEAR) { gen_boxgrid_curv2D(gridID1, xinc, yinc, gridID2); } + else { cdo_abort("Unsupported grid: %s", gridNamePtr(gridtype)); } return gridID2; } @@ -268,7 +257,7 @@ gridbox_stat(const Field &field1, Field &field2, size_t xinc, size_t yinc, int s auto ompthID = cdo_omp_get_thread_num(); auto &field = fields[ompthID]; - field.nmiss = 0; + field.numMissVals = 0; auto ilat = ig / nlon2; auto ilon = ig - ilat * nlon2; @@ -284,7 +273,7 @@ gridbox_stat(const Field &field1, Field &field2, size_t xinc, size_t yinc, int s auto index = jj * nlon1 + ii; if (ii >= nlon1) break; field.vec_d[isize] = (field1.memType == MemType::Float) ? (double) field1.vec_f[index] : field1.vec_d[index]; - if (dbl_is_equal(field.vec_d[isize], field.missval)) field.nmiss++; + if (dbl_is_equal(field.vec_d[isize], field.missval)) field.numMissVals++; if (useWeight) field.weightv[isize] = field1.weightv[index]; isize++; } @@ -301,28 +290,31 @@ gridbox_stat(const Field &field1, Field &field2, size_t xinc, size_t yinc, int s field_num_mv(field2); } -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("gridboxrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("gridboxmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("gridboxmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("gridboxsum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("gridboxmean", FieldFunc_Meanw, 1, nullptr); - cdo_operator_add("gridboxavg", FieldFunc_Avgw, 1, nullptr); - cdo_operator_add("gridboxvar", FieldFunc_Varw, 1, nullptr); - cdo_operator_add("gridboxvar1", FieldFunc_Var1w, 1, nullptr); - cdo_operator_add("gridboxstd", FieldFunc_Stdw, 1, nullptr); - cdo_operator_add("gridboxstd1", FieldFunc_Std1w, 1, nullptr); - cdo_operator_add("gridboxskew", FieldFunc_Skew, 0, nullptr); - cdo_operator_add("gridboxkurt", FieldFunc_Kurt, 0, nullptr); - cdo_operator_add("gridboxmedian", FieldFunc_Median, 0, nullptr); - // clang-format on -} - -class ModuleGridboxstat +class Gridboxstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Gridboxstat", + .operators = { { "gridboxrange", FieldFunc_Range, 0, GridboxstatHelp }, + { "gridboxmin", FieldFunc_Min, 0, GridboxstatHelp }, + { "gridboxmax", FieldFunc_Max, 0, GridboxstatHelp }, + { "gridboxsum", FieldFunc_Sum, 0, GridboxstatHelp }, + { "gridboxmean", FieldFunc_Meanw, 1, GridboxstatHelp }, + { "gridboxavg", FieldFunc_Avgw, 1, GridboxstatHelp }, + { "gridboxstd", FieldFunc_Stdw, 1, GridboxstatHelp }, + { "gridboxstd1", FieldFunc_Std1w, 1, GridboxstatHelp }, + { "gridboxvar", FieldFunc_Varw, 1, GridboxstatHelp }, + { "gridboxvar1", FieldFunc_Var1w, 1, GridboxstatHelp }, + { "gridboxskew", FieldFunc_Skew, 0, GridboxstatHelp }, + { "gridboxkurt", FieldFunc_Kurt, 0, GridboxstatHelp }, + { "gridboxmedian", FieldFunc_Median, 0, GridboxstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Gridboxstat> registration = RegisterEntry<Gridboxstat>(module); int lastgrid = -1; bool wstatus = false; @@ -344,17 +336,14 @@ class ModuleGridboxstat public: void - init(void *process) + init() { - cdo_initialize(process); operator_input_arg("xinc, yinc"); operator_check_argc(2); xinc = parameter_to_int(cdo_operator_argv(0)); yinc = parameter_to_int(cdo_operator_argv(1)); - add_operators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -434,18 +423,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Gridboxstat(void *process) -{ - ModuleGridboxstat gridboxstat; - gridboxstat.init(process); - gridboxstat.run(); - gridboxstat.close(); - - return nullptr; -} diff --git a/src/Gridcell.cc b/src/Gridcell.cc index 83bb357875a61cd03690e57be94737f242966ef2..ecf4d60197817c105436a814e27ba84d2139e8f4 100644 --- a/src/Gridcell.cc +++ b/src/Gridcell.cc @@ -20,34 +20,52 @@ #include "cdo_zaxis.h" #include <mpim_grid.h> #include "constants.h" +#include "param_conversion.h" +#include "pmlist.h" double gridGetPlanetRadius(int gridID); double -getPlanetRadius(int gridID) +planet_radius_env(void) { - static auto radiusFromEnv = true; - if (radiusFromEnv) + static double planetRadiusEnv{ 0 }; + static auto readFromEnv = true; + if (readFromEnv) { - radiusFromEnv = false; + readFromEnv = false; auto envstr = getenv("PLANET_RADIUS"); if (envstr) { - auto fval = atof(envstr); - if (fval > 0) PlanetRadius = fval; + auto fval = radius_str_to_meter(envstr); + if (is_not_equal(fval, 0)) planetRadiusEnv = fval; } } - auto planetRadius = PlanetRadius; + return planetRadiusEnv; +} + +double +get_planet_radius_in_meter(int gridID) +{ + auto planetRadiusInMeter{ PlanetRadiusDefault }; - auto gridRadius = gridGetPlanetRadius(gridID); - if (gridRadius > 1) planetRadius = gridRadius; + if (is_not_equal(planet_radius_env(), 0)) + { + planetRadiusInMeter = planet_radius_env(); + cdo_print("Using planet radius from env.var. PLANET_RADIUS: %.8gm", planetRadiusInMeter); + } + else if (gridGetPlanetRadius(gridID) > 1) + { + planetRadiusInMeter = gridGetPlanetRadius(gridID); + cdo_print("Using planet radius from grid description: %.8gm", planetRadiusInMeter); + } + else { cdo_print("Using default planet radius: %.8gm", planetRadiusInMeter); } - return planetRadius; + return planetRadiusInMeter; } -void -gridcell_areas(int gridID, Varray<double> &array) +static void +gridcell_areas(int gridID, Varray<double> &array, double planetRadiusInMeter) { auto gridtype = gridInqType(gridID); @@ -56,29 +74,36 @@ gridcell_areas(int gridID, Varray<double> &array) { if (gridHasArea(gridID)) { - if (Options::cdoVerbose) cdo_print("Using existing grid cell area!"); + cdo_print("Using existing grid cell area!"); gridInqArea(gridID, array.data()); } else { auto status = gridGenArea(gridID, array.data()); - if (status == 1) - cdo_abort("%s: Cell corner coordinates missing!", __func__); - else if (status == 2) - cdo_abort("%s: Can't compute grid cell area for this grid!", __func__); + // clang-format off + if (status == 1) cdo_abort("%s: Cell corner coordinates missing!", __func__); + else if (status == 2) cdo_abort("%s: Can't compute grid cell area for this grid!", __func__); + // clang-format on - auto planetRadius = getPlanetRadius(gridID); - if (Options::cdoVerbose) cdo_print("Planet radius: %.2f", planetRadius); + if (planetRadiusInMeter <= 0) planetRadiusInMeter = get_planet_radius_in_meter(gridID); auto ngp = gridInqSize(gridID); - for (size_t i = 0; i < ngp; ++i) array[i] *= planetRadius * planetRadius; + for (size_t i = 0; i < ngp; ++i) array[i] *= planetRadiusInMeter * planetRadiusInMeter; } } else { cdo_abort("%s: Unsupported grid type: %s", __func__, gridNamePtr(gridtype)); } } +void +gridcell_areas(int gridID, Varray<double> &array) +{ + gridcell_areas(gridID, array, 0.0); +} + static void -grid_dx(int gridID, Varray<double> &array) +grid_dx(int gridID, Varray<double> &array, double planetRadiusInMeter) { + if (planetRadiusInMeter <= 0) planetRadiusInMeter = get_planet_radius_in_meter(gridID); + auto gridsize = gridInqSize(gridID); auto xsize = gridInqXsize(gridID); auto ysize = gridInqYsize(gridID); @@ -93,9 +118,6 @@ grid_dx(int gridID, Varray<double> &array) cdo_grid_to_radian(gridID, CDI_XAXIS, xv, "grid longitudes"); cdo_grid_to_radian(gridID, CDI_YAXIS, yv, "grid latitudes"); - auto planetRadius = getPlanetRadius(gridID); - if (Options::cdoVerbose) cdo_print("Planet radius: %.2f", planetRadius); - for (size_t j = 0; j < ysize; ++j) { auto joff = j * xsize; @@ -118,14 +140,16 @@ grid_dx(int gridID, Varray<double> &array) len2 = orthodrome(xv[joff + i], yv[joff + i], xv[joff + i + 1], yv[joff + i + 1]); } - array[joff + i] = 0.5 * (len1 + len2) * planetRadius; + array[joff + i] = 0.5 * (len1 + len2) * planetRadiusInMeter; } } } static void -grid_dy(int gridID, Varray<double> &array) +grid_dy(int gridID, Varray<double> &array, double planetRadiusInMeter) { + if (planetRadiusInMeter <= 0) planetRadiusInMeter = get_planet_radius_in_meter(gridID); + auto gridsize = gridInqSize(gridID); auto xsize = gridInqXsize(gridID); auto ysize = gridInqYsize(gridID); @@ -140,9 +164,6 @@ grid_dy(int gridID, Varray<double> &array) cdo_grid_to_radian(gridID, CDI_XAXIS, xv, "grid longitudes"); cdo_grid_to_radian(gridID, CDI_YAXIS, yv, "grid latitudes"); - auto planetRadius = getPlanetRadius(gridID); - if (Options::cdoVerbose) cdo_print("Planet radius: %.2f", planetRadius); - for (size_t i = 0; i < xsize; ++i) { for (size_t j = 0; j < ysize; ++j) @@ -167,16 +188,61 @@ grid_dy(int gridID, Varray<double> &array) len2 = orthodrome(xv[joff + i], yv[joff + i], xv[joffp1 + i], yv[joffp1 + i]); } - array[joff + i] = 0.5 * (len1 + len2) * planetRadius; + array[joff + i] = 0.5 * (len1 + len2) * planetRadiusInMeter; } } } -class ModuleGridcell +static void +get_parameter(double &radiusInMeter) { + auto pargc = cdo_operator_argc(); + if (pargc) + { + auto &pargv = cdo_get_oper_argv(); + + KVList kvlist; + kvlist.name = cdo_module_name(); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); + if (Options::cdoVerbose) kvlist.print(); + + for (const auto &kv : kvlist) + { + const auto &key = kv.key; + if (kv.nvalues > 1) cdo_abort("Too many values for parameter key >%s<!", key); + if (kv.nvalues < 1) cdo_abort("Missing value for parameter key >%s<!", key); + const auto &value = kv.values[0]; + + // clang-format off + if (key == "radius") radiusInMeter = radius_str_to_meter(value); + else cdo_abort("Invalid parameter key >%s<!", key); + // clang-format on + } + } +} + +class Gridcell : public Process +{ +public: + using Process::Process; + inline static CdoModule module = { + .name = "Gridcell", + .operators = { { "gridarea", 1, 0, GridcellHelp }, + { "gridweights", GridcellHelp }, + { "gridmask", GridcellHelp }, + { "griddx", 1, 0, GridcellHelp }, + { "griddy", 1, 0, GridcellHelp }, + { "gridcellidx", GridcellHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Gridcell> registration = RegisterEntry<Gridcell>(module); + + int GRIDAREA, GRIDWEIGHTS, GRIDMASK, GRIDDX, GRIDDY, GRIDCELLIDX; CdoStreamID streamID1; - CdoStreamID streamID2; int operatorID; int gridID; @@ -184,29 +250,38 @@ class ModuleGridcell size_t gridsize; + double planetRadiusInMeter{ 0 }; + Varray<double> array; - int GRIDAREA, GRIDWEIGHTS, GRIDMASK, GRIDDX, GRIDDY, GRIDCELLIDX; public: void - init(void *process) + init() { - cdo_initialize(process); - // clang-format off - GRIDAREA = cdo_operator_add("gridarea", 1, 0, nullptr); - GRIDWEIGHTS= cdo_operator_add("gridweights", 1, 0, nullptr); - GRIDMASK = cdo_operator_add("gridmask", 0, 0, nullptr); - GRIDDX = cdo_operator_add("griddx", 1, 0, nullptr); - GRIDDY = cdo_operator_add("griddy", 1, 0, nullptr); - GRIDCELLIDX= cdo_operator_add("gridcellidx", 0, 0, nullptr); + GRIDAREA = module.get_id("gridarea"); + GRIDWEIGHTS = module.get_id("gridweights"); + GRIDMASK = module.get_id("gridmask"); + GRIDDX = module.get_id("griddx"); + GRIDDY = module.get_id("griddy"); + GRIDCELLIDX = module.get_id("gridcellidx"); // clang-format on operatorID = cdo_operator_id(); - operator_check_argc(0); + auto needRadius = (cdo_operator_f1(operatorID) > 0); - // const bool needRadius = cdo_operator_f1(operatorID) > 0; + if (needRadius && cdo_operator_argc() == 1) + { + double radiusInMeter{ 0 }; + get_parameter(radiusInMeter); + if (is_not_equal(radiusInMeter, 0)) + { + planetRadiusInMeter = radiusInMeter; + cdo_print("Using user defined planet radius: %.8gm", planetRadiusInMeter); + } + } + else { operator_check_argc(0); } streamID1 = cdo_open_read(0); auto vlistID1 = cdo_stream_inq_vlist(streamID1); @@ -269,7 +344,7 @@ public: void run() { - if (operatorID == GRIDAREA) { gridcell_areas(gridID, array); } + if (operatorID == GRIDAREA) { gridcell_areas(gridID, array, planetRadiusInMeter); } else if (operatorID == GRIDWEIGHTS) { auto status = gridcell_weights(gridID, array); @@ -293,35 +368,22 @@ public: { if (gridtype != GRID_CURVILINEAR) gridID = gridToCurvilinear(gridID, NeedCorners::Yes); - (operatorID == GRIDDX) ? grid_dx(gridID, array) : grid_dy(gridID, array); + (operatorID == GRIDDX) ? grid_dx(gridID, array, planetRadiusInMeter) : grid_dy(gridID, array, planetRadiusInMeter); } else { cdo_abort("Unsupported grid type: %s", gridNamePtr(gridtype)); } } - streamID2 = cdo_open_write(1); + auto streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); cdo_def_timestep(streamID2, 0); cdo_def_record(streamID2, 0, 0); cdo_write_record(streamID2, &array[0], 0); + cdo_stream_close(streamID2); } void close() { - cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Gridcell(void *process) -{ - ModuleGridcell gridcell; - gridcell.init(process); - gridcell.run(); - gridcell.close(); - - return nullptr; -} diff --git a/src/Gridsearch.cc b/src/Gridsearch.cc index 94312a32019944e99445bd2276d15932690d46e5..3af169b697002be467d4aa9f5bd93ffdaa569562 100644 --- a/src/Gridsearch.cc +++ b/src/Gridsearch.cc @@ -110,7 +110,8 @@ boundbox_from_corners1r(long ic, long nc, const Varray<double> &cornerLon, const } static void -boundbox_from_corners(long size, long nc, const Varray<double> &cornerLon, const Varray<double> &cornerLat, Varray<float> &bound_box) +boundbox_from_corners(long size, long nc, const Varray<double> &cornerLon, const Varray<double> &cornerLat, + Varray<float> &bound_box) { for (long i = 0; i < size; ++i) { @@ -215,23 +216,32 @@ cell_search(int gridIDsrc, int gridIDtgt) grid_delete(tgtGrid); } -class ModuleGridsearch +class Gridsearch : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Gridsearch", + .operators = { { "testpointsearch"}, { "testcellsearch"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 0, NoRestriction }, + }; + inline static RegisterEntry<Gridsearch> registration = RegisterEntry<Gridsearch>(module); + int TESTPOINTSEARCH, TESTCELLSEARCH; int operatorID; int gridID1; int gridID2; - int TESTCELLSEARCH, TESTPOINTSEARCH; - public: void - init(void *process) + init() { - cdo_initialize(process); - TESTPOINTSEARCH = cdo_operator_add("testpointsearch", 0, 0, nullptr); - TESTCELLSEARCH = cdo_operator_add("testcellsearch", 0, 0, nullptr); + TESTPOINTSEARCH = module.get_id("testpointsearch"); + TESTCELLSEARCH = module.get_id("testcellsearch"); operatorID = cdo_operator_id(); @@ -251,17 +261,5 @@ public: void close() { - cdo_finish(); } }; - -void * -Gridsearch(void *process) -{ - ModuleGridsearch gridsearch; - gridsearch.init(process); - gridsearch.run(); - gridsearch.close(); - - return nullptr; -} diff --git a/src/Harmonic.cc b/src/Harmonic.cc index 161d3efdbe78ecd270e04104bb7c8047a7393971..ce4846a323066065330805f7a5034e5a484d7ec2 100644 --- a/src/Harmonic.cc +++ b/src/Harmonic.cc @@ -20,8 +20,20 @@ #include "util_files.h" #include "util_string.h" -class ModuleHarmonic +class Harmonic : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Harmonic", + .operators = { { "harmonic"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Harmonic> registration = RegisterEntry<Harmonic>(module); + CdiDateTime vDateTime{}; CdoStreamID streamID1; @@ -44,10 +56,8 @@ class ModuleHarmonic public: void - init(void *process) + init() { - cdo_initialize(process); - operator_input_arg("wave number and wave length of first harmonic in number of timesteps"); operator_check_argc(2); @@ -102,10 +112,8 @@ public: work[j].resize(nvars); for (int varID = 0; varID < nvars; ++varID) { - auto gridsize = varList1[varID].gridsize; - auto nlevels = varList1[varID].nlevels; - work[j][varID].resize(gridsize * nlevels); - varray_fill(gridsize * nlevels, work[j][varID], 0.0); + const auto &var = varList1[varID]; + work[j][varID].resize(var.gridsize * var.nlevels, 0); } } @@ -128,10 +136,10 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); - if (nmiss) cdo_abort("Missing values are not allowed!"); + if (numMissVals) cdo_abort("Missing values are not allowed!"); auto gridsize = varList1[varID].gridsize; auto offset = gridsize * levelID; @@ -162,12 +170,11 @@ public: { for (int varID = 0; varID < nvars; ++varID) { - auto gridsize = varList2[varID].gridsize; - auto nlevels = varList2[varID].nlevels; - for (int levelID = 0; levelID < nlevels; ++levelID) + const auto &var2 = varList2[varID]; + for (int levelID = 0; levelID < var2.nlevels; ++levelID) { - auto offset = gridsize * levelID; - for (size_t i = 0; i < gridsize; ++i) + auto offset = var2.gridsize * levelID; + for (size_t i = 0; i < var2.gridsize; ++i) { auto sqrwork1 = work[j][varID][i + offset] * work[j][varID][i + offset]; auto sqrwork2 = work[n_out + j][varID][i + offset] * work[n_out + j][varID][i + offset]; @@ -181,12 +188,11 @@ public: { for (int varID = 0; varID < nvars; ++varID) { - auto gridsize = varList2[varID].gridsize; - auto nlevels = varList2[varID].nlevels; - for (int levelID = 0; levelID < nlevels; ++levelID) + const auto &var2 = varList2[varID]; + for (int levelID = 0; levelID < var2.nlevels; ++levelID) { - auto offset = gridsize * levelID; - for (size_t i = 0; i < gridsize; ++i) + auto offset = var2.gridsize * levelID; + for (size_t i = 0; i < var2.gridsize; ++i) out[n_out - 1][varID][i + offset] = work[2 * n_out - 1][varID][i + offset] / nts; } } @@ -202,11 +208,10 @@ public: for (int varID = 0; varID < nvars; ++varID) { - auto gridsize = varList2[varID].gridsize; - auto nlevels = varList2[varID].nlevels; - for (int levelID = 0; levelID < nlevels; ++levelID) + const auto &var2 = varList2[varID]; + for (int levelID = 0; levelID < var2.nlevels; ++levelID) { - auto offset = gridsize * levelID; + auto offset = var2.gridsize * levelID; cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, &out[j][varID][offset], 0); } @@ -217,18 +222,16 @@ public: { for (int varID = 0; varID < nvars; ++varID) { - auto gridsize = varList2[varID].gridsize; - auto nlevels = varList2[varID].nlevels; - auto missval = vlistInqVarMissval(vlistID2, varID); - for (int levelID = 0; levelID < nlevels; ++levelID) + const auto &var2 = varList2[varID]; + for (int levelID = 0; levelID < var2.nlevels; ++levelID) { - auto offset = gridsize * levelID; - for (size_t i = 0; i < gridsize; ++i) + auto offset = var2.gridsize * levelID; + for (size_t i = 0; i < var2.gridsize; ++i) { auto work1 = work[j][varID][i + offset]; auto work2 = work[n_out + j][varID][i + offset]; auto tmpatan2 = std::atan2(work1, work2) * n / (j + 1) / 2 / M_PI; - out[j][varID][i + offset] = (work1 > 0.0 || work2 > 0.0) ? tmpatan2 : missval; + out[j][varID][i + offset] = (work1 > 0.0 || work2 > 0.0) ? tmpatan2 : var2.missval; if (out[j][varID][i + offset] < 0) out[j][varID][i + offset] += n / (j + 1.); } } @@ -246,15 +249,13 @@ public: for (int varID = 0; varID < nvars; ++varID) { - auto gridsize = varList2[varID].gridsize; - auto nlevels = varList2[varID].nlevels; - auto missval = vlistInqVarMissval(vlistID2, varID); - for (int levelID = 0; levelID < nlevels; ++levelID) + const auto &var2 = varList2[varID]; + for (int levelID = 0; levelID < var2.nlevels; ++levelID) { - auto offset = gridsize * levelID; - auto nmiss = array_num_mv(gridsize, &out[j][varID][offset], missval); + auto offset = var2.gridsize * levelID; + auto numMissVals = array_num_mv(var2.gridsize, &out[j][varID][offset], var2.missval); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, &out[j][varID][offset], nmiss); + cdo_write_record(streamID2, &out[j][varID][offset], numMissVals); } } } @@ -264,19 +265,5 @@ public: close() { for (int j = 0; j < n_out; ++j) cdo_stream_close(streamIDs[j]); - - cdo_finish(); } }; - -void * -Harmonic(void *process) -{ - ModuleHarmonic harmonic; - - harmonic.init(process); - harmonic.run(); - harmonic.close(); - - return nullptr; -} diff --git a/src/Healpix.cc b/src/Healpix.cc index e8f8847a6b50bd1712d020b4ddd14e6785e8d46a..fe27e5b54042291d453f5e6003c347bb091c76e1 100644 --- a/src/Healpix.cc +++ b/src/Healpix.cc @@ -110,7 +110,7 @@ degrade(const Varray<T> &v1, size_t gridsize2, Varray<T> &v2, bool hasMissvals, static void hp_degrade(const Field &field1, Field &field2, const HealpixParams ¶ms) { - auto hasMissvals = (field1.nmiss > 0); + auto hasMissvals = (field1.numMissVals > 0); if (field1.memType == MemType::Float) degrade(field1.vec_f, field2.gridsize, field2.vec_f, hasMissvals, (float) field1.missval, params); else @@ -140,7 +140,7 @@ upgrade(size_t gridsize1, const Varray<T> &v1, Varray<T> &v2, bool hasMissvals, static void hp_upgrade(const Field &field1, Field &field2, const HealpixParams ¶ms) { - auto hasMissvals = (field1.nmiss > 0); + auto hasMissvals = (field1.numMissVals > 0); if (field1.memType == MemType::Float) upgrade(field1.gridsize, field1.vec_f, field2.vec_f, hasMissvals, (float) field1.missval, params); else @@ -208,7 +208,7 @@ get_parameter(void) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -294,8 +294,21 @@ hp_define_grid(int gridID1, HealpixParams ¶ms) return gridIDout; } -class ModuleHealpix +class Healpix : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Healpix", + .operators = { { "hpupgrade", HealpixHelp }, { "hpdegrade", HealpixHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Healpix> registration = RegisterEntry<Healpix>(module); + + int HPDEGRADE; CdoStreamID streamID1; int taxisID1; @@ -315,17 +328,14 @@ class ModuleHealpix public: void - init(void *process) + init() { - cdo_initialize(process); - // clang-format off - cdo_operator_add("hpupgrade", 0, 0, nullptr); - auto HPDEGRADE = cdo_operator_add("hpdegrade", 0, 0, nullptr); + HPDEGRADE = module.get_id("hpdegrade"); // clang-format on auto operatorID = cdo_operator_id(); - doDegrade = (operatorID == HPDEGRADE); + doDegrade = (operatorID == HPDEGRADE); params = get_parameter(); params.doDegrade = doDegrade; @@ -341,7 +351,7 @@ public: auto gridID = vlistGrid(vlistID1, 0); if (!is_healpix_grid(gridID)) cdo_abort("Input grid is not healpix!"); - vlistID2 = vlistDuplicate(vlistID1); + vlistID2 = vlistDuplicate(vlistID1); taxisID2 = taxisDuplicate(taxisID1); vlistDefTaxis(vlistID2, taxisID2); @@ -354,6 +364,7 @@ public: streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); } + void run() { @@ -388,6 +399,7 @@ public: tsID1++; } } + void close() { @@ -396,18 +408,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Healpix(void *process) -{ - - ModuleHealpix healpix; - healpix.init(process); - healpix.run(); - healpix.close(); - return nullptr; -} diff --git a/src/Hi.cc b/src/Hi.cc index 6d879448eb90ff9cdbb76e1641d66e851ce5b847..7ad878a86827665e4a9c26ca04fcec70c9c4016d 100644 --- a/src/Hi.cc +++ b/src/Hi.cc @@ -53,7 +53,7 @@ farexpr(Field &field1, const Field &field2, const Field &field3, double (*expres auto len = gridInqSize(grid1); if (len != gridInqSize(grid2) || len != gridInqSize(grid3)) cdo_abort("Fields have different gridsize (%s)", __func__); - if (field1.nmiss || field2.nmiss || field3.nmiss) + if (field1.numMissVals || field2.numMissVals || field3.numMissVals) { for (size_t i = 0; i < len; ++i) if (DBL_IS_EQUAL(field1.vec_d[i], missval1) || DBL_IS_EQUAL(field2.vec_d[i], missval2) @@ -67,11 +67,22 @@ farexpr(Field &field1, const Field &field2, const Field &field3, double (*expres for (size_t i = 0; i < len; ++i) field1.vec_d[i] = expression(field1.vec_d[i], field2.vec_d[i], field3.vec_d[i], missval1); } - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } -class ModuleHi +class Hi : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Hi", + .operators = { { "hi"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Hi> registration = RegisterEntry<Hi>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -92,11 +103,8 @@ class ModuleHi public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("hi", 0, 0, nullptr); operator_check_argc(0); @@ -166,15 +174,15 @@ public: { int varID1, levelID1; cdo_inq_record(streamID1, &varID1, &levelID1); - cdo_read_record(streamID1, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(streamID1, field1.vec_d.data(), &field1.numMissVals); int varID2, levelID2; cdo_inq_record(streamID2, &varID2, &levelID2); - cdo_read_record(streamID2, field2.vec_d.data(), &field2.nmiss); + cdo_read_record(streamID2, field2.vec_d.data(), &field2.numMissVals); int varID3, levelID3; cdo_inq_record(streamID3, &varID3, &levelID3); - cdo_read_record(streamID3, field3.vec_d.data(), &field3.nmiss); + cdo_read_record(streamID3, field3.vec_d.data(), &field3.numMissVals); if (varID1 != varID2 || varID1 != varID3 || levelID1 != levelID2 || levelID1 != levelID3) cdo_abort("Input streams have different structure!"); @@ -193,7 +201,7 @@ public: farexpr(field1, field2, field3, humidityIndex); cdo_def_record(streamID4, varID4, levelID1); - cdo_write_record(streamID4, field1.vec_d.data(), field1.nmiss); + cdo_write_record(streamID4, field1.vec_d.data(), field1.numMissVals); } tsID++; @@ -207,18 +215,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Hi(void *process) -{ - ModuleHi hi; - hi.init(process); - hi.run(); - hi.close(); - - return nullptr; -} diff --git a/src/Histogram.cc b/src/Histogram.cc index 49e0a8b9e8170c735feeae86bd877720ddefa493..df1b7ba3000516bb1762dfa7d240251ccf6a24b7 100644 --- a/src/Histogram.cc +++ b/src/Histogram.cc @@ -17,8 +17,24 @@ #include "process_int.h" #include "param_conversion.h" -class ModuleHistogram +class Histogram : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Histogram", + .operators = { { "histcount", HistogramHelp }, + { "histsum", HistogramHelp }, + { "histmean", HistogramHelp }, + { "histfreq", HistogramHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Histogram> registration = RegisterEntry<Histogram>(module); + int HISTCOUNT, HISTSUM, HISTMEAN, HISTFREQ; + private: CdoStreamID streamID1; CdoStreamID streamID2; @@ -39,22 +55,16 @@ private: int nvars; int operatorID; - int HISTCOUNT; - int HISTSUM; - int HISTMEAN; - int HISTFREQ; - public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - HISTCOUNT = cdo_operator_add("histcount", 0, 0, nullptr); - HISTSUM = cdo_operator_add("histsum", 0, 0, nullptr); - HISTMEAN = cdo_operator_add("histmean", 0, 0, nullptr); - HISTFREQ = cdo_operator_add("histfreq", 0, 0, nullptr); +HISTCOUNT = module.get_id("histcount"); +HISTSUM = module.get_id("histsum"); +HISTMEAN = module.get_id("histmean"); +HISTFREQ = module.get_id("histfreq"); // clang-format on (void) (HISTSUM); // unused @@ -143,13 +153,13 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); const auto gridsize = varList1[varID].gridsize; const auto missval = varList1[varID].missval; - nmiss = 0; + numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) { if (!DBL_IS_EQUAL(array[i], missval)) @@ -171,7 +181,7 @@ public: } else { - nmiss++; // missing value + numMissVals++; // missing value } } } @@ -188,7 +198,7 @@ public: for (int index = 0; index < nbins; ++index) { - size_t nmiss = 0; + size_t numMissVals = 0; const auto offset = gridsize * index; for (size_t i = 0; i < gridsize; ++i) @@ -208,7 +218,7 @@ public: } else { - nmiss++; + numMissVals++; varcount[varID][offset + i] = missval; vardata[varID][offset + i] = missval; } @@ -217,9 +227,9 @@ public: cdo_def_record(streamID2, varID, index); if (operatorID == HISTCOUNT) - cdo_write_record(streamID2, &varcount[varID][offset], nmiss); + cdo_write_record(streamID2, &varcount[varID][offset], numMissVals); else - cdo_write_record(streamID2, &vardata[varID][offset], nmiss); + cdo_write_record(streamID2, &vardata[varID][offset], numMissVals); } } } @@ -229,17 +239,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Histogram(void *process) -{ - ModuleHistogram histogram; - histogram.init(process); - histogram.run(); - histogram.close(); - return nullptr; -} diff --git a/src/Importamsr.cc b/src/Importamsr.cc index f7123b35aa55194f5955e92f0e1a8dac3437144d..bb2f57d6f86fe6555fb4387bd92fe78254ceda90 100644 --- a/src/Importamsr.cc +++ b/src/Importamsr.cc @@ -34,12 +34,12 @@ init_amsr_day(int vlistID, int gridID, int zaxisID, int nvars) */ const char *name[] = { "hours", "sst", "wind", "vapor", "cloud", "rain" }; const char *units[] = { "h", "deg Celcius", "m/s", "mm", "mm", "mm/h" }; - const double xscale[] = { 0.1, 0.15, 0.2, 0.3, 0.01, 0.1 }; - const double xminval[] = { 0., -3., 0., 0., 0., 0. }; + constexpr double xscale[] = { 0.1, 0.15, 0.2, 0.3, 0.01, 0.1 }; + constexpr double xminval[] = { 0., -3., 0., 0., 0., 0. }; for (int i = 0; i < nvars; ++i) { - const int varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING); + int varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING); cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, name[i]); cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, units[i]); vlistDefVarDatatype(vlistID, varID, CDI_DATATYPE_INT16); @@ -78,13 +78,13 @@ init_amsr_averaged(int vlistID, int gridID, int zaxisID, int nvars) */ const char *name[] = { "sst", "wind", "vapor", "cloud", "rain" }; const char *units[] = { "deg Celcius", "m/s", "mm", "mm", "mm/h" }; - const double xscale[] = { 0.15, 0.2, 0.3, 0.01, 0.1 }; - const double xminval[] = { -3., 0., 0., 0., 0. }; + constexpr double xscale[] = { 0.15, 0.2, 0.3, 0.01, 0.1 }; + constexpr double xminval[] = { -3., 0., 0., 0., 0. }; for (int i = 0; i < nvars; ++i) { // varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_CONSTANT); - const int varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING); + int varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING); cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, name[i]); cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, units[i]); vlistDefVarDatatype(vlistID, varID, CDI_DATATYPE_INT16); @@ -95,42 +95,42 @@ init_amsr_averaged(int vlistID, int gridID, int zaxisID, int nvars) } static void -read_amsr(FILE *fp, int vlistID, int nvars, Varray2D<double> &data, size_t *nmiss) +read_amsr(FILE *fp, int vlistID, int nvars, Varray2D<double> &data, size_t *numMissVals) { std::vector<unsigned char> amsr_data; for (int varID = 0; varID < nvars; ++varID) { - const size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID)); + size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID)); amsr_data.resize(gridsize); - const size_t size = fread(amsr_data.data(), 1, gridsize, fp); + size_t size = fread(amsr_data.data(), 1, gridsize, fp); if (size != gridsize) cdo_abort("Read error!"); - const double missval = vlistInqVarMissval(vlistID, varID); + double missval = vlistInqVarMissval(vlistID, varID); double xminval = 0.0, xscale = 1.0; cdiInqKeyFloat(vlistID, varID, CDI_KEY_SCALEFACTOR, &xscale); cdiInqKeyFloat(vlistID, varID, CDI_KEY_ADDOFFSET, &xminval); - nmiss[varID] = 0; + numMissVals[varID] = 0; for (size_t i = 0; i < gridsize; ++i) { if (amsr_data[i] <= 250) { data[varID][i] = amsr_data[i] * xscale + xminval; } else { data[varID][i] = missval; - nmiss[varID]++; + numMissVals[varID]++; } } } } static void -write_data(CdoStreamID streamID, int nvars, Varray2D<double> &data, size_t *nmiss) +write_data(CdoStreamID streamID, int nvars, Varray2D<double> &data, size_t *numMissVals) { for (int varID = 0; varID < nvars; ++varID) { cdo_def_record(streamID, varID, 0); - cdo_write_record(streamID, data[varID].data(), nmiss[varID]); + cdo_write_record(streamID, data[varID].data(), numMissVals[varID]); } } @@ -138,18 +138,30 @@ static int get_date(const char *name) { const char *pname = strchr(name, '_'); - const int date = pname ? atoi(pname + 1) : 0; + int date = pname ? atoi(pname + 1) : 0; return date; } -class ModuleImportamsr +class Importamsr : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Importamsr", + .operators = { { "import_amsr", ImportamsrHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Importamsr> registration = RegisterEntry<Importamsr>(module); + int tsID; int nvars; int vtime = 0; double xvals[NLON], yvals[NLAT]; Varray2D<double> data; - size_t nmiss[MAX_VARS]; + size_t numMissVals[MAX_VARS]; CdoStreamID streamID; @@ -184,9 +196,9 @@ class ModuleImportamsr vtime += 120000; // 13:30:00 cdo_def_timestep(streamID, tsID); - read_amsr(fp, vlistID, nvars, data, nmiss); + read_amsr(fp, vlistID, nvars, data, numMissVals); - write_data(streamID, nvars, data, nmiss); + write_data(streamID, nvars, data, numMissVals); } } @@ -208,18 +220,15 @@ class ModuleImportamsr tsID = 0; cdo_def_timestep(streamID, tsID); - read_amsr(fp, vlistID, nvars, data, nmiss); + read_amsr(fp, vlistID, nvars, data, numMissVals); - write_data(streamID, nvars, data, nmiss); + write_data(streamID, nvars, data, numMissVals); } public: void - init(void *process) + init() { - - cdo_initialize(process); - operator_check_argc(0); fp = std::fopen(cdo_get_stream_name(0), "r"); @@ -259,6 +268,7 @@ public: data = Varray2D<double>(MAX_VARS); } + void run() { @@ -267,6 +277,7 @@ public: else { cdo_abort("Unexpected file size for AMSR data!"); } process_def_var_num(vlistNvars(vlistID)); } + void close() { @@ -278,19 +289,5 @@ public: gridDestroy(gridID); zaxisDestroy(zaxisID); taxisDestroy(taxisID); - - cdo_finish(); } }; - -void * -Importamsr(void *process) -{ - ModuleImportamsr importamsr; - - importamsr.init(process); - importamsr.run(); - importamsr.close(); - - return nullptr; -} diff --git a/src/Importbinary.cc b/src/Importbinary.cc index 1a80b77acaa58a39129afd2da0ae1b02060fa218..096a1845134b12524f9b6e2414c867f761bb100c 100644 --- a/src/Importbinary.cc +++ b/src/Importbinary.cc @@ -110,9 +110,20 @@ define_level(dsets_t *pfi, int nlev) return zaxisID; } -class ModuleImportbinary +class Importbinary : public Process { - size_t nmiss = 0; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Importbinary", + .operators = { { "import_binary", ImportbinaryHelp } }, + .aliases = { { "import_grads", "import_binary" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Importbinary> registration = RegisterEntry<Importbinary>(module); + size_t numMissVals = 0; int told, fnum; int tmin = 0, tmax = 0; char *ch = nullptr; @@ -142,11 +153,9 @@ class ModuleImportbinary public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); dsets_init(&pfi); @@ -162,13 +171,13 @@ public: if (nvars == 0) cdo_abort("No variables found!"); - gridID = define_grid(&pfi); - zaxisID = define_level(&pfi, 0); + gridID = define_grid(&pfi); + zaxisID = define_level(&pfi, 0); auto zaxisIDsfc = zaxisCreate(ZAXIS_SURFACE, 1); zaxisDefLevels(zaxisIDsfc, &sfclevel); - vlistID = vlistCreate(); + vlistID = vlistCreate(); Varray<int> var_zaxisID(nvars); var_dfrm = Varray<int>(nrecs); @@ -273,12 +282,12 @@ public: rDateTime.time = cdiTime_encode(dtim.hr, dtim.mn, 0, 0); auto calendar = CALENDAR_STANDARD; - taxisID = cdo_taxis_create(TAXIS_RELATIVE); + taxisID = cdo_taxis_create(TAXIS_RELATIVE); taxisDefCalendar(taxisID, calendar); taxisDefRdatetime(taxisID, rDateTime); vlistDefTaxis(vlistID, taxisID); - streamID = cdo_open_write(1); + streamID = cdo_open_write(1); cdo_def_vlist(streamID, vlistID); gridsize = pfi.dnum[0] * pfi.dnum[1]; @@ -447,18 +456,18 @@ public: double fmin = 1.e99; double fmax = -1.e99; - nmiss = 0; + numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) { if (array[i] > pfi.ulow && array[i] < pfi.uhi) { array[i] = pfi.undef; - nmiss++; + numMissVals++; } else if (std::isnan(array[i])) { array[i] = pfi.undef; - nmiss++; + numMissVals++; } else { @@ -469,7 +478,7 @@ public: auto [varID, levelID] = recList[recID].get(); cdo_def_record(streamID, varID, levelID); - cdo_write_record(streamID, array.data(), nmiss); + cdo_write_record(streamID, array.data(), numMissVals); } } @@ -491,19 +500,5 @@ public: taxisDestroy(taxisID); if (pfi.infile) std::fclose(pfi.infile); - - cdo_finish(); } }; - -void * -Importbinary(void *process) -{ - ModuleImportbinary importbinary; - - importbinary.init(process); - importbinary.run(); - importbinary.close(); - - return nullptr; -} diff --git a/src/Importcmsaf.cc b/src/Importcmsaf.cc index 572672e5fcba256f5a146c2b0c463a923d9ec737..5dcc9846517083933097b793a7fe4fa9f8bafcc4 100644 --- a/src/Importcmsaf.cc +++ b/src/Importcmsaf.cc @@ -16,10 +16,10 @@ #endif #include <cdi.h> +#include <stdlib.h> // realloc() #include "cdo_options.h" #include "compare.h" -#include "dmemory.h" #include "varray.h" #include "process_int.h" #include "cdo_default_values.h" @@ -350,7 +350,7 @@ read_geolocation(hid_t loc_id, int nx, int ny, int lprojtype) H5Tinsert(proj_tid, "Reference ellipsoid", HOFFSET(proj_t, ellipsoid), str_tid); H5Tinsert(proj_tid, "Projection parameter", HOFFSET(proj_t, parameter), fltarr_tid); - //if (projection_name) Free(projection_name); failed with: pointer being freed was not allocated + // if (projection_name) free(projection_name); failed with: pointer being freed was not allocated grp_id = H5Gopen(loc_id, "Geolocation"); @@ -649,8 +649,8 @@ static void read_dataset(hid_t loc_id, const char *name, void *opdata) { hid_t dataspace; - hsize_t dims_out[9]; // dataset dimensions - herr_t status; // Generic return value + hsize_t dims_out[9]; // dataset dimensions + herr_t status; // Generic return value hid_t attr, atype, atype_mem; int iattr; float fattr; @@ -667,9 +667,9 @@ read_dataset(hid_t loc_id, const char *name, void *opdata) int ftype = 0; int len; int dtype = CDI_DATATYPE_FLT32; - char attstring[4096]; // Buffer to read string attribute back + char attstring[4096]; // Buffer to read string attribute back char varname[CDI_MAX_NAME]; - size_t nmiss; + size_t numMissVals; int num_attrs; attstring[0] = 0; @@ -927,19 +927,19 @@ read_dataset(hid_t loc_id, const char *name, void *opdata) else if (cdo_cmpstr(attname, "description")) { H5Aread(attr, atype_mem, attstring); - if (((datasets_t *) opdata)->obj[nset].description) Free(((datasets_t *) opdata)->obj[nset].description); + if (((datasets_t *) opdata)->obj[nset].description) free(((datasets_t *) opdata)->obj[nset].description); ((datasets_t *) opdata)->obj[nset].description = strdup(attstring); } else if (cdo_cmpstr(attname, "title")) { H5Aread(attr, atype_mem, attstring); - if (((datasets_t *) opdata)->obj[nset].title) Free(((datasets_t *) opdata)->obj[nset].title); + if (((datasets_t *) opdata)->obj[nset].title) free(((datasets_t *) opdata)->obj[nset].title); ((datasets_t *) opdata)->obj[nset].title = strdup(attstring); } else if (cdo_cmpstr(attname, "time")) { H5Aread(attr, atype_mem, attstring); - if (((datasets_t *) opdata)->obj[nset].time) Free(((datasets_t *) opdata)->obj[nset].time); + if (((datasets_t *) opdata)->obj[nset].time) free(((datasets_t *) opdata)->obj[nset].time); ((datasets_t *) opdata)->obj[nset].time = strdup(attstring); } else if (cdo_cmpstr(attname, "unit")) @@ -955,7 +955,7 @@ read_dataset(hid_t loc_id, const char *name, void *opdata) int offset = gridsize * (nz - 1); double *array = ((datasets_t *) opdata)->obj[nset].array; - array = (double *) Realloc(array, gridsize * nz * nt * sizeof(double)); + array = (double *) realloc(array, gridsize * nz * nt * sizeof(double)); ((datasets_t *) opdata)->obj[nset].array = array; array = array + offset; @@ -1007,7 +1007,7 @@ read_dataset(hid_t loc_id, const char *name, void *opdata) std::vector<bool> mask(gridsize * nt, false); - nmiss = 0; + numMissVals = 0; auto mm = varray_min_max(gridsize * nt, array); @@ -1041,7 +1041,7 @@ read_dataset(hid_t loc_id, const char *name, void *opdata) } else { - nmiss++; + numMissVals++; mask[i] = true; } } @@ -1058,7 +1058,7 @@ read_dataset(hid_t loc_id, const char *name, void *opdata) if (Options::cdoVerbose) cdo_print("Dataset %s: dtype = %d minval = %g maxval = %g missval = %g", varname, dtype, minval, maxval, missval); - if (nmiss) + if (numMissVals) { if (!(missval < minval || missval > maxval)) { @@ -1256,11 +1256,22 @@ dsets_init(datasets_t *dsets) } } #endif -class ModuleImportcmsaf +class Importcmsaf : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Importcmsaf", + .operators = { { "import_cmsaf", ImportcmsafHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Importcmsaf> registration = RegisterEntry<Importcmsaf>(module); #ifdef HAVE_LIBHDF5 int gridID = -1, zaxisID; - size_t nmiss; + size_t numMissVals; int ivar; int varID, levelID, tsID; hid_t file_id; @@ -1273,9 +1284,8 @@ class ModuleImportcmsaf public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -1423,14 +1433,14 @@ public: double *array = dsets.obj[ivar].array + offset; auto mm = varray_min_max_mv(gridsize, array, missval); - nmiss = gridsize - mm.n; + numMissVals = gridsize - mm.n; if (Options::cdoVerbose) - cdo_print(" Write var %d, level %d, nmiss %zu, missval %g, minval %g, maxval %g", varID, levelID, nmiss, missval, + cdo_print(" Write var %d, level %d, numMissVals %zu, missval %g, minval %g, maxval %g", varID, levelID, numMissVals, missval, mm.min, mm.max); cdo_def_record(streamID, varID, levelID); - cdo_write_record(streamID, array, nmiss); + cdo_write_record(streamID, array, numMissVals); } } } @@ -1455,19 +1465,8 @@ public: zaxisDestroy(zaxisID); taxisDestroy(taxisID); - for (ivar = 0; ivar < dsets.numSets; ++ivar) Free(dsets.obj[ivar].array); + for (ivar = 0; ivar < dsets.numSets; ++ivar) free(dsets.obj[ivar].array); #endif - cdo_finish(); } }; - -void * -Importcmsaf(void *process) -{ - ModuleImportcmsaf importcmsaf; - importcmsaf.init(process); - importcmsaf.run(); - importcmsaf.close(); - return nullptr; -} diff --git a/src/Importfv3grid.cc b/src/Importfv3grid.cc index 433ed06c414ad1dc629eb15feb541967fe8fe3ea..42b4783eb5a848c29eb1ffb611af1ed9b1922165 100644 --- a/src/Importfv3grid.cc +++ b/src/Importfv3grid.cc @@ -9,8 +9,19 @@ #include "process_int.h" -class ModuleImportfv3grid +class Importfv3grid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Importfv3grid", + .operators = { { "import_fv3grid"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Importfv3grid> registration = RegisterEntry<Importfv3grid>(module); size_t gridsize1; size_t gridsize2; @@ -28,9 +39,8 @@ class ModuleImportfv3grid public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -75,13 +85,13 @@ public: { Varray<double> buffer(gridsize1); int varID, levelID; - size_t nmiss; + size_t numMissVals; { Varray<double> grid_corner(4 * gridsize2); cdo_inq_record(streamID1, &varID, &levelID); // grid_lon - cdo_read_record(streamID1, buffer.data(), &nmiss); + cdo_read_record(streamID1, buffer.data(), &numMissVals); for (size_t j = 1; j < ny; ++j) for (size_t i = 1; i < nx; ++i) @@ -95,7 +105,7 @@ public: gridDefXbounds(gridIDo, grid_corner.data()); cdo_inq_record(streamID1, &varID, &levelID); // grid_lat - cdo_read_record(streamID1, buffer.data(), &nmiss); + cdo_read_record(streamID1, buffer.data(), &numMissVals); for (size_t j = 1; j < ny; ++j) for (size_t i = 1; i < nx; ++i) @@ -110,15 +120,15 @@ public: } cdo_inq_record(streamID1, &varID, &levelID); // grid_lont - cdo_read_record(streamID1, buffer.data(), &nmiss); + cdo_read_record(streamID1, buffer.data(), &numMissVals); gridDefXvals(gridIDo, buffer.data()); cdo_inq_record(streamID1, &varID, &levelID); // grid_latt - cdo_read_record(streamID1, buffer.data(), &nmiss); + cdo_read_record(streamID1, buffer.data(), &numMissVals); gridDefYvals(gridIDo, buffer.data()); cdo_inq_record(streamID1, &varID, &levelID); // area - cdo_read_record(streamID1, buffer.data(), &nmiss); + cdo_read_record(streamID1, buffer.data(), &numMissVals); double sfclevel = 0; surfaceID = zaxisCreate(ZAXIS_SURFACE, 1); @@ -151,19 +161,5 @@ public: vlistDestroy(vlistID2); gridDestroy(gridIDo); zaxisDestroy(surfaceID); - - cdo_finish(); } }; - -void * -Importfv3grid(void *process) -{ - ModuleImportfv3grid importfv3grid; - - importfv3grid.init(process); - importfv3grid.run(); - importfv3grid.close(); - - return nullptr; -} diff --git a/src/Importobs.cc b/src/Importobs.cc index 92016f8858278c2b676250b34d06c8de966d63d1..5943c9b2f9cd9ebea72051d3b0ac6e7c6e266c64 100644 --- a/src/Importobs.cc +++ b/src/Importobs.cc @@ -5,12 +5,13 @@ */ +#include <fstream> + #include <cdi.h> #include "cdo_options.h" #include "process_int.h" #include "varray.h" -#include "readline.h" #include <mpim_grid.h> #include "griddes.h" @@ -49,9 +50,9 @@ write_data(CdoStreamID streamID, int vlistID, int nvars, Varray2D<double> &data) { auto gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID)); auto missval = vlistInqVarMissval(vlistID, varID); - auto nmiss = varray_num_mv(gridsize, data[varID], missval); + auto numMissVals = varray_num_mv(gridsize, data[varID], missval); cdo_def_record(streamID, varID, 0); - cdo_write_record(streamID, data[varID].data(), nmiss); + cdo_write_record(streamID, data[varID].data(), numMissVals); } } @@ -63,11 +64,20 @@ get_date(const char *name) return date; } -#define MAX_LINE_LEN 4096 - -class ModuleImportobs +class Importobs : public Process { - char line[MAX_LINE_LEN]; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Importobs", + .operators = { { "import_obs", 0, 0, "grid description file or name"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Importobs>(module); + int nvars = 6; int vtime = 0; char dummy[32], station[32], datetime[32]; @@ -95,13 +105,8 @@ class ModuleImportobs public: void - init(void *process) + init() { - - cdo_initialize(process); - - cdo_operator_add("import_obs", 0, 0, "grid description file or name"); - auto operatorID = cdo_operator_id(); operator_input_arg(cdo_operator_enter(operatorID)); @@ -123,13 +128,6 @@ public: cdo_grid_to_degree(gridID, CDI_XAXIS, xvals, "grid center lon"); cdo_grid_to_degree(gridID, CDI_YAXIS, yvals, "grid center lat"); - fp = std::fopen(cdo_get_stream_name(0), "r"); - if (fp == nullptr) - { - perror(cdo_get_stream_name(0)); - exit(EXIT_FAILURE); - } - vdate = get_date(cdo_get_stream_name(0)); if (vdate <= 999999) vdate = vdate * 100 + 1; @@ -152,13 +150,17 @@ public: void run() { + std::ifstream file(cdo_get_stream_name(0)); + if (!file.is_open()) cdo_abort("Open failed on: %s\n", cdo_get_stream_name(0)); + int vdate0 = 0; int vtime0 = 0; // ntime = 0; int tsID = 0; - while (cdo::readline(fp, line, MAX_LINE_LEN)) + std::string line; + while (std::getline(file, line)) { - std::sscanf(line, "%s %s %s %g %g %g %d %g %g %g", dummy, station, datetime, &lat, &lon, &height1, &code, &pressure, + std::sscanf(line.c_str(), "%s %s %s %g %g %g %d %g %g %g", dummy, station, datetime, &lat, &lon, &height1, &code, &pressure, &height2, &value); long vdate_l; std::sscanf(datetime, "%ld_%d", &vdate_l, &vtime); @@ -221,6 +223,8 @@ public: */ } + file.close(); + write_data(streamID, vlistID, nvars, data); if (Options::cdoVerbose) printf("lonmin=%g, lonmax=%g, latmin=%g, latmax=%g\n", lonmin, lonmax, latmin, latmax); @@ -233,24 +237,9 @@ public: { cdo_stream_close(streamID); - std::fclose(fp); - vlistDestroy(vlistID); gridDestroy(gridID); zaxisDestroy(zaxisID); taxisDestroy(taxisID); - - cdo_finish(); } }; - -void * -Importobs(void *process) -{ - ModuleImportobs importobs; - importobs.init(process); - importobs.run(); - importobs.close(); - - return nullptr; -} diff --git a/src/Info.cc b/src/Info.cc index a0db061e2a44f18ae2a2c81b8771700c1f1eb913..57241d7dfcd8e28fc9d8ed41217ccb3854424654 100644 --- a/src/Info.cc +++ b/src/Info.cc @@ -32,7 +32,7 @@ struct Infostat double sum = 0.0; double sumi = 0.0; size_t nvals = 0; - size_t nmiss = 0; + size_t numMissVals = 0; int nlevels = 0; }; @@ -169,7 +169,7 @@ print_map(int nlon, int nlat, const Varray<T> &varray, double missval, double mi TextColor color(BLACK); switch (c) { - // clang-format off + // clang-format off case '0': mode = BRIGHT ; color = BLUE ; break; case '1': mode = MODELESS; color = BLUE ; break; case '2': mode = BRIGHT ; color = CYAN ; break; @@ -258,7 +258,7 @@ static void infostat_init(Infostat &infostat) { infostat.nvals = 0; - infostat.nmiss = 0; + infostat.numMissVals = 0; infostat.nlevels = 0; infostat.min = DBL_MAX; infostat.max = -DBL_MAX; @@ -282,7 +282,7 @@ print_header(int fileIndex, bool lvinfo, const std::string &e, const std::string static void compute_stat_real(const Field &field, Infostat &infostat, size_t &imiss, size_t gridsize) { - if (infostat.nmiss) + if (infostat.numMissVals) { auto nvals = field_min_max_sum_mv(field, infostat.min, infostat.max, infostat.sum); imiss = gridsize - nvals; @@ -329,7 +329,7 @@ print_stat_comp(const Infostat &infostat) fprintf(stdout, " - (%#12.5g,%#12.5g) -", arrmean_r, arrmean_i); } -class ModuleInfo +class Info : public Process { enum { @@ -337,6 +337,26 @@ class ModuleInfo E_CODE, E_PARAM }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Info", + .operators = { { "info", E_PARAM, 0, InfoHelp }, + { "infop", E_PARAM, 0, InfoHelp }, + { "infon", E_NAME, 0, InfoHelp }, + { "infoc", E_CODE, 0, InfoHelp }, + { "vinfon", E_NAME, 0, InfoHelp }, + { "xinfon", E_NAME, 0, InfoHelp }, + { "map", E_PARAM, 0, InfoHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { -1, 0, NoRestriction }, + }; + inline static RegisterEntry<Info> registration = RegisterEntry<Info>(module); + + int VINFON, XINFON, MAP; size_t imiss = 0; char paramstr[32]; @@ -348,24 +368,14 @@ class ModuleInfo std::string e; // parameter_name std::string v; // verbose; - // - int VINFON, XINFON, MAP; public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - cdo_operator_add("info", E_PARAM, 0, nullptr); - cdo_operator_add("infop", E_PARAM, 0, nullptr); - cdo_operator_add("infon", E_NAME, 0, nullptr); - cdo_operator_add("infoc", E_CODE, 0, nullptr); - VINFON = cdo_operator_add("vinfon", E_NAME, 0, nullptr); - XINFON = cdo_operator_add("xinfon", E_NAME, 0, nullptr); - MAP = cdo_operator_add("map", E_PARAM, 0, nullptr); - // clang-format on + VINFON = module.get_id("vinfon"); + XINFON = module.get_id("xinfon"); + MAP = module.get_id("map"); operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -422,19 +432,17 @@ public: const auto &var = varList[varID]; field.init(var); cdo_read_record(streamID, field); - auto nmiss = field.nmiss; + auto numMissVals = field.numMissVals; indg = lvinfo ? varID + 1 : indg + 1; - auto gridsize = var.gridsize; - auto loutput = !lvinfo; if (loutput) infostat_init(infostat[varID]); auto &infostatr = infostat[varID]; infostatr.nlevels += 1; - infostatr.nmiss += nmiss; + infostatr.numMissVals += numMissVals; if (var.nlevels == infostatr.nlevels) loutput = true; @@ -455,7 +463,7 @@ public: else fprintf(stdout, "%7g ", cdo_zaxis_inq_level(var.zaxisID, levelID)); - fprintf(stdout, "%8zu %7zu ", gridsize, infostatr.nmiss); + fprintf(stdout, "%8zu %7zu ", var.gridsize, infostatr.numMissVals); reset_text_color(stdout); fprintf(stdout, ":"); @@ -464,15 +472,15 @@ public: } // clang-format off - if (var.nwpv == CDI_REAL) compute_stat_real(field, infostatr, imiss, gridsize); - else compute_stat_comp(field, infostatr, imiss, gridsize); + if (var.nwpv == CDI_REAL) compute_stat_real(field, infostatr, imiss, var.gridsize); + else compute_stat_comp(field, infostatr, imiss, var.gridsize); // clang-format on if (loutput) { // clang-format off - if (var.nwpv == CDI_REAL) print_stat_real(infostatr); - else print_stat_comp(infostatr); + if (var.nwpv == CDI_REAL) print_stat_real(infostatr); + else print_stat_comp(infostatr); // clang-format on reset_text_color(stdout); @@ -481,16 +489,16 @@ public: // set_text_color(stdout, GREEN); // clang-format off - if (operfunc == E_NAME) fprintf(stdout, "%-14s", var.name.c_str()); - else if (operfunc == E_CODE) fprintf(stdout, "%4d ", var.code); - else fprintf(stdout, "%-14s", paramstr); + if (operfunc == E_NAME) fprintf(stdout, "%-14s", var.name.c_str()); + else if (operfunc == E_CODE) fprintf(stdout, "%4d ", var.code); + else fprintf(stdout, "%-14s", paramstr); // clang-format on // reset_text_color(stdout); fprintf(stdout, "\n"); } - if (imiss != nmiss && nmiss) cdo_warning("Found %zu of %zu missing values!", imiss, nmiss); + if (imiss != numMissVals && numMissVals) cdo_warning("Found %zu of %zu missing values!", imiss, numMissVals); if (operatorID == MAP) { @@ -519,17 +527,5 @@ public: void close() { - cdo_finish(); } }; - -void * -Info(void *process) -{ - ModuleInfo info; - info.init(process); - info.run(); - info.close(); - - return nullptr; -} diff --git a/src/Input.cc b/src/Input.cc index 58e8a554fa20a5bb758762f7484ecaf92fe47b0d..1dd086fde53c11009db73263846dd7fe2aa4b8b4 100644 --- a/src/Input.cc +++ b/src/Input.cc @@ -38,8 +38,25 @@ input_iarray(size_t nval, int *array) return ival; } -class ModuleInput +class Input : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Input", + // clang-format off + .operators = { { "input", InputHelp }, + { "inputsrv", InputHelp }, + { "inputext", InputHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 1, NoRestriction }, + }; + inline static RegisterEntry<Input> registration = RegisterEntry<Input>(module); + + int INPUT, INPUTSRV, INPUTEXT; int varID = 0; size_t gridsize0 = 0, gridsize = 0; int taxisID = 0; @@ -58,18 +75,13 @@ class ModuleInput int gridID = -1; int zaxisID = -1; - int INPUT, INPUTSRV, INPUTEXT; - public: void - init(void *process) + init() { - - cdo_initialize(process); - - INPUT = cdo_operator_add("input", 0, 0, nullptr); - INPUTSRV = cdo_operator_add("inputsrv", 0, 0, nullptr); - INPUTEXT = cdo_operator_add("inputext", 0, 0, nullptr); + INPUT = module.get_id("input"); + INPUTSRV = module.get_id("inputsrv"); + INPUTEXT = module.get_id("inputext"); operatorID = cdo_operator_id(); @@ -85,6 +97,7 @@ public: nlevs = (zaxisID == -1) ? 1 : zaxisInqSize(zaxisID); } + void run() { @@ -221,9 +234,9 @@ public: for (int levelID = 0; levelID < nlevs; ++levelID) { auto offset = gridsize * levelID; - auto nmiss = array_num_mv(gridsize, &array[offset], missval); + auto numMissVals = array_num_mv(gridsize, &array[offset], missval); cdo_def_record(streamID, varID, levelID); - cdo_write_record(streamID, &array[offset], nmiss); + cdo_write_record(streamID, &array[offset], numMissVals); } nrecs++; @@ -239,17 +252,5 @@ public: cdo_stream_close(streamID); vlistDestroy(vlistID); } - cdo_finish(); } }; -void * -Input(void *process) -{ - ModuleInput input; - - input.init(process); - input.run(); - input.close(); - - return nullptr; -} diff --git a/src/Intgrid.cc b/src/Intgrid.cc index 02b76049ea5787e6d02ffe1f21038c81d8cc54ee..9d50f086864e16f8f155e844508a8736c522df10 100644 --- a/src/Intgrid.cc +++ b/src/Intgrid.cc @@ -240,8 +240,25 @@ boxavg(const Field &field1, Field &field2, size_t xinc, size_t yinc) field_num_mv(field2); } -class ModuleIntgrid +class Intgrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Intgrid", + .operators = { { "intgridbil"}, + { "intgriddis"}, + { "intgridnn"}, + { "interpolate"}, + { "boxavg"}, + { "thinout"} }, + .aliases = { { "intgrid", "intgridbil" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Intgrid> registration = RegisterEntry<Intgrid>(module); + int INTGRIDBIL, INTGRIDDIS, INTGRIDNN, INTERPOLATE, BOXAVG, THINOUT; int gridID2 = -1; int xinc = 1, yinc = 1; @@ -258,20 +275,17 @@ class ModuleIntgrid VarList varList1, varList2; Field field1, field2; - int INTGRIDBIL, INTGRIDDIS, INTGRIDNN, INTERPOLATE, BOXAVG, THINOUT; - public: void - init(void *process) + init() { - cdo_initialize(process); - INTGRIDBIL = cdo_operator_add("intgridbil", 0, 0, nullptr); - INTGRIDDIS = cdo_operator_add("intgriddis", 0, 0, nullptr); - INTGRIDNN = cdo_operator_add("intgridnn", 0, 0, nullptr); - INTERPOLATE = cdo_operator_add("interpolate", 0, 0, nullptr); - BOXAVG = cdo_operator_add("boxavg", 0, 0, nullptr); - THINOUT = cdo_operator_add("thinout", 0, 0, nullptr); + INTGRIDBIL = module.get_id("intgridbil"); + INTGRIDDIS = module.get_id("intgriddis"); + INTGRIDNN = module.get_id("intgridnn"); + INTERPOLATE = module.get_id("interpolate"); + BOXAVG = module.get_id("boxavg"); + THINOUT = module.get_id("thinout"); operatorID = cdo_operator_id(); @@ -309,8 +323,7 @@ public: { if (index == 0) { - if (gridtype != GRID_LONLAT && gridtype != GRID_GAUSSIAN) - cdo_abort("%s data unsupported!", gridNamePtr(gridtype)); + if (gridtype != GRID_LONLAT && gridtype != GRID_GAUSSIAN) cdo_abort("%s data unsupported!", gridNamePtr(gridtype)); gridID2 = gen_boxavg_grid(gridID1, xinc, yinc); } @@ -384,13 +397,13 @@ public: } else { - cdo_read_record(streamID1, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(streamID1, field1.vec_d.data(), &field1.numMissVals); field1.grid = varList1[varID].gridID; field1.missval = varList1[varID].missval; field2.grid = gridID2; field2.missval = field1.missval; - field2.nmiss = 0; + field2.numMissVals = 0; } // clang-format off @@ -406,7 +419,7 @@ public: if (lfieldmem) cdo_write_record(streamID2, field2); else - cdo_write_record(streamID2, field2.vec_d.data(), field2.nmiss); + cdo_write_record(streamID2, field2.vec_d.data(), field2.numMissVals); } tsID++; } @@ -417,19 +430,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Intgrid(void *process) -{ - - ModuleIntgrid intgrid; - intgrid.init(process); - intgrid.run(); - intgrid.close(); - - return nullptr; -} diff --git a/src/Intgridtraj.cc b/src/Intgridtraj.cc index 50618e783bc7054001a6eb8e75c5c8c5c764d82f..1cddbb4cb95f0dba504ca562fa017b8555c43ed1 100644 --- a/src/Intgridtraj.cc +++ b/src/Intgridtraj.cc @@ -42,9 +42,20 @@ read_nextpos(FILE *fp, int calendar, JulianDate &julianDate, double &xpos, doubl return stat; } -class ModuleIntgridtraj +class Intgridtraj : public Process { - size_t nmiss = 0; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Intgridtraj", + .operators = { { "intgridtraj"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Intgridtraj> registration = RegisterEntry<Intgridtraj>(module); + size_t numMissVals = 0; double xpos, ypos; int calendar = CALENDAR_STANDARD; @@ -71,11 +82,9 @@ class ModuleIntgridtraj public: void - init(void *process) + init() { - cdo_initialize(process); - operator_input_arg("filename with grid trajectories"); operator_check_argc(1); @@ -146,8 +155,8 @@ public: const auto gridsize = varList1[varID].gridsize; const auto offset = gridsize * levelID; auto single1 = &vardata1[varID][offset]; - cdo_read_record(streamID1, single1, &nmiss); - if (nmiss) cdo_abort("Missing values unsupported for this operator!"); + cdo_read_record(streamID1, single1, &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported for this operator!"); } int tsIDo = 0; @@ -167,8 +176,8 @@ public: const auto gridsize = varList1[varID].gridsize; const auto offset = gridsize * levelID; auto single2 = &vardata2[varID][offset]; - cdo_read_record(streamID1, single2, &nmiss); - if (nmiss) cdo_abort("Missing values unsupported for this operator!"); + cdo_read_record(streamID1, single2, &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported for this operator!"); } while (julianDate_to_seconds(julianDate) < julianDate_to_seconds(julianDate2)) @@ -203,14 +212,14 @@ public: field1.grid = varList1[varID].gridID; field1.missval = varList1[varID].missval; - field1.nmiss = nmiss; + field1.numMissVals = numMissVals; field2.grid = gridID2; - field2.nmiss = 0; + field2.numMissVals = 0; intgridbil(field1, field2); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, field2.vec_d.data(), field2.nmiss); + cdo_write_record(streamID2, field2.vec_d.data(), field2.numMissVals); } } @@ -240,19 +249,5 @@ public: std::fclose(fp); if (streamID2 != CDO_STREAM_UNDEF) cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Intgridtraj(void *process) -{ - ModuleIntgridtraj intgridtraj; - - intgridtraj.init(process); - intgridtraj.run(); - intgridtraj.close(); - - return nullptr; -} diff --git a/src/Intlevel.cc b/src/Intlevel.cc index b0ccbf6fcc1833fd6394f972873359391e21d9d3..d5e87c999a67cca7d1fe4b9c50d9cad862baf02f 100644 --- a/src/Intlevel.cc +++ b/src/Intlevel.cc @@ -310,7 +310,7 @@ intlevel_get_parameter(std::string &zdescription, std::string &zvarname) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); auto def_level = false; @@ -326,24 +326,24 @@ intlevel_get_parameter(std::string &zdescription, std::string &zvarname) if (nvalues == 1 && value.empty()) nvalues = 0; // clang-format off - if (key == "level") + if (key == "level") { if (def_zdescription) cdo_abort("Parameter level and zdescription can't be mixed!"); levels.resize(nvalues); for (int i = 0; i < nvalues; ++i) levels[i] = parameter_to_double(values[i]); def_level = true; } - else if (key == "zdescription") + else if (key == "zdescription") { - if (def_level) cdo_abort("Parameter file and level can't be mixed!"); + if (def_level) cdo_abort("Parameter zdescription and level can't be mixed!"); zdescription = value; def_zdescription = true; } - else if (key == "zvarname") + else if (key == "zvarname") { zvarname = value; } - else cdo_abort("Invalid parameter key >%s<!", key); + else cdo_abort("Invalid parameter key >%s<!", key); // clang-format on } } @@ -426,8 +426,24 @@ handle_empty_zvar(size_t &wisize, int &nlevel, std::vector<double> &lev1, const wisize = nlev2; } -class ModuleIntlevel +class Intlevel : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Intlevel", + // clang-format off + .operators = { { "intlevel", IntlevelHelp }, + { "intlevelx", IntlevelHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Intlevel> registration = RegisterEntry<Intlevel>(module); + + int INTLEVEL, INTLEVELX; int zaxisID1 = -1; int nlevel = 0; @@ -439,7 +455,7 @@ class ModuleIntlevel std::vector<bool> processVars; std::vector<bool> interpVars; - std::vector<std::vector<size_t>> varnmiss; + std::vector<std::vector<size_t>> varnumMissVals; Field3DVector vardata1; Field3DVector vardata2; @@ -468,17 +484,12 @@ class ModuleIntlevel VarList varList1; VarList varList2; - int INTLEVEL, INTLEVELX; - public: void - init(void *process) + init() { - - cdo_initialize(process); - - INTLEVEL = cdo_operator_add("intlevel", 0, 0, nullptr); - INTLEVELX = cdo_operator_add("intlevelx", 0, 0, nullptr); + INTLEVEL = module.get_id("intlevel"); + INTLEVELX = module.get_id("intlevelx"); (void) (INTLEVEL); // unused @@ -510,7 +521,7 @@ public: } } - nlev2 = lev2.size(); + nlev2 = lev2.size(); if (Options::cdoVerbose) for (int i = 0; i < nlev2; ++i) cdo_print("level out %d: %g", i, lev2[i]); @@ -559,11 +570,11 @@ public: processVars = std::vector<bool>(nvars); interpVars = std::vector<bool>(nvars, false); - varnmiss = std::vector<std::vector<size_t>>(nvars); + varnumMissVals = std::vector<std::vector<size_t>>(nvars); vardata1 = Field3DVector(nvars); vardata2 = Field3DVector(nvars); - const int maxlev = (nlev1 > nlev2) ? nlev1 : nlev2; + int maxlev = (nlev1 > nlev2) ? nlev1 : nlev2; for (int varID = 0; varID < nvars; ++varID) { @@ -575,12 +586,13 @@ public: if (interpVars[varID]) { - varnmiss[varID].resize(maxlev, 0); + varnumMissVals[varID].resize(maxlev, 0); vardata2[varID].init(varList2[varID]); } - else { varnmiss[varID].resize(nlevels); } + else { varnumMissVals[varID].resize(nlevels); } } } + void run() { @@ -599,7 +611,7 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, vardata1[varID], levelID, &varnmiss[varID][levelID]); + cdo_read_record(streamID1, vardata1[varID], levelID, &varnumMissVals[varID][levelID]); processVars[varID] = true; } @@ -627,9 +639,9 @@ public: { auto offset = gridsize * levelID; if (memType == MemType::Float) - varnmiss[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_f[offset], (float) missval); + varnumMissVals[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_f[offset], (float) missval); else - varnmiss[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_d[offset], missval); + varnumMissVals[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_d[offset], missval); } } } @@ -642,7 +654,7 @@ public: { cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, interpVars[varID] ? vardata2[varID] : vardata1[varID], levelID, - varnmiss[varID][levelID]); + varnumMissVals[varID][levelID]); } } } @@ -650,24 +662,11 @@ public: tsID++; } } + void close() { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Intlevel(void *process) -{ - ModuleIntlevel intlevel; - - intlevel.init(process); - intlevel.run(); - intlevel.close(); - - return nullptr; -} diff --git a/src/Intlevel3d.cc b/src/Intlevel3d.cc index cbb551461a8bccd21fa015ac125577f29d146771..e4225db4ad2f3860a67f8dce389079201b59a6d1 100644 --- a/src/Intlevel3d.cc +++ b/src/Intlevel3d.cc @@ -105,9 +105,9 @@ read_source_coordinate(int streamNumber, VarList &varList2, Varray<float> &zleve int varID, levelID; cdo_inq_record(streamID2, &varID, &levelID); auto offset = gridsize * levelID; - size_t nmiss; - cdo_read_record_f(streamID2, &zlevelsIn[offset], &nmiss); - if (0 != nmiss) cdo_abort("Input vertical coordinate variables are not allowed to contain missing values."); + size_t numMissVals; + cdo_read_record_f(streamID2, &zlevelsIn[offset], &numMissVals); + if (0 != numMissVals) cdo_abort("Input vertical coordinate variables are not allowed to contain missing values."); } cdo_stream_close(streamID2); @@ -136,16 +136,28 @@ read_target_coordinate(const std::string &fileName, VarList &varList0, Varray<fl int varID, levelID; streamInqRecord(streamID0, &varID, &levelID); auto offset = gridsize * levelID; - size_t nmiss; - streamReadRecordF(streamID0, &zlevelsOut[offset], &nmiss); - if (0 != nmiss) cdo_abort("Output vertical coordinate variables are not allowd to contain missing values."); + size_t numMissVals; + streamReadRecordF(streamID0, &zlevelsOut[offset], &numMissVals); + if (0 != numMissVals) cdo_abort("Output vertical coordinate variables are not allowd to contain missing values."); } streamClose(streamID0); } -class ModuleIntlevel3d +class Intlevel3d : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Intlevel3d", + .operators = { { "intlevel3d", Intlevel3dHelp }, { "intlevelx3d", Intlevel3dHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Intlevel3d> registration = RegisterEntry<Intlevel3d>(module); + int INTLEVEL3D, INTLEVELX3D; CdoStreamID streamID1; CdoStreamID streamID2; @@ -170,7 +182,7 @@ class ModuleIntlevel3d std::vector<bool> processVars; std::vector<bool> interpVars; - std::vector<std::vector<size_t>> varnmiss; + std::vector<std::vector<size_t>> varnumMissVals; Field3DVector vardata1; Field3DVector vardata2; @@ -180,17 +192,14 @@ class ModuleIntlevel3d Varray<float> zlevelsOut; - int INTLEVEL3D, INTLEVELX3D; - public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - INTLEVEL3D = cdo_operator_add("intlevel3d", 0, 0, nullptr); - INTLEVELX3D = cdo_operator_add("intlevelx3d", 0, 0, nullptr); +INTLEVEL3D = module.get_id("intlevel3d"); +INTLEVELX3D = module.get_id("intlevelx3d"); // clang-format on (void) INTLEVEL3D; // unused @@ -294,7 +303,7 @@ public: processVars = std::vector<bool>(nvars); interpVars = std::vector<bool>(nvars, false); // marker for variables to be interpolated - varnmiss = std::vector<std::vector<size_t>>(nvars); // can for missing values of arbitrary variables + varnumMissVals = std::vector<std::vector<size_t>>(nvars); // can for missing values of arbitrary variables vardata1 = Field3DVector(nvars); vardata2 = Field3DVector(nvars); @@ -314,12 +323,12 @@ public: interpVars[varID] = (zaxisID == zaxisID1 && varID != oz3dvarID && gridsize == gridSize && gridsizeo == gridsize); if (interpVars[varID]) { - varnmiss[varID].resize(maxlev, 0); + varnumMissVals[varID].resize(maxlev, 0); vardata2[varID].init(varList3[varID]); } else { - varnmiss[varID].resize(nlevel); + varnumMissVals[varID].resize(nlevel); if (Options::cdoVerbose) cdo_print("Ignore variable %s (levels=%d gridsize=%zu)!", varList1[varID].name, nlevel, gridsize); } @@ -352,7 +361,7 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, vardata1[varID], levelID, &varnmiss[varID][levelID]); + cdo_read_record(streamID1, vardata1[varID], levelID, &varnumMissVals[varID][levelID]); processVars[varID] = true; } @@ -370,9 +379,9 @@ public: { auto offset = gridsize * levelID; if (memType == MemType::Float) - varnmiss[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_f[offset], (float) missval); + varnumMissVals[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_f[offset], (float) missval); else - varnmiss[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_d[offset], missval); + varnumMissVals[varID][levelID] = array_num_mv(gridsize, &vardata2[varID].vec_d[offset], missval); } } else @@ -390,7 +399,7 @@ public: { cdo_def_record(streamID3, varID, levelID); cdo_write_record(streamID3, interpVars[varID] ? vardata2[varID] : vardata1[varID], levelID, - varnmiss[varID][levelID]); + varnumMissVals[varID][levelID]); } } } @@ -413,19 +422,5 @@ public: cdo_stream_close(streamID3); vlistDestroy(vlistID3); - - cdo_finish(); } }; - -void * -Intlevel3d(void *process) -{ - ModuleIntlevel3d intlevel3d; - - intlevel3d.init(process); - intlevel3d.run(); - intlevel3d.close(); - - return nullptr; -} diff --git a/src/Intntime.cc b/src/Intntime.cc index d83f6e49a2cf7935de5efb0d020d6770c9b83f55..69907f3dac5abbfe49504c09b25a3b8aa295c763 100644 --- a/src/Intntime.cc +++ b/src/Intntime.cc @@ -23,8 +23,19 @@ void interp_time(double fac1, double fac2, const double *array1, const double *array2, Field &field3, bool withMissval); -class ModuleIntntime +class Intntime : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Intntime", + .operators = { { "intntime", InttimeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Intntime> registration = RegisterEntry<Intntime>(module); int curFirst = 0, curSecond = 1; CdoStreamID streamID1; @@ -46,14 +57,13 @@ class ModuleIntntime VarList varList; Field field3; std::vector<RecordInfo> recList; - Varray3D<size_t> nmiss; + Varray3D<size_t> numMissVals; Varray3D<double> vardata; public: void - init(void *process) + init() { - cdo_initialize(process); operator_input_arg("number of timesteps between 2 timesteps"); if (cdo_operator_argc() < 1) cdo_abort("Too few arguments!"); @@ -73,9 +83,9 @@ public: auto maxrecs = vlistNrecs(vlistID1); recList = std::vector<RecordInfo>(maxrecs); - nmiss = Varray3D<size_t>(2); - nmiss[0].resize(nvars); - nmiss[1].resize(nvars); + numMissVals = Varray3D<size_t>(2); + numMissVals[0].resize(nvars); + numMissVals[1].resize(nvars); vardata = Varray3D<double>(2); vardata[0].resize(nvars); vardata[1].resize(nvars); @@ -84,8 +94,8 @@ public: { auto gridsize = varList[varID].gridsize; auto nlevel = varList[varID].nlevels; - nmiss[0][varID].resize(nlevel); - nmiss[1][varID].resize(nlevel); + numMissVals[0][varID].resize(nlevel); + numMissVals[1][varID].resize(nlevel); vardata[0][varID].resize(gridsize * nlevel); vardata[1][varID].resize(gridsize * nlevel); } @@ -114,10 +124,10 @@ public: cdo_inq_record(streamID1, &varID, &levelID); auto offset = varList[varID].gridsize * levelID; auto single1 = &vardata[curFirst][varID][offset]; - cdo_read_record(streamID1, single1, &nmiss[curFirst][varID][levelID]); + cdo_read_record(streamID1, single1, &numMissVals[curFirst][varID][levelID]); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, single1, nmiss[curFirst][varID][levelID]); + cdo_write_record(streamID2, single1, numMissVals[curFirst][varID][levelID]); } } void @@ -140,7 +150,7 @@ public: auto offset = varList[varID].gridsize * levelID; auto single2 = &vardata[curSecond][varID][offset]; - cdo_read_record(streamID1, single2, &nmiss[curSecond][varID][levelID]); + cdo_read_record(streamID1, single2, &numMissVals[curSecond][varID][levelID]); } for (int it = 1; it < numts; it++) @@ -168,7 +178,7 @@ public: field3.init(varList[varID]); - auto withMissval = (nmiss[curFirst][varID][levelID] || nmiss[curSecond][varID][levelID]); + auto withMissval = (numMissVals[curFirst][varID][levelID] || numMissVals[curSecond][varID][levelID]); interp_time(fac1, fac2, single1, single2, field3, withMissval); cdo_def_record(streamID2, varID, levelID); @@ -186,7 +196,7 @@ public: auto single2 = &vardata[curSecond][varID][offset]; cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, single2, nmiss[curSecond][varID][levelID]); + cdo_write_record(streamID2, single2, numMissVals[curSecond][varID][levelID]); } julianDate1 = julianDate2; @@ -198,17 +208,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Intntime(void *process) -{ - ModuleIntntime intntime; - intntime.init(process); - intntime.run(); - intntime.close(); - return nullptr; -} diff --git a/src/Inttime.cc b/src/Inttime.cc index dfd853e0ec1d4ec4baa51eec4217ee23f0d63f23..518ed2f9d904ae7d892a603350b3afa628a2ab34 100644 --- a/src/Inttime.cc +++ b/src/Inttime.cc @@ -27,7 +27,7 @@ size_t interp_time(double fac1, double fac2, size_t gridsize, const double *v1, const double *v2, Varray<T> &v3, bool withMissval, double missval) { - size_t nmiss3 = 0; + size_t numMissVals3 = 0; if (withMissval) { @@ -42,7 +42,7 @@ interp_time(double fac1, double fac2, size_t gridsize, const double *v1, const d else { v3[i] = missval; - nmiss3++; + numMissVals3++; } } } @@ -54,16 +54,16 @@ interp_time(double fac1, double fac2, size_t gridsize, const double *v1, const d for (size_t i = 0; i < gridsize; ++i) v3[i] = v1[i] * fac1 + v2[i] * fac2; } - return nmiss3; + return numMissVals3; } void interp_time(double fac1, double fac2, const double *array1, const double *array2, Field &field3, bool withMissval) { if (field3.memType == MemType::Float) - field3.nmiss = interp_time(fac1, fac2, field3.gridsize, array1, array2, field3.vec_f, withMissval, field3.missval); + field3.numMissVals = interp_time(fac1, fac2, field3.gridsize, array1, array2, field3.vec_f, withMissval, field3.missval); else - field3.nmiss = interp_time(fac1, fac2, field3.gridsize, array1, array2, field3.vec_d, withMissval, field3.missval); + field3.numMissVals = interp_time(fac1, fac2, field3.gridsize, array1, array2, field3.vec_d, withMissval, field3.missval); } static void @@ -95,8 +95,19 @@ adjust_time_units(int taxisID, int timeUnitsOut) } } -class ModuleInttime +class Inttime : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Inttime", + .operators = { { "inttime", InttimeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Inttime> registration = RegisterEntry<Inttime>(module); CdiDateTime sDateTime{}; int incrPeriod = 0, incrUnits = 3600, timeUnits = TUNIT_HOUR; @@ -124,15 +135,14 @@ class ModuleInttime std::vector<RecordInfo> recList; Field field3; - Varray3D<size_t> nmiss; + Varray3D<size_t> numMissVals; Varray3D<double> vardata; VarList varList; public: void - init(void *process) + init() { - cdo_initialize(process); operator_input_arg("date,time<,increment> (format YYYY-MM-DD,hh:mm:ss)"); if (cdo_operator_argc() < 2) cdo_abort("Too few arguments!"); @@ -158,9 +168,9 @@ public: auto maxrecs = vlistNrecs(vlistID1); recList = std::vector<RecordInfo>(maxrecs); - nmiss = Varray3D<size_t>(2); - nmiss[0].resize(nvars); - nmiss[1].resize(nvars); + numMissVals = Varray3D<size_t>(2); + numMissVals[0].resize(nvars); + numMissVals[1].resize(nvars); vardata = Varray3D<double>(2); vardata[0].resize(nvars); vardata[1].resize(nvars); @@ -169,8 +179,8 @@ public: { auto gridsize = varList[varID].gridsize; auto nlevel = varList[varID].nlevels; - nmiss[0][varID].resize(nlevel); - nmiss[1][varID].resize(nlevel); + numMissVals[0][varID].resize(nlevel); + numMissVals[1][varID].resize(nlevel); vardata[0][varID].resize(gridsize * nlevel); vardata[1][varID].resize(gridsize * nlevel); } @@ -201,7 +211,7 @@ public: cdo_inq_record(streamID1, &varID, &levelID); auto offset = varList[varID].gridsize * levelID; auto single1 = &vardata[curFirst][varID][offset]; - cdo_read_record(streamID1, single1, &nmiss[curFirst][varID][levelID]); + cdo_read_record(streamID1, single1, &numMissVals[curFirst][varID][levelID]); } if (Options::cdoVerbose) @@ -241,7 +251,7 @@ public: auto offset = varList[varID].gridsize * levelID; auto single2 = &vardata[curSecond][varID][offset]; - cdo_read_record(streamID1, single2, &nmiss[curSecond][varID][levelID]); + cdo_read_record(streamID1, single2, &numMissVals[curSecond][varID][levelID]); } while (julianDate_to_seconds(julianDate) <= julianDate_to_seconds(julianDate2)) @@ -278,7 +288,7 @@ public: field3.init(varList[varID]); - auto withMissval = (nmiss[curFirst][varID][levelID] || nmiss[curSecond][varID][levelID]); + auto withMissval = (numMissVals[curFirst][varID][levelID] || numMissVals[curSecond][varID][levelID]); interp_time(fac1, fac2, single1, single2, field3, withMissval); cdo_def_record(streamID2, varID, levelID); @@ -302,17 +312,5 @@ public: cdo_stream_close(streamID1); if (tsIDo == 0) cdo_warning("Start date/time %s out of range, no time steps interpolated!", datetime_to_string(sDateTime)); - - cdo_finish(); } }; -void * -Inttime(void *process) -{ - ModuleInttime inttime; - inttime.init(process); - inttime.run(); - inttime.close(); - - return nullptr; -} diff --git a/src/Intyear.cc b/src/Intyear.cc index ced66b47d46387b3ace14b6e04d68992e4515f0e..33f4cbd303c00d2df34d870574d6ce2e3cdf5555 100644 --- a/src/Intyear.cc +++ b/src/Intyear.cc @@ -24,7 +24,7 @@ static size_t intlin_year(double fac1, double fac2, size_t gridsize, const Varray<double> &array1, const Varray<double> &array2, Varray<double> &array3, bool withMissval, double missval1, double missval2) { - size_t nmiss3 = 0; + size_t numMissVals3 = 0; if (withMissval) { @@ -37,7 +37,7 @@ intlin_year(double fac1, double fac2, size_t gridsize, const Varray<double> &arr else { array3[i] = missval1; - nmiss3++; + numMissVals3++; } } } @@ -46,11 +46,22 @@ intlin_year(double fac1, double fac2, size_t gridsize, const Varray<double> &arr for (size_t i = 0; i < gridsize; ++i) array3[i] = array1[i] * fac1 + array2[i] * fac2; } - return nmiss3; + return numMissVals3; } -class ModuleIntyear +class Intyear : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Intyear", + .operators = { { "intyear", IntyearHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, OBASE, NoRestriction }, + }; + inline static RegisterEntry<Intyear> registration = RegisterEntry<Intyear>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -71,9 +82,8 @@ class ModuleIntyear public: void - init(void *process) + init() { - cdo_initialize(process); operator_input_arg("years"); @@ -153,24 +163,24 @@ public: cdo_inq_record(streamID1, &varID, &levelID); cdo_inq_record(streamID2, &varID, &levelID); - size_t nmiss1, nmiss2; - cdo_read_record(streamID1, array1.data(), &nmiss1); - cdo_read_record(streamID2, array2.data(), &nmiss2); + size_t numMissVals1, numMissVals2; + cdo_read_record(streamID1, array1.data(), &numMissVals1); + cdo_read_record(streamID2, array2.data(), &numMissVals2); auto gridsize = varList1[varID].gridsize; auto missval1 = varList1[varID].missval; auto missval2 = varList2[varID].missval; - auto withMissval = (nmiss1 || nmiss2); + auto withMissval = (numMissVals1 || numMissVals2); for (int iy = 0; iy < nyears; iy++) { auto fac1 = ((double) year2 - iyears[iy]) / (year2 - year1); auto fac2 = ((double) iyears[iy] - year1) / (year2 - year1); - auto nmiss3 = intlin_year(fac1, fac2, gridsize, array1, array2, array3, withMissval, missval1, missval2); + auto numMissVals3 = intlin_year(fac1, fac2, gridsize, array1, array2, array3, withMissval, missval1, missval2); cdo_def_record(streamIDs[iy], varID, levelID); - cdo_write_record(streamIDs[iy], array3.data(), nmiss3); + cdo_write_record(streamIDs[iy], array3.data(), numMissVals3); } } @@ -185,18 +195,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Intyear(void *process) -{ - ModuleIntyear intyear; - intyear.init(process); - intyear.run(); - intyear.close(); - - return nullptr; -} diff --git a/src/Invert.cc b/src/Invert.cc index 1bb54933550a640173875548a8bf70bf1fceb5b5..5577958dd3b9b3cbb424d4c73a037a4ea42d7c29 100644 --- a/src/Invert.cc +++ b/src/Invert.cc @@ -258,7 +258,7 @@ invert_lat_des(int vlistID) } } -class ModuleInvert +class Invert : public Process { enum { @@ -269,6 +269,23 @@ class ModuleInvert func_lat }; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Invert", + .operators = { { "invertlat", func_all, func_lat, InvertHelp }, + { "invertlon", func_all, func_lon, InvertHelp }, + { "invertlatdes", func_hrd, func_lat, InvertHelp }, + { "invertlondes", func_hrd, func_lon, InvertHelp }, + { "invertlatdata", func_fld, func_lat, InvertHelp }, + { "invertlondata", func_fld, func_lon, InvertHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Invert> registration = RegisterEntry<Invert>(module); + CdoStreamID streamID1; CdoStreamID streamID2; @@ -283,17 +300,10 @@ class ModuleInvert public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("invertlat", func_all, func_lat, nullptr); - cdo_operator_add("invertlon", func_all, func_lon, nullptr); - cdo_operator_add("invertlatdes", func_hrd, func_lat, nullptr); - cdo_operator_add("invertlondes", func_hrd, func_lon, nullptr); - cdo_operator_add("invertlatdata", func_fld, func_lat, nullptr); - cdo_operator_add("invertlondata", func_fld, func_lon, nullptr); // clang-format on const auto operatorID = cdo_operator_id(); @@ -368,18 +378,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Invert(void *process) -{ - ModuleInvert invert; - - invert.init(process); - invert.run(); - invert.close(); - - return nullptr; -} diff --git a/src/Invertlev.cc b/src/Invertlev.cc index a0d6eb58b1f2d2404af646e35a231a094c7a5c94..9389f9dd6dba058584668a6ad16f1a6dad4c2c22 100644 --- a/src/Invertlev.cc +++ b/src/Invertlev.cc @@ -24,7 +24,6 @@ invertLevDes(int vlistID) { auto zaxisID1 = vlistZaxis(vlistID, index); auto zaxisID2 = zaxisDuplicate(zaxisID1); - auto zaxistype = zaxisInqType(zaxisID1); auto nlev = zaxisInqSize(zaxisID1); if (nlev <= 1) continue; @@ -49,9 +48,10 @@ invertLevDes(int vlistID) zaxisDefUbounds(zaxisID2, yb2.data()); } + auto zaxistype = zaxisInqType(zaxisID1); if (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) { - const int vctsize = zaxisInqVctSize(zaxisID1); + auto vctsize = zaxisInqVctSize(zaxisID1); if (vctsize && vctsize % 2 == 0) { Varray<double> vct1(vctsize), vct2(vctsize); @@ -69,8 +69,20 @@ invertLevDes(int vlistID) } } -class ModuleInvertlev +class Invertlev : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Invertlev", + .operators = { { "invertlev", InvertlevHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Invertlev> registration = RegisterEntry<Invertlev>(module); + CdoStreamID streamID1; CdoStreamID streamID2; @@ -84,20 +96,16 @@ class ModuleInvertlev int nvars; bool dataIsUnchanged; - std::vector<std::vector<size_t>> varnmiss; + std::vector<std::vector<size_t>> varnumMissVals; - size_t nmiss; + size_t numMissVals; public: void - init(void *process) + init() { - cdo_initialize(process); - dataIsUnchanged = data_is_unchanged(); - cdo_operator_add("invertlev", 0, 0, nullptr); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -121,24 +129,25 @@ public: nvars = vlistNvars(vlistID1); vardata = Varray2D<double>(nvars); - varnmiss = std::vector<std::vector<size_t>>(nvars); + varnumMissVals = Varray2D<size_t>(nvars); varList_init(varList1, vlistID1); auto has3dVar = false; for (int varID = 0; varID < nvars; ++varID) { - auto nlevels = varList1[varID].nlevels; - if (nlevels > 1) + const auto &var = varList1[varID]; + if (var.nlevels > 1) { has3dVar = true; - vardata[varID].resize(varList1[varID].gridsize * nlevels); - varnmiss[varID].resize(nlevels); + vardata[varID].resize(var.gridsize * var.nlevels); + varnumMissVals[varID].resize(var.nlevels); } } if (!has3dVar) cdo_warning("No variables with invertable levels found!"); } + void run() { @@ -160,8 +169,8 @@ public: if (vardata[varID].size()) { auto offset = varList1[varID].gridsize * levelID; - cdo_read_record(streamID1, &vardata[varID][offset], &nmiss); - varnmiss[varID][levelID] = nmiss; + cdo_read_record(streamID1, &vardata[varID][offset], &numMissVals); + varnumMissVals[varID][levelID] = numMissVals; } else { @@ -169,8 +178,8 @@ public: if (dataIsUnchanged) { cdo_copy_record(streamID2, streamID1); } else { - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); } } } @@ -179,16 +188,15 @@ public: { if (vardata[varID].size()) { - auto gridsize = varList1[varID].gridsize; - auto nlevels = varList1[varID].nlevels; - for (int levelID = 0; levelID < nlevels; ++levelID) + const auto &var = varList1[varID]; + for (int levelID = 0; levelID < var.nlevels; ++levelID) { cdo_def_record(streamID2, varID, levelID); - auto offset = gridsize * (nlevels - levelID - 1); - nmiss = varnmiss[varID][nlevels - levelID - 1]; + auto offset = var.gridsize * (var.nlevels - levelID - 1); + numMissVals = varnumMissVals[varID][var.nlevels - levelID - 1]; - cdo_write_record(streamID2, &vardata[varID][offset], nmiss); + cdo_write_record(streamID2, &vardata[varID][offset], numMissVals); } } } @@ -196,23 +204,11 @@ public: tsID++; } } + void close() { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Invertlev(void *process) -{ - ModuleInvertlev invertlev; - - invertlev.init(process); - invertlev.run(); - invertlev.close(); - - return nullptr; -} diff --git a/src/Lic.cc b/src/Lic.cc index 82d6cbfa56092c5446d9f360dbbdc287be40cba2..e8cb8a7e46684434e0ccbdb345c3f49a7fe848ec 100644 --- a/src/Lic.cc +++ b/src/Lic.cc @@ -165,7 +165,7 @@ WriteImage2PNG(int width, int height, unsigned char *pImage, float *mag, const c } // Initialize write structure - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr); if (png_ptr == nullptr) { fprintf(stderr, "Could not allocate write struct\n"); @@ -401,7 +401,7 @@ lic1(const char *obasename, int num, int n_xres, int n_yres, float *pVectr) // const char *fname = "LIC.ppm"; // WriteImage2PPM(n_xres, n_yres, pImage, fname); char filename[8192]; - sprintf(filename, "%s%04d.png", obasename, num); + std::snprintf(filename, sizeof(filename), "%s%04d.png", obasename, num); #ifdef HAVE_LIBPNG WriteImage2PNG(n_xres, n_yres, pImage, mag, filename); @@ -416,10 +416,21 @@ lic1(const char *obasename, int num, int n_xres, int n_yres, float *pVectr) free(mag); } -class ModuleLic +class Lic : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Lic", + .operators = { { "lic"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Lic> registration = RegisterEntry<Lic>(module); int nlev = 0; - size_t nmiss; + size_t numMissVals; CdoStreamID streamID1; CdoStreamID streamID2; @@ -447,11 +458,9 @@ class ModuleLic public: void - init(void *process) + init() { - cdo_initialize(process); - // clang-format off // int LIC = cdo_operator_add("lic", 0, 0, nullptr); // clang-format on @@ -531,8 +540,8 @@ public: if (varID == varID1 || varID == varID2) { - cdo_read_record(streamID1, array1.data(), &nmiss); - if (nmiss) cdo_abort("Missing values unsupported!"); + cdo_read_record(streamID1, array1.data(), &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported!"); gridsize = gridInqSize(gridID); @@ -563,21 +572,9 @@ public: { cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Lic(void *process) -{ - ModuleLic lic; - lic.init(process); - lic.run(); - lic.close(); - return nullptr; -} - // mencoder // png + alpha canel libpng // ls -1v | grep JPG > files.txt diff --git a/src/Longinfo.cc b/src/Longinfo.cc index 5f5e2f194874f8aa5ff0635eb0e77bb4e963b9e2..6951ce7779b2dd6c5252e69908daa19ce8f5c942 100644 --- a/src/Longinfo.cc +++ b/src/Longinfo.cc @@ -68,7 +68,7 @@ compute_stat_real(const Field &field, LonginfoStat &infostat, size_t gridsize) { size_t imiss = 0; - if (field.nmiss) + if (field.numMissVals) { auto nvals = field_min_max_sum_mv(field, infostat.min, infostat.max, infostat.sum); imiss = gridsize - nvals; @@ -89,8 +89,19 @@ compute_stat_real(const Field &field, LonginfoStat &infostat, size_t gridsize) return imiss; } -class ModuleLonginfo +class Longinfo : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Longinfo", + .operators = { { "linfo"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Longinfo> registration = RegisterEntry<Longinfo>(module); char paramstr[32]; CdoStreamID streamID; @@ -102,12 +113,10 @@ class ModuleLonginfo public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("linfo", 0, 0, nullptr); // clang-format on operator_check_argc(0); @@ -153,14 +162,14 @@ public: field.init(var); cdo_read_record(streamID, field); - auto nmiss = field.nmiss; + auto numMissVals = field.numMissVals; LonginfoStat infostat; fprintf(stdout, "\t\tdataType: %s\n", cdo::datatype_to_cstr(var.datatype)); fprintf(stdout, "\t\tmemoryType: %s\n", (var.memType == MemType::Float) ? "float" : "double"); fprintf(stdout, "\t\tgridsize: %zu\n", var.gridsize); - fprintf(stdout, "\t\tnumMiss: %zu\n", nmiss); + fprintf(stdout, "\t\tnumMiss: %zu\n", numMissVals); fprintf(stdout, "\t\tmissval: %.*g\n", dig, var.missval); double addoffset = 0.0, scalefactor = 1.0; @@ -188,7 +197,7 @@ public: cdoPrintAttributes(stdout, vlistID, varID, 16); } - // if (imiss != nmiss && nmiss) cdo_warning("Found %zu of %zu missing values!", imiss, nmiss); + // if (imiss != numMissVals && numMissVals) cdo_warning("Found %zu of %zu missing values!", imiss, numMissVals); tsID++; } @@ -197,17 +206,5 @@ public: close() { cdo_stream_close(streamID); - - cdo_finish(); } }; - -void * -Longinfo(void *process) -{ - ModuleLonginfo longinfo; - longinfo.init(process); - longinfo.run(); - longinfo.close(); - return nullptr; -} diff --git a/src/Maggraph.cc b/src/Maggraph.cc index 2b1683a13b9c917dd994e7d19a5705416e0e9211..cdd008ae9bba898715f7263a447e8957e4f82fb5 100644 --- a/src/Maggraph.cc +++ b/src/Maggraph.cc @@ -26,7 +26,7 @@ #define DBG 0 -const char *line_colours[] = { +static const char *line_colours[] = { "red", "green", "blue", @@ -82,10 +82,10 @@ const char *line_colours[] = { "purple", }; -const char *graph_params[] = { "ymin", "ymax", "sigma", "stat", "obsv", "device", "linewidth" }; +static const char *graph_params[] = { "ymin", "ymax", "sigma", "stat", "obsv", "device", "linewidth" }; -int graph_param_count = sizeof(graph_params) / sizeof(char *); -int num_colours = sizeof(line_colours) / sizeof(char *); +constexpr int graph_param_count = sizeof(graph_params) / sizeof(char *); +constexpr int num_colours = sizeof(line_colours) / sizeof(char *); int checkdevice(char *device_in); @@ -131,7 +131,7 @@ compareTime(CdiTime time1, CdiTime time2) static void maggraph(const char *plotfile, const std::string &varname, const std::string &varunits, long nfiles, std::vector<long> nts, - std::vector<std::vector<CdiDateTime>> vDateTimes, std::vector<std::vector<double>> datatab, int nparam, + const std::vector<std::vector<CdiDateTime>> &vDateTimes, std::vector<std::vector<double>> datatab, int nparam, std::vector<std::string> ¶ms) { char min_date_time_str[1024], max_date_time_str[1024]; @@ -271,8 +271,6 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va } } - if (DBG) fprintf(stderr, "STAT %d\n", (int) stat); - char ***date_time_str = (char ***) malloc(nfiles * sizeof(char **)); std::vector<double> date_time; @@ -294,7 +292,7 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va { date_time[tsID] = tsID + 1; date_time_str[0][tsID] = (char *) malloc(256); - sprintf(date_time_str[0][tsID], "%s", datetime_to_string(vDateTimes[0][tsID]).c_str()); + std::snprintf(date_time_str[0][tsID], 256, "%s", datetime_to_string(vDateTimes[0][tsID]).c_str()); mean_val[tsID] = 0.; std_dev_val[tsID] = 0.; @@ -302,7 +300,7 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va for (fileID = 0; fileID < nfiles; ++fileID) { - if (DBG) fprintf(stderr, "fileID=%ld\n", fileID); + if (DBG) fprintf(stderr, "fileID=%ld ", fileID); if (datatab[fileID][tsID] < min_val) min_val = datatab[fileID][tsID]; if (datatab[fileID][tsID] > max_val) max_val = datatab[fileID][tsID]; @@ -377,7 +375,7 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va date_time[tsID] = tsID + 1; date_time_str[fileID][tsID] = (char *) malloc(256); - sprintf(date_time_str[fileID][tsID], "%s", datetime_to_string(vDateTimes[fileID][tsID]).c_str()); + std::snprintf(date_time_str[fileID][tsID], 256, "%s", datetime_to_string(vDateTimes[fileID][tsID]).c_str()); if (DBG && (tsID == 0 || tsID == nts[fileID] - 1)) fprintf(stderr, "%s\n", date_time_str[fileID][tsID]); if (datatab[fileID][tsID] < min_val) min_val = datatab[fileID][tsID]; @@ -528,8 +526,7 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va { count = obsv ? i - 1 : i; if (DBG) fprintf(stderr, "Current File %ld\n", i); - // sprintf(legend_text_data, "ens_%d", count + 1); - sprintf(legend_text_data, "data_%d", count + 1); + std::snprintf(legend_text_data, sizeof(legend_text_data), "data_%d", count + 1); mag_setc("graph_line_colour", line_colours[count % num_colours]); mag_setc("legend_user_text", legend_text_data); if (stat) @@ -549,7 +546,7 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va if (obsv) { mag_setc("graph_line_colour", "black"); - sprintf(legend_text_data, "%s", "Obsv"); + std::snprintf(legend_text_data, sizeof(legend_text_data), "%s", "Obsv"); mag_setc("legend_user_text", legend_text_data); mag_set1c("graph_curve_date_x_values", (const char **) date_time_str[0], nts[0]); @@ -581,7 +578,7 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va // TEMPORARY FIX, UNITL NEW MAGICS LIBRARY RELEASE * end mag_set1r("graph_curve_y_values", mean_val.data(), ntime_steps); - sprintf(legend_text_data, "Mean"); + std::snprintf(legend_text_data, sizeof(legend_text_data), "Mean"); mag_setc("legend_user_text", legend_text_data); mag_graph(); @@ -595,7 +592,7 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va mag_set1c("graph_curve_date_x_values", (const char **) date_time_str[0], ntime_steps); mag_set1r("graph_curve_y_values", spread_min.data(), ntime_steps); mag_setc("graph_shade_colour", "grey"); - sprintf(legend_text_data, "%dSigma", num_sigma); + std::snprintf(legend_text_data, sizeof(legend_text_data), "%dSigma", num_sigma); mag_setc("legend_user_text", legend_text_data); // TEMPORARY FIX, UNITL NEW MAGICS LIBRARY RELEASE * begin @@ -609,11 +606,11 @@ maggraph(const char *plotfile, const std::string &varname, const std::string &va char *lines[1]; lines[0] = (char *) malloc(1024); // To be obtained from Meta Data - // sprintf( lines[0],"%s","ExpID : " ); - // sprintf( lines[0],"%sxxxx Variable : %s[%s]",lines[0], varname.c_str(), varunits.c_str() ); - // sprintf( lines[0],"Variable : %s[%s]",varname.c_str(), varunits.c_str() ); - // sprintf( lines[0],"%s Date : %s --%s",lines[0], min_date_time_str, max_date_time_str ); - sprintf(lines[0], "Variable : %s[%s] Date : %s --%s", varname.c_str(), varunits.c_str(), min_date_time_str, max_date_time_str); + // std::snprintf(lines[0], 1024, "%s","ExpID : " ); + // std::snprintf(lines[0], 1024, "%sxxxx Variable : %s[%s]",lines[0], varname.c_str(), varunits.c_str() ); + // std::snprintf(lines[0], 1024, "Variable : %s[%s]",varname.c_str(), varunits.c_str() ); + // std::snprintf(lines[0], 1024, "%s Date : %s --%s",lines[0], min_date_time_str, max_date_time_str ); + std::snprintf(lines[0], 1024, "Variable : %s[%s] Date : %s --%s", varname.c_str(), varunits.c_str(), min_date_time_str, max_date_time_str); mag_set1c("text_lines", (const char **) lines, 1); mag_setc("text_html", "true"); @@ -654,7 +651,7 @@ quit_MAGICS() } static void -VerifyGraphParameters(int num_param, std::vector<std::string> ¶m_names) +verifyGraphParameters(int num_param, std::vector<std::string> ¶m_names) { int i, j; bool found = false, syntax = true, halt_flag = false; @@ -756,8 +753,19 @@ VerifyGraphParameters(int num_param, std::vector<std::string> ¶m_names) } #endif -class ModuleMaggraph +class Maggraph : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Maggraph", + .operators = { { "graph", MaggraphHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Maggraph> registration = RegisterEntry<Maggraph>(module); std::string varname, units; int gridID; @@ -771,16 +779,13 @@ class ModuleMaggraph public: void - init(void *process) + init() { - cdo_initialize(process); - #ifdef HAVE_LIBMAGICS - nparam = cdo_operator_argc(); pnames = cdo_get_oper_argv(); - if (nparam) VerifyGraphParameters(nparam, pnames); + if (nparam) verifyGraphParameters(nparam, pnames); nfiles = cdo_stream_cnt() - 1; ofilename = cdo_get_stream_name(nfiles); @@ -848,9 +853,9 @@ public: int varID, levelID; cdo_inq_record(streamID, &varID, &levelID); - size_t nmiss; + size_t numMissVals; double val; - cdo_read_record(streamID, &val, &nmiss); + cdo_read_record(streamID, &val, &numMissVals); datatab[fileID][tsID] = val; vDateTimes[fileID][tsID] = taxisInqVdatetime(taxisID); @@ -867,11 +872,6 @@ public: init_MAGICS(); cdo_print("Creating PLOT for %s", varname); - if (DBG) - { - fprintf(stderr, "Num params %d\n", nparam); - for (int i = 0; i < nparam; ++i) fprintf(stderr, "Param %s\n", pnames[i].c_str()); - } maggraph(ofilename, varname, units, nfiles, nts, vDateTimes, datatab, nparam, pnames); @@ -890,17 +890,5 @@ public: quit_MAGICS(); if (vlistID0 != -1) vlistDestroy(vlistID0); #endif - cdo_finish(); } }; - -void * -Maggraph(void *process) -{ - ModuleMaggraph maggraph; - maggraph.init(process); - maggraph.run(); - maggraph.close(); - - return nullptr; -} diff --git a/src/Magplot.cc b/src/Magplot.cc index 14d3da2684f8cd6633744f3d20b511f33c4803b2..8e2f4d9de72a90aa1c5198e7c426af11946d34ee 100644 --- a/src/Magplot.cc +++ b/src/Magplot.cc @@ -36,8 +36,6 @@ subpage_upper_right_latitude subpage_upper_right_longitude ****/ -static int CONTOUR, SHADED, GRFILL; - static const char *contour_params[] = { "min", "max", "count", "interval", "list", "colour", "thickness", "style", "RGB", "device", "step_freq", "file_split", "lat_min", "lat_max", "lon_min", "lon_max", "projection" }; @@ -169,348 +167,6 @@ static double LON_MIN = 1.0e+200, LON_MAX = -1.e+200; const char *COLOUR = nullptr, *COLOUR_MIN = nullptr, *COLOUR_MAX = nullptr, *STYLE = nullptr; const char *DEVICE = nullptr, *COLOUR_TRIAD = nullptr, *PROJECTION = nullptr; -static void -magplot(const char *plotfile, int operatorID, const std::string &varname, const std::string &units, long nlon, long nlat, - Varray<double> &grid_center_lon, Varray<double> &grid_center_lat, Varray<double> &array, size_t nmiss, double missval, - int nparam, const std::vector<std::string> ¶ms, const std::string &datetimeStr, bool lregular) - -{ - double dlon = 0, dlat = 0; - char plotfilename[4096]; - char *titlename; - char tempname[256]; - - if (DBG) - { - fprintf(stderr, "Num params %d\n", nparam); - - for (int i = 0; i < nparam; ++i) fprintf(stderr, "Param %s\n", params[i].c_str()); - fflush(stderr); - - for (int i = 0; i < nparam; ++i) - { - const auto splitStrings = split_with_seperator(params[i], '='); - const auto &key = splitStrings[0]; - - if (key == "min") fprintf(stderr, "Min Val %g\n", YMIN); - if (key == "max") fprintf(stderr, "Max Val %g\n", YMAX); - // if (key == "resolution") fprintf(stderr,"RESOLUTION %g\n",RESOLUTION ); - if (key == "colour") fprintf(stderr, "COLOUR %s\n", COLOUR); - if (key == "colour_min") fprintf(stderr, "COLOUR %s\n", COLOUR_MIN); - if (key == "colour_max") fprintf(stderr, "COLOUR %s\n", COLOUR_MAX); - if (key == "interval") fprintf(stderr, "INTERVAL %f\n", INTERVAL); - if (key == "count") fprintf(stderr, "COUNT %d\n", COUNT); - - if (key == "list") - for (int j = 0; j < NUM_LEVELS; ++j) fprintf(stderr, "LIST %f\n", LEV_LIST[j]); - - if (key == "thickness") fprintf(stderr, "THICKNESS %d\n", THICKNESS); - if (key == "style") fprintf(stderr, "STYLE %s\n", STYLE); - if (key == "device") fprintf(stderr, "DEVICE %s\n", DEVICE); - if (key == "step_freq") fprintf(stderr, "STEP_FREQ %d\n", STEP_FREQ); - if (key == "lat_min") fprintf(stderr, "Lat Min Val %g\n", LAT_MIN); - if (key == "lat_max") fprintf(stderr, "Lat Max Val %g\n", LAT_MAX); - if (key == "lon_min") fprintf(stderr, "Lon Min Val %g\n", LON_MIN); - if (key == "lon_max") fprintf(stderr, "Lon Max Val %g\n", LON_MAX); - if (key == "projection") fprintf(stderr, "PROJECTION %s\n", PROJECTION); - } - } - - if (lregular) - { - if (nlon > 1) - { - for (int i = 1; i < nlon; ++i) dlon += (grid_center_lon[i] - grid_center_lon[i - 1]); - dlon /= (nlon - 1); - } - if (nlat > 1) - { - for (int i = 1; i < nlat; ++i) dlat += (grid_center_lat[nlon * i] - grid_center_lat[nlon * (i - 1)]); - dlat /= (nlat - 1); - } - } - - sprintf(plotfilename, "%s [%s] %s", varname.c_str(), units.c_str(), datetimeStr.c_str()); - titlename = strdup(plotfilename); - sprintf(plotfilename, "%s_%s", plotfile, varname.c_str()); - - if (Options::cdoVerbose) cdo_print("nlon: %zu nlat: %zu", nlon, nlat); - if (Options::cdoVerbose) cdo_print("dlon: %g dlat: %g", dlon, dlat); - - auto mm = nmiss ? varray_min_max_mv(nlon * nlat, array, missval) : varray_min_max(nlon * nlat, array); - - if (Options::cdoVerbose) cdo_print("min: %g max: %g", mm.min, mm.max); - if (Options::cdoVerbose) cdo_print("input_field_organization: %s", lregular ? "REGULAR" : "NONREGULAR"); - - mag_setc("output_name", plotfilename); - mag_new("page"); - - // Set the input data arrays to magics++ - - mag_set2r("input_field", array.data(), nlon, nlat); - - mag_setr("input_field_suppress_below", mm.min); - mag_setr("input_field_suppress_above", mm.max); - - if (lregular) - { - mag_setc("input_field_organization", "REGULAR"); - // mag_setc("input_field_organization", "GAUSSIAN"); - - mag_setr("input_field_initial_latitude", grid_center_lat[0]); - mag_setr("input_field_latitude_step", dlat); - - mag_setr("input_field_initial_longitude", grid_center_lon[0]); - mag_setr("input_field_longitude_step", dlon); - } - else - { - mag_setc("input_field_organization", "NONREGULAR"); - - mag_set2r("input_field_latitudes", grid_center_lat.data(), nlon, nlat); - mag_set2r("input_field_longitudes", grid_center_lon.data(), nlon, nlat); - } - - /* magics_template_parser( magics_node ); */ - /* results_template_parser(results_node, varname.c_str() ); */ - - /* set up the coastline attributes */ - /* mag_setc ("map_coastline_colour", "khaki"); */ - /* mag_setc ("map_grid_colour", "grey"); */ - - // Parameters common to all operators - if (DEVICE) mag_setc("output_format", DEVICE); - - if (PROJECTION) mag_setc("subpage_map_projection", PROJECTION); - - mag_seti("map_label_latitude_frequency", 2); - mag_seti("map_label_longitude_frequency", 2); - /*mag_setr ("map_label_height",0.5);*/ - mag_setr("map_label_height", 0.4); - - /* define the contouring parameters */ - if (operatorID == SHADED) - { - mag_setc("contour", "off"); - mag_setc("contour_shade", "on"); - mag_setc("contour_shade_method", "area_fill"); - mag_setc("contour_label", "off"); - - if (LAT_MIN < 1.0e+200) mag_setr("subpage_lower_left_latitude", LAT_MIN); - if (LON_MIN < 1.0e+200) mag_setr("subpage_lower_left_longitude", LON_MIN); - if (LAT_MAX > -1.0e+200) mag_setr("subpage_upper_right_latitude", LAT_MAX); - if (LON_MAX > -1.0e+200) mag_setr("subpage_upper_right_longitude", LON_MAX); - - if (YMIN < 1.0e+200) - { - mag_setr("contour_shade_min_level", YMIN); - mag_setr("contour_min_level", YMIN); - } - - if (YMAX > -1.0e+200) - { - mag_setr("contour_shade_max_level", YMAX); - mag_setr("contour_max_level", YMAX); - } - - if (COLOUR_MAX) mag_setc("contour_shade_max_level_colour", COLOUR_MAX); - if (COLOUR_MIN) mag_setc("contour_shade_min_level_colour", COLOUR_MIN); - - if (is_not_equal(INTERVAL, 8.0f)) - { - mag_setc("contour_level_selection_type", "INTERVAL"); - mag_setr("contour_interval", INTERVAL); - } - - if (COUNT != 10) - { - mag_setc("contour_level_selection_type", "COUNT"); - mag_seti("contour_level_count", COUNT); - } - - if (NUM_LEVELS) - { - mag_setc("contour_level_selection_type", "LEVEL_LIST"); - mag_set1r("contour_level_list", LEV_LIST, NUM_LEVELS); - } - - if (USR_COLOUR_COUNT) - { - mag_setc("contour_shade_colour_method", "LIST"); - mag_set1c("contour_shade_colour_list", (const char **) USR_COLOUR_TABLE, USR_COLOUR_COUNT); - } - - if (COLOUR_TRIAD) { mag_setc("contour_shade_colour_direction", COLOUR_TRIAD); } - - // Adjust Set The page slightly to fit the legend - mag_setr("subpage_x_length", 24.); - mag_setr("subpage_y_length", 30.); - - // Legend Settings - mag_setc("legend", "on"); - mag_setc("legend_display_type", "continuous"); - mag_setc("legend_entry_plot_direction", "column"); - mag_setc("legend_box_mode", "positional"); - mag_setr("legend_box_x_position", 26.5); - mag_setr("legend_box_y_position", 0.39); - mag_setr("legend_box_x_length", 2.0); - mag_setr("legend_box_y_length", 12.69); - - if (DBG) - { - mag_enqc("output_name", (char *) &tempname); - fprintf(stderr, " SHADED Done %s!\n", tempname); - fprintf(stderr, " SHADED Done!\n"); - } - } - else if (operatorID == CONTOUR) - { - mag_setc("contour", "on"); - mag_setc("contour_shade", "off"); - mag_setc("contour_label", "on"); - mag_setc("contour_highlight", "off"); - - if (LAT_MIN < 1.0e+200) mag_setr("subpage_lower_left_latitude", LAT_MIN); - if (LON_MIN < 1.0e+200) mag_setr("subpage_lower_left_longitude", LON_MIN); - if (LAT_MAX > -1.0e+200) mag_setr("subpage_upper_right_latitude", LAT_MAX); - if (LON_MAX > -1.0e+200) mag_setr("subpage_upper_right_longitude", LON_MAX); - - if (YMIN < 1.0e+200) mag_setr("contour_min_level", YMIN); - if (YMAX > -1.0e+200) mag_setr("contour_max_level", YMAX); - - if (COLOUR) mag_setc("contour_line_colour", COLOUR); - - if (is_not_equal(INTERVAL, 8.0f)) - { - mag_setc("contour_level_selection_type", "INTERVAL"); - mag_setr("contour_interval", INTERVAL); - } - - if (COUNT != 10) - { - mag_setc("contour_level_selection_type", "COUNT"); - mag_seti("contour_level_count", COUNT); - } - - if (NUM_LEVELS) - { - mag_setc("contour_level_selection_type", "LEVEL_LIST"); - mag_set1r("contour_level_list", LEV_LIST, NUM_LEVELS); - } - - if (THICKNESS != 1) mag_seti("contour_line_thickness", THICKNESS); - - if (STYLE) mag_setc("contour_line_style", STYLE); - - // Adjust Set The page slightly to fit the legend - mag_setr("subpage_x_length", 24.); - mag_setr("subpage_y_length", 30.); - - if (DBG) fprintf(stderr, " CONTOUR Done!\n"); - } - else if (operatorID == GRFILL) - { - mag_setc("contour", "off"); - mag_setc("contour_shade", "on"); - - // mag_setc ( "contour_shade_technique", "cell_shading" ); - mag_setc("contour_shade_technique", "grid_shading"); - - mag_setc("contour_shade_method", "area_fill"); - mag_setc("contour_label", "off"); - - if (LAT_MIN < 1.0e+200) mag_setr("subpage_lower_left_latitude", LAT_MIN); - if (LON_MIN < 1.0e+200) mag_setr("subpage_lower_left_longitude", LON_MIN); - if (LAT_MAX > -1.0e+200) mag_setr("subpage_upper_right_latitude", LAT_MAX); - if (LON_MAX > -1.0e+200) mag_setr("subpage_upper_right_longitude", LON_MAX); - - if (YMIN < 1.0e+200) - { - mag_setr("contour_shade_min_level", YMIN); - mag_setr("contour_min_level", YMIN); - } - - if (YMAX > -1.0e+200) - { - mag_setr("contour_shade_max_level", YMAX); - mag_setr("contour_max_level", YMAX); - } - - // if( YMIN < 1.0e+200 ) mag_setr( "contour_shade_min_level", YMIN ); - // if( YMAX > -1.0e+200 ) mag_setr( "contour_shade_max_level", YMAX ); - - if (COLOUR_MIN) mag_setc("contour_shade_min_level_colour", COLOUR_MIN); - if (COLOUR_MAX) mag_setc("contour_shade_max_level_colour", COLOUR_MAX); - - if (is_not_equal(INTERVAL, 8.0f)) - { - mag_setc("contour_level_selection_type", "INTERVAL"); - mag_setr("contour_interval", INTERVAL); - } - - if (COUNT != 10) - { - mag_setc("contour_level_selection_type", "COUNT"); - mag_seti("contour_level_count", COUNT); - } - - if (NUM_LEVELS) - { - mag_setc("contour_level_selection_type", "LEVEL_LIST"); - mag_set1r("contour_level_list", LEV_LIST, NUM_LEVELS); - } - - if (USR_COLOUR_COUNT) - { - mag_setc("contour_shade_colour_method", "LIST"); - mag_set1c("contour_shade_colour_list", (const char **) USR_COLOUR_TABLE, USR_COLOUR_COUNT); - } - /* - if( is_not_equal(RESOLUTION, 10.0f) ) - mag_setr( "contour_shade_cell_resolution", RESOLUTION ); - */ - if (COLOUR_TRIAD) mag_setc("contour_shade_colour_direction", COLOUR_TRIAD); - - // Adjust Set The page slightly to fit the legend - mag_setr("subpage_x_length", 24.); - mag_setr("subpage_y_length", 30.); - - // Legend Settings - mag_setc("legend", "on"); - mag_setc("legend_display_type", "continuous"); - mag_setc("legend_entry_plot_direction", "column"); - mag_setc("legend_box_mode", "positional"); - mag_setr("legend_box_x_position", 26.5); - mag_setr("legend_box_y_position", 0.39); - mag_setr("legend_box_x_length", 2.0); - mag_setr("legend_box_y_length", 12.69); - - if (DBG) fprintf(stderr, " GrFILL Done!\n"); - } - - // plot the title text and the coastlines - mag_cont(); - mag_coast(); - - mag_set1c("text_lines", (const char **) &titlename, 1); - mag_setc("text_colour", "black"); - - /* - mag_setr("text_font_size", 0.6); - mag_setc("text_mode", "positional"); - mag_setr("text_box_x_position", 1.5); - mag_setr("text_box_y_position", 16.5); - mag_setr("text_box_x_length", 20.); - mag_setr("text_box_y_length", 2.5); - mag_setc("text_border", "off"); - */ - - mag_setc("text_justification", "left"); - mag_text(); - - if (LEV_LIST) free(LEV_LIST); -} - static void init_MAGICS() { @@ -530,220 +186,6 @@ quit_MAGICS() if (DBG) fprintf(stderr, "Exiting From MAGICS\n"); } -static void -verifyPlotParameters(int num_param, const std::vector<std::string> ¶m_names, int opID) -{ - bool halt_flag = false; - int param_count = 0; - const char **params = nullptr; - char *temp_str; - const char orig_char = ';', rep_char = ','; - - /* - char *contour_params[] = {"ymin","ymax","count","interval","list","colour","thickness","style"}; - char *shaded_params[] = {"ymin","ymax","count","interval","list","colour_min","colour_max","colour_table","step_freq"}; - char *grfill_params[] = {"ymin","ymax","count","interval","list","colour_min","colour_max","colour_table","resolution"}; - */ - - for (int i = 0; i < num_param; ++i) - { - auto found = false; - auto syntax = true; - const auto splitStrings = split_with_seperator(param_names[i], '='); - - if (DBG) fprintf(stderr, "Verifying params!\n"); - - if (splitStrings.size() > 1) - { - const auto &key = splitStrings[0]; - auto value = strdup(splitStrings[1].c_str()); - - if (opID == CONTOUR) - { - param_count = contour_param_count; - params = contour_params; - } - else if (opID == SHADED) - { - param_count = shaded_param_count; - params = shaded_params; - } - else if (opID == GRFILL) - { - param_count = grfill_param_count; - params = grfill_params; - } - - for (int j = 0; j < param_count; ++j) - { - if (key == params[j]) - { - found = true; - if (key == "colour" || key == "style" || key == "colour_min" || key == "colour_max" || key == "RGB" - || key == "colour_triad" || key == "device" || key == "file_split" || key == "projection") - { - if (string_is_float(value)) { syntax = false; } - else - { - if (key == "RGB" || key == "file_split") - { - temp_str = strdup(value); - cstr_to_lower(temp_str); - if (strcmp(temp_str, "true") && strcmp(temp_str, "false")) { syntax = false; } - else - { - if (key == "RGB") - isRGB = cdo_cmpstr(temp_str, "true"); - else if (key == "file_split") - FILE_SPLIT = cdo_cmpstr(temp_str, "true"); - } - } - else if (key == "style") - { - if (checkstyle(value)) syntax = false; - } - else if (key == "colour" || key == "colour_min" || key == "colour_max") - { - - if (checkcolour(value)) { syntax = false; } - else - { - if (key == "colour") - { - temp_str = strdup(value); - if (!isRGB) - cstr_to_lower(temp_str); - else - { - cstr_to_upper(temp_str); - cstr_replace_char(temp_str, orig_char, rep_char); // replace ';' in RGB format to ',' - } - COLOUR = temp_str; - if (DBG) fprintf(stderr, "COLOUR %s\n", COLOUR); - } - if (key == "colour_min") - { - temp_str = strdup(value); - if (!isRGB) - cstr_to_lower(temp_str); - else - { - cstr_to_upper(temp_str); - cstr_replace_char(temp_str, orig_char, rep_char); // replace ';' in RGB format to ',' - } - COLOUR_MIN = temp_str; - if (DBG) fprintf(stderr, "COLOUR %s\n", COLOUR_MIN); - } - if (key == "colour_max") - { - temp_str = strdup(value); - if (!isRGB) - cstr_to_lower(temp_str); - else - { - cstr_to_upper(temp_str); - cstr_replace_char(temp_str, orig_char, rep_char); // replace ';' in RGB format to ',' - } - COLOUR_MAX = temp_str; - if (DBG) fprintf(stderr, "COLOUR %s\n", COLOUR_MAX); - } - } - } - else if (key == "device") - { - if (checkdevice(value)) syntax = false; - } - else if (key == "colour_triad") - { - temp_str = strdup(value); - cstr_to_upper(temp_str); - if (strcmp(temp_str, "CW") && strcmp(temp_str, "ACW")) - syntax = false; - else - { - if (DBG) fprintf(stderr, "TRIAD check %s!\n", temp_str); - COLOUR_TRIAD = cdo_cmpstr(temp_str, "CW") ? "clockwise" : "anti_clockwise"; - } - } - else if (key == "projection") - { - if (checkprojection(value)) syntax = false; - } - } - } - - if (key == "min" || key == "max" || key == "lat_min" || key == "lat_max" || key == "lon_min" || key == "lon_max" - || key == "count" || key == "interval" || key == "thickness" || key == "resolution" || key == "step_freq") - { - if (!string_is_float(value)) - syntax = false; - else - { - if (key == "min") YMIN = atof(value); - if (key == "max") YMAX = atof(value); - if (key == "count") COUNT = atoi(value); - if (key == "interval") INTERVAL = atof(value); - if (key == "thickness") THICKNESS = atoi(value); - if (key == "resolution") RESOLUTION = atoi(value); - if (key == "step_freq") STEP_FREQ = atoi(value); - if (key == "lat_min") LAT_MIN = atof(value); - if (key == "lat_max") LAT_MAX = atof(value); - if (key == "lon_min") LON_MIN = atof(value); - if (key == "lon_max") LON_MAX = atof(value); - } - } - - if (key == "colour_table") - { - auto fp = std::fopen(value, "r"); - if (fp == nullptr) - { - fprintf(stderr, "Input Color Table File not found in specified path '%s'\n", value); - halt_flag = true; - } - else { ReadColourTable(value); } - } - - if (key == "list") - { - const auto splitStrings2 = split_with_seperator(value, ';'); - if (!splitStrings2.size()) { syntax = false; } - else - { - for (size_t k = 0, n = splitStrings2.size(); k < n; ++k) - { - if (!string_is_float(splitStrings2[k])) syntax = false; - } - if (syntax == true) - { - NUM_LEVELS = (int) splitStrings2.size(); - LEV_LIST = (double *) malloc(NUM_LEVELS * sizeof(double)); - for (int k = 0; k < NUM_LEVELS; ++k) LEV_LIST[k] = std::stof(splitStrings2[k]); - } - } - } - } /*** if(key == params[j]) ***/ - } /*** Loop over param count ***/ - - // if (value) free(value); // value is use e.g. for DEVICE - } /*** (splitStrings.size() > 1) ***/ - else { syntax = false; } - - if (!found) - { - halt_flag = true; - fprintf(stderr, "Invalid parameter '%s'\n", param_names[i].c_str()); - } - if (found && syntax == false) - { - halt_flag = true; - fprintf(stderr, "Invalid parameter specification '%s'\n", param_names[i].c_str()); - } - } /*** Loop over params ****/ - - if (halt_flag) exit(0); -} - int checkcolour(char *colour_in) { @@ -960,8 +402,22 @@ checkprojection(char *projection_in) } #endif -class ModuleMagplot +class Magplot : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Magplot", + .operators = { { "contour", MagplotHelp }, + { "shaded", MagplotHelp }, + { "grfill", MagplotHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Magplot> registration = RegisterEntry<Magplot>(module); + int CONTOUR, SHADED, GRFILL; CdoStreamID streamID; int operatorID; @@ -984,21 +440,579 @@ class ModuleMagplot Varray<double> array; - int CONTOUR, SHADED, GRFILL; +#ifdef HAVE_LIBMAGICS + void + verifyPlotParameters(int num_param, const std::vector<std::string> ¶m_names, int opID) + { + bool halt_flag = false; + int param_count = 0; + const char **params = nullptr; + char *temp_str; + const char orig_char = ';', rep_char = ','; + + /* + char *contour_params[] = {"ymin","ymax","count","interval","list","colour","thickness","style"}; + char *shaded_params[] = {"ymin","ymax","count","interval","list","colour_min","colour_max","colour_table","step_freq"}; + char *grfill_params[] = {"ymin","ymax","count","interval","list","colour_min","colour_max","colour_table","resolution"}; + */ + + for (int i = 0; i < num_param; ++i) + { + auto found = false; + auto syntax = true; + const auto splitStrings = split_with_seperator(param_names[i], '='); + + if (DBG) fprintf(stderr, "Verifying params!\n"); + + if (splitStrings.size() > 1) + { + const auto &key = splitStrings[0]; + auto value = strdup(splitStrings[1].c_str()); + + if (opID == CONTOUR) + { + param_count = contour_param_count; + params = contour_params; + } + else if (opID == SHADED) + { + param_count = shaded_param_count; + params = shaded_params; + } + else if (opID == GRFILL) + { + param_count = grfill_param_count; + params = grfill_params; + } + + for (int j = 0; j < param_count; ++j) + { + if (key == params[j]) + { + found = true; + if (key == "colour" || key == "style" || key == "colour_min" || key == "colour_max" || key == "RGB" + || key == "colour_triad" || key == "device" || key == "file_split" || key == "projection") + { + if (string_is_float(value)) { syntax = false; } + else + { + if (key == "RGB" || key == "file_split") + { + temp_str = strdup(value); + cstr_to_lower(temp_str); + if (strcmp(temp_str, "true") && strcmp(temp_str, "false")) { syntax = false; } + else + { + if (key == "RGB") + isRGB = cdo_cmpstr(temp_str, "true"); + else if (key == "file_split") + FILE_SPLIT = cdo_cmpstr(temp_str, "true"); + } + } + else if (key == "style") + { + if (checkstyle(value)) syntax = false; + } + else if (key == "colour" || key == "colour_min" || key == "colour_max") + { + + if (checkcolour(value)) { syntax = false; } + else + { + if (key == "colour") + { + temp_str = strdup(value); + if (!isRGB) + cstr_to_lower(temp_str); + else + { + cstr_to_upper(temp_str); + cstr_replace_char(temp_str, orig_char, rep_char); // replace ';' in RGB format to ',' + } + COLOUR = temp_str; + if (DBG) fprintf(stderr, "COLOUR %s\n", COLOUR); + } + if (key == "colour_min") + { + temp_str = strdup(value); + if (!isRGB) + cstr_to_lower(temp_str); + else + { + cstr_to_upper(temp_str); + cstr_replace_char(temp_str, orig_char, rep_char); // replace ';' in RGB format to ',' + } + COLOUR_MIN = temp_str; + if (DBG) fprintf(stderr, "COLOUR %s\n", COLOUR_MIN); + } + if (key == "colour_max") + { + temp_str = strdup(value); + if (!isRGB) + cstr_to_lower(temp_str); + else + { + cstr_to_upper(temp_str); + cstr_replace_char(temp_str, orig_char, rep_char); // replace ';' in RGB format to ',' + } + COLOUR_MAX = temp_str; + if (DBG) fprintf(stderr, "COLOUR %s\n", COLOUR_MAX); + } + } + } + else if (key == "device") + { + if (checkdevice(value)) syntax = false; + } + else if (key == "colour_triad") + { + temp_str = strdup(value); + cstr_to_upper(temp_str); + if (strcmp(temp_str, "CW") && strcmp(temp_str, "ACW")) + syntax = false; + else + { + if (DBG) fprintf(stderr, "TRIAD check %s!\n", temp_str); + COLOUR_TRIAD = cdo_cmpstr(temp_str, "CW") ? "clockwise" : "anti_clockwise"; + } + } + else if (key == "projection") + { + if (checkprojection(value)) syntax = false; + } + } + } + + if (key == "min" || key == "max" || key == "lat_min" || key == "lat_max" || key == "lon_min" || key == "lon_max" + || key == "count" || key == "interval" || key == "thickness" || key == "resolution" || key == "step_freq") + { + if (!string_is_float(value)) + syntax = false; + else + { + if (key == "min") YMIN = atof(value); + if (key == "max") YMAX = atof(value); + if (key == "count") COUNT = atoi(value); + if (key == "interval") INTERVAL = atof(value); + if (key == "thickness") THICKNESS = atoi(value); + if (key == "resolution") RESOLUTION = atoi(value); + if (key == "step_freq") STEP_FREQ = atoi(value); + if (key == "lat_min") LAT_MIN = atof(value); + if (key == "lat_max") LAT_MAX = atof(value); + if (key == "lon_min") LON_MIN = atof(value); + if (key == "lon_max") LON_MAX = atof(value); + } + } + + if (key == "colour_table") + { + auto fp = std::fopen(value, "r"); + if (fp == nullptr) + { + fprintf(stderr, "Input Color Table File not found in specified path '%s'\n", value); + halt_flag = true; + } + else { ReadColourTable(value); } + } + + if (key == "list") + { + const auto splitStrings2 = split_with_seperator(value, ';'); + if (!splitStrings2.size()) { syntax = false; } + else + { + for (size_t k = 0, n = splitStrings2.size(); k < n; ++k) + { + if (!string_is_float(splitStrings2[k])) syntax = false; + } + if (syntax == true) + { + NUM_LEVELS = (int) splitStrings2.size(); + LEV_LIST = (double *) malloc(NUM_LEVELS * sizeof(double)); + for (int k = 0; k < NUM_LEVELS; ++k) LEV_LIST[k] = std::stof(splitStrings2[k]); + } + } + } + } /*** if(key == params[j]) ***/ + } /*** Loop over param count ***/ + + // if (value) free(value); // value is use e.g. for DEVICE + } /*** (splitStrings.size() > 1) ***/ + else { syntax = false; } + + if (!found) + { + halt_flag = true; + fprintf(stderr, "Invalid parameter '%s'\n", param_names[i].c_str()); + } + if (found && syntax == false) + { + halt_flag = true; + fprintf(stderr, "Invalid parameter specification '%s'\n", param_names[i].c_str()); + } + } /*** Loop over params ****/ + + if (halt_flag) exit(0); + } +#endif + +#ifdef HAVE_LIBMAGICS + void + magplot(const char *plotfile, int p_operatorID, const std::string &varname, const std::string &units, long p_nlon, long p_nlat, + Varray<double> &p_grid_center_lon, Varray<double> &p_grid_center_lat, Varray<double> &p_array, size_t numMissVals, + double missval, int p_nparam, const std::vector<std::string> ¶ms, const std::string &datetimeStr, bool p_lregular) + + { + double dlon = 0, dlat = 0; + char plotfilename[4096]; + char *titlename; + char tempname[256]; + + if (DBG) + { + fprintf(stderr, "Num params %d\n", p_nparam); + + for (int i = 0; i < p_nparam; ++i) fprintf(stderr, "Param %s\n", params[i].c_str()); + fflush(stderr); + + for (int i = 0; i < p_nparam; ++i) + { + const auto splitStrings = split_with_seperator(params[i], '='); + const auto &key = splitStrings[0]; + + if (key == "min") fprintf(stderr, "Min Val %g\n", YMIN); + if (key == "max") fprintf(stderr, "Max Val %g\n", YMAX); + // if (key == "resolution") fprintf(stderr,"RESOLUTION %g\n",RESOLUTION ); + if (key == "colour") fprintf(stderr, "COLOUR %s\n", COLOUR); + if (key == "colour_min") fprintf(stderr, "COLOUR %s\n", COLOUR_MIN); + if (key == "colour_max") fprintf(stderr, "COLOUR %s\n", COLOUR_MAX); + if (key == "interval") fprintf(stderr, "INTERVAL %f\n", INTERVAL); + if (key == "count") fprintf(stderr, "COUNT %d\n", COUNT); + + if (key == "list") + for (int j = 0; j < NUM_LEVELS; ++j) fprintf(stderr, "LIST %f\n", LEV_LIST[j]); + + if (key == "thickness") fprintf(stderr, "THICKNESS %d\n", THICKNESS); + if (key == "style") fprintf(stderr, "STYLE %s\n", STYLE); + if (key == "device") fprintf(stderr, "DEVICE %s\n", DEVICE); + if (key == "step_freq") fprintf(stderr, "STEP_FREQ %d\n", STEP_FREQ); + if (key == "lat_min") fprintf(stderr, "Lat Min Val %g\n", LAT_MIN); + if (key == "lat_max") fprintf(stderr, "Lat Max Val %g\n", LAT_MAX); + if (key == "lon_min") fprintf(stderr, "Lon Min Val %g\n", LON_MIN); + if (key == "lon_max") fprintf(stderr, "Lon Max Val %g\n", LON_MAX); + if (key == "projection") fprintf(stderr, "PROJECTION %s\n", PROJECTION); + } + } + + if (p_lregular) + { + if (p_nlon > 1) + { + for (int i = 1; i < p_nlon; ++i) dlon += (p_grid_center_lon[i] - p_grid_center_lon[i - 1]); + dlon /= (p_nlon - 1); + } + if (p_nlat > 1) + { + for (int i = 1; i < p_nlat; ++i) dlat += (p_grid_center_lat[p_nlon * i] - p_grid_center_lat[p_nlon * (i - 1)]); + dlat /= (p_nlat - 1); + } + } + + std::snprintf(plotfilename, sizeof(plotfilename), "%s [%s] %s", varname.c_str(), units.c_str(), datetimeStr.c_str()); + titlename = strdup(plotfilename); + std::snprintf(plotfilename, sizeof(plotfilename), "%s_%s", plotfile, varname.c_str()); + + if (Options::cdoVerbose) cdo_print("p_nlon: %zu p_nlat: %zu", p_nlon, p_nlat); + if (Options::cdoVerbose) cdo_print("dlon: %g dlat: %g", dlon, dlat); + + auto mm = numMissVals ? varray_min_max_mv(p_nlon * p_nlat, p_array, missval) : varray_min_max(p_nlon * p_nlat, p_array); + + if (Options::cdoVerbose) cdo_print("min: %g max: %g", mm.min, mm.max); + if (Options::cdoVerbose) cdo_print("input_field_organization: %s", p_lregular ? "REGULAR" : "NONREGULAR"); + + mag_setc("output_name", plotfilename); + mag_new("page"); + + // Set the input data arrays to magics++ + + mag_set2r("input_field", p_array.data(), p_nlon, p_nlat); + + mag_setr("input_field_suppress_below", mm.min); + mag_setr("input_field_suppress_above", mm.max); + + if (lregular) + { + mag_setc("input_field_organization", "REGULAR"); + // mag_setc("input_field_organization", "GAUSSIAN"); + + mag_setr("input_field_initial_latitude", p_grid_center_lat[0]); + mag_setr("input_field_latitude_step", dlat); + + mag_setr("input_field_initial_longitude", p_grid_center_lon[0]); + mag_setr("input_field_longitude_step", dlon); + } + else + { + mag_setc("input_field_organization", "NONREGULAR"); + + mag_set2r("input_field_latitudes", p_grid_center_lat.data(), p_nlon, p_nlat); + mag_set2r("input_field_longitudes", p_grid_center_lon.data(), p_nlon, p_nlat); + } + + /* magics_template_parser( magics_node ); */ + /* results_template_parser(results_node, varname.c_str() ); */ + + /* set up the coastline attributes */ + /* mag_setc ("map_coastline_colour", "khaki"); */ + /* mag_setc ("map_grid_colour", "grey"); */ + + // Parameters common to all operators + if (DEVICE) mag_setc("output_format", DEVICE); + + if (PROJECTION) mag_setc("subpage_map_projection", PROJECTION); + + mag_seti("map_label_latitude_frequency", 2); + mag_seti("map_label_longitude_frequency", 2); + /*mag_setr ("map_label_height",0.5);*/ + mag_setr("map_label_height", 0.4); + + /* define the contouring parameters */ + if (p_operatorID == SHADED) + { + mag_setc("contour", "off"); + mag_setc("contour_shade", "on"); + mag_setc("contour_shade_method", "area_fill"); + mag_setc("contour_label", "off"); + + if (LAT_MIN < 1.0e+200) mag_setr("subpage_lower_left_latitude", LAT_MIN); + if (LON_MIN < 1.0e+200) mag_setr("subpage_lower_left_longitude", LON_MIN); + if (LAT_MAX > -1.0e+200) mag_setr("subpage_upper_right_latitude", LAT_MAX); + if (LON_MAX > -1.0e+200) mag_setr("subpage_upper_right_longitude", LON_MAX); + + if (YMIN < 1.0e+200) + { + mag_setr("contour_shade_min_level", YMIN); + mag_setr("contour_min_level", YMIN); + } + + if (YMAX > -1.0e+200) + { + mag_setr("contour_shade_max_level", YMAX); + mag_setr("contour_max_level", YMAX); + } + + if (COLOUR_MAX) mag_setc("contour_shade_max_level_colour", COLOUR_MAX); + if (COLOUR_MIN) mag_setc("contour_shade_min_level_colour", COLOUR_MIN); + + if (is_not_equal(INTERVAL, 8.0f)) + { + mag_setc("contour_level_selection_type", "INTERVAL"); + mag_setr("contour_interval", INTERVAL); + } + + if (COUNT != 10) + { + mag_setc("contour_level_selection_type", "COUNT"); + mag_seti("contour_level_count", COUNT); + } + + if (NUM_LEVELS) + { + mag_setc("contour_level_selection_type", "LEVEL_LIST"); + mag_set1r("contour_level_list", LEV_LIST, NUM_LEVELS); + } + + if (USR_COLOUR_COUNT) + { + mag_setc("contour_shade_colour_method", "LIST"); + mag_set1c("contour_shade_colour_list", (const char **) USR_COLOUR_TABLE, USR_COLOUR_COUNT); + } + + if (COLOUR_TRIAD) { mag_setc("contour_shade_colour_direction", COLOUR_TRIAD); } + + // Adjust Set The page slightly to fit the legend + mag_setr("subpage_x_length", 24.); + mag_setr("subpage_y_length", 30.); + + // Legend Settings + mag_setc("legend", "on"); + mag_setc("legend_display_type", "continuous"); + mag_setc("legend_entry_plot_direction", "column"); + mag_setc("legend_box_mode", "positional"); + mag_setr("legend_box_x_position", 26.5); + mag_setr("legend_box_y_position", 0.39); + mag_setr("legend_box_x_length", 2.0); + mag_setr("legend_box_y_length", 12.69); + + if (DBG) + { + mag_enqc("output_name", (char *) &tempname); + fprintf(stderr, " SHADED Done %s!\n", tempname); + fprintf(stderr, " SHADED Done!\n"); + } + } + else if (p_operatorID == CONTOUR) + { + mag_setc("contour", "on"); + mag_setc("contour_shade", "off"); + mag_setc("contour_label", "on"); + mag_setc("contour_highlight", "off"); + + if (LAT_MIN < 1.0e+200) mag_setr("subpage_lower_left_latitude", LAT_MIN); + if (LON_MIN < 1.0e+200) mag_setr("subpage_lower_left_longitude", LON_MIN); + if (LAT_MAX > -1.0e+200) mag_setr("subpage_upper_right_latitude", LAT_MAX); + if (LON_MAX > -1.0e+200) mag_setr("subpage_upper_right_longitude", LON_MAX); + + if (YMIN < 1.0e+200) mag_setr("contour_min_level", YMIN); + if (YMAX > -1.0e+200) mag_setr("contour_max_level", YMAX); + + if (COLOUR) mag_setc("contour_line_colour", COLOUR); + + if (is_not_equal(INTERVAL, 8.0f)) + { + mag_setc("contour_level_selection_type", "INTERVAL"); + mag_setr("contour_interval", INTERVAL); + } + + if (COUNT != 10) + { + mag_setc("contour_level_selection_type", "COUNT"); + mag_seti("contour_level_count", COUNT); + } + + if (NUM_LEVELS) + { + mag_setc("contour_level_selection_type", "LEVEL_LIST"); + mag_set1r("contour_level_list", LEV_LIST, NUM_LEVELS); + } + + if (THICKNESS != 1) mag_seti("contour_line_thickness", THICKNESS); + + if (STYLE) mag_setc("contour_line_style", STYLE); + + // Adjust Set The page slightly to fit the legend + mag_setr("subpage_x_length", 24.); + mag_setr("subpage_y_length", 30.); + + if (DBG) fprintf(stderr, " CONTOUR Done!\n"); + } + else if (p_operatorID == GRFILL) + { + mag_setc("contour", "off"); + mag_setc("contour_shade", "on"); + + // mag_setc ( "contour_shade_technique", "cell_shading" ); + mag_setc("contour_shade_technique", "grid_shading"); + + mag_setc("contour_shade_method", "area_fill"); + mag_setc("contour_label", "off"); + + if (LAT_MIN < 1.0e+200) mag_setr("subpage_lower_left_latitude", LAT_MIN); + if (LON_MIN < 1.0e+200) mag_setr("subpage_lower_left_longitude", LON_MIN); + if (LAT_MAX > -1.0e+200) mag_setr("subpage_upper_right_latitude", LAT_MAX); + if (LON_MAX > -1.0e+200) mag_setr("subpage_upper_right_longitude", LON_MAX); + + if (YMIN < 1.0e+200) + { + mag_setr("contour_shade_min_level", YMIN); + mag_setr("contour_min_level", YMIN); + } + + if (YMAX > -1.0e+200) + { + mag_setr("contour_shade_max_level", YMAX); + mag_setr("contour_max_level", YMAX); + } + + // if( YMIN < 1.0e+200 ) mag_setr( "contour_shade_min_level", YMIN ); + // if( YMAX > -1.0e+200 ) mag_setr( "contour_shade_max_level", YMAX ); + + if (COLOUR_MIN) mag_setc("contour_shade_min_level_colour", COLOUR_MIN); + if (COLOUR_MAX) mag_setc("contour_shade_max_level_colour", COLOUR_MAX); + + if (is_not_equal(INTERVAL, 8.0f)) + { + mag_setc("contour_level_selection_type", "INTERVAL"); + mag_setr("contour_interval", INTERVAL); + } + + if (COUNT != 10) + { + mag_setc("contour_level_selection_type", "COUNT"); + mag_seti("contour_level_count", COUNT); + } + + if (NUM_LEVELS) + { + mag_setc("contour_level_selection_type", "LEVEL_LIST"); + mag_set1r("contour_level_list", LEV_LIST, NUM_LEVELS); + } + + if (USR_COLOUR_COUNT) + { + mag_setc("contour_shade_colour_method", "LIST"); + mag_set1c("contour_shade_colour_list", (const char **) USR_COLOUR_TABLE, USR_COLOUR_COUNT); + } + /* + if( is_not_equal(RESOLUTION, 10.0f) ) + mag_setr( "contour_shade_cell_resolution", RESOLUTION ); + */ + if (COLOUR_TRIAD) mag_setc("contour_shade_colour_direction", COLOUR_TRIAD); + + // Adjust Set The page slightly to fit the legend + mag_setr("subpage_x_length", 24.); + mag_setr("subpage_y_length", 30.); + + // Legend Settings + mag_setc("legend", "on"); + mag_setc("legend_display_type", "continuous"); + mag_setc("legend_entry_plot_direction", "column"); + mag_setc("legend_box_mode", "positional"); + mag_setr("legend_box_x_position", 26.5); + mag_setr("legend_box_y_position", 0.39); + mag_setr("legend_box_x_length", 2.0); + mag_setr("legend_box_y_length", 12.69); + + if (DBG) fprintf(stderr, " GrFILL Done!\n"); + } + + // plot the title text and the coastlines + mag_cont(); + mag_coast(); + + mag_set1c("text_lines", (const char **) &titlename, 1); + mag_setc("text_colour", "black"); + + /* + mag_setr("text_font_size", 0.6); + mag_setc("text_mode", "positional"); + mag_setr("text_box_x_position", 1.5); + mag_setr("text_box_y_position", 16.5); + mag_setr("text_box_x_length", 20.); + mag_setr("text_box_y_length", 2.5); + mag_setc("text_border", "off"); + */ + + mag_setc("text_justification", "left"); + mag_text(); + + if (LEV_LIST) free(LEV_LIST); + } + +#endif public: void - init(void *process) + init() { - cdo_initialize(process); #ifdef HAVE_LIBMAGICS nparam = cdo_operator_argc(); pnames = cdo_get_oper_argv(); - CONTOUR = cdo_operator_add("contour", 0, 0, nullptr); - SHADED = cdo_operator_add("shaded", 0, 0, nullptr); - GRFILL = cdo_operator_add("grfill", 0, 0, nullptr); + CONTOUR = module.get_id("contour"); + SHADED = module.get_id("shaded"); + GRFILL = module.get_id("grfill"); operatorID = cdo_operator_id(); @@ -1109,11 +1123,11 @@ public: { int varID, levelID; cdo_inq_record(streamID, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID, array.data(), &numMissVals); const auto missval = vlistInqVarMissval(vlistID, varID); - if (nmiss) cdo_set_nan(missval, gridsize, array.data()); + if (numMissVals) cdo_set_nan(missval, gridsize, array.data()); auto varname = cdo::inq_var_name(vlistID, varID); auto units = cdo::inq_var_units(vlistID, varID); @@ -1131,7 +1145,7 @@ public: if (DBG) fprintf(stderr, "Plot %d\n", varID); magplot(cdo_get_stream_name(1), operatorID, varname, units, nlon, nlat, grid_center_lon, grid_center_lat, array, - nmiss, missval, nparam, pnames, datetimeStr, lregular); + numMissVals, missval, nparam, pnames, datetimeStr, lregular); } else fprintf(stderr, "operator not implemented\n"); @@ -1175,18 +1189,5 @@ public: // quit_XML_template_parser( ); #endif - - cdo_finish(); } }; - -void * -Magplot(void *process) -{ - ModuleMagplot magplot; - magplot.init(process); - magplot.run(); - magplot.close(); - - return nullptr; -} diff --git a/src/Magvector.cc b/src/Magvector.cc index 6399f5376e8e89ce5db6c9831a691d9ae12f2aad..dc02af294a8cb9f846a8fac36b527b1888cb2f27 100644 --- a/src/Magvector.cc +++ b/src/Magvector.cc @@ -25,7 +25,6 @@ #define DBG 0 -int VECTOR, STREAM; const char *vector_params[] = { "thin_fac", "unit_vec", "device", "step_freq" }; int vector_param_count = sizeof(vector_params) / sizeof(char *); @@ -38,9 +37,31 @@ int checkdevice(char *device_in); extern const char *DEVICE; static void -magvector(const char *plotfile, int operatorID, long nlon, long nlat, Varray<double> &grid_center_lon, - Varray<double> &grid_center_lat, Varray<double> &uarray, Varray<double> &varray, int nparam, - std::vector<std::string> ¶ms, const std::string &datetimeStr) +init_MAGICS() + +{ + + setenv("MAGPLUS_QUIET", "1", 1); /* To suppress magics messages */ + mag_open(); + + /* Some standard parameters affectng the magics environment, moved from the xml file ** begin ** */ + mag_setc("page_id_line", "off"); +} + +static void +quit_MAGICS() +{ + mag_close(); + if (DBG) fprintf(stdout, "Exiting From MAGICS\n"); +} + +#endif + +#ifdef HAVE_LIBMAGICS +void +magvector(const char *plotfile, long nlon, long nlat, Varray<double> &grid_center_lon, Varray<double> &grid_center_lat, + Varray<double> &uarray, Varray<double> &varray, int nparam, std::vector<std::string> ¶ms, + const std::string &datetimeStr) { long i; @@ -70,7 +91,7 @@ magvector(const char *plotfile, int operatorID, long nlon, long nlat, Varray<dou for (i = 0; i < nparam; ++i) { - const auto splitStrings = split_with_seperator(params[i], '='); + auto splitStrings = split_with_seperator(params[i], '='); const auto &key = splitStrings[0]; const auto &value = splitStrings[1]; @@ -119,9 +140,9 @@ magvector(const char *plotfile, int operatorID, long nlon, long nlat, Varray<dou /* results_template_parser(results_node, varname ); */ - sprintf(plotfilename, "Velocity Vectors %s", datetimeStr.c_str()); + std::snprintf(plotfilename, sizeof(plotfilename), "Velocity Vectors %s", datetimeStr.c_str()); char *titlename = strdup(plotfilename); - sprintf(plotfilename, "%s", plotfile); + std::snprintf(plotfilename, sizeof(plotfilename), "%s", plotfile); mag_setc("output_name", plotfilename); mag_new("page"); @@ -141,56 +162,37 @@ magvector(const char *plotfile, int operatorID, long nlon, long nlat, Varray<dou /*mag_setr ("map_label_height",0.5);*/ mag_setr("map_label_height", 0.4); - if (operatorID == VECTOR) - { - /* Magics functions for performing vector operation */ - /* - mag_setc("wind_legend_only", "on" ); - mag_setc("wind_legend_text", "on" ); - */ + // if (operatorID == VECTOR) + { + /* Magics functions for performing vector operation */ + /* + mag_setc("wind_legend_only", "on" ); + mag_setc("wind_legend_text", "on" ); + */ - mag_setc("legend", "on"); - mag_setc("wind_flag_cross_boundary", "on"); - mag_seti("wind_arrow_thickness", 1); - mag_coast(); + mag_setc("legend", "on"); + mag_setc("wind_flag_cross_boundary", "on"); + mag_seti("wind_arrow_thickness", 1); + mag_coast(); - if (is_not_equal(THIN_FAC, 2.0f)) mag_setr("wind_thinning_factor", THIN_FAC); + if (is_not_equal(THIN_FAC, 2.0f)) mag_setr("wind_thinning_factor", THIN_FAC); - /*wind_arrow_unit_velocity */ - if (is_not_equal(UNIT_VEC, 25.0f)) mag_setr("wind_arrow_unit_velocity", UNIT_VEC); + /*wind_arrow_unit_velocity */ + if (is_not_equal(UNIT_VEC, 25.0f)) mag_setr("wind_arrow_unit_velocity", UNIT_VEC); - mag_wind(); + mag_wind(); - mag_set1c("text_lines", (const char **) &titlename, 1); - mag_setc("text_colour", "black"); - mag_setc("text_justification", "centre"); - mag_text(); - } + mag_set1c("text_lines", (const char **) &titlename, 1); + mag_setc("text_colour", "black"); + mag_setc("text_justification", "centre"); + mag_text(); + } free(titlename); } -static void -init_MAGICS() - -{ - - setenv("MAGPLUS_QUIET", "1", 1); /* To suppress magics messages */ - mag_open(); - - /* Some standard parameters affectng the magics environment, moved from the xml file ** begin ** */ - mag_setc("page_id_line", "off"); -} - -static void -quit_MAGICS() -{ - mag_close(); - if (DBG) fprintf(stdout, "Exiting From MAGICS\n"); -} - -static void -VerifyVectorParameters(int num_param, std::vector<std::string> ¶m_names, int opID) +void +verify_vector_parameters(int num_param, std::vector<std::string> ¶m_names, bool vectorMode) { int i, j; @@ -204,7 +206,7 @@ VerifyVectorParameters(int num_param, std::vector<std::string> ¶m_names, int { auto found = false; auto syntax = true; - const auto splitStrings = split_with_seperator(param_names[i], '='); + auto splitStrings = split_with_seperator(param_names[i], '='); if (DBG) fprintf(stderr, "Verifying params!\n"); @@ -212,7 +214,7 @@ VerifyVectorParameters(int num_param, std::vector<std::string> ¶m_names, int { const auto &key = splitStrings[0]; const auto &value = splitStrings[1]; - if (opID == VECTOR) + if (vectorMode) { param_count = vector_param_count; params = vector_params; @@ -268,10 +270,22 @@ VerifyVectorParameters(int num_param, std::vector<std::string> ¶m_names, int } #endif -class ModuleMagvector +class Magvector : public Process { - CdoStreamID streamID; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Magvector", + .operators = { { "vector", MagvectorHelp }, { "stream", MagvectorHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Magvector> registration = RegisterEntry<Magvector>(module); + int VECTOR, STREAM; + CdoStreamID streamID; int taxisID; int vlistID; int operatorID; @@ -294,16 +308,14 @@ class ModuleMagvector public: void - init(void *process) + init() { - cdo_initialize(process); - #ifdef HAVE_LIBMAGICS nparam = cdo_operator_argc(); pnames = cdo_get_oper_argv(); - VECTOR = cdo_operator_add("vector", 0, 0, nullptr); - STREAM = cdo_operator_add("stream", 0, 0, nullptr); + VECTOR = module.get_id("vector"); + STREAM = module.get_id("stream"); operatorID = cdo_operator_id(); @@ -312,7 +324,7 @@ public: if (DBG) for (int i = 0; i < nparam; ++i) fprintf(stderr, "Param %d is %s!\n", i + 1, pnames[i].c_str()); - VerifyVectorParameters(nparam, pnames, operatorID); + verify_vector_parameters(nparam, pnames, (operatorID == VECTOR)); } streamID = cdo_open_read(0); @@ -355,16 +367,16 @@ public: init_MAGICS(); #endif } + void run() { #ifdef HAVE_LIBMAGICS - int tsID = 0; while (true) { - const auto nrecs = cdo_stream_inq_timestep(streamID, tsID); + auto nrecs = cdo_stream_inq_timestep(streamID, tsID); if (nrecs == 0) break; if (ANIM_FLAG) @@ -384,7 +396,7 @@ public: } } - const auto datetimeStr = datetime_to_string(taxisInqVdatetime(taxisID)); + auto datetimeStr = datetime_to_string(taxisInqVdatetime(taxisID)); for (int recID = 0; recID < nrecs; ++recID) { @@ -398,17 +410,17 @@ public: if (varname == "var131" || varname == "u") // U Velocity as per GRIB is var131, as per NC 'u' { if (DBG) fprintf(stderr, "Found U VEL in Varname %s\n", varname.c_str()); - size_t nmiss; - cdo_read_record(streamID, uarray.data(), &nmiss); - if (nmiss) cdo_set_nan(vlistInqVarMissval(vlistID, varID), gridsize, uarray.data()); + size_t numMissVals; + cdo_read_record(streamID, uarray.data(), &numMissVals); + if (numMissVals) cdo_set_nan(vlistInqVarMissval(vlistID, varID), gridsize, uarray.data()); found++; } if (varname == "var132" || varname == "v") // V Velocity as per GRIB is var132, as per NC 'v' { if (DBG) fprintf(stderr, "Found V VEL in Varname %s\n", varname.c_str()); - size_t nmiss; - cdo_read_record(streamID, varray.data(), &nmiss); - if (nmiss) cdo_set_nan(vlistInqVarMissval(vlistID, varID), gridsize, varray.data()); + size_t numMissVals; + cdo_read_record(streamID, varray.data(), &numMissVals); + if (numMissVals) cdo_set_nan(vlistInqVarMissval(vlistID, varID), gridsize, varray.data()); found++; } if (found == 2) break; @@ -424,8 +436,8 @@ public: if (found == 2) { if (DBG) fprintf(stderr, "Found Both U & V VEL, Creating vector fields! \n"); - magvector(cdo_get_stream_name(1), operatorID, nlon, nlat, grid_center_lon, grid_center_lat, uarray, varray, nparam, - pnames, datetimeStr); + magvector(cdo_get_stream_name(1), nlon, nlat, grid_center_lon, grid_center_lat, uarray, varray, nparam, pnames, + datetimeStr); } else if (found == 1) { @@ -461,22 +473,8 @@ public: { #ifdef HAVE_LIBMAGICS cdo_stream_close(streamID); - /* quit_XML_template_parser( ); */ + // quit_XML_template_parser(); quit_MAGICS(); #endif - - cdo_finish(); } }; - -void * -Magvector(void *process) -{ - - ModuleMagvector magvector; - magvector.init(process); - magvector.run(); - magvector.close(); - - return nullptr; -} diff --git a/src/Makefile.am b/src/Makefile.am index 5424e6273148a1026c63b09c8420808421878d31..642e3a94f2b3e770a72fb0fdfd0e25c150c60d04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,8 +14,6 @@ libcdo_la_SOURCES = after_dvtrans.cc \ cdi_uuid.h \ cdoStream.cc \ cdoStream.h \ - cdo_apply.cc \ - cdo_apply.h \ cdo_cdi_wrapper.cc \ cdo_cdi_wrapper.h \ cdo_cmor.h \ @@ -37,6 +35,8 @@ libcdo_la_SOURCES = after_dvtrans.cc \ cdo_history.h \ cdo_math.cc \ cdo_math.h \ + cdo_module.cc \ + cdo_module.h \ cdo_options.cc \ cdo_options.h \ cdo_output.cc \ @@ -88,7 +88,6 @@ libcdo_la_SOURCES = after_dvtrans.cc \ datarangelist.h \ datetime.cc \ datetime.h \ - dmemory.h \ ecacore.cc \ ecacore.h \ ecautil.cc \ @@ -156,12 +155,8 @@ libcdo_la_SOURCES = after_dvtrans.cc \ matrix_view.h \ merge_axis.cc \ merge_axis.h \ - module_definitions.h \ - module_list.h \ module_info.cc \ module_info.h \ - module_static_maps.h \ - module_static_maps.cc \ modules.cc \ modules.h \ mpim_grid/grid_convert.h \ @@ -182,6 +177,7 @@ libcdo_la_SOURCES = after_dvtrans.cc \ namelist.cc \ namelist.h \ nanoflann.hpp \ + operator_help.cc \ operator_help.h \ par_io.cc \ par_io.h \ @@ -215,8 +211,6 @@ libcdo_la_SOURCES = after_dvtrans.cc \ progress.h \ pthread_debug.cc \ pthread_debug.h \ - readline.cc \ - readline.h \ region.h \ region.cc \ remap.h \ diff --git a/src/MapReduce.cc b/src/MapReduce.cc index 6111c9b68203a770b9bc2342600e2d67a8e9272d..d04ec39af961b249d10f154cb4f4c9478cc36bd4 100644 --- a/src/MapReduce.cc +++ b/src/MapReduce.cc @@ -16,12 +16,12 @@ static void read_first_record(const std::string &filename, double *field) { - size_t nmiss; + size_t numMissVals; int varID, levelID; auto streamID = stream_open_read_locked(filename.c_str()); streamInqTimestep(streamID, 0); streamInqRecord(streamID, &varID, &levelID); - streamReadRecord(streamID, field, &nmiss); + streamReadRecord(streamID, field, &numMissVals); streamClose(streamID); } @@ -39,8 +39,19 @@ countMask(const double *maskField, size_t gridSize, double falseVal) return counter; } -class ModuleMapReduce +class MapReduce : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "MapReduce", + .operators = { { "reducegrid", MapReduceHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<MapReduce> registration = RegisterEntry<MapReduce>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -59,9 +70,8 @@ class ModuleMapReduce public: void - init(void *process) + init() { - cdo_initialize(process); if (cdo_operator_argc() < 1) cdo_abort("Too few arguments!"); @@ -170,8 +180,8 @@ public: auto varID2 = vlistFindVar(vlistID2, varID); auto levelID2 = vlistFindLevel(vlistID2, varID, levelID); - size_t nmiss; - cdo_read_record(streamID1, arrayIn.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, arrayIn.data(), &numMissVals); for (size_t i = 0; i < maskSize; ++i) arrayOut[i] = arrayIn[maskIndexList[i]]; @@ -188,21 +198,9 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; /* * the operators argument has to be a single horizontal field, * non-zero values are used to mark the relevant locations */ -void * -MapReduce(void *process) -{ - ModuleMapReduce mapreduce; - mapreduce.init(process); - mapreduce.run(); - mapreduce.close(); - - return nullptr; -} diff --git a/src/Maskbox.cc b/src/Maskbox.cc index 44be74d5dae6780bd7f7f3179e12afec29ec907e..d2570d0443c51a58f3b5dadabdc1fa1c784975c3 100644 --- a/src/Maskbox.cc +++ b/src/Maskbox.cc @@ -19,7 +19,6 @@ #include "cdo_options.h" #include "process_int.h" -#include "readline.h" #include <mpim_grid.h> #include "selboxinfo.h" #include "util_string.h" @@ -220,8 +219,25 @@ get_processVars(int vlistID1, int gridID) return processVars; } -class ModuleMaskbox +class Maskbox : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Maskbox", + .operators = { { "masklonlatbox", 0, 0, "western and eastern longitude and southern and northern latitude", MaskboxHelp }, + { "maskindexbox", 0, 0, "index of first and last longitude and index of first and last latitude", MaskboxHelp }, + { "maskregion", 0, 0, "DCW region or the path to region file", MaskregionHelp }, + { "maskcircle", 0, 0, "Longitude, latitude of the center and radius of the circle", MaskregionHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Maskbox>(module); + + int MASKLONLATBOX, MASKINDEXBOX, MASKREGION, MASKCIRCLE; + private: CdoStreamID streamID1; CdoStreamID streamID2; @@ -236,16 +252,12 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - auto MASKLONLATBOX = cdo_operator_add("masklonlatbox", 0, 0, "western and eastern longitude and southern and northern latitude"); - auto MASKINDEXBOX = cdo_operator_add("maskindexbox", 0, 0, "index of first and last longitude and index of first and last latitude"); - auto MASKREGION = cdo_operator_add("maskregion", 0, 0, "DCW region or the path to region file"); - auto MASKCIRCLE = cdo_operator_add("maskcircle", 0, 0, "Longitude, latitude of the center and radius of the circle"); - // clang-format on + MASKLONLATBOX = module.get_id("masklonlatbox"); + MASKINDEXBOX = module.get_id("maskindexbox"); + MASKREGION = module.get_id("maskregion"); + MASKCIRCLE = module.get_id("maskcircle"); auto operatorID = cdo_operator_id(); auto operIndexBox = (operatorID == MASKINDEXBOX); @@ -305,9 +317,9 @@ public: for (int i = 0; i < numFiles; ++i) { Regions regions; - auto param = cdo_operator_argv(i).c_str(); - if (std::strncmp(param, "dcw:", 4) == 0) - read_regions_from_dcw(param + 4, regions); + auto param = cdo_operator_argv(i); + if (param.starts_with("dcw:")) + read_regions_from_dcw(param.c_str() + 4, regions); else read_regions_from_file(param, regions); @@ -402,18 +414,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Maskbox(void *process) -{ - ModuleMaskbox maskbox; - maskbox.init(process); - maskbox.run(); - maskbox.close(); - - return nullptr; -} diff --git a/src/Mastrfu.cc b/src/Mastrfu.cc index 7851d4e0b8ce9a66e327b6393259668390dfa67b..5906a494d58259f5ac53b41517dc96abbcb64bc0 100644 --- a/src/Mastrfu.cc +++ b/src/Mastrfu.cc @@ -19,7 +19,7 @@ #include "cdo_zaxis.h" static void -mastrfu(int gridID, int zaxisID, const Varray2D<double> &field1, Varray2D<double> &field2, size_t nmiss, double missval) +mastrfu(int gridID, int zaxisID, const Varray2D<double> &field1, Varray2D<double> &field2, size_t numMissVals, double missval) { auto fact = 4.0 * std::atan(1.0) * 6371000.0 / 9.81; @@ -47,7 +47,7 @@ mastrfu(int gridID, int zaxisID, const Varray2D<double> &field1, Varray2D<double for (int ilev = 0; ilev < nlev; ilev++) for (size_t ilat = 0; ilat < nlat; ilat++) field2[ilev][ilat] = 0.0; - if (nmiss == 0) + if (numMissVals == 0) { for (int ilev = nlev - 1; ilev >= 0; ilev--) for (int n = ilev; n < nlev - 1; ++n) @@ -73,8 +73,19 @@ mastrfu(int gridID, int zaxisID, const Varray2D<double> &field1, Varray2D<double } } -class ModuleMastrfu +class Mastrfu : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Mastrfu", + .operators = { { "mastrfu", MastrfuHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Mastrfu> registration = RegisterEntry<Mastrfu>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -93,9 +104,8 @@ class ModuleMastrfu public: void - init(void *process) + init() { - cdo_initialize(process); streamID1 = cdo_open_read(0); @@ -153,25 +163,25 @@ public: cdo_taxis_copy_timestep(taxisID2, taxisID1); cdo_def_timestep(streamID2, tsID); - size_t nmiss = 0; + size_t numMissVals = 0; for (int recID = 0; recID < nrecs; ++recID) { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss1; - cdo_read_record(streamID1, array1[levelID].data(), &nmiss1); - nmiss += nmiss1; + size_t numMissVals1; + cdo_read_record(streamID1, array1[levelID].data(), &numMissVals1); + numMissVals += numMissVals1; } - mastrfu(gridID, zaxisID, array1, array2, nmiss, missval); + mastrfu(gridID, zaxisID, array1, array2, numMissVals, missval); for (int recID = 0; recID < nrecs; ++recID) { int varID = 0; int levelID = recID; cdo_def_record(streamID2, varID, levelID); - nmiss = array_num_mv(nlat, array2[levelID].data(), missval); - cdo_write_record(streamID2, array2[levelID].data(), nmiss); + numMissVals = array_num_mv(nlat, array2[levelID].data(), missval); + cdo_write_record(streamID2, array2[levelID].data(), numMissVals); } tsID++; @@ -182,19 +192,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Mastrfu(void *process) -{ - ModuleMastrfu mastrfu; - - mastrfu.init(process); - mastrfu.run(); - mastrfu.close(); - - return nullptr; -} diff --git a/src/Math.cc b/src/Math.cc index 90fe4771183b709d63e42c033e2d72a79cdc1477..882baf41f48cef355023a935894f778384af4cdd 100644 --- a/src/Math.cc +++ b/src/Math.cc @@ -33,15 +33,15 @@ #include "param_conversion.h" static void -check_out_of_range(size_t &nmiss, const size_t len, double missval, Varray<double> &v, double rmin, double rmax) +check_out_of_range(size_t &numMissVals, const size_t len, double missval, Varray<double> &v, double rmin, double rmax) { - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < len; ++i) if (!dbl_is_equal(v[i], missval) && (v[i] < rmin || v[i] > rmax)) { v[i] = missval; - nmiss++; + numMissVals++; } } else @@ -50,21 +50,21 @@ check_out_of_range(size_t &nmiss, const size_t len, double missval, Varray<doubl if (v[i] < rmin || v[i] > rmax) { v[i] = missval; - nmiss++; + numMissVals++; } } } static void -check_lower_range(size_t &nmiss, const size_t len, double missval, Varray<double> &v, double rmin) +check_lower_range(size_t &numMissVals, const size_t len, double missval, Varray<double> &v, double rmin) { - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < len; ++i) if (!dbl_is_equal(v[i], missval) && v[i] < rmin) { v[i] = missval; - nmiss++; + numMissVals++; } } else @@ -73,17 +73,17 @@ check_lower_range(size_t &nmiss, const size_t len, double missval, Varray<double if (v[i] < rmin) { v[i] = missval; - nmiss++; + numMissVals++; } } } template <typename T, class UnaryOperation> void -math_varray_transform(const size_t nmiss, const size_t len, double missval1, const Varray<T> &array1, Varray<T> &array2, +math_varray_transform(const size_t numMissVals, const size_t len, double missval1, const Varray<T> &array1, Varray<T> &array2, UnaryOperation unary_op) { - if (nmiss) + if (numMissVals) for (size_t i = 0; i < len; ++i) array2[i] = dbl_is_equal(array1[i], missval1) ? missval1 : unary_op(array1[i]); else for (size_t i = 0; i < len; ++i) array2[i] = unary_op(array1[i]); @@ -171,36 +171,30 @@ enum struct Oper Arg }; -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("abs", (int)Oper::Abs, 0, nullptr); - cdo_operator_add("int", (int)Oper::Int, 0, nullptr); - cdo_operator_add("nint", (int)Oper::Nint, 0, nullptr); - cdo_operator_add("sqr", (int)Oper::Sqr, 0, nullptr); - cdo_operator_add("sqrt", (int)Oper::Sqrt, 0, nullptr); - cdo_operator_add("exp", (int)Oper::Exp, 0, nullptr); - cdo_operator_add("ln", (int)Oper::Ln, 0, nullptr); - cdo_operator_add("log10", (int)Oper::Log10, 0, nullptr); - cdo_operator_add("sin", (int)Oper::Sin, 0, nullptr); - cdo_operator_add("cos", (int)Oper::Cos, 0, nullptr); - cdo_operator_add("tan", (int)Oper::Tan, 0, nullptr); - cdo_operator_add("asin", (int)Oper::Asin, 0, nullptr); - cdo_operator_add("acos", (int)Oper::Acos, 0, nullptr); - cdo_operator_add("atan", (int)Oper::Atan, 0, nullptr); - cdo_operator_add("pow", (int)Oper::Pow, 0, nullptr); - cdo_operator_add("rand", (int)Oper::Rand, 0, nullptr); - cdo_operator_add("reci", (int)Oper::Reci, 0, nullptr); - cdo_operator_add("not", (int)Oper::Not, 0, nullptr); - cdo_operator_add("conj", (int)Oper::Conj, 0, nullptr); - cdo_operator_add("re", (int)Oper::Re, 0, nullptr); - cdo_operator_add("im", (int)Oper::Im, 0, nullptr); - cdo_operator_add("arg", (int)Oper::Arg, 0, nullptr); - // clang-format on -} -class ModuleMath +class Math : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Math", + .operators = { { "abs", (int) Oper::Abs, 0, MathHelp }, { "int", (int) Oper::Int, 0, MathHelp }, + { "nint", (int) Oper::Nint, 0, MathHelp }, { "sqr", (int) Oper::Sqr, 0, MathHelp }, + { "sqrt", (int) Oper::Sqrt, 0, MathHelp }, { "exp", (int) Oper::Exp, 0, MathHelp }, + { "ln", (int) Oper::Ln, 0, MathHelp }, { "log10", (int) Oper::Log10, 0, MathHelp }, + { "sin", (int) Oper::Sin, 0, MathHelp }, { "cos", (int) Oper::Cos, 0, MathHelp }, + { "tan", (int) Oper::Tan, 0, MathHelp }, { "asin", (int) Oper::Asin, 0, MathHelp }, + { "acos", (int) Oper::Acos, 0, MathHelp }, { "atan", (int) Oper::Atan, 0, MathHelp }, + { "pow", (int) Oper::Pow, 0, MathHelp }, { "rand", (int) Oper::Rand, 0, MathHelp }, + { "reci", (int) Oper::Reci, 0, MathHelp }, { "not", (int) Oper::Not, 0, MathHelp }, + { "conj", (int) Oper::Conj, 0, MathHelp }, { "re", (int) Oper::Re, 0, MathHelp }, + { "im", (int) Oper::Im, 0, MathHelp }, { "arg", (int) Oper::Arg, 0, MathHelp } }, + .aliases = { { "log", "ln" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Math> registration = RegisterEntry<Math>(module); + private: Oper operfunc; @@ -218,13 +212,9 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); - auto operatorID = cdo_operator_id(); operfunc = (Oper) cdo_operator_f1(operatorID); @@ -286,8 +276,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, &array1[0], &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, &array1[0], &numMissVals); auto is_EQ = dbl_is_equal; auto missval1 = varList1[varID].missval; @@ -299,41 +289,41 @@ public: // clang-format off switch (operfunc) { - case Oper::Abs: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_abs); break; - case Oper::Int: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_int); break; - case Oper::Nint: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_nint); break; - case Oper::Sqr: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_sqr); break; + case Oper::Abs: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_abs); break; + case Oper::Int: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_int); break; + case Oper::Nint: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_nint); break; + case Oper::Sqr: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_sqr); break; case Oper::Sqrt: for (size_t i = 0; i < n; ++i) array2[i] = SQRTM(array1[i]); break; - case Oper::Exp: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_exp); break; - case Oper::Ln: check_lower_range(nmiss, n, missval1, array1, -1); - math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_log); break; - case Oper::Log10: check_lower_range(nmiss, n, missval1, array1, -1); - math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_log10); break; - case Oper::Sin: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_sin); break; - case Oper::Cos: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_cos); break; - case Oper::Tan: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_tan); break; - case Oper::Asin: check_out_of_range(nmiss, n, missval1, array1, -1, 1); - math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_asin); break; - case Oper::Acos: check_out_of_range(nmiss, n, missval1, array1, -1, 1); - math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_acos); break; - case Oper::Atan: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_atan); break; + case Oper::Exp: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_exp); break; + case Oper::Ln: check_lower_range(numMissVals, n, missval1, array1, -1); + math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_log); break; + case Oper::Log10: check_lower_range(numMissVals, n, missval1, array1, -1); + math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_log10); break; + case Oper::Sin: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_sin); break; + case Oper::Cos: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_cos); break; + case Oper::Tan: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_tan); break; + case Oper::Asin: check_out_of_range(numMissVals, n, missval1, array1, -1, 1); + math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_asin); break; + case Oper::Acos: check_out_of_range(numMissVals, n, missval1, array1, -1, 1); + math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_acos); break; + case Oper::Atan: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_atan); break; case Oper::Pow: for (size_t i = 0; i < n; ++i) array2[i] = dbl_is_equal(array1[i], missval1) ? missval1 : std::pow(array1[i], rc); break; case Oper::Rand: for (size_t i = 0; i < n; ++i) array2[i] = dbl_is_equal(array1[i], missval1) ? missval1 : ((double) std::rand()) / ((double) RAND_MAX); break; - case Oper::Reci: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_reci); break; - case Oper::Not: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_not); break; + case Oper::Reci: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_reci); break; + case Oper::Not: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_not); break; case Oper::Re: - case Oper::Arg: math_varray_transform(nmiss, n, missval1, array1, array2, unary_op_nop); break; + case Oper::Arg: math_varray_transform(numMissVals, n, missval1, array1, array2, unary_op_nop); break; default: cdo_abort("Operator not implemented for real data!"); break; } // clang-format on - nmiss = varray_num_mv(n, array2, missval1); + numMissVals = varray_num_mv(n, array2, missval1); } else { @@ -351,11 +341,11 @@ public: } // clang-format on - nmiss = 0; + numMissVals = 0; } cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } tsID++; @@ -369,18 +359,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Math(void *process) -{ - ModuleMath math; - math.init(process); - math.run(); - math.close(); - - return nullptr; -} diff --git a/src/Merge.cc b/src/Merge.cc index 4847295c0da1d3cc5f68efa1798f70499752ceb7..f6cefcd9d1411b0003237f7b17c37795973b63f4 100644 --- a/src/Merge.cc +++ b/src/Merge.cc @@ -113,8 +113,19 @@ cdo_inq_base_filetype(CdoStreamID streamID) return filetype; } -class ModuleMerge +class Merge : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Merge", + .operators = { { "merge", MergeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Merge> registration = RegisterEntry<Merge>(module); CdoStreamID streamID2; int nmerge; @@ -137,9 +148,8 @@ class ModuleMerge public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -310,16 +320,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -Merge(void *process) -{ - ModuleMerge merge; - merge.init(process); - merge.run(); - merge.close(); - return nullptr; -} diff --git a/src/Mergegrid.cc b/src/Mergegrid.cc index 219621a4965712c666f257443d91c823049bf128..e287aae92b49edbfa567bd5b3d353c299ef84a28 100644 --- a/src/Mergegrid.cc +++ b/src/Mergegrid.cc @@ -18,8 +18,19 @@ void genGridIndex(int gridID1, int gridID2, std::vector<long> &index); -class ModuleMergegrid +class Mergegrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Mergegrid", + .operators = { { "mergegrid", MergegridHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Mergegrid> registration = RegisterEntry<Mergegrid>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -40,9 +51,8 @@ class ModuleMergegrid public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -108,14 +118,14 @@ public: { int varID, levelID; cdo_inq_record(streamID2, &varID, &levelID); - size_t nmiss2; - cdo_read_record(streamID2, array2.data(), &nmiss2); + size_t numMissVals2; + cdo_read_record(streamID2, array2.data(), &numMissVals2); auto missval2 = vlistInqVarMissval(vlistID2, varID); cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss1; - cdo_read_record(streamID1, array1.data(), &nmiss1); + size_t numMissVals1; + cdo_read_record(streamID1, array1.data(), &numMissVals1); auto missval1 = vlistInqVarMissval(vlistID1, varID); @@ -124,15 +134,15 @@ public: if (gindex[i] >= 0 && !DBL_IS_EQUAL(array2[i], missval2)) { array1[gindex[i]] = array2[i]; } } - if (nmiss1) + if (numMissVals1) { - nmiss1 = 0; + numMissVals1 = 0; for (size_t i = 0; i < gridsize1; ++i) - if (DBL_IS_EQUAL(array1[i], missval1)) nmiss1++; + if (DBL_IS_EQUAL(array1[i], missval1)) numMissVals1++; } cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, array1.data(), nmiss1); + cdo_write_record(streamID3, array1.data(), numMissVals1); } tsID++; @@ -144,17 +154,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Mergegrid(void *process) -{ - ModuleMergegrid mergegrid; - mergegrid.init(process); - mergegrid.run(); - mergegrid.close(); - return nullptr; -} diff --git a/src/Mergetime.cc b/src/Mergetime.cc index 15f219ee4f73aa1148bd5a606bd5be8b50e29563..df2163d7475f1b610c9b622182bbf59ffe70e52f 100644 --- a/src/Mergetime.cc +++ b/src/Mergetime.cc @@ -80,8 +80,19 @@ read_first_timestep(int nfiles, std::vector<StreamInfo> &streamInfo) } } -class ModuleMergetime +class Mergetime : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Mergetime", + .operators = { { "mergetime", MergeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Mergetime> registration = RegisterEntry<Mergetime>(module); int tsID2 = 0; int taxisID2 = CDI_UNDEFID; CdiDateTime lastDateTime{}; @@ -96,9 +107,8 @@ class ModuleMergetime public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -217,18 +227,5 @@ public: close() { cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Mergetime(void *process) -{ - ModuleMergetime mergetime; - mergetime.init(process); - mergetime.run(); - mergetime.close(); - - return nullptr; -} diff --git a/src/Merstat.cc b/src/Merstat.cc index 49bc12aa3cbf5f712cf4c72d8893a51ef5450c0a..19f38350bed79c78f41fca2dcd89d1d5676035da 100644 --- a/src/Merstat.cc +++ b/src/Merstat.cc @@ -28,29 +28,32 @@ #include <mpim_grid.h> #include "field_functions.h" -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("merrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("mermin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("mermax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("mersum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("mermean", FieldFunc_Meanw, 1, nullptr); - cdo_operator_add("meravg", FieldFunc_Avgw, 1, nullptr); - cdo_operator_add("mervar", FieldFunc_Varw, 1, nullptr); - cdo_operator_add("mervar1", FieldFunc_Var1w, 1, nullptr); - cdo_operator_add("merstd", FieldFunc_Stdw, 1, nullptr); - cdo_operator_add("merstd1", FieldFunc_Std1w, 1, nullptr); - cdo_operator_add("merskew", FieldFunc_Skew, 0, nullptr); - cdo_operator_add("merkurt", FieldFunc_Kurt, 0, nullptr); - cdo_operator_add("mermedian", FieldFunc_Median, 0, nullptr); - cdo_operator_add("merpctl", FieldFunc_Pctl, 0, nullptr); - // clang-format on -} - -class ModuleMerstat +class Merstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Merstat", + .operators = { { "merrange", FieldFunc_Range, 0, MerstatHelp }, + { "mermin", FieldFunc_Min, 0, MerstatHelp }, + { "mermax", FieldFunc_Max, 0, MerstatHelp }, + { "mersum", FieldFunc_Sum, 0, MerstatHelp }, + { "mermean", FieldFunc_Meanw, 1, MerstatHelp }, + { "meravg", FieldFunc_Avgw, 1, MerstatHelp }, + { "merstd", FieldFunc_Stdw, 1, MerstatHelp }, + { "merstd1", FieldFunc_Std1w, 1, MerstatHelp }, + { "mervar", FieldFunc_Varw, 1, MerstatHelp }, + { "mervar1", FieldFunc_Var1w, 1, MerstatHelp }, + { "merskew", FieldFunc_Skew, 0, MerstatHelp }, + { "merkurt", FieldFunc_Kurt, 0, MerstatHelp }, + { "mermedian", FieldFunc_Median, 0, MerstatHelp }, + { "merpctl", FieldFunc_Pctl, 0, MerstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Merstat> registration = RegisterEntry<Merstat>(module); int gridID1, gridID2 = -1, lastgrid = -1; int index; @@ -71,11 +74,8 @@ class ModuleMerstat public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -182,18 +182,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Merstat(void *process) -{ - ModuleMerstat merstat; - merstat.init(process); - merstat.run(); - merstat.close(); - - return nullptr; -} diff --git a/src/Monarith.cc b/src/Monarith.cc index 81d6ee605ee1351f107a13ff7c738571549d91c7..c0e73b4b0a236ca025c5c9cafd0112d0932dc6ba 100644 --- a/src/Monarith.cc +++ b/src/Monarith.cc @@ -20,17 +20,22 @@ #include "cdo_vlist.h" #include "field_functions.h" -static void -add_operators(void) -{ - cdo_operator_add("monadd", FieldFunc_Add, 0, nullptr); - cdo_operator_add("monsub", FieldFunc_Sub, 0, nullptr); - cdo_operator_add("monmul", FieldFunc_Mul, 0, nullptr); - cdo_operator_add("mondiv", FieldFunc_Div, 0, nullptr); -} - -class ModuleMonarith +class Monarith : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Monarith", + .operators = { { "monadd", FieldFunc_Add, 0, MonarithHelp }, + { "monsub", FieldFunc_Sub, 0, MonarithHelp }, + { "monmul", FieldFunc_Mul, 0, MonarithHelp }, + { "mondiv", FieldFunc_Div, 0, MonarithHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Monarith> registration = RegisterEntry<Monarith>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -47,11 +52,8 @@ class ModuleMonarith public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -151,18 +153,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Monarith(void *process) -{ - ModuleMonarith monarith; - monarith.init(process); - monarith.run(); - monarith.close(); - - return nullptr; -} diff --git a/src/Mrotuv.cc b/src/Mrotuv.cc index 0e0f42db855e36be03ef094cd2cfc8e042235a33..e73a8f768478324960fa022ce4dd182778ee2bfe 100644 --- a/src/Mrotuv.cc +++ b/src/Mrotuv.cc @@ -176,9 +176,21 @@ p_to_uv_grid(long nlon, long nlat, Varray<double> &grid1x_v, Varray<double> &gri } } -class ModuleMrotuv +class Mrotuv : public Process { - size_t nmiss1 = 0, nmiss2 = 0; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Mrotuv", + .operators = { { "mrotuv"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 2, NoRestriction }, + }; + inline static RegisterEntry<Mrotuv> registration = RegisterEntry<Mrotuv>(module); + + size_t numMissVals1 = 0, numMissVals2 = 0; int uid = -1, vid = -1; CdoStreamID streamID1; @@ -212,10 +224,8 @@ class ModuleMrotuv public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -322,6 +332,7 @@ public: missval1 = vlistInqVarMissval(vlistID1, uid); missval2 = vlistInqVarMissval(vlistID1, vid); } + void run() { @@ -356,14 +367,14 @@ public: int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - if (varID == uid) cdo_read_record(streamID1, urfield[levelID].data(), &nmiss1); - if (varID == vid) cdo_read_record(streamID1, vrfield[levelID].data(), &nmiss2); + if (varID == uid) cdo_read_record(streamID1, urfield[levelID].data(), &numMissVals1); + if (varID == vid) cdo_read_record(streamID1, vrfield[levelID].data(), &numMissVals2); } for (int levelID = 0; levelID < nlevs; ++levelID) { // remove missing values - if (nmiss1 || nmiss2) + if (numMissVals1 || numMissVals2) { for (size_t i = 0; i < gridsize; ++i) { @@ -402,33 +413,20 @@ public: for (size_t i = 0; i < nlon; ++i) { vfield[nlat - 1][i] = vhelp[nlat - 1][i + 1]; } cdo_def_record(streamID2, 0, levelID); - cdo_write_record(streamID2, ufield_v.data(), nmiss1); + cdo_write_record(streamID2, ufield_v.data(), numMissVals1); cdo_def_record(streamID3, 0, levelID); - cdo_write_record(streamID3, vfield_v.data(), nmiss2); + cdo_write_record(streamID3, vfield_v.data(), numMissVals2); } tsID++; } } + void close() { cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Mrotuv(void *process) -{ - ModuleMrotuv mrotuv; - - mrotuv.init(process); - mrotuv.run(); - mrotuv.close(); - - return nullptr; -} diff --git a/src/Mrotuvb.cc b/src/Mrotuvb.cc index 605290acb8af4644c21214a548238a8061016fc8..003eefd7c979734011d0b710f9c6899f87257f4d 100644 --- a/src/Mrotuvb.cc +++ b/src/Mrotuvb.cc @@ -225,8 +225,19 @@ uv_to_p_grid(size_t nlon, size_t nlat, Varray<double> &grid1x_v, Varray<double> } } -class ModuleMrotuvb +class Mrotuvb : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Mrotuvb", + .operators = { { "mrotuvb", MrotuvbHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Mrotuvb> registration = RegisterEntry<Mrotuvb>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -254,9 +265,8 @@ class ModuleMrotuvb public: void - init(void *process) + init() { - cdo_initialize(process); gpint = !(cdo_operator_argc() == 1 && cdo_operator_argv(0) == "noint"); @@ -396,12 +406,12 @@ public: cdo_inq_record(streamID1, &varID1, &levelID); cdo_inq_record(streamID2, &varID2, &levelID); - size_t nmiss1, nmiss2; - cdo_read_record(streamID1, ufield_v.data(), &nmiss1); - cdo_read_record(streamID2, vfield_v.data(), &nmiss2); + size_t numMissVals1, numMissVals2; + cdo_read_record(streamID1, ufield_v.data(), &numMissVals1); + cdo_read_record(streamID2, vfield_v.data(), &numMissVals2); // remove missing values - if (nmiss1 || nmiss2) + if (numMissVals1 || numMissVals2) { for (size_t i = 0; i < gridsize; ++i) { @@ -483,18 +493,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Mrotuvb(void *process) -{ - ModuleMrotuvb mrotuvb; - mrotuvb.init(process); - mrotuvb.run(); - mrotuvb.close(); - - return nullptr; -} diff --git a/src/NCL_wind.cc b/src/NCL_wind.cc index e30942db146242dbefaf5cf1f27e105a2762caab..07bd3e05b54aea432dbeb917703268fc07457c4e 100644 --- a/src/NCL_wind.cc +++ b/src/NCL_wind.cc @@ -36,7 +36,7 @@ uv2dv_cfd_W(double missval, double *u, double *v, double *lon, double *lat, size double *tmp_v = v + k * gridsize_uv; double *tmp_div = div + k * gridsize_uv; // Init output array. - varray_fill(gridsize_uv, tmp_div, 0.0); + ranges::fill_n(tmp_div, gridsize_uv, 0.0); // Call the Fortran routine. #ifdef HAVE_CF_INTERFACE DDVFIDF(tmp_u, tmp_v, lat, lon, inlon, inlat, missval, boundOpt, tmp_div, ierror); @@ -66,7 +66,7 @@ uv2vr_cfd_W(double missval, double *u, double *v, double *lon, double *lat, size double *tmp_v = v + k * gridsize_uv; double *tmp_vort = vort + k * gridsize_uv; // Init output array. - varray_fill(gridsize_uv, tmp_vort, 0.0); + ranges::fill_n(tmp_vort, gridsize_uv, 0.0); // Call the Fortran routine. #ifdef HAVE_CF_INTERFACE DVRFIDF(tmp_u, tmp_v, lat, lon, inlon, inlat, missval, boundOpt, tmp_vort, ierror); @@ -96,10 +96,10 @@ enum struct OutMode }; // Parameter -OutMode outMode(OutMode::NEW); -int boundOpt = -1; -std::string uName; -std::string vName; +static OutMode outMode(OutMode::NEW); +static int boundOpt = -1; +static std::string uName; +static std::string vName; static void print_parameter(void) @@ -123,7 +123,7 @@ set_parameter(void) KVList kvlist; kvlist.name = "PARAMETER"; - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -152,8 +152,24 @@ set_parameter(void) if (Options::cdoVerbose) print_parameter(); } -class ModuleNCL_wind +class NCL_wind : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "NCL_wind", + // clang-format off + .operators = { { "uv2dv_cfd", 0, 0, "[u,v,boundsOpt,outMode]", NCL_windHelp }, + { "uv2vr_cfd", 0, 0, "[u,v,boundsOpt,outMode]", NCL_windHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<NCL_wind> registration = RegisterEntry<NCL_wind>(module); + + int UV2DV_CFD, UV2VR_CFD; CdoStreamID streamID1; CdoStreamID streamID2; @@ -182,17 +198,14 @@ class ModuleNCL_wind Varray<double> lon; Varray<double> lat; - int UV2DV_CFD, UV2VR_CFD; VarList varList1; public: void - init(void *process) + init() { - cdo_initialize(process); - - UV2DV_CFD = cdo_operator_add("uv2dv_cfd", 0, 0, "[u, v, boundsOpt, outMode]"); - UV2VR_CFD = cdo_operator_add("uv2vr_cfd", 0, 0, "[u, v, boundsOpt, outMode]"); + UV2DV_CFD = module.get_id("uv2dv_cfd"); + UV2VR_CFD = module.get_id("uv2vr_cfd"); operatorID = cdo_operator_id(); @@ -281,7 +294,6 @@ public: void run() { - const auto &varU = varList1[varIDu]; const auto &varV = varList1[varIDv]; int tsID = 0; @@ -290,7 +302,7 @@ public: auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); if (nrecs == 0) break; - size_t nmissu = 0, nmissv = 0; + size_t numMissValsu = 0, numMissValsv = 0; cdo_taxis_copy_timestep(taxisID2, taxisID1); cdo_def_timestep(streamID2, tsID); @@ -299,34 +311,34 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, &array[0], &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, &array[0], &numMissVals); if (varID == varIDu || varID == varIDv) { if (varID == varIDu) { std::copy_n(&array[0], gridsizeuv, &arrayu[levelID * gridsizeuv]); - nmissu += nmiss; + numMissValsu += numMissVals; } if (varID == varIDv) { std::copy_n(&array[0], gridsizeuv, &arrayv[levelID * gridsizeuv]); - nmissv += nmiss; + numMissValsv += numMissVals; } } if (outMode == OutMode::APPEND) { cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, &array[0], nmiss); + cdo_write_record(streamID2, &array[0], numMissVals); } } - if (nmissu != nmissv) + if (numMissValsu != numMissValsv) { cdo_abort("u and v have different number of missing values!"); - if (nmissu && !dbl_is_equal(varU.missval, varV.missval)) + if (numMissValsu && !dbl_is_equal(varU.missval, varV.missval)) { for (int levelID = 0; levelID < nlev; ++levelID) { @@ -345,14 +357,15 @@ public: for (int levelID = 0; levelID < nlev; ++levelID) { auto parray = &arrayo[levelID * gridsizeuv]; - auto nmiss = array_num_mv(gridsizeuv, parray, varU.missval); + auto numMissVals = array_num_mv(gridsizeuv, parray, varU.missval); cdo_def_record(streamID2, varIDo, levelID); - cdo_write_record(streamID2, parray, nmiss); + cdo_write_record(streamID2, parray, numMissVals); } tsID++; } } + void close() { @@ -360,19 +373,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -NCL_wind(void *process) - -{ - ModuleNCL_wind ncl_wind; - - ncl_wind.init(process); - ncl_wind.run(); - ncl_wind.close(); - - return nullptr; -} diff --git a/src/Ninfo.cc b/src/Ninfo.cc index 5e4c5ce9608afdb4de99519c4317c0820dd5b6eb..df57a367de3c4a05d71b50a2fd5bfde0ae964882 100644 --- a/src/Ninfo.cc +++ b/src/Ninfo.cc @@ -22,7 +22,7 @@ #include "process_int.h" -class ModuleNinfo +class Ninfo : public Process { enum { @@ -36,6 +36,26 @@ class ModuleNinfo NGRIDS }; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ninfo", + .operators = { { "nyear", NYEAR, 0, NinfoHelp }, + { "nmon", NMON, 0, NinfoHelp }, + { "ndate", NDATE, 0, NinfoHelp }, + { "ntime", NTIME, 0, NinfoHelp }, + { "ncode", NinfoHelp }, + { "npar", NPAR, 0, NinfoHelp }, + { "nlevel", NLEVEL, 0, NinfoHelp }, + { "ngridpoints", NGRIDPOINTS, 0, NinfoHelp }, + { "ngrids", NGRIDS, 0, NinfoHelp } }, + .aliases = { { "nvar", "npar" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Ninfo> registration = RegisterEntry<Ninfo>(module); + int operfunc; int ntsteps; CdoStreamID streamID; @@ -47,18 +67,8 @@ class ModuleNinfo public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("nyear", NYEAR, 0, nullptr); - cdo_operator_add("nmon", NMON, 0, nullptr); - cdo_operator_add("ndate", NDATE, 0, nullptr); - cdo_operator_add("ntime", NTIME, 0, nullptr); - cdo_operator_add("npar", NPAR, 0, nullptr); - cdo_operator_add("nlevel", NLEVEL, 0, nullptr); - cdo_operator_add("ngridpoints", NGRIDPOINTS, 0, nullptr); - cdo_operator_add("ngrids", NGRIDS, 0, nullptr); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -165,17 +175,5 @@ public: close() { cdo_stream_close(streamID); - - cdo_finish(); } }; - -void * -Ninfo(void *process) -{ - ModuleNinfo ninfo; - ninfo.init(process); - ninfo.run(); - ninfo.close(); - return nullptr; -} diff --git a/src/Nmldump.cc b/src/Nmldump.cc index fc068039a4517fa1103a940a8aa7c1d09355a5f5..93d5e8e0dcf6a8dae433a1b0c8e7dddce01176fe 100644 --- a/src/Nmldump.cc +++ b/src/Nmldump.cc @@ -65,20 +65,30 @@ kvldump(const PMList &pmlist) } } -class ModuleNmldump +class Nmldump : public Process { - int operatorID; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Nmldump", + .operators = { { "nmldump"}, { "kvldump"} }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 0, NoRestriction }, + }; + inline static RegisterEntry<Nmldump> registration = RegisterEntry<Nmldump>(module); int NMLDUMP, KVLDUMP; + int operatorID; PMList pmlist; public: void - init(void *process) + init() { - cdo_initialize(process); - NMLDUMP = cdo_operator_add("nmldump", 0, 0, nullptr); - KVLDUMP = cdo_operator_add("kvldump", 0, 0, nullptr); + NMLDUMP = module.get_id("nmldump"); + KVLDUMP = module.get_id("kvldump"); operatorID = cdo_operator_id(); @@ -98,18 +108,5 @@ public: void close() { - cdo_finish(); } }; - -void * -Nmldump(void *process) -{ - ModuleNmldump nmldump; - - nmldump.init(process); - nmldump.run(); - nmldump.close(); - - return nullptr; -} diff --git a/src/Output.cc b/src/Output.cc index 30402d50fd0dcba0222f4d683964fa9dcb51eebd..0a3d924626a97d6736a6a60c166901ea7c29a27f 100644 --- a/src/Output.cc +++ b/src/Output.cc @@ -225,9 +225,59 @@ outputf(int nelem, const std::string &format, size_t gridsize, const Varray<doub fprintf(stdout, "\n"); } -class ModuleOutput +class Output : public Process { - size_t nmiss; + enum + { + knohead, + kvalue, + kparam, + kcode, + kname, + kx, + ky, + klon, + klat, + klev, + kbin, + kxind, + kyind, + ktimestep, + kdate, + ktime, + kyear, + kmonth, + kday + }; + struct KeyLenEntry + { + std::string key; + int idx; + int len; + }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Output", + .operators = { { "output", 0, 1, OutputHelp }, + { "outputint", OutputHelp }, + { "outputsrv", OutputHelp }, + { "outputext", OutputHelp }, + { "outputf", OutputHelp }, + { "outputts", OutputHelp }, + { "outputfld", OutputHelp }, + { "outputarr", OutputHelp }, + { "outputxyz", OutputHelp }, + { "outputtab", OutputtabHelp } }, + .aliases = { { "outputkey", "outputtab" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { -1, 0, NoRestriction }, + }; + inline static RegisterEntry<Output> registration = RegisterEntry<Output>(module); + int OUTPUT, OUTPUTINT, OUTPUTSRV, OUTPUTEXT, OUTPUTF, OUTPUTTS, OUTPUTFLD, OUTPUTARR, OUTPUTXYZ, OUTPUTTAB; + size_t numMissVals; int nelem = 1; int index; std::string format; @@ -238,12 +288,6 @@ class ModuleOutput int operatorID; // clang-format off - enum {knohead, kvalue, kparam, kcode, kname, kx, ky, klon, klat, klev, kbin, kxind, kyind, ktimestep, kdate, ktime, kyear, kmonth, kday}; - struct KeyLenEntry { - std::string key; - int idx; - int len; - }; std::vector<KeyLenEntry> keyMap = { { "nohead", knohead, 0 }, { "value", kvalue, 8 }, @@ -267,25 +311,21 @@ class ModuleOutput // clang-format on }; - int OUTPUT, OUTPUTINT, OUTPUTSRV, OUTPUTEXT, OUTPUTF, OUTPUTTS, OUTPUTFLD, OUTPUTARR, OUTPUTXYZ, OUTPUTTAB; - public: void - init(void *process) + init() { - cdo_initialize(process); - - OUTPUT = cdo_operator_add("output", 0, 1, nullptr); - OUTPUTINT = cdo_operator_add("outputint", 0, 0, nullptr); - OUTPUTSRV = cdo_operator_add("outputsrv", 0, 0, nullptr); - OUTPUTEXT = cdo_operator_add("outputext", 0, 0, nullptr); - OUTPUTF = cdo_operator_add("outputf", 0, 0, nullptr); - OUTPUTTS = cdo_operator_add("outputts", 0, 0, nullptr); - OUTPUTFLD = cdo_operator_add("outputfld", 0, 0, nullptr); - OUTPUTARR = cdo_operator_add("outputarr", 0, 0, nullptr); - OUTPUTXYZ = cdo_operator_add("outputxyz", 0, 0, nullptr); - OUTPUTTAB = cdo_operator_add("outputtab", 0, 0, nullptr); + OUTPUT = module.get_id("output"); + OUTPUTINT = module.get_id("outputint"); + OUTPUTSRV = module.get_id("outputsrv"); + OUTPUTEXT = module.get_id("outputext"); + OUTPUTF = module.get_id("outputf"); + OUTPUTTS = module.get_id("outputts"); + OUTPUTFLD = module.get_id("outputfld"); + OUTPUTARR = module.get_id("outputarr"); + OUTPUTXYZ = module.get_id("outputxyz"); + OUTPUTTAB = module.get_id("outputtab"); (void) (OUTPUT); // unused @@ -427,7 +467,7 @@ public: nlat = 1; } - cdo_read_record(streamID, array.data(), &nmiss); + cdo_read_record(streamID, array.data(), &numMissVals); auto vdate = cdiDate_get(vDateTime.date); auto vtime = cdiTime_get(vDateTime.time); @@ -525,16 +565,5 @@ public: void close() { - cdo_finish(); } }; - -void * -Output(void *process) -{ - ModuleOutput output; - output.init(process); - output.run(); - output.close(); - return nullptr; -} diff --git a/src/Outputgmt.cc b/src/Outputgmt.cc index 5de0cdf7d03f396b209a7c507337e519ad475054..5447e7f6f2beaf07f64ed40af86a6eba71575dd3 100644 --- a/src/Outputgmt.cc +++ b/src/Outputgmt.cc @@ -353,11 +353,31 @@ output_vector(long nlon, long nlat, int ninc, const Varray<double> &lon, const V fprintf(stdout, "#\n"); } -class ModuleOutputgmt +class Outputgmt : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Outputgmt", + .operators = { { "gmtxyz", OutputgmtHelp }, + { "gmtcells", OutputgmtHelp }, + { "outputcenter2", OutputgmtHelp }, + { "outputcentercpt", OutputgmtHelp }, + { "outputboundscpt", OutputgmtHelp }, + { "outputvector", OutputgmtHelp }, + { "outputtri", OutputgmtHelp }, + { "outputvrml", OutputgmtHelp }, + { "outputkml", OutputgmtHelp } }, + .aliases = { { "outputcenter", "gmtxyz" }, { "outputbounds", "gmtcells" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Outputgmt> registration = RegisterEntry<Outputgmt>(module); + int GMTXYZ, OUTPUTCENTER2, OUTPUTCENTERCPT, GMTCELLS, OUTPUTBOUNDSCPT, OUTPUTVECTOR, OUTPUTTRI, OUTPUTVRML, OUTPUTKML; int varID0; size_t gridsize2 = 0; - size_t nmiss; + size_t numMissVals; int ninc = 1; bool lzon = false, lmer = false, lhov = false; Varray<double> grid_center_lat2, grid_center_lon2; @@ -386,8 +406,6 @@ class ModuleOutputgmt bool printHeader; bool grid_is_circular; - int GMTXYZ, OUTPUTCENTER2, OUTPUTCENTERCPT, GMTCELLS, OUTPUTBOUNDSCPT, OUTPUTVECTOR, OUTPUTTRI, OUTPUTVRML, OUTPUTKML; - VarList varList; Varray<double> array; Varray<double> array2; @@ -406,19 +424,18 @@ class ModuleOutputgmt public: void - init(void *process) + init() { - cdo_initialize(process); - - GMTXYZ = cdo_operator_add("gmtxyz", 0, 0, nullptr); - OUTPUTCENTER2 = cdo_operator_add("outputcenter2", 0, 0, nullptr); - OUTPUTCENTERCPT = cdo_operator_add("outputcentercpt", 0, 0, nullptr); - GMTCELLS = cdo_operator_add("gmtcells", 0, 0, nullptr); - OUTPUTBOUNDSCPT = cdo_operator_add("outputboundscpt", 0, 0, nullptr); - OUTPUTVECTOR = cdo_operator_add("outputvector", 0, 0, nullptr); - OUTPUTTRI = cdo_operator_add("outputtri", 0, 0, nullptr); - OUTPUTVRML = cdo_operator_add("outputvrml", 0, 0, nullptr); - OUTPUTKML = cdo_operator_add("outputkml", 0, 0, nullptr); + + GMTXYZ = module.get_id("gmtxyz"); + OUTPUTCENTER2 = module.get_id("outputcenter2"); + OUTPUTCENTERCPT = module.get_id("outputcentercpt"); + GMTCELLS = module.get_id("gmtcells"); + OUTPUTBOUNDSCPT = module.get_id("outputboundscpt"); + OUTPUTVECTOR = module.get_id("outputvector"); + OUTPUTTRI = module.get_id("outputtri"); + OUTPUTVRML = module.get_id("outputvrml"); + OUTPUTKML = module.get_id("outputkml"); operatorID = cdo_operator_id(); @@ -636,7 +653,7 @@ public: if (varID != varID0) continue; if (recID > 0 && !lzon && !lmer) continue; - cdo_read_record(streamID, array.data(), &nmiss); + cdo_read_record(streamID, array.data(), &numMissVals); if (operatorID == OUTPUTCENTER2 && grid_is_circular) make_cyclic(array.data(), array2.data(), nlon, nlat); @@ -717,7 +734,7 @@ public: varray_copy(gridsize, array, uf); cdo_inq_record(streamID, &varID, &levelID); - cdo_read_record(streamID, vf.data(), &nmiss); + cdo_read_record(streamID, vf.data(), &numMissVals); output_vector(nlon, nlat, ninc, grid_center_lon, grid_center_lat, uf, vf); @@ -782,17 +799,5 @@ public: close() { cdo_stream_close(streamID); - - cdo_finish(); } }; - -void * -Outputgmt(void *process) -{ - ModuleOutputgmt outputgmt; - outputgmt.init(process); - outputgmt.run(); - outputgmt.close(); - return nullptr; -} diff --git a/src/Pack.cc b/src/Pack.cc index 14bba9954498050e933adb963ae6c582d2496f08..59549835cba1f5586905a9f4416a6431322bc35c 100644 --- a/src/Pack.cc +++ b/src/Pack.cc @@ -11,11 +11,8 @@ Pack pack Pack */ -#ifdef _OPENMP -#include <omp.h> -#endif - #include <climits> +#include <fstream> #include <cdi.h> @@ -24,6 +21,68 @@ #include "datetime.h" #include "cdo_default_values.h" #include "field_functions.h" +#include "pmlist.h" +#include "param_conversion.h" +#include "util_string.h" + +struct PackParams +{ + double add_offset{ 0 }; + double scale_factor{ 1 }; + std::string filename; + bool printParam{ false }; +}; + +struct PackEntry +{ + double add_offset{ 0 }; + double scale_factor{ 1 }; + std::string name; +}; + +static std::vector<PackEntry> +read_params_from_file(const std::string &filename) +{ + std::vector<PackEntry> packList; + + if (filename.size()) + { + std::ifstream file(filename); + if (!file.is_open()) cdo_abort("Open failed on: %s\n", filename); + + std::string line; + while (std::getline(file, line)) + { + auto keyValuesLine = split_string(line, " +"); + + KVList kvlist; + if (kvlist.parse_arguments(keyValuesLine) != 0) cdo_abort("Parse error!"); + if (Options::cdoVerbose) kvlist.print(); + + PackEntry packEntry; + for (const auto &kv : kvlist) + { + const auto &key = kv.key; + if (kv.nvalues > 1) cdo_abort("Too many values for parameter key >%s<!", key); + if (kv.nvalues < 1) cdo_abort("Missing value for parameter key >%s<!", key); + const auto &value = kv.values[0]; + + // clang-format off + if (key == "name") packEntry.name = parameter_to_word(value); + else if (key == "add_offset") packEntry.add_offset = parameter_to_double(value); + else if (key == "scale_factor") packEntry.scale_factor = parameter_to_double(value); + else cdo_abort("Invalid parameter key >%s<!", key); + // clang-format on + } + + if (!packEntry.name.empty()) packList.push_back(packEntry); + } + + file.close(); + } + + return packList; +} static int get_type_values(int datatype, double &tmin, double &tmax, double &tmv) @@ -67,14 +126,14 @@ compute_scale_and_offset(int datatype, double fmin, double fmax, double &scaleFa static MinMax field_min_max(Field &field) { - auto nmiss = field.nmiss; + auto numMissVals = field.numMissVals; auto missval = field.missval; auto len = field.size; if (field.memType == MemType::Float) - return nmiss ? varray_min_max_mv(len, field.vec_f, (float) missval) : varray_min_max(len, field.vec_f); + return numMissVals ? varray_min_max_mv(len, field.vec_f, (float) missval) : varray_min_max(len, field.vec_f); else - return nmiss ? varray_min_max_mv(len, field.vec_d, missval) : varray_min_max(len, field.vec_d); + return numMissVals ? varray_min_max_mv(len, field.vec_d, missval) : varray_min_max(len, field.vec_d); } static void @@ -96,8 +155,74 @@ field_change_missval(Field &field, double missval1, double missval2) } } -class ModulePack +static void +print_parameter(const PackParams ¶ms) { + std::stringstream outbuffer; + + outbuffer << "add_offset=" << params.add_offset; + outbuffer << ", scale_factor=" << params.scale_factor; + outbuffer << ", printpack=" << params.printParam; + outbuffer << ", filename=" << params.filename; + + cdo_verbose("%s", outbuffer.str()); +} + +static void +print_pack_params(const std::string& name, double addOffset, double scaleFactor) +{ + fprintf(stdout, "name=%s add_offset=%.9g scale_factor=%.9g\n", name.c_str(), addOffset, scaleFactor); +} + +static PackParams +get_parameter() +{ + PackParams params; + + auto pargc = cdo_operator_argc(); + if (pargc) + { + const auto &pargv = cdo_get_oper_argv(); + + KVList kvlist; + kvlist.name = cdo_module_name(); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); + if (Options::cdoVerbose) kvlist.print(); + + for (const auto &kv : kvlist) + { + const auto &key = kv.key; + if (kv.nvalues > 1) cdo_abort("Too many values for parameter key >%s<!", key); + if (kv.nvalues < 1) cdo_abort("Missing value for parameter key >%s<!", key); + const auto &value = kv.values[0]; + + // clang-format off + if (key == "add_offset") params.add_offset = parameter_to_double(value); + else if (key == "scale_factor") params.scale_factor = parameter_to_double(value); + else if (key == "printparam") params.printParam = parameter_to_bool(value); + else if (key == "filename") params.filename = parameter_to_word(value); + else cdo_abort("Invalid parameter key >%s<!", key); + // clang-format on + } + } + + return params; +} + +class Pack : public Process +{ +public: + using Process::Process; + inline static CdoModule module = { + .name = "Pack", + .operators = { { "pack", PackHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Pack>(module); + CdoStreamID streamID1; CdoStreamID streamID2; @@ -107,52 +232,20 @@ class ModulePack int vlistID1; int vlistID2; + PackParams params; + int datatype = CDI_DATATYPE_INT16; int nvars; VarList varList; - FieldVector3D vars; - DateTimeList dtlist; -public: +private: void - init(void *process) + run_method1() { - cdo_initialize(process); - - operator_check_argc(0); - - streamID1 = cdo_open_read(0); - - vlistID1 = cdo_stream_inq_vlist(streamID1); - vlistID2 = vlistDuplicate(vlistID1); - - taxisID1 = vlistInqTaxis(vlistID1); - taxisID2 = taxisDuplicate(taxisID1); - vlistDefTaxis(vlistID2, taxisID2); - - streamID2 = cdo_open_write(1); + FieldVector3D vars; + DateTimeList dtlist; - varList_init(varList, vlistID1); - - nvars = vlistNvars(vlistID1); - - if (CdoDefault::DataType != CDI_UNDEFID) - { - // 32-bit float routing error with CDI_DATATYPE_INT32|CDI_DATATYPE_UINT32 - if (CdoDefault::DataType == CDI_DATATYPE_FLT64 || CdoDefault::DataType == CDI_DATATYPE_FLT32 || - CdoDefault::DataType == CDI_DATATYPE_INT32 || CdoDefault::DataType == CDI_DATATYPE_UINT32) - { - cdo_warning("Changed default output datatype to int16"); - CdoDefault::DataType = datatype; - } - else { datatype = CdoDefault::DataType; } - } - } - - void - run() - { int tsID = 0; while (true) { @@ -187,7 +280,7 @@ public: const auto &var = varList[varID]; double fmin = undefValue, fmax = -undefValue; - size_t nmisspv = 0; + size_t numMissValspv = 0; for (int levelID = 0; levelID < var.nlevels; ++levelID) { @@ -196,11 +289,11 @@ public: if (t > 0 && var.isConstant) continue; auto &field = vars[t][varID][levelID]; - auto nmiss = field.nmiss; + auto numMissVals = field.numMissVals; - if (nmiss) nmisspv += nmiss; + if (numMissVals) numMissValspv += numMissVals; - if (nmiss < var.gridsize) + if (numMissVals < var.gridsize) { auto mm = field_min_max(field); fmin = std::min(fmin, mm.min); @@ -213,7 +306,7 @@ public: auto hasValidData = (is_not_equal(fmin, undefValue) && is_not_equal(fmax, -undefValue)); - if (nmisspv) + if (numMissValspv) { double tmin, tmax, missval2; if (!get_type_values(datatype, tmin, tmax, missval2)) @@ -230,7 +323,7 @@ public: if (t > 0 && var.isConstant) continue; auto &field = vars[t][varID][levelID]; - if (field.nmiss) field_change_missval(field, var.missval, missval2); + if (field.numMissVals) field_change_missval(field, var.missval, missval2); } } } @@ -244,6 +337,8 @@ public: auto memTypeIsFloat = (var.memType == MemType::Float); cdiDefKeyFloat(vlistID2, varID, CDI_KEY_ADDOFFSET, memTypeIsFloat ? (float) addOffset : addOffset); cdiDefKeyFloat(vlistID2, varID, CDI_KEY_SCALEFACTOR, memTypeIsFloat ? (float) scaleFactor : scaleFactor); + + if (params.printParam) print_pack_params(var.name, addOffset, scaleFactor); } } } @@ -272,6 +367,106 @@ public: } } + void + run_method2() + { + const auto packList = read_params_from_file(params.filename); + + for (int varID = 0; varID < nvars; ++varID) + { + const auto &var = varList[varID]; + + for (auto &packEntry: packList) + { + if (var.name == packEntry.name) + { + vlistDefVarDatatype(vlistID2, varID, datatype); + + auto scaleFactor = packEntry.scale_factor; + auto addOffset = packEntry.add_offset; + auto memTypeIsFloat = (var.memType == MemType::Float); + cdiDefKeyFloat(vlistID2, varID, CDI_KEY_ADDOFFSET, memTypeIsFloat ? (float) addOffset : addOffset); + cdiDefKeyFloat(vlistID2, varID, CDI_KEY_SCALEFACTOR, memTypeIsFloat ? (float) scaleFactor : scaleFactor); + + if (params.printParam) print_pack_params(var.name, addOffset, scaleFactor); + + break; + } + } + } + + cdo_def_vlist(streamID2, vlistID2); + + Field field; + + int tsID = 0; + while (true) + { + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + if (nrecs == 0) break; + + cdo_taxis_copy_timestep(taxisID2, taxisID1); + cdo_def_timestep(streamID2, tsID); + + for (int recID = 0; recID < nrecs; ++recID) + { + int varID, levelID; + cdo_inq_record(streamID1, &varID, &levelID); + field.init(varList[varID]); + cdo_read_record(streamID1, field); + + cdo_def_record(streamID2, varID, levelID); + cdo_write_record(streamID2, field); + } + + tsID++; + } + } + +public: + void + init() + { + params = get_parameter(); + if (Options::cdoVerbose) print_parameter(params); + + streamID1 = cdo_open_read(0); + + vlistID1 = cdo_stream_inq_vlist(streamID1); + vlistID2 = vlistDuplicate(vlistID1); + + taxisID1 = vlistInqTaxis(vlistID1); + taxisID2 = taxisDuplicate(taxisID1); + vlistDefTaxis(vlistID2, taxisID2); + + streamID2 = cdo_open_write(1); + + varList_init(varList, vlistID1); + + nvars = vlistNvars(vlistID1); + + if (CdoDefault::DataType != CDI_UNDEFID) + { + // 32-bit float rounding error with CDI_DATATYPE_INT32|CDI_DATATYPE_UINT32 + if (CdoDefault::DataType == CDI_DATATYPE_FLT64 || CdoDefault::DataType == CDI_DATATYPE_FLT32 + || CdoDefault::DataType == CDI_DATATYPE_INT32 || CdoDefault::DataType == CDI_DATATYPE_UINT32) + { + cdo_warning("Changed default output datatype to int16"); + CdoDefault::DataType = datatype; + } + else { datatype = CdoDefault::DataType; } + } + } + + void + run() + { + if (params.filename.empty()) + run_method1(); + else + run_method2(); + } + void close() { @@ -279,18 +474,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Pack(void *process) -{ - ModulePack pack; - pack.init(process); - pack.run(); - pack.close(); - - return nullptr; -} diff --git a/src/Pardup.cc b/src/Pardup.cc index 6de1cd2944e32a680c733e2b57d32964be760448..1187cdd2640feebb5478ce4fdabf1e60317575d6 100644 --- a/src/Pardup.cc +++ b/src/Pardup.cc @@ -18,8 +18,20 @@ #include "process_int.h" #include "param_conversion.h" -class ModulePardup +class Pardup : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Pardup", + .operators = { { "pardup"}, { "parmul"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Pardup> registration = RegisterEntry<Pardup>(module); + int PARDUP, PARMUL; CdoStreamID streamID1; CdoStreamID streamID2; @@ -32,16 +44,15 @@ class ModulePardup std::vector<RecordInfo> recList; Varray<double> array; Varray2D<double> vardata; - std::vector<std::vector<size_t>> varnmiss; + std::vector<std::vector<size_t>> varnumMissVals; public: void - init(void *process) + init() { - cdo_initialize(process); - const auto PARDUP = cdo_operator_add("pardup", 0, 0, nullptr); - const auto PARMUL = cdo_operator_add("parmul", 0, 0, nullptr); + PARDUP = module.get_id("pardup"); + PARMUL = module.get_id("parmul"); const auto operatorID = cdo_operator_id(); @@ -73,14 +84,14 @@ public: const auto gridsizemax = vlistGridsizeMax(vlistID1); array = Varray<double>(gridsizemax); vardata = Varray2D<double>(nvars); - varnmiss = std::vector<std::vector<size_t>>(nvars); + varnumMissVals = std::vector<std::vector<size_t>>(nvars); for (int varID = 0; varID < nvars; ++varID) { const auto gridsize = varList1[varID].gridsize; const auto nlevels = varList1[varID].nlevels; vardata[varID].resize(gridsize * nlevels); - varnmiss[varID].resize(nlevels); + varnumMissVals[varID].resize(nlevels); } for (int i = 1; i < nmul; ++i) @@ -116,9 +127,9 @@ public: const auto offset = gridsize * levelID; auto single = &vardata[varID][offset]; - size_t nmiss; - cdo_read_record(streamID1, single, &nmiss); - varnmiss[varID][levelID] = nmiss; + size_t numMissVals; + cdo_read_record(streamID1, single, &numMissVals); + varnumMissVals[varID][levelID] = numMissVals; } for (int i = 0; i < nmul; ++i) @@ -131,11 +142,11 @@ public: const auto gridsize = varList1[varID].gridsize; const auto offset = gridsize * levelID; auto single = &vardata[varID][offset]; - const auto nmiss = varnmiss[varID][levelID]; + const auto numMissVals = varnumMissVals[varID][levelID]; array_copy(gridsize, single, array.data()); cdo_def_record(streamID2, varID2, levelID); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); } tsID++; @@ -147,19 +158,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Pardup(void *process) -{ - ModulePardup pardup; - - pardup.init(process); - pardup.run(); - pardup.close(); - - return nullptr; -} diff --git a/src/Pinfo.cc b/src/Pinfo.cc index ab4be4988520a9ac0e334eb49be95ce29e071936..5904d90218ed2b890e96f8e182c074d5f8b2bae8 100644 --- a/src/Pinfo.cc +++ b/src/Pinfo.cc @@ -16,8 +16,20 @@ #include "printinfo.h" #include "cdo_zaxis.h" -class ModulePinfo +class Pinfo : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Pinfo", + .operators = { { "pinfo"}, { "pinfov"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Pinfo> registration = RegisterEntry<Pinfo>(module); + int PINFO, PINFOV; CdoStreamID streamID1; CdoStreamID streamID2; @@ -32,16 +44,13 @@ class ModulePinfo VarList varList1; - int PINFO, PINFOV; - public: void - init(void *process) + init() { - cdo_initialize(process); - PINFO = cdo_operator_add("pinfo", 0, 0, nullptr); - PINFOV = cdo_operator_add("pinfov", 0, 0, nullptr); + PINFO = module.get_id("pinfo"); + PINFOV = module.get_id("pinfov"); (void) (PINFO); // unused @@ -98,8 +107,8 @@ public: int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); const auto &var = varList1[varID]; indg += 1; @@ -114,15 +123,15 @@ public: auto level = cdo_zaxis_inq_level(var.zaxisID, levelID); fprintf(stdout, " %7g ", level); - fprintf(stdout, "%7zu %7zu :", gridsize, nmiss); + fprintf(stdout, "%7zu %7zu :", gridsize, numMissVals); - if (gridInqType(var.gridID) == GRID_SPECTRAL || (gridsize == 1 && nmiss == 0)) + if (gridInqType(var.gridID) == GRID_SPECTRAL || (gridsize == 1 && numMissVals == 0)) { fprintf(stdout, " %#12.5g\n", array1[0]); } else { - if (nmiss) + if (numMissVals) { auto mmm = varray_min_max_mean_mv(gridsize, array1, var.missval); arrmin = mmm.min; @@ -143,13 +152,13 @@ public: if (gridsize) { fprintf(stdout, "%#12.5g%#12.5g%#12.5g\n", arrmin, arrmean, arrmax); } else { fprintf(stdout, " nan\n"); } - if (imiss != nmiss && nmiss) fprintf(stdout, "Found %zu of %zu missing values!\n", imiss, nmiss); + if (imiss != numMissVals && numMissVals) fprintf(stdout, "Found %zu of %zu missing values!\n", imiss, numMissVals); } varray_copy(gridsize, array1, array2); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } tsID++; @@ -160,17 +169,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Pinfo(void *process) -{ - ModulePinfo pinfo; - pinfo.init(process); - pinfo.run(); - pinfo.close(); - return nullptr; -} diff --git a/src/Pressure.cc b/src/Pressure.cc index d6e660c0dc5a70ad8190ea3c19bd30ed19631e71..cd0e10ab0dc073fcddbb0c2c6eade560a9ec1dd7 100644 --- a/src/Pressure.cc +++ b/src/Pressure.cc @@ -8,9 +8,9 @@ /* This module contains the following operators: - Pressure pressure_fl Pressure on full hybrid levels - Pressure pressure_hl Pressure on half hybrid levels - Pressure deltap Difference of two half hybrid levels + Pressure pressure Pressure on model full-levels + Pressure pressure_half Pressure on model half-levels + Pressure delta_pressure Difference of two pressure half-levels */ #include <cdi.h> @@ -22,8 +22,25 @@ #include "stdnametable.h" #include "const.h" -class ModulePressure +class Pressure : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Pressure", + // clang-format off + .operators = { { "pressure", PressureHelp }, + { "pressure_half", PressureHelp }, + { "delta_pressure", PressureHelp } }, + // clang-format on + .aliases = { { "pressure_full", "pressure" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Pressure> registration = RegisterEntry<Pressure>(module); + + int PRESSURE_FULL, PRESSURE_HALF, DELTA_PRESSURE; CdoStreamID streamID1; CdoStreamID streamID2; @@ -42,23 +59,19 @@ class ModulePressure Varray<double> psProg; Varray<double> vct; Varray<double> array; - Varray<double> deltap; - Varray<double> fullPress; - Varray<double> halfPress; + Varray<double> deltaPressure; + Varray<double> pressureFull; + Varray<double> pressureHalf; int numHybridLevels = 0, numFullLevels = 0, numHalfLevels = 0; - int PRESSURE_FL, PRESSURE_HL, DELTAP; - public: void - init(void *process) + init() { - cdo_initialize(process); - - PRESSURE_FL = cdo_operator_add("pressure_fl", 0, 0, nullptr); - PRESSURE_HL = cdo_operator_add("pressure_hl", 0, 0, nullptr); - DELTAP = cdo_operator_add("deltap", 0, 0, nullptr); + PRESSURE_FULL = module.get_id("pressure"); + PRESSURE_HALF = module.get_id("pressure_half"); + DELTA_PRESSURE = module.get_id("delta_pressure"); operatorID = cdo_operator_id(); @@ -80,13 +93,13 @@ public: if (!hasVars3D) cdo_abort("No 3D variable with hybrid sigma pressure coordinate found!"); psProg = Varray<double>(gridsize); - deltap = Varray<double>(gridsize * numFullLevels); - fullPress = Varray<double>(gridsize * numFullLevels); - halfPress = Varray<double>(gridsize * numHalfLevels); + deltaPressure = Varray<double>(gridsize * numFullLevels); + pressureFull = Varray<double>(gridsize * numFullLevels); + pressureHalf = Varray<double>(gridsize * numHalfLevels); int zaxisID_PL = -1; int zaxisType = -1; - if (operatorID == PRESSURE_FL || operatorID == DELTAP) + if (operatorID == PRESSURE_FULL || operatorID == DELTA_PRESSURE) { if (numFullLevels == numHybridLevels) zaxisID_PL = zaxisID_ML; @@ -125,8 +138,8 @@ public: { cdo_print("Found:"); // clang-format off - if (-1 != varIDs.psID) cdo_print(" %s -> %s", var_stdname(surface_air_pressure), varList1[varIDs.psID].name); - if (-1 != varIDs.lnpsID) cdo_print(" LOG(%s) -> %s", var_stdname(surface_air_pressure), varList1[varIDs.lnpsID].name); + if (-1 != varIDs.psID) cdo_print(" %s -> %s", var_stdname(surface_air_pressure), varList1[varIDs.psID].name); + if (-1 != varIDs.lnpsID) cdo_print(" LOG(%s) -> %s", var_stdname(surface_air_pressure), varList1[varIDs.lnpsID].name); // clang-format on } @@ -170,6 +183,7 @@ public: streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); } + void run() { @@ -189,9 +203,9 @@ public: if (varID == pvarID) { - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); - if (nmiss) cdo_abort("Missing valus unsupported!"); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); + if (numMissVals) cdo_abort("Missing valus unsupported!"); } } @@ -206,29 +220,29 @@ public: auto mm = varray_min_max(psProg); if (mm.min < MIN_PS || mm.max > MAX_PS) cdo_warning("Surface pressure out of range (min=%g max=%g)!", mm.min, mm.max); - vct_to_hybrid_pressure(fullPress.data(), halfPress.data(), vct.data(), psProg.data(), numFullLevels, gridsize); + vct_to_hybrid_pressure(pressureFull.data(), pressureHalf.data(), vct.data(), psProg.data(), numFullLevels, gridsize); } double *pout = nullptr; int nlevels = 0; - if (operatorID == PRESSURE_FL) + if (operatorID == PRESSURE_FULL) { nlevels = numFullLevels; - pout = fullPress.data(); + pout = pressureFull.data(); } - else if (operatorID == DELTAP) + else if (operatorID == DELTA_PRESSURE) { nlevels = numFullLevels; for (int k = 0; k < numFullLevels; ++k) for (size_t i = 0; i < gridsize; ++i) - deltap[k * gridsize + i] = halfPress[(k + 1) * gridsize + i] - halfPress[k * gridsize + i]; + deltaPressure[k * gridsize + i] = pressureHalf[(k + 1) * gridsize + i] - pressureHalf[k * gridsize + i]; - pout = deltap.data(); + pout = deltaPressure.data(); } - else if (operatorID == PRESSURE_HL) + else if (operatorID == PRESSURE_HALF) { nlevels = numHalfLevels; - pout = halfPress.data(); + pout = pressureHalf.data(); } int varID = 0; @@ -248,17 +262,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Pressure(void *process) -{ - ModulePressure pressure; - pressure.init(process); - pressure.run(); - pressure.close(); - return nullptr; -} diff --git a/src/Query.cc b/src/Query.cc index 2230aac10f18d1bcda8641b89001c35ae5411d51..d69af6d45a8859f5549f5e4455e4b0a22979cdb9 100644 --- a/src/Query.cc +++ b/src/Query.cc @@ -14,9 +14,21 @@ #include "pmlist.h" #include "cdo_default_values.h" -class ModuleQuery +class Query : public Process { - int streamID1; //QueryStream +public: + using Process::Process; + inline static CdoModule module = { + .name = "Query", + .operators = { { "query", 0, 0, "queryentries"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, FilesOnly }, + }; + inline static RegisterEntry<Query> registration = RegisterEntry<Query>(module); + + int streamID1; // QueryStream CdoStreamID streamID2; int taxisID1; @@ -27,13 +39,9 @@ class ModuleQuery public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("query", 0, 0, "query entries"); - - //auto dataIsUnchanged = data_is_unchanged(); + // auto dataIsUnchanged = data_is_unchanged(); auto operatorID = cdo_operator_id(); @@ -47,7 +55,7 @@ public: PMList pmlist; KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(natts, cdo_get_oper_argv()) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(cdo_get_oper_argv()) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); auto pkvlist = &kvlist; @@ -71,7 +79,7 @@ public: set_query_parameter(*pkvlist, query); if (Options::cdoVerbose) cdiQueryPrint(query); - streamID1 = streamOpenReadQuery(cdo_get_stream_name(0), query); + streamID1 = streamOpenReadQuery(cdo_get_stream_name(0), query); if (streamID1 < 0) cdi_open_error(streamID1, "Open failed on >%s<", cdo_get_stream_name(0)); cdiQueryPrintEntriesNotFound(query); @@ -83,11 +91,11 @@ public: auto vlistID1 = streamInqVlist(streamID1); auto vlistID2 = vlistDuplicate(vlistID1); - taxisID1 = vlistInqTaxis(vlistID1); - taxisID2 = taxisDuplicate(taxisID1); + taxisID1 = vlistInqTaxis(vlistID1); + taxisID2 = taxisDuplicate(taxisID1); vlistDefTaxis(vlistID2, taxisID2); - streamID2 = cdo_open_write(1); + streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); varList_init(varList1, vlistID1); @@ -120,9 +128,9 @@ public: { field.init(varList1[varID]); if (field.memType == MemType::Float) - streamReadRecordF(streamID1, field.vec_f.data(), &field.nmiss); + streamReadRecordF(streamID1, field.vec_f.data(), &field.numMissVals); else - streamReadRecord(streamID1, field.vec_d.data(), &field.nmiss); + streamReadRecord(streamID1, field.vec_d.data(), &field.numMissVals); cdo_write_record(streamID2, field); } } @@ -136,18 +144,5 @@ public: { streamClose(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Query(void *process) -{ - ModuleQuery query; - query.init(process); - query.run(); - query.close(); - - return nullptr; -} diff --git a/src/Recttocomplex.cc b/src/Recttocomplex.cc index cd032345bdea3d6daaed07c77348bef8276d88fa..5773837799e005a865d124f6cd78193949b53581 100644 --- a/src/Recttocomplex.cc +++ b/src/Recttocomplex.cc @@ -9,8 +9,19 @@ #include "process_int.h" -class ModuleRecttocomplex +class Recttocomplex : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Recttocomplex", + .operators = { { "recttocomplex"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Recttocomplex> registration = RegisterEntry<Recttocomplex>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -28,9 +39,8 @@ class ModuleRecttocomplex public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -54,7 +64,7 @@ public: vlistDefVarDatatype(vlistID3, varID, datatype); } - streamID3 = cdo_open_write(2); + streamID3 = cdo_open_write(2); cdo_def_vlist(streamID3, vlistID3); auto gridsizemax = vlistGridsizeMax(vlistID1); @@ -87,9 +97,9 @@ public: cdo_inq_record(streamID2, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); - cdo_read_record(streamID2, array2.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); + cdo_read_record(streamID2, array2.data(), &numMissVals); auto gridsize = varList1[varID].gridsize; for (size_t i = 0; i < gridsize; ++i) @@ -98,7 +108,7 @@ public: array3[2 * i + 1] = array2[i]; } - cdo_write_record(streamID3, array3.data(), nmiss); + cdo_write_record(streamID3, array3.data(), numMissVals); } tsID++; @@ -112,19 +122,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID3); - - cdo_finish(); } }; - -void * -Recttocomplex(void *process) -{ - ModuleRecttocomplex recttocomplex; - - recttocomplex.init(process); - recttocomplex.run(); - recttocomplex.close(); - - return nullptr; -} diff --git a/src/Regres.cc b/src/Regres.cc index 87b61d8ba8122ac7c1548a04d9b0148087191f12..0cabd833811c7d029bb8d30c49c0129ea2a9f02a 100644 --- a/src/Regres.cc +++ b/src/Regres.cc @@ -34,7 +34,7 @@ regresGetParameter(bool &tstepIsEqual) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -52,8 +52,20 @@ regresGetParameter(bool &tstepIsEqual) } } -class ModuleRegres +class Regres : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Regres", + .operators = { { "regres", RegresHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Regres> registration = RegisterEntry<Regres>(module); + CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -74,10 +86,8 @@ class ModuleRegres public: void - init(void *process) + init() { - cdo_initialize(process); - tstepIsEqual = true; regresGetParameter(tstepIsEqual); @@ -137,8 +147,8 @@ public: recList[recID].set(varID, levelID); - size_t nmiss; - cdo_read_record(streamID1, field1.vec_d.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, field1.vec_d.data(), &numMissVals); auto gridsize = varList[varID].gridsize; auto missval = varList[varID].missval; @@ -206,18 +216,5 @@ public: { cdo_stream_close(streamID3); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Regres(void *process) -{ - ModuleRegres regress; - regress.init(process); - regress.run(); - regress.close(); - - return nullptr; -} diff --git a/src/Remapeta.cc b/src/Remapeta.cc index 20b4f847fff1230ce89b3c8cede997b109468a2f..0e9993616e9b2a6b9e0be99a60eed031601149d7 100644 --- a/src/Remapeta.cc +++ b/src/Remapeta.cc @@ -11,11 +11,12 @@ Remapeta remapeta Model to model level interpolation */ +#include <fstream> + #include <cdi.h> #include "process_int.h" #include "cdo_vlist.h" -#include "readline.h" #include "hetaeta.h" #include "vertical_interp.h" #include "stdnametable.h" @@ -85,27 +86,23 @@ ncctop(double cptop, long nlev, long nlevp1, const double *vct_a, const double * } static Varray<double> -vctFromFile(const char *filename) +vct_from_file(const std::string &filename) { - char line[1024], *pline; - int i = 0; constexpr int maxvct = 8192; - - auto fp = std::fopen(filename, "r"); - if (fp == nullptr) - { - perror(filename); - exit(EXIT_FAILURE); - } - Varray<double> vct; vct.resize(maxvct); - while (cdo::readline(fp, line, 1024)) + std::ifstream file(filename); + if (!file.is_open()) cdo_abort("Open failed on: %s\n", filename); + + int i = 0; + std::string line; + while (std::getline(file, line)) { if (line[0] == '#' || line[0] == '\0') continue; - pline = line; + char *lineCpy = strdup(line.c_str()); + char *pline = lineCpy; auto num = (int) strtod(pline, &pline); if (pline == nullptr) cdo_abort("Format error in VCT file %s!", filename); if (num != i) cdo_warning("Inconsistent VCT file, entry %d is %d.", i, num); @@ -117,10 +114,12 @@ vctFromFile(const char *filename) vct[i + maxvct / 2] = strtod(pline, &pline); + free(lineCpy); + i++; } - std::fclose(fp); + file.close(); auto nvct = 2 * i; auto nlevh = i - 1; @@ -163,15 +162,35 @@ field_copy_array(size_t len, const Field &field, T *array) } #define MAX_VARS3D 1024 - template <typename T> -class ModuleRemapeta +void +resize(Varray<T> &arr, size_t new_size) +{ + arr.resize(new_size); +} + +class Remapeta : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Remapeta", + .operators = { { "remapeta", 0, 0, "VCT filename", RemapetaHelp }, + { "remapeta_s", 0, 0, "VCT filename", RemapetaHelp }, + { "remapeta_z", 0, 0, "VCT filename", RemapetaHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Remapeta>(module); + + int REMAPETA, REMAPETA_S, REMAPETA_Z; double cconst = 1.0E-6; size_t nfis2gp = 0; int nvars3D = 0; Varray<double> fis2; - size_t nmissout = 0; + size_t numMissValsout = 0; bool lfis2 = false; int varids[MAX_VARS3D]; Varray<int> imiss; @@ -190,8 +209,13 @@ class ModuleRemapeta VarIDs varIDs; Varray<double> ps2; - Varray<T> t1, t2; - Varray<T> q1, q2; + + Varray<float> f_t1, f_t2; + Varray<float> f_q1, f_q2; + + Varray<double> d_t1, d_t2; + Varray<double> d_q1, d_q2; + Varray<double> tscor, pscor, secor; Varray<double> fis1; Varray<double> ps1; @@ -215,7 +239,8 @@ class ModuleRemapeta Varray<double> sum1, sum2; Varray<double> deltap1, deltap2; Varray<double> halfPress1, halfPress2; - Varray2D<T> vars1, vars2; + Varray2D<float> f_vars1, f_vars2; + Varray2D<double> d_vars1, d_vars2; Varray<double> vct1; Varray<double> vct2; @@ -226,20 +251,115 @@ class ModuleRemapeta double *a2; double *b2; - int REMAPETA_S, REMAPETA_Z; + template <typename T> + void + do_work(long nctop, Varray<T> &t2, Varray<T> &q2, Varray2D<T> &vars1, Varray2D<T> &vars2) + { + if (ltq) + { + int varID = varIDs.tempID; + for (int levelID = 0; levelID < varList2[varID].nlevels; ++levelID) + { + auto offset = gridsize * levelID; + auto single2 = &t2[offset]; + + auto mm = array_min_max_mask(gridsize, single2, imiss); + if (mm.min < MIN_T || mm.max > MAX_T) + cdo_warning("Output temperature at level %d out of range (min=%g max=%g)!", levelID + 1, mm.min, mm.max); + + setmissval(gridsize, imiss, missval, single2); + cdo_def_record(streamID2, varID, levelID); + + if (memType == MemType::Float) + cdo_write_record_f(streamID2, (float *) single2, numMissValsout); + else + cdo_write_record(streamID2, (double *) single2, numMissValsout); + } + + varID = varIDs.humID; + for (int levelID = 0; levelID < varList2[varID].nlevels; ++levelID) + { + auto offset = gridsize * levelID; + auto single2 = &q2[offset]; + + corr_hum(gridsize, single2, MIN_Q); + + if (levelID < nctop) + for (size_t i = 0; i < gridsize; ++i) single2[i] = cconst; + + auto mm = array_min_max_mask(gridsize, single2, imiss); + if (mm.min < MIN_Q || mm.max > MAX_Q) + cdo_warning("Output humidity at level %d out of range (min=%g max=%g)!", levelID + 1, mm.min, mm.max); + + setmissval(gridsize, imiss, missval, single2); + cdo_def_record(streamID2, varID, levelID); + + if (memType == MemType::Float) + cdo_write_record_f(streamID2, (float *) single2, numMissValsout); + else + cdo_write_record(streamID2, (double *) single2, numMissValsout); + } + } + + for (int iv = 0; iv < nvars3D; ++iv) + { + int varID = varids[iv]; + + auto nlevels = varList2[varID].nlevels; + + if (operatorID == REMAPETA_S) + { + vertSum(sum1, vars1[iv], gridsize, numFullLevels1); + vertSum(sum2, vars2[iv], gridsize, numFullLevels2); + } + else if (operatorID == REMAPETA_Z) + { + vct_to_hybrid_pressure((double *) nullptr, halfPress1.data(), vct1.data(), ps1.data(), numFullLevels1, gridsize); + for (int k = 0; k < numFullLevels1; ++k) + for (size_t i = 0; i < gridsize; ++i) + { + deltap1[k * gridsize + i] = halfPress1[(k + 1) * gridsize + i] - halfPress1[k * gridsize + i]; + deltap1[k * gridsize + i] = std::log(deltap1[k * gridsize + i]); + } + vertSumw(sum1, vars1[iv], gridsize, numFullLevels1, deltap1); + + vct_to_hybrid_pressure((double *) nullptr, halfPress2.data(), vct2.data(), ps1.data(), numFullLevels2, gridsize); + for (int k = 0; k < numFullLevels2; ++k) + for (size_t i = 0; i < gridsize; ++i) + { + deltap2[k * gridsize + i] = halfPress2[(k + 1) * gridsize + i] - halfPress2[k * gridsize + i]; + deltap2[k * gridsize + i] = std::log(deltap2[k * gridsize + i]); + } + vertSumw(sum2, vars2[iv], gridsize, numFullLevels2, deltap2); + } + + for (int levelID = 0; levelID < nlevels; ++levelID) + { + auto offset = gridsize * levelID; + auto single2 = &vars2[iv][offset]; + + if (operatorID == REMAPETA_S || operatorID == REMAPETA_Z) + for (size_t i = 0; i < gridsize; ++i) single2[i] = single2[i] * sum1[i] / sum2[i]; + + setmissval(gridsize, imiss, missval, single2); + cdo_def_record(streamID2, varID, levelID); + + if (memType == MemType::Float) + cdo_write_record_f(streamID2, (float *) single2, numMissValsout); + else + cdo_write_record(streamID2, (double *) single2, numMissValsout); + } + } + } public: void - init(void *process) + init() { memType = Options::CDO_Memtype; - cdo_initialize(process); - // clang-format off - cdo_operator_add("remapeta", 0, 0, "VCT file name"); - REMAPETA_S = cdo_operator_add("remapeta_s", 0, 0, "VCT file name"); - REMAPETA_Z = cdo_operator_add("remapeta_z", 0, 0, "VCT file name"); - // clang-format on + REMAPETA_S = module.get_id("remapeta_s"); + REMAPETA_Z = module.get_id("remapeta_z"); operatorID = cdo_operator_id(); @@ -256,8 +376,8 @@ public: } } - vct2 = vctFromFile(cdo_operator_argv(0).c_str()); - const int nvct2 = vct2.size(); + vct2 = vct_from_file(cdo_operator_argv(0)); + int nvct2 = vct2.size(); numFullLevels2 = nvct2 / 2 - 1; a2 = vct2.data(); @@ -282,16 +402,16 @@ public: fis2.resize(nfis2gp); - size_t nmiss; - streamReadRecord(streamID, fis2.data(), &nmiss); + size_t numMissVals; + streamReadRecord(streamID, fis2.data(), &numMissVals); - if (nmiss) + if (numMissVals) { missval = vlistInqVarMissval(vlistID1, varID); imiss.resize(nfis2gp); for (size_t i = 0; i < nfis2gp; ++i) imiss[i] = dbl_is_equal(fis2[i], missval); - nmissout = nmiss; + numMissValsout = numMissVals; } // check range of surface_geopotential @@ -431,30 +551,42 @@ public: if (lfis2 && gridsize != nfis2gp) cdo_abort("Orographies have different grid size!"); ps2 = Varray<double>(gridsize); + if (ltq) { tscor.resize(gridsize); pscor.resize(gridsize); secor.resize(gridsize); - t1.resize(gridsize * numFullLevels1); - q1.resize(gridsize * numFullLevels1); + auto gs1 = gridsize * numFullLevels1; + auto gs2 = gridsize * numFullLevels2; + (memType == MemType::Float) ? resize(f_t1, gs1) : resize(d_t1, gs1); + (memType == MemType::Float) ? resize(f_q1, gs1) : resize(d_q1, gs1); - t2.resize(gridsize * numFullLevels2); - q2.resize(gridsize * numFullLevels2); + (memType == MemType::Float) ? resize(f_t2, gs2) : resize(d_t2, gs2); + (memType == MemType::Float) ? resize(f_q2, gs2) : resize(d_q2, gs2); } if (nvars3D) { - vars1.resize(nvars); - vars2.resize(nvars); - for (int varID = 0; varID < nvars3D; ++varID) vars1[varID].resize(gridsize * numFullLevels1); - for (int varID = 0; varID < nvars3D; ++varID) vars2[varID].resize(gridsize * numFullLevels2); + (memType == MemType::Float) ? resize(f_vars1, nvars) : resize(d_vars1, nvars); + (memType == MemType::Float) ? resize(f_vars2, nvars) : resize(d_vars2, nvars); + + if (memType == MemType::Float) + { + for (int varID = 0; varID < nvars3D; ++varID) f_vars1[varID].resize(gridsize * numFullLevels1); + for (int varID = 0; varID < nvars3D; ++varID) f_vars2[varID].resize(gridsize * numFullLevels2); + } + else + { + for (int varID = 0; varID < nvars3D; ++varID) d_vars1[varID].resize(gridsize * numFullLevels1); + for (int varID = 0; varID < nvars3D; ++varID) d_vars2[varID].resize(gridsize * numFullLevels2); + } } if (zaxisID_ML != -1 && varIDs.sgeopotID == -1) { - varray_fill(fis1, 0.0); + ranges::fill(fis1, 0.0); if (ltq) cdo_warning("%s not found - set to zero!", var_stdname(surface_geopotential)); } @@ -481,7 +613,6 @@ public: void run() { - int tsID = 0; while (true) { @@ -518,9 +649,11 @@ public: field_copy_array(gridsize, field, ps1.data()); } else if (ltq && varID == varIDs.tempID) - field_copy_array(gridsize, field, &t1[offset]); + if (memType == MemType::Float) { field_copy_array(gridsize, field, &f_t1[offset]); } + else { field_copy_array(gridsize, field, &d_t1[offset]); } else if (ltq && varID == varIDs.humID) - field_copy_array(gridsize, field, &q1[offset]); + if (memType == MemType::Float) { field_copy_array(gridsize, field, &f_q1[offset]); } + else { field_copy_array(gridsize, field, &d_q1[offset]); } // else if ( zaxisID == zaxisID_ML ) else if (zaxisInqType(zaxisID) == ZAXIS_HYBRID && nlevels == numFullLevels1) { @@ -530,7 +663,8 @@ public: if (i == nvars3D) cdo_abort("Internal error, 3D variable not found!"); - field_copy_array(gridsize, field, &vars1[i][offset]); + if (memType == MemType::Float) { field_copy_array(gridsize, field, &f_vars1[i][offset]); } + else { field_copy_array(gridsize, field, &d_vars1[i][offset]); } } else { @@ -565,7 +699,11 @@ public: for (int levelID = 0; levelID < varList1[varID].nlevels; ++levelID) { auto offset = gridsize * levelID; - auto mm = array_min_max_mask(gridsize, &t1[offset], imiss); + auto mm = [&]() { + if (memType == MemType::Float) { return array_min_max_mask(gridsize, &f_t1[offset], imiss); } + else { return array_min_max_mask(gridsize, &d_t1[offset], imiss); } + }(); + if (mm.min < MIN_T || mm.max > MAX_T) cdo_warning("Input temperature at level %d out of range (min=%g max=%g)!", levelID + 1, mm.min, mm.max); } @@ -574,9 +712,16 @@ public: for (int levelID = 0; levelID < varList1[varID].nlevels; ++levelID) { auto offset = gridsize * levelID; - corr_hum(gridsize, &q1[offset], MIN_Q); - auto mm = array_min_max_mask(gridsize, &q1[offset], imiss); + if (memType == MemType::Float) + corr_hum(gridsize, &f_q1[offset], MIN_Q); + else + corr_hum(gridsize, &d_q1[offset], MIN_Q); + + auto mm = [&]() { + if (memType == MemType::Float) { return array_min_max_mask(gridsize, &f_q1[offset], imiss); } + else { return array_min_max_mask(gridsize, &d_q1[offset], imiss); } + }(); if (mm.min < MIN_Q || mm.max > MAX_Q) cdo_warning("Input humidity at level %d out of range (min=%g max=%g)!", levelID + 1, mm.min, mm.max); } @@ -584,8 +729,12 @@ public: if (nvars3D || ltq) { - hetaeta(ltq, gridsize, imiss.data(), numFullLevels1, a1, b1, fis1, ps1, t1, q1, numFullLevels2, a2, b2, fis2, ps2, t2, - q2, nvars3D, vars1, vars2, tscor, pscor, secor); + if (memType == MemType::Float) + hetaeta(ltq, gridsize, imiss.data(), numFullLevels1, a1, b1, fis1, ps1, f_t1, f_q1, numFullLevels2, a2, b2, fis2, ps2, + f_t2, f_q2, nvars3D, f_vars1, f_vars2, tscor, pscor, secor); + else + hetaeta(ltq, gridsize, imiss.data(), numFullLevels1, a1, b1, fis1, ps1, d_t1, d_q1, numFullLevels2, a2, b2, fis2, ps2, + d_t2, d_q2, nvars3D, d_vars1, d_vars2, tscor, pscor, secor); } long nctop = (cptop > 0) ? ncctop(cptop, (long) numFullLevels2, (long) numFullLevels2 + 1, a2, b2) : 0; @@ -596,7 +745,7 @@ public: int levelID = 0; setmissval(gridsize, imiss, missval, fis2.data()); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, fis2.data(), nmissout); + cdo_write_record(streamID2, fis2.data(), numMissValsout); } if (zaxisID_ML != -1 && varIDs.lnpsID != -1) @@ -608,104 +757,11 @@ public: int levelID = 0; setmissval(gridsize, imiss, missval, ps2.data()); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, ps2.data(), nmissout); - } - - if (ltq) - { - int varID = varIDs.tempID; - for (int levelID = 0; levelID < varList2[varID].nlevels; ++levelID) - { - auto offset = gridsize * levelID; - auto single2 = &t2[offset]; - - auto mm = array_min_max_mask(gridsize, single2, imiss); - if (mm.min < MIN_T || mm.max > MAX_T) - cdo_warning("Output temperature at level %d out of range (min=%g max=%g)!", levelID + 1, mm.min, mm.max); - - setmissval(gridsize, imiss, missval, single2); - cdo_def_record(streamID2, varID, levelID); - - if (memType == MemType::Float) - cdo_write_record_f(streamID2, (float *) single2, nmissout); - else - cdo_write_record(streamID2, (double *) single2, nmissout); - } - - varID = varIDs.humID; - for (int levelID = 0; levelID < varList2[varID].nlevels; ++levelID) - { - auto offset = gridsize * levelID; - auto single2 = &q2[offset]; - - corr_hum(gridsize, single2, MIN_Q); - - if (levelID < nctop) - for (size_t i = 0; i < gridsize; ++i) single2[i] = cconst; - - auto mm = array_min_max_mask(gridsize, single2, imiss); - if (mm.min < MIN_Q || mm.max > MAX_Q) - cdo_warning("Output humidity at level %d out of range (min=%g max=%g)!", levelID + 1, mm.min, mm.max); - - setmissval(gridsize, imiss, missval, single2); - cdo_def_record(streamID2, varID, levelID); - - if (memType == MemType::Float) - cdo_write_record_f(streamID2, (float *) single2, nmissout); - else - cdo_write_record(streamID2, (double *) single2, nmissout); - } + cdo_write_record(streamID2, ps2.data(), numMissValsout); } - for (int iv = 0; iv < nvars3D; ++iv) - { - int varID = varids[iv]; - - auto nlevels = varList2[varID].nlevels; - - if (operatorID == REMAPETA_S) - { - vertSum(sum1, vars1[iv], gridsize, numFullLevels1); - vertSum(sum2, vars2[iv], gridsize, numFullLevels2); - } - else if (operatorID == REMAPETA_Z) - { - vct_to_hybrid_pressure((double *) nullptr, halfPress1.data(), vct1.data(), ps1.data(), numFullLevels1, gridsize); - for (int k = 0; k < numFullLevels1; ++k) - for (size_t i = 0; i < gridsize; ++i) - { - deltap1[k * gridsize + i] = halfPress1[(k + 1) * gridsize + i] - halfPress1[k * gridsize + i]; - deltap1[k * gridsize + i] = std::log(deltap1[k * gridsize + i]); - } - vertSumw(sum1, vars1[iv], gridsize, numFullLevels1, deltap1); - - vct_to_hybrid_pressure((double *) nullptr, halfPress2.data(), vct2.data(), ps1.data(), numFullLevels2, gridsize); - for (int k = 0; k < numFullLevels2; ++k) - for (size_t i = 0; i < gridsize; ++i) - { - deltap2[k * gridsize + i] = halfPress2[(k + 1) * gridsize + i] - halfPress2[k * gridsize + i]; - deltap2[k * gridsize + i] = std::log(deltap2[k * gridsize + i]); - } - vertSumw(sum2, vars2[iv], gridsize, numFullLevels2, deltap2); - } - - for (int levelID = 0; levelID < nlevels; ++levelID) - { - auto offset = gridsize * levelID; - auto single2 = &vars2[iv][offset]; - - if (operatorID == REMAPETA_S || operatorID == REMAPETA_Z) - for (size_t i = 0; i < gridsize; ++i) single2[i] = single2[i] * sum1[i] / sum2[i]; - - setmissval(gridsize, imiss, missval, single2); - cdo_def_record(streamID2, varID, levelID); - - if (memType == MemType::Float) - cdo_write_record_f(streamID2, (float *) single2, nmissout); - else - cdo_write_record(streamID2, (double *) single2, nmissout); - } - } + if (memType == MemType::Float) { do_work(nctop, f_t2, f_q2, f_vars1, f_vars2); } + else { do_work(nctop, d_t2, d_q2, d_vars1, d_vars2); } tsID++; } @@ -714,30 +770,7 @@ public: void close() { - cdo_stream_close(streamID2); cdo_stream_close(streamID1); - cdo_finish(); } }; - -void * -Remapeta(void *process) -{ - if (Options::CDO_Memtype == MemType::Float) - { - ModuleRemapeta<float> remapeta; - remapeta.init(process); - remapeta.run(); - remapeta.close(); - } - else - { - ModuleRemapeta<double> remapeta; - remapeta.init(process); - remapeta.run(); - remapeta.close(); - } - - return nullptr; -}; diff --git a/src/Remapgrid.cc b/src/Remapgrid.cc index d2f8e179c92a52f74a2c4e82d1cf9334f5e41b81..9e77955afb495c126cf0158de300953d59275006 100644 --- a/src/Remapgrid.cc +++ b/src/Remapgrid.cc @@ -211,7 +211,7 @@ remap_read_weights(const std::string &remapWeightsFile, int gridID1, int gridID2 if (gridInqType(gridID1) == GRID_GME) gridsize = remap0.srcGrid.size; for (size_t i = 0; i < gridsize; ++i) - if (remap0.srcGrid.mask[i] == false) remap0.nmiss++; + if (remap0.srcGrid.mask[i] == false) remap0.numMissVals++; auto gridsize2 = gridInqSize(gridID2); if (gridInqType(gridID2) == GRID_GME) @@ -232,7 +232,7 @@ remap_read_weights(const std::string &remapWeightsFile, int gridID1, int gridID2 return remapSwitches; } -double getPlanetRadius(int gridID); +double get_planet_radius_in_meter(int gridID); static void print_node_info(int gridID2, const RemapVars &rv, const RemapGrid &srcGrid) @@ -251,16 +251,13 @@ print_node_info(int gridID2, const RemapVars &rv, const RemapGrid &srcGrid) auto lon1 = RAD2DEG * llpoint.lon; auto lat1 = RAD2DEG * llpoint.lat; if (lon1 > 180.0) lon1 -= 360.0; - auto distance - = orthodrome(DEG2RAD * lon1, DEG2RAD * lat1, DEG2RAD * lon2, DEG2RAD * lat2) * getPlanetRadius(srcGrid.gridID) / 1000; + auto distance = orthodrome(DEG2RAD * lon1, DEG2RAD * lat1, DEG2RAD * lon2, DEG2RAD * lat2) + * get_planet_radius_in_meter(srcGrid.gridID) / 1000; cdo_print("Target Point: lon=%g/lat=%g Source Point: index=%zu lon=%g/lat=%g distance=%.3fkm", lon2, lat2, srcCellIndex + 1, lon1, lat1, distance); } - else if (rv.numLinks == 0) - { - cdo_print("Target Point: lon=%g/lat=%g Source Point: out of grid area", lon2, lat2); - } + else if (rv.numLinks == 0) { cdo_print("Target Point: lon=%g/lat=%g Source Point: out of grid area", lon2, lat2); } } void @@ -271,26 +268,31 @@ obsolete_operator(const std::string &operatorOld, const std::string &operatorNew cdo_warning("%s", outStr); } -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("remap", REMAP, 0, nullptr); - cdo_operator_add("remapcon", REMAPCON, 0, nullptr); - cdo_operator_add("remapycon2test",REMAPYCON2, 0, nullptr); - cdo_operator_add("remapscon", REMAPSCON, 0, nullptr); - cdo_operator_add("remapscon2", REMAPSCON2, 0, nullptr); - cdo_operator_add("remapbil", REMAPBIL, 0, nullptr); - cdo_operator_add("remapbic", REMAPBIC, 0, nullptr); - cdo_operator_add("remapdis", REMAPDIS, 0, nullptr); - cdo_operator_add("remapnn", REMAPNN, 0, nullptr); - cdo_operator_add("remaplaf", REMAPLAF, 0, nullptr); - cdo_operator_add("remapavgtest", REMAPAVG, 0, nullptr); - // clang-format on -} - -class ModuleRemapgrid +class Remapgrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Remapgrid", + // clang-format off + .operators = { { "remap", REMAP, 0, RemapHelp }, + { "remapbil", REMAPBIL, 0, RemapbilHelp }, + { "remapbic", REMAPBIC, 0, RemapbicHelp }, + { "remapnn", REMAPNN, 0, RemapnnHelp }, + { "remapdis", REMAPDIS, 0, RemapdisHelp }, + { "remapcon", REMAPCON, 0, RemapconHelp }, + { "remapycon2test", REMAPYCON2, 0, nullptr}, + { "remapscon", REMAPSCON, 0, nullptr}, + { "remapscon2", REMAPSCON2, 0, nullptr}, + { "remaplaf", REMAPLAF, 0, RemaplafHelp }, + { "remapavgtest", REMAPAVG, 0, nullptr} }, + // clang-format on + .aliases = { { "remapycon", "remapcon" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Remapgrid> registration = RegisterEntry<Remapgrid>(module); RemapSwitches remapSwitches; bool remap_genweights = Options::REMAP_genweights; int numRemaps = 0; @@ -330,12 +332,8 @@ class ModuleRemapgrid public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -368,10 +366,7 @@ public: if (inum < 1) cdo_abort("Number of nearest neighbors out of range (>0)!"); numNeighbors = inum; } - else - { - operator_check_argc(1); - } + else { operator_check_argc(1); } } gridID2 = cdo_define_grid(cdo_operator_argv(0)); @@ -392,7 +387,7 @@ public: remapGrids = remap_set_grids(vlistID1, varList1); - auto numRemapGrids = std::count_if(remapGrids.begin(), remapGrids.end(), [](auto flag) { return (flag == true); }); + auto numRemapGrids = ranges::count_if(remapGrids, [](auto flag) { return (flag == true); }); if (numRemapGrids == 0) cdo_abort("No remappable grid found!"); auto numGrids = vlistNgrids(vlistID1); @@ -420,10 +415,7 @@ public: // printf("read remapWeightsFile %d: %s\n", numRemaps+1, remapWeightsFile.c_str()); auto &remap = remaps[numRemaps]; remapSwitches = remap_read_weights(remapWeightsFile, gridID1, gridID2, remap, extrapolateIsSet, remapExtrapolate); - if (numRemaps == 0) - { - operfunc = maptype_to_operfunc(remapSwitches); - } + if (numRemaps == 0) { operfunc = maptype_to_operfunc(remapSwitches); } else if (operfunc != maptype_to_operfunc(remapSwitches)) { cdo_abort("Remapping method changed in input weights files!"); @@ -497,7 +489,7 @@ public: auto &var = varList1[varID]; field1.init(var); cdo_read_record(streamID1, field1); - auto nmiss1 = useMask ? field1.nmiss : 0; + auto numMissVals1 = useMask ? field1.numMissVals : 0; field2.init(varList2[varID]); @@ -511,7 +503,7 @@ public: if (gridIsCircular(var.gridID) && !extrapolateIsSet) remapExtrapolate = true; - remap_set_mask(var.gridsize, field1, nmiss1, var.missval, imask); + remap_set_mask(var.gridsize, field1, numMissVals1, var.missval, imask); int remapIndex = -1; for (remapIndex = numRemaps - 1; remapIndex >= 0; remapIndex--) @@ -519,7 +511,7 @@ public: auto &remap = remaps[remapIndex]; if (var.gridID == remap.gridID) { - if ((useMask && nmiss1 == remap.nmiss && imask == remap.srcGrid.mask) || !useMask) + if ((useMask && numMissVals1 == remap.numMissVals && imask == remap.srcGrid.mask) || !useMask) { remap.nused++; break; @@ -577,7 +569,7 @@ public: } remap.gridID = var.gridID; - remap.nmiss = nmiss1; + remap.numMissVals = numMissVals1; if (var.gridType == GRID_GME) { @@ -589,16 +581,16 @@ public: if (mapType == RemapMethod::CONSERV_SCRIP || mapType == RemapMethod::CONSERV) { - varray_fill(remap.srcGrid.cell_area, 0.0); - varray_fill(remap.srcGrid.cell_frac, 0.0); - varray_fill(remap.tgtGrid.cell_area, 0.0); + ranges::fill(remap.srcGrid.cell_area, 0.0); + ranges::fill(remap.srcGrid.cell_frac, 0.0); + ranges::fill(remap.tgtGrid.cell_area, 0.0); } - varray_fill(remap.tgtGrid.cell_frac, 0.0); + ranges::fill(remap.tgtGrid.cell_frac, 0.0); // initialize some remapping variables remap_vars_init(mapType, remapOrder, remap.vars); - remap_print_info(operfunc, remap_genweights, remap.srcGrid, remap.tgtGrid, nmiss1, remapSwitches.numNeighbors); + remap_print_info(operfunc, remap_genweights, remap.srcGrid, remap.tgtGrid, numMissVals1, remapSwitches.numNeighbors); if (remap_genweights) { @@ -646,10 +638,7 @@ public: else remap_field(field2, var.missval, gridsize2, remap.vars, field1, gradients); } - else - { - remap_field(remapSwitches, remap, field1, field2); - } + else { remap_field(remapSwitches, remap, field1, field2); } if (operfunc == REMAPSCON || operfunc == REMAPSCON2 || operfunc == REMAPCON || operfunc == REMAPYCON2) { @@ -666,7 +655,7 @@ public: if (gridInqType(gridID2) == GRID_GME) restore_gme_grid(field2, remap.tgtGrid); - field2.nmiss = field_num_mv(field2); + field2.numMissVals = field_num_mv(field2); } cdo_def_record(streamID2, varID, levelID); @@ -677,7 +666,7 @@ public: } if (doRemap && remap_genweights && remaps[0].nused == 0) - remap_print_warning(remapWeightsFiles[0], operfunc, remaps[0].srcGrid, remaps[0].nmiss); + remap_print_warning(remapWeightsFiles[0], operfunc, remaps[0].srcGrid, remaps[0].numMissVals); for (int remapIndex = 0; remapIndex < numRemaps; remapIndex++) { @@ -696,18 +685,5 @@ public: cdo_stream_close(streamID1); gridDestroy(gridID2); - - cdo_finish(); } }; - -void * -Remapgrid(void *process) -{ - ModuleRemapgrid remapGrid; - remapGrid.init(process); - remapGrid.run(); - remapGrid.close(); - - return nullptr; -} diff --git a/src/Remapstat.cc b/src/Remapstat.cc index 1f5a78810afb605b71a530ffb44d930c68acc29e..a2cfb4df5ea08d4b94b39a4062c33fe2fbb2e112 100644 --- a/src/Remapstat.cc +++ b/src/Remapstat.cc @@ -424,7 +424,7 @@ get_bin_num(double lon1, double lat1, size_t numBins, const std::vector<double> } static void -check_vmask(std::vector<char> vmask) +check_vmask(const std::vector<char> &vmask) { constexpr int maxVals = 128; size_t vm[maxVals] = { 0 }; @@ -540,10 +540,7 @@ gen_mapdata(int gridID1, int gridID2) : calc_maxdist(i, nv, lon2, lat2, xbounds, ybounds); if (maxdist < 2.0) { maxdist = 1.01 * std::sqrt(maxdist); } - else - { - cdo_abort("Search radius of target grid cell[%zu] > 90 degrees!", i + 1); - } + else { cdo_abort("Search radius of target grid cell[%zu] > 90 degrees!", i + 1); } auto numIndices = grid_point_search_distance_qnearest(gps, maxdist, lon2, lat2, ndistMax, indices, dist); // printf("%zu numIndices %zu\n", i+1, numIndices); @@ -582,30 +579,30 @@ gen_mapdata(int gridID1, int gridID2) template <typename T> static T -remap_kernel(int operfunc, const Varray<size_t> &indices, size_t &nmiss2, Field &field, Varray<T> &fieldvec, const Varray<T> &vec1, +remap_kernel(int operfunc, const Varray<size_t> &indices, size_t &numMissVals2, Field &field, Varray<T> &fieldvec, const Varray<T> &vec1, T missval) { T value; auto nvalues = indices.size(); if (nvalues) { - field.nmiss = 0; + field.numMissVals = 0; for (size_t k = 0; k < nvalues; ++k) { auto v1 = vec1[indices[k]]; fieldvec[k] = v1; - if (dbl_is_equal(v1, missval)) field.nmiss++; + if (dbl_is_equal(v1, missval)) field.numMissVals++; } field.size = nvalues; field.missval = missval; value = field_function(field, operfunc); - if (dbl_is_equal(value, missval)) nmiss2++; + if (dbl_is_equal(value, missval)) numMissVals2++; } else { value = missval; - nmiss2++; + numMissVals2++; } return value; @@ -619,9 +616,9 @@ remap_field(const Varray2D<size_t> &mapdata, const Field &field1, Field &field2, auto gridsize2 = gridInqSize(field2.grid); cdo::timer timer; - size_t nmiss2 = 0; + size_t numMissVals2 = 0; #ifdef _OPENMP -#pragma omp parallel for default(shared) schedule(static) reduction(+ : nmiss2) +#pragma omp parallel for default(shared) schedule(static) reduction(+ : numMissVals2) #endif for (size_t i = 0; i < gridsize2; ++i) { @@ -639,9 +636,9 @@ remap_field(const Varray2D<size_t> &mapdata, const Field &field1, Field &field2, double rvalue = 0.0; if (field1.memType == MemType::Float) - rvalue = remap_kernel(operfunc, indices, nmiss2, field, field.vec_f, field1.vec_f, (float) missval); + rvalue = remap_kernel(operfunc, indices, numMissVals2, field, field.vec_f, field1.vec_f, (float) missval); else - rvalue = remap_kernel(operfunc, indices, nmiss2, field, field.vec_d, field1.vec_d, missval); + rvalue = remap_kernel(operfunc, indices, numMissVals2, field, field.vec_d, field1.vec_d, missval); if (field2.memType == MemType::Float) field2.vec_f[i] = rvalue; @@ -649,33 +646,36 @@ remap_field(const Varray2D<size_t> &mapdata, const Field &field1, Field &field2, field2.vec_d[i] = rvalue; } - field2.nmiss = nmiss2; + field2.numMissVals = numMissVals2; if (Options::cdoVerbose) cdo_print("Remap: %.3f seconds", timer.elapsed()); } -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("remaprange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("remapmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("remapmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("remapsum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("remapmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("remapavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("remapstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("remapstd1", FieldFunc_Std1, 0, nullptr); - cdo_operator_add("remapvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("remapvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("remapskew", FieldFunc_Skew, 0, nullptr); - cdo_operator_add("remapkurt", FieldFunc_Kurt, 0, nullptr); - cdo_operator_add("remapmedian", FieldFunc_Median, 0, nullptr); - // clang-format on -} - -class ModuleRemapstat +class Remapstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Remapstat", + .operators = { { "remaprange", FieldFunc_Range, 0, RemapstatHelp }, + { "remapmin", FieldFunc_Min, 0, RemapstatHelp }, + { "remapmax", FieldFunc_Max, 0, RemapstatHelp }, + { "remapsum", FieldFunc_Sum, 0, RemapstatHelp }, + { "remapmean", FieldFunc_Mean, 0, RemapstatHelp }, + { "remapavg", FieldFunc_Avg, 0, RemapstatHelp }, + { "remapstd", FieldFunc_Std, 0, RemapstatHelp }, + { "remapstd1", FieldFunc_Std1, 0, RemapstatHelp }, + { "remapvar", FieldFunc_Var, 0, RemapstatHelp }, + { "remapvar1", FieldFunc_Var1, 0, RemapstatHelp }, + { "remapskew", FieldFunc_Skew, 0, RemapstatHelp }, + { "remapkurt", FieldFunc_Kurt, 0, RemapstatHelp }, + { "remapmedian", FieldFunc_Median, 0, RemapstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Remapstat> registration = RegisterEntry<Remapstat>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -690,11 +690,8 @@ class ModuleRemapstat public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -787,17 +784,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Remapstat(void *process) -{ - ModuleRemapstat remapstat; - remapstat.init(process); - remapstat.run(); - remapstat.close(); - return nullptr; -} diff --git a/src/Remapweights.cc b/src/Remapweights.cc index a29fe5dfafb7ac43113d6380e31b6ed8089cf680..9c73da285d9e7f67f1be0f4596a8e217533ec087 100644 --- a/src/Remapweights.cc +++ b/src/Remapweights.cc @@ -44,7 +44,7 @@ get_parameter(int offset, int &neighbors, bool &map3D, std::string &grid) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -65,7 +65,7 @@ get_parameter(int offset, int &neighbors, bool &map3D, std::string &grid) } static void -remap_write_weights(const std::string remapWeightsFile, const RemapSwitches &remapSwitches, RemapType &remap) +remap_write_weights(const std::string &remapWeightsFile, const RemapSwitches &remapSwitches, RemapType &remap) { remap_write_data_scrip(remapWeightsFile, remapSwitches, remap.srcGrid, remap.tgtGrid, remap.vars); @@ -76,24 +76,28 @@ remap_write_weights(const std::string remapWeightsFile, const RemapSwitches &rem remap_search_free(remap.search); } -static void -add_operators(void) +class Remapweights : public Process { - // clang-format off - cdo_operator_add("gencon", GENCON, 0, nullptr); - cdo_operator_add("genycon2test", GENYCON2, 0, nullptr); - cdo_operator_add("genscon", GENSCON, 0, nullptr); - cdo_operator_add("genscon2", GENSCON2, 0, nullptr); - cdo_operator_add("genbil", GENBIL, 0, nullptr); - cdo_operator_add("genbic", GENBIC, 0, nullptr); - cdo_operator_add("gendis", GENDIS, 0, nullptr); - cdo_operator_add("gennn", GENNN, 0, nullptr); - cdo_operator_add("genlaf", GENLAF, 0, nullptr); - // clang-format on -} +public: + using Process::Process; + inline static CdoModule module = { + .name = "Remapweights", + .operators = { { "genbil", GENBIL, 0, RemapbilHelp }, + { "genbic", GENBIC, 0, RemapbicHelp }, + { "gennn", GENNN, 0, RemapnnHelp }, + { "gendis", GENDIS, 0, RemapdisHelp }, + { "gencon", GENCON, 0, RemapconHelp }, + { "genycon2test", GENYCON2, 0, nullptr}, + { "genscon", GENSCON, 0, nullptr}, + { "genscon2", GENSCON2, 0, nullptr}, + { "genlaf", GENLAF, 0, RemaplafHelp } }, + .aliases = { { "genycon", "gencon" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Remapweights> registration = RegisterEntry<Remapweights>(module); -class ModuleRemapweights -{ RemapSwitches remapSwitches; int numRemaps{ 0 }; int numNeighbors{ 0 }; @@ -128,11 +132,8 @@ class ModuleRemapweights public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -161,10 +162,7 @@ public: if (numNeighborsParam > 0) numNeighbors = numNeighborsParam; } } - else - { - operator_check_argc(1); - } + else { operator_check_argc(1); } gridID2 = cdo_define_grid(targetGrid); if (gridInqType(gridID2) == GRID_GENERIC) cdo_abort("Unsupported target grid type (generic)!"); @@ -177,7 +175,7 @@ public: remapGrids = remap_set_grids(vlistID1, varList1); - auto numRemapGrids = std::count_if(remapGrids.begin(), remapGrids.end(), [](auto flag) { return (flag == true); }); + auto numRemapGrids = ranges::count_if(remapGrids, [](auto flag) { return (flag == true); }); if (numRemapGrids == 0) cdo_abort("No remappable grid found!"); maxRemaps = remapParams.maxRemaps; @@ -225,24 +223,21 @@ public: auto &var = varList1[varID]; field1.init(var); cdo_read_record(streamID1, field1); - auto nmiss1 = useMask ? field1.nmiss : 0; + auto numMissVals1 = useMask ? field1.numMissVals : 0; auto gridIndex = vlistGridIndex(vlistID1, var.gridID); if (remapGrids[gridIndex]) { if (numRemaps == 0) { gridIDout = var.gridID; } - else if (gridIDout != var.gridID) - { - continue; - } + else if (gridIDout != var.gridID) { continue; } if (mapType != RemapMethod::CONSERV_SCRIP && mapType != RemapMethod::CONSERV && var.gridType == GRID_GME) cdo_abort("Only conservative remapping is available to remap between GME grids!"); if (gridIsCircular(var.gridID) && !extrapolateIsSet) remapExtrapolate = true; - remap_set_mask(var.gridsize, field1, nmiss1, var.missval, imask); + remap_set_mask(var.gridsize, field1, numMissVals1, var.missval, imask); int remapIndex = -1; for (remapIndex = numRemaps - 1; remapIndex >= 0; remapIndex--) @@ -250,7 +245,7 @@ public: auto &remap = remaps[remapIndex]; if (var.gridID == remap.gridID) { - if ((useMask && nmiss1 == remap.nmiss && imask == remap.srcGrid.mask) || !useMask) + if ((useMask && numMissVals1 == remap.numMissVals && imask == remap.srcGrid.mask) || !useMask) { remap.nused++; break; @@ -290,7 +285,7 @@ public: remap_search_init(mapType, remap.search, remap.srcGrid, remap.tgtGrid); remap.gridID = var.gridID; - remap.nmiss = nmiss1; + remap.numMissVals = numMissVals1; if (var.gridType == GRID_GME) { @@ -302,16 +297,16 @@ public: if (mapType == RemapMethod::CONSERV_SCRIP || mapType == RemapMethod::CONSERV) { - varray_fill(remap.srcGrid.cell_area, 0.0); - varray_fill(remap.srcGrid.cell_frac, 0.0); - varray_fill(remap.tgtGrid.cell_area, 0.0); + ranges::fill(remap.srcGrid.cell_area, 0.0); + ranges::fill(remap.srcGrid.cell_frac, 0.0); + ranges::fill(remap.tgtGrid.cell_area, 0.0); } - varray_fill(remap.tgtGrid.cell_frac, 0.0); + ranges::fill(remap.tgtGrid.cell_frac, 0.0); // initialize some remapping variables remap_vars_init(mapType, remapOrder, remap.vars); - remap_print_info(operfunc, remap_genweights, remap.srcGrid, remap.tgtGrid, nmiss1, remapSwitches.numNeighbors); + remap_print_info(operfunc, remap_genweights, remap.srcGrid, remap.tgtGrid, numMissVals1, remapSwitches.numNeighbors); if (needGradients && remap.srcGrid.rank != 2 && remapOrder == 2) { @@ -350,18 +345,5 @@ public: close() { cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Remapweights(void *process) -{ - ModuleRemapweights remapweights; - remapweights.init(process); - remapweights.run(); - remapweights.close(); - - return nullptr; -} diff --git a/src/Replace.cc b/src/Replace.cc index 363c4d7bebba54c90b1a1616c9dd4ed2036a2cca..abf0032548f7944f0886c51b35d181dac5cb3fbd 100644 --- a/src/Replace.cc +++ b/src/Replace.cc @@ -18,12 +18,23 @@ #include "cdo_vlist.h" #include "cdo_zaxis.h" -class ModuleReplace +class Replace : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Replace", + .operators = { { "replace", ReplaceHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Replace> registration = RegisterEntry<Replace>(module); static const int MaxVars = 1024; int nchvars = 0; int idx; - size_t nmiss = 0; + size_t numMissVals = 0; CdoStreamID streamID1; CdoStreamID streamID2; @@ -36,7 +47,7 @@ class ModuleReplace int vars1[MaxVars], vars2[MaxVars]; std::vector<std::vector<int>> varlevel; - std::vector<std::vector<size_t>> varnmiss2; + std::vector<std::vector<size_t>> varnumMissVals2; Varray<double> array; VarList varList1, varList2; @@ -44,9 +55,8 @@ class ModuleReplace public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -101,7 +111,7 @@ public: if (nchvars) { vardata2.resize(nchvars); - varnmiss2.resize(nchvars); + varnumMissVals2.resize(nchvars); varlevel.resize(nchvars); for (idx = 0; idx < nchvars; idx++) { @@ -111,7 +121,7 @@ public: auto nlevel2 = varList2[varID2].nlevels; auto gridsize = varList2[varID2].gridsize; vardata2[idx].resize(nlevel2 * gridsize); - varnmiss2[idx].resize(nlevel2); + varnumMissVals2[idx].resize(nlevel2); varlevel[idx].resize(nlevel1); /* for ( levelID = 0; levelID < nlevel1; levelID++ ) @@ -178,8 +188,8 @@ public: if (vars2[idx] == varID) { auto offset = varList2[varID].gridsize * levelID; - cdo_read_record(streamID2, &vardata2[idx][offset], &nmiss); - varnmiss2[idx][levelID] = nmiss; + cdo_read_record(streamID2, &vardata2[idx][offset], &numMissVals); + varnumMissVals2[idx][levelID] = numMissVals; break; } } @@ -202,15 +212,15 @@ public: { auto offset = varList1[varID].gridsize * levelID2; parray = &vardata2[idx][offset]; - nmiss = varnmiss2[idx][levelID2]; + numMissVals = varnumMissVals2[idx][levelID2]; break; } } - if (idx == nchvars) cdo_read_record(streamID1, parray, &nmiss); + if (idx == nchvars) cdo_read_record(streamID1, parray, &numMissVals); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, parray, nmiss); + cdo_write_record(streamID3, parray, numMissVals); } tsID++; @@ -222,17 +232,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Replace(void *process) -{ - ModuleReplace replace; - replace.init(process); - replace.run(); - replace.close(); - return nullptr; -} diff --git a/src/Replacevalues.cc b/src/Replacevalues.cc index c32a8d7fe88e47631bc2e7a47ceb4f238d61ef47..b87bceea987c78980fed473dafb40bf80eab34cd 100644 --- a/src/Replacevalues.cc +++ b/src/Replacevalues.cc @@ -18,8 +18,22 @@ #include "process_int.h" #include "param_conversion.h" -class ModuleReplacevalues +class Replacevalues : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Replacevalues", + .operators = { { "setvals", 0, 0, "I1,O1,...,In,On", ReplacevaluesHelp }, + { "setrtoc", 0, 0, "range(min,max),value", ReplacevaluesHelp }, + { "setrtoc2", 0, 0, "range(min,max),value1,value2", ReplacevaluesHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Replacevalues> registration = RegisterEntry<Replacevalues>(module); + int SETVALS, SETRTOC, SETRTOC2; int nvals = 0; std::vector<double> fltarr; double rmin = 0, rmax = 0; @@ -36,17 +50,14 @@ class ModuleReplacevalues Varray<double> array; VarList varList1; - int SETVALS, SETRTOC, SETRTOC2; - public: void - init(void *process) + init() { - cdo_initialize(process); - SETVALS = cdo_operator_add("setvals", 0, 0, "I1,O1,...,In,On"); - SETRTOC = cdo_operator_add("setrtoc", 0, 0, "range (min, max), value"); - SETRTOC2 = cdo_operator_add("setrtoc2", 0, 0, "range (min, max), value1, value2"); + SETVALS = module.get_id("setvals"); + SETRTOC = module.get_id("setrtoc"); + SETRTOC2 = module.get_id("setrtoc2"); operatorID = cdo_operator_id(); @@ -110,8 +121,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); const auto gridsize = varList1[varID].gridsize; const auto missval = varList1[varID].missval; @@ -146,7 +157,7 @@ public: } cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); } tsID++; @@ -157,18 +168,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Replacevalues(void *process) -{ - ModuleReplacevalues replaveValues; - replaveValues.init(process); - replaveValues.run(); - replaveValues.close(); - - return nullptr; -} diff --git a/src/Rhopot.cc b/src/Rhopot.cc index 8d8cbf0ec1f4fa3f6a948da0dd0af5455c98f013..9431edadfa6b4d91538d2906108a5d18ec119221 100644 --- a/src/Rhopot.cc +++ b/src/Rhopot.cc @@ -141,8 +141,20 @@ calc_rhopot(size_t gridsize, size_t nlevel, const Varray<double> &pressure, cons } } -class ModuleRhopot +class Rhopot : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Rhopot", + .operators = { { "rhopot", RhopotHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Rhopot> registration = RegisterEntry<Rhopot>(module); + int zaxisID; int toID = -1, saoID = -1, thoID = -1; double pin = -1; @@ -166,10 +178,8 @@ class ModuleRhopot public: void - init(void *process) + init() { - cdo_initialize(process); - if (cdo_operator_argc() == 1) pin = parameter_to_double(cdo_operator_argv(0)); streamID1 = cdo_open_read(0); @@ -186,20 +196,20 @@ public: auto stdname = string_to_lower(cdo::inq_key_string(vlistID1, varID, CDI_KEY_STDNAME)); // clang-format off - if (varname == "to") code = 20; - else if (varname == "sao") code = 5; - else if (varname == "tho") code = 2; - else if (varname == "s") code = 5; - else if (varname == "t") code = 2; - else if (stdname == "sea_water_salinity") code = 5; - else if (stdname == "sea_water_potential_temperature") code = 2; + if (varname == "to") code = 20; + else if (varname == "sao") code = 5; + else if (varname == "tho") code = 2; + else if (varname == "s") code = 5; + else if (varname == "t") code = 2; + else if (stdname == "sea_water_salinity") code = 5; + else if (stdname == "sea_water_potential_temperature") code = 2; // clang-format on } // clang-format off - if (code == 20) toID = varID; - else if (code == 5) saoID = varID; - else if (code == 2) thoID = varID; + if (code == 20) toID = varID; + else if (code == 5) saoID = varID; + else if (code == 2) thoID = varID; // clang-format on } @@ -274,6 +284,7 @@ public: streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); } + void run() { @@ -290,8 +301,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - if (varID == toID) cdo_read_record(streamID1, to[levelID].vec_d.data(), &to[levelID].nmiss); - if (varID == saoID) cdo_read_record(streamID1, sao[levelID].vec_d.data(), &sao[levelID].nmiss); + if (varID == toID) cdo_read_record(streamID1, to[levelID].vec_d.data(), &to[levelID].numMissVals); + if (varID == saoID) cdo_read_record(streamID1, sao[levelID].vec_d.data(), &sao[levelID].numMissVals); } calc_rhopot(gridsize, nlevel, pressure, to, sao, rho); @@ -313,18 +324,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -Rhopot(void *process) -{ - ModuleRhopot rhopot; - - rhopot.init(process); - rhopot.run(); - rhopot.close(); - - return nullptr; -} diff --git a/src/Rotuv.cc b/src/Rotuv.cc index 440132771e8b77525781b4badfec8ae13dfe4a90..6ebcb1468e4fece4190828a22a45355e20c5d309 100644 --- a/src/Rotuv.cc +++ b/src/Rotuv.cc @@ -54,8 +54,19 @@ rot_uv_back(int gridID, Varray<double> &us, Varray<double> &vs) #define MAXARG 16384 -class ModuleRotuv +class Rotuv : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Rotuv", + .operators = { { "rotuvb", RotuvbHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Rotuv> registration = RegisterEntry<Rotuv>(module); int chcodes[MAXARG]; const char *chvars[MAXARG]; @@ -73,13 +84,12 @@ class ModuleRotuv VarList varList1; Varray3D<double> vardata; std::vector<RecordInfo> recList; - std::vector<std::vector<size_t>> varnmiss; + std::vector<std::vector<size_t>> varnumMissVals; public: void - init(void *process) + init() { - cdo_initialize(process); operator_input_arg("pairs of u and v in the rotated system"); @@ -118,7 +128,7 @@ public: recList = std::vector<RecordInfo>(maxrecs); - varnmiss = std::vector<std::vector<size_t>>(nvars); + varnumMissVals = std::vector<std::vector<size_t>>(nvars); vardata = Varray3D<double>(nvars); bool lfound[MAXARG]; @@ -154,7 +164,7 @@ public: auto gridsize = gridInqSize(gridID); auto nlevels = varList1[varID].nlevels; - varnmiss[varID].resize(nlevels); + varnumMissVals[varID].resize(nlevels); vardata[varID].resize(nlevels); for (int levelID = 0; levelID < nlevels; ++levelID) vardata[varID][levelID].resize(gridsize); } @@ -186,8 +196,8 @@ public: recList[recID].set(varID, levelID); - cdo_read_record(streamID1, vardata[varID][levelID].data(), &varnmiss[varID][levelID]); - if (varnmiss[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); + cdo_read_record(streamID1, vardata[varID][levelID].data(), &varnumMissVals[varID][levelID]); + if (varnumMissVals[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); } for (int i = 0; i < nch; i += 2) @@ -248,7 +258,7 @@ public: { auto [varID, levelID] = recList[recID].get(); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, vardata[varID][levelID].data(), varnmiss[varID][levelID]); + cdo_write_record(streamID2, vardata[varID][levelID].data(), varnumMissVals[varID][levelID]); } tsID++; @@ -260,18 +270,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Rotuv(void *process) -{ - ModuleRotuv rotuv; - rotuv.init(process); - rotuv.run(); - rotuv.close(); - - return nullptr; -} diff --git a/src/Runpctl.cc b/src/Runpctl.cc index 2b20138a98ac54745458a22a089dadd2706431f7..c9e8815047992cf4ce1a965dfa2361a317814f9f 100644 --- a/src/Runpctl.cc +++ b/src/Runpctl.cc @@ -26,7 +26,7 @@ static size_t runpctl(double pn, int ndates, size_t gridsize, Varray<T> &v2, T missval, const FieldVector3D &vars1, int varID, int levelID, MemType memType) { - size_t nmiss = 0; + size_t numMissVals = 0; Varray2D<T> array_2D(Threading::ompNumThreads, Varray<T>(ndates)); #ifdef _OPENMP @@ -59,25 +59,36 @@ runpctl(double pn, int ndates, size_t gridsize, Varray<T> &v2, T missval, const else { v2[i] = missval; - nmiss++; + numMissVals++; } } - return nmiss; + return numMissVals; } static void runpctl(double pn, int ndates, Field &field1, const FieldVector3D &vars1, int varID, int levelID) { if (field1.memType == MemType::Float) - field1.nmiss + field1.numMissVals = runpctl(pn, ndates, field1.gridsize, field1.vec_f, (float) field1.missval, vars1, varID, levelID, field1.memType); else - field1.nmiss = runpctl(pn, ndates, field1.gridsize, field1.vec_d, field1.missval, vars1, varID, levelID, field1.memType); + field1.numMissVals = runpctl(pn, ndates, field1.gridsize, field1.vec_d, field1.missval, vars1, varID, levelID, field1.memType); } -class ModuleRunpctl +class Runpctl : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Runpctl", + .operators = { { "runpctl", RunpctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Runpctl> registration = RegisterEntry<Runpctl>(module); CdoStreamID streamID1; CdoStreamID streamID2; int vlistID1; @@ -97,12 +108,10 @@ class ModuleRunpctl public: void - init(void *process) + init() { constexpr auto timestatDate{ TimeStat::MEAN }; - cdo_initialize(process); - operator_input_arg("percentile number, number of timesteps"); operator_check_argc(2); pn = parameter_to_double(cdo_operator_argv(0)); @@ -224,18 +233,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Runpctl(void *process) -{ - ModuleRunpctl pctl; - pctl.init(process); - pctl.run(); - pctl.close(); - - return nullptr; -} diff --git a/src/Runstat.cc b/src/Runstat.cc index 6e3919354f04b3071afac004189abb124722185d..88e3126985ca315b15cb3cfb2d8ba3430bde3a9d 100644 --- a/src/Runstat.cc +++ b/src/Runstat.cc @@ -27,25 +27,28 @@ #include "datetime.h" #include "field_functions.h" -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("runrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("runmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("runmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("runsum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("runmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("runavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("runvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("runvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("runstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("runstd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} - -class ModuleRunstat +class Runstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Runstat", + .operators = { { "runrange", FieldFunc_Range, 0, RunstatHelp }, + { "runmin", FieldFunc_Min, 0, RunstatHelp }, + { "runmax", FieldFunc_Max, 0, RunstatHelp }, + { "runsum", FieldFunc_Sum, 0, RunstatHelp }, + { "runmean", FieldFunc_Mean, 0, RunstatHelp }, + { "runavg", FieldFunc_Avg, 0, RunstatHelp }, + { "runstd", FieldFunc_Std, 0, RunstatHelp }, + { "runstd1", FieldFunc_Std1, 0, RunstatHelp }, + { "runvar", FieldFunc_Var, 0, RunstatHelp }, + { "runvar1", FieldFunc_Var1, 0, RunstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Runstat> registration = RegisterEntry<Runstat>(module); TimeStat timestatDate{ TimeStat::MEAN }; bool runstat_nomiss = false; @@ -74,9 +77,8 @@ class ModuleRunstat public: void - init(void *process) + init() { - cdo_initialize(process); auto envstr = getenv("RUNSTAT_NOMISS"); if (envstr) @@ -86,8 +88,6 @@ public: if (envval == 1) runstat_nomiss = true; } - add_operators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); // used in omp loop @@ -189,11 +189,11 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[numSteps][varID][levelID].nmiss = rvars1.nmiss; + vars2[numSteps][varID][levelID].numMissVals = rvars1.numMissVals; vars2[numSteps][varID][levelID].vec_d = rvars1.vec_d; } - if (runstat_nomiss && rvars1.nmiss) cdo_abort("Missing values supported was swichted off by env. RUNSTAT_NOMISS!"); + if (runstat_nomiss && rvars1.numMissVals) cdo_abort("Missing values supported was swichted off by env. RUNSTAT_NOMISS!"); if (!runstat_nomiss) { @@ -314,18 +314,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Runstat(void *process) -{ - ModuleRunstat runstat; - runstat.init(process); - runstat.run(); - runstat.close(); - - return nullptr; -} diff --git a/src/Samplegrid.cc b/src/Samplegrid.cc index 4802a70cbabd381bc4fbdc7a674ad0a6c0ac812c..feb78ea1f0b1d5a512df394685f4c40d33e12441 100644 --- a/src/Samplegrid.cc +++ b/src/Samplegrid.cc @@ -24,11 +24,11 @@ static void sampleData(const double *array1, int gridID1, double *array2, int gridID2, int resampleFactor) { - const auto nlon1 = gridInqXsize(gridID1); - const auto nlat1 = gridInqYsize(gridID1); + auto nlon1 = gridInqXsize(gridID1); + auto nlat1 = gridInqYsize(gridID1); - const auto nlon2 = gridInqXsize(gridID2); - const auto nlat2 = gridInqYsize(gridID2); + auto nlon2 = gridInqXsize(gridID2); + auto nlat2 = gridInqYsize(gridID2); if (cdoDebugExt >= 100) cdo_print("%s(): (nlon1: %zu; nlat1: %zu) => (nlon2: %zu; nlat2: %zu); " @@ -42,9 +42,9 @@ sampleData(const double *array1, int gridID1, double *array2, int gridID2, int r static void cropData(double *array1, int gridID1, double *array2, int gridID2, int subI0, int subI1, int subJ0, int subJ1) { - const long nlon1 = gridInqXsize(gridID1); - const long nlon2 = gridInqXsize(gridID2); - const long rowLen = subI1 - subI0 + 1; // must be same as nlon1 + long nlon1 = gridInqXsize(gridID1); + long nlon2 = gridInqXsize(gridID2); + long rowLen = subI1 - subI0 + 1; // must be same as nlon1 if (rowLen != nlon2) cdo_abort("cropData() rowLen!= nlon2 [%d != %d]", rowLen, nlon2); @@ -58,8 +58,22 @@ cropData(double *array1, int gridID1, double *array2, int gridID2, int subI0, in } } -class ModuleSamplegrid +class Samplegrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Samplegrid", + .operators = { { "samplegrid", 0, 0, "resample factor, typically 2 (which will half the resolution)", SamplegridHelp }, + { "subgrid", 0, 0, "sub-grid indices: i0,i1,j0,j1", SamplegridHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Samplegrid> registration = RegisterEntry<Samplegrid>(module); + + int SAMPLEGRID, SUBGRID; int resampleFactor = 0; int subI0 = 0, subI1 = 0, subJ0 = 0, subJ1 = 0; struct sbox_t @@ -86,16 +100,12 @@ class ModuleSamplegrid size_t gridsize2; std::vector<sbox_t> sbox; - int SAMPLEGRID, SUBGRID; - public: void - init(void *process) + init() { - cdo_initialize(process); - - SAMPLEGRID = cdo_operator_add("samplegrid", 0, 0, "resample factor, typically 2 (which will half the resolution)"); - SUBGRID = cdo_operator_add("subgrid", 0, 0, " sub-grid indices: i0,i1,j0,j1"); + SAMPLEGRID = module.get_id("samplegrid"); + SUBGRID = module.get_id("subgrid"); operatorID = cdo_operator_id(); @@ -187,13 +197,14 @@ public: Debug(cdoDebugExt, "gridsize = %ld, gridsize2 = %ld", gridsize, gridsize2); } + void run() { int tsID = 0; while (true) { - const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); if (nrecs == 0) break; cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -203,8 +214,8 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); cdo_def_record(streamID2, varID, levelID); @@ -212,7 +223,7 @@ public: if (vars[varID]) { - const auto gridSrcID = vlistInqVarGrid(vlistID1, varID); + auto gridSrcID = vlistInqVarGrid(vlistID1, varID); int index; for (index = 0; index < ngrids; ++index) @@ -220,7 +231,7 @@ public: if (index == ngrids) cdo_abort("Internal problem, grid not found!"); - const int gridIDsampled = sbox[index].gridIDsampled; + int gridIDsampled = sbox[index].gridIDsampled; gridsize2 = gridInqSize(gridIDsampled); if (operatorID == SAMPLEGRID) @@ -232,20 +243,21 @@ public: cropData(array1.data(), gridSrcID, array2.data(), gridIDsampled, subI0, subI1, subJ0, subJ1); } - if (nmiss) + if (numMissVals) { - const auto missval = vlistInqVarMissval(vlistID2, varID); - nmiss = varray_num_mv(gridsize2, array2, missval); + auto missval = vlistInqVarMissval(vlistID2, varID); + numMissVals = varray_num_mv(gridsize2, array2, missval); } - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } - else { cdo_write_record(streamID2, array1.data(), nmiss); } + else { cdo_write_record(streamID2, array1.data(), numMissVals); } } tsID++; } } + void close() { @@ -253,17 +265,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Samplegrid(void *process) -{ - ModuleSamplegrid samplegrid; - samplegrid.init(process); - samplegrid.run(); - samplegrid.close(); - return nullptr; -} diff --git a/src/Samplegridicon.cc b/src/Samplegridicon.cc index 9e210bb05282f4439a55287fea76abcbabd2f619..90cbaa5e0b026ffc2d2455a09487b73b6806679f 100644 --- a/src/Samplegridicon.cc +++ b/src/Samplegridicon.cc @@ -5,8 +5,6 @@ */ -#include <algorithm> // sort - #include <cdi.h> #include "cdo_options.h" @@ -95,11 +93,11 @@ read_cellindex(const std::string &filename, CellIndex &cellindex) for (int recID = 0; recID < nrecs; ++recID) { int varID, levelID; - size_t nmiss; + size_t numMissVals; streamInqRecord(streamID, &varID, &levelID); if (varID == pid /* || varID == nid || varID == cid */) { - streamReadRecord(streamID, data.data(), &nmiss); + streamReadRecord(streamID, data.data(), &numMissVals); // if (varID == pid) { if (Options::cdoVerbose) cdo_print("Read parent_cell_index"); @@ -184,12 +182,6 @@ struct SortInfo int p, i; }; -static bool -cmpsinfo(const SortInfo &a, const SortInfo &b) -{ - return a.p < b.p; -} - static void compute_child_from_parent(CellIndex &cellindex1, CellIndex &cellindex2) { @@ -210,7 +202,7 @@ compute_child_from_parent(CellIndex &cellindex1, CellIndex &cellindex2) sinfo[j].p = parent1[j]; sinfo[j].i = idx1[j]; } - std::sort(sinfo.begin(), sinfo.end(), cmpsinfo); + ranges::sort(sinfo, {}, &SortInfo::p); for (long j = 0; j < ncells1; ++j) { parent1[j] = sinfo[j].p; @@ -263,7 +255,8 @@ read_coordinates(const std::string &filename, long n, Varray<double> &lon, Varra } static void -read_coordinates(const std::string &filename, long n, Varray<double> &lon, Varray<double> &lat, int nv, Varray<double> &lon_bnds, Varray<double> &lat_bnds) +read_coordinates(const std::string &filename, long n, Varray<double> &lon, Varray<double> &lat, int nv, Varray<double> &lon_bnds, + Varray<double> &lat_bnds) { auto streamID = streamOpenRead(filename.c_str()); auto vlistID = streamInqVlist(streamID); @@ -300,8 +293,8 @@ constexpr int MAX_SEARCH = 128; // the triangles are distorted! static void compute_child_from_bounds(CellIndex &cellindex2, long ncells2, Varray<double> &grid_center_lon2, Varray<double> &grid_center_lat2, - Varray<double> &grid_corner_lon2, Varray<double> &grid_corner_lat2, long ncells1, const Varray<double> &grid_center_lon1, - const Varray<double> &grid_center_lat1) + Varray<double> &grid_corner_lon2, Varray<double> &grid_corner_lat2, long ncells1, + const Varray<double> &grid_center_lon1, const Varray<double> &grid_center_lat1) { if (Options::cdoVerbose) cdo_print("%s", __func__); @@ -466,8 +459,20 @@ samplegrid(double missval, long nci, Varray<CellIndex> &cellindex, const Varray< } } -class ModuleSamplegridicon +class Samplegridicon : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Samplegridicon", + .operators = { { "samplegridicon", 0, 0, "samplegrids"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 2, OnlyFirst }, + }; + inline static RegisterEntry<Samplegridicon> registration = RegisterEntry<Samplegridicon>(module); + CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -491,12 +496,8 @@ class ModuleSamplegridicon public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("samplegridicon", 0, 0, "sample grids"); - nsamplegrids = cdo_operator_argc(); if (nsamplegrids < 2) cdo_abort("Parameter missing!"); @@ -575,20 +576,20 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); auto missval = vlistInqVarMissval(vlistID1, varID); samplegrid(missval, nsamplegrids, cellindex, array1, array2, array3); - nmiss = varray_num_mv(gridsize2, array2, missval); + numMissVals = varray_num_mv(gridsize2, array2, missval); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); - nmiss = varray_num_mv(gridsize2, array3, missval); + numMissVals = varray_num_mv(gridsize2, array3, missval); cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, array3.data(), nmiss); + cdo_write_record(streamID3, array3.data(), numMissVals); } tsID++; @@ -604,18 +605,5 @@ public: vlistDestroy(vlistID2); gridDestroy(gridID2); - - cdo_finish(); } }; - -void * -Samplegridicon(void *process) -{ - ModuleSamplegridicon samplegridicon; - samplegridicon.init(process); - samplegridicon.run(); - samplegridicon.close(); - - return nullptr; -} diff --git a/src/Seascount.cc b/src/Seascount.cc index fcecf5781da17dd7f365504dbfdb70e83a8f4f58..a3efafe858ebd64a882ce62438bd052fdfee7244 100644 --- a/src/Seascount.cc +++ b/src/Seascount.cc @@ -21,8 +21,19 @@ #include "process_int.h" #include "field_functions.h" -class ModuleSeascount +class Seascount : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Seascount", + .operators = { { "seascount"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Seascount> registration = RegisterEntry<Seascount>(module); CdiDateTime vDateTime0{}; int seas0 = 0; int oldmon = 0; @@ -42,11 +53,8 @@ class ModuleSeascount public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("seascount", 0, 0, nullptr); operator_check_argc(0); @@ -123,7 +131,7 @@ public: if (numSets == 0) { for (size_t i = 0; i < fieldsize; ++i) vars1[varID][levelID].vec_d[i] = vars1[varID][levelID].missval; - vars1[varID][levelID].nmiss = fieldsize; + vars1[varID][levelID].numMissVals = fieldsize; } field.init(var); @@ -148,7 +156,7 @@ public: if (otsID && varList1[varID].isConstant) continue; cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, vars1[varID][levelID].vec_d.data(), vars1[varID][levelID].nmiss); + cdo_write_record(streamID2, vars1[varID][levelID].vec_d.data(), vars1[varID][levelID].numMissVals); } if (nrecs == 0) break; @@ -160,17 +168,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Seascount(void *process) -{ - ModuleSeascount seascount; - seascount.init(process); - seascount.run(); - seascount.close(); - return nullptr; -} diff --git a/src/Seasmonstat.cc b/src/Seasmonstat.cc index df28bc486530eb87f259f790f66c648eda6e808b..4cac345819833f6a9c452e939704005566eac76c 100644 --- a/src/Seasmonstat.cc +++ b/src/Seasmonstat.cc @@ -22,8 +22,19 @@ #include "cdo_season.h" #include "field_functions.h" -class ModuleSeasmonstat +class Seasmonstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Seasmonstat", + .operators = { { "seasmonmean", FieldFunc_Mean, 0, nullptr}, { "seasmonavg", FieldFunc_Avg, 0, nullptr} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Seasmonstat> registration = RegisterEntry<Seasmonstat>(module); TimeStat timestatDate{ TimeStat::MEAN }; CdiDateTime vDateTime0{}; CdiDateTime vDateTime1{}; @@ -55,13 +66,10 @@ class ModuleSeasmonstat public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("seasmonmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("seasmonavg", FieldFunc_Avg, 0, nullptr); // clang-format on auto operatorID = cdo_operator_id(); @@ -175,7 +183,7 @@ public: fieldc_mul(rvars1, dpm); - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(fieldsize); field2_vinit(rsamp1, rvars1, dpm); @@ -188,7 +196,7 @@ public: fieldc_mul(field, dpm); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(fieldsize, dsets); field2_vincr(rsamp1, field, dpm); @@ -253,18 +261,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Seasmonstat(void *process) -{ - ModuleSeasmonstat seasmonstat; - seasmonstat.init(process); - seasmonstat.run(); - seasmonstat.close(); - - return nullptr; -} diff --git a/src/Seaspctl.cc b/src/Seaspctl.cc index 769166468b8b84eeac8b790e9efc117822999580..b0230087f7124fbae786ac279865c91a92261106 100644 --- a/src/Seaspctl.cc +++ b/src/Seaspctl.cc @@ -24,8 +24,19 @@ #include "cdo_season.h" #include "field_functions.h" -class ModuleSeaspctl +class Seaspctl : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Seaspctl", + .operators = { { "seaspctl", FieldFunc_Pctl, 0, SeaspctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Seaspctl> registration = RegisterEntry<Seaspctl>(module); TimeStat timestatDate{ TimeStat::MEAN }; int seas0 = 0; int oldmon = 0; @@ -52,11 +63,8 @@ class ModuleSeaspctl public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("seaspctl", FieldFunc_Pctl, 0, nullptr); operator_input_arg("percentile number"); pn = parameter_to_double(cdo_operator_argv(0)); @@ -232,18 +240,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Seaspctl(void *process) -{ - ModuleSeaspctl seaspctl; - seaspctl.init(process); - seaspctl.run(); - seaspctl.close(); - - return nullptr; -} diff --git a/src/Seasstat.cc b/src/Seasstat.cc index 43e7ad27cd6ce167f5cbfc76b661fa25c4203fd2..5a3293cf8a2b619f0a75e30a0d68542271fee5dc 100644 --- a/src/Seasstat.cc +++ b/src/Seasstat.cc @@ -29,25 +29,28 @@ #include "cdo_season.h" #include "field_functions.h" -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("seasrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("seasmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("seasmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("seassum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("seasmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("seasavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("seasvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("seasvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("seasstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("seasstd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} - -class ModuleSeasstat +class Seasstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Seasstat", + .operators = { { "seasrange", FieldFunc_Range, 0, SeasstatHelp }, + { "seasmin", FieldFunc_Min, 0, SeasstatHelp }, + { "seasmax", FieldFunc_Max, 0, SeasstatHelp }, + { "seassum", FieldFunc_Sum, 0, SeasstatHelp }, + { "seasmean", FieldFunc_Mean, 0, SeasstatHelp }, + { "seasavg", FieldFunc_Avg, 0, SeasstatHelp }, + { "seasstd", FieldFunc_Std, 0, SeasstatHelp }, + { "seasstd1", FieldFunc_Std1, 0, SeasstatHelp }, + { "seasvar", FieldFunc_Var, 0, SeasstatHelp }, + { "seasvar1", FieldFunc_Var1, 0, SeasstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Seasstat> registration = RegisterEntry<Seasstat>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -81,11 +84,8 @@ class ModuleSeasstat public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -195,11 +195,11 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[varID][levelID].nmiss = rvars1.nmiss; + vars2[varID][levelID].numMissVals = rvars1.numMissVals; vars2[varID][levelID].vec_d = rvars1.vec_d; } - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -210,7 +210,7 @@ public: field.init(var); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, numSets); field2_vincr(rsamp1, field); @@ -297,18 +297,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Seasstat(void *process) -{ - ModuleSeasstat seasstat; - seasstat.init(process); - seasstat.run(); - seasstat.close(); - - return nullptr; -} diff --git a/src/Selbox.cc b/src/Selbox.cc index 5800a68f162c5386166007f63c6d9896378344c6..5a1f8c9cce0e81b1ca009453d899844d9fc837a8 100644 --- a/src/Selbox.cc +++ b/src/Selbox.cc @@ -985,7 +985,11 @@ get_selboxInfo(int vlistID1, int vlistID2, bool operIndexBox) || (!operIndexBox && (gridtype == GRID_UNSTRUCTURED || is_healpix_grid(gridID1)))) { if (operIndexBox) { selboxInfo.push_back(selbox_index_grid(gridID1)); } - else { selboxInfo.push_back((gridtype == GRID_UNSTRUCTURED || is_healpix_grid(gridID1)) ? selbox_cell_grid(gridID1) : selbox_lonlat_grid(gridID1)); } + else + { + selboxInfo.push_back((gridtype == GRID_UNSTRUCTURED || is_healpix_grid(gridID1)) ? selbox_cell_grid(gridID1) + : selbox_lonlat_grid(gridID1)); + } vlistChangeGridIndex(vlistID2, index, selboxInfo.back().gridID2); } @@ -1042,8 +1046,22 @@ get_grid_index(int gridID, const std::vector<SelboxInfo> &selboxInfo) return index; } -class ModuleSelbox +class Selbox : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selbox", + .operators = { { "sellonlatbox", 0, 0, "western and eastern longitude and southern and northern latitude", SelboxHelp }, + { "selindexbox", 0, 0, "index of first and last longitude and index of first and last latitude", SelboxHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Selbox> registration = RegisterEntry<Selbox>(module); + + int SELLONLATBOX, SELINDEXBOX; CdoStreamID streamID1; CdoStreamID streamID2; @@ -1054,9 +1072,6 @@ class ModuleSelbox VarList varList1, varList2; - int SELLONLATBOX; - int SELINDEXBOX; - int vlistID2; int operatorID; @@ -1065,14 +1080,10 @@ class ModuleSelbox public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - SELLONLATBOX = cdo_operator_add("sellonlatbox", 0, 0, "western and eastern longitude and southern and northern latitude"); - SELINDEXBOX = cdo_operator_add("selindexbox", 0, 0, "index of first and last longitude and index of first and last latitude"); - // clang-format on + SELLONLATBOX = module.get_id("sellonlatbox"); + SELINDEXBOX = module.get_id("selindexbox"); operatorID = cdo_operator_id(); @@ -1130,7 +1141,7 @@ public: else window_box(field1, field2, sb.lat1, sb.lat2, sb.lon11, sb.lon12, sb.lon21, sb.lon22); - if (field1.nmiss) field_num_mv(field2); + if (field1.numMissVals) field_num_mv(field2); cdo_write_record(streamID2, field2); } @@ -1148,18 +1159,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Selbox(void *process) -{ - ModuleSelbox selbox; - selbox.init(process); - selbox.run(); - selbox.close(); - - return nullptr; -} diff --git a/src/Select.cc b/src/Select.cc index 8a6a4c5d8c604cc23dd1f66cd6dc5cd9c64610fe..2d7d88cc48636267c15db44fc1e7976c316b9ec6 100644 --- a/src/Select.cc +++ b/src/Select.cc @@ -52,9 +52,9 @@ write_const_vars(CdoStreamID streamID2, const VarList &varList2, int nvars, Varr for (int levelID2 = 0; levelID2 < var.nlevels; ++levelID2) { auto pdata = &vardata2[varID2][var.gridsize * levelID2]; - auto nmiss = array_num_mv(var.gridsize, pdata, var.missval); + auto numMissVals = array_num_mv(var.gridsize, pdata, var.missval); cdo_def_record(streamID2, varID2, levelID2); - cdo_write_record(streamID2, pdata, nmiss); + cdo_write_record(streamID2, pdata, numMissVals); } vardata2[varID2].clear(); vardata2[varID2].shrink_to_fit(); @@ -128,8 +128,21 @@ datetime_to_double(CdiDateTime dateTime) return fdatetime; } -class ModuleSelect +class Select : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Select", + .operators = { { "select", 0, 0, "parameter list", SelectHelp }, { "delete", 0, 0, "parameter list", SelectHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Select> registration = RegisterEntry<Select>(module); + + int SELECT, DELETE; CdoStreamID streamID2 = CDO_STREAM_UNDEF; int tsID2 = 0; int vlistID0 = -1, vlistID2 = -1; @@ -138,16 +151,12 @@ class ModuleSelect KVList kvlist; int operatorID; - int SELECT, DELETE; - public: void - init(void *process) + init() { - cdo_initialize(process); - - SELECT = cdo_operator_add("select", 0, 0, "parameter list"); - DELETE = cdo_operator_add("delete", 0, 0, "parameter list"); + SELECT = module.get_id("select"); + DELETE = module.get_id("delete"); dataIsUnchanged = data_is_unchanged(); @@ -161,7 +170,7 @@ public: if (argc == 0) cdo_abort("Parameter missing!"); kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(argc, argnames) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(argnames) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); auto kv = kvlist.search("timestepmask"); @@ -348,7 +357,7 @@ public: { levidx = levelID + 1; level = cdo_zaxis_inq_level(zaxisID, levelID); - if (!processVars[varID] && SELINFO_CHECK(levidx)) processVars[varID] = true; + if (!processVars[varID] && SELINFO_CHECK_INDEX(levidx, var.nlevels)) processVars[varID] = true; if (!processVars[varID] && SELINFO_CHECK(level)) processVars[varID] = true; if (!processVars[varID] && SELINFO_CHECK_RANGE(levrange, level)) processVars[varID] = true; } @@ -388,7 +397,7 @@ public: { if (SELINFO_NVAL(levidx)) { - if (SELINFO_CHECK(levidx)) vlistDefFlag(vlistID1, varID, levelID, xresult); + if (SELINFO_CHECK_INDEX(levidx, var.nlevels)) vlistDefFlag(vlistID1, varID, levelID, xresult); } else if (SELINFO_NVAL(level)) { @@ -398,10 +407,7 @@ public: { if (SELINFO_CHECK_RANGE(levrange, level)) vlistDefFlag(vlistID1, varID, levelID, xresult); } - else - { - vlistDefFlag(vlistID1, varID, levelID, xresult); - } + else { vlistDefFlag(vlistID1, varID, levelID, xresult); } } } } @@ -437,10 +443,7 @@ public: for (int levelID = 0; levelID < var.nlevels; ++levelID) vlistDefFlag(vlistID1, varID, levelID, true); } } - else - { - cdo_abort("No variable selected!"); - } + else { cdo_abort("No variable selected!"); } } // if (Options::cdoVerbose) vlistPrint(vlistID1); @@ -520,10 +523,7 @@ public: if (SELINFO_NVAL(startdate)) fstartdate = date_str_to_double(startdate, 0); if (SELINFO_NVAL(enddate)) fenddate = date_str_to_double(enddate, 1); } - else - { - vlist_compare(vlistID0, vlistID1, CmpVlist::All); - } + else { vlist_compare(vlistID0, vlistID1, CmpVlist::All); } if (nvars2 == 0) { @@ -686,8 +686,8 @@ public: { auto levelID2 = vlistFindLevel(vlistID2, varID, levelID); if (levelID == 0) vardata2[varID2].resize(var.gridsize * var.nlevels); - size_t nmiss; - cdo_read_record(streamID1, &vardata2[varID2][var.gridsize * levelID2], &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, &vardata2[varID2][var.gridsize * levelID2], &numMissVals); } } } @@ -726,18 +726,5 @@ public: vlistDestroy(vlistID2); if (tsID2 == 0) cdo_abort("No timesteps selected!"); - - cdo_finish(); } }; - -void * -Select(void *process) -{ - ModuleSelect select; - select.init(process); - select.run(); - select.close(); - - return nullptr; -} diff --git a/src/Selgridcell.cc b/src/Selgridcell.cc index 4f3790cb1d1b5e36195c72ac9e06072fc01d0cf9..7480c4ac591bdb616a610bdbb214bfd1b765defb 100644 --- a/src/Selgridcell.cc +++ b/src/Selgridcell.cc @@ -31,10 +31,7 @@ gen_grid_unstr_from_healpix(int gridID1, size_t gridsize2, const std::vector<lon auto [nside, order] = cdo::get_healpix_params(gridID1); - for (size_t i = 0; i < gridsize2; ++i) - { - hp_index_to_lonlat(order, nside, cellidx[i], &xvals[i], &yvals[i]); - } + for (size_t i = 0; i < gridsize2; ++i) { hp_index_to_lonlat(order, nside, cellidx[i], &xvals[i], &yvals[i]); } auto gridID2 = gridCreate(GRID_UNSTRUCTURED, gridsize2); cdiDefKeyString(gridID2, CDI_XAXIS, CDI_KEY_UNITS, "radians"); @@ -95,8 +92,22 @@ select_index(const Field &field1, Field &field2, long nind, const std::vector<lo select_index(field1.vec_d, field2.vec_d, nind, cellidx); } -class ModuleSelgridcell +class Selgridcell : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selgridcell", + .operators = { { "selgridcell", 0, 0, "gridcell indices(1-N)", SelgridcellHelp }, + { "delgridcell", 0, 0, "gridcell indices(1-N)", SelgridcellHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Selgridcell> registration = RegisterEntry<Selgridcell>(module); + + int DELGRIDCELL; struct sindex_t { int gridID1, gridID2; @@ -124,15 +135,12 @@ class ModuleSelgridcell public: void - init(void *process) + init() { int nind = 0; std::vector<int> indarr; - cdo_initialize(process); - - cdo_operator_add("selgridcell", 0, 0, "grid cell indices (1-N)"); - auto DELGRIDCELL = cdo_operator_add("delgridcell", 0, 0, "grid cell indices (1-N)"); + DELGRIDCELL = module.get_id("delgridcell"); operator_input_arg(cdo_operator_enter(0)); @@ -196,10 +204,8 @@ public: if (nind == 0) cdo_abort("Argument %s generates no input!", cdo_operator_argv(0)); - auto minmax = std::minmax_element(indarr.begin(), indarr.end()); - auto indmin = *minmax.first; - auto indmax = *minmax.second; - if (indmin < 0) cdo_abort("Index < 1 not allowed!"); + const auto [indmin, indmax] = ranges::minmax_element(indarr); + if (*indmin < 0) cdo_abort("Index < 1 not allowed!"); streamID1 = cdo_open_read(0); @@ -245,7 +251,7 @@ public: auto gridsize = gridInqSize(gridID1); if (gridsize == 1) continue; - if ((size_t) indmax >= gridsize) + if ((size_t) *indmax >= gridsize) { cdo_warning("Max grid index is greater than grid size, skipped grid %d!", index + 1); continue; @@ -307,7 +313,7 @@ public: field2.init(varList2[varID]); select_index(field1, field2, ncells, cellidx); - if (field1.nmiss) field2.nmiss = field_num_mv(field2); + if (field1.numMissVals) field2.numMissVals = field_num_mv(field2); cdo_write_record(streamID2, field2); } @@ -325,17 +331,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -Selgridcell(void *process) -{ - ModuleSelgridcell selgridcell; - selgridcell.init(process); - selgridcell.run(); - selgridcell.close(); - - return nullptr; -} diff --git a/src/Selmulti.cc b/src/Selmulti.cc index 625df34c8bf23081c6a20a4378e7cafa372581ec..92dee562348987d49fd6ece4ffcb1507bee9042d 100644 --- a/src/Selmulti.cc +++ b/src/Selmulti.cc @@ -5,11 +5,12 @@ */ +#include <fstream> + #include <cdi.h> #include "process_int.h" #include "cdo_zaxis.h" -#include "readline.h" #include "cdi_lockedIO.h" // NOTE: All operators in this module works only on GRIB edition 1 files! @@ -149,8 +150,23 @@ int getNumberOfDeleteSelectionTuples(); int multiSelectionParser(const char *filenameOrString); -class ModuleSelmulti +class Selmulti : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selmulti", + .operators = { { "selmulti", 0, 0, "filename/string with selection specification", SelmultiHelp }, + { "delmulti", 0, 0, "filename/string with selection specification", SelmultiHelp }, + { "changemulti", 0, 0, "filename/string with selection specification", SelmultiHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Selmulti> registration = RegisterEntry<Selmulti>(module); + + int SELMULTI, DELMULTI, CHANGEMULTI; CdoStreamID streamID1; CdoStreamID streamID2; @@ -169,20 +185,13 @@ class ModuleSelmulti VarList varList1; Varray<double> array; - int SELMULTI, DELMULTI, CHANGEMULTI; - public: void - init(void *process) + init() { - - cdo_initialize(process); - - // clang-format off - SELMULTI = cdo_operator_add("selmulti", 0, 0, "filename/string with selection specification"); - DELMULTI = cdo_operator_add("delmulti", 0, 0, "filename/string with selection specification"); - CHANGEMULTI = cdo_operator_add("changemulti", 0, 0, "filename/string with selection specification"); - // clang-format on + SELMULTI = module.get_id("selmulti"); + DELMULTI = module.get_id("delmulti"); + CHANGEMULTI = module.get_id("changemulti"); operatorID = cdo_operator_id(); @@ -477,8 +486,8 @@ public: } else { - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); if (!simpleMath) { @@ -501,7 +510,7 @@ public: } } - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); } // end of else ( lcopy ) } // end if ( vlistInqFlag(vlistID1, varID, levelID) == true ) } // end for ( recID .. @@ -517,22 +526,10 @@ public: vlistDestroy(vlistID2); - cdo_finish(); - cdoDebugExt = 0; } }; -void * -Selmulti(void *process) -{ - ModuleSelmulti selmulti; - selmulti.init(process); - selmulti.run(); - selmulti.close(); - return nullptr; -} - TUPLEREC * TUPLERECNew() { @@ -608,7 +605,7 @@ static char * removeSpaces(char *pline) { if (pline == nullptr) return nullptr; - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; return pline; } @@ -616,9 +613,9 @@ static char * skipSeparator(char *pline) { if (pline == nullptr) return nullptr; - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; if (*pline == '=' || *pline == ':' || *pline == '/' || *pline == ',') pline++; - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; return pline; } @@ -627,7 +624,7 @@ goToNextSeparator(char *pline) { if (pline == nullptr) return nullptr; int separatorFound = 0; - while (isspace((int) *pline) || !separatorFound) + while (std::isspace((int) *pline) || !separatorFound) { if (*pline == '\0') return nullptr; pline++; @@ -643,7 +640,7 @@ goToNextSeparator(char *pline) } if (separatorFound) pline++; Debug(cdoDebugExt >= 100, "goToNextSeparator(): pline= ('%s') ", pline); - // while ( isspace((int) *pline) ) pline++; + // while ( std::isspace((int) *pline) ) pline++; pline = removeSpaces(pline); return pline; } @@ -725,12 +722,17 @@ findTupleEnd(char *str) } static char * -readlineForParsing(FILE *gfp, char *strToParsePtr, char *line) +readlineForParsing(std::ifstream &gfile, char *strToParsePtr, char *line) { - if (gfp != nullptr) // file is open => we parse text from a file + if (gfile.is_open()) // file is open => we parse text from a file { - int status = cdo::readline(gfp, line, MAX_LINE_LEN); - return (status == 0) ? nullptr : line; + std::string strLine; + if (std::getline(gfile, strLine)) + { + strcpy(line, strLine.c_str()); + return line; + } + else { return nullptr; } } else if (strToParsePtr != nullptr) // we parse a given string { @@ -761,14 +763,13 @@ readlineForParsing(FILE *gfp, char *strToParsePtr, char *line) int multiSelectionParser(const char *filenameOrString) { - char line[MAX_LINE_LEN], *pline; + std::ifstream gfile; char *strpos; char *parEnd; int val; float floatval; TUPLEREC *tuplerec; int selectionRec; - FILE *gfp = nullptr; char strToParse[MAX_LINE_LEN]; char *strToParsePtr = nullptr; strToParse[0] = 0; @@ -793,22 +794,23 @@ multiSelectionParser(const char *filenameOrString) } else { - gfp = std::fopen(filenameOrString, "r"); + gfile.open(filenameOrString); Debug(cdoDebugExt, " Parsing file: %s", filenameOrString); - if (gfp == nullptr) + if (!gfile.is_open()) { cdo_abort(" Missing file: %s", filenameOrString); return 0; } } - while ((strToParsePtr = readlineForParsing(gfp, strToParsePtr, line))) + char line[MAX_LINE_LEN]; + while ((strToParsePtr = readlineForParsing(gfile, strToParsePtr, line))) { if (line[0] == '#') continue; if (line[0] == '\0') continue; - pline = line; + char *pline = line; if (cdoDebugExt >= 30) cdo_print(": Line: %s", pline); - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; if (pline[0] == '\0') continue; strpos = strContains(pline, "SELECT, "); selectionRec = 0; // default is 0; sel_or_del_or_change: 0: operator @@ -1166,8 +1168,9 @@ multiSelectionParser(const char *filenameOrString) } // end while pline } // end if "(" - } // end while ( cdo::readline(gfp, line, MAX_LINE_LEN) ) - if (gfp != nullptr) std::fclose(gfp); + } // end while ( readlineForParsing() ) + + if (gfile.is_open()) gfile.close(); printSelectionTuples(); return 1; @@ -1191,7 +1194,7 @@ printSelectionTuples() tuplerec->nlevels); for (ri = 0; ri < tuplerec->ncodes; ri++) { - sprintf(bff, "%d", tuplerec->codeLST[ri]); + std::snprintf(bff, sizeof(bff), "%d", tuplerec->codeLST[ri]); strcat(strval, bff); if ((ri + 1) < tuplerec->ncodes) strcat(strval, "/"); @@ -1200,7 +1203,7 @@ printSelectionTuples() } for (ri = 0; ri < tuplerec->nlevelTypes; ri++) { - sprintf(bff, "%d", tuplerec->levelTypeLST[ri]); + std::snprintf(bff, sizeof(bff), "%d", tuplerec->levelTypeLST[ri]); strcat(strval, bff); if ((ri + 1) < tuplerec->nlevelTypes) strcat(strval, "/"); @@ -1209,7 +1212,7 @@ printSelectionTuples() } for (ri = 0; ri < tuplerec->nlevels; ri++) { - sprintf(bff, "%d", tuplerec->levelLST[ri]); + std::snprintf(bff, sizeof(bff), "%d", tuplerec->levelLST[ri]); strcat(strval, bff); if ((ri + 1) < tuplerec->nlevels) strcat(strval, "/"); @@ -1219,7 +1222,7 @@ printSelectionTuples() if (tuplerec->simpleMath) { - sprintf(bff, " {scale = %f; offset = %f}", tuplerec->scale, tuplerec->offset); + std::snprintf(bff, sizeof(bff), " {scale = %f; offset = %f}", tuplerec->scale, tuplerec->offset); strcat(strval, bff); } diff --git a/src/Seloperator.cc b/src/Seloperator.cc index 5a90c928c776cc80fc0a03ec29a0b30c3f75c3ad..a0f5e3cbf5efc514f151797343a4f24af6e9a77b 100644 --- a/src/Seloperator.cc +++ b/src/Seloperator.cc @@ -12,8 +12,19 @@ #include "param_conversion.h" #include "cdi_lockedIO.h" -class ModuleSeloperator +class Seloperator : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Seloperator", + .operators = { { "seloperator"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Seloperator> registration = RegisterEntry<Seloperator>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -33,12 +44,10 @@ class ModuleSeloperator public: void - init(void *process) + init() { bool selfound = false; - cdo_initialize(process); - dataIsUnchanged = data_is_unchanged(); operator_input_arg("code, ltype, level"); @@ -133,17 +142,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Seloperator(void *process) -{ - ModuleSeloperator seloperator; - seloperator.init(process); - seloperator.run(); - seloperator.close(); - return nullptr; -} diff --git a/src/Selrec.cc b/src/Selrec.cc index 906a7844856e5542c98d762f9977e35f868eff9d..4db1886229bcc372b1e21118cfd5938f232b4419 100644 --- a/src/Selrec.cc +++ b/src/Selrec.cc @@ -17,8 +17,19 @@ #include "process_int.h" #include "param_conversion.h" -class ModuleSelrec +class Selrec : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selrec", + .operators = { { "selrec", SelvarHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, OnlyFirst }, + }; + inline static RegisterEntry<Selrec> registration = RegisterEntry<Selrec>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -30,11 +41,8 @@ class ModuleSelrec public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); operator_input_arg("records"); @@ -104,17 +112,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Selrec(void *process) -{ - ModuleSelrec selrec; - selrec.init(process); - selrec.run(); - selrec.close(); - return nullptr; -} diff --git a/src/Selregion.cc b/src/Selregion.cc index 357711d71b5140fd8eb5c411ea8af0e501f7b469..0f7f077304537fd192d3d3fa6ab6428a82f91975 100644 --- a/src/Selregion.cc +++ b/src/Selregion.cc @@ -119,9 +119,9 @@ generate_region_grid(int gridID1, long &gridsize2, std::vector<long> &cellidx, i for (int i = 0; i < numFiles; ++i) { Regions regions; - auto param = cdo_operator_argv(i).c_str(); - if (std::strncmp(param, "dcw:", 4) == 0) - read_regions_from_dcw(param + 4, regions); + auto param = cdo_operator_argv(i); + if (param.starts_with("dcw:")) + read_regions_from_dcw(param.c_str() + 4, regions); else read_regions_from_file(param, regions); @@ -206,7 +206,7 @@ selcircle_get_parameter(CirclePoint &cpoint) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -227,8 +227,22 @@ selcircle_get_parameter(CirclePoint &cpoint) } } -class ModuleSelregion +class Selregion : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selregion", + .operators = { { "selregion", 0, 0, "DCW region or the path to region file", SelregionHelp }, + { "selcircle", 0, 0, "Longitude, latitude of the center and radius of the circle", SelregionHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Selregion>(module); + + int SELREGION, SELCIRCLE; CdoStreamID streamID1; CdoStreamID streamID2; @@ -244,12 +258,10 @@ class ModuleSelregion public: void - init(void *process) + init() { - cdo_initialize(process); - - auto SELREGION = cdo_operator_add("selregion", 0, 0, "DCW region or the path to region file"); - auto SELCIRCLE = cdo_operator_add("selcircle", 0, 0, "Longitude, latitude of the center and radius of the circle"); + SELREGION = module.get_id("selregion"); + SELCIRCLE = module.get_id("selcircle"); auto operatorID = cdo_operator_id(); @@ -369,7 +381,7 @@ public: field2.init(varList2[varID]); window_cell(field1, field2, regions[index].cellidx); - if (field1.nmiss) field_num_mv(field2); + if (field1.numMissVals) field_num_mv(field2); cdo_write_record(streamID2, field2); } @@ -385,18 +397,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Selregion(void *process) -{ - ModuleSelregion selregion; - selregion.init(process); - selregion.run(); - selregion.close(); - - return nullptr; -} diff --git a/src/Selsurface.cc b/src/Selsurface.cc index 7dbaa2851f5582e9d425fff6a8bc65ce3d78ebe2..40eea4883f9d1c7ceb61358635bb72cdc25ebabf 100644 --- a/src/Selsurface.cc +++ b/src/Selsurface.cc @@ -16,7 +16,7 @@ template <typename T> static void -isosurface_kernel(double isoval, size_t nmiss, const Varray<double> &levels, int nlevels, size_t gridsize, T missval, +isosurface_kernel(double isoval, size_t numMissVals, const Varray<double> &levels, int nlevels, size_t gridsize, T missval, const Varray<const T *> &data3D, Varray<T> &data2D) { #ifdef _OPENMP @@ -31,7 +31,7 @@ isosurface_kernel(double isoval, size_t nmiss, const Varray<double> &levels, int const double val1 = data3D[k][i]; const double val2 = data3D[k + 1][i]; - if (nmiss) + if (numMissVals) { auto hasMissvals1 = dbl_is_equal(val1, missval); auto hasMissvals2 = dbl_is_equal(val2, missval); @@ -56,20 +56,20 @@ isosurface(double isoval, int nlevels, const Varray<double> &levels, const Field auto gridsize = gridInqSize(field3D[0].grid); auto missval = field3D[0].missval; - auto nmiss = field3D[0].nmiss; - for (int k = 1; k < nlevels; ++k) nmiss += field3D[k].nmiss; + auto numMissVals = field3D[0].numMissVals; + for (int k = 1; k < nlevels; ++k) numMissVals += field3D[k].numMissVals; if (field3D[0].memType == MemType::Float) { Varray<const float *> data3D(nlevels); for (int k = 0; k < nlevels; ++k) data3D[k] = field3D[k].vec_f.data(); - isosurface_kernel(isoval, nmiss, levels, nlevels, gridsize, (float) missval, data3D, field2D.vec_f); + isosurface_kernel(isoval, numMissVals, levels, nlevels, gridsize, (float) missval, data3D, field2D.vec_f); } else { Varray<const double *> data3D(nlevels); for (int k = 0; k < nlevels; ++k) data3D[k] = field3D[k].vec_d.data(); - isosurface_kernel(isoval, nmiss, levels, nlevels, gridsize, missval, data3D, field2D.vec_d); + isosurface_kernel(isoval, numMissVals, levels, nlevels, gridsize, missval, data3D, field2D.vec_d); } field_num_mv(field2D); @@ -165,8 +165,22 @@ layer_value_max(int nlevels, const FieldVector &field3D, Field &field2D) field_num_mv(field2D); } -class ModuleSelsurface +class Selsurface : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selsurface", + .operators = { { "isosurface", SelsurfaceHelp }, + { "bottomvalue", SelsurfaceHelp }, + { "topvalue", SelsurfaceHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Selsurface> registration = RegisterEntry<Selsurface>(module); + int ISOSURFACE, BOTTOMVALUE, TOPVALUE; CdoStreamID streamID1; CdoStreamID streamID2; @@ -194,18 +208,15 @@ class ModuleSelsurface bool isPositive; bool isReverse; - int ISOSURFACE, BOTTOMVALUE, TOPVALUE; - public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - ISOSURFACE = cdo_operator_add("isosurface", 0, 0, nullptr); - BOTTOMVALUE = cdo_operator_add("bottomvalue", 0, 0, nullptr); - TOPVALUE = cdo_operator_add("topvalue", 0, 0, nullptr); +ISOSURFACE = module.get_id("isosurface"); +BOTTOMVALUE = module.get_id("bottomvalue"); +TOPVALUE = module.get_id("topvalue"); // clang-format on operatorID = cdo_operator_id(); @@ -340,16 +351,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -Selsurface(void *process) -{ - ModuleSelsurface selsurface; - selsurface.init(process); - selsurface.run(); - selsurface.close(); - return nullptr; -} diff --git a/src/Seltime.cc b/src/Seltime.cc index f9f7e93ab2022ee79787b492d9b0bbfa612d8d4d..4e5a687ee4a4ca0251eff095ededc06859820960 100644 --- a/src/Seltime.cc +++ b/src/Seltime.cc @@ -19,7 +19,6 @@ Seltime selsmon Select single month */ #include <cassert> -#include <algorithm> // sort #include <cdi.h> #include "cdo_options.h" @@ -160,10 +159,37 @@ cdo_argv_to_int_timestep(const std::vector<std::string> &argv, int ntimesteps) return v; } -void *Select(void *process); - -class ModuleSeltime +class Seltime : public Process { + enum + { + func_time, + func_date, + func_step, + func_datetime + }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Seltime", + .operators = { { "seltimestep", func_step, 0, "timesteps", SeltimeHelp }, + { "selyear", func_date, 0, "years", SeltimeHelp }, + { "selseason", func_date, 0, "seasons", SeltimeHelp }, + { "selmonth", func_date, 0, "months", SeltimeHelp }, + { "selday", func_date, 0, "days", SeltimeHelp }, + { "selhour", func_time, 0, "hours", SeltimeHelp }, + { "seldate", func_datetime, 0, "startdateandenddate(formatYYYY-MM-DDThh:mm:ss)", SeltimeHelp }, + { "seltime", func_time, 0, "times(formathh:mm:ss)", SeltimeHelp }, + { "selsmon", func_date, 0, "month[,nts1[,nts2]]", SeltimeHelp } }, + .aliases = { { "selseas", "selseason" }, { "selmon", "selmonth" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Seltime> registration = RegisterEntry<Seltime>(module); + + int SELTIMESTEP, SELDATE, SELTIME, SELHOUR, SELDAY, SELMONTH, SELYEAR, SELSEASON, SELSMON; CdoStreamID streamID1; CdoStreamID streamID2 = CDO_STREAM_UNDEF; @@ -202,35 +228,21 @@ class ModuleSeltime FieldVector3D vars; std::vector<bool> selfound; - int SELTIMESTEP, SELDATE, SELTIME, SELHOUR, SELDAY, SELMONTH, SELYEAR, SELSEASON, SELSMON; - - enum - { - func_time, - func_date, - func_step, - func_datetime - }; - public: void - init(void *process) + init() { - cdo_initialize(process); - dataIsUnchanged = data_is_unchanged(); - // clang-format off - SELTIMESTEP = cdo_operator_add("seltimestep", func_step, 0, "timesteps"); - SELDATE = cdo_operator_add("seldate", func_datetime, 0, "start date and end date (format YYYY-MM-DDThh:mm:ss)"); - SELTIME = cdo_operator_add("seltime", func_time, 0, "times (format hh:mm:ss)"); - SELHOUR = cdo_operator_add("selhour", func_time, 0, "hours"); - SELDAY = cdo_operator_add("selday", func_date, 0, "days"); - SELMONTH = cdo_operator_add("selmonth", func_date, 0, "months"); - SELYEAR = cdo_operator_add("selyear", func_date, 0, "years"); - SELSEASON = cdo_operator_add("selseason", func_date, 0, "seasons"); - SELSMON = cdo_operator_add("selsmon", func_date, 0, "month[,nts1[,nts2]]"); - // clang-format on + SELTIMESTEP = module.get_id("seltimestep"); + SELDATE = module.get_id("seldate"); + SELTIME = module.get_id("seltime"); + SELHOUR = module.get_id("selhour"); + SELDAY = module.get_id("selday"); + SELMONTH = module.get_id("selmonth"); + SELYEAR = module.get_id("selyear"); + SELSEASON = module.get_id("selseason"); + SELSMON = module.get_id("selsmon"); operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -245,26 +257,32 @@ public: if (redirectEnabled) { // clang-format off - if (ID == SELTIMESTEP ) { newCommand += "timestep=" + argv; } - else if (ID == SELDATE) { newCommand += "date=" + argv; } - //else if(ID == SELTIME) { newCommand += "time=" + argv; } // unimplemented - else if (ID == SELHOUR) { newCommand += "hour=" + argv; } - else if (ID == SELDAY) { newCommand += "day=" + argv; } - else if (ID == SELMONTH) { newCommand += "month=" + argv; } - else if (ID == SELYEAR) { newCommand += "year=" + argv; } - else if (ID == SELSEASON) { newCommand += "season=" + argv; } - else if (ID == SELSMON) { newCommand += "month=" + argv; } - else { redirectFound = false; } + if (ID == SELTIMESTEP ) { newCommand += "timestep=" + argv; } + else if (ID == SELDATE) { newCommand += "date=" + argv; } + //else if(ID == SELTIME) { newCommand += "time=" + argv; } // unimplemented + else if (ID == SELHOUR) { newCommand += "hour=" + argv; } + else if (ID == SELDAY) { newCommand += "day=" + argv; } + else if (ID == SELMONTH) { newCommand += "month=" + argv; } + else if (ID == SELYEAR) { newCommand += "year=" + argv; } + else if (ID == SELSEASON) { newCommand += "season=" + argv; } + else if (ID == SELSMON) { newCommand += "month=" + argv; } + else { redirectFound = false; } // clang-format on } if (redirectFound && redirectEnabled) { - Debug(Yellow("Redirecting to %s"), newCommand); - ((Process *) process)->init_process("select", { newCommand }); - Select(process); - return; - // If a redirect was found the entire process is ended through this return! + cdo_abort("Redirecting was disabled and does no longer work"); + /* + * This was a temporary feature and does no longer work with the new module system. + * Redirecting has to be implemented in antother way or Select needs to be able to handle this kind of + * input. + * + * Debug(Yellow("Redirecting to %s"), newCommand); + * ((Process *) process)->init_process("select", { newCommand }); + * Select(process); + * return; + * // If a redirect was found the entire process is ended through this return! */ } if (operatorID == SELSEASON) @@ -352,7 +370,7 @@ public: if (operatorID == SELTIMESTEP) { - std::sort(intarr.begin(), intarr.end()); + ranges::sort(intarr); auto ip = std::unique(intarr.begin(), intarr.end()); intarr.resize(std::distance(intarr.begin(), ip)); numSel = intarr.size(); @@ -536,8 +554,8 @@ public: { cdo_def_record(streamID2, varID, levelID); auto single = vars[it][varID][levelID].vec_d.data(); - auto nmiss = vars[it][varID][levelID].nmiss; - cdo_write_record(streamID2, single, nmiss); + auto numMissVals = vars[it][varID][levelID].numMissVals; + cdo_write_record(streamID2, single, numMissVals); } } } @@ -567,8 +585,8 @@ public: { cdo_def_record(streamID2, varID, levelID); auto single = vars[nts][varID][levelID].vec_d.data(); - auto nmiss = vars[nts][varID][levelID].nmiss; - cdo_write_record(streamID2, single, nmiss); + auto numMissVals = vars[nts][varID][levelID].numMissVals; + cdo_write_record(streamID2, single, numMissVals); } } } @@ -612,7 +630,7 @@ public: for (levelID = 0; levelID < var.nlevels; ++levelID) { vars[it][varID][levelID].vec_d = vars[it + 1][varID][levelID].vec_d; - vars[it][varID][levelID].nmiss = vars[it + 1][varID][levelID].nmiss; + vars[it][varID][levelID].numMissVals = vars[it + 1][varID][levelID].numMissVals; } } } @@ -629,7 +647,7 @@ public: if (lnts1 || var.isConstant) { auto single = vars[nts][varID][levelID].vec_d.data(); - cdo_read_record(streamID1, single, &vars[nts][varID][levelID].nmiss); + cdo_read_record(streamID1, single, &vars[nts][varID][levelID].numMissVals); } } } @@ -694,17 +712,5 @@ public: close() { vlistDestroy(vlistID2); - cdo_finish(); } }; - -void * -Seltime(void *process) -{ - ModuleSeltime seltime; - seltime.init(process); - seltime.run(); - seltime.close(); - - return nullptr; -} diff --git a/src/Selvar.cc b/src/Selvar.cc index 0dcf3cf9ed3ef89e465a7b2f40932df26770970a..f52d0ed9c7a9bd34acdbac730073efe13369c778 100644 --- a/src/Selvar.cc +++ b/src/Selvar.cc @@ -33,8 +33,35 @@ #include "cdi_lockedIO.h" #include "param_conversion.h" -class ModuleSelvar +class Selvar : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selvar", + .operators = { { "selparam", 0, 2, "parameters", SelvarHelp }, + { "selcode", 0, 4, "code numbers", SelvarHelp }, + { "selname", 0, 2, "variable names", SelvarHelp }, + { "selstdname", 0, 2, "standard names", SelvarHelp }, + { "sellevel", 0, 8, "levels", SelvarHelp }, + { "sellevidx", 0, 4, "index of levels", SelvarHelp }, + { "selgrid", 0, 4 | 2, "list of grid names or numbers", SelvarHelp }, + { "selzaxis", 0, 4 | 2, "list of zaxis types or numbers", SelvarHelp }, + { "selzaxisname", 0, 2, "list of zaxis names", SelvarHelp }, + { "seltabnum", 0, 4, "table numbers", SelvarHelp }, + { "delparam", 1, 2 | 1, "parameter", SelvarHelp }, + { "delcode", 1, 1, "code numbers", SelvarHelp }, + { "delname", 1, 2 | 1, "variable names", SelvarHelp }, + { "selltype", 0, 4, "GRIB level types", SelvarHelp } }, + .aliases = { { "selvar", "selname" }, { "delvar", "delname" }, { "selgridname", "selgrid" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Selvar> registration = RegisterEntry<Selvar>(module); + + int SELPARAM, SELCODE, SELNAME, SELSTDNAME, SELLEVEL, SELLEVIDX, SELGRID, SELZAXIS, SELZAXISNAME, SELTABNUM, DELPARAM, DELCODE, + DELNAME, SELLTYPE; CdoStreamID streamID1; CdoStreamID streamID2; @@ -50,12 +77,9 @@ class ModuleSelvar bool dataIsUnchanged; - int SELPARAM, SELCODE, SELNAME, SELSTDNAME, SELLEVEL, SELLEVIDX, SELGRID, SELZAXIS, SELZAXISNAME, SELTABNUM, DELPARAM, DELCODE, - DELNAME, SELLTYPE; - public: void - init(void *process) + init() { int nsel = 0; char paramstr[32]; @@ -64,8 +88,6 @@ public: std::vector<int> intarr; std::vector<double> fltarr; - cdo_initialize(process); - dataIsUnchanged = data_is_unchanged(); #define INVERTS_SELECTION(id) (cdo_operator_f2(id) & 1) @@ -73,22 +95,20 @@ public: #define TAKES_INTEGERS(id) (cdo_operator_f2(id) & 4) #define TAKES_FLOATS(id) (cdo_operator_f2(id) & 8) - // clang-format off - SELPARAM = cdo_operator_add("selparam", 0, 2, "parameters"); - SELCODE = cdo_operator_add("selcode", 0, 4, "code numbers"); - SELNAME = cdo_operator_add("selname", 0, 2, "variable names"); - SELSTDNAME = cdo_operator_add("selstdname", 0, 2, "standard names"); - SELLEVEL = cdo_operator_add("sellevel", 0, 8, "levels"); - SELLEVIDX = cdo_operator_add("sellevidx", 0, 4, "index of levels"); - SELGRID = cdo_operator_add("selgrid", 0, 4|2, "list of grid names or numbers"); - SELZAXIS = cdo_operator_add("selzaxis", 0, 4|2, "list of zaxis types or numbers"); - SELZAXISNAME = cdo_operator_add("selzaxisname", 0, 2, "list of zaxis names"); - SELTABNUM = cdo_operator_add("seltabnum", 0, 4, "table numbers"); - DELPARAM = cdo_operator_add("delparam", 1, 2|1, "parameter"); - DELCODE = cdo_operator_add("delcode", 1, 1, "code numbers"); - DELNAME = cdo_operator_add("delname", 1, 2|1, "variable names"); - SELLTYPE = cdo_operator_add("selltype", 0, 4, "GRIB level types"); - // clang-format on + SELPARAM = module.get_id("selparam"); + SELCODE = module.get_id("selcode"); + SELNAME = module.get_id("selname"); + SELSTDNAME = module.get_id("selstdname"); + SELLEVEL = module.get_id("sellevel"); + SELLEVIDX = module.get_id("sellevidx"); + SELGRID = module.get_id("selgrid"); + SELZAXIS = module.get_id("selzaxis"); + SELZAXISNAME = module.get_id("selzaxisname"); + SELTABNUM = module.get_id("seltabnum"); + DELPARAM = module.get_id("delparam"); + DELCODE = module.get_id("delcode"); + DELNAME = module.get_id("delname"); + SELLTYPE = module.get_id("selltype"); auto operatorID = cdo_operator_id(); @@ -284,10 +304,10 @@ public: if (npar == 0) cdo_abort("No variables selected!"); - vlistID2 = vlistCreate(); + vlistID2 = vlistCreate(); cdo_vlist_copy_flag(vlistID2, vlistID1); - if (Options::cdoVerbose) vlistPrint(vlistID2); + // if (Options::cdoVerbose) vlistPrint(vlistID2); nvars = vlistNvars(vlistID2); { @@ -297,13 +317,14 @@ public: if (varID == nvars) vlistDefNtsteps(vlistID2, 0); } - taxisID1 = vlistInqTaxis(vlistID1); - taxisID2 = taxisDuplicate(taxisID1); + taxisID1 = vlistInqTaxis(vlistID1); + taxisID2 = taxisDuplicate(taxisID1); vlistDefTaxis(vlistID2, taxisID2); - streamID2 = cdo_open_write(1); + streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); } + void run() { @@ -348,17 +369,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Selvar(void *process) -{ - ModuleSelvar selvar; - selvar.init(process); - selvar.run(); - selvar.close(); - return nullptr; -} diff --git a/src/Selyearidx.cc b/src/Selyearidx.cc index 435133548c0f0c9b54ea5e01e6ca635cbe1c9ecf..52e477a13a572c65a043d2eae5136485e578a99f 100644 --- a/src/Selyearidx.cc +++ b/src/Selyearidx.cc @@ -17,8 +17,19 @@ #include "cdo_vlist.h" #include "field_functions.h" -class ModuleSelyearidx +class Selyearidx : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Selyearidx", + .operators = { { "selyearidx", SelyearidxHelp }, { "seltimeidx", 1, 0, SelyearidxHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Selyearidx> registration = RegisterEntry<Selyearidx>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -38,12 +49,8 @@ class ModuleSelyearidx public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("selyearidx", 0, 0, nullptr); - cdo_operator_add("seltimeidx", 1, 0, nullptr); ltime = cdo_operator_f1(cdo_operator_id()); @@ -110,9 +117,9 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, vars1[varID][levelID].vec_d.data(), &nmiss); - vars1[varID][levelID].nmiss = nmiss; + size_t numMissVals; + cdo_read_record(streamID1, vars1[varID][levelID].vec_d.data(), &numMissVals); + vars1[varID][levelID].numMissVals = numMissVals; if (tsID == 0) recList[recID].set(varID, levelID); } @@ -129,8 +136,8 @@ public: { int varID, levelID; cdo_inq_record(streamID2, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID2, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID2, array.data(), &numMissVals); const auto &var = varList2[varID]; for (size_t i = 0; i < var.gridsize; ++i) @@ -175,24 +182,11 @@ public: } } -void + void close() { cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Selyearidx(void *process) -{ - ModuleSelyearidx selyearidx; - selyearidx.init(process); - selyearidx.run(); - selyearidx.close(); - - return nullptr; -} diff --git a/src/Set.cc b/src/Set.cc index 8395813dfe0f1c421f755375d556e4e39996b1c6..86845c5aa8e23dd939b61ebdaca614ac9fba008a 100644 --- a/src/Set.cc +++ b/src/Set.cc @@ -25,12 +25,12 @@ static void set_level(int vlistID2, double newlevel) { - const auto nzaxis = vlistNzaxis(vlistID2); + auto nzaxis = vlistNzaxis(vlistID2); for (int index = 0; index < nzaxis; ++index) { - const auto zaxisID1 = vlistZaxis(vlistID2, index); - const auto zaxisID2 = zaxisDuplicate(zaxisID1); - const auto nlevs = zaxisInqSize(zaxisID2); + auto zaxisID1 = vlistZaxis(vlistID2, index); + auto zaxisID2 = zaxisDuplicate(zaxisID1); + auto nlevs = zaxisInqSize(zaxisID2); Varray<double> levels(nlevs); cdo_zaxis_inq_levels(zaxisID2, levels.data()); levels[0] = newlevel; @@ -42,20 +42,40 @@ set_level(int vlistID2, double newlevel) static void set_ltype(int vlistID2, double newval) { - const auto nzaxis = vlistNzaxis(vlistID2); + auto nzaxis = vlistNzaxis(vlistID2); for (int index = 0; index < nzaxis; ++index) { - const auto zaxisID1 = vlistZaxis(vlistID2, index); - const auto zaxisID2 = zaxisDuplicate(zaxisID1); - const auto zaxistype = ZAXIS_GENERIC; + auto zaxisID1 = vlistZaxis(vlistID2, index); + auto zaxisID2 = zaxisDuplicate(zaxisID1); + auto zaxistype = ZAXIS_GENERIC; zaxisChangeType(zaxisID2, zaxistype); cdiDefKeyInt(zaxisID2, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, newval); vlistChangeZaxis(vlistID2, zaxisID1, zaxisID2); } } -class ModuleSet +class Set : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Set", + .operators = { { "setcode", 0, 0, "code number", SetHelp }, + { "setparam", 0, 0, "parameter identifier (format:code[.tabnum]ornum[.cat[.dis]])", SetHelp }, + { "setname", 0, 0, "variable name", SetHelp }, + { "setunit", 0, 0, "variable unit", SetHelp }, + { "setlevel", 0, 0, "level", SetHelp }, + { "setltype", 0, 0, "GRIB level type", SetHelp }, + { "settabnum", 0, 0, "GRIB table number", SetHelp }, + { "setmaxsteps", 0, 0, "max. number of timesteps", SetHelp } }, + .aliases = { { "setvar", "setname" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Set> registration = RegisterEntry<Set>(module); + + int SETCODE, SETPARAM, SETNAME, SETUNIT, SETLEVEL, SETLTYPE, SETTABNUM, SETMAXSTEPS; int maxSteps = -1; int newval = -1, tabnum = 0; int newparam = 0; @@ -73,22 +93,18 @@ class ModuleSet public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - const auto SETCODE = cdo_operator_add("setcode", 0, 0, "code number"); - const auto SETPARAM = cdo_operator_add("setparam", 0, 0, "parameter identifier (format: code[.tabnum] or num[.cat[.dis]])"); - const auto SETNAME = cdo_operator_add("setname", 0, 0, "variable name"); - const auto SETUNIT = cdo_operator_add("setunit", 0, 0, "variable unit"); - const auto SETLEVEL = cdo_operator_add("setlevel", 0, 0, "level"); - const auto SETLTYPE = cdo_operator_add("setltype", 0, 0, "GRIB level type"); - const auto SETTABNUM = cdo_operator_add("settabnum", 0, 0, "GRIB table number"); - const auto SETMAXSTEPS = cdo_operator_add("setmaxsteps", 0, 0, "max. number of timesteps"); - // clang-format on + SETCODE = module.get_id("setcode"); + SETPARAM = module.get_id("setparam"); + SETNAME = module.get_id("setname"); + SETUNIT = module.get_id("setunit"); + SETLEVEL = module.get_id("setlevel"); + SETLTYPE = module.get_id("setltype"); + SETTABNUM = module.get_id("settabnum"); + SETMAXSTEPS = module.get_id("setmaxsteps"); - const auto operatorID = cdo_operator_id(); + auto operatorID = cdo_operator_id(); operator_input_arg(cdo_operator_enter(operatorID)); if (operatorID == SETCODE || operatorID == SETLTYPE) { newval = parameter_to_int(cdo_operator_argv(0)); } @@ -101,8 +117,8 @@ public: streamID1 = cdo_open_read(0); - const auto vlistID1 = cdo_stream_inq_vlist(streamID1); - const auto vlistID2 = vlistDuplicate(vlistID1); + auto vlistID1 = cdo_stream_inq_vlist(streamID1); + auto vlistID2 = vlistDuplicate(vlistID1); // vlistPrint(vlistID2); taxisID1 = vlistInqTaxis(vlistID1); @@ -111,7 +127,7 @@ public: if (operatorID == SETCODE) { - const auto nvars = vlistNvars(vlistID2); + auto nvars = vlistNvars(vlistID2); for (int varID = 0; varID < nvars; ++varID) vlistDefVarCode(vlistID2, varID, newval); } else if (operatorID == SETPARAM) { vlistDefVarParam(vlistID2, 0, newparam); } @@ -119,8 +135,8 @@ public: else if (operatorID == SETUNIT) { cdiDefKeyString(vlistID2, 0, CDI_KEY_UNITS, newunit); } else if (operatorID == SETTABNUM) { - const auto tableID = tableDef(-1, tabnum, nullptr); - const auto nvars = vlistNvars(vlistID2); + auto tableID = tableDef(-1, tabnum, nullptr); + auto nvars = vlistNvars(vlistID2); for (int varID = 0; varID < nvars; ++varID) vlistDefVarTable(vlistID2, varID, tableID); } else if (operatorID == SETLEVEL) { set_level(vlistID2, newlevel); } @@ -138,7 +154,7 @@ public: int tsID = 0; while (true) { - const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); if (nrecs == 0) break; cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -163,17 +179,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Set(void *process) -{ - ModuleSet set; - set.init(process); - set.run(); - set.close(); - return nullptr; -} diff --git a/src/Setattribute.cc b/src/Setattribute.cc index 37f3a1c2fc61b8dc362c3e7c6979df93b36c7993..afbea5dd8357a01a3ff947b14189e2a8569e5e18 100644 --- a/src/Setattribute.cc +++ b/src/Setattribute.cc @@ -189,9 +189,7 @@ find_attribute(int cdiID, int varID, const std::string &attrName, int &dtype) auto longname = cdo::inq_var_longname(cdiID, varID); auto units = cdo::inq_var_units(cdiID, varID); - auto param = vlistInqVarParam(cdiID, varID); - char paramstr[32]; - param_to_string(param, paramstr, sizeof(paramstr)); + auto paramstr = param_to_string(vlistInqVarParam(cdiID, varID)); auto code = vlistInqVarCode(cdiID, varID); auto table = vlistInqVarTable(cdiID, varID); @@ -349,8 +347,20 @@ set_attributes(const KVList &kvlist, int vlistID) } } -class ModuleSetattribute +class Setattribute : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setattribute", + .operators = { { "setattribute", 0, 0, "attributes", SetattributeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Setattribute> registration = RegisterEntry<Setattribute>(module); + CdoStreamID streamID1; CdoStreamID streamID2; @@ -364,12 +374,8 @@ class ModuleSetattribute public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("setattribute", 0, 0, "attributes"); - dataIsUnchanged = data_is_unchanged(); auto operatorID = cdo_operator_id(); @@ -382,7 +388,7 @@ public: PMList pmlist; KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(natts, cdo_get_oper_argv()) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(cdo_get_oper_argv()) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); auto pkvlist = &kvlist; @@ -455,17 +461,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - cdo_finish(); } }; - -void * -Setattribute(void *process) -{ - ModuleSetattribute setattribute; - setattribute.init(process); - setattribute.run(); - setattribute.close(); - - return nullptr; -} diff --git a/src/Setbox.cc b/src/Setbox.cc index 790e874cdee2ab1a3d1884aa773cc2c2fdac37d9..5ef49deac3d1440e0a822606e9633de2a32f497d 100644 --- a/src/Setbox.cc +++ b/src/Setbox.cc @@ -28,8 +28,8 @@ setcbox(double constant, double *array, int gridID, const SelboxInfo &selboxInfo const auto &lon12 = selboxInfo.lon12; const auto &lon21 = selboxInfo.lon21; const auto &lon22 = selboxInfo.lon22; - const long nlon = gridInqXsize(gridID); - const long nlat = gridInqYsize(gridID); + long nlon = gridInqXsize(gridID); + long nlat = gridInqYsize(gridID); for (long ilat = 0; ilat < nlat; ilat++) for (long ilon = 0; ilon < nlon; ilon++) @@ -44,17 +44,17 @@ get_gridID(int vlistID1, bool operIndexBox) { std::vector<int> gridsFound; - const auto ngrids = vlistNgrids(vlistID1); + auto ngrids = vlistNgrids(vlistID1); for (int index = 0; index < ngrids; ++index) { - const auto gridID1 = vlistGrid(vlistID1, index); + auto gridID1 = vlistGrid(vlistID1, index); if (gridInqSize(gridID1) == 1) continue; - const auto gridtype = gridInqType(gridID1); - const auto projtype = gridInqProjType(gridID1); + auto gridtype = gridInqType(gridID1); + auto projtype = gridInqProjType(gridID1); - const auto isReg2dGeoGrid = (gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || gridtype == GRID_CURVILINEAR); - const auto projHasGeoCoords = (gridtype == GRID_PROJECTION && projtype == CDI_PROJ_RLL); + auto isReg2dGeoGrid = (gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || gridtype == GRID_CURVILINEAR); + auto projHasGeoCoords = (gridtype == GRID_PROJECTION && projtype == CDI_PROJ_RLL); if (isReg2dGeoGrid || projHasGeoCoords || (operIndexBox && (gridtype == GRID_GENERIC || gridtype == GRID_PROJECTION))) { @@ -69,14 +69,14 @@ get_gridID(int vlistID1, bool operIndexBox) if (gridsFound.size() == 0) cdo_abort("No processable grid found!"); if (gridsFound.size() > 1) cdo_abort("Too many different grids!"); - const auto gridID = gridsFound[0]; + auto gridID = gridsFound[0]; return gridID; } static std::vector<bool> get_processVars(int vlistID1, int gridID) { - const auto nvars = vlistNvars(vlistID1); + auto nvars = vlistNvars(vlistID1); std::vector<bool> processVars(nvars, false); @@ -92,8 +92,22 @@ get_processVars(int vlistID1, int gridID) return processVars; } -class ModuleSetbox +class Setbox : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setbox", + .operators = { { "setclonlatbox", 0, 0, "constant, western and eastern longitude and southern and northern latitude", SetboxHelp }, + { "setcindexbox", 0, 0, "constant, index of first and last longitude and index of first and last latitude", SetboxHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Setbox> registration = RegisterEntry<Setbox>(module); + + int SETCLONLATBOX, SETCINDEXBOX; CdoStreamID streamID1; CdoStreamID streamID2; @@ -109,24 +123,19 @@ class ModuleSetbox Varray<double> array; std::vector<bool> processVars; - int SETCLONLATBOX, SETCINDEXBOX; SelboxInfo selboxInfo; public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - SETCLONLATBOX = cdo_operator_add("setclonlatbox", 0, 0, "constant, western and eastern longitude and southern and northern latitude"); - SETCINDEXBOX = cdo_operator_add("setcindexbox", 0, 0, "constant, index of first and last longitude and index of first and last latitude"); - // clang-format on + SETCLONLATBOX = module.get_id("setclonlatbox"); + SETCINDEXBOX = module.get_id("setcindexbox"); (void) SETCLONLATBOX; - const auto operatorID = cdo_operator_id(); - const auto operIndexBox = (operatorID == SETCINDEXBOX); + auto operatorID = cdo_operator_id(); + auto operIndexBox = (operatorID == SETCINDEXBOX); operator_input_arg(cdo_operator_enter(operatorID)); @@ -143,7 +152,7 @@ public: selboxInfo = operIndexBox ? gen_index_selbox(1, gridID) : gen_lonlat_selbox(1, gridID); - const auto vlistID2 = vlistDuplicate(vlistID1); + auto vlistID2 = vlistDuplicate(vlistID1); taxisID1 = vlistInqTaxis(vlistID1); taxisID2 = taxisDuplicate(taxisID1); @@ -156,13 +165,14 @@ public: gridsize = gridInqSize(gridID); array = Varray<double>(gridsize); } + void run() { int tsID = 0; while (true) { - const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); if (nrecs == 0) break; cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -175,38 +185,26 @@ public: if (processVars[varID]) { - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); setcbox(constant, array.data(), gridID, selboxInfo); - const auto missval = vlistInqVarMissval(vlistID1, varID); - nmiss = varray_num_mv(gridsize, array, missval); + auto missval = vlistInqVarMissval(vlistID1, varID); + numMissVals = varray_num_mv(gridsize, array, missval); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); } } tsID++; } } + void close() { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Setbox(void *process) -{ - ModuleSetbox setbox; - setbox.init(process); - setbox.run(); - setbox.close(); - - return nullptr; -} diff --git a/src/Setgrid.cc b/src/Setgrid.cc index 6c511155f94229d5b17ef4cec377775ea4508819..6a1fb6a8624540cf379bdaebbdf37c5184792205 100644 --- a/src/Setgrid.cc +++ b/src/Setgrid.cc @@ -100,6 +100,11 @@ grid_set_type(int vlistID1, int vlistID2, int gridtype, const std::string &gridn gridID2 = -1; cdo_warning("Conversion of generic grid to regular grid failed!"); } + else if (gridtype == GRID_LONLAT && gridtype1 == GRID_PROJECTION) + { + gridID2 = gridProjectionToRegular(gridID1); + if (gridID2 == -1) cdo_warning("Conversion of projection to regular grid failed!"); + } else if (gridtype == GRID_LONLAT && gridtype1 == GRID_LONLAT) { gridID2 = gridID1; } else if (gridtype == GRID_PROJECTION) { @@ -254,8 +259,8 @@ grid_read_cellarea(const std::string &areafile, Varray<double> &gridcellArea) auto areasize = gridInqSize(varList[varID].gridID); gridcellArea.resize(areasize); - size_t nmiss; - streamReadRecord(streamID, gridcellArea.data(), &nmiss); + size_t numMissVals; + streamReadRecord(streamID, gridcellArea.data(), &numMissVals); break; } } @@ -263,8 +268,29 @@ grid_read_cellarea(const std::string &areafile, Varray<double> &gridcellArea) streamClose(streamID); } -class ModuleSetgrid +class Setgrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setgrid", + .operators = { { "setgrid", 0, 0, "grid description file or name", SetgridHelp }, + { "setgridtype", 0, 0, "gridtype", SetgridHelp }, + { "setgridarea", 0, 0, "filename with areaweights", SetgridHelp }, + { "setgridmask", 0, 0, "filename with gridmask", SetgridHelp }, + { "unsetgridmask", SetgridHelp }, + { "setgridnumber", 0, 0, "gridnumber and optionally grid position", SetgridHelp }, + { "setgriduri", 0, 0, "reference URI of the horizontal grid", SetgridHelp }, + { "usegridnumber", 0, 0, "use existing grid identified by gridnumber", SetgridHelp }, + { "setprojparams", 0, 0, "proj library parameter (e.g.:+init=EPSG:3413)", SetgridHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Setgrid>(module); + + int SETGRID, SETGRIDTYPE, SETGRIDAREA, SETGRIDMASK, UNSETGRIDMASK, SETGRIDNUMBER, SETGRIDURI, USEGRIDNUMBER, SETPROJPARAMS; CdoStreamID streamID1; CdoStreamID streamID2; @@ -281,7 +307,7 @@ class ModuleSetgrid public: void - init(void *process) + init() { int number = 0, position = 0; std::string griduri; @@ -289,19 +315,15 @@ public: std::string gridname; std::string gridfile; - cdo_initialize(process); - - // clang-format off - auto SETGRID = cdo_operator_add("setgrid", 0, 0, "grid description file or name"); - auto SETGRIDTYPE = cdo_operator_add("setgridtype", 0, 0, "grid type"); - auto SETGRIDAREA = cdo_operator_add("setgridarea", 0, 0, "filename with area weights"); - auto SETGRIDMASK = cdo_operator_add("setgridmask", 0, 0, "filename with grid mask"); - auto UNSETGRIDMASK = cdo_operator_add("unsetgridmask", 0, 0, nullptr); - auto SETGRIDNUMBER = cdo_operator_add("setgridnumber", 0, 0, "grid number and optionally grid position"); - auto SETGRIDURI = cdo_operator_add("setgriduri", 0, 0, "reference URI of the horizontal grid"); - auto USEGRIDNUMBER = cdo_operator_add("usegridnumber", 0, 0, "use existing grid identified by grid number"); - auto SETPROJPARAMS = cdo_operator_add("setprojparams", 0, 0, "proj library parameter (e.g.: +init=EPSG:3413)"); - // clang-format on + SETGRID = module.get_id("setgrid"); + SETGRIDTYPE = module.get_id("setgridtype"); + SETGRIDAREA = module.get_id("setgridarea"); + SETGRIDMASK = module.get_id("setgridmask"); + UNSETGRIDMASK = module.get_id("unsetgridmask"); + SETGRIDNUMBER = module.get_id("setgridnumber"); + SETGRIDURI = module.get_id("setgriduri"); + USEGRIDNUMBER = module.get_id("usegridnumber"); + SETPROJPARAMS = module.get_id("setprojparams"); auto operatorID = cdo_operator_id(); @@ -346,8 +368,8 @@ public: auto masksize = gridInqSize(gridID); gridmask.resize(masksize); - size_t nmiss; - streamReadRecord(streamID, gridmask.data(), &nmiss); + size_t numMissVals; + streamReadRecord(streamID, gridmask.data(), &numMissVals); streamClose(streamID); for (size_t i = 0; i < masksize; ++i) @@ -482,7 +504,7 @@ public: field.init((lregular || lregularnn) ? varList2[varID] : varList1[varID]); cdo_read_record(streamID1, field); - auto nmiss = field.nmiss; + auto numMissVals = field.numMissVals; auto gridID1 = varList1[varID].gridID; if (lregular || lregularnn) @@ -491,7 +513,7 @@ public: { auto missval = varList1[varID].missval; int lnearst = lregularnn ? 1 : 0; - field2regular(gridID1, varList2[varID].gridID, missval, field.vec_d.data(), nmiss, lnearst); + field2regular(gridID1, varList2[varID].gridID, missval, field.vec_d.data(), numMissVals, lnearst); } } else if (gridInqType(gridID1) == GRID_GME) @@ -521,17 +543,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Setgrid(void *process) -{ - ModuleSetgrid setgrid; - setgrid.init(process); - setgrid.run(); - setgrid.close(); - return nullptr; -} diff --git a/src/Setgridcell.cc b/src/Setgridcell.cc index b95c19295edc2f0075c79777c44b21bcc16fb56d..5e8fa8c8495c40bf01dd72d631cf802db121780e 100644 --- a/src/Setgridcell.cc +++ b/src/Setgridcell.cc @@ -31,9 +31,9 @@ static void set_value(Field &field, double value) { if (field.memType == MemType::Float) - field.nmiss = set_value(field.size, field.vec_f, (float) field.missval, (float) value); + field.numMissVals = set_value(field.size, field.vec_f, (float) field.missval, (float) value); else - field.nmiss = set_value(field.size, field.vec_d, field.missval, value); + field.numMissVals = set_value(field.size, field.vec_d, field.missval, value); } template <typename T> @@ -54,9 +54,9 @@ static void set_value(Field &field, double value, const Varray<size_t> &cells) { if (field.memType == MemType::Float) - field.nmiss = set_value(field.size, field.vec_f, (float) field.missval, (float) value, cells); + field.numMissVals = set_value(field.size, field.vec_f, (float) field.missval, (float) value, cells); else - field.nmiss = set_value(field.size, field.vec_d, field.missval, value, cells); + field.numMissVals = set_value(field.size, field.vec_d, field.missval, value, cells); } static void @@ -88,7 +88,7 @@ setgridcell_get_parameter(double &constant, Varray<size_t> &cells, std::vector<s KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -126,8 +126,19 @@ setgridcell_get_parameter(double &constant, Varray<size_t> &cells, std::vector<s } } -class ModuleSetgridcell +class Setgridcell : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setgridcell", + .operators = { { "setgridcell", 0, 0, "value=constant[,cell=gridcellindices(1-N)]", SetgridcellHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Setgridcell> registration = RegisterEntry<Setgridcell>(module); Field field; @@ -149,11 +160,8 @@ class ModuleSetgridcell public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("setgridcell", 0, 0, "value=constant[, cell=grid cell indices (1-N)]"); operator_input_arg(cdo_operator_enter(0)); @@ -254,17 +262,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Setgridcell(void *process) -{ - ModuleSetgridcell setgridcell; - setgridcell.init(process); - setgridcell.run(); - setgridcell.close(); - return nullptr; -} diff --git a/src/Sethalo.cc b/src/Sethalo.cc index 0f73d78c1dca412efddef360f83774c9fcbf96fd..3957d0118fa6621d9f4caac14ab6296d94b105bb 100644 --- a/src/Sethalo.cc +++ b/src/Sethalo.cc @@ -350,7 +350,7 @@ get_parameter(void) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -382,10 +382,7 @@ gen_index_grid(int gridID1, Halo &halo) halo.east = parameter_to_long(cdo_operator_argv(0)); halo.west = parameter_to_long(cdo_operator_argv(1)); } - else - { - halo = get_parameter(); - } + else { halo = get_parameter(); } auto isCircularGrid = gridIsCircular(gridID1); long nlon = gridInqXsize(gridID1); @@ -502,8 +499,20 @@ get_gridID(int vlistID1) return gridID1; } -class ModuleSethalo +class Sethalo : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Sethalo", + .operators = { { "sethalo", SethaloHelp }, { "tpnhalo", SethaloHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Sethalo> registration = RegisterEntry<Sethalo>(module); + int SETHALO; int operatorID; @@ -525,14 +534,9 @@ class ModuleSethalo public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - SETHALO = cdo_operator_add("sethalo", 0, 0, nullptr); - cdo_operator_add("tpnhalo", 0, 0, nullptr); - // clang-format on + SETHALO = module.get_id("sethalo"); operatorID = cdo_operator_id(); @@ -591,8 +595,8 @@ public: if (vars[varID]) { - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); auto recalcNumMiss = false; auto missval = varList[varID].missval; @@ -601,10 +605,10 @@ public: else tripolar_halo(array1, gridID1, array2); - if (nmiss || recalcNumMiss) nmiss = varray_num_mv(array2.size(), array2, missval); + if (numMissVals || recalcNumMiss) numMissVals = varray_num_mv(array2.size(), array2, missval); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } } @@ -617,18 +621,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Sethalo(void *process) -{ - ModuleSethalo sethalo; - sethalo.init(process); - sethalo.run(); - sethalo.close(); - - return nullptr; -} diff --git a/src/Setmiss.cc b/src/Setmiss.cc index c4d93fc2871603282d962507e83c4a04cc2dc0d3..aade5cc3617b0acaf5a0d24e48c87c3b4511fed2 100644 --- a/src/Setmiss.cc +++ b/src/Setmiss.cc @@ -25,39 +25,39 @@ template <typename T> static size_t set_missval(size_t gridsize, Varray<T> &array, T missval, T new_missval) { - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) if (DBL_IS_EQUAL(array[i], missval) || DBL_IS_EQUAL(array[i], (float) missval) || DBL_IS_EQUAL(array[i], new_missval) || DBL_IS_EQUAL(array[i], (float) new_missval)) { array[i] = new_missval; - nmiss++; + numMissVals++; } - return nmiss; + return numMissVals; } static void set_missval(Field &field, double new_missval) { if (field.memType == MemType::Float) - field.nmiss = set_missval(field.size, field.vec_f, (float) field.missval, (float) new_missval); + field.numMissVals = set_missval(field.size, field.vec_f, (float) field.missval, (float) new_missval); else - field.nmiss = set_missval(field.size, field.vec_d, field.missval, new_missval); + field.numMissVals = set_missval(field.size, field.vec_d, field.missval, new_missval); } template <typename T> static size_t set_const_to_miss(size_t gridsize, Varray<T> &array, T missval, T rconst) { - size_t nmiss = 0; + size_t numMissVals = 0; if (std::isnan(rconst)) { for (size_t i = 0; i < gridsize; ++i) if (std::isnan(array[i])) { array[i] = missval; - nmiss++; + numMissVals++; } } else @@ -66,20 +66,20 @@ set_const_to_miss(size_t gridsize, Varray<T> &array, T missval, T rconst) if (DBL_IS_EQUAL(array[i], rconst) || DBL_IS_EQUAL(array[i], (float) rconst)) { array[i] = missval; - nmiss++; + numMissVals++; } } - return nmiss; + return numMissVals; } static void set_const_to_miss(Field &field, double rconst) { if (field.memType == MemType::Float) - field.nmiss += set_const_to_miss(field.size, field.vec_f, (float) field.missval, (float) rconst); + field.numMissVals += set_const_to_miss(field.size, field.vec_f, (float) field.missval, (float) rconst); else - field.nmiss += set_const_to_miss(field.size, field.vec_d, field.missval, rconst); + field.numMissVals += set_const_to_miss(field.size, field.vec_d, field.missval, rconst); } template <typename T> @@ -96,33 +96,33 @@ static void set_miss_to_const(Field &field, double rconst) { if (field.memType == MemType::Float) - field.nmiss = set_miss_to_const(field.size, field.vec_f, (float) field.missval, (float) rconst); + field.numMissVals = set_miss_to_const(field.size, field.vec_f, (float) field.missval, (float) rconst); else - field.nmiss = set_miss_to_const(field.size, field.vec_d, field.missval, rconst); + field.numMissVals = set_miss_to_const(field.size, field.vec_d, field.missval, rconst); } template <typename T> static size_t set_range_to_miss(size_t gridsize, Varray<T> &array, T missval, T rmin, T rmax) { - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) if (array[i] >= rmin && array[i] <= rmax) { array[i] = missval; - nmiss++; + numMissVals++; } - return nmiss; + return numMissVals; } static void set_range_to_miss(Field &field, double rmin, double rmax) { if (field.memType == MemType::Float) - field.nmiss += set_range_to_miss(field.size, field.vec_f, (float) field.missval, (float) rmin, (float) rmax); + field.numMissVals += set_range_to_miss(field.size, field.vec_f, (float) field.missval, (float) rmin, (float) rmax); else - field.nmiss += set_range_to_miss(field.size, field.vec_d, field.missval, rmin, rmax); + field.numMissVals += set_range_to_miss(field.size, field.vec_d, field.missval, rmin, rmax); } template <typename T> @@ -132,22 +132,38 @@ set_valid_range(size_t gridsize, Varray<T> &array, T missval, T rmin, T rmax) for (size_t i = 0; i < gridsize; ++i) if (array[i] < rmin || array[i] > rmax) array[i] = missval; - const auto nmiss = varray_num_mv(gridsize, array, missval); + const auto numMissVals = varray_num_mv(gridsize, array, missval); - return nmiss; + return numMissVals; } static void set_valid_range(Field &field, double rmin, double rmax) { if (field.memType == MemType::Float) - field.nmiss = set_valid_range(field.size, field.vec_f, (float) field.missval, (float) rmin, (float) rmax); + field.numMissVals = set_valid_range(field.size, field.vec_f, (float) field.missval, (float) rmin, (float) rmax); else - field.nmiss = set_valid_range(field.size, field.vec_d, field.missval, rmin, rmax); + field.numMissVals = set_valid_range(field.size, field.vec_d, field.missval, rmin, rmax); } -class ModuleSetmiss +class Setmiss : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setmiss", + .operators = { { "setmissval", 0, 0, "missing value", SetmissHelp }, + { "setctomiss", 0, 0, "constant", SetmissHelp }, + { "setmisstoc", 0, 0, "constant", SetmissHelp }, + { "setrtomiss", 0, 0, "range(min,max)", SetmissHelp }, + { "setvrange", 0, 0, "range(min,max)", SetmissHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Setmiss> registration = RegisterEntry<Setmiss>(module); + int SETMISSVAL, SETCTOMISS, SETMISSTOC, SETRTOMISS, SETVRANGE; CdoStreamID streamID1; CdoStreamID streamID2; @@ -158,8 +174,6 @@ class ModuleSetmiss Field field; int operatorID; - int SETMISSVAL, SETCTOMISS, SETMISSTOC, SETRTOMISS, SETVRANGE; - double rconst = 0.0; double rmin = 0.0; double rmax = 0.0; @@ -167,16 +181,15 @@ class ModuleSetmiss public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - SETMISSVAL = cdo_operator_add("setmissval", 0, 0, "missing value"); - SETCTOMISS = cdo_operator_add("setctomiss", 0, 0, "constant"); - SETMISSTOC = cdo_operator_add("setmisstoc", 0, 0, "constant"); - SETRTOMISS = cdo_operator_add("setrtomiss", 0, 0, "range (min, max)"); - SETVRANGE = cdo_operator_add("setvrange", 0, 0, "range (min, max)"); +SETMISSVAL = module.get_id("setmissval"); +SETCTOMISS = module.get_id("setctomiss"); +SETMISSTOC = module.get_id("setmisstoc"); +SETRTOMISS = module.get_id("setrtomiss"); +SETVRANGE = module.get_id("setvrange"); // clang-format on operatorID = cdo_operator_id(); @@ -280,17 +293,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Setmiss(void *process) -{ - ModuleSetmiss setmiss; - setmiss.init(process); - setmiss.run(); - setmiss.close(); - - return nullptr; -} diff --git a/src/Setpartab.cc b/src/Setpartab.cc index 34725167b71f4c36fd2fe5942e06ecab79eda18d..bf7420feb4b36dc759cb8b0c6c902954a6022e4e 100644 --- a/src/Setpartab.cc +++ b/src/Setpartab.cc @@ -151,8 +151,24 @@ apply_parameterList(pt_mode_t ptmode, PMList &pmlist, int nvars, int vlistID2, s } } -class ModuleSetpartab +class Setpartab : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setpartab", + .operators = { { "setcodetab", 0, 0, "parameter code table name", SetHelp }, + { "setpartabc", 0, 0, "parameter table name", SetpartabHelp }, + { "setpartabp", 0, 0, "parameter table name", SetpartabHelp }, + { "setpartabn", 0, 0, "parameter table name", SetpartabHelp } }, + .aliases = { { "setpartab", "setcodetab" }, { "setpartabv", "setpartabn" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Setpartab> registration = RegisterEntry<Setpartab>(module); + + int SETCODETAB, SETPARTABC, SETPARTABP, SETPARTABN; int tableID = -1; int tableformat = 0; bool deleteVars = false; @@ -172,19 +188,14 @@ class ModuleSetpartab Varray<double> array; VarList varList2; - int SETCODETAB, SETPARTABC, SETPARTABP, SETPARTABN; - public: void - init(void *process) + init() { - - cdo_initialize(process); - - SETCODETAB = cdo_operator_add("setcodetab", 0, 0, "parameter code table name"); - SETPARTABC = cdo_operator_add("setpartabc", 0, 0, "parameter table name"); - SETPARTABP = cdo_operator_add("setpartabp", 0, 0, "parameter table name"); - SETPARTABN = cdo_operator_add("setpartabn", 0, 0, "parameter table name"); + SETCODETAB = module.get_id("setcodetab"); + SETPARTABC = module.get_id("setpartabc"); + SETPARTABP = module.get_id("setpartabp"); + SETPARTABN = module.get_id("setpartabn"); auto operatorID = cdo_operator_id(); @@ -389,13 +400,13 @@ public: cdo_def_record(streamID2, varID2, levelID2); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); auto missval = varList2[varID2].missval; auto gridsize = varList2[varID2].nwpv * varList2[varID2].gridsize; - if (nmiss && var.changemissval) + if (numMissVals && var.changemissval) { for (size_t i = 0; i < gridsize; ++i) { @@ -432,7 +443,7 @@ public: } #endif - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); cmor_check_prep(var, gridsize, missval, array.data()); } @@ -455,17 +466,5 @@ public: cdo_convert_destroy(); #endif - - cdo_finish(); } }; -void * -Setpartab(void *process) -{ - ModuleSetpartab setpartab; - setpartab.init(process); - setpartab.run(); - setpartab.close(); - - return nullptr; -} diff --git a/src/Setrcaname.cc b/src/Setrcaname.cc index e88ed182aaf04f3451d32a49a03f00e525ca9ca5..3f3ad613ef5b7eade9c7af74bf617449050bb140 100644 --- a/src/Setrcaname.cc +++ b/src/Setrcaname.cc @@ -5,22 +5,26 @@ */ +#include <fstream> + #include <cdi.h> #include "process_int.h" -#include "readline.h" #include "cdo_zaxis.h" -#define MAX_LINE_LEN 4096 - -class ModuleSetrcaname +class Setrcaname : public Process { - const char *rcsnames; - char line[MAX_LINE_LEN]; - char sname[CDI_MAX_NAME], sdescription[CDI_MAX_NAME], sunits[CDI_MAX_NAME]; - int scode, sltype, slevel; - int zaxisID, ltype, code, nlev; - int level; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setrcaname", + .operators = { { "setrcaname"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static auto registration = RegisterEntry<Setrcaname>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -39,47 +43,42 @@ class ModuleSetrcaname Field field; void - read_rca(const char *p_filename, int p_nvars, int p_vlistID2) + read_rca(const std::string &filename, int p_nvars, int p_vlistID2) { - auto fp = std::fopen(p_filename, "r"); - if (fp != nullptr) + std::ifstream file(filename); + if (!file.is_open()) cdo_abort("Open failed on: %s\n", filename); + + std::string line; + while (std::getline(file, line)) { - while (cdo::readline(fp, line, MAX_LINE_LEN)) + char sname[CDI_MAX_NAME], sdescription[CDI_MAX_NAME], sunits[CDI_MAX_NAME]; + int scode, sltype, slevel; + std::sscanf(line.c_str(), "%d\t%d\t%d\t%s\t%s\t%s", &scode, &sltype, &slevel, sname, sdescription, sunits); + /* + printf("%s\n", line); + printf("%d:%d:%d:%s:%s:%s\n", scode, sltype, slevel, sname, + sdescription, sunits); + */ + for (int varID = 0; varID < p_nvars; ++varID) { - std::sscanf(line, "%d\t%d\t%d\t%s\t%s\t%s", &scode, &sltype, &slevel, sname, sdescription, sunits); - /* - printf("%s\n", line); - printf("%d:%d:%d:%s:%s:%s\n", scode, sltype, slevel, sname, - sdescription, sunits); - */ - for (int varID = 0; varID < p_nvars; ++varID) - { - code = vlistInqVarCode(p_vlistID2, varID); - zaxisID = vlistInqVarZaxis(p_vlistID2, varID); - nlev = zaxisInqSize(zaxisID); + auto code = vlistInqVarCode(p_vlistID2, varID); + auto zaxisID = vlistInqVarZaxis(p_vlistID2, varID); + auto nlev = zaxisInqSize(zaxisID); - ltype = zaxis_to_ltype(zaxisID); + auto ltype = zaxis_to_ltype(zaxisID); - if (code == scode) + if (code == scode) + { + if (ltype == 105) { - if (ltype == 105) + if (nlev != 1) { - if (nlev != 1) - { - cdo_warning("Number of levels should be 1 for level type 105!"); - cdo_warning("Maybe environment variable SPLIT_LTYPE_105 is not set."); - continue; - } - level = (int) cdo_zaxis_inq_level(zaxisID, 0); - if (sltype == 105 && slevel == level) - { - cdiDefKeyString(p_vlistID2, varID, CDI_KEY_NAME, sname); - cdiDefKeyString(p_vlistID2, varID, CDI_KEY_LONGNAME, sdescription); - cdiDefKeyString(p_vlistID2, varID, CDI_KEY_UNITS, sunits); - break; - } + cdo_warning("Number of levels should be 1 for level type 105!"); + cdo_warning("Maybe environment variable SPLIT_LTYPE_105 is not set."); + continue; } - else if (sltype != 105) + auto level = (int) cdo_zaxis_inq_level(zaxisID, 0); + if (sltype == 105 && slevel == level) { cdiDefKeyString(p_vlistID2, varID, CDI_KEY_NAME, sname); cdiDefKeyString(p_vlistID2, varID, CDI_KEY_LONGNAME, sdescription); @@ -87,24 +86,28 @@ class ModuleSetrcaname break; } } + else if (sltype != 105) + { + cdiDefKeyString(p_vlistID2, varID, CDI_KEY_NAME, sname); + cdiDefKeyString(p_vlistID2, varID, CDI_KEY_LONGNAME, sdescription); + cdiDefKeyString(p_vlistID2, varID, CDI_KEY_UNITS, sunits); + break; + } } } - - std::fclose(fp); } - else { perror(rcsnames); } + + file.close(); } public: void - init(void *process) + init() { - cdo_initialize(process); - dataIsUnchanged = data_is_unchanged(); operator_input_arg("file name with RCA names"); - rcsnames = cdo_operator_argv(0).c_str(); + auto rcsnames = cdo_operator_argv(0); streamID1 = cdo_open_read(0); @@ -164,17 +167,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Setrcaname(void *process) -{ - ModuleSetrcaname setrcaname; - setrcaname.init(process); - setrcaname.run(); - setrcaname.close(); - return nullptr; -} diff --git a/src/Settime.cc b/src/Settime.cc index 6690f624ecccbefdc5896a924ab08f7609f49304..3ce9d159f784964272ed375cce83df82532c443f 100644 --- a/src/Settime.cc +++ b/src/Settime.cc @@ -162,8 +162,30 @@ timeunits_is_valid(int timeUnits) || timeUnits == TUNIT_DAY || timeUnits == TUNIT_MONTH || timeUnits == TUNIT_YEAR); } -class ModuleSettime +class Settime : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Settime", + .operators = { { "setyear", 0, 1, "year", SettimeHelp }, + { "setmon", 0, 1, "month", SettimeHelp }, + { "setday", 0, 1, "day", SettimeHelp }, + { "setdate", 0, 1, "date(format:YYYY-MM-DD)", SettimeHelp }, + { "settime", 0, 1, "time(format:hh:mm:ss)", SettimeHelp }, + { "settunits", 0, 1, "timeunits(seconds,minutes,hours,days,months,years)", SettimeHelp }, + { "settaxis", 0, -2, "date<,time<,increment>>(formatYYYY-MM-DD,hh:mm:ss)", SettimeHelp }, + { "settbounds", 0, 1, "frequency(hour,day,month,year)", SettimeHelp }, + { "setreftime", 0, -2, "date<,time<,units>>(formatYYYY-MM-DD,hh:mm:ss)", SettimeHelp }, + { "setcalendar", 0, 1, "calendar(standard,proleptic_gregorian,360_day,365_day,366_day)", SettimeHelp }, + { "shifttime", 0, 1, "shiftvalue", SettimeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Settime> registration = RegisterEntry<Settime>(module); + int SETYEAR, SETMON, SETDAY, SETDATE, SETTIME, SETTUNITS, SETTAXIS, SETTBOUNDS, SETREFTIME, SETCALENDAR, SHIFTTIME; int64_t newval = 0; int timeUnits = TUNIT_DAY; int64_t ijulinc = 0; @@ -178,8 +200,6 @@ class ModuleSettime CdiDateTime vDateTimeBounds[2]{}; JulianDate julianDate; - int SETYEAR, SETMON, SETDAY, SETDATE, SETTIME, SETTUNITS, SETTAXIS, SETTBOUNDS, SETREFTIME, SETCALENDAR, SHIFTTIME; - CdoStreamID streamID1; CdoStreamID streamID2 = CDO_STREAM_UNDEF; @@ -198,23 +218,21 @@ class ModuleSettime public: void - init(void *process) + init() { - cdo_initialize(process); - // clang-format off - SETYEAR = cdo_operator_add("setyear", 0, 1, "year"); - SETMON = cdo_operator_add("setmon", 0, 1, "month"); - SETDAY = cdo_operator_add("setday", 0, 1, "day"); - SETDATE = cdo_operator_add("setdate", 0, 1, "date (format: YYYY-MM-DD)"); - SETTIME = cdo_operator_add("settime", 0, 1, "time (format: hh:mm:ss)"); - SETTUNITS = cdo_operator_add("settunits", 0, 1, "time units (seconds, minutes, hours, days, months, years)"); - SETTAXIS = cdo_operator_add("settaxis", 0, -2, "date<,time<,increment>> (format YYYY-MM-DD,hh:mm:ss)"); - SETTBOUNDS = cdo_operator_add("settbounds", 0, 1, "frequency (hour, day, month, year)"); - SETREFTIME = cdo_operator_add("setreftime", 0, -2, "date<,time<,units>> (format YYYY-MM-DD,hh:mm:ss)"); - SETCALENDAR = cdo_operator_add("setcalendar", 0, 1, "calendar (standard, proleptic_gregorian, 360_day, 365_day, 366_day)"); - SHIFTTIME = cdo_operator_add("shifttime", 0, 1, "shift value"); +SETYEAR = module.get_id("setyear"); +SETMON = module.get_id("setmon"); +SETDAY = module.get_id("setday"); +SETDATE = module.get_id("setdate"); +SETTIME = module.get_id("settime"); +SETTUNITS = module.get_id("settunits"); +SETTAXIS = module.get_id("settaxis"); +SETTBOUNDS = module.get_id("settbounds"); +SETREFTIME = module.get_id("setreftime"); +SETCALENDAR = module.get_id("setcalendar"); +SHIFTTIME = module.get_id("shifttime"); // clang-format on operatorID = cdo_operator_id(); @@ -477,18 +495,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Settime(void *process) -{ - - ModuleSettime settime; - settime.init(process); - settime.run(); - settime.close(); - return nullptr; -} diff --git a/src/Setzaxis.cc b/src/Setzaxis.cc index 9f77b17b8dd20cb3655ab0bae6f9a1149d867f6f..76241a1b7d109ba416a30b55dfaa28c0b29ca52d 100644 --- a/src/Setzaxis.cc +++ b/src/Setzaxis.cc @@ -39,8 +39,21 @@ getkeyval_dp(const std::string &p_keyval, const char *p_key, double *val) return status; } -class ModuleSetzaxis +class Setzaxis : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Setzaxis", + .operators = { { "setzaxis", 0, 0, "zaxis description file", SetzaxisHelp }, { "genlevelbounds", SetzaxisHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Setzaxis> registration = RegisterEntry<Setzaxis>(module); + + int SETZAXIS, GENLEVELBOUNDS; int zaxisID1, zaxisID2 = -1; int nzaxis, index; @@ -58,19 +71,12 @@ class ModuleSetzaxis int operatorID; - int SETZAXIS, GENLEVELBOUNDS; - public: void - init(void *process) + init() { - - cdo_initialize(process); - - // clang-format off - SETZAXIS = cdo_operator_add("setzaxis", 0, 0, "zaxis description file"); - GENLEVELBOUNDS = cdo_operator_add("genlevelbounds", 0, 0, nullptr); - // clang-format on + SETZAXIS = module.get_id("setzaxis"); + GENLEVELBOUNDS = module.get_id("genlevelbounds"); operatorID = cdo_operator_id(); @@ -192,9 +198,9 @@ public: cdo_inq_record(streamID1, &varID, &levelID); cdo_def_record(streamID2, varID, levelID); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); } tsID++; @@ -206,16 +212,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - cdo_finish(); } }; - -void * -Setzaxis(void *process) -{ - ModuleSetzaxis setzaxis; - setzaxis.init(process); - setzaxis.run(); - setzaxis.close(); - return nullptr; -} diff --git a/src/Shiftxy.cc b/src/Shiftxy.cc index 79bf5693244179db709383ee622891913bae07d9..ba8c87516da30e6d24568229c7cfc495b612b46e 100644 --- a/src/Shiftxy.cc +++ b/src/Shiftxy.cc @@ -80,9 +80,9 @@ shifty(bool fillCyclic, int numberOfShifts, int nx, int ny, Varray<double> &v1, static int shiftx_coord(bool fillCyclic, int numberOfShifts, int gridID1) { - const auto gridID2 = gridDuplicate(gridID1); + auto gridID2 = gridDuplicate(gridID1); - const auto nx = gridInqXsize(gridID1); + auto nx = gridInqXsize(gridID1); auto ny = gridInqYsize(gridID1); if (gridInqType(gridID1) != GRID_CURVILINEAR) ny = 1; @@ -93,7 +93,7 @@ shiftx_coord(bool fillCyclic, int numberOfShifts, int gridID1) if (gridInqXbounds(gridID1, nullptr)) { - const size_t nv = (gridInqType(gridID1) != GRID_CURVILINEAR) ? 2 : 4; + size_t nv = (gridInqType(gridID1) != GRID_CURVILINEAR) ? 2 : 4; Varray<double> bounds(nx * ny * nv); gridInqXbounds(gridID1, bounds.data()); @@ -112,10 +112,10 @@ shiftx_coord(bool fillCyclic, int numberOfShifts, int gridID1) static int shifty_coord(bool fillCyclic, int numberOfShifts, int gridID1) { - const auto gridID2 = gridDuplicate(gridID1); + auto gridID2 = gridDuplicate(gridID1); auto nx = gridInqXsize(gridID1); - const auto ny = gridInqYsize(gridID1); + auto ny = gridInqYsize(gridID1); if (gridInqType(gridID1) != GRID_CURVILINEAR) nx = 1; Varray<double> v1(nx * ny), v2(nx * ny); @@ -125,7 +125,7 @@ shifty_coord(bool fillCyclic, int numberOfShifts, int gridID1) if (gridInqYbounds(gridID1, nullptr)) { - const size_t nv = (gridInqType(gridID1) != GRID_CURVILINEAR) ? 2 : 4; + size_t nv = (gridInqType(gridID1) != GRID_CURVILINEAR) ? 2 : 4; Varray<double> bounds(nx * ny * nv); gridInqYbounds(gridID1, bounds.data()); @@ -141,10 +141,22 @@ shifty_coord(bool fillCyclic, int numberOfShifts, int gridID1) return gridID2; } -class ModuleShiftxy +class Shiftxy : public Process { - int operatorID; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Shiftxy", + .operators = { { "shiftx", ShiftxyHelp }, { "shifty", ShiftxyHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Shiftxy> registration = RegisterEntry<Shiftxy>(module); + int SHIFTX, SHIFTY; + int operatorID; CdoStreamID streamID1; CdoStreamID streamID2; @@ -166,12 +178,10 @@ class ModuleShiftxy public: void - init(void *process) + init() { - cdo_initialize(process); - - SHIFTX = cdo_operator_add("shiftx", 0, 0, nullptr); - SHIFTY = cdo_operator_add("shifty", 0, 0, nullptr); + SHIFTX = module.get_id("shiftx"); + SHIFTY = module.get_id("shifty"); operatorID = cdo_operator_id(); @@ -198,14 +208,14 @@ public: taxisID2 = taxisDuplicate(taxisID1); vlistDefTaxis(vlistID2, taxisID2); - const auto nvars = vlistNvars(vlistID1); + auto nvars = vlistNvars(vlistID1); vars = std::vector<bool>(nvars, false); - const auto ngrids = vlistNgrids(vlistID1); + auto ngrids = vlistNgrids(vlistID1); for (int index = 0; index < ngrids; ++index) { - const auto gridID1 = vlistGrid(vlistID1, index); - const auto gridtype = gridInqType(gridID1); + auto gridID1 = vlistGrid(vlistID1, index); + auto gridtype = gridInqType(gridID1); if (gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || gridtype == GRID_CURVILINEAR || (gridtype == GRID_PROJECTION && gridInqProjType(gridID1) == CDI_PROJ_RLL) @@ -239,7 +249,7 @@ public: streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); - const auto gridsizemax = vlistGridsizeMax(vlistID1); + auto gridsizemax = vlistGridsizeMax(vlistID1); array1 = Varray<double>(gridsizemax); array2 = Varray<double>(gridsizemax); } @@ -250,7 +260,7 @@ public: int tsID = 0; while (true) { - const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); if (nrecs == 0) break; cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -260,29 +270,29 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); cdo_def_record(streamID2, varID, levelID); if (vars[varID]) { - const auto gridID1 = vlistInqVarGrid(vlistID1, varID); - const auto gridsize = gridInqSize(gridID1); - const auto missval = vlistInqVarMissval(vlistID2, varID); + auto gridID1 = vlistInqVarGrid(vlistID1, varID); + auto gridsize = gridInqSize(gridID1); + auto missval = vlistInqVarMissval(vlistID2, varID); - const auto nx = gridInqXsize(gridID1); - const auto ny = gridInqYsize(gridID1); + auto nx = gridInqXsize(gridID1); + auto ny = gridInqYsize(gridID1); if (operatorID == SHIFTX) shiftx(fillCyclic, numberOfShifts, nx, ny, array1, array2, missval); else if (operatorID == SHIFTY) shifty(fillCyclic, numberOfShifts, nx, ny, array1, array2, missval); - nmiss = varray_num_mv(gridsize, array2, missval); - cdo_write_record(streamID2, array2.data(), nmiss); + numMissVals = varray_num_mv(gridsize, array2, missval); + cdo_write_record(streamID2, array2.data(), numMissVals); } - else { cdo_write_record(streamID2, array1.data(), nmiss); } + else { cdo_write_record(streamID2, array1.data(), numMissVals); } } tsID++; } @@ -295,17 +305,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Shiftxy(void *process) -{ - ModuleShiftxy shiftxy; - shiftxy.init(process); - shiftxy.run(); - shiftxy.close(); - return nullptr; -} diff --git a/src/Showattribute.cc b/src/Showattribute.cc index 680ae9383db27bcff58a4dd9be5d92c97a9218f0..095ef685878e48ad6afaf83a49f6ab27d22de06b 100644 --- a/src/Showattribute.cc +++ b/src/Showattribute.cc @@ -11,6 +11,7 @@ #include "process_int.h" #include "util_wildcards.h" #include "util_string.h" +#include "cdi_uuid.h" void print_attributes(const VarList &varList, int vlistID, int varOrGlobal, int natts, char *argument) @@ -107,6 +108,50 @@ print_attributes(const VarList &varList, int vlistID, int varOrGlobal, int natts } else { cdo_warning("Unsupported type %i name %s", atttype, attname); } } + + if (varOrGlobal == CDI_GLOBAL) + { + auto gridID = vlistInqVarGrid(vlistID, 0); + if (gridInqType(gridID) == GRID_UNSTRUCTURED) + { + { + const char *attname = "number_of_grid_used"; + if (argument == nullptr || (argument && wildcardmatch(argument, attname) == 0)) + { + int number = 0; + cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, &number); + if (number > 0) fprintf(stdout, " %s = %d\n", attname, number); + } + } + { + const char *attname = "grid_file_uri"; + if (argument == nullptr || (argument && wildcardmatch(argument, attname) == 0)) + { + int length = 0; + if (CDI_NOERR == cdiInqKeyLen(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, &length)) + { + char referenceLink[8192]; + cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, referenceLink, &length); + fprintf(stdout, " %s = \"%s\"\n", attname, referenceLink); + } + } + } + { + const char *attname = "uuidOfHGrid"; + if (argument == nullptr || (argument && wildcardmatch(argument, attname) == 0)) + { + unsigned char uuid[CDI_UUID_SIZE] = { 0 }; + int length = CDI_UUID_SIZE; + auto status = cdiInqKeyBytes(gridID, CDI_GLOBAL, CDI_KEY_UUID, uuid, &length); + if (status == CDI_NOERR && !cdiUUIDIsNull(uuid)) + { + char uuidStr[uuidNumHexChars + 1] = { 0 }; + if (cdiUUID2Str(uuid, uuidStr) == uuidNumHexChars) fprintf(stdout, " %s = \"%s\"\n", attname, uuidStr); + } + } + } + } + } } void @@ -129,9 +174,23 @@ check_varname_and_print(const VarList &varList, int vlistID, int nvars, char *ch if (!lfound && checkvarname) cdo_abort("Could not find variable %s!", checkvarname); } -class ModuleShowattribute +class Showattribute : public Process { - int delim = '@'; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Showattribute", + // clang-format off + .operators = { { "showattribute", ShowattributeHelp }, + { "showattsvar", ShowattributeHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Showattribute> registration = RegisterEntry<Showattribute>(module); + int SHOWATTRIBUTE, SHOWATTSVAR; CdoStreamID streamID; @@ -143,12 +202,10 @@ class ModuleShowattribute public: void - init(void *process) + init() { - cdo_initialize(process); - - SHOWATTRIBUTE = cdo_operator_add("showattribute", 0, 0, nullptr); - SHOWATTSVAR = cdo_operator_add("showattsvar", 0, 0, nullptr); + SHOWATTRIBUTE = module.get_id("showattribute"); + SHOWATTSVAR = module.get_id("showattsvar"); operatorID = cdo_operator_id(); @@ -188,6 +245,7 @@ public: } else { + constexpr int delim = '@'; auto params = cdo_get_oper_argv(); char buffer[CDI_MAX_NAME]; for (int i = 0; i < nargs; ++i) @@ -224,21 +282,10 @@ public: } } } + void close() { cdo_stream_close(streamID); - - cdo_finish(); } }; - -void * -Showattribute(void *process) -{ - ModuleShowattribute showattribute; - showattribute.init(process); - showattribute.run(); - showattribute.close(); - return nullptr; -} diff --git a/src/Showinfo.cc b/src/Showinfo.cc index 11735c70b4b001cc1789184faff3c01b9d523464..6ee2f28c852fe31d790e0a9127e4f6c3cd520b09 100644 --- a/src/Showinfo.cc +++ b/src/Showinfo.cc @@ -341,8 +341,34 @@ show_atts(int vlistID, const VarList &varList) print_attributes(varList, vlistID, varID, nattsvar, nullptr); } } -class ModuleShowinfo +class Showinfo : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Showinfo", + .operators = { { "showyear", ShowinfoHelp }, + { "showmon", ShowinfoHelp }, + { "showdate", ShowinfoHelp }, + { "showtime", ShowinfoHelp }, + { "showtimestamp", ShowinfoHelp }, + { "showcode", ShowinfoHelp }, + { "showunit", ShowinfoHelp }, + { "showparam", ShowinfoHelp }, + { "showname", ShowinfoHelp }, + { "showstdname", ShowinfoHelp }, + { "showlevel", ShowinfoHelp }, + { "showltype", ShowinfoHelp }, + { "showformat", ShowinfoHelp }, + { "showgrid", ShowinfoHelp }, + { "showatts", ShowinfoHelp }, + { "showattsglob", ShowinfoHelp } }, + .aliases = { { "showvar", "showname" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Showinfo> registration = RegisterEntry<Showinfo>(module); int SHOWYEAR, SHOWMON, SHOWDATE, SHOWTIME, SHOWTIMESTAMP, SHOWCODE, SHOWUNIT, SHOWPARAM, SHOWNAME, SHOWSTDNAME, SHOWLEVEL, SHOWLTYPE, SHOWFORMAT, SHOWGRID, SHOWATTS, SHOWATTSGLOB; int operatorID; @@ -352,27 +378,26 @@ class ModuleShowinfo public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - SHOWYEAR = cdo_operator_add("showyear", 0, 0, nullptr); - SHOWMON = cdo_operator_add("showmon", 0, 0, nullptr); - SHOWDATE = cdo_operator_add("showdate", 0, 0, nullptr); - SHOWTIME = cdo_operator_add("showtime", 0, 0, nullptr); - SHOWTIMESTAMP = cdo_operator_add("showtimestamp", 0, 0, nullptr); - SHOWCODE = cdo_operator_add("showcode", 0, 0, nullptr); - SHOWUNIT = cdo_operator_add("showunit", 0, 0, nullptr); - SHOWPARAM = cdo_operator_add("showparam", 0, 0, nullptr); - SHOWNAME = cdo_operator_add("showname", 0, 0, nullptr); - SHOWSTDNAME = cdo_operator_add("showstdname", 0, 0, nullptr); - SHOWLEVEL = cdo_operator_add("showlevel", 0, 0, nullptr); - SHOWLTYPE = cdo_operator_add("showltype", 0, 0, nullptr); - SHOWFORMAT = cdo_operator_add("showformat", 0, 0, nullptr); - SHOWGRID = cdo_operator_add("showgrid", 0, 0, nullptr); - SHOWATTS = cdo_operator_add("showatts", 0, 0, nullptr); - SHOWATTSGLOB = cdo_operator_add("showattsglob", 0, 0, nullptr); +SHOWYEAR = module.get_id("showyear"); +SHOWMON = module.get_id("showmon"); +SHOWDATE = module.get_id("showdate"); +SHOWTIME = module.get_id("showtime"); +SHOWTIMESTAMP = module.get_id("showtimestamp"); +SHOWCODE = module.get_id("showcode"); +SHOWUNIT = module.get_id("showunit"); +SHOWPARAM = module.get_id("showparam"); +SHOWNAME = module.get_id("showname"); +SHOWSTDNAME = module.get_id("showstdname"); +SHOWLEVEL = module.get_id("showlevel"); +SHOWLTYPE = module.get_id("showltype"); +SHOWFORMAT = module.get_id("showformat"); +SHOWGRID = module.get_id("showgrid"); +SHOWATTS = module.get_id("showatts"); +SHOWATTSGLOB = module.get_id("showattsglob"); operatorID = cdo_operator_id(); operator_check_argc(0); @@ -413,16 +438,5 @@ public: close() { cdo_stream_close(streamID); - - cdo_finish(); } }; -void * -Showinfo(void *process) -{ - ModuleShowinfo showinfo; - showinfo.init(process); - showinfo.run(); - showinfo.close(); - return nullptr; -} diff --git a/src/Sinfo.cc b/src/Sinfo.cc index 7a7ae9da3863281bf43174111e9eed389e99f791..3906a1d7f380615a4d6d6ee20e57516d02ccbda7 100644 --- a/src/Sinfo.cc +++ b/src/Sinfo.cc @@ -86,10 +86,7 @@ get_num_output_bits(int datatype) { if (CdoDefault::FileType != CDI_UNDEFID) {} } - else - { - datatype = CdoDefault::DataType; - } + else { datatype = CdoDefault::DataType; } return get_num_input_bits(datatype); } @@ -307,16 +304,10 @@ print_time_info_xs(int ntsteps, int taxisID, CdoStreamID streamID) auto jdelta = julianDate_to_seconds(julianDate_sub(julianDate, julianDate0)); timeIncrement = get_time_increment(jdelta, vDateTimeLast.date, vDateTime.date); } - else - { - vDateTimeFirst = vDateTime; - } + else { vDateTimeFirst = vDateTime; } if (tsID == 1) { timeIncrement0 = timeIncrement; } - else if (tsID > 1 && timeIncrement0 != timeIncrement) - { - timeIncrement0.period = 0; - } + else if (tsID > 1 && timeIncrement0 != timeIncrement) { timeIncrement0.period = 0; } vDateTimeLast = vDateTime; @@ -379,27 +370,31 @@ print_time_info_xs(int ntsteps, int taxisID, CdoStreamID streamID) return numTimesteps; } -static void -add_operators(void) +class Sinfo : public Process { - // clang-format off - cdo_operator_add("sinfo", func_generic, 0, nullptr); - cdo_operator_add("sinfop", func_param, 0, nullptr); - cdo_operator_add("sinfon", func_name, 0, nullptr); - cdo_operator_add("sinfoc", func_code, 0, nullptr); - cdo_operator_add("seinfo", func_generic, 1, nullptr); - cdo_operator_add("seinfop", func_param, 1, nullptr); - cdo_operator_add("seinfon", func_name, 1, nullptr); - cdo_operator_add("seinfoc", func_code, 1, nullptr); - cdo_operator_add("xsinfo", func_name, 2, nullptr); - cdo_operator_add("xsinfop", func_param, 2, nullptr); - cdo_operator_add("xsinfon", func_name, 2, nullptr); - cdo_operator_add("xsinfoc", func_code, 2, nullptr); - // clang-format on -} +public: + using Process::Process; + inline static CdoModule module = { + .name = "Sinfo", + .operators = { { "sinfo", func_generic, 0, SinfoHelp }, + { "sinfop", func_param, 0, SinfoHelp }, + { "sinfon", func_name, 0, SinfoHelp }, + { "sinfoc", func_code, 0, SinfoHelp }, + { "seinfo", func_generic, 1, SinfoHelp }, + { "seinfop", func_param, 1, SinfoHelp }, + { "seinfon", func_name, 1, SinfoHelp }, + { "seinfoc", func_code, 1, SinfoHelp }, + { "xsinfo", func_name, 2, XSinfoHelp }, + { "xsinfop", func_param, 2, XSinfoHelp }, + { "xsinfon", func_name, 2, XSinfoHelp }, + { "xsinfoc", func_code, 2, XSinfoHelp } }, + .aliases = { { "infov", "infon" }, { "sinfov", "sinfon" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { -1, 0, NoRestriction }, + }; + inline static RegisterEntry<Sinfo> registration = RegisterEntry<Sinfo>(module); -class ModuleSinfo -{ private: int operfunc; int ensembleInfo; @@ -407,11 +402,8 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); @@ -553,16 +545,5 @@ public: void close() { - cdo_finish(); } }; - -void * -Sinfo(void *process) -{ - ModuleSinfo sinfo; - sinfo.init(process); - sinfo.run(); - sinfo.close(); - return nullptr; -} diff --git a/src/Smooth.cc b/src/Smooth.cc index 30c8f23ac8c03b02594d4b72614ba202f5debee2..d7550a961d9654008a2c2a664cb72480fb9b5e98 100644 --- a/src/Smooth.cc +++ b/src/Smooth.cc @@ -117,7 +117,7 @@ smooth(int gridID, T missval, const Varray<T> &array1, Varray<T> &array2, const progress::update(0, 1, 1); - size_t nmissx = atomicNumMiss; + size_t numMissValsx = atomicNumMiss; size_t numPoints = atomicSum; if (Options::cdoVerbose) cdo_print("Point search nearest: %.2f seconds (%zu points)", timer.elapsed(), numPoints); @@ -127,7 +127,7 @@ smooth(int gridID, T missval, const Varray<T> &array1, Varray<T> &array2, const if (gridID0 != gridID) gridDestroy(gridID); - return nmissx; + return numMissValsx; } static void @@ -136,9 +136,9 @@ smooth(const Field &field1, Field &field2, const SmoothPoint &spoint) if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); if (field1.memType == MemType::Float) - field2.nmiss = smooth(field1.grid, (float) field1.missval, field1.vec_f, field2.vec_f, spoint); + field2.numMissVals = smooth(field1.grid, (float) field1.missval, field1.vec_f, field2.vec_f, spoint); else - field2.nmiss = smooth(field1.grid, field1.missval, field1.vec_d, field2.vec_d, spoint); + field2.numMissVals = smooth(field1.grid, field1.missval, field1.vec_d, field2.vec_d, spoint); } template <typename T> @@ -165,7 +165,7 @@ smooth9(int gridID, T missval, const Varray<T> &array1, Varray<T> &array2) for (size_t i = 0; i < gridsize; ++i) mask[i] = !dbl_is_equal(missval, array1[i]); - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < nlat; ++i) { for (size_t j = 0; j < nlon; ++j) @@ -241,12 +241,12 @@ smooth9(int gridID, T missval, const Varray<T> &array1, Varray<T> &array2) else { array2[i * nlon + j] = missval; - nmiss++; + numMissVals++; } } } - return nmiss; + return numMissVals; } static void @@ -255,15 +255,15 @@ smooth9(const Field &field1, Field &field2) if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); if (field1.memType == MemType::Float) - field2.nmiss = smooth9(field1.grid, (float) field1.missval, field1.vec_f, field2.vec_f); + field2.numMissVals = smooth9(field1.grid, (float) field1.missval, field1.vec_f, field2.vec_f); else - field2.nmiss = smooth9(field1.grid, field1.missval, field1.vec_d, field2.vec_d); + field2.numMissVals = smooth9(field1.grid, field1.missval, field1.vec_d, field2.vec_d); } double radiusDegToKm(double radiusInDeg) { - return radiusInDeg * (2.0 * PlanetRadius * M_PI) / (360.0 * 1000.0); + return radiusInDeg * (2.0 * PlanetRadiusDefault * M_PI) / (360.0 * 1000.0); } static CurveForm @@ -289,7 +289,7 @@ get_parameter(int &xnsmooth, SmoothPoint &spoint) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -335,8 +335,21 @@ check_radius_range(double radius, const char *name) if (radius < 0.0 || radius > 180.0) cdo_abort("%s=%g out of bounds (0-180 deg)!", name, radius); } -class ModuleSmooth +class Smooth : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Smooth", + .operators = { { "smooth", SmoothHelp }, { "smooth9", SmoothHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Smooth> registration = RegisterEntry<Smooth>(module); + + int SMOOTH, SMOOTH9; int nvars; VarList varList1; Field field1, field2; @@ -355,18 +368,12 @@ class ModuleSmooth SmoothPoint spoint; - int SMOOTH, SMOOTH9; - public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - SMOOTH = cdo_operator_add("smooth", 0, 0, nullptr); - SMOOTH9 = cdo_operator_add("smooth9", 0, 0, nullptr); - // clang-format on + SMOOTH = module.get_id("smooth"); + SMOOTH9 = module.get_id("smooth9"); operatorID = cdo_operator_id(); @@ -462,18 +469,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Smooth(void *process) -{ - ModuleSmooth smooth; - smooth.init(process); - smooth.run(); - smooth.close(); - - return nullptr; -} diff --git a/src/Sort.cc b/src/Sort.cc index 1cb377f297352361599851ee82eb21a1b66771aa..5c9085a342d68d1a67878b31baa5a2eb288e0254 100644 --- a/src/Sort.cc +++ b/src/Sort.cc @@ -11,8 +11,6 @@ Sort sortcode Sort by code number */ -#include <algorithm> // sort - #include <cdi.h> #include "cdo_options.h" @@ -24,72 +22,58 @@ struct LevInfo { int levelID; - size_t nmiss; + size_t numMissVals; double level; }; struct VarInfo { int varID; - int nlevs; + int nlevels; int code; - char param[CDI_MAX_NAME]; - char name[CDI_MAX_NAME]; + std::string param; + std::string name; std::vector<LevInfo> levInfo; }; -static bool -cmpvarcode(const VarInfo &a, const VarInfo &b) -{ - return a.code < b.code; -} - -static bool -cmpvarparam(const VarInfo &a, const VarInfo &b) -{ - return strcmp(a.param, b.param) < 0; -} - -static bool -cmpvarname(const VarInfo &a, const VarInfo &b) -{ - return strcmp(a.name, b.name) < 0; -} - -static bool -cmpvarlevel(const LevInfo &a, const LevInfo &b) -{ - return a.level < b.level; -} - -static bool -cmpvarlevelrev(const LevInfo &a, const LevInfo &b) -{ - return a.level > b.level; -} - static void -setNmiss(int varID, int levelID, int nvars, std::vector<VarInfo> &varInfo, size_t nmiss) +setNmiss(int varID, int levelID, int nvars, std::vector<VarInfo> &varsInfo, size_t numMissVals) { int vindex, lindex; for (vindex = 0; vindex < nvars; vindex++) - if (varInfo[vindex].varID == varID) break; + if (varsInfo[vindex].varID == varID) break; if (vindex == nvars) cdo_abort("Internal problem; varID not found!"); - auto nlevels = varInfo[vindex].nlevs; + auto nlevels = varsInfo[vindex].nlevels; for (lindex = 0; lindex < nlevels; lindex++) - if (varInfo[vindex].levInfo[lindex].levelID == levelID) break; + if (varsInfo[vindex].levInfo[lindex].levelID == levelID) break; if (lindex == nlevels) cdo_abort("Internal problem; levelID not found!"); - varInfo[vindex].levInfo[lindex].nmiss = nmiss; + varsInfo[vindex].levInfo[lindex].numMissVals = numMissVals; } -class ModuleSort +class Sort : public Process { - bool (*cmpvarlev)(const LevInfo &a, const LevInfo &b) = cmpvarlevel; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Sort", + .operators = { { "sortcode"}, + { "sortparam"}, + { "sortname"}, + { "sortlevel"} }, + .aliases = { { "sortvar", "sortname" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Sort> registration = RegisterEntry<Sort>(module); + + int SORTCODE, SORTPARAM, SORTNAME, SORTLEVEL; + bool compareLess = true; CdoStreamID streamID1; CdoStreamID streamID2; @@ -98,24 +82,18 @@ class ModuleSort int nvars; VarList varList1; - std::vector<VarInfo> varInfo; + std::vector<VarInfo> varsInfo; Varray2D<double> vardata; int operatorID; - int SORTCODE, SORTPARAM, SORTNAME, SORTLEVEL; - public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - SORTCODE = cdo_operator_add("sortcode", 0, 0, nullptr); - SORTPARAM = cdo_operator_add("sortparam", 0, 0, nullptr); - SORTNAME = cdo_operator_add("sortname", 0, 0, nullptr); - SORTLEVEL = cdo_operator_add("sortlevel", 0, 0, nullptr); - // clang-format on + SORTCODE = module.get_id("sortcode"); + SORTPARAM = module.get_id("sortparam"); + SORTNAME = module.get_id("sortname"); + SORTLEVEL = module.get_id("sortlevel"); operatorID = cdo_operator_id(); @@ -124,7 +102,7 @@ public: if (operatorID == SORTLEVEL && cdo_operator_argc() == 1) { auto iarg = parameter_to_int(cdo_operator_argv(0)); - if (iarg < 0) cmpvarlev = cmpvarlevelrev; + if (iarg < 0) compareLess = false; } streamID1 = cdo_open_read(0); @@ -151,12 +129,12 @@ public: nvars = vlistNvars(vlistID1); - varInfo = std::vector<VarInfo>(nvars); + varsInfo = std::vector<VarInfo>(nvars); for (int varID = 0; varID < nvars; ++varID) { const auto &var = varList1[varID]; - varInfo[varID].nlevs = var.nlevels; - varInfo[varID].levInfo.resize(var.nlevels); + varsInfo[varID].nlevels = var.nlevels; + varsInfo[varID].levInfo.resize(var.nlevels); } vardata = Varray2D<double>(nvars); @@ -166,6 +144,7 @@ public: vardata[varID].resize(var.gridsize * var.nlevels); } } + void run() { @@ -186,22 +165,23 @@ public: if (tsID == 0) { - varInfo[varID].varID = varID; - varInfo[varID].code = var.code; - param_to_string(var.param, varInfo[varID].param, sizeof(varInfo[varID].param)); - std::strcpy(varInfo[varID].name, var.name.c_str()); - varInfo[varID].levInfo[levelID].levelID = levelID; - varInfo[varID].levInfo[levelID].level = cdo_zaxis_inq_level(var.zaxisID, levelID); + auto &varInfo = varsInfo[varID]; + varInfo.varID = varID; + varInfo.code = var.code; + varInfo.param = param_to_string(var.param); + varInfo.name = var.name; + varInfo.levInfo[levelID].levelID = levelID; + varInfo.levInfo[levelID].level = cdo_zaxis_inq_level(var.zaxisID, levelID); } auto offset = var.gridsize * levelID; auto single = &vardata[varID][offset]; - size_t nmiss; - cdo_read_record(streamID1, single, &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, single, &numMissVals); - setNmiss(varID, levelID, nvars, varInfo, nmiss); - // varInfo[varID].levInfo[levelID].nmiss = nmiss; + setNmiss(varID, levelID, nvars, varsInfo, numMissVals); + // varsInfo[varID].levInfo[levelID].numMissVals = numMissVals; } if (tsID == 0) @@ -209,50 +189,55 @@ public: if (Options::cdoVerbose) for (int vindex = 0; vindex < nvars; vindex++) { - auto nlevels = varInfo[vindex].nlevs; - for (int lindex = 0; lindex < nlevels; ++lindex) - printf("sort in: %d %s %d %d %g\n", vindex, varInfo[vindex].name, varInfo[vindex].code, varInfo[vindex].nlevs, - varInfo[vindex].levInfo[lindex].level); + const auto &varInfo = varsInfo[vindex]; + for (int lindex = 0; lindex < varInfo.nlevels; ++lindex) + printf("sort in: %d %s %d %d %g\n", vindex, varInfo.name.c_str(), varInfo.code, varInfo.nlevels, + varInfo.levInfo[lindex].level); } if (operatorID == SORTCODE) - std::sort(varInfo.begin(), varInfo.end(), cmpvarcode); + ranges::sort(varsInfo, {}, &VarInfo::code); else if (operatorID == SORTPARAM) - std::sort(varInfo.begin(), varInfo.end(), cmpvarparam); + ranges::sort(varsInfo, {}, &VarInfo::param); else if (operatorID == SORTNAME) - std::sort(varInfo.begin(), varInfo.end(), cmpvarname); + ranges::sort(varsInfo, {}, &VarInfo::name); else if (operatorID == SORTLEVEL) { for (int vindex = 0; vindex < nvars; vindex++) - std::sort(varInfo[vindex].levInfo.begin(), varInfo[vindex].levInfo.end(), cmpvarlev); + { + if (compareLess) + ranges::sort(varsInfo[vindex].levInfo, ranges::less(), &LevInfo::level); + else + ranges::sort(varsInfo[vindex].levInfo, ranges::greater(), &LevInfo::level); + } } if (Options::cdoVerbose) for (int vindex = 0; vindex < nvars; vindex++) { - auto nlevels = varInfo[vindex].nlevs; - for (int lindex = 0; lindex < nlevels; ++lindex) - printf("sort out: %d %s %d %d %g\n", vindex, varInfo[vindex].name, varInfo[vindex].code, varInfo[vindex].nlevs, - varInfo[vindex].levInfo[lindex].level); + const auto &varInfo = varsInfo[vindex]; + for (int lindex = 0; lindex < varInfo.nlevels; ++lindex) + printf("sort out: %d %s %d %d %g\n", vindex, varInfo.name.c_str(), varInfo.code, varInfo.nlevels, + varInfo.levInfo[lindex].level); } } for (int vindex = 0; vindex < nvars; vindex++) { - auto varID = varInfo[vindex].varID; - const auto &var = varList1[varID]; + const auto &varInfo = varsInfo[vindex]; + const auto &var = varList1[varInfo.varID]; for (int lindex = 0; lindex < var.nlevels; ++lindex) { - auto levelID = varInfo[vindex].levInfo[lindex].levelID; - auto nmiss = varInfo[vindex].levInfo[lindex].nmiss; + auto levelID = varInfo.levInfo[lindex].levelID; + auto numMissVals = varInfo.levInfo[lindex].numMissVals; - if (tsID == 0 || var.isConstant) + if (tsID == 0 || !var.isConstant) { auto offset = var.gridsize * levelID; - auto single = &vardata[varID][offset]; + auto single = &vardata[varInfo.varID][offset]; - cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, single, nmiss); + cdo_def_record(streamID2, varInfo.varID, levelID); + cdo_write_record(streamID2, single, numMissVals); } } } @@ -260,21 +245,11 @@ public: tsID++; } } + void close() { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; -void * -Sort(void *process) -{ - ModuleSort sort; - sort.init(process); - sort.run(); - sort.close(); - return nullptr; -} diff --git a/src/Sorttimestamp.cc b/src/Sorttimestamp.cc index 931a7fead4a2816f17889d0845cc9da937f16fab..52937e2c17183728225186e4dfa601b2f14da4d1 100644 --- a/src/Sorttimestamp.cc +++ b/src/Sorttimestamp.cc @@ -11,8 +11,6 @@ Sorttimestamp sorttimestamp Sort all timesteps */ -#include <algorithm> // sort - #include <cdi.h> #include "julian_date.h" @@ -30,13 +28,20 @@ struct TimeInfo double datetime; }; -static bool -cmpdatetime(const TimeInfo &a, const TimeInfo &b) -{ - return a.datetime < b.datetime; -} -class ModuleSorttimestamp +class Sorttimestamp : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Sorttimestamp", + .operators = { { "sorttimestamp"}, { "sorttaxis"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { -1, 1, NoRestriction }, + }; + inline static RegisterEntry<Sorttimestamp> registration = RegisterEntry<Sorttimestamp>(module); + int varID, levelID; int lasttsID = -1; int nalloc = 0; @@ -51,10 +56,8 @@ class ModuleSorttimestamp public: void - init(void *process) + init() { - cdo_initialize(process); - skipSameTime = getenv_skip_same_time(); if (cdo_operator_argc() == 1) @@ -145,7 +148,7 @@ public: timeinfo[tsID].datetime = jdatetime; } - std::stable_sort(timeinfo.begin(), timeinfo.end(), cmpdatetime); + ranges::stable_sort(timeinfo, {}, &TimeInfo::datetime); vlistDefTaxis(vlistID2, taxisID2); @@ -216,17 +219,5 @@ public: close() { cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Sorttimestamp(void *process) -{ - ModuleSorttimestamp sorttimestamp; - sorttimestamp.init(process); - sorttimestamp.run(); - sorttimestamp.close(); - return nullptr; -} diff --git a/src/Specinfo.cc b/src/Specinfo.cc index b7f7adf257dcabe716cded479ddc5bea6d81ba46..e6c17c0ad72b4734683479eb9bba9d283496efbd 100644 --- a/src/Specinfo.cc +++ b/src/Specinfo.cc @@ -224,8 +224,20 @@ lookup_rl(long nsp, long *nroot, long *nlevel) } } -class ModuleSpecinfo +class Specinfo : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Specinfo", + .operators = { { "specinfo"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 0, NoRestriction }, + }; + inline static RegisterEntry<Specinfo> registration = RegisterEntry<Specinfo>(module); + char arg[128], *parg; std::string argument; struct GridSpecifications @@ -404,6 +416,7 @@ private: NLON_NLAT(p_grid_specs1, p_grid_specs2, p_grid_specs3); } + void NLAT(GridSpecifications &p_grid_specs1, GridSpecifications &p_grid_specs2, GridSpecifications &p_grid_specs3) { @@ -465,13 +478,12 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); operator_input_arg("Txx, TLxx, NLON=xx, NLAT=xx, NIxx or ICONRyyLxx"); - const long len = cdo_operator_argv(0).size(); + long len = cdo_operator_argv(0).size(); if ((len + 1) >= 128) cdo_abort("Parameter string too large!"); @@ -479,7 +491,7 @@ public: arg[len] = 0; argument = std::string(cdo_operator_argv(0)); - std::transform(argument.begin(), argument.end(), argument.begin(), ::toupper); + ranges::transform(argument, argument.begin(), ::toupper); } void @@ -529,16 +541,5 @@ public: void close() { - cdo_finish(); } }; -void * -Specinfo(void *process) -{ - ModuleSpecinfo specinfo; - specinfo.init(process); - specinfo.run(); - specinfo.close(); - - return nullptr; -} diff --git a/src/Spectral.cc b/src/Spectral.cc index f185f857840e0cf2d9fdfff9bb4ce3e70b83558f..3b56d1dc09e2455198967b45ba0f9d5fd718e79d 100644 --- a/src/Spectral.cc +++ b/src/Spectral.cc @@ -95,8 +95,25 @@ sp2gp_init(SP_Transformation &spTrans, int gridID1, int gridIDsp, int gridIDgp, return gridID2; } -class ModuleSpectral +class Spectral : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Spectral", + .operators = { { "gp2sp", SpectralHelp }, + { "gp2spl", SpectralHelp }, + { "sp2gp", SpectralHelp }, + { "sp2gpl", SpectralHelp }, + { "sp2sp", SpecconvHelp }, + { "spcut", SpecconvHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Spectral> registration = RegisterEntry<Spectral>(module); + int GP2SP, GP2SPL, SP2GP, SP2GPL, SP2SP, SPCUT; int gridID1 = -1, gridID2 = -1; int defaultTrunc = 0; @@ -122,28 +139,20 @@ class ModuleSpectral bool lsp2gp; bool linear; - int GP2SP; - int GP2SPL; - int SP2GP; - int SP2GPL; - int SP2SP; - int SPCUT; - public: void - init(void *process) + init() { - cdo_initialize(process); dataIsUnchanged = data_is_unchanged(); // clang-format off - GP2SP = cdo_operator_add("gp2sp", 0, 0, nullptr); - GP2SPL = cdo_operator_add("gp2spl", 0, 0, nullptr); - SP2GP = cdo_operator_add("sp2gp", 0, 0, nullptr); - SP2GPL = cdo_operator_add("sp2gpl", 0, 0, nullptr); - SP2SP = cdo_operator_add("sp2sp", 0, 0, nullptr); - SPCUT = cdo_operator_add("spcut", 0, 0, nullptr); +GP2SP = module.get_id("gp2sp"); +GP2SPL = module.get_id("gp2spl"); +SP2GP = module.get_id("sp2gp"); +SP2GPL = module.get_id("sp2gpl"); +SP2SP = module.get_id("sp2sp"); +SPCUT = module.get_id("spcut"); // clang-format on operatorID = cdo_operator_id(); @@ -285,9 +294,9 @@ public: if (processVars[varID]) { - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); - if (nmiss) cdo_abort("Missing values unsupported for spectral data!"); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported for spectral data!"); gridID1 = vlistInqVarGrid(vlistID1, varID); // clang-format off @@ -298,7 +307,7 @@ public: // clang-format on cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } else { @@ -306,9 +315,9 @@ public: if (dataIsUnchanged) { cdo_copy_record(streamID2, streamID1); } else { - size_t nmiss; - cdo_read_record(streamID1, array1.data(), &nmiss); - cdo_write_record(streamID2, array1.data(), nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array1.data(), &numMissVals); + cdo_write_record(streamID2, array1.data(), numMissVals); } } } @@ -322,18 +331,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Spectral(void *process) -{ - ModuleSpectral spectral; - spectral.init(process); - spectral.run(); - spectral.close(); - - return nullptr; -} diff --git a/src/Spectrum.cc b/src/Spectrum.cc index e76fb2c8cf43048dcc75858ae45d5cab858f6c8a..61a8352900b3b500f9e32ff9e18b95a1d918f54b 100644 --- a/src/Spectrum.cc +++ b/src/Spectrum.cc @@ -127,12 +127,23 @@ spectrum(int nrec, double *data, double *spectrum, double *real, double *imag, c if (!(seg_l & 1)) spectrum[seg_l / 2] *= 2; } -class ModuleSpectrum +class Spectrum : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Spectrum", + .operators = { { "spectrum"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Spectrum> registration = RegisterEntry<Spectrum>(module); int varID, levelID; int k; int nalloc = 0; - size_t nmiss; + size_t numMissVals; int freq; int nvars; @@ -149,9 +160,8 @@ class ModuleSpectrum public: void - init(void *process) + init() { - cdo_initialize(process); streamID1 = cdo_open_read(0); @@ -196,10 +206,10 @@ public: cdo_inq_record(streamID1, &varID, &levelID); const auto &var = varList[varID]; vars[tsID][varID][levelID].resize(var.gridsize); - cdo_read_record(streamID1, vars[tsID][varID][levelID].vec_d.data(), &nmiss); - vars[tsID][varID][levelID].nmiss = nmiss; + cdo_read_record(streamID1, vars[tsID][varID][levelID].vec_d.data(), &numMissVals); + vars[tsID][varID][levelID].numMissVals = numMissVals; - if (nmiss) cdo_abort("Missing values are not allowed!"); + if (numMissVals) cdo_abort("Missing values are not allowed!"); } tsID++; @@ -296,7 +306,7 @@ public: { if (!vars2[tsID][varID][levelID].empty()) { - nmiss = vars2[tsID][varID][levelID].nmiss; + numMissVals = vars2[tsID][varID][levelID].numMissVals; cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, vars2[tsID][varID][levelID].vec_d.data(), 0); } @@ -309,17 +319,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Spectrum(void *process) -{ - ModuleSpectrum spectrum; - spectrum.init(process); - spectrum.run(); - spectrum.close(); - - return nullptr; -} diff --git a/src/Split.cc b/src/Split.cc index 86a2160d7c29557e3133aac765670f4fa7fe2b86..808b239883fd42235b83f07a347e57de39d38467 100644 --- a/src/Split.cc +++ b/src/Split.cc @@ -164,7 +164,7 @@ split_name(bool swapObase, const std::string &fileSuffix, std::string &fileName, cdo_vlist_copy_flag(vlistID2, vlistID1); vlistIDs[index] = vlistID2; - std::string formatted = fileName + var.name; + std::string formatted = fileName + var.name; gen_filename(formatted, swapObase, cdo_get_obase(), fileSuffix); streamIDs[index] = cdo_open_write(formatted); @@ -304,7 +304,6 @@ split_zaxis(bool swapObase, const std::string &fileSuffix, std::string &fileName cdo_vlist_copy_flag(vlistID2, vlistID1); vlistIDs[index] = vlistID2; - std::string formatted = fileName + string_format("%02d", vlistZaxisIndex(vlistID1, zaxisIDs[index]) + 1); gen_filename(formatted, swapObase, cdo_get_obase(), fileSuffix); @@ -365,15 +364,28 @@ split_tabnum(bool swapObase, const std::string &fileSuffix, std::string &fileNam return nsplit; } -class ModuleSplit +class Split : public Process { - int SPLITCODE; - int SPLITPARAM; - int SPLITNAME; - int SPLITLEVEL; - int SPLITGRID; - int SPLITZAXIS; - int SPLITTABNUM; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Split", + .operators = { { "splitcode", SplitHelp }, + { "splitparam", SplitHelp }, + { "splitname", SplitHelp }, + { "splitlevel", SplitHelp }, + { "splitgrid", SplitHelp }, + { "splitzaxis", SplitHelp }, + { "splittabnum", SplitHelp } }, + .aliases = { { "splitvar", "splitname" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, OBASE, OnlyFirst }, + }; + + inline static RegisterEntry<Split> registration = RegisterEntry<Split>(module); + + int SPLITCODE, SPLITPARAM, SPLITNAME, SPLITLEVEL, SPLITGRID, SPLITZAXIS, SPLITTABNUM; std::vector<int> vlistIDs; std::vector<CdoStreamID> streamIDs; @@ -387,23 +399,19 @@ class ModuleSplit public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); - dataIsUnchanged = data_is_unchanged(); // clang-format off - SPLITCODE = cdo_operator_add("splitcode", 0, 0, nullptr); - SPLITPARAM = cdo_operator_add("splitparam", 0, 0, nullptr); - SPLITNAME = cdo_operator_add("splitname", 0, 0, nullptr); - SPLITLEVEL = cdo_operator_add("splitlevel", 0, 0, nullptr); - SPLITGRID = cdo_operator_add("splitgrid", 0, 0, nullptr); - SPLITZAXIS = cdo_operator_add("splitzaxis", 0, 0, nullptr); - SPLITTABNUM = cdo_operator_add("splittabnum", 0, 0, nullptr); +SPLITCODE = module.get_id("splitcode"); +SPLITPARAM = module.get_id("splitparam"); +SPLITNAME = module.get_id("splitname"); +SPLITLEVEL = module.get_id("splitlevel"); +SPLITGRID = module.get_id("splitgrid"); +SPLITZAXIS = module.get_id("splitzaxis"); +SPLITTABNUM = module.get_id("splittabnum"); // clang-format on auto operatorID = cdo_operator_id(); @@ -512,18 +520,5 @@ public: for (auto &streamID : streamIDs) cdo_stream_close(streamID); for (auto &id : vlistIDs) vlistDestroy(id); - - cdo_finish(); } }; - -void * -Split(void *process) -{ - ModuleSplit split; - split.init(process); - split.run(); - split.close(); - - return nullptr; -} diff --git a/src/Splitdate.cc b/src/Splitdate.cc index 9e177edf1c9af534734143aaee50e7616d56ec25..9c4d7d10eed36f03b9cc2b3cf6b78074d4dfe469 100644 --- a/src/Splitdate.cc +++ b/src/Splitdate.cc @@ -19,8 +19,20 @@ #include "util_files.h" #include "util_string.h" -class ModuleSplitdate +class Splitdate : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Splitdate", + .operators = { { "splitdate", SplitdateHelp }, { "splitdatetime", SplitdateHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Splitdate> registration = RegisterEntry<Splitdate>(module); + int SPLITDATE; CdoStreamID streamID1; int taxisID1; @@ -40,16 +52,12 @@ class ModuleSplitdate public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); dataIsUnchanged = data_is_unchanged(); - auto SPLITDATE = cdo_operator_add("splitdate", 0, 0, nullptr); - cdo_operator_add("splitdatetime", 0, 0, nullptr); + SPLITDATE = module.get_id("splitdate"); auto operatorID = cdo_operator_id(); splitDate = (operatorID == SPLITDATE); @@ -147,7 +155,8 @@ public: cdiDate_decode(vDateTime.date, &year, &month, &day); int hour, minute, second, ms; cdiTime_decode(vDateTime.time, &hour, &minute, &second, &ms); - auto fileName = cdo_get_obase() + string_format("%04d-%02d-%02dT%02d:%02d:%02d", year, month, day, hour, minute, second); + auto fileName + = cdo_get_obase() + string_format("%04d-%02d-%02dT%02d:%02d:%02d", year, month, day, hour, minute, second); if (fileSuffix.size() > 0) fileName += fileSuffix; if (Options::cdoVerbose) cdo_print("create file %s", fileName); @@ -169,8 +178,8 @@ public: for (int levelID = 0; levelID < var.nlevels; ++levelID) { cdo_def_record(streamID2, varID, levelID); - auto nmiss = vars[varID][levelID].nmiss; - cdo_write_record(streamID2, vars[varID][levelID].vec_d.data(), nmiss); + auto numMissVals = vars[varID][levelID].numMissVals; + cdo_write_record(streamID2, vars[varID][levelID].vec_d.data(), numMissVals); } } } @@ -185,9 +194,9 @@ public: if (dataIsUnchanged && !(tsID == 0 && haveConstVars)) { cdo_copy_record(streamID2, streamID1); } else { - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); if (tsID == 0 && haveConstVars) { @@ -195,7 +204,7 @@ public: if (var.isConstant) { varray_copy(var.gridsize, array, vars[varID][levelID].vec_d); - vars[varID][levelID].nmiss = nmiss; + vars[varID][levelID].numMissVals = numMissVals; } } } @@ -214,18 +223,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Splitdate(void *process) -{ - ModuleSplitdate splitdate; - splitdate.init(process); - splitdate.run(); - splitdate.close(); - - return nullptr; -} diff --git a/src/Splitrec.cc b/src/Splitrec.cc index 0a45d85d172225ecf3ba672ae09fdd685385a22b..7ee57a464295539d5f0d05f342f8fe062e5c17f5 100644 --- a/src/Splitrec.cc +++ b/src/Splitrec.cc @@ -19,8 +19,19 @@ #include "util_files.h" #include "util_string.h" -class ModuleSplitrec +class Splitrec : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Splitrec", + .operators = { { "splitrec", SplitHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Splitrec> registration = RegisterEntry<Splitrec>(module); CdoStreamID streamID1; int vlistID1; @@ -31,11 +42,8 @@ class ModuleSplitrec public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); operator_check_argc(0); @@ -104,16 +112,5 @@ public: close() { cdo_stream_close(streamID1); - cdo_finish(); } }; - -void * -Splitrec(void *process) -{ - ModuleSplitrec splitrec; - splitrec.init(process); - splitrec.run(); - splitrec.close(); - return nullptr; -} diff --git a/src/Splitsel.cc b/src/Splitsel.cc index a2438a85f738e367e6ea0518f70fe3f6cd7605b3..a50e891747122ecf1a35094aa4efcb003a8c333e 100644 --- a/src/Splitsel.cc +++ b/src/Splitsel.cc @@ -19,8 +19,19 @@ #include "util_files.h" #include "util_string.h" -class ModuleSplitsel +class Splitsel : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Splitsel", + .operators = { { "splitsel", SplitselHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Splitsel> registration = RegisterEntry<Splitsel>(module); int noffset; CdoStreamID streamID1; @@ -43,16 +54,11 @@ class ModuleSplitsel public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); dataIsUnchanged = data_is_unchanged(); - cdo_operator_add("splitsel", 0, 0, nullptr); - // operator_input_arg("numSets <noffset <numSkip>>"); auto nargc = cdo_operator_argc(); @@ -143,7 +149,7 @@ public: if (var.isConstant) { auto &field = fields[varID][levelID]; - cdo_read_record(streamID1, field.vec_d.data(), &field.nmiss); + cdo_read_record(streamID1, field.vec_d.data(), &field.numMissVals); } } } @@ -185,7 +191,7 @@ public: { cdo_def_record(streamID2, varID, levelID); auto &field = fields[varID][levelID]; - cdo_write_record(streamID2, field.vec_d.data(), field.nmiss); + cdo_write_record(streamID2, field.vec_d.data(), field.numMissVals); } } } @@ -200,9 +206,9 @@ public: if (dataIsUnchanged && !(tsID == 0 && haveConstVars)) { cdo_copy_record(streamID2, streamID1); } else { - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); if (tsID == 0 && haveConstVars) { @@ -211,7 +217,7 @@ public: { auto &field = fields[varID][levelID]; varray_copy(var.gridsize, array, field.vec_d); - field.nmiss = nmiss; + field.numMissVals = numMissVals; } } } @@ -244,18 +250,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Splitsel(void *process) -{ - ModuleSplitsel splitsel; - splitsel.init(process); - splitsel.run(); - splitsel.close(); - - return nullptr; -} diff --git a/src/Splittime.cc b/src/Splittime.cc index 3f326abbb024509419b4722e1c3684f7b69cab57..f819a12280df8fdda2d66086572ec441c535d33d 100644 --- a/src/Splittime.cc +++ b/src/Splittime.cc @@ -45,8 +45,29 @@ datetime_to_tm(CdiDateTime vDateTime) return stime; } -class ModuleSplitTime +class Splittime : public Process { + enum + { + func_time, + func_date + }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Splittime", + .operators = { { "splithour", func_time, 10000, SplittimeHelp }, + { "splitday", func_date, 1, SplittimeHelp }, + { "splitmon", func_date, 100, SplittimeHelp }, + { "splitseas", func_date, 100, SplittimeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Splittime> registration = RegisterEntry<Splittime>(module); + int SPLITMON, SPLITSEAS; CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamIDs[MaxStreams]; @@ -65,9 +86,6 @@ class ModuleSplitTime std::string fileSuffix; const char *format = nullptr; - int SPLITMON; - int SPLITSEAS; - VarList varList1; FieldVector2D vars; Varray<double> array; @@ -75,27 +93,16 @@ class ModuleSplitTime bool haveConstVars; bool dataIsUnchanged; - enum - { - func_time, - func_date - }; - public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); dataIsUnchanged = data_is_unchanged(); // clang-format off - cdo_operator_add("splithour", func_time, 10000, nullptr); - cdo_operator_add("splitday", func_date, 1, nullptr); - SPLITMON = cdo_operator_add("splitmon", func_date, 100, nullptr); - SPLITSEAS = cdo_operator_add("splitseas", func_date, 100, nullptr); +SPLITMON = module.get_id("splitmon"); +SPLITSEAS = module.get_id("splitseas"); // clang-format on operatorID = cdo_operator_id(); @@ -175,10 +182,7 @@ public: if (operatorID == SPLITSEAS) index = month_to_season(index); } - else if (operfunc == func_time) - { - index = (cdiTime_get(vDateTime.time) / operintval) % 100; - } + else if (operfunc == func_time) { index = (cdiTime_get(vDateTime.time) / operintval) % 100; } if (index < 0 || index >= MaxStreams) cdo_abort("Index out of range!"); @@ -228,8 +232,8 @@ public: for (int levelID = 0; levelID < var.nlevels; ++levelID) { cdo_def_record(streamID2, varID, levelID); - auto nmiss = vars[varID][levelID].nmiss; - cdo_write_record(streamID2, vars[varID][levelID].vec_d.data(), nmiss); + auto numMissVals = vars[varID][levelID].numMissVals; + cdo_write_record(streamID2, vars[varID][levelID].vec_d.data(), numMissVals); } } } @@ -244,9 +248,9 @@ public: if (dataIsUnchanged && !(tsID == 0 && haveConstVars)) { cdo_copy_record(streamID2, streamID1); } else { - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); if (tsID == 0 && haveConstVars) { @@ -254,7 +258,7 @@ public: if (var.isConstant) { varray_copy(var.gridsize, array, vars[varID][levelID].vec_d); - vars[varID][levelID].nmiss = nmiss; + vars[varID][levelID].numMissVals = numMissVals; } } } @@ -276,18 +280,5 @@ public: } vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Splittime(void *process) -{ - ModuleSplitTime splittime; - splittime.init(process); - splittime.run(); - splittime.close(); - - return nullptr; -} diff --git a/src/Splityear.cc b/src/Splityear.cc index c1e53028d4f604c65eb19de92c1e0c19615d15f7..0d8f6ca169d68d10490f0517ed598dca265310aa 100644 --- a/src/Splityear.cc +++ b/src/Splityear.cc @@ -22,8 +22,20 @@ #define MAX_YEARS 99999 -class ModuleSplitYear +class Splityear : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Splityear", + .operators = { { "splityear", SplittimeHelp }, { "splityearmon", SplittimeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, OBASE, OnlyFirst }, + }; + inline static RegisterEntry<Splityear> registration = RegisterEntry<Splityear>(module); + int SPLITYEAR, SPLITYEARMON; int operatorID; CdoStreamID streamID1; Varray<int> cyear = Varray<int>(MAX_YEARS, 0); @@ -32,8 +44,6 @@ class ModuleSplitYear int taxisID2; int vlistID2; CdoStreamID streamID2 = CDO_STREAM_UNDEF; - int SPLITYEAR; - int SPLITYEARMON; Varray<double> array; VarList varList1; bool haveConstVars; @@ -42,18 +52,14 @@ class ModuleSplitYear public: void - init(void *process) + init() { - cdo_initialize(process); - - if (process_self().m_ID != 0) cdo_abort("This operator can't be combined with other operators!"); - dataIsUnchanged = data_is_unchanged(); // clang-format off - SPLITYEAR = cdo_operator_add("splityear", 0, 0, nullptr); - SPLITYEARMON = cdo_operator_add("splityearmon", 0, 0, nullptr); +SPLITYEAR = module.get_id("splityear"); +SPLITYEARMON = module.get_id("splityearmon"); // clang-format on operatorID = cdo_operator_id(); @@ -186,9 +192,9 @@ public: { for (int levelID = 0; levelID < var.nlevels; ++levelID) { - auto nmiss = vars[varID][levelID].nmiss; + auto numMissVals = vars[varID][levelID].numMissVals; cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, vars[varID][levelID].vec_d.data(), nmiss); + cdo_write_record(streamID2, vars[varID][levelID].vec_d.data(), numMissVals); } } } @@ -203,9 +209,9 @@ public: if (dataIsUnchanged && !(tsID == 0 && haveConstVars)) { cdo_copy_record(streamID2, streamID1); } else { - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); if (tsID == 0 && haveConstVars) { @@ -213,7 +219,7 @@ public: if (var.isConstant) { varray_copy(var.gridsize, array, vars[varID][levelID].vec_d); - vars[varID][levelID].nmiss = nmiss; + vars[varID][levelID].numMissVals = numMissVals; } } } @@ -229,17 +235,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; -void * -Splityear(void *process) -{ - ModuleSplitYear splitYear; - splitYear.init(process); - splitYear.run(); - splitYear.close(); - - return nullptr; -} diff --git a/src/Tee.cc b/src/Tee.cc index a5cae93a95e3298d4c63f636cb96d82aa5d9ce60..51d58cd81a044a65fdeb411ceaed2e67f9aa0979 100644 --- a/src/Tee.cc +++ b/src/Tee.cc @@ -9,8 +9,19 @@ #include "process_int.h" -class ModuleTee +class Tee : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Tee", + .operators = { { "tee", TeeHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Tee> registration = RegisterEntry<Tee>(module); Field field; CdoStreamID streamID1; CdoStreamID streamID2; @@ -22,9 +33,8 @@ class ModuleTee public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(1); streamID1 = cdo_open_read(0); @@ -78,9 +88,9 @@ public: streamDefRecord(streamID3, varID, levelID); if (field.memType == MemType::Float) - streamWriteRecordF(streamID3, field.vec_f.data(), field.nmiss); + streamWriteRecordF(streamID3, field.vec_f.data(), field.numMissVals); else - streamWriteRecord(streamID3, field.vec_d.data(), field.nmiss); + streamWriteRecord(streamID3, field.vec_d.data(), field.numMissVals); } tsID++; @@ -93,18 +103,5 @@ public: cdo_stream_close(streamID1); cdo_stream_close(streamID2); streamClose(streamID3); - - cdo_finish(); } }; - -void * -Tee(void *process) -{ - ModuleTee tee; - tee.init(process); - tee.run(); - tee.close(); - - return nullptr; -} diff --git a/src/Templates.cc b/src/Templates.cc index 21fb6cdf648bd492ed3f683ebdd28b81fdba8de8..5e7e79123a8530bf77ba208707b8360c70c3878f 100644 --- a/src/Templates.cc +++ b/src/Templates.cc @@ -9,7 +9,6 @@ #include "process_int.h" -class ModuleTemplate1 { CdoStreamID streamID1; int taxisID1; @@ -18,16 +17,14 @@ class ModuleTemplate1 int taxisID2; int vlistID2; - size_t nmiss; + size_t numMissVals; bool dataIsUnchanged; Varray<double> array; public: - void - init(void *process) + void init() { - cdo_initialize(process); dataIsUnchanged = data_is_unchanged(); @@ -51,8 +48,7 @@ public: } } - void - run() + void run() { int tsID = 0; while (true) @@ -72,29 +68,25 @@ public: if (dataIsUnchanged) { cdo_copy_record(streamID2, streamID1); } else { - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); } } tsID++; } } - void - close() + void close() { cdo_stream_close(streamID1); cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; -class ModuleTemplate2 { - size_t nmiss; + size_t numMissVals; CdoStreamID streamID1; int taxisID1; @@ -106,10 +98,8 @@ class ModuleTemplate2 Varray<double> array; public: - void - init(void *process) + void init() { - cdo_initialize(process); streamID1 = cdo_open_read(0); @@ -127,8 +117,7 @@ public: const auto gridsizemax = vlistGridsizeMax(vlistID1); array = Varray<double>(gridsizemax); } - void - run() + void run() { int tsID = 0; while (true) @@ -145,21 +134,18 @@ public: cdo_inq_record(streamID1, &varID, &levelID); cdo_def_record(streamID2, varID, levelID); - cdo_read_record(streamID1, array.data(), &nmiss); - cdo_write_record(streamID2, array.data(), nmiss); + cdo_read_record(streamID1, array.data(), &numMissVals); + cdo_write_record(streamID2, array.data(), numMissVals); } tsID++; } } - void - close() + void close() { cdo_stream_close(streamID1); cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; diff --git a/src/Test.cc b/src/Test.cc index 4d9ee576cf185caed68b8b4dd7120bafce817fa6..568b343d19f49be0e9082a8aebb55ff65b7d52ee 100644 --- a/src/Test.cc +++ b/src/Test.cc @@ -10,8 +10,18 @@ #include "process_int.h" #include "varray.h" -class TestModuleTestdata +class Testdata : public Process { + using Process::Process; + inline static CdoModule module = { + .name = "Testdata", + .operators = { { "testdata" } }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Testdata> registration = RegisterEntry<Testdata>(module); CdoStreamID streamID1; int taxisID1; int vlistID1; @@ -30,9 +40,8 @@ class TestModuleTestdata public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -77,8 +86,8 @@ public: cdo_inq_record(streamID1, &varID, &levelID); cdo_def_record(streamID2, varID, levelID); - size_t nmiss; - cdo_read_record(streamID1, array.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, array.data(), &numMissVals); gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID)); for (size_t i = 0; i < gridsize; ++i) @@ -98,7 +107,7 @@ public: (unsigned int) cval[4 * i + 2], (unsigned int) cval[4 * i + 3], ival[i], fval[i]); } - cdo_write_record(streamID2, array.data(), nmiss); + cdo_write_record(streamID2, array.data(), numMissVals); fwrite(cval.data(), 4, gridsize, fp); } @@ -113,19 +122,5 @@ public: std::fclose(fp); cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Testdata(void *process) -{ - TestModuleTestdata testdata; - - testdata.init(process); - testdata.run(); - testdata.close(); - - return nullptr; -} diff --git a/src/Tests.cc b/src/Tests.cc index 999d64a4d7a50917c2345daf16285a2552029cfc..15d36625212c388b32b06b7339e84c8fbdb606b4 100644 --- a/src/Tests.cc +++ b/src/Tests.cc @@ -11,8 +11,25 @@ #include "param_conversion.h" #include "statistic.h" -class ModuleTests +class Tests : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Tests", + .operators = { { "normal" }, + { "studentt", 0, 0, "degree of freedom" }, + { "chisquare", 0, 0, "degree of freedom" }, + { "beta", 0, 0, "p and q" }, + { "fisher", 0, 0, "degree of freedom of nominator and of denominator" } }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Tests> registration = RegisterEntry<Tests>(module); + + int NORMAL, STUDENTT, CHISQUARE, BETA, FISHER; CdoStreamID streamID1; int taxisID1; @@ -27,21 +44,15 @@ class ModuleTests Varray<double> array1, array2; VarList varList1; - int NORMAL, STUDENTT, CHISQUARE, BETA, FISHER; - public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - NORMAL = cdo_operator_add("normal", 0, 0, nullptr); - STUDENTT = cdo_operator_add("studentt", 0, 0, "degree of freedom"); - CHISQUARE = cdo_operator_add("chisquare", 0, 0, "degree of freedom"); - BETA = cdo_operator_add("beta", 0, 0, "p and q"); - FISHER = cdo_operator_add("fisher", 0, 0, "degree of freedom of nominator and of denominator"); - // clang-format on + NORMAL = module.get_id("normal"); + STUDENTT = module.get_id("studentt"); + CHISQUARE = module.get_id("chisquare"); + BETA = module.get_id("beta"); + FISHER = module.get_id("fisher"); operatorID = cdo_operator_id(); @@ -94,6 +105,7 @@ public: varList_init(varList1, vlistID1); } + void run() { @@ -109,9 +121,9 @@ public: for (int recID = 0; recID < nrecs; ++recID) { int varID, levelID; - size_t nmiss; + size_t numMissVals; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, array1.data(), &nmiss); + cdo_read_record(streamID1, array1.data(), &numMissVals); auto gridsize = varList1[varID].gridsize; auto missval = varList1[varID].missval; @@ -148,12 +160,13 @@ public: else { cdo_abort("Internal problem, operator not implemented!"); } cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } tsID++; } } + void close() { @@ -161,17 +174,5 @@ public: cdo_stream_close(streamID2); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Tests(void *process) -{ - ModuleTests tests; - tests.init(process); - tests.run(); - tests.close(); - return nullptr; -} diff --git a/src/Timcount.cc b/src/Timcount.cc index 3e9a63a70b86c29e9a9b6b34d2d492c176953bf0..6cdf57c38de2adb408356f9e964a67f801170b24 100644 --- a/src/Timcount.cc +++ b/src/Timcount.cc @@ -24,8 +24,23 @@ #include "util_date.h" #include "field_functions.h" -class ModuleTimcount +class Timcount : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timcount", + .operators = { { "timcount", 0, CMP_DATE, nullptr}, + { "yearcount", 0, CMP_YEAR, nullptr}, + { "moncount", 0, CMP_MONTH, nullptr}, + { "daycount", 0, CMP_DAY, nullptr}, + { "hourcount", 0, CMP_HOUR, nullptr} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Timcount> registration = RegisterEntry<Timcount>(module); CdoStreamID streamID1; int taxisID1; @@ -45,16 +60,10 @@ class ModuleTimcount public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("timcount", 0, CMP_DATE, nullptr); - cdo_operator_add("yearcount", 0, CMP_YEAR, nullptr); - cdo_operator_add("moncount", 0, CMP_MONTH, nullptr); - cdo_operator_add("daycount", 0, CMP_DAY, nullptr); - cdo_operator_add("hourcount", 0, CMP_HOUR, nullptr); // clang-format on auto operatorID = cdo_operator_id(); @@ -122,7 +131,7 @@ public: if (numSets == 0) { for (size_t i = 0; i < fieldsize; ++i) vars1[varID][levelID].vec_d[i] = vars1[varID][levelID].missval; - vars1[varID][levelID].nmiss = fieldsize; + vars1[varID][levelID].numMissVals = fieldsize; } field.init(varList1[varID]); @@ -147,7 +156,7 @@ public: if (otsID && varList1[varID].isConstant) continue; cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, vars1[varID][levelID].vec_d.data(), vars1[varID][levelID].nmiss); + cdo_write_record(streamID2, vars1[varID][levelID].vec_d.data(), vars1[varID][levelID].numMissVals); } if (nrecs == 0) break; @@ -160,19 +169,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Timcount(void *process) -{ - ModuleTimcount timcount; - - timcount.init(process); - timcount.run(); - timcount.close(); - - return nullptr; -} diff --git a/src/Timcumsum.cc b/src/Timcumsum.cc index cca35e19f189ae2102b56f5ae68cb2bc2e84f9dd..8792c1f9a6d86eb888a76a0e2118c19452ac2a5b 100644 --- a/src/Timcumsum.cc +++ b/src/Timcumsum.cc @@ -16,8 +16,19 @@ #include "process_int.h" #include "field_functions.h" -class ModuleTimcumsum +class Timcumsum : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timcumsum", + .operators = { { "timcumsum", TimcumsumHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Timcumsum> registration = RegisterEntry<Timcumsum>(module); CdoStreamID streamID1; int taxisID1; CdoStreamID streamID2; @@ -30,9 +41,8 @@ class ModuleTimcumsum public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -77,19 +87,19 @@ public: if (tsID == 0) { - cdo_read_record(streamID1, rvars1.vec_d.data(), &rvars1.nmiss); - if (rvars1.nmiss) + cdo_read_record(streamID1, rvars1.vec_d.data(), &rvars1.numMissVals); + if (rvars1.numMissVals) for (size_t i = 0; i < fieldsize; ++i) if (DBL_IS_EQUAL(rvars1.vec_d[i], rvars1.missval)) rvars1.vec_d[i] = 0; } else { - cdo_read_record(streamID1, field.vec_d.data(), &field.nmiss); + cdo_read_record(streamID1, field.vec_d.data(), &field.numMissVals); field.size = fieldsize; field.grid = rvars1.grid; field.missval = rvars1.missval; - if (field.nmiss) + if (field.numMissVals) for (size_t i = 0; i < fieldsize; ++i) if (DBL_IS_EQUAL(field.vec_d[i], rvars1.missval)) field.vec_d[i] = 0; @@ -97,7 +107,7 @@ public: } cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, rvars1.vec_d.data(), rvars1.nmiss); + cdo_write_record(streamID2, rvars1.vec_d.data(), rvars1.numMissVals); } tsID++; @@ -108,19 +118,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Timcumsum(void *process) -{ - ModuleTimcumsum timcumsum; - - timcumsum.init(process); - timcumsum.run(); - timcumsum.close(); - - return nullptr; -} diff --git a/src/Timfillmiss.cc b/src/Timfillmiss.cc index a7a88eb1813be877aa95add0dceb8724eb1319d9..9c223f2738f1b2eee894789a404fc67988524361 100644 --- a/src/Timfillmiss.cc +++ b/src/Timfillmiss.cc @@ -28,8 +28,20 @@ julianDate_to_double(int calendar, const CdiDateTime &dateTime1, const CdiDateTi / 86400.0; } -class ModuleTimfillmiss +class Timfillmiss : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timfillmiss", + .operators = { { "timfillmiss", TimfillmissHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Timfillmiss> registration = RegisterEntry<Timfillmiss>(module); + private: DateTimeList dtlist; CdoStreamID streamID1; @@ -55,12 +67,6 @@ private: Varray<double> timeValues; int numSteps; - void - add_operators() - { - cdo_operator_add("timfillmiss", 0, 0, nullptr); - } - FillMethod convert_fillmethod(const std::string &methodStr) { @@ -81,7 +87,7 @@ private: KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -103,12 +109,8 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); - get_parameter(); limit = std::max(limit, 0); maxGaps = std::max(maxGaps, 0); @@ -239,18 +241,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Timfillmiss(void *process) -{ - ModuleTimfillmiss timfillmiss; - timfillmiss.init(process); - timfillmiss.run(); - timfillmiss.close(); - - return nullptr; -} diff --git a/src/Timpctl.cc b/src/Timpctl.cc index 9ffa918b8e1961c0c368599fa8caa746da2669fb..3d0d4d5c6d3c813da67f4ad2a3ac3f1de627bf13 100644 --- a/src/Timpctl.cc +++ b/src/Timpctl.cc @@ -28,8 +28,23 @@ #include "datetime.h" #include "field_functions.h" -class ModuleTimpctl +class Timpctl : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timpctl", + .operators = { { "timpctl", FieldFunc_Pctl, CMP_DATE, TimpctlHelp }, + { "yearpctl", FieldFunc_Pctl, CMP_YEAR, YearpctlHelp }, + { "monpctl", FieldFunc_Pctl, CMP_MONTH, MonpctlHelp }, + { "daypctl", FieldFunc_Pctl, CMP_DAY, DaypctlHelp }, + { "hourpctl", FieldFunc_Pctl, CMP_HOUR, HourpctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Timpctl> registration = RegisterEntry<Timpctl>(module); CdiDateTime vDateTime0{}; CdoStreamID streamID1; @@ -58,16 +73,10 @@ class ModuleTimpctl public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("timpctl", FieldFunc_Pctl, CMP_DATE, nullptr); - cdo_operator_add("yearpctl", FieldFunc_Pctl, CMP_YEAR, nullptr); - cdo_operator_add("monpctl", FieldFunc_Pctl, CMP_MONTH, nullptr); - cdo_operator_add("daypctl", FieldFunc_Pctl, CMP_DAY, nullptr); - cdo_operator_add("hourpctl", FieldFunc_Pctl, CMP_HOUR, nullptr); // clang-format on operator_input_arg("percentile number"); pn = parameter_to_double(cdo_operator_argv(0)); @@ -224,17 +233,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - cdo_finish(); } }; - -void * -Timpctl(void *process) -{ - ModuleTimpctl timpctl; - timpctl.init(process); - timpctl.run(); - timpctl.close(); - - return nullptr; -} diff --git a/src/Timselpctl.cc b/src/Timselpctl.cc index 8351e487e5d402236fad65315240613083e10868..25a73642495b8a199d375135f6f617d55ba95633 100644 --- a/src/Timselpctl.cc +++ b/src/Timselpctl.cc @@ -24,8 +24,19 @@ #include "datetime.h" #include "field_functions.h" -class ModuleTimselpctl +class Timselpctl : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timselpctl", + .operators = { { "timselpctl", FieldFunc_Pctl, 0, TimselpctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Timselpctl> registration = RegisterEntry<Timselpctl>(module); CdoStreamID streamID1; int taxisID1; @@ -54,11 +65,8 @@ class ModuleTimselpctl public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("timselpctl", FieldFunc_Pctl, 0, nullptr); operator_input_arg("percentile number, numSets <,noffset <,nskip>>"); @@ -242,18 +250,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Timselpctl(void *process) -{ - ModuleTimselpctl timselpctl; - timselpctl.init(process); - timselpctl.run(); - timselpctl.close(); - - return nullptr; -} diff --git a/src/Timselstat.cc b/src/Timselstat.cc index 02d4beaf6bbf1a6e17010332e2c7135ab79a308b..cf47fd3cae91b0213aa502b6d62714ad3aafb459 100644 --- a/src/Timselstat.cc +++ b/src/Timselstat.cc @@ -28,25 +28,28 @@ #include "datetime.h" #include "field_functions.h" -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("timselrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("timselmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("timselmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("timselsum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("timselmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("timselavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("timselvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("timselvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("timselstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("timselstd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} - -class ModuleTimselstat +class Timselstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timselstat", + .operators = { { "timselrange", FieldFunc_Range, 0, TimselstatHelp }, + { "timselmin", FieldFunc_Min, 0, TimselstatHelp }, + { "timselmax", FieldFunc_Max, 0, TimselstatHelp }, + { "timselsum", FieldFunc_Sum, 0, TimselstatHelp }, + { "timselmean", FieldFunc_Mean, 0, TimselstatHelp }, + { "timselavg", FieldFunc_Avg, 0, TimselstatHelp }, + { "timselvar", FieldFunc_Var, 0, TimselstatHelp }, + { "timselvar1", FieldFunc_Var1, 0, TimselstatHelp }, + { "timselstd", FieldFunc_Std, 0, TimselstatHelp }, + { "timselstd1", FieldFunc_Std1, 0, TimselstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Timselstat> registration = RegisterEntry<Timselstat>(module); CdoStreamID streamID1; int taxisID1; @@ -75,11 +78,8 @@ class ModuleTimselstat public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -186,11 +186,11 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[varID][levelID].nmiss = rvars1.nmiss; + vars2[varID][levelID].numMissVals = rvars1.numMissVals; vars2[varID][levelID].vec_d = rvars1.vec_d; } - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -201,7 +201,7 @@ public: field.init(varList[varID]); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, numSets); field2_vincr(rsamp1, field); @@ -287,19 +287,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Timselstat(void *process) -{ - ModuleTimselstat timselstat; - - timselstat.init(process); - timselstat.run(); - timselstat.close(); - - return nullptr; -} diff --git a/src/Timsort.cc b/src/Timsort.cc index 2dd174fa06d07d5b96c31e84423417234447ea3d..58af4eaba4ee971d6aeca1e79fa3f8516236324c 100644 --- a/src/Timsort.cc +++ b/src/Timsort.cc @@ -11,8 +11,6 @@ Timsort timsort Sort over the time */ -#include <algorithm> // sort - #include <cdi.h> #include "process_int.h" @@ -21,8 +19,20 @@ #include "cimdOmp.h" #include "field_functions.h" -class ModuleTimsort +class Timsort : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timsort", + .operators = { { "timsort", TimsortHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Timsort> registration = RegisterEntry<Timsort>(module); + int varID, levelID; int nalloc = 0; @@ -42,9 +52,8 @@ class ModuleTimsort public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -64,6 +73,7 @@ public: nvars = vlistNvars(vlistID1); } + void run() { @@ -123,7 +133,7 @@ public: v.resize(nts); for (int t = 0; t < nts; ++t) v[t] = vars[t][varID][levelID].vec_f[i]; - std::sort(v.begin(), v.end()); + ranges::sort(v); for (int t = 0; t < nts; ++t) vars[t][varID][levelID].vec_f[i] = v[t]; } @@ -133,7 +143,7 @@ public: v.resize(nts); for (int t = 0; t < nts; ++t) v[t] = vars[t][varID][levelID].vec_d[i]; - std::sort(v.begin(), v.end()); + ranges::sort(v); for (int t = 0; t < nts; ++t) vars[t][varID][levelID].vec_d[i] = v[t]; } @@ -161,24 +171,11 @@ public: } } } + void close() { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Timsort(void *process) -{ - ModuleTimsort timsort; - - timsort.init(process); - timsort.run(); - timsort.close(); - - return nullptr; -} diff --git a/src/Timstat.cc b/src/Timstat.cc index 69855976d179d14323275215a9f830f8193e7599..4e920c585659f25334130a197167543cf90242d6 100644 --- a/src/Timstat.cc +++ b/src/Timstat.cc @@ -104,72 +104,78 @@ set_missval(Field &field, const Field &samp, int numSets, double vfrac) } } - if (irun) field.nmiss = field_num_miss(field); + if (irun) field.numMissVals = field_num_miss(field); } -static void -addOperators(void) +class Timstat : public Process { - // clang-format off - cdo_operator_add("timrange", FieldFunc_Range, CMP_DATE, nullptr); - cdo_operator_add("timmin", FieldFunc_Min, CMP_DATE, nullptr); - cdo_operator_add("timmax", FieldFunc_Max, CMP_DATE, nullptr); - cdo_operator_add("timminidx", FieldFunc_Minidx, CMP_DATE, nullptr); - cdo_operator_add("timmaxidx", FieldFunc_Maxidx, CMP_DATE, nullptr); - cdo_operator_add("timsum", FieldFunc_Sum, CMP_DATE, nullptr); - cdo_operator_add("timmean", FieldFunc_Mean, CMP_DATE, nullptr); - cdo_operator_add("timavg", FieldFunc_Avg, CMP_DATE, nullptr); - cdo_operator_add("timvar", FieldFunc_Var, CMP_DATE, nullptr); - cdo_operator_add("timvar1", FieldFunc_Var1, CMP_DATE, nullptr); - cdo_operator_add("timstd", FieldFunc_Std, CMP_DATE, nullptr); - cdo_operator_add("timstd1", FieldFunc_Std1, CMP_DATE, nullptr); - cdo_operator_add("yearrange", FieldFunc_Range, CMP_YEAR, nullptr); - cdo_operator_add("yearmin", FieldFunc_Min, CMP_YEAR, nullptr); - cdo_operator_add("yearmax", FieldFunc_Max, CMP_YEAR, nullptr); - cdo_operator_add("yearminidx", FieldFunc_Minidx, CMP_YEAR, nullptr); - cdo_operator_add("yearmaxidx", FieldFunc_Maxidx, CMP_YEAR, nullptr); - cdo_operator_add("yearsum", FieldFunc_Sum, CMP_YEAR, nullptr); - cdo_operator_add("yearmean", FieldFunc_Mean, CMP_YEAR, nullptr); - cdo_operator_add("yearavg", FieldFunc_Avg, CMP_YEAR, nullptr); - cdo_operator_add("yearvar", FieldFunc_Var, CMP_YEAR, nullptr); - cdo_operator_add("yearvar1", FieldFunc_Var1, CMP_YEAR, nullptr); - cdo_operator_add("yearstd", FieldFunc_Std, CMP_YEAR, nullptr); - cdo_operator_add("yearstd1", FieldFunc_Std1, CMP_YEAR, nullptr); - cdo_operator_add("monrange", FieldFunc_Range, CMP_MONTH, nullptr); - cdo_operator_add("monmin", FieldFunc_Min, CMP_MONTH, nullptr); - cdo_operator_add("monmax", FieldFunc_Max, CMP_MONTH, nullptr); - cdo_operator_add("monsum", FieldFunc_Sum, CMP_MONTH, nullptr); - cdo_operator_add("monmean", FieldFunc_Mean, CMP_MONTH, nullptr); - cdo_operator_add("monavg", FieldFunc_Avg, CMP_MONTH, nullptr); - cdo_operator_add("monvar", FieldFunc_Var, CMP_MONTH, nullptr); - cdo_operator_add("monvar1", FieldFunc_Var1, CMP_MONTH, nullptr); - cdo_operator_add("monstd", FieldFunc_Std, CMP_MONTH, nullptr); - cdo_operator_add("monstd1", FieldFunc_Std1, CMP_MONTH, nullptr); - cdo_operator_add("dayrange", FieldFunc_Range, CMP_DAY, nullptr); - cdo_operator_add("daymin", FieldFunc_Min, CMP_DAY, nullptr); - cdo_operator_add("daymax", FieldFunc_Max, CMP_DAY, nullptr); - cdo_operator_add("daysum", FieldFunc_Sum, CMP_DAY, nullptr); - cdo_operator_add("daymean", FieldFunc_Mean, CMP_DAY, nullptr); - cdo_operator_add("dayavg", FieldFunc_Avg, CMP_DAY, nullptr); - cdo_operator_add("dayvar", FieldFunc_Var, CMP_DAY, nullptr); - cdo_operator_add("dayvar1", FieldFunc_Var1, CMP_DAY, nullptr); - cdo_operator_add("daystd", FieldFunc_Std, CMP_DAY, nullptr); - cdo_operator_add("daystd1", FieldFunc_Std1, CMP_DAY, nullptr); - cdo_operator_add("hourrange", FieldFunc_Range, CMP_HOUR, nullptr); - cdo_operator_add("hourmin", FieldFunc_Min, CMP_HOUR, nullptr); - cdo_operator_add("hourmax", FieldFunc_Max, CMP_HOUR, nullptr); - cdo_operator_add("hoursum", FieldFunc_Sum, CMP_HOUR, nullptr); - cdo_operator_add("hourmean", FieldFunc_Mean, CMP_HOUR, nullptr); - cdo_operator_add("houravg", FieldFunc_Avg, CMP_HOUR, nullptr); - cdo_operator_add("hourvar", FieldFunc_Var, CMP_HOUR, nullptr); - cdo_operator_add("hourvar1", FieldFunc_Var1, CMP_HOUR, nullptr); - cdo_operator_add("hourstd", FieldFunc_Std, CMP_HOUR, nullptr); - cdo_operator_add("hourstd1", FieldFunc_Std1, CMP_HOUR, nullptr); - // clang-format on -} +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timstat", + // clang-format off + .operators = { { "timrange", FieldFunc_Range, CMP_DATE, TimstatHelp }, + { "timmin", FieldFunc_Min, CMP_DATE, TimstatHelp }, + { "timmax", FieldFunc_Max, CMP_DATE, TimstatHelp }, + { "timsum", FieldFunc_Sum, CMP_DATE, TimstatHelp }, + { "timmean", FieldFunc_Mean, CMP_DATE, TimstatHelp }, + { "timavg", FieldFunc_Avg, CMP_DATE, TimstatHelp }, + { "timvar", FieldFunc_Var, CMP_DATE, TimstatHelp }, + { "timvar1", FieldFunc_Var1, CMP_DATE, TimstatHelp }, + { "timstd", FieldFunc_Std, CMP_DATE, TimstatHelp }, + { "timstd1", FieldFunc_Std1, CMP_DATE, TimstatHelp }, + { "timminidx", FieldFunc_Minidx, CMP_DATE, TimstatHelp }, + { "timmaxidx", FieldFunc_Maxidx, CMP_DATE, TimstatHelp }, + { "yearrange", FieldFunc_Range, CMP_YEAR, YearstatHelp }, + { "yearmin", FieldFunc_Min, CMP_YEAR, YearstatHelp }, + { "yearmax", FieldFunc_Max, CMP_YEAR, YearstatHelp }, + { "yearsum", FieldFunc_Sum, CMP_YEAR, YearstatHelp }, + { "yearmean", FieldFunc_Mean, CMP_YEAR, YearstatHelp }, + { "yearavg", FieldFunc_Avg, CMP_YEAR, YearstatHelp }, + { "yearvar", FieldFunc_Var, CMP_YEAR, YearstatHelp }, + { "yearvar1", FieldFunc_Var1, CMP_YEAR, YearstatHelp }, + { "yearstd", FieldFunc_Std, CMP_YEAR, YearstatHelp }, + { "yearstd1", FieldFunc_Std1, CMP_YEAR, YearstatHelp }, + { "yearminidx", FieldFunc_Minidx, CMP_YEAR, YearstatHelp }, + { "yearmaxidx", FieldFunc_Maxidx, CMP_YEAR, YearstatHelp }, + { "monrange", FieldFunc_Range, CMP_MONTH, MonstatHelp }, + { "monmin", FieldFunc_Min, CMP_MONTH, MonstatHelp }, + { "monmax", FieldFunc_Max, CMP_MONTH, MonstatHelp }, + { "monsum", FieldFunc_Sum, CMP_MONTH, MonstatHelp }, + { "monmean", FieldFunc_Mean, CMP_MONTH, MonstatHelp }, + { "monavg", FieldFunc_Avg, CMP_MONTH, MonstatHelp }, + { "monvar", FieldFunc_Var, CMP_MONTH, MonstatHelp }, + { "monvar1", FieldFunc_Var1, CMP_MONTH, MonstatHelp }, + { "monstd", FieldFunc_Std, CMP_MONTH, MonstatHelp }, + { "monstd1", FieldFunc_Std1, CMP_MONTH, MonstatHelp }, + { "dayrange", FieldFunc_Range, CMP_DAY, DaystatHelp }, + { "daymin", FieldFunc_Min, CMP_DAY, DaystatHelp }, + { "daymax", FieldFunc_Max, CMP_DAY, DaystatHelp }, + { "daysum", FieldFunc_Sum, CMP_DAY, DaystatHelp }, + { "daymean", FieldFunc_Mean, CMP_DAY, DaystatHelp }, + { "dayavg", FieldFunc_Avg, CMP_DAY, DaystatHelp }, + { "dayvar", FieldFunc_Var, CMP_DAY, DaystatHelp }, + { "dayvar1", FieldFunc_Var1, CMP_DAY, DaystatHelp }, + { "daystd", FieldFunc_Std, CMP_DAY, DaystatHelp }, + { "daystd1", FieldFunc_Std1, CMP_DAY, DaystatHelp }, + { "hourrange", FieldFunc_Range, CMP_HOUR, HourstatHelp }, + { "hourmin", FieldFunc_Min, CMP_HOUR, HourstatHelp }, + { "hourmax", FieldFunc_Max, CMP_HOUR, HourstatHelp }, + { "hoursum", FieldFunc_Sum, CMP_HOUR, HourstatHelp }, + { "hourmean", FieldFunc_Mean, CMP_HOUR, HourstatHelp }, + { "houravg", FieldFunc_Avg, CMP_HOUR, HourstatHelp }, + { "hourvar", FieldFunc_Var, CMP_HOUR, HourstatHelp }, + { "hourvar1", FieldFunc_Var1, CMP_HOUR, HourstatHelp }, + { "hourstd", FieldFunc_Std, CMP_HOUR, HourstatHelp }, + { "hourstd1", FieldFunc_Std1, CMP_HOUR, HourstatHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Timstat> registration = RegisterEntry<Timstat>(module); -class ModuleTimstat -{ static const TimeStat timestatDate{ TimeStat::MEAN }; CdiDateTime vDateTime0{}; CdiDateTime vDateTimeN{}; @@ -181,7 +187,7 @@ class ModuleTimstat int taxisID2; CdoStreamID streamID3; - int vlistID3, taxisID3 = -1; + int vlistID3, taxisID3{ -1 }; int ntsteps1; @@ -198,8 +204,8 @@ class ModuleTimstat int compareDate; int maxrecs; - bool lvfrac = false; - double vfrac = 1.0; + bool lvfrac{ false }; + double vfrac{ 1.0 }; DateTimeList dtlist; std::vector<RecordInfo> recList; @@ -211,11 +217,8 @@ class ModuleTimstat public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -244,10 +247,7 @@ public: else if (oargc > 1) cdo_abort("Too many arguments!"); } - else - { - operator_check_argc(0); - } + else { operator_check_argc(0); } streamID1 = cdo_open_read(0); @@ -370,13 +370,13 @@ public: cdo_read_record(streamID1, rvars1); if (lrange || lminidx || lmaxidx) { - vars2[varID][levelID].nmiss = rvars1.nmiss; + vars2[varID][levelID].numMissVals = rvars1.numMissVals; vars2[varID][levelID].vec_d = rvars1.vec_d; } if (lminidx || lmaxidx) field_fill(rvars1, 0.0); - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -387,7 +387,7 @@ public: field.init(varList[varID]); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, numSets); field2_vincr(rsamp1, field); @@ -441,10 +441,7 @@ public: else fieldc_stdvar_func(rvars1, vars2[varID][levelID], numSets, divisor); } - else if (lrange) - { - field2_sub(rvars1, vars2[varID][levelID]); - } + else if (lrange) { field2_sub(rvars1, vars2[varID][levelID]); } } if (Options::cdoVerbose) cdo_print("%s vfrac = %g, numSets = %d", datetime_to_string(vDateTimeN), vfrac, numSets); @@ -486,7 +483,7 @@ public: if (!rsamp1.empty()) samp = rsamp1.vec_d; else - varray_fill(samp, (double) numSets); + ranges::fill(samp, (double) numSets); cdo_def_record(streamID3, varID, levelID); cdo_write_record(streamID3, samp.data(), 0); @@ -506,17 +503,5 @@ public: if (Options::cdoDiag) cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Timstat(void *process) -{ - ModuleTimstat timstat; - timstat.init(process); - timstat.run(); - timstat.close(); - - return nullptr; -} diff --git a/src/Timstat2.cc b/src/Timstat2.cc index 45f1a10525c5d0aa5cf77ab3b90535eb8a050314..b64fce1557d40b9ba906c57de43f51b4898331db 100644 --- a/src/Timstat2.cc +++ b/src/Timstat2.cc @@ -19,6 +19,15 @@ #include "cimdOmp.h" #include "field_functions.h" +double +calc_pvalue(double cor, size_t n) +{ + // Author: Estanislao Gavilan + double t_stat = cor * std::sqrt((n - 2) / (1 - cor * cor)); + double pvalue = 0.5 * (1.0 + std::erf(std::fabs(t_stat / std::sqrt(2.0)))); + return pvalue; +} + // correlation in time template <typename T1, typename T2> void @@ -55,17 +64,14 @@ correlation_init(bool hasMissValues, size_t gridsize, const Varray<T1> &x, const #pragma omp parallel for default(shared) schedule(static) #endif #endif - for (size_t i = 0; i < gridsize; ++i) - { - correlation_sum(i); - } + for (size_t i = 0; i < gridsize; ++i) { correlation_sum(i); } } } static void correlation_init(size_t gridsize, const Field &field1, const Field &field2, Varray<size_t> &nofvals, Varray2D<double> &work) { - auto hasMissValues = (field1.nmiss > 0 || field2.nmiss > 0); + auto hasMissValues = (field1.numMissVals > 0 || field2.numMissVals > 0); if (field1.memType == MemType::Float && field2.memType == MemType::Float) correlation_init(hasMissValues, gridsize, field1.vec_f, field2.vec_f, (float) field1.missval, (float) field2.missval, nofvals, @@ -85,10 +91,11 @@ correlation(size_t gridsize, double missval, const Varray<size_t> &nofvals, Varr auto missval1 = missval; auto missval2 = missval; - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) { double cor; + double pvalue; auto nvals = nofvals[i]; if (nvals > 0) { @@ -104,18 +111,22 @@ correlation(size_t gridsize, double missval, const Varray<size_t> &nofvals, Varr cor = DIVM(temp1, SQRTM(temp6)); cor = std::clamp(cor, -1.0, 1.0); - if (dbl_is_equal(cor, missval)) nmiss++; + if (dbl_is_equal(cor, missval)) numMissVals++; + + pvalue = (nvals <= 2) ? missval : ((fabs(cor) < 1) ? calc_pvalue(cor, nvals) : 1); } else { - nmiss++; + numMissVals++; cor = missval; + pvalue = missval; } work[0][i] = cor; + work[1][i] = pvalue; } - return nmiss; + return numMissVals; } // covariance in time @@ -152,17 +163,14 @@ covariance_init(bool hasMissValues, size_t gridsize, const Varray<T1> &x, const #pragma omp parallel for default(shared) schedule(static) #endif #endif - for (size_t i = 0; i < gridsize; ++i) - { - covariance_sum(i); - } + for (size_t i = 0; i < gridsize; ++i) { covariance_sum(i); } } } static void covariance_init(size_t gridsize, const Field &field1, const Field &field2, Varray<size_t> &nofvals, Varray2D<double> &work) { - auto hasMissValues = (field1.nmiss > 0 || field2.nmiss > 0); + auto hasMissValues = (field1.numMissVals > 0 || field2.numMissVals > 0); if (field1.memType == MemType::Float && field2.memType == MemType::Float) covariance_init(hasMissValues, gridsize, field1.vec_f, field2.vec_f, (float) field1.missval, (float) field2.missval, nofvals, @@ -182,7 +190,7 @@ covariance(size_t gridsize, double missval, const Varray<size_t> &nofvals, Varra auto missval1 = missval; auto missval2 = missval; - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) { double covar; @@ -192,18 +200,18 @@ covariance(size_t gridsize, double missval, const Varray<size_t> &nofvals, Varra double dnvals = nvals; auto temp = DIVM(MULM(work[0][i], work[1][i]), dnvals * dnvals); covar = SUBM(DIVM(work[2][i], dnvals), temp); - if (dbl_is_equal(covar, missval)) nmiss++; + if (dbl_is_equal(covar, missval)) numMissVals++; } else { - nmiss++; + numMissVals++; covar = missval; } work[0][i] = covar; } - return nmiss; + return numMissVals; } // rms in time @@ -239,51 +247,58 @@ rmsd_init(size_t gridsize, const Field &field1, const Field &field2, Varray<size static size_t rmsd_compute(size_t gridsize, double missval, const Varray<size_t> &nofvals, Varray<double> &rmsd) { - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < gridsize; ++i) { if (nofvals[i] > 0) { rmsd[i] = std::sqrt(rmsd[i] / (double) nofvals[i]); } else { - nmiss++; + numMissVals++; rmsd[i] = missval; } } - return nmiss; + return numMissVals; } -class ModuleTimstat2 +class Timstat2 : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timstat2", + .operators = { { "timcor", FieldFunc_Cor, 5, TimcorHelp }, + { "timcovar", FieldFunc_Covar, 3, TimcovarHelp }, + { "timrmsd", FieldFunc_Rmsd, 1, nullptr} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Timstat2> registration = RegisterEntry<Timstat2>(module); + int numWork{}; CdiDateTime vDateTime{}; CdoStreamID streamID1; - int taxisID1; CdoStreamID streamID2; - CdoStreamID streamID3; + int taxisID1; int taxisID3; - int operfunc; + int operfunc{}; VarList varList1, varList2; int nrecs1; + bool doWritePvalue{false}; + public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - cdo_operator_add("timcor", FieldFunc_Cor, 5, nullptr); - cdo_operator_add("timcovar", FieldFunc_Covar, 3, nullptr); - cdo_operator_add("timrmsd", FieldFunc_Rmsd, 1, nullptr); - // clang-format on - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); numWork = cdo_operator_f2(operatorID); @@ -312,6 +327,17 @@ public: if (timeIsConst) for (int varID = 0; varID < nvars; ++varID) vlistDefVarTimetype(vlistID3, varID, TIME_CONSTANT); + auto const&var = varList1[0]; + doWritePvalue = (operfunc == FieldFunc_Cor && varList1.size() == 1 && var.nlevels == 1); + + if (doWritePvalue) + { + auto varID = vlistDefVar(vlistID3, var.gridID, var.zaxisID, var.timetype); + vlistDefVarName(vlistID3, varID, "pvalue"); + } + + vlistDefNtsteps(vlistID3, 1); + vlistDefTaxis(vlistID3, taxisID3); streamID3 = cdo_open_write(2); cdo_def_vlist(streamID3, vlistID3); @@ -384,14 +410,8 @@ public: auto &rnofvals = nofvals[varID][levelID]; if (operfunc == FieldFunc_Cor) { correlation_init(gridsize, field1, field2, rnofvals, rwork); } - else if (operfunc == FieldFunc_Covar) - { - covariance_init(gridsize, field1, field2, rnofvals, rwork); - } - else if (operfunc == FieldFunc_Rmsd) - { - rmsd_init(gridsize, field1, field2, rnofvals, rwork[0]); - } + else if (operfunc == FieldFunc_Covar) { covariance_init(gridsize, field1, field2, rnofvals, rwork); } + else if (operfunc == FieldFunc_Rmsd) { rmsd_init(gridsize, field1, field2, rnofvals, rwork[0]); } } tsID++; @@ -412,19 +432,19 @@ public: auto &rwork = work[varID][levelID]; const auto &rnofvals = nofvals[varID][levelID]; - size_t nmiss = 0; - if (operfunc == FieldFunc_Cor) { nmiss = correlation(gridsize, missval, rnofvals, rwork); } - else if (operfunc == FieldFunc_Covar) - { - nmiss = covariance(gridsize, missval, rnofvals, rwork); - } - else if (operfunc == FieldFunc_Rmsd) - { - nmiss = rmsd_compute(gridsize, missval, rnofvals, rwork[0]); - } + size_t numMissVals = 0; + if (operfunc == FieldFunc_Cor) { numMissVals = correlation(gridsize, missval, rnofvals, rwork); } + else if (operfunc == FieldFunc_Covar) { numMissVals = covariance(gridsize, missval, rnofvals, rwork); } + else if (operfunc == FieldFunc_Rmsd) { numMissVals = rmsd_compute(gridsize, missval, rnofvals, rwork[0]); } cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, rwork[0].data(), nmiss); + cdo_write_record(streamID3, rwork[0].data(), numMissVals); + + if (doWritePvalue) + { + cdo_def_record(streamID3, 1, levelID); + cdo_write_record(streamID3, rwork[1].data(), numMissVals); + } } } @@ -434,18 +454,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Timstat2(void *process) -{ - ModuleTimstat2 timstat2; - timstat2.init(process); - timstat2.run(); - timstat2.close(); - - return nullptr; -} diff --git a/src/Timstat3.cc b/src/Timstat3.cc index ed2a545efd4315533a5c49bb45258d0b92e01aa9..332514710ff7105fe67faae912e1129b380aa4ee 100644 --- a/src/Timstat3.cc +++ b/src/Timstat3.cc @@ -98,14 +98,26 @@ meandiff2test(double rconst, double risk, size_t gridsize, double missval, Varra for (size_t i = 0; i < gridsize; ++i) out[i] = meandiff2test_kernel(i, is_equal); } -class ModuleTimstat3 +class Timstat3 : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Timstat3", + .operators = { { "meandiff2test"}, { "varquot2test"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Timstat3> registration = RegisterEntry<Timstat3>(module); + + int VARQUOT2TEST, MEANDIFF2TEST; int vlistID[NIN], vlistID2 = -1; CdoStreamID streamID[NIN]; - int taxisID1; - CdoStreamID streamID3; + int taxisID1; int taxisID3; double rconst; @@ -117,18 +129,12 @@ class ModuleTimstat3 VarList varList0; - int VARQUOT2TEST, MEANDIFF2TEST; - public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - VARQUOT2TEST = cdo_operator_add("varquot2test", 0, 0, nullptr); - MEANDIFF2TEST = cdo_operator_add("meandiff2test", 0, 0, nullptr); - // clang-format on + VARQUOT2TEST = module.get_id("varquot2test"); + MEANDIFF2TEST = module.get_id("meandiff2test"); operatorID = cdo_operator_id(); @@ -227,7 +233,7 @@ public: if (tsID == 0 && is == 0) recList[recID].set(varID, levelID); - cdo_read_record(streamID[is], inField.vec_d.data(), &inField.nmiss); + cdo_read_record(streamID[is], inField.vec_d.data(), &inField.numMissVals); auto const &inArray = inField.vec_d; auto &rwork1 = work[varID][levelID][3 * is + 0]; @@ -262,10 +268,7 @@ public: auto const &rwork = work[varID][levelID]; if (operatorID == VARQUOT2TEST) { varquot2test(rconst, risk, var.gridsize, var.missval, rwork, out[0].vec_d); } - else if (operatorID == MEANDIFF2TEST) - { - meandiff2test(rconst, risk, var.gridsize, var.missval, rwork, out[0].vec_d); - } + else if (operatorID == MEANDIFF2TEST) { meandiff2test(rconst, risk, var.gridsize, var.missval, rwork, out[0].vec_d); } out[0].missval = var.missval; cdo_def_record(streamID3, varID, levelID); @@ -278,18 +281,5 @@ public: { cdo_stream_close(streamID3); for (int is = 0; is < NIN; ++is) cdo_stream_close(streamID[is]); - - cdo_finish(); } }; - -void * -Timstat3(void *process) -{ - ModuleTimstat3 timstat3; - timstat3.init(process); - timstat3.run(); - timstat3.close(); - - return nullptr; -} diff --git a/src/Tinfo.cc b/src/Tinfo.cc index 5075a42a5a0597a347087c25c49fdbbc051900ae..5994ca1f54185ae1061b10b5cc855c39ce8c66cd 100644 --- a/src/Tinfo.cc +++ b/src/Tinfo.cc @@ -49,8 +49,8 @@ print_bounds(int taxisID, int calendar) static int fill_gap(int ngaps, int (&ntsm)[MaxNTSM], int (&rangetsm)[MaxGaps][2], CdiDateTime (&vDateTimesM)[MaxGaps][MaxNTSM], int tsID, - TimeIncrement timeIncr0, CdiDateTime vDateTime, CdiDateTime vDateTime0, int calendar, int day0, - JulianDate julianDate, JulianDate julianDate0) + TimeIncrement timeIncr0, CdiDateTime vDateTime, CdiDateTime vDateTime0, int calendar, int day0, JulianDate julianDate, + JulianDate julianDate0) { int its = 0; int year, month, day; @@ -108,8 +108,19 @@ fill_gap(int ngaps, int (&ntsm)[MaxNTSM], int (&rangetsm)[MaxGaps][2], CdiDateTi return its; } -class ModuleTinfo +class Tinfo : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Tinfo", + .operators = { { "tinfo"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Tinfo> registration = RegisterEntry<Tinfo>(module); CdoStreamID streamID; int taxisID; int ntsteps; @@ -135,9 +146,8 @@ class ModuleTinfo public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -258,15 +268,15 @@ public: jdelta0 = jdelta; timeIncr0 = timeIncr; - its = fill_gap(ngaps, ntsm, rangetsm, vDateTimesM, 1, timeIncr0, vDateTimeFirst, vDateTime, calendar, - day, julianDate0, julianDate_encode(calendar, vDateTimeFirst)); + its = fill_gap(ngaps, ntsm, rangetsm, vDateTimesM, 1, timeIncr0, vDateTimeFirst, vDateTime, calendar, day, + julianDate0, julianDate_encode(calendar, vDateTimeFirst)); arrow = '^'; } else { - its = fill_gap(ngaps, ntsm, rangetsm, vDateTimesM, tsID, timeIncr0, vDateTime, vDateTime0, calendar, - day0, julianDate, julianDate0); + its = fill_gap(ngaps, ntsm, rangetsm, vDateTimesM, tsID, timeIncr0, vDateTime, vDateTime0, calendar, day0, + julianDate, julianDate0); arrow = '<'; @@ -359,17 +369,5 @@ public: fprintf(stdout, "\n"); } } - - cdo_finish(); } }; - -void * -Tinfo(void *process) -{ - ModuleTinfo tinfo; - tinfo.init(process); - tinfo.run(); - tinfo.close(); - return nullptr; -} diff --git a/src/Tocomplex.cc b/src/Tocomplex.cc index 0cd399d8dbf059e7720352f5a7ed256b7ed7056e..958b8385979d30a07979d14c1aa8913a94213268 100644 --- a/src/Tocomplex.cc +++ b/src/Tocomplex.cc @@ -10,8 +10,20 @@ #include "process_int.h" #include "cdo_default_values.h" // Namespace CdoDefault -class ModuleTocomplex +class Tocomplex : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Tocomplex", + .operators = { { "retocomplex"}, { "imtocomplex"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Tocomplex> registration = RegisterEntry<Tocomplex>(module); + int RETOCOMPLEX, IMTOCOMPLEX; CdoStreamID streamID1; int taxisID1; @@ -24,24 +36,22 @@ class ModuleTocomplex VarList varList1; Varray<double> array1, array2; - int RETOCOMPLEX,IMTOCOMPLEX; public: void - init(void *process) + init() { - cdo_initialize(process); - RETOCOMPLEX = cdo_operator_add("retocomplex", 0, 0, nullptr); - IMTOCOMPLEX = cdo_operator_add("imtocomplex", 0, 0, nullptr); + RETOCOMPLEX = module.get_id("retocomplex"); + IMTOCOMPLEX = module.get_id("imtocomplex"); - operatorID = cdo_operator_id(); + operatorID = cdo_operator_id(); operator_check_argc(0); - streamID1 = cdo_open_read(0); + streamID1 = cdo_open_read(0); auto vlistID1 = cdo_stream_inq_vlist(streamID1); - vlistID2 = vlistDuplicate(vlistID1); + vlistID2 = vlistDuplicate(vlistID1); auto nvars = vlistNvars(vlistID2); for (int varID = 0; varID < nvars; ++varID) @@ -51,12 +61,12 @@ public: vlistDefVarDatatype(vlistID2, varID, datatype); } - taxisID1 = vlistInqTaxis(vlistID1); - taxisID2 = taxisDuplicate(taxisID1); + taxisID1 = vlistInqTaxis(vlistID1); + taxisID2 = taxisDuplicate(taxisID1); vlistDefTaxis(vlistID2, taxisID2); // if (CdoDefault::FileType != CDI_FILETYPE_EXT) cdo_abort("Complex numbers need EXTRA format; used CDO option -f ext!"); - streamID2 = cdo_open_write(1); + streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); auto gridsizemax = vlistGridsizeMax(vlistID1); @@ -81,12 +91,12 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - size_t nmiss; + size_t numMissVals; int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); cdo_def_record(streamID2, varID, levelID); - cdo_read_record(streamID1, array1.data(), &nmiss); + cdo_read_record(streamID1, array1.data(), &numMissVals); auto gridsize = varList1[varID].gridsize; if (operatorID == RETOCOMPLEX) @@ -106,7 +116,7 @@ public: } } - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } tsID++; @@ -119,19 +129,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Tocomplex(void *process) -{ - ModuleTocomplex tocomplex; - - tocomplex.init(process); - tocomplex.run(); - tocomplex.close(); - - return nullptr; -} diff --git a/src/Transpose.cc b/src/Transpose.cc index 6b8f827c29785017d6e65d679fc0689d300ecfcf..ef454755c28c53d86a7053a388c0cebea1018ffa 100644 --- a/src/Transpose.cc +++ b/src/Transpose.cc @@ -37,8 +37,20 @@ transxy(int gridID, const Varray<double> &v1, Varray<double> &v2) } } -class ModuleTranspose +class Transpose : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Transpose", + .operators = { { "transxy"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Transpose> registration = RegisterEntry<Transpose>(module); + private: CdoStreamID streamID1; CdoStreamID streamID2; @@ -53,10 +65,8 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -106,16 +116,16 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - size_t nmiss; + size_t numMissVals; int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, array1.data(), &nmiss); + cdo_read_record(streamID1, array1.data(), &numMissVals); auto gridID = vlistInqVarGrid(vlistID1, varID); transxy(gridID, array1, array2); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, array2.data(), nmiss); + cdo_write_record(streamID2, array2.data(), numMissVals); } tsID++; @@ -127,17 +137,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Transpose(void *process) -{ - ModuleTranspose transpose; - transpose.init(process); - transpose.run(); - transpose.close(); - return nullptr; -} diff --git a/src/Trend.cc b/src/Trend.cc index c8185b4429f0270d5c47a59c744ca1f4656b97bc..6cda549976a6b8f49c51eaeb0b38eb95580b5ecb 100644 --- a/src/Trend.cc +++ b/src/Trend.cc @@ -32,7 +32,7 @@ trendGetParameter(bool &tstepIsEqual) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -50,8 +50,19 @@ trendGetParameter(bool &tstepIsEqual) } } -class ModuleTrend +class Trend : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Trend", + .operators = { { "trend", TrendHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 2, OnlyFirst }, + }; + inline static RegisterEntry<Trend> registration = RegisterEntry<Trend>(module); static const int nwork = 5; FieldVector2D work[nwork]; @@ -76,10 +87,8 @@ class ModuleTrend public: void - init(void *process) + init() { - cdo_initialize(process); - trendGetParameter(tstepIsEqual); streamID1 = cdo_open_read(0); @@ -119,7 +128,7 @@ public: calendar = taxisInqCalendar(taxisID1); } - + void run() { @@ -147,7 +156,7 @@ public: recList[recID].set(varID, levelID); - cdo_read_record(streamID1, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(streamID1, field1.vec_d.data(), &field1.numMissVals); auto gridsize = varList1[varID].gridsize; auto missval = varList1[varID].missval; @@ -221,25 +230,12 @@ public: cdo_write_record(streamID3, field2.vec_d.data(), field_num_miss(field2)); } } - + void close() { cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Trend(void *process) -{ - ModuleTrend trend; - trend.init(process); - trend.run(); - trend.close(); - - return nullptr; -} diff --git a/src/Trendarith.cc b/src/Trendarith.cc index a73d01ef341e3e8152695fa70060c21a8cff8ca9..56a5ea7d1cb4cb9a7500706390493e3ab45971ea 100644 --- a/src/Trendarith.cc +++ b/src/Trendarith.cc @@ -29,9 +29,7 @@ add_trend(double zj, const Varray<T> &v1, const Varray<double> &v2, const Varray auto missval1 = mv; auto missval2 = mv; - auto add_kernel = [&](auto i, auto is_EQ) { - return ADDM(v1[i], ADDM(v2[i], MULM(v3[i], zj))); - }; + auto add_kernel = [&](auto i, auto is_EQ) { return ADDM(v1[i], ADDM(v2[i], MULM(v3[i], zj))); }; if (std::isnan(missval1)) for (size_t i = 0; i < n; ++i) v4[i] = add_kernel(i, dbl_is_equal); @@ -57,9 +55,7 @@ sub_trend(double zj, const Varray<T> &v1, const Varray<double> &v2, const Varray auto missval1 = mv; auto missval2 = mv; - auto sub_kernel = [&](auto i, auto is_EQ) { - return SUBM(v1[i], ADDM(v2[i], MULM(v3[i], zj))); - }; + auto sub_kernel = [&](auto i, auto is_EQ) { return SUBM(v1[i], ADDM(v2[i], MULM(v3[i], zj))); }; if (std::isnan(missval1)) for (size_t i = 0; i < n; ++i) v4[i] = sub_kernel(i, dbl_is_equal); @@ -88,7 +84,7 @@ trendarithGetParameter(bool &tstepIsEqual) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -106,8 +102,23 @@ trendarithGetParameter(bool &tstepIsEqual) } } -class ModuleTrendarith +class Trendarith : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Trendarith", + // clang-format off + .operators = { { "addtrend", FieldFunc_Add, 0, TrendarithHelp }, + { "subtrend", FieldFunc_Sub, 0, TrendarithHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Trendarith> registration = RegisterEntry<Trendarith>(module); + CdoStreamID streamID1; int taxisID1; @@ -130,13 +141,8 @@ class ModuleTrendarith public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("addtrend", FieldFunc_Add, 0, nullptr); - cdo_operator_add("subtrend", FieldFunc_Sub, 0, nullptr); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -175,7 +181,7 @@ public: { int varID, levelID; cdo_inq_record(streamID2, &varID, &levelID); - cdo_read_record(streamID2, vars2[varID][levelID].vec_d.data(), &vars2[varID][levelID].nmiss); + cdo_read_record(streamID2, vars2[varID][levelID].vec_d.data(), &vars2[varID][levelID].numMissVals); } } @@ -185,7 +191,7 @@ public: { int varID, levelID; cdo_inq_record(streamID3, &varID, &levelID); - cdo_read_record(streamID3, vars3[varID][levelID].vec_d.data(), &vars3[varID][levelID].nmiss); + cdo_read_record(streamID3, vars3[varID][levelID].vec_d.data(), &vars3[varID][levelID].numMissVals); } } @@ -226,7 +232,7 @@ public: else sub_trend(zj, field1, vars2[varID][levelID], vars3[varID][levelID], field4); - field4.nmiss = field1.nmiss; + field4.numMissVals = field1.numMissVals; cdo_def_record(streamID4, varID, levelID); cdo_write_record(streamID4, field4); } @@ -242,18 +248,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Trendarith(void *process) -{ - ModuleTrendarith trendarith; - trendarith.init(process); - trendarith.run(); - trendarith.close(); - - return nullptr; -} diff --git a/src/Tstepcount.cc b/src/Tstepcount.cc index 0b61f8261a200016ce5770ce710559acc8f610cf..a8eb370dba52861c81f04391d06ab500864d1235 100644 --- a/src/Tstepcount.cc +++ b/src/Tstepcount.cc @@ -36,8 +36,20 @@ tstepcount(long nts, T missval, const Varray<T> &v, T refval) return (j == nts) ? missval : (T) n; } -class ModuleTstepcount +class Tstepcount : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Tstepcount", + .operators = { { "tstepcount"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Tstepcount> registration = RegisterEntry<Tstepcount>(module); + CdiDateTime vDateTime{}; CdoStreamID streamID1; @@ -55,10 +67,8 @@ class ModuleTstepcount public: void - init(void *process) + init() { - cdo_initialize(process); - refval = (cdo_operator_argc() == 1) ? parameter_to_double(cdo_operator_argv(0)) : 0.0; streamID1 = cdo_open_read(0); @@ -80,13 +90,14 @@ public: varList_init(varList1, vlistID1); } + void run() { int tsID = 0; while (true) { - const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); if (nrecs == 0) break; constexpr size_t NALLOC_INC = 1024; @@ -124,7 +135,7 @@ public: #endif for (size_t i = 0; i < gridsize; ++i) { - const auto ompthID = cdo_omp_get_thread_num(); + auto ompthID = cdo_omp_get_thread_num(); if (memType == MemType::Float) { @@ -132,7 +143,7 @@ public: v.resize(nts); for (int t = 0; t < nts; ++t) v[t] = vars[t][varID][levelID].vec_f[i]; - const auto count = tstepcount(nts, (float) missval, v, (float) refval); + auto count = tstepcount(nts, (float) missval, v, (float) refval); vars[0][varID][levelID].vec_f[i] = count; } @@ -142,7 +153,7 @@ public: v.resize(nts); for (int t = 0; t < nts; ++t) v[t] = vars[t][varID][levelID].vec_d[i]; - const auto count = tstepcount(nts, missval, v, refval); + auto count = tstepcount(nts, missval, v, refval); vars[0][varID][levelID].vec_d[i] = count; } @@ -164,24 +175,11 @@ public: } } } + void close() { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Tstepcount(void *process) -{ - ModuleTstepcount tstepcount; - - tstepcount.init(process); - tstepcount.run(); - tstepcount.close(); - - return nullptr; -} diff --git a/src/Unpack.cc b/src/Unpack.cc index a9c56afb9b116e63945a6766c66c3c19bacae6dd..46165ad0f770a12a29e113cd6640570a2e7c7b84 100644 --- a/src/Unpack.cc +++ b/src/Unpack.cc @@ -9,8 +9,20 @@ #include "process_int.h" -class ModuleUnpack +class Unpack : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Unpack", + .operators = { { "unpack", UnpackHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Unpack> registration = RegisterEntry<Unpack>(module); + CdoStreamID streamID1; int taxisID1; @@ -21,10 +33,8 @@ class ModuleUnpack public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -92,17 +102,5 @@ public: { cdo_stream_close(streamID1); cdo_stream_close(streamID2); - - cdo_finish(); } }; - -void * -Unpack(void *process) -{ - ModuleUnpack unpack; - unpack.init(process); - unpack.run(); - unpack.close(); - return nullptr; -} diff --git a/src/Vargen.cc b/src/Vargen.cc index 7e4895726842e11f63aee861f68b4b3ad650eef0..7b0d7d75ed964f9da4f0ea6b8b14b661688985d2 100644 --- a/src/Vargen.cc +++ b/src/Vargen.cc @@ -313,20 +313,32 @@ define_temperature_attributes(int vlistID, int varID) cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, "K"); } -class ModuleVargen +class Vargen : public Process { -private: - int RANDOM; - int SINCOS; - int COSHILL; - int TESTFIELD; - int CONST; - int SEQ; - int TOPO; - int TEMP; - int MASK; - int STDATM; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vargen", + .operators = { { "random", 0, 0, "grid description file or name, <seed>", VargenHelp }, + { "const", 0, 0, "constant value, grid description file or name", VargenHelp }, + { "sincos", 0, 0, "grid description file or name", VargenHelp }, + { "coshill", 0, 0, "grid description file or name", VargenHelp }, + { "testfield", 0, 0, "grid description file or name", VargenHelp }, + { "seq", 0, 0, "start,end,<increment>", VargenHelp }, + { "topo", VargenHelp }, + { "temp", VargenHelp }, + { "mask", VargenHelp }, + { "stdatm", 0, 0, "height levels[m]", VargenHelp } }, + .aliases = { { "for", "seq" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 1, NoRestriction }, + }; + inline static RegisterEntry<Vargen> registration = RegisterEntry<Vargen>(module); + + int RANDOM, SINCOS, COSHILL, TESTFIELD, CONST, SEQ, TOPO, TEMP, MASK, STDATM; +private: static constexpr size_t nlat = 360, nlon = 720; double lon[nlon], lat[nlat]; int nlevels = 1; @@ -349,23 +361,19 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - RANDOM = cdo_operator_add("random", 0, 0, "grid description file or name, <seed>"); - SINCOS = cdo_operator_add("sincos", 0, 0, "grid description file or name"); - COSHILL = cdo_operator_add("coshill", 0, 0, "grid description file or name"); - //not usesd todo: make unavailable for non developers - TESTFIELD = cdo_operator_add("testfield", 0, 0, "grid description file or name"); - CONST = cdo_operator_add("const", 0, 0, "constant value, grid description file or name"); - SEQ = cdo_operator_add("seq", 0, 0, "start, end, <increment>"); - TOPO = cdo_operator_add("topo", 0, 0, nullptr); - TEMP = cdo_operator_add("temp", 0, 0, nullptr); - MASK = cdo_operator_add("mask", 0, 0, nullptr); - STDATM = cdo_operator_add("stdatm", 0, 0, "height levels [m]"); - // clang-format on + RANDOM = module.get_id("random"); + SINCOS = module.get_id("sincos"); + COSHILL = module.get_id("coshill"); + // not usesd todo: make unavailable for non developers + TESTFIELD = module.get_id("testfield"); + CONST = module.get_id("const"); + SEQ = module.get_id("seq"); + TOPO = module.get_id("topo"); + TEMP = module.get_id("temp"); + MASK = module.get_id("mask"); + STDATM = module.get_id("stdatm"); operatorID = cdo_operator_id(); @@ -555,17 +563,5 @@ public: cdo_stream_close(streamID); vlistDestroy(vlistID); - - cdo_finish(); } }; - -void * -Vargen(void *process) -{ - ModuleVargen vargen; - vargen.init(process); - vargen.run(); - vargen.close(); - return nullptr; -} diff --git a/src/Varrms.cc b/src/Varrms.cc index 30131783f9b805eb84d83832c27782f4da4ad00c..8a6ed153c68d8eab726836a19665ffb77f09928b 100644 --- a/src/Varrms.cc +++ b/src/Varrms.cc @@ -32,7 +32,7 @@ var_rms(const Varray<double> &w, const FieldVector &field1, const FieldVector &f auto len = gridInqSize(grid1); if (len != gridInqSize(grid2)) cdo_abort("fields have different size!"); - // if ( nmiss1 ) + // if ( numMissVals1 ) { for (size_t k = 0; k < nlev; ++k) { @@ -58,15 +58,27 @@ else auto ravg = SQRTM(DIVM(rsum, rsumw)); - size_t rnmiss = 0; - if (is_EQ(ravg, missval1)) rnmiss++; + size_t rnumMissVals = 0; + if (is_EQ(ravg, missval1)) rnumMissVals++; field3.vec_d[0] = ravg; - field3.nmiss = rnmiss; + field3.numMissVals = rnumMissVals; } -class ModuleVarrms +class Varrms : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Varrms", + .operators = { { "varrms"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Varrms> registration = RegisterEntry<Varrms>(module); + private: CdoStreamID streamID1; CdoStreamID streamID2; @@ -92,11 +104,9 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -163,15 +173,15 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - size_t nmiss; + size_t numMissVals; int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, vars1[varID][levelID].vec_d.data(), &nmiss); - if (nmiss) cdo_abort("Missing values unsupported for this operator!"); + cdo_read_record(streamID1, vars1[varID][levelID].vec_d.data(), &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported for this operator!"); cdo_inq_record(streamID2, &varID, &levelID); - cdo_read_record(streamID2, vars2[varID][levelID].vec_d.data(), &nmiss); - if (nmiss) cdo_abort("Missing values unsupported for this operator!"); + cdo_read_record(streamID2, vars2[varID][levelID].vec_d.data(), &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported for this operator!"); } for (int varID = 0; varID < nvars; ++varID) @@ -191,7 +201,7 @@ public: var_rms(weights, vars1[varID], vars2[varID], field3); cdo_def_record(streamID3, varID, 0); - cdo_write_record(streamID3, field3.vec_d.data(), field3.nmiss); + cdo_write_record(streamID3, field3.vec_d.data(), field3.numMissVals); } tsID++; @@ -206,18 +216,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID3); - - cdo_finish(); } }; - -void * -Varrms(void *process) -{ - ModuleVarrms varrms; - varrms.init(process); - varrms.run(); - varrms.close(); - - return nullptr; -} diff --git a/src/Varsstat.cc b/src/Varsstat.cc index 5450813224250a3998aca0aacad148b1388968bb..21d525bae67b84aae87776ce9ffb918894fb473c 100644 --- a/src/Varsstat.cc +++ b/src/Varsstat.cc @@ -63,25 +63,28 @@ set_attributes(const VarList &varList1, int vlistID2, int varID2, int operatorID } } -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("varsrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("varsmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("varsmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("varssum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("varsmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("varsavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("varsvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("varsvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("varsstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("varsstd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} - -class ModuleVarsstat +class Varsstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Varsstat", + .operators = { { "varsrange", FieldFunc_Range, 0, VarsstatHelp }, + { "varsmin", FieldFunc_Min, 0, VarsstatHelp }, + { "varsmax", FieldFunc_Max, 0, VarsstatHelp }, + { "varssum", FieldFunc_Sum, 0, VarsstatHelp }, + { "varsmean", FieldFunc_Mean, 0, VarsstatHelp }, + { "varsavg", FieldFunc_Avg, 0, VarsstatHelp }, + { "varsstd", FieldFunc_Std, 0, VarsstatHelp }, + { "varsstd1", FieldFunc_Std1, 0, VarsstatHelp }, + { "varsvar", FieldFunc_Var, 0, VarsstatHelp }, + { "varsvar1", FieldFunc_Var1, 0, VarsstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Varsstat> registration = RegisterEntry<Varsstat>(module); CdoStreamID streamID1; int taxisID1; @@ -105,11 +108,8 @@ class ModuleVarsstat public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -212,13 +212,13 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[levelID].nmiss = rvars1.nmiss; + vars2[levelID].numMissVals = rvars1.numMissVals; vars2[levelID].vec_d = rvars1.vec_d; } if (lvarstd) field2_moq(vars2[levelID], rvars1); - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -229,7 +229,7 @@ public: field.init(varList1[varID]); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, rvars1.nsamp); field2_vincr(rsamp1, field); @@ -283,18 +283,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Varsstat(void *process) -{ - ModuleVarsstat varsstat; - varsstat.init(process); - varsstat.run(); - varsstat.close(); - - return nullptr; -} diff --git a/src/Verifygrid.cc b/src/Verifygrid.cc index 30b6dde568346092ef392d5d671be38cbbb09e76..8c8ca7a7cc4f273db8d97fd36b622606c9efe43d 100644 --- a/src/Verifygrid.cc +++ b/src/Verifygrid.cc @@ -771,8 +771,19 @@ print_lonlat(int dig, int gridID, size_t gridsize, const Varray<double> &lon, co if (ymm.min < -90.00001 || ymm.max > 90.00001) cdo_warning("Grid cell center latitudes out of range!"); } -class ModuleVerifygrid +class Verifygrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Verifygrid", + .operators = { { "verifygrid", VerifygridHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 0, NoRestriction }, + }; + inline static RegisterEntry<Verifygrid> registration = RegisterEntry<Verifygrid>(module); CdoStreamID streamID; int vlistID; @@ -781,11 +792,8 @@ class ModuleVerifygrid public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("verifygrid", 0, 0, nullptr); operator_check_argc(0); @@ -881,18 +889,5 @@ public: close() { cdo_stream_close(streamID); - - cdo_finish(); } }; - -void * -Verifygrid(void *process) -{ - - ModuleVerifygrid verifygrid; - verifygrid.init(process); - verifygrid.run(); - verifygrid.close(); - return nullptr; -} diff --git a/src/Verifyweights.cc b/src/Verifyweights.cc index d59e2980d7b97a6a6f308e1b800948ba3e09891c..910cea4664589a5f1bcb3458059a7557cadee05c 100644 --- a/src/Verifyweights.cc +++ b/src/Verifyweights.cc @@ -165,11 +165,11 @@ struct RemapVarsW RemapMethod mapType{ RemapMethod::UNDEF }; // identifier for remapping method NormOpt normOpt{ NormOpt::NONE }; // option for normalization (conserv only) size_t numLinks = 0; // number of links for remapping - size_t numWeights = 0; // number of weights used in remapping + size_t numWeights = 0; // number of weights used in remapping Varray<size_t> srcCellIndices; // source grid indices for each link Varray<size_t> tgtCellIndices; // target grid indices for each link - Varray<double> weights; // map weights for each link [numLinks*numWeights] + Varray<double> weights; // map weights for each link [numLinks*numWeights] }; static void @@ -374,10 +374,7 @@ cdfWriteVarSize(int ncfileid, int ncvarid, nc_type sizetype, size_t len, size_t nce(nc_put_var_int(ncfileid, ncvarid, iarray.data())); } #ifdef HAVE_NETCDF4 - else - { - nce(nc_put_var_ulonglong(ncfileid, ncvarid, (unsigned long long *) array)); - } + else { nce(nc_put_var_ulonglong(ncfileid, ncvarid, (unsigned long long *) array)); } #endif } @@ -698,24 +695,33 @@ write_remap_scrip(const std::string &remapFileIn, const std::string &remapFileOu } #endif -class ModuleVerifyweights +class Verifyweights : public Process { - int operatorID; - std::string remapFileIn; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Verifyweights", + .operators = { { "verifyweights", 0, 1, "remap filename"}, { "writeremapscrip", 0, 2, "input and output remap filename"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 0, 0, NoRestriction }, + }; + inline static RegisterEntry<Verifyweights> registration = RegisterEntry<Verifyweights>(module); int VERIFYWEIGHTS, WRITEREMAPSCRIP; + int operatorID; + std::string remapFileIn; public: void - init(void *process) + init() { - cdo_initialize(process); - #ifndef HAVE_LIBNETCDF cdo_abort("NetCDF support not compiled in!"); #else - VERIFYWEIGHTS = cdo_operator_add("verifyweights", 0, 1, "remap file name"); - WRITEREMAPSCRIP = cdo_operator_add("writeremapscrip", 0, 2, "input and output remap file name"); + VERIFYWEIGHTS = module.get_id("verifyweights"); + WRITEREMAPSCRIP = module.get_id("writeremapscrip"); operatorID = cdo_operator_id(); @@ -741,17 +747,5 @@ public: void close() { - cdo_finish(); } }; - -void * -Verifyweights(void *process) -{ - ModuleVerifyweights verifyweights; - verifyweights.init(process); - verifyweights.run(); - verifyweights.close(); - - return nullptr; -} diff --git a/src/Vertcum.cc b/src/Vertcum.cc index 4e7ddf19c7d8008ccc2c5fbc19c6a15df7a23767..67593e5a6a97012eb382ba8ce929ee795167d379 100644 --- a/src/Vertcum.cc +++ b/src/Vertcum.cc @@ -37,8 +37,20 @@ add_vars_mv(size_t gridsize, double missval, const Varray<double> &var1, const V } } -class ModuleVertcum +class Vertcum : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertcum", + .operators = { { "vertcum"}, { "vertcumhl"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertcum> registration = RegisterEntry<Vertcum>(module); + int VERTCUMHL; int nlevshl = 0; CdoStreamID streamID1; @@ -53,20 +65,16 @@ class ModuleVertcum int nvars; VarList varList1, varList2; - std::vector<std::vector<size_t>> varnmiss; + std::vector<std::vector<size_t>> varnumMissVals; Varray3D<double> vardata1, vardata2; - int VERTCUMHL; - public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - cdo_operator_add("vertcum", 0, 0, nullptr); - VERTCUMHL = cdo_operator_add("vertcumhl", 0, 0, nullptr); +VERTCUMHL = module.get_id("vertcumhl"); // clang-format on operatorID = cdo_operator_id(); @@ -124,18 +132,17 @@ public: varList_init(varList2, vlistID2); nvars = vlistNvars(vlistID1); - varnmiss = std::vector<std::vector<size_t>>(nvars); + varnumMissVals = std::vector<std::vector<size_t>>(nvars); vardata1 = Varray3D<double>(nvars); vardata2 = Varray3D<double>(nvars); - for (int varID = 0; varID < nvars; ++varID) { auto gridsize = varList1[varID].gridsize; auto nlevs = varList1[varID].nlevels; auto nlevs2 = varList2[varID].nlevels; - varnmiss[varID].resize(nlevs); + varnumMissVals[varID].resize(nlevs); vardata1[varID].resize(nlevs); vardata2[varID].resize(nlevs2); for (int levelID = 0; levelID < nlevs; ++levelID) vardata1[varID][levelID].resize(gridsize); @@ -166,7 +173,7 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, &vardata1[varID][levelID][0], &varnmiss[varID][levelID]); + cdo_read_record(streamID1, &vardata1[varID][levelID][0], &varnumMissVals[varID][levelID]); } for (int varID = 0; varID < nvars; ++varID) @@ -218,9 +225,9 @@ public: for (int levelID = 0; levelID < nlevs2; ++levelID) { auto &single = vardata2[varID][levelID]; - auto nmiss = varray_num_mv(gridsize, single, missval); + auto numMissVals = varray_num_mv(gridsize, single, missval); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, single.data(), nmiss); + cdo_write_record(streamID2, single.data(), numMissVals); } } @@ -235,17 +242,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; -void * -Vertcum(void *process) -{ - ModuleVertcum vertcum; - vertcum.init(process); - vertcum.run(); - vertcum.close(); - - return nullptr; -} diff --git a/src/Vertfillmiss.cc b/src/Vertfillmiss.cc index e9de1e73fc65408ed53d81ad49df4ae719ce9574..63934629c2ac036ac18a717c24e145c79c551906 100644 --- a/src/Vertfillmiss.cc +++ b/src/Vertfillmiss.cc @@ -20,8 +20,20 @@ #include "pmlist.h" #include "fill_1d.h" -class ModuleVertfillmiss +class Vertfillmiss : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertfillmiss", + .operators = { { "vertfillmiss", VertfillmissHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertfillmiss> registration = RegisterEntry<Vertfillmiss>(module); + private: CdoStreamID streamID1; CdoStreamID streamID2; @@ -44,12 +56,6 @@ private: Varray2D<double> dataValues2D; Varray<double> levelValues; - void - add_operators() - { - cdo_operator_add("vertfillmiss", 0, 0, nullptr); - } - FillMethod convert_fillmethod(const std::string &methodStr) { @@ -70,7 +76,7 @@ private: KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -92,12 +98,8 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); - get_parameter(); limit = std::max(limit, 0); maxGaps = std::max(maxGaps, 0); @@ -198,7 +200,7 @@ public: if (numLevels > 1) { size_t numMissVals = 0; - for (int levelID = 0; levelID < numLevels; ++levelID) { numMissVals += vars[varID][levelID].nmiss; } + for (int levelID = 0; levelID < numLevels; ++levelID) { numMissVals += vars[varID][levelID].numMissVals; } if (numMissVals > 0) fillmiss(varID); } } @@ -226,18 +228,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Vertfillmiss(void *process) -{ - ModuleVertfillmiss verfillmiss; - verfillmiss.init(process); - verfillmiss.run(); - verfillmiss.close(); - - return nullptr; -} diff --git a/src/Vertintap.cc b/src/Vertintap.cc index 7bb789850c42f6257eee76df8a46f6065c672fad..3cef326b6c549817ba1ae2601fb64b6ad46b15c8 100644 --- a/src/Vertintap.cc +++ b/src/Vertintap.cc @@ -72,13 +72,32 @@ calc_half_press(const Field3D &fullPress, Field3D &halfPress) calc_half_press(fullPress.gridsize, fullPress.nlevels, fullPress.vec_d, halfPress.nlevels, halfPress.vec_d); } -class ModuleVertintap +class Vertintap : public Process { enum { func_pl, func_hl }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertintap", + // clang-format off + .operators = { { "ap2pl", func_pl, 0, "pressure levels in pascal", VertintapHelp }, + { "ap2plx", func_pl, 0, "pressure levels in pascal", VertintapHelp }, + { "ap2hl", func_hl, 0, "height levels in meter", VertintapHelp }, + { "ap2hlx", func_hl, 0, "height levels in meter", VertintapHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertintap> registration = RegisterEntry<Vertintap>(module); + + int AP2PLX, AP2HLX; int apressID_FL = -1, apressID_HL = -1, dpressID = -1; int psID = -1; @@ -105,7 +124,7 @@ class ModuleVertintap Varray<double> levels; std::vector<bool> processVars, interpVars; - Varray2D<size_t> varnmiss; + Varray2D<size_t> varnumMissVals; Field3DVector vardata1, vardata2; Varray<size_t> numMiss_FL, numMiss_HL; @@ -117,16 +136,10 @@ class ModuleVertintap public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - cdo_operator_add("ap2pl", func_pl, 0, "pressure levels in pascal"); - auto AP2PLX = cdo_operator_add("ap2plx", func_pl, 0, "pressure levels in pascal"); - cdo_operator_add("ap2hl", func_hl, 0, "height levels in meter"); - auto AP2HLX = cdo_operator_add("ap2hlx", func_hl, 0, "height levels in meter"); - // clang-format on + AP2PLX = module.get_id("ap2plx"); + AP2HLX = module.get_id("ap2hlx"); auto operatorID = cdo_operator_id(); auto useHeightLevel = (cdo_operator_f1(operatorID) == func_hl); @@ -141,14 +154,10 @@ public: if (useHeightLevel) levels = { 10, 50, 100, 500, 1000, 5000, 10000, 15000, 20000, 25000, 30000 }; else - levels = { - 100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000 - }; - } - else - { - levels = cdo_argv_to_flt(cdo_get_oper_argv()); + levels = { 100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, + 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000 }; } + else { levels = cdo_argv_to_flt(cdo_get_oper_argv()); } numPL = levels.size(); @@ -222,7 +231,7 @@ public: processVars = std::vector<bool>(nvars); interpVars = std::vector<bool>(nvars); - varnmiss = Varray2D<size_t>(nvars); + varnumMissVals = Varray2D<size_t>(nvars); vardata1 = Field3DVector(nvars), vardata2 = Field3DVector(nvars); auto maxLevels = std::max(std::max(numFullLevels, numHalfLevels), numPL); @@ -269,7 +278,7 @@ public: if (interpVars[varID]) { - varnmiss[varID].resize(maxLevels, 0); + varnumMissVals[varID].resize(maxLevels, 0); vardata2[varID].init(varList2[varID]); } else @@ -278,7 +287,7 @@ public: cdo_warning("Parameter %d has wrong number of levels, skipped! (name=%s nlevel=%d)", varID + 1, var.name, var.nlevels); - varnmiss[varID].resize(var.nlevels); + varnumMissVals[varID].resize(var.nlevels); } } @@ -313,7 +322,7 @@ public: { processVars[varID] = false; const auto &var = varList1[varID]; - for (int levelID = 0; levelID < var.nlevels; ++levelID) varnmiss[varID][levelID] = 0; + for (int levelID = 0; levelID < var.nlevels; ++levelID) varnumMissVals[varID][levelID] = 0; } cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -323,7 +332,7 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, vardata1[varID], levelID, &varnmiss[varID][levelID]); + cdo_read_record(streamID1, vardata1[varID], levelID, &varnumMissVals[varID][levelID]); processVars[varID] = true; } @@ -384,7 +393,7 @@ public: for (int levelID = 0; levelID < var.nlevels; ++levelID) { - if (varnmiss[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); + if (varnumMissVals[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); } const auto &levels3D = (var.nlevels == numFullLevels) ? fullPress : halfPress; @@ -394,7 +403,7 @@ public: if (!extrapolate) { const auto &numMiss = (var.nlevels == numFullLevels) ? numMiss_FL : numMiss_HL; - varray_copy(numPL, numMiss, varnmiss[varID]); + varray_copy(numPL, numMiss, varnumMissVals[varID]); } } @@ -402,7 +411,7 @@ public: { cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, interpVars[varID] ? vardata2[varID] : vardata1[varID], levelID, - varnmiss[varID][levelID]); + varnumMissVals[varID][levelID]); } } } @@ -416,17 +425,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Vertintap(void *process) -{ - ModuleVertintap verintap; - verintap.init(process); - verintap.run(); - verintap.close(); - return nullptr; -} diff --git a/src/Vertintgh.cc b/src/Vertintgh.cc index aa73b0603aea9cef9f24f5cc056c3f7960673ea7..9815053619a44c9c2ba1b8c707a84ede3ec19460 100644 --- a/src/Vertintgh.cc +++ b/src/Vertintgh.cc @@ -60,10 +60,7 @@ create_zaxis_height(Varray<double> &heightLevels) else cdo_abort("Open failed on %s", zfilename); } - else - { - heightLevels = cdo_argv_to_flt(cdo_get_oper_argv()); - } + else { heightLevels = cdo_argv_to_flt(cdo_get_oper_argv()); } if (zaxisID == CDI_UNDEFID) { @@ -74,8 +71,24 @@ create_zaxis_height(Varray<double> &heightLevels) return zaxisID; } -class ModuleVertintgh +class Vertintgh : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertintgh", + // clang-format off + .operators = { { "gh2hl", 0, 0, "height levels in meter", VertintghHelp }, + { "gh2hlx", 0, 0, "height levels in meter", VertintghHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertintgh> registration = RegisterEntry<Vertintgh>(module); + + int GH2HLX; CdoStreamID streamID1; int taxisID1; @@ -97,25 +110,20 @@ class ModuleVertintgh VarList varList1; VarList varList2; - Varray2D<size_t> varnmiss; + Varray2D<size_t> varnumMissVals; Field3DVector vardata1, vardata2; Varray<double> heightLevels; - Field heightBottom; Varray<size_t> numMiss_FL, numMiss_HL; - std::vector<int> vertIndex_FL, vertIndex_HL; + std::vector<int> vertIndex_FL; + std::vector<int> vertIndex_HL; public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - cdo_operator_add("gh2hl", 0, 0, "height levels in meter"); - auto GH2HLX = cdo_operator_add("gh2hlx", 0, 0, "height levels in meter"); - // clang-format on + GH2HLX = module.get_id("gh2hlx"); auto operatorID = cdo_operator_id(); @@ -148,11 +156,8 @@ public: for (int varID = 0; varID < nvars; ++varID) { auto stdname = string_to_lower(cdo::inq_key_string(vlistID1, varID, CDI_KEY_STDNAME)); - - // clang-format off if (stdname == stdnameHeight_FL) heightID_FL = varID; if (stdname == stdnameHeight_HL) heightID_HL = varID; - // clang-format on } if (-1 == heightID_FL && -1 == heightID_HL) @@ -174,10 +179,8 @@ public: if (Options::cdoVerbose) { cdo_print("Found:"); - // clang-format off if (-1 != heightID_FL) cdo_print(" %s -> %s", stdnameHeight_FL, varList1[heightID_FL].name); if (-1 != heightID_HL) cdo_print(" %s -> %s", stdnameHeight_HL, varList1[heightID_HL].name); - // clang-format on } if (-1 == heightID_FL && -1 == heightID_HL) cdo_abort("%s not found!", stdnameHeight_FL); @@ -208,7 +211,7 @@ public: processVars = std::vector<bool>(nvars); interpVars = std::vector<bool>(nvars); - varnmiss = Varray2D<size_t>(nvars); + varnumMissVals = Varray2D<size_t>(nvars); vardata1 = Field3DVector(nvars); vardata2 = Field3DVector(nvars); @@ -228,7 +231,7 @@ public: if (interpVars[varID]) { - varnmiss[varID].resize(maxLevels, 0); + varnumMissVals[varID].resize(maxLevels, 0); vardata2[varID].init(varList2[varID]); } else @@ -243,7 +246,7 @@ public: cdo_warning("Parameter %d has wrong number of levels, skipped! (name=%s nlevel=%d)", varID + 1, var.name, var.nlevels); } - varnmiss[varID].resize(var.nlevels); + varnumMissVals[varID].resize(var.nlevels); } } @@ -260,6 +263,8 @@ public: void run() { + Field heightBottom; + int tsID = 0; while (true) { @@ -270,7 +275,7 @@ public: { processVars[varID] = false; const auto &var = varList1[varID]; - for (int levelID = 0; levelID < var.nlevels; ++levelID) varnmiss[varID][levelID] = 0; + for (int levelID = 0; levelID < var.nlevels; ++levelID) varnumMissVals[varID][levelID] = 0; } cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -280,7 +285,7 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, vardata1[varID], levelID, &varnmiss[varID][levelID]); + cdo_read_record(streamID1, vardata1[varID], levelID, &varnumMissVals[varID][levelID]); processVars[varID] = true; } @@ -324,7 +329,7 @@ public: for (int levelID = 0; levelID < var.nlevels; ++levelID) { - if (varnmiss[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); + if (varnumMissVals[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); } const auto &height3D = (var.nlevels == numFullLevels) ? vardata1[heightID_FL] : vardata1[heightID_HL]; @@ -333,8 +338,8 @@ public: if (!extrapolate) { - const auto &numMiss = (var.nlevels == numFullLevels) ? numMiss_FL : numMiss_HL; - varray_copy(heightLevels.size(), numMiss, varnmiss[varID]); + auto numMiss = (var.nlevels == numFullLevels) ? numMiss_FL : numMiss_HL; + varray_copy(heightLevels.size(), numMiss, varnumMissVals[varID]); } } @@ -342,7 +347,7 @@ public: { cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, interpVars[varID] ? vardata2[varID] : vardata1[varID], levelID, - varnmiss[varID][levelID]); + varnumMissVals[varID][levelID]); } } } @@ -356,17 +361,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Vertintgh(void *process) -{ - ModuleVertintgh vertintgh; - vertintgh.init(process); - vertintgh.run(); - vertintgh.close(); - return nullptr; -} diff --git a/src/Vertintml.cc b/src/Vertintml.cc index aec1fab81a31a66d7097c4d0d173a20414e9c02e..7cc5ac8811c935cb58701685f24ab7d278c472af 100644 --- a/src/Vertintml.cc +++ b/src/Vertintml.cc @@ -25,6 +25,7 @@ #include "param_conversion.h" #include "vertint_util.h" +/* static void field_copy_div_2d_to_3d(MemType memType, size_t gridsize, int nlevels, const Field &field2d, Field3D &field3d) { @@ -33,6 +34,28 @@ field_copy_div_2d_to_3d(MemType memType, size_t gridsize, int nlevels, const Fie else for (size_t i = 0; i < gridsize; ++i) field3d.vec_d[gridsize * nlevels + i] = field2d.vec_d[i] / PlanetGrav; } +*/ +template <typename T> +static void +field_check_sgeopot(const Varray<T> &sgeopot, const T *gheightAtSurface) +{ + auto len = sgeopot.size(); + double sumDiff = 0; + for (size_t i = 0; i < len; ++i) sumDiff += std::fabs((sgeopot[i] / PlanetGrav) - gheightAtSurface[i]); + + constexpr double lim = 0.1; // 10cm per grid point + if ((sumDiff / len) > lim) cdo_warning("Bottom level of gheight differ from sgeopot/%g (diff=%g)!", PlanetGrav, sumDiff / len); + // printf("sumDiff %g %g\n", sumDiff, sumDiff / len); +} + +static void +field_check_sgeopot(MemType memType, size_t gridsize, int nlevels, const Field &field2d, Field3D &field3d) +{ + if (memType == MemType::Float) + field_check_sgeopot(field2d.vec_f, &field3d.vec_f[gridsize * (nlevels - 1)]); + else + field_check_sgeopot(field2d.vec_d, &field3d.vec_d[gridsize * (nlevels - 1)]); +} static void vct_to_hybrid_pressure(MemType memType, Field3D &pressure_FL, Field3D &pressure_HL, const double *vct, const Field &ps, @@ -82,9 +105,9 @@ check_range_sgeopot(int stepNum, const Field &sgeopot) } static bool -zaxis_is_hybrid(int zaxistype) +zaxis_is_hybrid(int zaxisType) { - return (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF); + return (zaxisType == ZAXIS_HYBRID || zaxisType == ZAXIS_HYBRID_HALF); } static void @@ -95,9 +118,9 @@ change_hybrid_zaxis(int vlistID1, int vlistID2, int vctSize, double *vct, int za { auto zaxisID = vlistZaxis(vlistID1, iz); auto nlevels = zaxisInqSize(zaxisID); - auto zaxistype = zaxisInqType(zaxisID); + auto zaxisType = zaxisInqType(zaxisID); - if (zaxis_is_hybrid(zaxistype) && (nlevels == numHalfLevels || nlevels == numFullLevels)) + if (zaxis_is_hybrid(zaxisType) && (nlevels == numHalfLevels || nlevels == numFullLevels)) { auto vctSize2 = zaxisInqVctSize(zaxisID); if (vctSize2 == vctSize && memcmp(vct, zaxisInqVctPtr(zaxisID), vctSize * sizeof(double)) == 0) @@ -163,28 +186,23 @@ pressure_level_interpolation(Varray<double> &pressureLevels, bool useHeightLevel auto nvars = vlistNvars(vlistID1); std::vector<bool> processVars(nvars), interpVars(nvars); - Varray2D<size_t> varnmiss(nvars); + Varray2D<size_t> varnumMissVals(nvars); Field3DVector vardata1(nvars), vardata2(nvars); auto maxLevels = std::max(numHalfLevels, numPL); - Varray<size_t> pnmiss; - if (!extrapolate) pnmiss.resize(numPL); + Varray<size_t> pnumMissVals; + if (!extrapolate) pnumMissVals.resize(numPL); // check levels if (zaxisID_ML != -1) { - auto nlev = zaxisInqSize(zaxisID_ML); - if (nlev != numHybridLevels) cdo_abort("Internal error, wrong number of hybrid level!"); + if (zaxisInqSize(zaxisID_ML) != numHybridLevels) cdo_abort("Internal error, wrong number of hybrid level!"); } - std::vector<int> vertIndex; - Field3D pressure_FL, pressure_HL; if (zaxisID_ML != -1 && gridsize > 0) { - vertIndex.resize(gridsize * numPL); - CdoVar var3Df, var3Dh; var3Df.gridsize = gridsize; var3Df.nlevels = numFullLevels; @@ -212,6 +230,14 @@ pressure_level_interpolation(Varray<double> &pressureLevels, bool useHeightLevel VarIDs varIDs = search_varIDs(varList1, vlistID1, numFullLevels); + // vertical_interp_Z() is implemented for gheight on model half levels only + if (-1 != varIDs.gheightID && varList1[varIDs.gheightID].nlevels == numFullLevels) + { + if (Options::cdoVerbose) + cdo_print("%s(%s) on model full levels found!", var_stdname(geopotential_height), varList1[varIDs.gheightID].name); + varIDs.gheightID = -1; + } + if (Options::cdoVerbose) { cdo_print("Found:"); @@ -228,38 +254,52 @@ pressure_level_interpolation(Varray<double> &pressureLevels, bool useHeightLevel for (int varID = 0; varID < nvars; ++varID) { auto &var1 = varList1[varID]; - auto gridID = var1.gridID; - auto zaxisID = var1.zaxisID; - auto zaxistype = zaxisInqType(zaxisID); auto nlevels = var1.nlevels; - if (gridInqType(gridID) == GRID_SPECTRAL && zaxis_is_hybrid(zaxistype)) - cdo_abort("Spectral data on model level unsupported!"); + if (var1.gridType == GRID_SPECTRAL && zaxis_is_hybrid(var1.zaxisType)) cdo_abort("Spectral data on model level unsupported!"); - if (gridInqType(gridID) == GRID_SPECTRAL) cdo_abort("Spectral data unsupported!"); + if (var1.gridType == GRID_SPECTRAL) cdo_abort("Spectral data unsupported!"); - if (varID == varIDs.gheightID) var1.nlevels = nlevels + 1; + // if (varID == varIDs.gheightID) var1.nlevels = nlevels + 1; vardata1[varID].init(var1); - if (varID == varIDs.gheightID) var1.nlevels = nlevels; + // if (varID == varIDs.gheightID) var1.nlevels = nlevels; - // interpVars[varID] = (zaxis_is_hybrid(zaxistype) && zaxisID_ML != -1 && nlevels == numHybridLevels); + // interpVars[varID] = (zaxis_is_hybrid(var1.zaxisType) && zaxisID_ML != -1 && nlevels == numHybridLevels); interpVars[varID] - = (zaxisID == zaxisID_ML - || (zaxis_is_hybrid(zaxistype) && zaxisID_ML != -1 && (nlevels == numHalfLevels || nlevels == numFullLevels))); + = (var1.zaxisID == zaxisID_ML + || (zaxis_is_hybrid(var1.zaxisType) && zaxisID_ML != -1 && (nlevels == numHalfLevels || nlevels == numFullLevels))); if (interpVars[varID]) { - varnmiss[varID].resize(maxLevels, 0); + varnumMissVals[varID].resize(maxLevels, 0); vardata2[varID].init(varList2[varID]); } else { - varnmiss[varID].resize(nlevels); - if (zaxis_is_hybrid(zaxistype) && zaxisID_ML != -1 && nlevels > 1) + varnumMissVals[varID].resize(nlevels); + if (zaxis_is_hybrid(var1.zaxisType) && zaxisID_ML != -1 && nlevels > 1) cdo_warning("Parameter %d has wrong number of levels, skipped! (param=%s nlevel=%d)", varID + 1, var1.name, nlevels); } } + auto needVertIndexHalf{ false }; + for (int varID = 0; varID < nvars; ++varID) + { + if (interpVars[varID]) + { + auto &var1 = varList1[varID]; + if (var1.nlevels == numHalfLevels && varID != varIDs.gheightID) needVertIndexHalf = true; + } + } + + std::vector<int> vertIndex_FL; + std::vector<int> vertIndex_HL; + if (zaxisID_ML != -1 && gridsize > 0) + { + vertIndex_FL.resize(gridsize * numPL); + if (needVertIndexHalf) vertIndex_HL.resize(gridsize * numPL); + } + if (zaxisID_ML != -1 && varIDs.gheightID != -1 && varIDs.tempID == -1) cdo_abort("%s not found, needed for vertical interpolation of %s!", var_stdname(air_temperature), var_stdname(geopotential_height)); @@ -324,7 +364,7 @@ pressure_level_interpolation(Varray<double> &pressureLevels, bool useHeightLevel if (vctIsInverted && zaxisID_ML != -1 && var.zaxisID == zaxisID_ML) levelID = var.nlevels - 1 - levelID; - cdo_read_record(streamID1, vardata1[varID], levelID, &varnmiss[varID][levelID]); + cdo_read_record(streamID1, vardata1[varID], levelID, &varnumMissVals[varID][levelID]); processVars[varID] = true; } @@ -352,9 +392,14 @@ pressure_level_interpolation(Varray<double> &pressureLevels, bool useHeightLevel vct_to_hybrid_pressure(memType, pressure_FL, pressure_HL, vct.data(), psProg, numFullLevels, gridsize); - gen_vert_index(vertIndex, pressureLevels, pressure_FL, gridsize); + gen_vert_index(vertIndex_FL, pressureLevels, pressure_FL, gridsize); + if (!extrapolate) gen_vert_index_mv(vertIndex_FL, pressureLevels, gridsize, psProg, pnumMissVals); - if (!extrapolate) gen_vert_index_mv(vertIndex, pressureLevels, gridsize, psProg, pnmiss); + if (needVertIndexHalf) + { + gen_vert_index(vertIndex_HL, pressureLevels, pressure_HL, gridsize); + if (!extrapolate) gen_vert_index_mv(vertIndex_HL, pressureLevels, gridsize, psProg, pnumMissVals); + } } for (int varID = 0; varID < nvars; ++varID) @@ -367,43 +412,44 @@ pressure_level_interpolation(Varray<double> &pressureLevels, bool useHeightLevel if (interpVars[varID]) { - auto nlevels = var.nlevels; - if (nlevels != numFullLevels && nlevels != numHalfLevels) + if (var.nlevels != numFullLevels && var.nlevels != numHalfLevels) cdo_abort("Number of hybrid level differ from full/half level (param=%s)!", var.name); - for (int levelID = 0; levelID < nlevels; ++levelID) + for (int levelID = 0; levelID < var.nlevels; ++levelID) { - if (varnmiss[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); + if (varnumMissVals[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); } if (varID == varIDs.tempID) { - if (nlevels == numHalfLevels) cdo_abort("Temperature on half level unsupported!"); + if (var.nlevels == numHalfLevels) cdo_abort("Temperature on half level unsupported!"); - vertical_interp_T(nlevels, pressure_FL, pressure_HL, vardata1[varID], vardata2[varID], sgeopot, vertIndex, - pressureLevels, gridsize); + vertical_interp_T(var.nlevels, pressure_FL, pressure_HL, vardata1[varID], vardata2[varID], sgeopot, + vertIndex_FL, pressureLevels, gridsize); } else if (varID == varIDs.gheightID) { - field_copy_div_2d_to_3d(memType, gridsize, nlevels, sgeopot, vardata1[varID]); + // field_copy_div_2d_to_3d(memType, gridsize, var.nlevels, sgeopot, vardata1[varID]); + field_check_sgeopot(memType, gridsize, var.nlevels, sgeopot, vardata1[varID]); - vertical_interp_Z(nlevels, pressure_FL, pressure_HL, vardata1[varID], vardata2[varID], - vardata1[varIDs.tempID], sgeopot, vertIndex, pressureLevels, gridsize); + vertical_interp_Z(numFullLevels, pressure_FL, pressure_HL, vardata1[varID], vardata2[varID], + vardata1[varIDs.tempID], sgeopot, vertIndex_FL, pressureLevels, gridsize); } else { - const auto &levels3D = (nlevels == numFullLevels) ? pressure_FL : pressure_HL; - vertical_interp_X(levels3D, vardata1[varID], vardata2[varID], vertIndex, pressureLevels, gridsize); + const auto &levels3D = (var.nlevels == numFullLevels) ? pressure_FL : pressure_HL; + const auto &vertIndex3D = (var.nlevels == numFullLevels) ? vertIndex_FL : vertIndex_HL; + vertical_interp_X(levels3D, vardata1[varID], vardata2[varID], vertIndex3D, pressureLevels, gridsize); } - if (!extrapolate) varray_copy(numPL, pnmiss, varnmiss[varID]); + if (!extrapolate) varray_copy(numPL, pnumMissVals, varnumMissVals[varID]); } for (int levelID = 0; levelID < varList2[varID].nlevels; ++levelID) { cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, interpVars[varID] ? vardata2[varID] : vardata1[varID], levelID, - varnmiss[varID][levelID]); + varnumMissVals[varID][levelID]); } } } @@ -415,10 +461,14 @@ pressure_level_interpolation(Varray<double> &pressureLevels, bool useHeightLevel cdo_stream_close(streamID1); } +//#define ENABLE_HEIGHT_LEVEL_INTERPOLATION + +#ifdef ENABLE_HEIGHT_LEVEL_INTERPOLATION +// obsolete, use intlevel!!! static void height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) { - int numHL = heightLevels.size(); + int numHeightLevels = heightLevels.size(); auto streamID1 = cdo_open_read(0); @@ -436,7 +486,7 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) auto gridsize = vlist_check_gridsize(vlistID1); - auto zaxisID_HL = zaxisCreate(ZAXIS_HEIGHT, numHL); + auto zaxisID_HL = zaxisCreate(ZAXIS_HEIGHT, numHeightLevels); zaxisDefLevels(zaxisID_HL, heightLevels.data()); int zaxisID_ML = -1; @@ -452,7 +502,7 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) VarList varList2; varList_init(varList2, vlistID2); varListSetMemtype(varList2, memType); - + /* auto vctIsInverted = false; if (vctSize && vctSize % 2 == 0) { @@ -467,17 +517,17 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) if (Options::cdoVerbose) cdo_print("vctIsInverted = %d", static_cast<int>(vctIsInverted)); if (vctIsInverted) invert_vct(vct); - + */ auto nvars = vlistNvars(vlistID1); std::vector<bool> processVars(nvars), interpVars(nvars); - Varray2D<size_t> varnmiss(nvars); + Varray2D<size_t> varnumMissVals(nvars); Field3DVector vardata1(nvars), vardata2(nvars); - auto maxLevels = std::max(numHalfLevels, numHL); + auto maxLevels = std::max(numHalfLevels, numHeightLevels); - Varray<size_t> pnmiss; - if (!extrapolate) pnmiss.resize(numHL); + Varray<size_t> pnumMissVals; + if (!extrapolate) pnumMissVals.resize(numHeightLevels); // check levels if (zaxisID_ML != -1) @@ -487,23 +537,7 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) } std::vector<int> vertIndex; - - Field3D pressure_FL, pressure_HL; - if (zaxisID_ML != -1 && gridsize > 0) - { - vertIndex.resize(gridsize * numHL); - - CdoVar var3Df, var3Dh; - var3Df.gridsize = gridsize; - var3Df.nlevels = numFullLevels; - var3Df.memType = memType; - pressure_FL.init(var3Df); - - var3Dh.gridsize = gridsize; - var3Dh.nlevels = numHalfLevels; - var3Dh.memType = memType; - pressure_HL.init(var3Dh); - } + if (zaxisID_ML != -1 && gridsize > 0) { vertIndex.resize(gridsize * numHeightLevels); } else cdo_warning("No 3D variable with hybrid sigma pressure coordinate found!"); @@ -524,39 +558,35 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) for (int varID = 0; varID < nvars; ++varID) { - auto &var1 = varList1[varID]; - auto gridID = var1.gridID; - auto zaxisID = var1.zaxisID; - auto zaxistype = zaxisInqType(zaxisID); + const auto &var1 = varList1[varID]; auto nlevels = var1.nlevels; - if (gridInqType(gridID) == GRID_SPECTRAL && zaxis_is_hybrid(zaxistype)) - cdo_abort("Spectral data on model level unsupported!"); + if (var1.gridType == GRID_SPECTRAL && zaxis_is_hybrid(var1.zaxisType)) cdo_abort("Spectral data on model level unsupported!"); - if (gridInqType(gridID) == GRID_SPECTRAL) cdo_abort("Spectral data unsupported!"); + if (var1.gridType == GRID_SPECTRAL) cdo_abort("Spectral data unsupported!"); vardata1[varID].init(var1); - // interpVars[varID] = (zaxis_is_hybrid(zaxistype) && zaxisID_ML != -1 && nlevels == numHybridLevels); + // interpVars[varID] = (zaxis_is_hybrid(var1.zaxisType) && zaxisID_ML != -1 && nlevels == numHybridLevels); interpVars[varID] - = (zaxisID == zaxisID_ML - || (zaxis_is_hybrid(zaxistype) && zaxisID_ML != -1 && (nlevels == numHalfLevels || nlevels == numFullLevels))); + = (var1.zaxisID == zaxisID_ML + || (zaxis_is_hybrid(var1.zaxisType) && zaxisID_ML != -1 && (nlevels == numHalfLevels || nlevels == numFullLevels))); if (interpVars[varID]) { - varnmiss[varID].resize(maxLevels, 0); + varnumMissVals[varID].resize(maxLevels, 0); vardata2[varID].init(varList2[varID]); } else { - varnmiss[varID].resize(nlevels); - if (zaxis_is_hybrid(zaxistype) && zaxisID_ML != -1 && nlevels > 1) + varnumMissVals[varID].resize(nlevels); + if (zaxis_is_hybrid(var1.zaxisType) && zaxisID_ML != -1 && nlevels > 1) cdo_warning("Parameter %d has wrong number of levels, skipped! (param=%s nlevel=%d)", varID + 1, var1.name, nlevels); } } if (zaxisID_ML != -1 && varIDs.gheightID == -1) cdo_abort("%s not found!", var_stdname(geopotential_height)); - + /* auto sgeopotNeeded = (!extrapolate && varIDs.gheightID != -1); Field sgeopot; @@ -572,17 +602,16 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) if (extrapolate) cdo_warning("%s not found - set to zero!", var_stdname(surface_geopotential)); } - else - { - sgeopot.init(varList1[varIDs.sgeopotID]); - } + else { sgeopot.init(varList1[varIDs.sgeopotID]); } field_fill(sgeopot, 0.0); } - + */ auto streamID2 = cdo_open_write(1); cdo_def_vlist(streamID2, vlistID2); + Field heightBottom; + int tsID = 0; while (true) { @@ -598,16 +627,21 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, vardata1[varID], levelID, &varnmiss[varID][levelID]); + cdo_read_record(streamID1, vardata1[varID], levelID, &varnumMissVals[varID][levelID]); processVars[varID] = true; } + auto lreverse = true; if (zaxisID_ML != -1) { - gen_vert_index(vertIndex, heightLevels, vardata1[varIDs.gheightID], gridsize); - - // if (!extrapolate) gen_vert_index_mv(vertIndex, heightLevels, gridsize, psProg, pnmiss); + gen_vert_index(vertIndex, heightLevels, vardata1[varIDs.gheightID], gridsize, lreverse); + if (!extrapolate) + { + heightBottom.init(varList1[varIDs.gheightID]); + field_copy(vardata1[varIDs.gheightID], numFullLevels - 1, heightBottom); + gen_vert_index_mv(vertIndex, heightLevels, gridsize, heightBottom, pnumMissVals, lreverse); + } } for (int varID = 0; varID < nvars; ++varID) @@ -624,21 +658,20 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) for (int levelID = 0; levelID < var.nlevels; ++levelID) { - if (varnmiss[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); + if (varnumMissVals[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); } - // const auto &levels3D = (nlevels == numFullLevels) ? vardata1[varIDs.gheightID] : pressure_HL; const auto &levels3D = vardata1[varIDs.gheightID]; vertical_interp_X(levels3D, vardata1[varID], vardata2[varID], vertIndex, heightLevels, gridsize); - if (!extrapolate) varray_copy(numHL, pnmiss, varnmiss[varID]); + if (!extrapolate) varray_copy(numHeightLevels, pnumMissVals, varnumMissVals[varID]); } for (int levelID = 0; levelID < varList2[varID].nlevels; ++levelID) { cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, interpVars[varID] ? vardata2[varID] : vardata1[varID], levelID, - varnmiss[varID][levelID]); + varnumMissVals[varID][levelID]); } } } @@ -649,8 +682,9 @@ height_level_interpolation(Varray<double> &heightLevels, bool extrapolate) cdo_stream_close(streamID2); cdo_stream_close(streamID1); } +#endif -class ModuleVertintml +class Vertintml : public Process { enum { @@ -658,32 +692,49 @@ class ModuleVertintml func_hl }; - bool doPressureInterpolation; +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertintml", + // clang-format off + .operators = { { "ml2pl", func_pl, 0, "pressure levels in pascal", VertintmlHelp }, + { "ml2hl", func_hl, 0, "height levels in meter", VertintmlHelp }, + { "ml2plx", func_pl, 0, "pressure levels in pascal", VertintmlHelp }, + { "ml2hlx", func_hl, 0, "height levels in meter", VertintmlHelp }, +#ifdef ENABLE_HEIGHT_LEVEL_INTERPOLATION + { "ml2height", func_hl, 1, "height levels in meter", VertintmlHelp }, + { "ml2heightx", func_hl, 1, "height levels in meter", VertintmlHelp } +#endif + }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertintml> registration = RegisterEntry<Vertintml>(module); + + int ML2PLX, ML2HLX, ML2HEIGHTX; + + bool doHeightInterpolation; bool useHeightLevel; bool extrapolate; Varray<double> levels; - int ML2PLX, ML2HLX, ML2HEIGHTX; - public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - cdo_operator_add("ml2pl", func_pl, 0, "pressure levels in pascal"); - ML2PLX = cdo_operator_add("ml2plx", func_pl, 0, "pressure levels in pascal"); - cdo_operator_add("ml2hl", func_hl, 0, "height levels in meter"); - ML2HLX = cdo_operator_add("ml2hlx", func_hl, 0, "height levels in meter"); - cdo_operator_add("ml2height", func_hl, 1, "height levels in meter"); - ML2HEIGHTX = cdo_operator_add("ml2heightx", func_hl, 1, "height levels in meter"); - // clang-format on + ML2PLX = module.get_id("ml2plx"); + ML2HLX = module.get_id("ml2hlx"); +#ifdef ENABLE_HEIGHT_LEVEL_INTERPOLATION + ML2HEIGHTX = module.get_id("ml2heightx"); +#endif auto operatorID = cdo_operator_id(); useHeightLevel = (cdo_operator_f1(operatorID) == func_hl); - doPressureInterpolation = (cdo_operator_f2(operatorID) == 0); + doHeightInterpolation = (cdo_operator_f2(operatorID) == 1); extrapolate = (operatorID == ML2PLX || operatorID == ML2HLX || operatorID == ML2HEIGHTX); if (extrapolate == false) extrapolate = getenv_extrapolate(); @@ -698,34 +749,22 @@ public: levels = { 100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000 }; } - else - { - levels = cdo_argv_to_flt(cdo_get_oper_argv()); - } + else { levels = cdo_argv_to_flt(cdo_get_oper_argv()); } } void run() { - if (doPressureInterpolation) - pressure_level_interpolation(levels, useHeightLevel, extrapolate); - else +#ifdef ENABLE_HEIGHT_LEVEL_INTERPOLATION + if (doHeightInterpolation) height_level_interpolation(levels, extrapolate); + else +#endif + pressure_level_interpolation(levels, useHeightLevel, extrapolate); } void close() { - cdo_finish(); } }; - -void * -Vertintml(void *process) -{ - ModuleVertintml vertintml; - vertintml.init(process); - vertintml.run(); - vertintml.close(); - return nullptr; -} diff --git a/src/Vertintzs.cc b/src/Vertintzs.cc index 1693285970a59584b5d8a9940aad2a0e45eed82f..5f69b64e55e3865969c56ef7e57343ca36c2f600 100644 --- a/src/Vertintzs.cc +++ b/src/Vertintzs.cc @@ -52,10 +52,7 @@ create_zaxis_depth(Varray<double> &depthLevels) else cdo_abort("Open failed on %s", zfilename); } - else - { - depthLevels = cdo_argv_to_flt(cdo_get_oper_argv()); - } + else { depthLevels = cdo_argv_to_flt(cdo_get_oper_argv()); } if (zaxisID == CDI_UNDEFID) { @@ -66,8 +63,20 @@ create_zaxis_depth(Varray<double> &depthLevels) return zaxisID; } -class ModuleVertintzs +class Vertintzs : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertintzs", + .operators = { { "zs2zl", 0, 0, "depth levels in meter"}, { "zs2zlx"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertintzs> registration = RegisterEntry<Vertintzs>(module); + private: int nvars; std::vector<bool> processVars; @@ -84,7 +93,7 @@ private: Field3DVector vardata1; Field3DVector vardata2; - Varray2D<size_t> varnmiss; + Varray2D<size_t> varnumMissVals; int depthID = -1; @@ -99,15 +108,12 @@ private: Field depthBottom; int numFullLevels; - Varray<size_t> pnmiss; + Varray<size_t> pnumMissVals; public: void - init(void *process) + init() { - cdo_initialize(process); - - cdo_operator_add("zs2zl", 0, 0, "depth levels in meter"); auto operatorID = cdo_operator_id(); @@ -162,13 +168,13 @@ public: varList_init(varList2, vlistID2); varListSetMemtype(varList2, memType); - if (!extrapolate) pnmiss.resize(depthLevels.size()); + if (!extrapolate) pnumMissVals.resize(depthLevels.size()); vertIndexFull.resize(gridsize * depthLevels.size()); processVars = std::vector<bool>(nvars); interpVars = std::vector<bool>(nvars); - varnmiss = Varray2D<size_t>(nvars); + varnumMissVals = Varray2D<size_t>(nvars); vardata1 = Field3DVector(nvars); vardata2 = Field3DVector(nvars); @@ -181,7 +187,7 @@ public: if (gridInqType(var.gridID) == GRID_SPECTRAL) cdo_abort("Spectral data unsupported!"); vardata1[varID].init(var); - varnmiss[varID].resize(maxlev, 0); + varnumMissVals[varID].resize(maxlev, 0); interpVars[varID] = (var.zaxisID == zaxisIDfull || (is_depth_axis(var.zaxisID) && (var.nlevels == numFullLevels))); @@ -218,7 +224,7 @@ public: { processVars[varID] = false; const auto &var = varList1[varID]; - for (int levelID = 0; levelID < var.nlevels; ++levelID) varnmiss[varID][levelID] = 0; + for (int levelID = 0; levelID < var.nlevels; ++levelID) varnumMissVals[varID][levelID] = 0; } cdo_taxis_copy_timestep(taxisID2, taxisID1); @@ -228,7 +234,7 @@ public: { int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); - cdo_read_record(streamID1, vardata1[varID], levelID, &varnmiss[varID][levelID]); + cdo_read_record(streamID1, vardata1[varID], levelID, &varnumMissVals[varID][levelID]); processVars[varID] = true; } @@ -244,7 +250,7 @@ public: { depthBottom.init(varList1[depthID]); field_copy(fullDepth, numFullLevels - 1, depthBottom); - gen_vert_index_mv(vertIndexFull, depthLevels, gridsize, depthBottom, pnmiss, lreverse); + gen_vert_index_mv(vertIndexFull, depthLevels, gridsize, depthBottom, pnumMissVals, lreverse); } } @@ -263,19 +269,19 @@ public: for (int levelID = 0; levelID < var.nlevels; ++levelID) { - if (varnmiss[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); + if (varnumMissVals[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); } vertical_interp_X(fullDepth, vardata1[varID], vardata2[varID], vertIndexFull, depthLevels, gridsize); - if (!extrapolate) varray_copy(depthLevels.size(), pnmiss, varnmiss[varID]); + if (!extrapolate) varray_copy(depthLevels.size(), pnumMissVals, varnumMissVals[varID]); } for (int levelID = 0; levelID < varList2[varID].nlevels; ++levelID) { cdo_def_record(streamID2, varID, levelID); auto varout = (interpVars[varID] ? vardata2[varID] : vardata1[varID]); - cdo_write_record(streamID2, varout, levelID, varnmiss[varID][levelID]); + cdo_write_record(streamID2, varout, levelID, varnumMissVals[varID][levelID]); } } } @@ -289,17 +295,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Vertintzs(void *process) -{ - ModuleVertintzs vertintzs; - vertintzs.init(process); - vertintzs.run(); - vertintzs.close(); - return nullptr; -} diff --git a/src/Vertstat.cc b/src/Vertstat.cc index 95c7694df3f9ff2386760700cb3f0bf701e2981d..01c4a7afea39ae3a2ce7064dd8610d6a1a8cd404 100644 --- a/src/Vertstat.cc +++ b/src/Vertstat.cc @@ -76,7 +76,7 @@ vertstat_get_parameter(bool &weights, bool &genbounds) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -95,8 +95,31 @@ vertstat_get_parameter(bool &weights, bool &genbounds) } } -class ModuleVertstat +class Vertstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertstat", + .operators = { { "vertrange", FieldFunc_Range, 0, VertstatHelp }, + { "vertmin", FieldFunc_Min, 0, VertstatHelp }, + { "vertmax", FieldFunc_Max, 0, VertstatHelp }, + { "vertsum", FieldFunc_Sum, 0, VertstatHelp }, + { "vertint", FieldFunc_Sum, 1, VertstatHelp }, + { "vertmean", FieldFunc_Mean, 1, VertstatHelp }, + { "vertavg", FieldFunc_Avg, 1, VertstatHelp }, + { "vertstd", FieldFunc_Std, 1, VertstatHelp }, + { "vertstd1", FieldFunc_Std1, 1, VertstatHelp }, + { "vertvar", FieldFunc_Var, 1, VertstatHelp }, + { "vertvar1", FieldFunc_Var1, 1, VertstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertstat> registration = RegisterEntry<Vertstat>(module); + + int VERTINT; struct VertInfo { int zaxisID = -1; @@ -136,27 +159,12 @@ class ModuleVertstat Field field; std::vector<VertInfo> vert; - int VERTINT; public: void - init(void *process) + init() { - cdo_initialize(process); - - // clang-format off - cdo_operator_add("vertrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("vertmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("vertmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("vertsum", FieldFunc_Sum, 0, nullptr); - VERTINT = cdo_operator_add("vertint", FieldFunc_Sum, 1, nullptr); - cdo_operator_add("vertmean", FieldFunc_Mean, 1, nullptr); - cdo_operator_add("vertavg", FieldFunc_Avg, 1, nullptr); - cdo_operator_add("vertvar", FieldFunc_Var, 1, nullptr); - cdo_operator_add("vertvar1", FieldFunc_Var1, 1, nullptr); - cdo_operator_add("vertstd", FieldFunc_Std, 1, nullptr); - cdo_operator_add("vertstd1", FieldFunc_Std1, 1, nullptr); - // clang-format on + VERTINT = module.get_id("vertint"); operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -254,7 +262,6 @@ public: void run() { - auto field2_stdvar_func = lstd ? field2_std : field2_var; auto fieldc_stdvar_func = lstd ? fieldc_std : fieldc_var; int tsID = 0; @@ -310,7 +317,7 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[varID].nmiss = rvars1.nmiss; + vars2[varID].numMissVals = rvars1.numMissVals; vars2[varID].vec_d = rvars1.vec_d; } @@ -327,7 +334,7 @@ public: else { field2_moq(vars2[varID], rvars1); } } - if (rvars1.nmiss || !rsamp1.empty() || needWeights) + if (rvars1.numMissVals || !rsamp1.empty() || needWeights) { if (rsamp1.empty()) rsamp1.resize(gridsize); @@ -343,7 +350,7 @@ public: if (operatorID == VERTINT && is_not_equal(layerThickness, 1.0)) fieldc_mul(field, layerThickness); if (lmean && is_not_equal(layerWeight, 1.0)) fieldc_mul(field, layerWeight); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(gridsize, rvars1.nsamp); @@ -414,19 +421,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); - } }; - -void * -Vertstat(void *process) -{ - ModuleVertstat vertstat; - vertstat.init(process); - vertstat.run(); - vertstat.close(); - - return nullptr; -} diff --git a/src/Vertwind.cc b/src/Vertwind.cc index 1b8ca443a58e82b8d6cd79e95401d2499e895a4a..c79e0008be82e4311a0d3e5a823a872084debbac 100644 --- a/src/Vertwind.cc +++ b/src/Vertwind.cc @@ -23,8 +23,19 @@ constexpr double R = 287.07; // spezielle Gaskonstante fuer Luft constexpr double G = 9.80665; // Erdbeschleunigung -class ModuleVertwind +class Vertwind : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Vertwind", + .operators = { { "vertwind"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Vertwind> registration = RegisterEntry<Vertwind>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -54,11 +65,9 @@ class ModuleVertwind public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -84,33 +93,15 @@ public: auto varname = string_to_lower(varList1[varID].name); if (varname == "st") { code = temp_code; } - else if (varname == "sq") - { - code = sq_code; - } - else if (varname == "aps") - { - code = ps_code; - } - else if (varname == "omega") - { - code = omega_code; - } + else if (varname == "sq") { code = sq_code; } + else if (varname == "aps") { code = ps_code; } + else if (varname == "omega") { code = omega_code; } } if (code == temp_code) { tempID = varID; } - else if (code == sq_code) - { - sqID = varID; - } - else if (code == ps_code) - { - psID = varID; - } - else if (code == omega_code) - { - omegaID = varID; - } + else if (code == sq_code) { sqID = varID; } + else if (code == ps_code) { psID = varID; } + else if (code == omega_code) { omegaID = varID; } } if (tempID == -1 || sqID == -1 || omegaID == -1) @@ -205,20 +196,20 @@ public: for (int recID = 0; recID < nrecs; ++recID) { - size_t nmiss; + size_t numMissVals; int varID, levelID; cdo_inq_record(streamID1, &varID, &levelID); auto offset = (size_t) levelID * gridsize; if (varID == tempID) - cdo_read_record(streamID1, &temp[offset], &nmiss); + cdo_read_record(streamID1, &temp[offset], &numMissVals); else if (varID == sqID) - cdo_read_record(streamID1, &sq[offset], &nmiss); + cdo_read_record(streamID1, &sq[offset], &numMissVals); else if (varID == omegaID) - cdo_read_record(streamID1, &omega[offset], &nmiss); + cdo_read_record(streamID1, &omega[offset], &numMissVals); else if (varID == psID && zaxisInqType(zaxisID) == ZAXIS_HYBRID) - cdo_read_record(streamID1, psProg.data(), &nmiss); + cdo_read_record(streamID1, psProg.data(), &numMissVals); } if (zaxisInqType(zaxisID) == ZAXIS_HYBRID) @@ -255,12 +246,12 @@ public: { auto offset = (size_t) levelID * gridsize; - size_t nmiss_out = 0; + size_t numMissVals_out = 0; for (size_t i = 0; i < gridsize; ++i) - if (dbl_is_equal(wms[offset + i], missval_out)) nmiss_out++; + if (dbl_is_equal(wms[offset + i], missval_out)) numMissVals_out++; cdo_def_record(streamID2, 0, levelID); - cdo_write_record(streamID2, &wms[offset], nmiss_out); + cdo_write_record(streamID2, &wms[offset], numMissVals_out); } tsID++; @@ -274,18 +265,5 @@ public: cdo_stream_close(streamID1); vlistDestroy(vlistID2); - - cdo_finish(); } }; - -void * -Vertwind(void *process) -{ - ModuleVertwind vertwind; - vertwind.init(process); - vertwind.run(); - vertwind.close(); - - return nullptr; -} diff --git a/src/Wct.cc b/src/Wct.cc index 53e581656b7cf43de5fb189a456348b13d6c8716..b6abb14fcee1df8af71e79e57bbf642b860612e3 100644 --- a/src/Wct.cc +++ b/src/Wct.cc @@ -50,7 +50,7 @@ farexpr(Field &field1, Field &field2, double (*expression)(double, double, doubl auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { for (size_t i = 0; i < len; ++i) if (DBL_IS_EQUAL(field1.vec_d[i], missval1) || DBL_IS_EQUAL(field2.vec_d[i], missval2)) @@ -63,11 +63,23 @@ farexpr(Field &field1, Field &field2, double (*expression)(double, double, doubl for (size_t i = 0; i < len; ++i) field1.vec_d[i] = expression(field1.vec_d[i], field2.vec_d[i], missval1); } - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } -class ModuleWct +class Wct : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Wct", + .operators = { { "wct", WctHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Wct> registration = RegisterEntry<Wct>(module); + CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -84,11 +96,8 @@ class ModuleWct public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("wct", 0, 0, nullptr); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -147,11 +156,11 @@ public: { int varID1, levelID1; cdo_inq_record(streamID1, &varID1, &levelID1); - cdo_read_record(streamID1, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(streamID1, field1.vec_d.data(), &field1.numMissVals); int varID2, levelID2; cdo_inq_record(streamID2, &varID2, &levelID2); - cdo_read_record(streamID2, field2.vec_d.data(), &field2.nmiss); + cdo_read_record(streamID2, field2.vec_d.data(), &field2.numMissVals); if (varID1 != varID2 || levelID1 != levelID2) cdo_abort("Input streams have different structure!"); @@ -163,7 +172,7 @@ public: farexpr(field1, field2, windchillTemperature); cdo_def_record(streamID3, varID3, levelID1); - cdo_write_record(streamID3, field1.vec_d.data(), field1.nmiss); + cdo_write_record(streamID3, field1.vec_d.data(), field1.numMissVals); } tsID++; @@ -176,18 +185,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Wct(void *process) -{ - ModuleWct wct; - wct.init(process); - wct.run(); - wct.close(); - - return nullptr; -} diff --git a/src/Wind.cc b/src/Wind.cc index 40b2552db46166714291b06bf2b847b804cbe931..0b62441ae8d4036792be08c2db14377df72aae5f 100644 --- a/src/Wind.cc +++ b/src/Wind.cc @@ -66,8 +66,25 @@ defineAttributesPS(int vlistID2, int varID1, int varID2) cdiDefKeyString(vlistID2, varID2, CDI_KEY_UNITS, "m^2/s"); } -class ModuleWind +class Wind : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Wind", + .operators = { { "uv2dv", WindHelp }, + { "uv2dvl", WindHelp }, + { "dv2uv", WindHelp }, + { "dv2uvl", WindHelp }, + { "dv2ps", Wind2Help } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Wind> registration = RegisterEntry<Wind>(module); + + int UV2DV, UV2DVL, DV2UV, DV2UVL, DV2PS; CdoStreamID streamID1; CdoStreamID streamID2; @@ -86,15 +103,9 @@ class ModuleWind int operatorID; - int UV2DV; - int UV2DVL; - int DV2UV; - int DV2UVL; - int DV2PS; - size_t nlev = 0; int gridID1 = -1, gridID2 = -1; - size_t nmiss; + size_t numMissVals; long ntr = -1; int varID1 = -1, varID2 = -1; SP_Transformation spTrans; @@ -102,24 +113,21 @@ class ModuleWind public: void - init(void *process) + init() { - cdo_initialize(process); - dataIsUnchanged = data_is_unchanged(); - // clang-format off - UV2DV = cdo_operator_add("uv2dv", 0, 0, nullptr); - UV2DVL = cdo_operator_add("uv2dvl", 0, 0, nullptr); - DV2UV = cdo_operator_add("dv2uv", 0, 0, nullptr); - DV2UVL = cdo_operator_add("dv2uvl", 0, 0, nullptr); - DV2PS = cdo_operator_add("dv2ps", 0, 0, nullptr); + UV2DV = module.get_id("uv2dv"); + UV2DVL = module.get_id("uv2dvl"); + DV2UV = module.get_id("dv2uv"); + DV2UVL = module.get_id("dv2uvl"); + DV2PS = module.get_id("dv2ps"); operatorID = cdo_operator_id(); - luv2dv = (operatorID == UV2DV || operatorID == UV2DVL); - ldv2uv = (operatorID == DV2UV || operatorID == DV2UVL); - linear = (operatorID == UV2DVL || operatorID == DV2UVL); + luv2dv = (operatorID == UV2DV || operatorID == UV2DVL); + ldv2uv = (operatorID == DV2UV || operatorID == DV2UVL); + linear = (operatorID == UV2DVL || operatorID == DV2UVL); int (*nlat2ntr)(int) = linear ? nlat_to_ntr_linear : nlat_to_ntr; const char *ctype = linear ? "l" : ""; @@ -127,12 +135,13 @@ public: if ((luv2dv || ldv2uv) && cdo_operator_argc() == 1) { std::string type = parameter_to_word(cdo_operator_argv(0)); + // clang-format off if (type == "linear") { nlat2ntr = nlat_to_ntr_linear; ctype = "l"; } else if (type == "cubic") { nlat2ntr = nlat_to_ntr_cubic; ctype = "c"; } else if (type == "quadratic") { nlat2ntr = nlat_to_ntr; } else cdo_abort("Unsupported type: %s\n", type); + // clang-format on } - // clang-format on streamID1 = cdo_open_read(0); @@ -202,9 +211,9 @@ public: if (gridID1 != vlistInqVarGrid(vlistID1, varID2)) cdo_abort("U and V wind must have the same grid represention!"); auto numLPE = gridInqNP(gridID1); - const long nlon = gridInqXsize(gridID1); - const long nlat = gridInqYsize(gridID1); - const long ntr1 = nlat2ntr(nlat); + long nlon = gridInqXsize(gridID1); + long nlat = gridInqYsize(gridID1); + long ntr1 = nlat2ntr(nlat); if (numLPE > 0 && nlat != (numLPE * 2)) cdo_abort("U and V fields on Gaussian grid are not global!"); @@ -246,8 +255,8 @@ public: if (gridIDgp != -1) { - const long nlat = gridInqYsize(gridIDgp); - const long ntr1 = nlat2ntr(nlat); + long nlat = gridInqYsize(gridIDgp); + long ntr1 = nlat2ntr(nlat); if (gridInqTrunc(gridIDsp) != ntr1) gridIDgp = -1; } @@ -262,8 +271,8 @@ public: defineAttributesUV(vlistID2, gridID2, varID1, varID2); - const long nlon = gridInqXsize(gridID2); - const long nlat = gridInqYsize(gridID2); + long nlon = gridInqXsize(gridID2); + long nlat = gridInqYsize(gridID2); ntr = gridInqTrunc(gridID1); nlev = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID1)); @@ -311,6 +320,7 @@ public: ovar2.resize(nlev * gridsize); } } + void run() { @@ -330,8 +340,8 @@ public: if ((varID1 != -1 && varID2 != -1) && (varID == varID1 || varID == varID2)) { - cdo_read_record(streamID1, array1.data(), &nmiss); - if (nmiss) cdo_abort("Missing values unsupported for spectral data!"); + cdo_read_record(streamID1, array1.data(), &numMissVals); + if (numMissVals) cdo_abort("Missing values unsupported for spectral data!"); auto gridsize = gridInqSize(gridID1); auto offset = gridsize * levelID; @@ -347,8 +357,8 @@ public: if (dataIsUnchanged) { cdo_copy_record(streamID2, streamID1); } else { - cdo_read_record(streamID1, array1.data(), &nmiss); - cdo_write_record(streamID2, array1.data(), nmiss); + cdo_read_record(streamID1, array1.data(), &numMissVals); + cdo_write_record(streamID2, array1.data(), numMissVals); } } } @@ -407,17 +417,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; -void * -Wind(void *process) -{ - ModuleWind wind; - wind.init(process); - wind.run(); - wind.close(); - - return nullptr; -} diff --git a/src/WindTrans.cc b/src/WindTrans.cc index e96344a44f974e9bedd7852eb38913d5993ebe4b..7808239d5445026ebd072eb8416ea277ba4f30a4 100644 --- a/src/WindTrans.cc +++ b/src/WindTrans.cc @@ -564,8 +564,8 @@ DestaggerUV() if (UorV >= 0) // re-check again since it could mean that current record with U or V is not staggered { - size_t nmiss; - cdo_read_record(streamID1, ivar.data(), &nmiss); + size_t numMissVals; + cdo_read_record(streamID1, ivar.data(), &numMissVals); // void destaggerUorV(double *fu, double *fuOut, int klev, int nlat, int nlon, int UorV, long int offset); // We handle one level at the time; klev=1;offset=0. @@ -595,7 +595,7 @@ DestaggerUV() cdo_print("Setting GRID id from: %d => to: %d", var.gridID, vlistInqVarGrid(vlistID2, varID)); cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, ovar.data(), nmiss); + cdo_write_record(streamID2, ovar.data(), numMissVals); } else { // copy the record to the output unchanged... @@ -625,8 +625,6 @@ DestaggerUV() cdo_stream_close(streamID2); cdo_stream_close(streamID1); - cdo_finish(); - return 0; } @@ -1106,401 +1104,414 @@ project_uv_latlon(int gridID, double *us, double *vs) Debug(cdoDebugExt >= 20, "%s(gridname=%s) finished.", __func__, gridNamePtr(gridInqType(gridID))); } - -class ModuleWindtrans +class WindTrans : public Process { - int operatorID; +public: + using Process::Process; + inline static CdoModule module = { + .name = "WindTrans", + .operators = { { "uvDestag", WindTransHelp }, + { "rotuvN", WindTransHelp }, + { "rotuvNorth", WindTransHelp }, + { "projuvLatLon", WindTransHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<WindTrans> registration = RegisterEntry<WindTrans>(module); int UVDESTAG, ROTUVNORTH, ROTUVN, PROJUVLATLON; + int operatorID; -void * -TransformUV() -{ - int varID, levelID; - int varID1, varID2, nlevel1, nlevel2; - size_t gridsize = 0; - int code, gridID; - int ltype, level, nlevs, zaxisID; - int pnum, pcat, pdis; - int chcodes[MAXARG]; - const char *chvars[MAXARG]; - int gridIDcurvl = -1; - int gridIDlastused = -1; - - // Note: Already initialized by the caller! Don't call again: cdo_initialize(process); - - operator_input_arg("Pairs of u and v in the rotated system;\n usage: rotuvNorth,u,v -or- rotuvNorth,33,34"); - - int nch = cdo_operator_argc(); - if (nch != 2) cdo_abort("Number of input arguments != 2"); - if (nch >= MAXARG) cdo_abort("Number of input arguments >= %d", MAXARG); + void * + TransformUV() + { + int varID, levelID; + int varID1, varID2, nlevel1, nlevel2; + size_t gridsize = 0; + int code, gridID; + int ltype, level, nlevs, zaxisID; + int pnum, pcat, pdis; + int chcodes[MAXARG]; + const char *chvars[MAXARG]; + int gridIDcurvl = -1; + int gridIDlastused = -1; + + // Note: Already initialized by the caller! Don't call again: cdo_initialize(process); + + operator_input_arg("Pairs of u and v in the rotated system;\n usage: rotuvNorth,u,v -or- rotuvNorth,33,34"); + + int nch = cdo_operator_argc(); + if (nch != 2) cdo_abort("Number of input arguments != 2"); + if (nch >= MAXARG) cdo_abort("Number of input arguments >= %d", MAXARG); + + bool lvar = false; // We have a list of codes + int len = (int) cdo_operator_argv(0).size(); + int ix = (cdo_operator_argv(0)[0] == '-') ? 1 : 0; + for (int i = ix; i < len; ++i) + if (!std::isdigit(cdo_operator_argv(0)[i])) + { + lvar = true; // We have a list of variables + break; + } - bool lvar = false; // We have a list of codes - int len = (int) cdo_operator_argv(0).size(); - int ix = (cdo_operator_argv(0)[0] == '-') ? 1 : 0; - for (int i = ix; i < len; ++i) - if (!std::isdigit(cdo_operator_argv(0)[i])) + if (lvar) { - lvar = true; // We have a list of variables - break; + for (int i = 0; i < nch; ++i) chvars[i] = cdo_operator_argv(i).c_str(); + } + else + { + for (int i = 0; i < nch; ++i) chcodes[i] = parameter_to_int(cdo_operator_argv(i)); } - if (lvar) - { - for (int i = 0; i < nch; ++i) chvars[i] = cdo_operator_argv(i).c_str(); - } - else - { - for (int i = 0; i < nch; ++i) chcodes[i] = parameter_to_int(cdo_operator_argv(i)); - } - - auto streamID1 = cdo_open_read(0); + auto streamID1 = cdo_open_read(0); - auto vlistID1 = cdo_stream_inq_vlist(streamID1); - auto vlistID2 = vlistDuplicate(vlistID1); + auto vlistID1 = cdo_stream_inq_vlist(streamID1); + auto vlistID2 = vlistDuplicate(vlistID1); - auto nvars = vlistNvars(vlistID1); - auto num_recs = vlistNrecs(vlistID1); + auto nvars = vlistNvars(vlistID1); + auto num_recs = vlistNrecs(vlistID1); - std::vector<RecordInfo> recList(num_recs); + std::vector<RecordInfo> recList(num_recs); - std::vector<std::vector<size_t>> varnmiss(nvars); - Varray3D<double> vardata(nvars); + std::vector<std::vector<size_t>> varnumMissVals(nvars); + Varray3D<double> vardata(nvars); - // U & V are NOT grid relative - for (varID = 0; varID < nvars; ++varID) cdiDefKeyInt(vlistID2, varID, CDI_KEY_UVRELATIVETOGRID, 0); + // U & V are NOT grid relative + for (varID = 0; varID < nvars; ++varID) cdiDefKeyInt(vlistID2, varID, CDI_KEY_UVRELATIVETOGRID, 0); - VarList varList1, varList2; - varList_init(varList1, vlistID1); - varList_init(varList2, vlistID2); + VarList varList1, varList2; + varList_init(varList1, vlistID1); + varList_init(varList2, vlistID2); - bool lfound[MAXARG]; - for (int i = 0; i < nch; ++i) lfound[i] = false; + bool lfound[MAXARG]; + for (int i = 0; i < nch; ++i) lfound[i] = false; - if (lvar) - { - for (varID = 0; varID < nvars; ++varID) - { - for (int i = 0; i < nch; ++i) - if (varList2[varID].name == chvars[i]) lfound[i] = true; - } - for (int i = 0; i < nch; ++i) - if (!lfound[i]) cdo_abort("Variable %s not found!", chvars[i]); - } - else - { - for (varID = 0; varID < nvars; ++varID) - { - for (int i = 0; i < nch; ++i) - if (varList2[varID].code == chcodes[i]) lfound[i] = true; - } - for (int i = 0; i < nch; ++i) - if (!lfound[i]) cdo_abort("Code %d not found!", chcodes[i]); - } - - int VarIsU, VarIsV; - - // NOTE: Variable with codes (3[3,4],105,10) will get from CDO typically a name: "10u", resp. "10v" - - for (varID = 0; varID < nvars; ++varID) - { - const auto &var = varList1[varID]; + if (lvar) + { + for (varID = 0; varID < nvars; ++varID) + { + for (int i = 0; i < nch; ++i) + if (varList2[varID].name == chvars[i]) lfound[i] = true; + } + for (int i = 0; i < nch; ++i) + if (!lfound[i]) cdo_abort("Variable %s not found!", chvars[i]); + } + else + { + for (varID = 0; varID < nvars; ++varID) + { + for (int i = 0; i < nch; ++i) + if (varList2[varID].code == chcodes[i]) lfound[i] = true; + } + for (int i = 0; i < nch; ++i) + if (!lfound[i]) cdo_abort("Code %d not found!", chcodes[i]); + } - cdiDecodeParam(var.param, &pnum, &pcat, &pdis); - code = pnum; - zaxisID = var.zaxisID; - ltype = zaxis_to_ltype(zaxisID); - nlevs = zaxisInqSize(zaxisID); + int VarIsU, VarIsV; - gridID = var.gridID; - if (cdoDebugExt >= 20) - cdo_print( - "Var.id [%4d] with grib code:%3d and has name: %6s; level type: %3d; number of levels: %3d; gridID: %d; zaxisID: %d", - varID, code, var.name, ltype, nlevs, gridID, zaxisID); + // NOTE: Variable with codes (3[3,4],105,10) will get from CDO typically a name: "10u", resp. "10v" - if (!(gridInqType(gridID) == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL)) - cdo_abort("Only rotated lon/lat grids supported!"); + for (varID = 0; varID < nvars; ++varID) + { + const auto &var = varList1[varID]; - CheckVarIsU(varID, var.name, code); - CheckVarIsV(varID, var.name, code); - if (VarIsU || VarIsV) - { - gridsize = gridInqSize(gridID); - if (cdoDebugExt) - cdo_print("Allocating memory for variableID %4d (code=%3d): gridsize(%zu)*nlevels(%d) = %zu [%4.3f MB]", varID, - varList2[varID].code, gridsize, nlevs, gridsize * nlevs, gridsize * nlevs * sizeof(double) / (1024.0 * 1024)); - varnmiss[varID].resize(nlevs); - vardata[varID].resize(nlevs); - for (levelID = 0; levelID < nlevs; ++levelID) vardata[varID][levelID].resize(gridsize); - } - } + cdiDecodeParam(var.param, &pnum, &pcat, &pdis); + code = pnum; + zaxisID = var.zaxisID; + ltype = zaxis_to_ltype(zaxisID); + nlevs = zaxisInqSize(zaxisID); - Debug(cdoDebugExt, "Neccessary memory has been allocated."); + gridID = var.gridID; + if (cdoDebugExt >= 20) + cdo_print( + "Var.id [%4d] with grib code:%3d and has name: %6s; level type: %3d; number of levels: %3d; gridID: %d; zaxisID: %d", + varID, code, var.name, ltype, nlevs, gridID, zaxisID); - auto taxisID1 = vlistInqTaxis(vlistID1); - auto taxisID2 = taxisDuplicate(taxisID1); - vlistDefTaxis(vlistID2, taxisID2); + if (!(gridInqType(gridID) == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL)) + cdo_abort("Only rotated lon/lat grids supported!"); - auto streamID2 = cdo_open_write(1); + CheckVarIsU(varID, var.name, code); + CheckVarIsV(varID, var.name, code); + if (VarIsU || VarIsV) + { + gridsize = gridInqSize(gridID); + if (cdoDebugExt) + cdo_print("Allocating memory for variableID %4d (code=%3d): gridsize(%zu)*nlevels(%d) = %zu [%4.3f MB]", varID, + varList2[varID].code, gridsize, nlevs, gridsize * nlevs, + gridsize * nlevs * sizeof(double) / (1024.0 * 1024)); + varnumMissVals[varID].resize(nlevs); + vardata[varID].resize(nlevs); + for (levelID = 0; levelID < nlevs; ++levelID) vardata[varID][levelID].resize(gridsize); + } + } - cdo_def_vlist(streamID2, vlistID2); // from this point the stream is using a different vlistID !!!!! - vlistID2 = cdo_stream_inq_vlist(streamID2); // refresh it + Debug(cdoDebugExt, "Neccessary memory has been allocated."); - int tsID = 0; - while (true) - { - auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); - if (nrecs == 0) break; + auto taxisID1 = vlistInqTaxis(vlistID1); + auto taxisID2 = taxisDuplicate(taxisID1); + vlistDefTaxis(vlistID2, taxisID2); - cdo_taxis_copy_timestep(taxisID2, taxisID1); - cdo_def_timestep(streamID2, tsID); + auto streamID2 = cdo_open_write(1); - if (cdoDebugExt) cdo_print("About to read U & V data to memory. Other data will be stream-copied to the output file."); + cdo_def_vlist(streamID2, vlistID2); // from this point the stream is using a different vlistID !!!!! + vlistID2 = cdo_stream_inq_vlist(streamID2); // refresh it - for (int recID = 0; recID < nrecs; ++recID) - { - cdo_inq_record(streamID1, &varID, &levelID); - code = varList1[varID].code; - zaxisID = varList1[varID].zaxisID; - ltype = zaxis_to_ltype(zaxisID); - level = zaxisInqLevel(zaxisID, levelID); - - if (vardata[varID].empty()) - { // This means that it is not eighter U neither V. - recList[recID].varID = -1; // We will NOT record/store this field in memory - recList[recID].levelID = -1; - // We will stream-copy this data - cdo_def_record(streamID2, varID, levelID); - // if ( cdoDebugExt>10 ) cdo_print("Copying data record.. %05d (timestep:%05d)", recID, tsID); - if (cdoDebugExt >= 20) - cdo_print("Stream-copy data record: %05d (timestep:%d); Var.id [%4d]; (code=%3d; ltype=%3d; level=%4d; " - "levelID=%3d)", - recID, tsID, varID, code, ltype, level, levelID); - cdo_copy_record(streamID2, streamID1); // cannot do this ! We have to set the flag uvGridRelative = 0 - } - else - { - recList[recID].varID = varID; - recList[recID].levelID = levelID; - if (cdoDebugExt >= 10) - cdo_print("Memmory-read data record: %05d (timestep:%d); Var.id [%4d]; (code=%3d; ltype=%3d; level=%4d; " - "levelID=%3d)", - recID, tsID, varID, code, ltype, level, levelID); - cdo_read_record(streamID1, vardata[varID][levelID].data(), &varnmiss[varID][levelID]); - if (varnmiss[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); - } - } // end of for ( recID = 0; recID < nrecs; .. + int tsID = 0; + while (true) + { + auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + if (nrecs == 0) break; - Debug(cdoDebugExt, "All neccessary U & V data are in memory. About to transform the windvectors..."); + cdo_taxis_copy_timestep(taxisID2, taxisID1); + cdo_def_timestep(streamID2, tsID); - int code1, zaxisID1, ltype1; - int code2, zaxisID2, ltype2; - Debug(cdoDebugExt, "Looping over %d variables to look for U-wind..", nvars); + if (cdoDebugExt) cdo_print("About to read U & V data to memory. Other data will be stream-copied to the output file."); - // find u-variables: - for (varID1 = 0; varID1 < nvars; ++varID1) - if (vardata[varID1].empty()) + for (int recID = 0; recID < nrecs; ++recID) { - // if ( cdoDebugExt ) cdo_print("Checking U-wind: vardata[%d]== nullptr ",varID1); - } - else // This means that it is U or V. - { - code1 = varList2[varID1].code; - zaxisID1 = varList2[varID1].zaxisID; - ltype1 = zaxis_to_ltype(zaxisID1); - nlevel1 = zaxisInqSize(zaxisID1); - CheckVarIsV(varID1, varList2[varID1].name, code1); - if (VarIsV) continue; - if (cdoDebugExt >= 20) - cdo_print("Checking U-wind: Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of levels: %3d; " - "zaxisID: %d", - varID1, code1, varList2[varID1].name, ltype1, nlevel1, zaxisID1); - CheckVarIsU(varID1, varList2[varID1].name, code1); - if (!VarIsU) continue; - if (cdoDebugExt >= 10) - cdo_print("** FOUND U-wind; Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of levels: %3d; " - "zaxisID: %d", - varID1, code1, varList2[varID1].name, ltype1, nlevel1, zaxisID1); - auto usvarID = varID1; - // find corresponding v-variable to u-variable: - for (varID2 = 0; varID2 < nvars; ++varID2) - if (vardata[varID2].empty()) - { - // if ( cdoDebugExt ) cdo_print("Checking V-wind: vardata[%d]== nullptr ",varID1); - } - else // This means that it is U or V. - { - code2 = varList2[varID2].code; - zaxisID2 = varList2[varID2].zaxisID; - ltype2 = zaxis_to_ltype(zaxisID2); - nlevel2 = zaxisInqSize(zaxisID2); - CheckVarIsU(varID2, varList2[varID2].name, code2); - if (VarIsU) continue; - if (cdoDebugExt >= 20) - cdo_print("Checking V-wind: Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of " - "levels: %3d; zaxisID: %d", - varID2, code2, varList2[varID2].name, ltype2, nlevel2, zaxisID2); - CheckVarIsV(varID2, varList2[varID2].name, code2); - if (!VarIsV) continue; - if (!((ltype1 == ltype2) && (nlevel1 == nlevel2) && (zaxisID1 == zaxisID2))) continue; - if (cdoDebugExt >= 10) - cdo_print("** FOUND V-wind; Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of " - "levels: %3d; zaxisID: %d", - varID2, code2, varList2[varID2].name, ltype1, nlevel2, zaxisID2); - auto vsvarID = varID2; - if (cdoDebugExt >= 20) - cdo_print("Using code %d [%d](u) and code %d [%d](v)", varList1[varID1].code, code1, varList1[varID2].code, - code2); - gridID = varList1[varID1].gridID; - if (operatorID != ROTUVN) // ROTUVN operator does not need creation of gridIDcurvl ... - { - if ((gridIDcurvl != -1) && (gridIDlastused != gridID)) - cdo_abort("The gridID (%d) used just previously for uv-wind tranformation is not same this " - "time(%d)!", - gridIDlastused, gridID); + cdo_inq_record(streamID1, &varID, &levelID); + code = varList1[varID].code; + zaxisID = varList1[varID].zaxisID; + ltype = zaxis_to_ltype(zaxisID); + level = zaxisInqLevel(zaxisID, levelID); + + if (vardata[varID].empty()) + { // This means that it is not eighter U neither V. + recList[recID].varID = -1; // We will NOT record/store this field in memory + recList[recID].levelID = -1; + // We will stream-copy this data + cdo_def_record(streamID2, varID, levelID); + // if ( cdoDebugExt>10 ) cdo_print("Copying data record.. %05d (timestep:%05d)", recID, tsID); + if (cdoDebugExt >= 20) + cdo_print("Stream-copy data record: %05d (timestep:%d); Var.id [%4d]; (code=%3d; ltype=%3d; level=%4d; " + "levelID=%3d)", + recID, tsID, varID, code, ltype, level, levelID); + cdo_copy_record(streamID2, streamID1); // cannot do this ! We have to set the flag uvGridRelative = 0 + } + else + { + recList[recID].varID = varID; + recList[recID].levelID = levelID; + if (cdoDebugExt >= 10) + cdo_print("Memmory-read data record: %05d (timestep:%d); Var.id [%4d]; (code=%3d; ltype=%3d; level=%4d; " + "levelID=%3d)", + recID, tsID, varID, code, ltype, level, levelID); + cdo_read_record(streamID1, vardata[varID][levelID].data(), &varnumMissVals[varID][levelID]); + if (varnumMissVals[varID][levelID]) cdo_abort("Missing values unsupported for this operator!"); + } + } // end of for ( recID = 0; recID < nrecs; .. - if (gridIDcurvl == -1) - { - if (cdoDebugExt) cdo_print("Building LAT-LON grid for the direction to the North. (First time only)."); - gridIDlastused = gridID; - // Compute 2D array with latlons only once. We expect that all horizontal grids for UV are same. - // NOTE: At this stage U and V cannot be staggered! - gridIDcurvl = gridToCurvilinear(gridID, NeedCorners::Yes); - if (cdoDebugExt) - cdo_print("Transformed rotated-latLon grid (id:%d) to curvilinear (id:%d) with true lat-lon " - "coordinates.", - gridID, gridIDcurvl); - // Grid definition with id: "gridIDcurvl" contains latlons of every gridpoint.. - // For details see: ./libcdi/src/cdi.h; Setgridtype to GRID_CURVILINEAR - - if (gridIDcurvl == -1) cdo_abort("Creation of curvilinear grid definition failed!"); - - if (gridInqType(gridIDcurvl) != GRID_CURVILINEAR) - { - gridDestroy(gridIDcurvl); - cdo_abort("Creation of curvilinear grid definition failed: type != GRID_CURVILINEAR"); - } - if (cdoDebugExt) - { - double xpole = 0, ypole = 0, angle = 0; - if (gridInqType(gridID) == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL) - gridInqParamRLL(gridID, &xpole, &ypole, &angle); - - cdo_print("GRID_PROJECTION(id: %d) && CDI_PROJ_RLL:", gridID); - cdo_print("grid Xsize %zu, grid Ysize %zu", gridInqXsize(gridID), gridInqYsize(gridID)); - cdo_print("grid Xfirst %4.3f, grid Yfirst %4.3f", gridInqXval(gridID, 0), gridInqYval(gridID, 0)); - cdo_print("grid Xinc %4.3f, grid Yinc %4.3f", gridInqXinc(gridID), gridInqYinc(gridID)); - cdo_print("grid Xpole %4.3f, grid Ypole %4.3f", xpole, ypole); - cdo_print("GRID_CURVILINEAR (id: %d):", gridIDcurvl); - cdo_print("grid Xsize %zu, grid Ysize %zu", gridInqXsize(gridIDcurvl), gridInqYsize(gridIDcurvl)); - cdo_print("grid Xfirst %4.3f, grid Yfirst %4.3f", gridInqXval(gridIDcurvl, 0), - gridInqYval(gridIDcurvl, 0)); - cdo_print("grid Xlast %4.3f, grid Ylast %4.3f", - gridInqXval(gridIDcurvl, gridInqSize(gridIDcurvl) - 1), - gridInqYval(gridIDcurvl, gridInqSize(gridIDcurvl) - 1)); - if (cdoDebugExt >= 20) - { - printf("Xvals (size=%zu):\n", gridInqSize(gridIDcurvl)); - size_t ii; - for (ii = 0; ii < 10; ++ii) printf("%4.3f ", gridInqXval(gridIDcurvl, ii)); - printf("\n...\n"); - for (ii = gridInqSize(gridIDcurvl) - 10; ii < gridInqSize(gridIDcurvl); ++ii) - printf("%4.3f ", gridInqXval(gridIDcurvl, ii)); - printf("\n"); - printf("Yvals (size=%zu):\n", gridInqSize(gridIDcurvl)); - for (ii = 0; ii < 10; ++ii) printf("%4.3f ", gridInqYval(gridIDcurvl, ii)); - printf("\n...\n"); - for (ii = gridInqSize(gridIDcurvl) - 10; ii < gridInqSize(gridIDcurvl); ++ii) - printf("%4.3f ", gridInqYval(gridIDcurvl, ii)); - printf("\n"); - } - } // end of if (cdoDebugExt) - Debug(cdoDebugExt, "LAT-LON grid created."); - } // end of if (gridIDcurvl==-1) - } // end of if (operatorID != ROTUVN) - - int uRelativeToGrid = -1, vRelativeToGrid = -1; - cdiInqKeyInt(vlistID1, varID1, CDI_KEY_UVRELATIVETOGRID, &uRelativeToGrid); - cdiInqKeyInt(vlistID1, varID2, CDI_KEY_UVRELATIVETOGRID, &vRelativeToGrid); - - if (uRelativeToGrid != 1) - { - cdo_warning("U component is NOT relative to grid. No transformation to north-pole takes place!"); - } - else if (vRelativeToGrid != 1) - { - cdo_warning("V component is NOT relative to grid. No transformation to north-pole takes place!"); - } - else - { - for (levelID = 0; levelID < nlevel1; ++levelID) - { - if (cdoDebugExt) - cdo_print("RotuvNorth(): processing level type: %d; level %d (out of [0:%d])", ltype1, levelID, - nlevel1 - 1); - auto usvar = vardata[usvarID][levelID].data(); - auto vsvar = vardata[vsvarID][levelID].data(); - if (operatorID == ROTUVNORTH) - { - rot_uv_north(gridIDcurvl, usvar, vsvar); - // rot_uv_north(gridIDlastused, usvar, vsvar); - // transform "in-place" the uv from grid relative into north-pole related - } - else if (operatorID == PROJUVLATLON) - project_uv_latlon(gridIDcurvl, usvar, vsvar); - else if (operatorID == ROTUVN) - rot_uv_back_mode64(gridID, usvar, vsvar); - } - } + Debug(cdoDebugExt, "All neccessary U & V data are in memory. About to transform the windvectors..."); - Debug(cdoDebugExt, "Finished processing level type: %d", ltype1); - break; - } // end for varID2 - } // end for varID1 + int code1, zaxisID1, ltype1; + int code2, zaxisID2, ltype2; + Debug(cdoDebugExt, "Looping over %d variables to look for U-wind..", nvars); - for (int recID = 0; recID < nrecs; ++recID) - { - varID = recList[recID].varID; - levelID = recList[recID].levelID; - if (varID != -1) + // find u-variables: + for (varID1 = 0; varID1 < nvars; ++varID1) + if (vardata[varID1].empty()) { - code = varList1[varID].code; - zaxisID = varList1[varID].zaxisID; - ltype = zaxis_to_ltype(zaxisID); - level = zaxisInqLevel(zaxisID, levelID); - if (cdoDebugExt >= 10) - cdo_print("Write modified data record: %05d (timestep:%d); Var.id [%4d]; (code=%3d; ltype=%3d; level=%4d; " - "levelID=%3d)", - recID, tsID, varID, code, ltype, level, levelID); - - cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, vardata[varID][levelID].data(), varnmiss[varID][levelID]); + // if ( cdoDebugExt ) cdo_print("Checking U-wind: vardata[%d]== nullptr ",varID1); } - } + else // This means that it is U or V. + { + code1 = varList2[varID1].code; + zaxisID1 = varList2[varID1].zaxisID; + ltype1 = zaxis_to_ltype(zaxisID1); + nlevel1 = zaxisInqSize(zaxisID1); + CheckVarIsV(varID1, varList2[varID1].name, code1); + if (VarIsV) continue; + if (cdoDebugExt >= 20) + cdo_print("Checking U-wind: Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of levels: %3d; " + "zaxisID: %d", + varID1, code1, varList2[varID1].name, ltype1, nlevel1, zaxisID1); + CheckVarIsU(varID1, varList2[varID1].name, code1); + if (!VarIsU) continue; + if (cdoDebugExt >= 10) + cdo_print("** FOUND U-wind; Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of levels: %3d; " + "zaxisID: %d", + varID1, code1, varList2[varID1].name, ltype1, nlevel1, zaxisID1); + auto usvarID = varID1; + // find corresponding v-variable to u-variable: + for (varID2 = 0; varID2 < nvars; ++varID2) + if (vardata[varID2].empty()) + { + // if ( cdoDebugExt ) cdo_print("Checking V-wind: vardata[%d]== nullptr ",varID1); + } + else // This means that it is U or V. + { + code2 = varList2[varID2].code; + zaxisID2 = varList2[varID2].zaxisID; + ltype2 = zaxis_to_ltype(zaxisID2); + nlevel2 = zaxisInqSize(zaxisID2); + CheckVarIsU(varID2, varList2[varID2].name, code2); + if (VarIsU) continue; + if (cdoDebugExt >= 20) + cdo_print("Checking V-wind: Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of " + "levels: %3d; zaxisID: %d", + varID2, code2, varList2[varID2].name, ltype2, nlevel2, zaxisID2); + CheckVarIsV(varID2, varList2[varID2].name, code2); + if (!VarIsV) continue; + if (!((ltype1 == ltype2) && (nlevel1 == nlevel2) && (zaxisID1 == zaxisID2))) continue; + if (cdoDebugExt >= 10) + cdo_print("** FOUND V-wind; Var.id [%4d] with grib code:%3d; name: %6s; level type: %3d; number of " + "levels: %3d; zaxisID: %d", + varID2, code2, varList2[varID2].name, ltype1, nlevel2, zaxisID2); + auto vsvarID = varID2; + if (cdoDebugExt >= 20) + cdo_print("Using code %d [%d](u) and code %d [%d](v)", varList1[varID1].code, code1, varList1[varID2].code, + code2); + gridID = varList1[varID1].gridID; + if (operatorID != ROTUVN) // ROTUVN operator does not need creation of gridIDcurvl ... + { + if ((gridIDcurvl != -1) && (gridIDlastused != gridID)) + cdo_abort("The gridID (%d) used just previously for uv-wind tranformation is not same this " + "time(%d)!", + gridIDlastused, gridID); + + if (gridIDcurvl == -1) + { + if (cdoDebugExt) cdo_print("Building LAT-LON grid for the direction to the North. (First time only)."); + gridIDlastused = gridID; + // Compute 2D array with latlons only once. We expect that all horizontal grids for UV are same. + // NOTE: At this stage U and V cannot be staggered! + gridIDcurvl = gridToCurvilinear(gridID, NeedCorners::Yes); + if (cdoDebugExt) + cdo_print("Transformed rotated-latLon grid (id:%d) to curvilinear (id:%d) with true lat-lon " + "coordinates.", + gridID, gridIDcurvl); + // Grid definition with id: "gridIDcurvl" contains latlons of every gridpoint.. + // For details see: ./libcdi/src/cdi.h; Setgridtype to GRID_CURVILINEAR + + if (gridIDcurvl == -1) cdo_abort("Creation of curvilinear grid definition failed!"); + + if (gridInqType(gridIDcurvl) != GRID_CURVILINEAR) + { + gridDestroy(gridIDcurvl); + cdo_abort("Creation of curvilinear grid definition failed: type != GRID_CURVILINEAR"); + } + if (cdoDebugExt) + { + double xpole = 0, ypole = 0, angle = 0; + if (gridInqType(gridID) == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL) + gridInqParamRLL(gridID, &xpole, &ypole, &angle); + + cdo_print("GRID_PROJECTION(id: %d) && CDI_PROJ_RLL:", gridID); + cdo_print("grid Xsize %zu, grid Ysize %zu", gridInqXsize(gridID), gridInqYsize(gridID)); + cdo_print("grid Xfirst %4.3f, grid Yfirst %4.3f", gridInqXval(gridID, 0), gridInqYval(gridID, 0)); + cdo_print("grid Xinc %4.3f, grid Yinc %4.3f", gridInqXinc(gridID), gridInqYinc(gridID)); + cdo_print("grid Xpole %4.3f, grid Ypole %4.3f", xpole, ypole); + cdo_print("GRID_CURVILINEAR (id: %d):", gridIDcurvl); + cdo_print("grid Xsize %zu, grid Ysize %zu", gridInqXsize(gridIDcurvl), + gridInqYsize(gridIDcurvl)); + cdo_print("grid Xfirst %4.3f, grid Yfirst %4.3f", gridInqXval(gridIDcurvl, 0), + gridInqYval(gridIDcurvl, 0)); + cdo_print("grid Xlast %4.3f, grid Ylast %4.3f", + gridInqXval(gridIDcurvl, gridInqSize(gridIDcurvl) - 1), + gridInqYval(gridIDcurvl, gridInqSize(gridIDcurvl) - 1)); + if (cdoDebugExt >= 20) + { + printf("Xvals (size=%zu):\n", gridInqSize(gridIDcurvl)); + size_t ii; + for (ii = 0; ii < 10; ++ii) printf("%4.3f ", gridInqXval(gridIDcurvl, ii)); + printf("\n...\n"); + for (ii = gridInqSize(gridIDcurvl) - 10; ii < gridInqSize(gridIDcurvl); ++ii) + printf("%4.3f ", gridInqXval(gridIDcurvl, ii)); + printf("\n"); + printf("Yvals (size=%zu):\n", gridInqSize(gridIDcurvl)); + for (ii = 0; ii < 10; ++ii) printf("%4.3f ", gridInqYval(gridIDcurvl, ii)); + printf("\n...\n"); + for (ii = gridInqSize(gridIDcurvl) - 10; ii < gridInqSize(gridIDcurvl); ++ii) + printf("%4.3f ", gridInqYval(gridIDcurvl, ii)); + printf("\n"); + } + } // end of if (cdoDebugExt) + Debug(cdoDebugExt, "LAT-LON grid created."); + } // end of if (gridIDcurvl==-1) + } // end of if (operatorID != ROTUVN) + + int uRelativeToGrid = -1, vRelativeToGrid = -1; + cdiInqKeyInt(vlistID1, varID1, CDI_KEY_UVRELATIVETOGRID, &uRelativeToGrid); + cdiInqKeyInt(vlistID1, varID2, CDI_KEY_UVRELATIVETOGRID, &vRelativeToGrid); + + if (uRelativeToGrid != 1) + { + cdo_warning("U component is NOT relative to grid. No transformation to north-pole takes place!"); + } + else if (vRelativeToGrid != 1) + { + cdo_warning("V component is NOT relative to grid. No transformation to north-pole takes place!"); + } + else + { + for (levelID = 0; levelID < nlevel1; ++levelID) + { + if (cdoDebugExt) + cdo_print("RotuvNorth(): processing level type: %d; level %d (out of [0:%d])", ltype1, levelID, + nlevel1 - 1); + auto usvar = vardata[usvarID][levelID].data(); + auto vsvar = vardata[vsvarID][levelID].data(); + if (operatorID == ROTUVNORTH) + { + rot_uv_north(gridIDcurvl, usvar, vsvar); + // rot_uv_north(gridIDlastused, usvar, vsvar); + // transform "in-place" the uv from grid relative into north-pole related + } + else if (operatorID == PROJUVLATLON) + project_uv_latlon(gridIDcurvl, usvar, vsvar); + else if (operatorID == ROTUVN) + rot_uv_back_mode64(gridID, usvar, vsvar); + } + } + + Debug(cdoDebugExt, "Finished processing level type: %d", ltype1); + break; + } // end for varID2 + } // end for varID1 + + for (int recID = 0; recID < nrecs; ++recID) + { + varID = recList[recID].varID; + levelID = recList[recID].levelID; + if (varID != -1) + { + code = varList1[varID].code; + zaxisID = varList1[varID].zaxisID; + ltype = zaxis_to_ltype(zaxisID); + level = zaxisInqLevel(zaxisID, levelID); + if (cdoDebugExt >= 10) + cdo_print("Write modified data record: %05d (timestep:%d); Var.id [%4d]; (code=%3d; ltype=%3d; level=%4d; " + "levelID=%3d)", + recID, tsID, varID, code, ltype, level, levelID); + + cdo_def_record(streamID2, varID, levelID); + cdo_write_record(streamID2, vardata[varID][levelID].data(), varnumMissVals[varID][levelID]); + } + } - tsID++; - } // end of while (true) + tsID++; + } // end of while (true) - cdo_stream_close(streamID2); - cdo_stream_close(streamID1); + cdo_stream_close(streamID2); + cdo_stream_close(streamID1); - if (gridIDcurvl != -1) gridDestroy(gridIDcurvl); // at the end must Free the allocated curvilinear grid definition... + if (gridIDcurvl != -1) gridDestroy(gridIDcurvl); // at the end must Free the allocated curvilinear grid definition... - cdo_finish(); + return 0; + } - return 0; -} public: void - init(void *process) + init() { - cdo_initialize(process); // clang-format off - UVDESTAG = cdo_operator_add("uvDestag", 0, 0, nullptr); - ROTUVNORTH = cdo_operator_add("rotuvNorth", 0, 0, nullptr); - ROTUVN = cdo_operator_add("rotuvN", 0, 0, nullptr); +UVDESTAG = module.get_id("uvDestag"); +ROTUVNORTH = module.get_id("rotuvNorth"); +ROTUVN = module.get_id("rotuvN"); // Cylindrical Equidistant projection - PROJUVLATLON = cdo_operator_add("projuvLatLon", 0, 0, nullptr); +PROJUVLATLON = module.get_id("projuvLatLon"); // clang-format on operatorID = cdo_operator_id(); @@ -1530,14 +1541,3 @@ public: // TODO: split the TransformUV and DestaggerUV into seperate classes and fix their close } }; - -void * -WindTrans(void *process) -{ - ModuleWindtrans windtrans; - windtrans.init(process); - windtrans.run(); - windtrans.close(); - - return nullptr; -} diff --git a/src/Writegrid.cc b/src/Writegrid.cc index cf3d073dc623e7a79a3c71093e994d2ad28c981c..0d83790d28a312ea67495eb23f5e8f0659adbe3a 100644 --- a/src/Writegrid.cc +++ b/src/Writegrid.cc @@ -17,18 +17,27 @@ #include <mpim_grid.h> #include "griddes.h" -class ModuleWriteGrid +class Writegrid : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Writegrid", + .operators = { { "writegrid"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Writegrid> registration = RegisterEntry<Writegrid>(module); CdoStreamID streamID; int gridID; std::vector<int> mask; - public: void - init(void *process) + init() { - cdo_initialize(process); operator_check_argc(0); @@ -43,7 +52,7 @@ public: if (!gridHasCoordinates(gridID)) cdo_abort("Cell corner coordinates missing!"); - mask =std::vector<int>(gridsize); + mask = std::vector<int>(gridsize); if (gridInqMask(gridID, nullptr)) { gridInqMask(gridID, mask.data()); } else @@ -62,16 +71,3 @@ public: cdo_stream_close(streamID); } }; - -void * -Writegrid(void *process) -{ - - ModuleWriteGrid writegrid; - writegrid.init(process); - writegrid.run(); - writegrid.close(); - cdo_finish(); - - return nullptr; -} diff --git a/src/Writerandom.cc b/src/Writerandom.cc index 54ab34effe558fec0474ced3438326cf9512b67b..69dd2e21930726662afafe64665741164ade4cde 100644 --- a/src/Writerandom.cc +++ b/src/Writerandom.cc @@ -16,8 +16,19 @@ #include "process_int.h" -class ModuleWriteRandom +class Writerandom : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Writerandom", + .operators = { { "writerandom"} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Writerandom> registration = RegisterEntry<Writerandom>(module); CdoStreamID streamID1; CdoStreamID streamID2; @@ -28,11 +39,9 @@ class ModuleWriteRandom public: void - init(void *process) + init() { - cdo_initialize(process); - operator_check_argc(0); streamID1 = cdo_open_read(0); @@ -64,7 +73,7 @@ public: Varray2D<double> recdata(nrecs); std::vector<int> recvarID(nrecs), reclevelID(nrecs), recindex(nrecs); - std::vector<size_t> recnmiss(nrecs); + std::vector<size_t> recnumMissVals(nrecs); for (int recID = 0; recID < nrecs; ++recID) { @@ -73,7 +82,7 @@ public: recvarID[recID] = varID; reclevelID[recID] = levelID; recdata[recID].resize(varList1[varID].gridsize); - cdo_read_record(streamID1, recdata[recID].data(), &recnmiss[recID]); + cdo_read_record(streamID1, recdata[recID].data(), &recnumMissVals[recID]); } for (int recID = 0; recID < nrecs; ++recID) recindex[recID] = -1; @@ -105,7 +114,7 @@ public: const auto varID = recvarID[rindex]; const auto levelID = reclevelID[rindex]; cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, recdata[rindex].data(), recnmiss[rindex]); + cdo_write_record(streamID2, recdata[rindex].data(), recnumMissVals[rindex]); } tsID++; @@ -116,18 +125,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Writerandom(void *process) -{ - ModuleWriteRandom writerandom; - writerandom.init(process); - writerandom.run(); - writerandom.close(); - - return nullptr; -} diff --git a/src/XTimstat.cc b/src/XTimstat.cc index 966d83f6116245d6c52f0181d42e0b601118966b..b8f7b5996914cc088b1c0d14f92c050ce2975e5e 100644 --- a/src/XTimstat.cc +++ b/src/XTimstat.cc @@ -69,7 +69,7 @@ #include "param_conversion.h" #include "field_functions.h" -#define USE_CDI_STREAM 1 +#define USE_CDI_STREAM 0 struct ReadArguments { @@ -113,20 +113,20 @@ cdoReadTimestep(void *rarg) recList[recID].levelID = levelID; } - size_t nmiss; + size_t numMissVals; #ifdef USE_CDI_STREAM if (Options::CDO_Memtype == MemType::Float) - streamReadRecordF(streamID, input_vars[varID][levelID].vec_f.data(), &nmiss); + streamReadRecordF(streamID, input_vars[varID][levelID].vec_f.data(), &numMissVals); else - streamReadRecord(streamID, input_vars[varID][levelID].vec_d.data(), &nmiss); + streamReadRecord(streamID, input_vars[varID][levelID].vec_d.data(), &numMissVals); #else if (Options::CDO_Memtype == MemType::Float) - cdo_read_record_f(streamID, input_vars[varID][levelID].vec_f.data(), &nmiss); + cdo_read_record_f(streamID, input_vars[varID][levelID].vec_f.data(), &numMissVals); else - cdo_read_record(streamID, input_vars[varID][levelID].vec_d.data(), &nmiss); + cdo_read_record(streamID, input_vars[varID][levelID].vec_d.data(), &numMissVals); #endif - input_vars[varID][levelID].nmiss = nmiss; + input_vars[varID][levelID].numMissVals = numMissVals; } #ifdef USE_CDI_STREAM @@ -150,273 +150,317 @@ vlistSetFrequency(int vlistID, int compareDate) if (freq) cdiDefAttTxt(vlistID, CDI_GLOBAL, "frequency", (int) strlen(freq), freq); } -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("xtimmin", FieldFunc_Min, CMP_DATE, nullptr); - cdo_operator_add("xtimmax", FieldFunc_Max, CMP_DATE, nullptr); - cdo_operator_add("xtimsum", FieldFunc_Sum, CMP_DATE, nullptr); - cdo_operator_add("xtimmean", FieldFunc_Mean, CMP_DATE, nullptr); - cdo_operator_add("xtimavg", FieldFunc_Avg, CMP_DATE, nullptr); - cdo_operator_add("xtimvar", FieldFunc_Var, CMP_DATE, nullptr); - cdo_operator_add("xtimvar1", FieldFunc_Var1, CMP_DATE, nullptr); - cdo_operator_add("xtimstd", FieldFunc_Std, CMP_DATE, nullptr); - cdo_operator_add("xtimstd1", FieldFunc_Std1, CMP_DATE, nullptr); - cdo_operator_add("xyearmin", FieldFunc_Min, CMP_YEAR, nullptr); - cdo_operator_add("xyearmax", FieldFunc_Max, CMP_YEAR, nullptr); - cdo_operator_add("xyearsum", FieldFunc_Sum, CMP_YEAR, nullptr); - cdo_operator_add("xyearmean", FieldFunc_Mean, CMP_YEAR, nullptr); - cdo_operator_add("xyearavg", FieldFunc_Avg, CMP_YEAR, nullptr); - cdo_operator_add("xyearvar", FieldFunc_Var, CMP_YEAR, nullptr); - cdo_operator_add("xyearvar1", FieldFunc_Var1, CMP_YEAR, nullptr); - cdo_operator_add("xyearstd", FieldFunc_Std, CMP_YEAR, nullptr); - cdo_operator_add("xyearstd1", FieldFunc_Std1, CMP_YEAR, nullptr); - cdo_operator_add("xmonmin", FieldFunc_Min, CMP_MONTH, nullptr); - cdo_operator_add("xmonmax", FieldFunc_Max, CMP_MONTH, nullptr); - cdo_operator_add("xmonsum", FieldFunc_Sum, CMP_MONTH, nullptr); - cdo_operator_add("xmonmean", FieldFunc_Mean, CMP_MONTH, nullptr); - cdo_operator_add("xmonavg", FieldFunc_Avg, CMP_MONTH, nullptr); - cdo_operator_add("xmonvar", FieldFunc_Var, CMP_MONTH, nullptr); - cdo_operator_add("xmonvar1", FieldFunc_Var1, CMP_MONTH, nullptr); - cdo_operator_add("xmonstd", FieldFunc_Std, CMP_MONTH, nullptr); - cdo_operator_add("xmonstd1", FieldFunc_Std1, CMP_MONTH, nullptr); - // clang-format on -} - -void * -XTimstat(void *process) +class XTimstat : public Process { - constexpr auto timestatDate{ TimeStat::MEAN }; + TimeStat timestatDate{ TimeStat::MEAN }; CdiDateTime vDateTime0{}; CdiDateTime vDateTimeN{}; CdoStreamID streamID3 = CDO_STREAM_UNDEF; - int vlistID3, taxisID3 = -1; bool lvfrac = false; double vfrac = 1; - cdo_initialize(process); + int tsID = 0; + int otsID = 0; + int nrecs; + + int compareDate; - addOperators(); +#ifdef USE_CDI_STREAM + int streamID1; +#else + CdoStreamID streamID1; +#endif + CdoStreamID streamID2; - auto operatorID = cdo_operator_id(); - auto operfunc = cdo_operator_f1(operatorID); - auto compareDate = cdo_operator_f2(operatorID); + int vlistID1; + int vlistID3; - auto lmean = (operfunc == FieldFunc_Mean || operfunc == FieldFunc_Avg); - auto lstd = (operfunc == FieldFunc_Std || operfunc == FieldFunc_Std1); - auto lvarstd = (lstd || operfunc == FieldFunc_Var || operfunc == FieldFunc_Var1); - auto lvars2 = lvarstd; - int divisor = (operfunc == FieldFunc_Std1 || operfunc == FieldFunc_Var1); + int taxisID1; + int taxisID2; + int taxisID3 = -1; - auto field2_stdvar_func = lstd ? field2_std : field2_var; - auto fieldc_stdvar_func = lstd ? fieldc_std : fieldc_var; + DateTimeList dtlist; + std::vector<RecordInfo> recList; + FieldVector3D input_vars = FieldVector3D(2); - if (operfunc == FieldFunc_Mean) - { - auto oargc = cdo_operator_argc(); - if (oargc == 1) - { - lvfrac = true; - vfrac = parameter_to_double(cdo_operator_argv(0)); - if (Options::cdoVerbose) cdo_print("Set vfrac to %g", vfrac); - if (vfrac < 0 || vfrac > 1) cdo_abort("vfrac out of range!"); - } - else if (oargc > 1) - cdo_abort("Too many arguments!"); - } - else { operator_check_argc(0); } + int curFirst = 0; + //int curSecond = 1; + + bool lparallelread = false; + bool ltsfirst = true; + cdo::Task *read_task = nullptr; + void *readresult = nullptr; + + int maxrecs = 0; + FieldVector2D samp1, vars1, vars2; + + int operatorID; + int operfunc; + + int lmean, lstd, lvarstd, lvars2, divisor; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "XTimstat", + .operators = { { "xtimmin", FieldFunc_Min, CMP_DATE, nullptr}, { "xtimmax", FieldFunc_Max, CMP_DATE, nullptr}, + { "xtimsum", FieldFunc_Sum, CMP_DATE, nullptr}, { "xtimmean", FieldFunc_Mean, CMP_DATE, nullptr}, + { "xtimavg", FieldFunc_Avg, CMP_DATE, nullptr}, { "xtimvar", FieldFunc_Var, CMP_DATE, nullptr}, + { "xtimvar1", FieldFunc_Var1, CMP_DATE, nullptr}, { "xtimstd", FieldFunc_Std, CMP_DATE, nullptr}, + { "xtimstd1", FieldFunc_Std1, CMP_DATE, nullptr}, { "xyearmin", FieldFunc_Min, CMP_YEAR, nullptr}, + { "xyearmax", FieldFunc_Max, CMP_YEAR, nullptr}, { "xyearsum", FieldFunc_Sum, CMP_YEAR, nullptr}, + { "xyearmean", FieldFunc_Mean, CMP_YEAR, nullptr}, { "xyearavg", FieldFunc_Avg, CMP_YEAR, nullptr}, + { "xyearvar", FieldFunc_Var, CMP_YEAR, nullptr}, { "xyearvar1", FieldFunc_Var1, CMP_YEAR, nullptr}, + { "xyearstd", FieldFunc_Std, CMP_YEAR, nullptr}, { "xyearstd1", FieldFunc_Std1, CMP_YEAR, nullptr}, + { "xmonmin", FieldFunc_Min, CMP_MONTH, nullptr}, { "xmonmax", FieldFunc_Max, CMP_MONTH, nullptr}, + { "xmonsum", FieldFunc_Sum, CMP_MONTH, nullptr}, { "xmonmean", FieldFunc_Mean, CMP_MONTH, nullptr}, + { "xmonavg", FieldFunc_Avg, CMP_MONTH, nullptr}, { "xmonvar", FieldFunc_Var, CMP_MONTH, nullptr}, + { "xmonvar1", FieldFunc_Var1, CMP_MONTH, nullptr}, { "xmonstd", FieldFunc_Std, CMP_MONTH, nullptr}, + { "xmonstd1", FieldFunc_Std1, CMP_MONTH, nullptr} }, + .aliases = {}, + .mode = INTERNAL, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<XTimstat> registration = RegisterEntry<XTimstat>(module); + + void + init() + { + operatorID = cdo_operator_id(); + operfunc = cdo_operator_f1(operatorID); + compareDate = cdo_operator_f2(operatorID); + + lmean = (operfunc == FieldFunc_Mean || operfunc == FieldFunc_Avg); + lstd = (operfunc == FieldFunc_Std || operfunc == FieldFunc_Std1); + lvarstd = (lstd || operfunc == FieldFunc_Var || operfunc == FieldFunc_Var1); + lvars2 = lvarstd; + divisor = (operfunc == FieldFunc_Std1 || operfunc == FieldFunc_Var1); + + if (operfunc == FieldFunc_Mean) + { + auto oargc = cdo_operator_argc(); + if (oargc == 1) + { + lvfrac = true; + vfrac = parameter_to_double(cdo_operator_argv(0)); + if (Options::cdoVerbose) cdo_print("Set vfrac to %g", vfrac); + if (vfrac < 0 || vfrac > 1) cdo_abort("vfrac out of range!"); + } + else if (oargc > 1) + cdo_abort("Too many arguments!"); + } + else { operator_check_argc(0); } #ifdef USE_CDI_STREAM - auto streamID1 = streamOpenRead(cdo_get_stream_name(0)); - auto vlistID1 = streamInqVlist(streamID1); + streamID1 = streamOpenRead(cdo_get_stream_name(0)); + vlistID1 = streamInqVlist(streamID1); #else - auto streamID1 = cdo_open_read(0); - auto vlistID1 = cdo_stream_inq_vlist(streamID1); + streamID1 = cdo_open_read(0); + vlistID1 = cdo_stream_inq_vlist(streamID1); #endif - auto vlistID2 = vlistDuplicate(vlistID1); - vlist_define_timestep_type(vlistID2, operfunc); + auto vlistID2 = vlistDuplicate(vlistID1); + vlist_define_timestep_type(vlistID2, operfunc); - vlistDefNtsteps(vlistID2, (compareDate == CMP_DATE) ? 1 : -1); + vlistDefNtsteps(vlistID2, (compareDate == CMP_DATE) ? 1 : -1); - auto taxisID1 = vlistInqTaxis(vlistID1); - auto taxisID2 = taxisDuplicate(taxisID1); - taxisWithBounds(taxisID2); - if (taxisInqType(taxisID2) == TAXIS_FORECAST) taxisDefType(taxisID2, TAXIS_RELATIVE); - vlistDefTaxis(vlistID2, taxisID2); + taxisID1 = vlistInqTaxis(vlistID1); + taxisID2 = taxisDuplicate(taxisID1); + taxisWithBounds(taxisID2); + if (taxisInqType(taxisID2) == TAXIS_FORECAST) taxisDefType(taxisID2, TAXIS_RELATIVE); + vlistDefTaxis(vlistID2, taxisID2); - auto nvars = vlistNvars(vlistID1); + auto nvars = vlistNvars(vlistID1); - vlistSetFrequency(vlistID2, compareDate); + vlistSetFrequency(vlistID2, compareDate); - auto streamID2 = cdo_open_write(1); - cdo_def_vlist(streamID2, vlistID2); + streamID2 = cdo_open_write(1); + cdo_def_vlist(streamID2, vlistID2); - if (Options::cdoDiag) - { - char filename[8192]; - std::strcpy(filename, cdo_operator_name(operatorID)); - strcat(filename, "_"); - strcat(filename, cdo_get_stream_name(1)); - streamID3 = cdo_open_write(filename); + if (Options::cdoDiag) + { + char filename[8192]; + std::strcpy(filename, cdo_operator_name(operatorID)); + strcat(filename, "_"); + strcat(filename, cdo_get_stream_name(1)); + streamID3 = cdo_open_write(filename); - vlistID3 = vlistDuplicate(vlistID1); + vlistID3 = vlistDuplicate(vlistID1); - for (int varID = 0; varID < nvars; ++varID) - { - vlistDefVarDatatype(vlistID3, varID, CDI_DATATYPE_INT32); - vlistDefVarMissval(vlistID3, varID, -1); - cdiDefKeyString(vlistID3, varID, CDI_KEY_UNITS, ""); - cdiDeleteKey(vlistID3, varID, CDI_KEY_ADDOFFSET); - cdiDeleteKey(vlistID3, varID, CDI_KEY_SCALEFACTOR); - } + for (int varID = 0; varID < nvars; ++varID) + { + vlistDefVarDatatype(vlistID3, varID, CDI_DATATYPE_INT32); + vlistDefVarMissval(vlistID3, varID, -1); + cdiDefKeyString(vlistID3, varID, CDI_KEY_UNITS, ""); + cdiDeleteKey(vlistID3, varID, CDI_KEY_ADDOFFSET); + cdiDeleteKey(vlistID3, varID, CDI_KEY_SCALEFACTOR); + } - taxisID3 = taxisDuplicate(taxisID1); - taxisWithBounds(taxisID3); - vlistDefTaxis(vlistID3, taxisID3); + taxisID3 = taxisDuplicate(taxisID1); + taxisWithBounds(taxisID3); + vlistDefTaxis(vlistID3, taxisID3); - cdo_def_vlist(streamID3, vlistID3); - } + cdo_def_vlist(streamID3, vlistID3); + } - DateTimeList dtlist; - dtlist.set_stat(timestatDate); - dtlist.set_calendar(taxisInqCalendar(taxisID1)); - - int FIELD_MEMTYPE = 0; - if (operfunc == FieldFunc_Mean && Options::CDO_Memtype == MemType::Float) FIELD_MEMTYPE = FIELD_FLT; - FieldVector3D input_vars(2); - fields_from_vlist(vlistID1, input_vars[0], FIELD_VEC | FIELD_MEMTYPE); - fields_from_vlist(vlistID1, input_vars[1], FIELD_VEC | FIELD_MEMTYPE); - FieldVector2D samp1, vars1, vars2; - fields_from_vlist(vlistID1, samp1); - fields_from_vlist(vlistID1, vars1, FIELD_VEC); - if (lvars2) fields_from_vlist(vlistID1, vars2, FIELD_VEC); + dtlist.set_stat(timestatDate); + dtlist.set_calendar(taxisInqCalendar(taxisID1)); - int curFirst = 0; - int curSecond = 1; - (void) curSecond; + int FIELD_MEMTYPE = 0; + if (operfunc == FieldFunc_Mean && Options::CDO_Memtype == MemType::Float) FIELD_MEMTYPE = FIELD_FLT; + fields_from_vlist(vlistID1, input_vars[0], FIELD_VEC | FIELD_MEMTYPE); + fields_from_vlist(vlistID1, input_vars[1], FIELD_VEC | FIELD_MEMTYPE); - ReadArguments readarg(input_vars[curFirst]); - readarg.streamID = streamID1; + fields_from_vlist(vlistID1, samp1); + fields_from_vlist(vlistID1, vars1, FIELD_VEC); + if (lvars2) fields_from_vlist(vlistID1, vars2, FIELD_VEC); - bool lparallelread = Options::CDO_Parallel_Read > 0; - bool ltsfirst = true; - cdo::Task *read_task = nullptr; - void *readresult = nullptr; + lparallelread = (Options::CDO_Parallel_Read > 0); + if (lparallelread) read_task = new cdo::Task; - if (lparallelread) read_task = new cdo::Task; - - int tsID = 0; - int otsID = 0; #ifdef USE_CDI_STREAM - auto nrecs = streamInqTimestep(streamID1, tsID); + nrecs = streamInqTimestep(streamID1, tsID); #else - auto nrecs = cdo_stream_inq_timestep(streamID1, tsID); + nrecs = cdo_stream_inq_timestep(streamID1, tsID); #endif - int maxrecs = nrecs; - std::vector<RecordInfo> recList(maxrecs); - tsID++; - while (true) - { - int numSets = 0; - while (nrecs > 0) - { - dtlist.taxis_inq_timestep(taxisID1, numSets); - auto vDateTime = dtlist.get_vDateTime(numSets); + maxrecs = nrecs; + recList = std::vector<RecordInfo>(maxrecs); + } - if (numSets == 0) vDateTime0 = vDateTime; + void + run() + { + auto field2_stdvar_func = lstd ? field2_std : field2_var; + auto fieldc_stdvar_func = lstd ? fieldc_std : fieldc_var; - if (date_is_neq(vDateTime, vDateTime0, compareDate)) - { - cdo_add_steps(-1); - break; - } + tsID++; - readarg.tsIDnext = tsID; - readarg.nrecs = nrecs; - readarg.recList = recList.data(); - readarg.vars = input_vars[curFirst]; + ReadArguments readarg(input_vars[curFirst]); + readarg.streamID = streamID1; - if (ltsfirst || !lparallelread) - { - ltsfirst = false; - readresult = cdoReadTimestep(&readarg); - } - else { readresult = read_task->wait(); } + while (true) + { + int numSets = 0; + while (nrecs > 0) + { + dtlist.taxis_inq_timestep(taxisID1, numSets); + auto vDateTime = dtlist.get_vDateTime(numSets); - nrecs = *(int *) readresult; + if (numSets == 0) vDateTime0 = vDateTime; - // std::swap(curFirst, curSecond); + if (date_is_neq(vDateTime, vDateTime0, compareDate)) + { + cdo_add_steps(-1); + break; + } - if (nrecs && lparallelread) - { - readarg.vars = input_vars[curFirst]; - readarg.tsIDnext = tsID + 1; - read_task->start(cdoReadTimestep, &readarg); - } + readarg.tsIDnext = tsID; + readarg.nrecs = nrecs; + readarg.recList = recList.data(); + readarg.vars = input_vars[curFirst]; - if (numSets == 0) - { + if (ltsfirst || !lparallelread) + { + ltsfirst = false; + readresult = cdoReadTimestep(&readarg); + } + else { readresult = read_task->wait(); } + + nrecs = *(int *) readresult; + + // std::swap(curFirst, curSecond); + + if (nrecs && lparallelread) + { + readarg.vars = input_vars[curFirst]; + readarg.tsIDnext = tsID + 1; + read_task->start(cdoReadTimestep, &readarg); + } + + if (numSets == 0) + { #ifdef _OPENMP #pragma omp parallel for default(shared) if (maxrecs > 1) #endif - for (int recID = 0; recID < maxrecs; ++recID) - { - auto varID = recList[recID].varID; - auto levelID = recList[recID].levelID; + for (int recID = 0; recID < maxrecs; ++recID) + { + auto varID = recList[recID].varID; + auto levelID = recList[recID].levelID; - auto &rsamp1 = samp1[varID][levelID]; - auto &rvars1 = vars1[varID][levelID]; - auto &rinput_var = input_vars[curFirst][varID][levelID]; + auto &rsamp1 = samp1[varID][levelID]; + auto &rvars1 = vars1[varID][levelID]; + auto &rinput_var = input_vars[curFirst][varID][levelID]; - auto nmiss = rinput_var.nmiss; + auto numMissVals = rinput_var.numMissVals; - field_copy(rinput_var, rvars1); - rvars1.nmiss = nmiss; - if (nmiss || !rsamp1.empty()) - { - auto fieldsize = rvars1.size; - if (rsamp1.empty()) rsamp1.resize(fieldsize); + field_copy(rinput_var, rvars1); + rvars1.numMissVals = numMissVals; + if (numMissVals || !rsamp1.empty()) + { + auto fieldsize = rvars1.size; + if (rsamp1.empty()) rsamp1.resize(fieldsize); - for (size_t i = 0; i < fieldsize; ++i) rsamp1.vec_d[i] = !DBL_IS_EQUAL(rvars1.vec_d[i], rvars1.missval); - } - } - } - else - { + for (size_t i = 0; i < fieldsize; ++i) rsamp1.vec_d[i] = !DBL_IS_EQUAL(rvars1.vec_d[i], rvars1.missval); + } + } + } + else + { #ifdef _OPENMP #pragma omp parallel for default(shared) if (maxrecs > 1) #endif + for (int recID = 0; recID < maxrecs; ++recID) + { + auto varID = recList[recID].varID; + auto levelID = recList[recID].levelID; + + auto &rsamp1 = samp1[varID][levelID]; + auto &rvars1 = vars1[varID][levelID]; + auto &rinput_var = input_vars[curFirst][varID][levelID]; + + auto numMissVals = rinput_var.numMissVals; + + if (numMissVals || !rsamp1.empty()) + { + auto fieldsize = rvars1.size; + if (rsamp1.empty()) rsamp1.resize(fieldsize, numSets); + + for (size_t i = 0; i < fieldsize; ++i) + if (!DBL_IS_EQUAL(rinput_var.vec_d[i], rvars1.missval)) rsamp1.vec_d[i]++; + } + + // clang-format off + if (lvarstd) field2_sumsumq(rvars1, vars2[varID][levelID], rinput_var); + else field2_function(rvars1, rinput_var, operfunc); + // clang-format on + } + } + + if (numSets == 0 && lvarstd) for (int recID = 0; recID < maxrecs; ++recID) { auto varID = recList[recID].varID; auto levelID = recList[recID].levelID; - auto &rsamp1 = samp1[varID][levelID]; - auto &rvars1 = vars1[varID][levelID]; - auto &rinput_var = input_vars[curFirst][varID][levelID]; - - auto nmiss = rinput_var.nmiss; + if (vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; - if (nmiss || !rsamp1.empty()) - { - auto fieldsize = rvars1.size; - if (rsamp1.empty()) rsamp1.resize(fieldsize, numSets); + field2_moq(vars2[varID][levelID], vars1[varID][levelID]); + } - for (size_t i = 0; i < fieldsize; ++i) - if (!DBL_IS_EQUAL(rinput_var.vec_d[i], rvars1.missval)) rsamp1.vec_d[i]++; - } + vDateTimeN = vDateTime; + numSets++; + tsID++; + } - // clang-format off - if (lvarstd) field2_sumsumq(rvars1, vars2[varID][levelID], rinput_var); - else field2_function(rvars1, rinput_var, operfunc); - // clang-format on - } - } + if (nrecs == 0 && numSets == 0) break; - if (numSets == 0 && lvarstd) + if (lmean) + { +#ifdef _OPENMP +#pragma omp parallel for default(shared) if (maxrecs > 1) +#endif for (int recID = 0; recID < maxrecs; ++recID) { auto varID = recList[recID].varID; @@ -424,128 +468,108 @@ XTimstat(void *process) if (vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; - field2_moq(vars2[varID][levelID], vars1[varID][levelID]); + if (!samp1[varID][levelID].empty()) + field2_div(vars1[varID][levelID], samp1[varID][levelID]); + else + fieldc_div(vars1[varID][levelID], (double) numSets); } + } + else if (lvarstd) + { + for (int recID = 0; recID < maxrecs; ++recID) + { + auto varID = recList[recID].varID; + auto levelID = recList[recID].levelID; - vDateTimeN = vDateTime; - numSets++; - tsID++; - } + if (vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; - if (nrecs == 0 && numSets == 0) break; + const auto &rsamp1 = samp1[varID][levelID]; + auto &rvars1 = vars1[varID][levelID]; + const auto &rvars2 = vars2[varID][levelID]; - if (lmean) - { -#ifdef _OPENMP -#pragma omp parallel for default(shared) if (maxrecs > 1) -#endif - for (int recID = 0; recID < maxrecs; ++recID) - { - auto varID = recList[recID].varID; - auto levelID = recList[recID].levelID; + if (!rsamp1.empty()) + field2_stdvar_func(rvars1, rvars2, rsamp1, divisor); + else + fieldc_stdvar_func(rvars1, rvars2, numSets, divisor); + } + } - if (vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; + if (Options::cdoVerbose) cdo_print("%s vfrac = %g, numSets = %d", datetime_to_string(vDateTimeN), vfrac, numSets); - if (!samp1[varID][levelID].empty()) - field2_div(vars1[varID][levelID], samp1[varID][levelID]); - else - fieldc_div(vars1[varID][levelID], (double) numSets); - } - } - else if (lvarstd) - { + if (lvfrac && operfunc == FieldFunc_Mean) for (int recID = 0; recID < maxrecs; ++recID) { auto varID = recList[recID].varID; auto levelID = recList[recID].levelID; + auto &rvars1 = vars1[varID][levelID]; if (vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; - const auto &rsamp1 = samp1[varID][levelID]; - auto &rvars1 = vars1[varID][levelID]; - const auto &rvars2 = vars2[varID][levelID]; + auto missval = rvars1.missval; + if (!samp1[varID][levelID].empty()) + { + auto fieldsize = rvars1.size; + size_t irun = 0; + for (size_t i = 0; i < fieldsize; ++i) + { + if ((samp1[varID][levelID].vec_d[i] / numSets) < vfrac) + { + rvars1.vec_d[i] = missval; + irun++; + } + } - if (!rsamp1.empty()) - field2_stdvar_func(rvars1, rvars2, rsamp1, divisor); - else - fieldc_stdvar_func(rvars1, rvars2, numSets, divisor); + if (irun) rvars1.numMissVals = field_num_miss(rvars1); + } } - } - if (Options::cdoVerbose) cdo_print("%s vfrac = %g, numSets = %d", datetime_to_string(vDateTimeN), vfrac, numSets); + dtlist.stat_taxis_def_timestep(taxisID2, numSets); + cdo_def_timestep(streamID2, otsID); + + if (Options::cdoDiag) + { + dtlist.stat_taxis_def_timestep(taxisID3, numSets); + cdo_def_timestep(streamID3, otsID); + } - if (lvfrac && operfunc == FieldFunc_Mean) for (int recID = 0; recID < maxrecs; ++recID) { auto varID = recList[recID].varID; auto levelID = recList[recID].levelID; auto &rvars1 = vars1[varID][levelID]; - if (vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; + if (otsID && vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; + + cdo_def_record(streamID2, varID, levelID); + cdo_write_record(streamID2, rvars1.vec_d.data(), rvars1.numMissVals); - auto missval = rvars1.missval; - if (!samp1[varID][levelID].empty()) + if (Options::cdoDiag) { - auto fieldsize = rvars1.size; - size_t irun = 0; - for (size_t i = 0; i < fieldsize; ++i) + if (!samp1[varID][levelID].empty()) { - if ((samp1[varID][levelID].vec_d[i] / numSets) < vfrac) - { - rvars1.vec_d[i] = missval; - irun++; - } + cdo_def_record(streamID3, varID, levelID); + cdo_write_record(streamID3, samp1[varID][levelID].vec_d.data(), 0); } - - if (irun) rvars1.nmiss = field_num_miss(rvars1); } } - dtlist.stat_taxis_def_timestep(taxisID2, numSets); - cdo_def_timestep(streamID2, otsID); + if (nrecs == 0) break; + otsID++; + } + } - if (Options::cdoDiag) - { - dtlist.stat_taxis_def_timestep(taxisID3, numSets); - cdo_def_timestep(streamID3, otsID); - } - - for (int recID = 0; recID < maxrecs; ++recID) - { - auto varID = recList[recID].varID; - auto levelID = recList[recID].levelID; - auto &rvars1 = vars1[varID][levelID]; - - if (otsID && vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT) continue; + void + close() + { - cdo_def_record(streamID2, varID, levelID); - cdo_write_record(streamID2, rvars1.vec_d.data(), rvars1.nmiss); - - if (Options::cdoDiag) - { - if (!samp1[varID][levelID].empty()) - { - cdo_def_record(streamID3, varID, levelID); - cdo_write_record(streamID3, samp1[varID][levelID].vec_d.data(), 0); - } - } - } - - if (nrecs == 0) break; - otsID++; - } - - if (Options::cdoDiag) cdo_stream_close(streamID3); - cdo_stream_close(streamID2); + if (Options::cdoDiag) cdo_stream_close(streamID3); + cdo_stream_close(streamID2); #ifdef USE_CDI_STREAM - streamClose(streamID1); + streamClose(streamID1); #else - cdo_stream_close(streamID1); + cdo_stream_close(streamID1); #endif - if (read_task) delete read_task; - - cdo_finish(); - - return nullptr; -} + if (read_task) delete read_task; + } +}; diff --git a/src/Ydayarith.cc b/src/Ydayarith.cc index 1265428620ca40f1f564f968271061d8419475f7..7ea26ccc18b087b25fa252a7cb5e87b6d841e4e1 100644 --- a/src/Ydayarith.cc +++ b/src/Ydayarith.cc @@ -22,17 +22,23 @@ #include "printinfo.h" #include "field_functions.h" -static void -add_operators(void) +class Ydayarith : public Process { - cdo_operator_add("ydayadd", FieldFunc_Add, 0, nullptr); - cdo_operator_add("ydaysub", FieldFunc_Sub, 0, nullptr); - cdo_operator_add("ydaymul", FieldFunc_Mul, 0, nullptr); - cdo_operator_add("ydaydiv", FieldFunc_Div, 0, nullptr); -} +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ydayarith", + .operators = { { "ydayadd", FieldFunc_Add, 0, YdayarithHelp }, + { "ydaysub", FieldFunc_Sub, 0, YdayarithHelp }, + { "ydaymul", FieldFunc_Mul, 0, YdayarithHelp }, + { "ydaydiv", FieldFunc_Div, 0, YdayarithHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Ydayarith> registration = RegisterEntry<Ydayarith>(module); -class ModuleYdayarith -{ private: static const int MaxDays = 373; //~31*12 Field field; @@ -54,11 +60,8 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -87,7 +90,7 @@ public: cdo_def_vlist(streamID3, vlistID3); } - int + void run() { int tsID = 0; @@ -102,13 +105,13 @@ public: if (dayOfYear == 0) { cdo_error("Day of year %d out of range (date=%s)!", dayOfYear, date_to_string(vDateTime.date)); - return -1; + return; } if (vars2[dayOfYear].size() > 0) { cdo_error("Day of year index %d already allocated (date=%s)! Each day of year must only exist once", dayOfYear, date_to_string(vDateTime.date)); - return -1; + return; } fields_from_vlist(vlistID2, vars2[dayOfYear], FIELD_VEC | FIELD_NAT); @@ -135,12 +138,12 @@ public: if (dayOfYear == 0) { cdo_error("Day of year %d out of range (date=%s)!", dayOfYear, date_to_string(vDateTime.date)); - return -1; + return; } if (vars2[dayOfYear].size() == 0) { cdo_error("Day of year index %d not found (date=%s)!", dayOfYear, date_to_string(vDateTime.date)); - return -1; + return; } cdo_taxis_copy_timestep(taxisID3, taxisID1); @@ -160,7 +163,7 @@ public: } tsID++; } - return 0; + return; } void @@ -169,19 +172,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID3); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Ydayarith(void *process) -{ - ModuleYdayarith ydayarith; - ydayarith.init(process); - auto success = ydayarith.run(); - (void) success; - ydayarith.close(); - - return nullptr; -} diff --git a/src/Ydaypctl.cc b/src/Ydaypctl.cc index 5d4710eeddb789b83e954e3a8e649ebe8c7472f2..0c7726d47e44d39c93097432185dca29fa0523e9 100644 --- a/src/Ydaypctl.cc +++ b/src/Ydaypctl.cc @@ -24,8 +24,19 @@ #include "percentiles_hist.h" #include "field_functions.h" -class ModuleYdaypctl +class Ydaypctl : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ydaypctl", + .operators = { { "ydaypctl", FieldFunc_Pctl, 0, YdaypctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Ydaypctl> registration = RegisterEntry<Ydaypctl>(module); static const int MaxDays = 373; CdiDateTime vDateTimes1[MaxDays]{}; CdiDateTime vDateTimes2[MaxDays]{}; @@ -59,10 +70,8 @@ class ModuleYdaypctl public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("ydaypctl", FieldFunc_Pctl, 0, nullptr); operator_input_arg("percentile number"); pn = parameter_to_double(cdo_operator_argv(0)); @@ -245,17 +254,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - cdo_finish(); } }; - -void * -Ydaypctl(void *process) -{ - ModuleYdaypctl ydaypctl; - ydaypctl.init(process); - ydaypctl.run(); - ydaypctl.close(); - - return nullptr; -} diff --git a/src/Ydaystat.cc b/src/Ydaystat.cc index 27ebfb2ef653274b71708f814667bd74a4a560c9..913534130dd43a67d974e493d5ec8e9c7597d2d0 100644 --- a/src/Ydaystat.cc +++ b/src/Ydaystat.cc @@ -43,7 +43,7 @@ setParameter(void) KVList kvlist; kvlist.name = cdo_module_name(); - if (kvlist.parse_arguments(pargc, pargv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(pargv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); for (const auto &kv : kvlist) @@ -61,24 +61,29 @@ setParameter(void) } } -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("ydayrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("ydaymin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("ydaymax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("ydaysum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("ydaymean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("ydayavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("ydayvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("ydayvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("ydaystd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("ydaystd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} -class ModuleYdaystat +class Ydaystat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ydaystat", + .operators = { { "ydayrange", FieldFunc_Range, 0, YdaystatHelp }, + { "ydaymin", FieldFunc_Min, 0, YdaystatHelp }, + { "ydaymax", FieldFunc_Max, 0, YdaystatHelp }, + { "ydaysum", FieldFunc_Sum, 0, YdaystatHelp }, + { "ydaymean", FieldFunc_Mean, 0, YdaystatHelp }, + { "ydayavg", FieldFunc_Avg, 0, YdaystatHelp }, + { "ydaystd", FieldFunc_Std, 0, YdaystatHelp }, + { "ydaystd1", FieldFunc_Std1, 0, YdaystatHelp }, + { "ydayvar", FieldFunc_Var, 0, YdaystatHelp }, + { "ydayvar1", FieldFunc_Var1, 0, YdaystatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Ydaystat> registration = RegisterEntry<Ydaystat>(module); + private: static const int MaxDays = 373; @@ -111,14 +116,10 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - setParameter(); - addOperators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -201,11 +202,11 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[dayOfYear][varID][levelID].nmiss = rvars1.nmiss; + vars2[dayOfYear][varID][levelID].numMissVals = rvars1.numMissVals; vars2[dayOfYear][varID][levelID].vec_d = rvars1.vec_d; } - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -216,7 +217,7 @@ public: field.init(var); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, numSets); field2_vincr(rsamp1, field); @@ -313,18 +314,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Ydaystat(void *process) -{ - ModuleYdaystat ydaystat; - ydaystat.init(process); - ydaystat.run(); - ydaystat.close(); - - return nullptr; -} diff --git a/src/Ydrunpctl.cc b/src/Ydrunpctl.cc index 1f6e0f48934279b9b32ec3f5383ba749dc147957..036aa3f5a5939a4ef9f93c5c0c1d7fb97bb9d40c 100644 --- a/src/Ydrunpctl.cc +++ b/src/Ydrunpctl.cc @@ -28,8 +28,20 @@ #include "field_functions.h" constexpr int MaxDays = 373; -class ModuleYdrunpctl +class Ydrunpctl : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ydrunpctl", + .operators = { { "ydrunpctl", FieldFunc_Pctl, 0, YdrunpctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Ydrunpctl> registration = RegisterEntry<Ydrunpctl>(module); + private: CdoStreamID streamID1; CdoStreamID streamID2; @@ -67,13 +79,10 @@ private: public: void - init(void *process) + init() { vars2 = std::vector<bool>(MaxDays, false); - cdo_initialize(process); - cdo_operator_add("ydrunpctl", FieldFunc_Pctl, 0, nullptr); - pn = parameter_to_double(cdo_operator_argv(0)); ndates = parameter_to_int(cdo_operator_argv(1)); @@ -82,7 +91,7 @@ public: auto params = cdo_get_oper_argv(); params = std::vector<std::string>(params.begin() + 2, params.end()); KVList kvlist; - if (kvlist.parse_arguments(cdo_operator_argc() - 2, params) != 0) cdo_abort("Argument parse error!"); + if (kvlist.parse_arguments(params) != 0) cdo_abort("Argument parse error!"); auto kv = kvlist.search("pm"); if (kv && kv->nvalues > 0) percMethod = parameter_to_word(kv->values[0]); kv = kvlist.search("rm"); @@ -286,9 +295,9 @@ public: streamInqRecord(cdiStream, &varID, &levelID); auto &pvars1 = vars1[ndates - 1][varID][levelID]; if (pvars1.memType == MemType::Float) - streamReadRecordF(cdiStream, pvars1.vec_f.data(), &pvars1.nmiss); + streamReadRecordF(cdiStream, pvars1.vec_f.data(), &pvars1.numMissVals); else - streamReadRecord(cdiStream, pvars1.vec_d.data(), &pvars1.nmiss); + streamReadRecord(cdiStream, pvars1.vec_d.data(), &pvars1.numMissVals); } cdiDateTimes[ndates] = datetime_avg(dpy, ndates, cdiDateTimes); @@ -383,18 +392,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Ydrunpctl(void *process) -{ - ModuleYdrunpctl ydrunstat; - ydrunstat.init(process); - ydrunstat.run(); - ydrunstat.close(); - - return nullptr; -} diff --git a/src/Ydrunstat.cc b/src/Ydrunstat.cc index 7b355913a0d9985cd4f6d19de32112df778d4062..8f4fabc0c0c24c250598452dadcd64b47ea165a5 100644 --- a/src/Ydrunstat.cc +++ b/src/Ydrunstat.cc @@ -123,24 +123,28 @@ ydstat_finalize(YdayStats &stats, int operfunc) } } -static void -addOperators(void) +class Ydrunstat : public Process { - // clang-format off - cdo_operator_add("ydrunmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("ydrunmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("ydrunsum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("ydrunmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("ydrunavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("ydrunvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("ydrunvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("ydrunstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("ydrunstd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ydrunstat", + .operators = { { "ydrunmin", FieldFunc_Min, 0, YdrunstatHelp }, + { "ydrunmax", FieldFunc_Max, 0, YdrunstatHelp }, + { "ydrunsum", FieldFunc_Sum, 0, YdrunstatHelp }, + { "ydrunmean", FieldFunc_Mean, 0, YdrunstatHelp }, + { "ydrunavg", FieldFunc_Avg, 0, YdrunstatHelp }, + { "ydrunstd", FieldFunc_Std, 0, YdrunstatHelp }, + { "ydrunstd1", FieldFunc_Std1, 0, YdrunstatHelp }, + { "ydrunvar", FieldFunc_Var, 0, YdrunstatHelp }, + { "ydrunvar1", FieldFunc_Var1, 0, YdrunstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Ydrunstat> registration = RegisterEntry<Ydrunstat>(module); -class ModuleYdrunstat -{ private: int operfunc; @@ -165,11 +169,8 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -322,7 +323,7 @@ public: auto &rvars1 = vars1[ndates - 1][varID][levelID]; - streamReadRecord(cdiStream, rvars1.vec_d.data(), &rvars1.nmiss); + streamReadRecord(cdiStream, rvars1.vec_d.data(), &rvars1.numMissVals); if (lvarstd) { @@ -391,18 +392,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Ydrunstat(void *process) -{ - ModuleYdrunstat ydrunstat; - ydrunstat.init(process); - ydrunstat.run(); - ydrunstat.close(); - - return nullptr; -} diff --git a/src/Yeararith.cc b/src/Yeararith.cc index 9ab2eb69e6dc245046dd0e5d336deeec08219364..c6901503010d83f875e3259019fc82a890121b55 100644 --- a/src/Yeararith.cc +++ b/src/Yeararith.cc @@ -23,19 +23,22 @@ #include "process_int.h" #include "field_functions.h" -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("yearadd", FieldFunc_Add, 0, nullptr); - cdo_operator_add("yearsub", FieldFunc_Sub, 0, nullptr); - cdo_operator_add("yearmul", FieldFunc_Mul, 0, nullptr); - cdo_operator_add("yeardiv", FieldFunc_Div, 0, nullptr); - // clang-format on -} - -class ModuleYearArith +class Yeararith : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Yeararith", + .operators = { { "yearadd", FieldFunc_Add, 0, YeararithHelp }, + { "yearsub", FieldFunc_Sub, 0, YeararithHelp }, + { "yearmul", FieldFunc_Mul, 0, YeararithHelp }, + { "yeardiv", FieldFunc_Div, 0, YeararithHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Yeararith> registration = RegisterEntry<Yeararith>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -52,11 +55,8 @@ class ModuleYearArith public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -156,18 +156,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Yeararith(void *process) -{ - ModuleYearArith yeararith; - yeararith.init(process); - yeararith.run(); - yeararith.close(); - - return nullptr; -} diff --git a/src/Yearmonstat.cc b/src/Yearmonstat.cc index 4a82f602afd5a67171a7a8019fa96fd86895b72a..d7205917507bbed4af0faf42d5461e1f4a5b891a 100644 --- a/src/Yearmonstat.cc +++ b/src/Yearmonstat.cc @@ -22,8 +22,20 @@ #include "printinfo.h" #include "field_functions.h" -class ModuleYearMonStat +class Yearmonstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Yearmonstat", + .operators = { { "yearmonmean", FieldFunc_Mean, 0, YearmonstatHelp }, + { "yearmonavg", FieldFunc_Avg, 0, YearmonstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Yearmonstat> registration = RegisterEntry<Yearmonstat>(module); private: CdoStreamID streamID1; @@ -56,14 +68,10 @@ private: public: void - init(void *process) + init() { - cdo_initialize(process); - // clang-format off - cdo_operator_add("yearmonmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("yearmonavg", FieldFunc_Avg, 0, nullptr); // clang-format on auto operatorID = cdo_operator_id(); @@ -156,7 +164,7 @@ public: fieldc_mul(rvars1, dpm); - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1, dpm); @@ -169,7 +177,7 @@ public: fieldc_mul(field, dpm); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, dsets); field2_vincr(rsamp1, field, dpm); @@ -228,18 +236,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Yearmonstat(void *process) -{ - ModuleYearMonStat yearmonstat; - yearmonstat.init(process); - yearmonstat.run(); - yearmonstat.close(); - - return nullptr; -} diff --git a/src/Yhourarith.cc b/src/Yhourarith.cc index e00077e5f50b3f33bc8f2dabaf37ea30c2b2f613..5a4dc590ee358b94ec487d9f2a3c129420d2c913 100644 --- a/src/Yhourarith.cc +++ b/src/Yhourarith.cc @@ -35,17 +35,22 @@ getHourOfYearIndex(const CdiDateTime &vDateTime) return houroy; } -static void -add_operators(void) -{ - cdo_operator_add("yhouradd", FieldFunc_Add, 0, nullptr); - cdo_operator_add("yhoursub", FieldFunc_Sub, 0, nullptr); - cdo_operator_add("yhourmul", FieldFunc_Mul, 0, nullptr); - cdo_operator_add("yhourdiv", FieldFunc_Div, 0, nullptr); -} - -class ModuleYhourArith +class Yhourarith : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Yhourarith", + .operators = { { "yhouradd", FieldFunc_Add, 0, YhourarithHelp }, + { "yhoursub", FieldFunc_Sub, 0, YhourarithHelp }, + { "yhourmul", FieldFunc_Mul, 0, YhourarithHelp }, + { "yhourdiv", FieldFunc_Div, 0, YhourarithHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Yhourarith> registration = RegisterEntry<Yhourarith>(module); int operfunc; CdoStreamID streamID1; CdoStreamID streamID2; @@ -63,11 +68,8 @@ class ModuleYhourArith public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -157,18 +159,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Yhourarith(void *process) -{ - ModuleYhourArith yhourarith; - yhourarith.init(process); - yhourarith.run(); - yhourarith.close(); - - return nullptr; -} diff --git a/src/Yhourstat.cc b/src/Yhourstat.cc index d9e72f505c54ff12f484abeb0dfb71626253dbaa..42db06594a7fc35dcd4e0a3aea1c8c3f07660d8f 100644 --- a/src/Yhourstat.cc +++ b/src/Yhourstat.cc @@ -39,36 +39,41 @@ #include "printinfo.h" #include "field_functions.h" -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("yhourrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("yhourmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("yhourmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("yhoursum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("yhourmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("yhouravg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("yhourvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("yhourvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("yhourstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("yhourstd1", FieldFunc_Std1, 0, nullptr); - - cdo_operator_add("dhourrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("dhourmin", FieldFunc_Min, 1, nullptr); - cdo_operator_add("dhourmax", FieldFunc_Max, 1, nullptr); - cdo_operator_add("dhoursum", FieldFunc_Sum, 1, nullptr); - cdo_operator_add("dhourmean", FieldFunc_Mean, 1, nullptr); - cdo_operator_add("dhouravg", FieldFunc_Avg, 1, nullptr); - cdo_operator_add("dhourvar", FieldFunc_Var, 1, nullptr); - cdo_operator_add("dhourvar1", FieldFunc_Var1, 1, nullptr); - cdo_operator_add("dhourstd", FieldFunc_Std, 1, nullptr); - cdo_operator_add("dhourstd1", FieldFunc_Std1, 1, nullptr); - // clang-format on -} - -class ModuleYhourStat +class Yhourstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Yhourstat", + // clang-format off + .operators = { { "yhourrange", FieldFunc_Range, 0, YhourstatHelp }, + { "yhourmin", FieldFunc_Min, 0, YhourstatHelp }, + { "yhourmax", FieldFunc_Max, 0, YhourstatHelp }, + { "yhoursum", FieldFunc_Sum, 0, YhourstatHelp }, + { "yhourmean", FieldFunc_Mean, 0, YhourstatHelp }, + { "yhouravg", FieldFunc_Avg, 0, YhourstatHelp }, + { "yhourstd", FieldFunc_Std, 0, YhourstatHelp }, + { "yhourstd1", FieldFunc_Std1, 0, YhourstatHelp }, + { "yhourvar", FieldFunc_Var, 0, YhourstatHelp }, + { "yhourvar1", FieldFunc_Var1, 0, YhourstatHelp }, + { "dhourrange", FieldFunc_Range, 0, DhourstatHelp }, + { "dhourmin", FieldFunc_Min, 1, DhourstatHelp }, + { "dhourmax", FieldFunc_Max, 1, DhourstatHelp }, + { "dhoursum", FieldFunc_Sum, 1, DhourstatHelp }, + { "dhourmean", FieldFunc_Mean, 1, DhourstatHelp }, + { "dhouravg", FieldFunc_Avg, 1, DhourstatHelp }, + { "dhourstd", FieldFunc_Std, 1, DhourstatHelp }, + { "dhourstd1", FieldFunc_Std1, 1, DhourstatHelp }, + { "dhourvar", FieldFunc_Var, 1, DhourstatHelp }, + { "dhourvar1", FieldFunc_Var1, 1, DhourstatHelp } }, + // clang-format on + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Yhourstat> registration = RegisterEntry<Yhourstat>(module); + private: int MaxHours; @@ -104,14 +109,10 @@ private: public: void - init(void *process) + init() { constexpr auto timestatDate{ TimeStat::LAST }; - cdo_initialize(process); - - addOperators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -213,11 +214,11 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[hourot][varID][levelID].nmiss = rvars1.nmiss; + vars2[hourot][varID][levelID].numMissVals = rvars1.numMissVals; vars2[hourot][varID][levelID].vec_d = rvars1.vec_d; } - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -228,7 +229,7 @@ public: field.init(var); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, numSets); field2_vincr(rsamp1, field); @@ -281,10 +282,7 @@ public: else fieldc_stdvar_func(rvars1, vars2[hourot][varID][levelID], numSets, divisor); } - else if (lrange) - { - field2_sub(rvars1, vars2[hourot][varID][levelID]); - } + else if (lrange) { field2_sub(rvars1, vars2[hourot][varID][levelID]); } } dtlist[hourot].stat_taxis_def_timestep(taxisID2, hourot_numSets[hourot]); @@ -310,18 +308,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Yhourstat(void *process) -{ - ModuleYhourStat yhourstat; - yhourstat.init(process); - yhourstat.run(); - yhourstat.close(); - - return nullptr; -} diff --git a/src/Ymonarith.cc b/src/Ymonarith.cc index c251dc2a23e4733f54d31dbb105e627794d2bcd4..c0040be55f05ca9431a001f22075ca2aa3d14a72 100644 --- a/src/Ymonarith.cc +++ b/src/Ymonarith.cc @@ -45,23 +45,26 @@ enum SEASONAL }; -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("ymonadd", FieldFunc_Add, MONTHLY, nullptr); - cdo_operator_add("ymonsub", FieldFunc_Sub, MONTHLY, nullptr); - cdo_operator_add("ymonmul", FieldFunc_Mul, MONTHLY, nullptr); - cdo_operator_add("ymondiv", FieldFunc_Div, MONTHLY, nullptr); - cdo_operator_add("yseasadd", FieldFunc_Add, SEASONAL, nullptr); - cdo_operator_add("yseassub", FieldFunc_Sub, SEASONAL, nullptr); - cdo_operator_add("yseasmul", FieldFunc_Mul, SEASONAL, nullptr); - cdo_operator_add("yseasdiv", FieldFunc_Div, SEASONAL, nullptr); - // clang-format on -} - -class ModuleYmonArith +class Ymonarith : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ymonarith", + .operators = { { "ymonadd", FieldFunc_Add, MONTHLY, YmonarithHelp }, + { "ymonsub", FieldFunc_Sub, MONTHLY, YmonarithHelp }, + { "ymonmul", FieldFunc_Mul, MONTHLY, YmonarithHelp }, + { "ymondiv", FieldFunc_Div, MONTHLY, YmonarithHelp }, + { "yseasadd", FieldFunc_Add, SEASONAL, YseasarithHelp }, + { "yseassub", FieldFunc_Sub, SEASONAL, YseasarithHelp }, + { "yseasmul", FieldFunc_Mul, SEASONAL, YseasarithHelp }, + { "yseasdiv", FieldFunc_Div, SEASONAL, YseasarithHelp } }, + .aliases = { { "anomaly", "ymonsub" } }, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Ymonarith> registration = RegisterEntry<Ymonarith>(module); int operfunc; int opertype; @@ -161,11 +164,8 @@ class ModuleYmonArith public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); opertype = cdo_operator_f2(operatorID); @@ -210,17 +210,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID3); cdo_stream_close(streamID1); - cdo_finish(); } }; - -void * -Ymonarith(void *process) -{ - ModuleYmonArith ymonarith; - ymonarith.init(process); - ymonarith.run(); - ymonarith.close(); - - return nullptr; -} diff --git a/src/Ymoncomp.cc b/src/Ymoncomp.cc index 3d2e95417d683a6624b598018bf2aedbf424e47d..7c867606378d2fb1103605b21e18847040b767db 100644 --- a/src/Ymoncomp.cc +++ b/src/Ymoncomp.cc @@ -62,7 +62,7 @@ comp_function(int operFunc, bool hasMissvals, size_t ngp, T1 missval1, T2 missva static void comp_function(Field &f1, const Field &f2, int operFunc) { - auto hasMissvals = (f1.nmiss > 0 || f2.nmiss > 0); + auto hasMissvals = (f1.numMissVals > 0 || f2.numMissVals > 0); if (f1.memType == MemType::Float && f2.memType == MemType::Float) comp_function(operFunc, hasMissvals, f1.size, (float) f1.missval, (float) f2.missval, f1.vec_f, f2.vec_f); else if (f1.memType == MemType::Float && f2.memType == MemType::Double) @@ -94,27 +94,30 @@ enum SEASONAL }; -static void -add_operators(void) -{ - // clang-format off - cdo_operator_add("ymoneq", FieldFunc_EQ, MONTHLY, nullptr); - cdo_operator_add("ymonne", FieldFunc_NE, MONTHLY, nullptr); - cdo_operator_add("ymonle", FieldFunc_LE, MONTHLY, nullptr); - cdo_operator_add("ymonlt", FieldFunc_LT, MONTHLY, nullptr); - cdo_operator_add("ymonge", FieldFunc_GE, MONTHLY, nullptr); - cdo_operator_add("ymongt", FieldFunc_GT, MONTHLY, nullptr); - cdo_operator_add("yseaseq", FieldFunc_EQ, SEASONAL, nullptr); - cdo_operator_add("yseasne", FieldFunc_NE, SEASONAL, nullptr); - cdo_operator_add("yseasle", FieldFunc_LE, SEASONAL, nullptr); - cdo_operator_add("yseaslt", FieldFunc_LT, SEASONAL, nullptr); - cdo_operator_add("yseasge", FieldFunc_GE, SEASONAL, nullptr); - cdo_operator_add("yseasgt", FieldFunc_GT, SEASONAL, nullptr); - // clang-format on -} - -class ModuleYmonComp +class Ymoncomp : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ymoncomp", + .operators = { { "ymoneq", FieldFunc_EQ, MONTHLY, YmoncompHelp }, + { "ymonne", FieldFunc_NE, MONTHLY, YmoncompHelp }, + { "ymonle", FieldFunc_LE, MONTHLY, YmoncompHelp }, + { "ymonlt", FieldFunc_LT, MONTHLY, YmoncompHelp }, + { "ymonge", FieldFunc_GE, MONTHLY, YmoncompHelp }, + { "ymongt", FieldFunc_GT, MONTHLY, YmoncompHelp }, + { "yseaseq", FieldFunc_EQ, SEASONAL, nullptr}, + { "yseasne", FieldFunc_NE, SEASONAL, nullptr}, + { "yseasle", FieldFunc_LE, SEASONAL, nullptr}, + { "yseaslt", FieldFunc_LT, SEASONAL, nullptr}, + { "yseasge", FieldFunc_GE, SEASONAL, nullptr}, + { "yseasgt", FieldFunc_GT, SEASONAL, nullptr} }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 2, 1, NoRestriction }, + }; + inline static RegisterEntry<Ymoncomp> registration = RegisterEntry<Ymoncomp>(module); int operfunc; int opertype; @@ -214,11 +217,8 @@ class ModuleYmonComp public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -263,17 +263,5 @@ public: cdo_stream_close(streamID2); cdo_stream_close(streamID3); cdo_stream_close(streamID1); - cdo_finish(); } }; - -void * -Ymoncomp(void *process) -{ - ModuleYmonComp ymoncomp; - ymoncomp.init(process); - ymoncomp.run(); - ymoncomp.close(); - - return nullptr; -} diff --git a/src/Ymonpctl.cc b/src/Ymonpctl.cc index 091cf264d91f521920c10d61a3b425741435b685..8586fa91158da9bef3abf06fbb37632515bb349f 100644 --- a/src/Ymonpctl.cc +++ b/src/Ymonpctl.cc @@ -25,8 +25,19 @@ #include "percentiles_hist.h" #include "field_functions.h" -class ModuleYmonpctl +class Ymonpctl : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ymonpctl", + .operators = { { "ymonpctl", FieldFunc_Pctl, 0, YmonpctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Ymonpctl> registration = RegisterEntry<Ymonpctl>(module); constexpr static int MaxMonths = 17; CdoStreamID streamID1; @@ -58,10 +69,8 @@ class ModuleYmonpctl public: void - init(void *process) + init() { - cdo_initialize(process); - cdo_operator_add("ymonpctl", FieldFunc_Pctl, 0, nullptr); operator_input_arg("percentile number"); pn = parameter_to_double(cdo_operator_argv(0)); @@ -240,18 +249,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Ymonpctl(void *process) -{ - ModuleYmonpctl ymonpctl; - ymonpctl.init(process); - ymonpctl.run(); - ymonpctl.close(); - - return nullptr; -} diff --git a/src/Ymonstat.cc b/src/Ymonstat.cc index e011921460fd1755447c0c3f3db626af3eeaedde..46ef57077ace52981f60a8c4ecf2994a41049cb1 100644 --- a/src/Ymonstat.cc +++ b/src/Ymonstat.cc @@ -28,27 +28,28 @@ #include "printinfo.h" #include "field_functions.h" -static void -addOperators(void) -{ - // clang-format off - cdo_operator_add("ymonrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("ymonmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("ymonmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("ymonmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("ymonmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("ymonsum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("ymonmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("ymonavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("ymonvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("ymonvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("ymonstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("ymonstd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} - -class ModuleYmonstat +class Ymonstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Ymonstat", + .operators = { { "ymonrange", FieldFunc_Range, 0, YmonstatHelp }, + { "ymonmin", FieldFunc_Min, 0, YmonstatHelp }, + { "ymonmax", FieldFunc_Max, 0, YmonstatHelp }, + { "ymonsum", FieldFunc_Sum, 0, YmonstatHelp }, + { "ymonmean", FieldFunc_Mean, 0, YmonstatHelp }, + { "ymonavg", FieldFunc_Avg, 0, YmonstatHelp }, + { "ymonstd", FieldFunc_Std, 0, YmonstatHelp }, + { "ymonstd1", FieldFunc_Std1, 0, YmonstatHelp }, + { "ymonvar", FieldFunc_Var, 0, YmonstatHelp }, + { "ymonvar1", FieldFunc_Var1, 0, YmonstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Ymonstat> registration = RegisterEntry<Ymonstat>(module); static const int MaxMonths = 17; int month_numSets[MaxMonths] = { 0 }; int mon[MaxMonths] = { 0 }; @@ -79,14 +80,10 @@ class ModuleYmonstat public: void - init(void *process) + init() { constexpr auto timestatDate{ TimeStat::LAST }; - cdo_initialize(process); - - addOperators(); - auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -177,11 +174,11 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) { - vars2[month][varID][levelID].nmiss = rvars1.nmiss; + vars2[month][varID][levelID].numMissVals = rvars1.numMissVals; vars2[month][varID][levelID].vec_d = rvars1.vec_d; } - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -192,7 +189,7 @@ public: field.init(var); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, numSets); field2_vincr(rsamp1, field); @@ -256,10 +253,7 @@ public: else fieldc_stdvar_func(rvars1, vars2[month][varID][levelID], numSets, divisor); } - else if (lrange) - { - field2_sub(rvars1, vars2[month][varID][levelID]); - } + else if (lrange) { field2_sub(rvars1, vars2[month][varID][levelID]); } } dtlists[month].stat_taxis_def_timestep(taxisID2); @@ -285,18 +279,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Ymonstat(void *process) -{ - ModuleYmonstat ymonstat; - ymonstat.init(process); - ymonstat.run(); - ymonstat.close(); - - return nullptr; -} diff --git a/src/Yseaspctl.cc b/src/Yseaspctl.cc index dfb8c16524daa7c08e3cf71c013482c6eb4e85c6..680d3bcf448d9ba0749abb2295b48e76a2a8bfba 100644 --- a/src/Yseaspctl.cc +++ b/src/Yseaspctl.cc @@ -26,8 +26,25 @@ #include "printinfo.h" #include "field_functions.h" -class ModuleYseaspctl +class Yseaspctl : public Process { + enum + { + MaxSeasons = 4 + }; + long numSets[MaxSeasons] = { 0 }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Yseaspctl", + .operators = { { "yseaspctl", FieldFunc_Pctl, 0, YseaspctlHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 3, 1, NoRestriction }, + }; + inline static RegisterEntry<Yseaspctl> registration = RegisterEntry<Yseaspctl>(module); CdoStreamID streamID1; CdoStreamID streamID2; CdoStreamID streamID3; @@ -42,8 +59,6 @@ class ModuleYseaspctl VarList varList1; Field field1, field2; - enum { MaxSeasons = 4 }; - long numSets[MaxSeasons] = { 0 }; CdiDateTime vDateTimes1[MaxSeasons]{}; CdiDateTime vDateTimes2[MaxSeasons]{}; @@ -58,14 +73,10 @@ class ModuleYseaspctl public: void - init(void *process) + init() { vars1 = std::vector<bool>(MaxSeasons, false); - cdo_initialize(process); - - cdo_operator_add("yseaspctl", FieldFunc_Pctl, 0, nullptr); - operator_input_arg("percentile number"); pn = parameter_to_double(cdo_operator_argv(0)); @@ -241,18 +252,5 @@ public: cdo_stream_close(streamID3); cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Yseaspctl(void *process) -{ - ModuleYseaspctl yseaspctl; - yseaspctl.init(process); - yseaspctl.run(); - yseaspctl.close(); - - return nullptr; -} diff --git a/src/Yseasstat.cc b/src/Yseasstat.cc index 6a34a1d047f99af713841b25918ecbf79711e88c..e9dfddffe2b539150dc633415d4b3ff6ff3e7a6e 100644 --- a/src/Yseasstat.cc +++ b/src/Yseasstat.cc @@ -27,27 +27,34 @@ #include "process_int.h" #include "field_functions.h" -static void -addOperators(void) +class Yseasstat : public Process { - // clang-format off - cdo_operator_add("yseasrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("yseasmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("yseasmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("yseassum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("yseasmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("yseasavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("yseasvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("yseasvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("yseasstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("yseasstd1", FieldFunc_Std1, 0, nullptr); - // clang-format on -} - -class ModuleYseasstat -{ - enum { MaxSeasons = 4 }; + enum + { + MaxSeasons = 4 + }; int seas_numSets[MaxSeasons] = { 0 }; + +public: + using Process::Process; + inline static CdoModule module = { + .name = "Yseasstat", + .operators = { { "yseasrange", FieldFunc_Range, 0, YseasstatHelp }, + { "yseasmin", FieldFunc_Min, 0, YseasstatHelp }, + { "yseasmax", FieldFunc_Max, 0, YseasstatHelp }, + { "yseassum", FieldFunc_Sum, 0, YseasstatHelp }, + { "yseasmean", FieldFunc_Mean, 0, YseasstatHelp }, + { "yseasavg", FieldFunc_Avg, 0, YseasstatHelp }, + { "yseasstd", FieldFunc_Std, 0, YseasstatHelp }, + { "yseasstd1", FieldFunc_Std1, 0, YseasstatHelp }, + { "yseasvar", FieldFunc_Var, 0, YseasstatHelp }, + { "yseasvar1", FieldFunc_Var1, 0, YseasstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Yseasstat> registration = RegisterEntry<Yseasstat>(module); CdiDateTime vDateTimes[MaxSeasons]{}; FieldVector2D vars1[MaxSeasons], vars2[MaxSeasons], samp1[MaxSeasons]; CdoStreamID streamID1; @@ -75,11 +82,8 @@ class ModuleYseasstat public: void - init(void *process) + init() { - cdo_initialize(process); - - addOperators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -161,7 +165,7 @@ public: cdo_read_record(streamID1, rvars1); if (lrange) field_copy(rvars1, vars2[seas][varID][levelID]); - if (rvars1.nmiss || !rsamp1.empty()) + if (rvars1.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size); field2_vinit(rsamp1, rvars1); @@ -172,7 +176,7 @@ public: field.init(var); cdo_read_record(streamID1, field); - if (field.nmiss || !rsamp1.empty()) + if (field.numMissVals || !rsamp1.empty()) { if (rsamp1.empty()) rsamp1.resize(rvars1.size, numSets); field2_vincr(rsamp1, field); @@ -251,18 +255,5 @@ public: { cdo_stream_close(streamID2); cdo_stream_close(streamID1); - - cdo_finish(); } }; - -void * -Yseasstat(void *process) -{ - ModuleYseasstat yseasstat; - yseasstat.init(process); - yseasstat.run(); - yseasstat.close(); - - return nullptr; -} diff --git a/src/Zonstat.cc b/src/Zonstat.cc index f74e6966ac9124449b539cc32f6f593cafa195d5..1afafd1175d36ed96bb0fce4bd86936cc1e62ee0 100644 --- a/src/Zonstat.cc +++ b/src/Zonstat.cc @@ -69,8 +69,32 @@ define_reduced_grid(int gridID1, size_t ysize, std::vector<int> &hpReducedPoints return gridID; } -class ModuleZonStat +class Zonstat : public Process { +public: + using Process::Process; + inline static CdoModule module = { + .name = "Zonstat", + .operators = { { "zonrange", FieldFunc_Range, 0, ZonstatHelp }, + { "zonmin", FieldFunc_Min, 0, ZonstatHelp }, + { "zonmax", FieldFunc_Max, 0, ZonstatHelp }, + { "zonsum", FieldFunc_Sum, 0, ZonstatHelp }, + { "zonmean", FieldFunc_Mean, 0, ZonstatHelp }, + { "zonavg", FieldFunc_Avg, 0, ZonstatHelp }, + { "zonstd", FieldFunc_Std, 0, ZonstatHelp }, + { "zonstd1", FieldFunc_Std1, 0, ZonstatHelp }, + { "zonvar", FieldFunc_Var, 0, ZonstatHelp }, + { "zonvar1", FieldFunc_Var1, 0, ZonstatHelp }, + { "zonskew", FieldFunc_Skew, 0, ZonstatHelp }, + { "zonkurt", FieldFunc_Kurt, 0, ZonstatHelp }, + { "zonmedian", FieldFunc_Median, 0, ZonstatHelp }, + { "zonpctl", FieldFunc_Pctl, 0, ZonstatHelp } }, + .aliases = {}, + .mode = EXPOSED, // Module mode: 0:intern 1:extern + .number = CDI_REAL, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<Zonstat> registration = RegisterEntry<Zonstat>(module); int gridIDdestroy = -1, gridID1 = -1, gridID2 = -1; int zongridID = -1; int sourceGridIsRegular = true; @@ -94,34 +118,10 @@ class ModuleZonStat double pn = 0.0; - void - add_operators(void) - { - // clang-format off - cdo_operator_add("zonmin", FieldFunc_Min, 0, nullptr); - cdo_operator_add("zonmax", FieldFunc_Max, 0, nullptr); - cdo_operator_add("zonrange", FieldFunc_Range, 0, nullptr); - cdo_operator_add("zonsum", FieldFunc_Sum, 0, nullptr); - cdo_operator_add("zonmean", FieldFunc_Mean, 0, nullptr); - cdo_operator_add("zonavg", FieldFunc_Avg, 0, nullptr); - cdo_operator_add("zonvar", FieldFunc_Var, 0, nullptr); - cdo_operator_add("zonvar1", FieldFunc_Var1, 0, nullptr); - cdo_operator_add("zonstd", FieldFunc_Std, 0, nullptr); - cdo_operator_add("zonstd1", FieldFunc_Std1, 0, nullptr); - cdo_operator_add("zonskew", FieldFunc_Skew, 0, nullptr); - cdo_operator_add("zonkurt", FieldFunc_Kurt, 0, nullptr); - cdo_operator_add("zonmedian", FieldFunc_Median, 0, nullptr); - cdo_operator_add("zonpctl", FieldFunc_Pctl, 0, nullptr); - // clang-format on - } - public: void - init(void *process) + init() { - cdo_initialize(process); - - add_operators(); auto operatorID = cdo_operator_id(); operfunc = cdo_operator_f1(operatorID); @@ -142,10 +142,7 @@ public: if (!gridInqYbounds(gridID2, NULL)) cdo_abort("Target grid cell bounds missing!"); if (gridInqXsize(gridID2) > 1) cdo_abort("Target grid must be zonal!"); } - else - { - operator_check_argc(0); - } + else { operator_check_argc(0); } streamID1 = cdo_open_read(0); @@ -274,10 +271,7 @@ public: if (is_healpix_grid(varList1[varID].gridID)) reorder_field(field1, hpRingIndices); (operfunc == FieldFunc_Pctl) ? zonal_pctl(field1, field2, pn) : zonal_function(field1, field2, operfunc); } - else - { - remap_zonal_mean(remapIndices, remapWeights, field1, field2); - } + else { remap_zonal_mean(remapIndices, remapWeights, field1, field2); } cdo_def_record(streamID2, varID, levelID); cdo_write_record(streamID2, field2); @@ -304,18 +298,5 @@ public: cdo_stream_close(streamID1); if (gridIDdestroy != -1) gridDestroy(gridIDdestroy); - - cdo_finish(); } }; - -void * -Zonstat(void *process) -{ - ModuleZonStat zonstat; - zonstat.init(process); - zonstat.run(); - zonstat.close(); - - return nullptr; -} diff --git a/src/after_dvtrans.cc b/src/after_dvtrans.cc index 6b0f8f16f798c3edfdca09556106bf4ac3bdd059..d0752c484bc679eb7cbcf667e08372195232df2d 100644 --- a/src/after_dvtrans.cc +++ b/src/after_dvtrans.cc @@ -12,7 +12,7 @@ #include "constants.h" -#define SQUARE_RADIUS (-PlanetRadius * PlanetRadius) +#define SQUARE_RADIUS (-PlanetRadiusDefault * PlanetRadiusDefault) void dv2ps(const double *restrict div, double *restrict pot, long nlev, long ntr) @@ -220,8 +220,8 @@ geninx(long ntr, double *f, double *g) long n2 = n * n; if (n) { - *g++ = -PlanetRadius / n * std::sqrt((double) (n2 - m2) / (double) (4 * n2 - 1)); - *f++ = -PlanetRadius * m / (double) (n2 + n); + *g++ = -PlanetRadiusDefault / n * std::sqrt((double) (n2 - m2) / (double) (4 * n2 - 1)); + *f++ = -PlanetRadiusDefault * m / (double) (n2 + n); } else { diff --git a/src/after_sptrans.cc b/src/after_sptrans.cc index 9fad4adde1fa49818c8632a8419f2fba09d32964..fa2d5c4af3f528a8ecc9213a5c746eabe8726c60 100644 --- a/src/after_sptrans.cc +++ b/src/after_sptrans.cc @@ -25,17 +25,17 @@ phcs(bool needHnm, double *pnm, double *hnm, long waves, double pmu, double *zte double zcospar, zsinpar, zcosfak, zsinfak; double zq, zwm2, zw, zwq, zq2m1, zwm2q2, z2q2, zcnm, zdnm, zenm; - const auto twowaves = waves << 1; + auto twowaves = waves << 1; - const auto zcos2 = std::sqrt(1.0 - pmu * pmu); - const auto lat = std::acos(pmu); + auto zcos2 = std::sqrt(1.0 - pmu * pmu); + auto lat = std::acos(pmu); auto zan = 1.0; ztemp1[0] = 0.5; for (long jn = 1; jn < twowaves; jn++) { - const auto zsqp = 1.0 / std::sqrt((double) (jn + jn * jn)); + auto zsqp = 1.0 / std::sqrt((double) (jn + jn * jn)); zan *= std::sqrt(1.0 - 1.0 / (4 * jn * jn)); zcospar = std::cos(lat * jn); @@ -122,7 +122,7 @@ after_legini_full(long ntr, long nlat, double *restrict poli, double *restrict p { auto dimsp = (ntr + 1) * (ntr + 2); auto waves = ntr + 1; - const auto twowaves = waves << 1; + auto twowaves = waves << 1; Varray<double> gmu(nlat), gwt(nlat); gaussian_latitudes(nlat, gmu.data(), gwt.data()); @@ -150,20 +150,20 @@ after_legini_full(long ntr, long nlat, double *restrict poli, double *restrict p for (long jgl = 0; jgl < nlat; ++jgl) { #ifdef _OPENMP - const auto ompthID = cdo_omp_get_thread_num(); + auto ompthID = cdo_omp_get_thread_num(); auto &pnm = pnm_2[ompthID]; auto &hnm = hnm_2[ompthID]; auto &ztemp1 = ztemp1_2[ompthID]; auto &ztemp2 = ztemp2_2[ompthID]; #endif - const auto gmusq = 1.0 - gmu[jgl] * gmu[jgl]; + auto gmusq = 1.0 - gmu[jgl] * gmu[jgl]; coslat[jgl] = std::sqrt(gmusq); phcs(needHnm, pnm.data(), hnm.data(), waves, gmu[jgl], ztemp1.data(), ztemp2.data()); - const auto zgwt = gwt[jgl]; - const auto zrafgmusqr = 1.0 / (PlanetRadius * gmusq); - const auto zradsqrtgmusqr = 1.0 / (-PlanetRadius * std::sqrt(gmusq)); + auto zgwt = gwt[jgl]; + auto zrafgmusqr = 1.0 / (PlanetRadiusDefault * gmusq); + auto zradsqrtgmusqr = 1.0 / (-PlanetRadiusDefault * std::sqrt(gmusq)); auto jsp = jgl; for (long jm = 0; jm < waves; ++jm) @@ -182,8 +182,8 @@ after_legini_full(long ntr, long nlat, double *restrict poli, double *restrict p static inline void sp2fc_kernel(long nlat, const double *pol, const double *sal, double *restrict far, double *restrict fai) { - const auto sar = sal[0]; - const auto sai = sal[1]; + auto sar = sal[0]; + auto sai = sal[1]; for (long lat = 0; lat < nlat; lat++) { far[lat] += pol[lat] * sar; diff --git a/src/afterburner.h b/src/afterburner.h index 34fe7d4b78204f1a85c84146c632889ec41fe7f5..57fef16751861460bf27f61ac9e7eddaebba4427 100644 --- a/src/afterburner.h +++ b/src/afterburner.h @@ -10,16 +10,15 @@ #include <string.h> #include <stdarg.h> -#include "dmemory.h" #include "process_int.h" #include "transform.h" #include "cdo_task.h" +#include "varray.h" -#define MaxLevel 1024 +constexpr int MaxLevel = 1024; +constexpr int MaxCodes = 277; -#define MaxCodes 277 - -#define S_ECHAM5 1 +constexpr int ECHAM5_Source = 1; struct Date { @@ -64,13 +63,13 @@ struct AfterControl struct Date OldDate; struct Date StartDate; + int numHalfLevels = 0; int nvct = 0; - double *vct = nullptr; + Varray<double> vct; - int *vertIndex = nullptr; - size_t *pnmiss = nullptr; - double *p_of_height = nullptr; - double *Orography = nullptr; + Varray<int> vertIndex; + Varray<double> p_of_height; + Varray<double> orography; int Type = 0; int unitsel = 0; @@ -89,14 +88,14 @@ struct AfterControl long DimFC = 0, DimGP = 0, DimSP = 0; long DimSP_half = 0; - double *poli = nullptr; - double *pold = nullptr; - double *pdev = nullptr; - double *pol2 = nullptr; - double *pol3 = nullptr; + Varray <double> poli; + Varray <double> pold; + Varray <double> pdev; + Varray <double> pol2; + Varray <double> pol3; - double *dv2uv_f1 = nullptr; - double *dv2uv_f2 = nullptr; + Varray <double> dv2uv_f1; + Varray <double> dv2uv_f2; int NumCodesRequest = 0; @@ -105,33 +104,10 @@ struct AfterControl int NumLevelRequest = 0; double LevelRequest[MaxLevel]; - double *rcoslat = nullptr; - double *coslat = nullptr; - double *DerivationFactor = nullptr; - double *Field = nullptr; - - ~AfterControl() - { - if (vct) Free(vct); - if (vertIndex) Free(vertIndex); - if (pnmiss) Free(pnmiss); - if (p_of_height) Free(p_of_height); - if (Orography) Free(Orography); - - if (poli) Free(poli); - if (pold) Free(pold); - if (pdev) Free(pdev); - if (pol2) Free(pol2); - if (pol3) Free(pol3); - - if (dv2uv_f1) Free(dv2uv_f1); - if (dv2uv_f2) Free(dv2uv_f2); - - if (rcoslat) Free(rcoslat); - if (coslat) Free(coslat); - if (DerivationFactor) Free(DerivationFactor); - if (Field) Free(Field); - } + Varray<double> rcoslat; + Varray<double> coslat; + Varray<double> derivationFactor; + Varray<double> varray; }; struct Variable @@ -152,8 +128,8 @@ struct Variable int ogridID; int izaxisID; int ozaxisID; - size_t nmiss0; - size_t nmiss; + size_t numMissVals0; + size_t numMissVals; double missval; double *spectral; double *spectral0; @@ -172,10 +148,10 @@ struct Variable #define LOW_CLOUD 34 #define MID_CLOUD 35 #define HIH_CLOUD 36 -#define LOW_WATER 37 /* not used ? */ -#define MID_WATER 38 /* not used ? */ -#define HIH_WATER 39 /* not used ? */ -#define ALL_WATER 40 /* not used ? */ +#define LOW_WATER 37 // not used ? +#define MID_WATER 38 // not used ? +#define HIH_WATER 39 // not used ? +#define ALL_WATER 40 // not used ? #define GEOPOTENTIAL 129 #define TEMPERATURE 130 @@ -194,11 +170,10 @@ struct Variable #define GEOPOTHEIGHT 156 #define RHUMIDITY 157 -#define SW_BOT_CLF 189 /* not used ? */ -#define LW_BOT_CLF 190 /* not used ? */ -#define SW_TOP_CLF 191 /* not used ? */ -#define LW_TOP_CLF 192 /* not used ? */ -#define NET_TOP_CLF 193 /* not computed */ +#define SW_BOT_CLF 189 // not used ? +#define LW_BOT_CLF 190 // not used ? +#define SW_TOP_CLF 191 // not used ? +#define LW_TOP_CLF 192 // not used ? #define WINDSPEED 259 #define PRECIP 260 @@ -235,10 +210,10 @@ void after_processPL(AfterControl &globs, struct Variable *vars); void after_processML(AfterControl &globs, struct Variable *vars); void after_AnalysisAddRecord(const AfterControl *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, - size_t nmiss); + size_t numMissVals); double *after_get_dataptr(struct Variable *vars, int code, int gridID, int zaxisID, int levelID); void after_EchamAddRecord(const AfterControl *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, - size_t nmiss); + size_t numMissVals); void after_AnalysisDependencies(struct Variable *vars, int ncodes); void after_EchamDependencies(struct Variable *vars, int ncodes, int type, int source); diff --git a/src/afterburnerlib.cc b/src/afterburnerlib.cc index 28f995104ccf9d338b1fb2df12440bb0f5bdb978..bc5db67d20dfe2e305fd8bd84f7fd941cec0cc08 100644 --- a/src/afterburnerlib.cc +++ b/src/afterburnerlib.cc @@ -21,46 +21,45 @@ FieldName(int code, const char *text) } // Free array space -static void * -FreeMemory(void *ptr) +template <typename T> +static void +FreeMemory(T &ptr) { - Free(ptr); - return nullptr; + if (ptr) + { + free(ptr); + ptr = nullptr; + } } static void FreeSpectral(struct Variable *vars) { - for (int code = MaxCodes - 1; code >= 0; --code) - if (vars[code].spectral) vars[code].spectral = (double *) FreeMemory(vars[code].spectral); + for (int code = MaxCodes - 1; code >= 0; --code) FreeMemory(vars[code].spectral); } static void FreeFourier(struct Variable *vars) { - for (int code = 0; code < MaxCodes; ++code) - if (vars[code].fourier) vars[code].fourier = (double *) FreeMemory(vars[code].fourier); + for (int code = 0; code < MaxCodes; ++code) FreeMemory(vars[code].fourier); } static void FreeHybrid(struct Variable *vars) { - for (int code = 0; code < MaxCodes; ++code) - if (vars[code].hybrid) vars[code].hybrid = (double *) FreeMemory(vars[code].hybrid); + for (int code = 0; code < MaxCodes; ++code) FreeMemory(vars[code].hybrid); } static void FreeGrid(struct Variable *vars) { - for (int code = 0; code < MaxCodes; ++code) - if (vars[code].grid) vars[code].grid = (double *) FreeMemory(vars[code].grid); + for (int code = 0; code < MaxCodes; ++code) FreeMemory(vars[code].grid); } static void FreeSamp(struct Variable *vars) { - for (int code = 0; code < MaxCodes; ++code) - if (vars[code].samp) vars[code].samp = (int *) FreeMemory(vars[code].samp); + for (int code = 0; code < MaxCodes; ++code) FreeMemory(vars[code].samp); } // alloc_dp - Allocate space for double array @@ -71,7 +70,7 @@ alloc_dp(int words, const char *array_name) if (words > 0) { - result = (double *) Malloc(words * sizeof(double)); + result = (double *) malloc(words * sizeof(double)); if (result == nullptr) cdo_sys_error(array_name, "No Memory!"); } @@ -101,18 +100,15 @@ VarQuaSum(double *Variance, const double *restrict Sum, int len, int n) } static void -AddVector(double *dest, const double *src, size_t len, size_t *nmiss, double missval) +AddVector(double *dest, const double *src, size_t len, size_t *numMissVals, double missval) { - if (*nmiss) + if (*numMissVals) { array_add_array_mv(len, dest, src, missval); - *nmiss = array_num_mv(len, dest, missval); - if (*nmiss == 0) *nmiss = 1; - } - else - { - array_add_array(len, dest, src); + *numMissVals = array_num_mv(len, dest, missval); + if (*numMissVals == 0) *numMissVals = 1; } + else { array_add_array(len, dest, src); } } static void @@ -128,9 +124,9 @@ Sub2Vectors(double *dest, const double *restrict srcA, const double *restrict sr } static void -MultVectorScalar(double *dest, const double *restrict src, double factor, size_t len, size_t nmiss, double missval) +MultVectorScalar(double *dest, const double *restrict src, double factor, size_t len, size_t numMissVals, double missval) { - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < len; ++i) dest[i] = (IS_EQUAL(src[i], missval)) ? missval : src[i] * factor; } @@ -141,16 +137,16 @@ MultVectorScalar(double *dest, const double *restrict src, double factor, size_t } static void -DivVectorIvector(double *dest, const double *restrict src, const int *samp, size_t len, size_t *nmiss, double missval) +DivVectorIvector(double *dest, const double *restrict src, const int *samp, size_t len, size_t *numMissVals, double missval) { - *nmiss = 0; + *numMissVals = 0; for (size_t i = 0; i < len; ++i) { if (IS_EQUAL(src[i], missval) || samp[i] == 0) { dest[i] = missval; - *nmiss = *nmiss + 1; + *numMissVals = *numMissVals + 1; } else dest[i] = src[i] / samp[i]; @@ -178,7 +174,7 @@ after_gp2sp(const AfterControl &globs, struct Variable *vars, int ccode) } var->spectral = alloc_dp(globs.Dim3SP, "gp2sp.spectral"); - fc2sp(var->fourier, var->spectral, globs.pold, var->hlev, globs.Latitudes, globs.Fouriers, globs.Truncation); + fc2sp(var->fourier, var->spectral, globs.pold.data(), var->hlev, globs.Latitudes, globs.Fouriers, globs.Truncation); } } @@ -190,8 +186,8 @@ after_GP2FC(double *gp, double *fc, long nlat, long nlon, long nlev, long nfc) if (ifax[9] != nlon) { - if (trig) Free(trig); - trig = (double *) Malloc(nlon * sizeof(double)); + if (trig) free(trig); + trig = (double *) malloc(nlon * sizeof(double)); int status = fft_set(trig, ifax, nlon); if (status < 0) exit(1); } @@ -207,8 +203,8 @@ after_FC2GP(double *fc, double *gp, long nlat, long nlon, long nlev, long nfc) if (ifax[9] != nlon) { - if (trig) Free(trig); - trig = (double *) Malloc(nlon * sizeof(double)); + if (trig) free(trig); + trig = (double *) malloc(nlon * sizeof(double)); int status = fft_set(trig, ifax, nlon); if (status < 0) exit(1); } @@ -221,9 +217,6 @@ after_FC2GP(double *fc, double *gp, long nlat, long nlon, long nlev, long nfc) static void sh2rh(int AnalysisData, double *sphum, double *rhum, double *t, int lev, int dimgpout, const double *level, double *fullpresshybrid) { - int lpi, lfp; - double es, qsatr; - /* ***************************************************** */ /* Define constants for calculation in presence of water */ /* ***************************************************** */ @@ -253,8 +246,8 @@ sh2rh(int AnalysisData, double *sphum, double *rhum, double *t, int lev, int dim { for (int i = 0; i < dimgpout; ++i) { - lpi = lp * dimgpout + i; - lfp = (1 - AnalysisData) * lpi + AnalysisData * lp; + auto lpi = lp * dimgpout + i; + auto lfp = (1 - AnalysisData) * lpi + AnalysisData * lp; /* if (t[lpi] < C_RTT) { RGAM = RGAMS; RBET = RBETS; RALP = RALPS; @@ -262,9 +255,9 @@ sh2rh(int AnalysisData, double *sphum, double *rhum, double *t, int lev, int dim RGAM = RGAMW; RBET = RBETW; RALP = RALPW; } */ - es = (std::exp(RALP - RBET / t[lpi] - RGAM * std::log(t[lpi]))) / fullp[lfp]; + auto es = (std::exp(RALP - RBET / t[lpi] - RGAM * std::log(t[lpi]))) / fullp[lfp]; // qsat = es / (1. + C_RETV * (1. - es)); - qsatr = (1. + C_RETV * (1. - es)) / es; + auto qsatr = (1. + C_RETV * (1. - es)) / es; rhum[lpi] = sphum[lpi] * 100. * qsatr; } } @@ -273,9 +266,6 @@ sh2rh(int AnalysisData, double *sphum, double *rhum, double *t, int lev, int dim static void rh2sh(double *sphum, double *rhum, double *t, int lev, int dimgpout, const double *level) { - int lpi; - double es, qsat; - /* ***************************************************** */ /* Define constants for calculation in presence of water */ /* ***************************************************** */ @@ -303,14 +293,14 @@ rh2sh(double *sphum, double *rhum, double *t, int lev, int dimgpout, const doubl { for (int i = 0; i < dimgpout; ++i) { - lpi = lp * dimgpout + i; + auto lpi = lp * dimgpout + i; /* if (t[lpi] < C_RTT) { */ /* RGAM = RGAMS; RBET = RBETS; RALP = RALPS; */ /* } else { */ /* RGAM = RGAMW; RBET = RBETW; RALP = RALPW; */ /* } */ - es = (std::exp(RALP - RBET / t[lpi] - RGAM * std::log(t[lpi]))) / level[lp]; - qsat = es / (1. + C_RETV * (1. - es)); + auto es = (std::exp(RALP - RBET / t[lpi] - RGAM * std::log(t[lpi]))) / level[lp]; + auto qsat = es / (1. + C_RETV * (1. - es)); sphum[lpi] = rhum[lpi] * qsat / 100.; } } @@ -334,34 +324,36 @@ after_FCrh2FCsh(const AfterControl &globs, struct Variable *vars) after_GP2FC(vars[HUMIDITY].grid, vars[HUMIDITY].fourier, globs.Latitudes, globs.Longitudes, vars[HUMIDITY].plev, globs.Fouriers); - vars[HUMIDITY].grid = (double *) FreeMemory(vars[HUMIDITY].grid); - vars[RHUMIDITY].grid = (double *) FreeMemory(vars[RHUMIDITY].grid); - vars[TEMPERATURE].grid = (double *) FreeMemory(vars[TEMPERATURE].grid); + FreeMemory(vars[HUMIDITY].grid); + FreeMemory(vars[RHUMIDITY].grid); + FreeMemory(vars[TEMPERATURE].grid); } void after_SPuv2SPdv(const AfterControl &globs, struct Variable *vars) { - double *Div, *DivOut, *Vor, *VorOut; + auto numLevels = globs.NumLevelRequest; + auto numLats = globs.Latitudes; - Div = DivOut = vars[DIVERGENCE].spectral; - Vor = VorOut = vars[VORTICITY].spectral; - auto fieldSize = globs.DimFC * globs.NumLevelRequest; + auto Div = vars[DIVERGENCE].spectral; + auto Vor = vars[VORTICITY].spectral; + auto DivOut = Div; + auto VorOut = Vor; + auto fieldSize = globs.DimFC * numLevels; - if (vars[U_WIND].fourier == nullptr) vars[U_WIND].fourier = alloc_dp(fieldSize, "vars[U_WIND].fourier"); - if (vars[V_WIND].fourier == nullptr) vars[V_WIND].fourier = alloc_dp(fieldSize, "vars[V_WIND].fourier"); + auto &u_wind = vars[U_WIND]; + auto &v_wind = vars[V_WIND]; + if (u_wind.fourier == nullptr) u_wind.fourier = alloc_dp(fieldSize, "u_wind.fourier"); + if (v_wind.fourier == nullptr) v_wind.fourier = alloc_dp(fieldSize, "v_wind.fourier"); - sp2fc(vars[U_WIND].spectral, vars[U_WIND].fourier, globs.poli, globs.NumLevelRequest, globs.Latitudes, globs.Fouriers, - globs.Truncation); - sp2fc(vars[V_WIND].spectral, vars[V_WIND].fourier, globs.poli, globs.NumLevelRequest, globs.Latitudes, globs.Fouriers, - globs.Truncation); - uv2dv(vars[U_WIND].fourier, vars[V_WIND].fourier, Div, Vor, globs.pol2, globs.pol3, globs.NumLevelRequest, globs.Latitudes, - globs.Truncation); + sp2fc(u_wind.spectral, u_wind.fourier, globs.poli.data(), numLevels, numLats, globs.Fouriers, globs.Truncation); + sp2fc(v_wind.spectral, v_wind.fourier, globs.poli.data(), numLevels, numLats, globs.Fouriers, globs.Truncation); + uv2dv(u_wind.fourier, v_wind.fourier, Div, Vor, globs.pol2.data(), globs.pol3.data(), numLevels, numLats, globs.Truncation); - vars[U_WIND].fourier = (double *) FreeMemory(vars[U_WIND].fourier); - vars[V_WIND].fourier = (double *) FreeMemory(vars[V_WIND].fourier); + FreeMemory(u_wind.fourier); + FreeMemory(v_wind.fourier); - for (int i = 0; i < globs.NumLevelRequest; ++i) + for (int i = 0; i < numLevels; ++i) { sp2sp(Div, globs.Truncation, DivOut, globs.Truncation); sp2sp(Vor, globs.Truncation, VorOut, globs.Truncation); @@ -391,9 +383,9 @@ after_FCsh2FCrh(const AfterControl &globs, struct Variable *vars) after_GP2FC(vars[RHUMIDITY].grid, vars[RHUMIDITY].fourier, globs.Latitudes, globs.Longitudes, vars[RHUMIDITY].plev, globs.Fouriers); - vars[HUMIDITY].grid = (double *) FreeMemory(vars[HUMIDITY].grid); - vars[RHUMIDITY].grid = (double *) FreeMemory(vars[RHUMIDITY].grid); - vars[TEMPERATURE].grid = (double *) FreeMemory(vars[TEMPERATURE].grid); + FreeMemory(vars[HUMIDITY].grid); + FreeMemory(vars[RHUMIDITY].grid); + FreeMemory(vars[TEMPERATURE].grid); } /* ENDE HUMTEST */ @@ -481,8 +473,8 @@ after_processPL(AfterControl &globs, struct Variable *vars) vars[U_WIND].spectral = alloc_dp(globs.DimSP * globs.NumLevelRequest, "vars[U_WIND].spectral"); if (vars[V_WIND].spectral == nullptr) vars[V_WIND].spectral = alloc_dp(globs.DimSP * globs.NumLevelRequest, "vars[V_WIND].spectral"); - dv2uv(vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, vars[U_WIND].spectral, vars[V_WIND].spectral, globs.dv2uv_f1, - globs.dv2uv_f2, globs.Truncation, globs.DimSP, globs.NumLevelRequest); + dv2uv(vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, vars[U_WIND].spectral, vars[V_WIND].spectral, + globs.dv2uv_f1.data(), globs.dv2uv_f2.data(), globs.Truncation, globs.DimSP, globs.NumLevelRequest); } if (vars[VELOPOT].comp) @@ -544,13 +536,13 @@ after_processPL(AfterControl &globs, struct Variable *vars) auto fieldSize = vars[code].plev * globs.DimFC; vars[code].fourier = alloc_dp(fieldSize, FieldName(code, "fourier")); } - sp2fc(vars[code].spectral, vars[code].fourier, globs.poli, vars[code].plev, globs.Latitudes, globs.Fouriers, + sp2fc(vars[code].spectral, vars[code].fourier, globs.poli.data(), vars[code].plev, globs.Latitudes, globs.Fouriers, globs.Truncation); } if (vars[U_WIND].needed && vars[U_WIND].fourier) - scaluv(vars[U_WIND].fourier, globs.rcoslat, globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); + scaluv(vars[U_WIND].fourier, globs.rcoslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); if (vars[V_WIND].needed && vars[V_WIND].fourier) - scaluv(vars[V_WIND].fourier, globs.rcoslat, globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); + scaluv(vars[V_WIND].fourier, globs.rcoslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); /* HUMTEST */ if (globs.Type < 70 && vars[HUMIDITY].needed && vars[HUMIDITY].fourier == nullptr) @@ -698,15 +690,15 @@ after_processPL(AfterControl &globs, struct Variable *vars) if (globs.MeanCount == 1) array_copy(fieldSize, vars[code].grid, vars[code].mean); else - AddVector(vars[code].mean, vars[code].grid, fieldSize, &vars[code].nmiss, vars[code].missval); + AddVector(vars[code].mean, vars[code].grid, fieldSize, &vars[code].numMissVals, vars[code].missval); if (globs.EndOfInterval) { if (vars[code].samp == nullptr) - MultVectorScalar(vars[code].mean, vars[code].mean, 1.0 / globs.MeanCount, fieldSize, vars[code].nmiss, + MultVectorScalar(vars[code].mean, vars[code].mean, 1.0 / globs.MeanCount, fieldSize, vars[code].numMissVals, vars[code].missval); else - DivVectorIvector(vars[code].mean, vars[code].mean, vars[code].samp, fieldSize, &vars[code].nmiss, + DivVectorIvector(vars[code].mean, vars[code].mean, vars[code].samp, fieldSize, &vars[code].numMissVals, vars[code].missval); } } @@ -751,12 +743,12 @@ after_processPL(AfterControl &globs, struct Variable *vars) if (globs.Mean != 2) { streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].mean + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].mean + offset, vars[code].numMissVals); } if (globs.Mean >= 2) { streamDefRecord(globs.ostreamID2, vars[code].ovarID2, k); - streamWriteRecord(globs.ostreamID2, vars[code].variance + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID2, vars[code].variance + offset, vars[code].numMissVals); } } } @@ -780,7 +772,7 @@ after_processPL(AfterControl &globs, struct Variable *vars) { auto offset = k * globs.DimGP; streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].grid + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].grid + offset, vars[code].numMissVals); } } @@ -790,12 +782,13 @@ after_processPL(AfterControl &globs, struct Variable *vars) } static void -theta(double *pthetaf, double *pthetah, double *ph, double *ps, double *tf, double *ts, int levels, int dimgp, int dim3gp) +theta(double *pthetaf, double *pthetah, const double *ph, const double *ps, const double *tf, const double *ts, int levels, + int dimgp, int dim3gp) { - double *thetah = pthetah; - double *thetaf = pthetaf; + auto thetah = pthetah; + auto thetaf = pthetaf; - double kappa = PlanetRD / C_RCPD; + auto kappa = PlanetRD / C_RCPD; for (int h = 0; h < dimgp; h++) thetah[h] = 0.0; thetah += dimgp; @@ -820,75 +813,67 @@ windSpeed(double *uvspeed, double *u, double *v, int dim3gp) } static void -Omega(double *omega_in, double *divergence, double *u_wind, double *v_wind, double *halfpress, double *fullpress, double *dpsdx, - double *dpsdy, double *vct, int dimgp, int nlev) +Omega(double *omega_in, const double *divergence, const double *u_wind, const double *v_wind, const double *halfpress, + const double *fullpress, double *dpsdx, const double *dpsdy, const double *vct, int dimgp, int nlev) { - double DeltaHybrid, Cterm, Pterm; - double *diver, *halfp, *fullp, *uwind, *vwind; - double *omega = omega_in; - // Compute half level part of vertical velocity - for (int i = 0; i < dimgp; ++i) omega[i] = 0.0; + for (int i = 0; i < dimgp; ++i) omega_in[i] = 0.0; for (int j = 0; j < nlev; ++j) { - omega = omega_in + j * dimgp; - halfp = halfpress + j * dimgp; - diver = divergence + j * dimgp; - uwind = u_wind + j * dimgp; - vwind = v_wind + j * dimgp; + auto omega = omega_in + j * dimgp; + const auto halfp = halfpress + j * dimgp; + const auto diver = divergence + j * dimgp; + const auto uwind = u_wind + j * dimgp; + const auto vwind = v_wind + j * dimgp; - DeltaHybrid = vct[nlev + j + 2] - vct[nlev + j + 1]; + auto deltaHybrid = vct[nlev + j + 2] - vct[nlev + j + 1]; for (int i = 0; i < dimgp; ++i) { omega[i + dimgp] - = omega[i] - diver[i] * (halfp[i + dimgp] - halfp[i]) - DeltaHybrid * (uwind[i] * dpsdx[i] + vwind[i] * dpsdy[i]); + = omega[i] - diver[i] * (halfp[i + dimgp] - halfp[i]) - deltaHybrid * (uwind[i] * dpsdx[i] + vwind[i] * dpsdy[i]); } } - /* interpolate to full levels */ + // interpolate to full levels for (int j = 0; j < nlev; ++j) { - omega = omega_in + j * dimgp; + auto omega = omega_in + j * dimgp; for (int i = 0; i < dimgp; ++i) omega[i] = 0.5 * (omega[i] + omega[i + dimgp]); } - /* compute full level part of vertical velocity */ + // compute full level part of vertical velocity #ifdef _OPENMP -#pragma omp parallel for default(shared) private(omega, halfp, fullp, uwind, vwind, DeltaHybrid, Cterm, Pterm) +#pragma omp parallel for default(shared) #endif for (int j = 0; j < nlev; ++j) { - omega = omega_in + j * dimgp; - halfp = halfpress + j * dimgp; - fullp = fullpress + j * dimgp; - uwind = u_wind + j * dimgp; - vwind = v_wind + j * dimgp; + auto omega = omega_in + j * dimgp; + const auto halfp = halfpress + j * dimgp; + const auto fullp = fullpress + j * dimgp; + const auto uwind = u_wind + j * dimgp; + const auto vwind = v_wind + j * dimgp; - DeltaHybrid = vct[nlev + j + 2] - vct[nlev + j + 1]; - if (std::fabs(DeltaHybrid) > 0) + auto deltaHybrid = vct[nlev + j + 2] - vct[nlev + j + 1]; + if (std::fabs(deltaHybrid) > 0) { - Cterm = vct[j + 1] * vct[nlev + j + 1] - vct[j] * vct[nlev + j + 2]; + auto cterm = vct[j + 1] * vct[nlev + j + 1] - vct[j] * vct[nlev + j + 2]; + auto ctermIsValid = is_not_equal(cterm, 0.0); for (int i = 0; i < dimgp; ++i) { - if (is_not_equal(Cterm, 0.0)) - Pterm = Cterm / (halfp[i + dimgp] - halfp[i]) * std::log(halfp[i + dimgp] / halfp[i]); - else - Pterm = 0.0; - + auto pterm = ctermIsValid ? cterm / (halfp[i + dimgp] - halfp[i]) * std::log(halfp[i + dimgp] / halfp[i]) : 0.0; omega[i] - += fullp[i] * (uwind[i] * dpsdx[i] + vwind[i] * dpsdy[i]) / (halfp[i + dimgp] - halfp[i]) * (DeltaHybrid + Pterm); + += fullp[i] * (uwind[i] * dpsdx[i] + vwind[i] * dpsdy[i]) / (halfp[i + dimgp] - halfp[i]) * (deltaHybrid + pterm); } } } } void -geopot_height_halflevel(double *gheight, const double *const ta_fl, const double *const hus_fl, const double *const p_hl, long ngp, - long nlev) +geopot_height_half(double *gheight, const double *ta_fl, const double *hus_fl, const double *p_hl, long ngp, long nlev) { // Computes geopotential height on half level @@ -904,11 +889,11 @@ geopot_height_halflevel(double *gheight, const double *const ta_fl, const double { for (long k = nlev; k > 1; k--) { - long offset = ngp * (k - 1); - double *gh = gheight + offset; - const double *const p = p_hl + offset; - const double *const ta = ta_fl + offset; - const double *const hus = hus_fl + offset; + auto offset = ngp * (k - 1); + auto gh = gheight + offset; + const auto p = p_hl + offset; + const auto ta = ta_fl + offset; + const auto hus = hus_fl + offset; for (long i = 0; i < ngp; ++i) gh[i] = gh[i + ngp] + PlanetRD * ta[i] * (1.0 + vtmp * hus[i]) * std::log(p[i + ngp] / p[i]); } @@ -920,10 +905,10 @@ geopot_height_halflevel(double *gheight, const double *const ta_fl, const double { for (long k = nlev; k > 1; k--) { - long offset = ngp * (k - 1); - double *gh = gheight + offset; - const double *const p = p_hl + offset; - const double *const ta = ta_fl + offset; + auto offset = ngp * (k - 1); + auto gh = gheight + offset; + const auto p = p_hl + offset; + const auto ta = ta_fl + offset; for (long i = 0; i < ngp; ++i) gh[i] = gh[i + ngp] + PlanetRD * ta[i] * std::log(p[i + ngp] / p[i]); } @@ -936,8 +921,7 @@ geopot_height_halflevel(double *gheight, const double *const ta_fl, const double } void -geopot_height_fulllevel(double *gheight, const double *const ta_fl, const double *const hus_fl, const double *const p_hl, long ngp, - long nlev) +geopot_height_full(double *gheight, const double *ta_fl, const double *hus_fl, const double *p_hl, long ngp, long nlev) { // Computes geopotential height on full level @@ -953,11 +937,11 @@ geopot_height_fulllevel(double *gheight, const double *const ta_fl, const double { for (long k = nlev; k > 1; k--) { - long offset = ngp * (k - 1); - double *gh = gheight + offset; - const double *const p = p_hl + offset; - const double *const ta = ta_fl + offset; - const double *const hus = hus_fl + offset; + auto offset = ngp * (k - 1); + auto gh = gheight + offset; + const auto p = p_hl + offset; + const auto ta = ta_fl + offset; + const auto hus = hus_fl + offset; for (long i = 0; i < ngp; ++i) gh[i] = gh[i + ngp] + PlanetRD * ta[i] * (1.0 + vtmp * hus[i]) * std::log(p[i + ngp] / p[i]); } @@ -969,9 +953,9 @@ geopot_height_fulllevel(double *gheight, const double *const ta_fl, const double { long offset = ngp * k; double *gh = gheight + offset; - const double *const p = p_hl + offset; - const double *const ta = ta_fl + offset; - const double *const hus = hus_fl + offset; + const auto p = p_hl + offset; + const auto ta = ta_fl + offset; + const auto hus = hus_fl + offset; for (long i = 0; i < ngp; ++i) gh[i] = gh[i + ngp] + PlanetRD * ta[i] * (1.0 + vtmp * hus[i]) * (1.0 - (p[i] / (p[i + ngp] - p[i])) * std::log(p[i + ngp] / p[i])); @@ -981,10 +965,10 @@ geopot_height_fulllevel(double *gheight, const double *const ta_fl, const double { for (long k = nlev; k > 1; k--) { - long offset = ngp * (k - 1); - double *gh = gheight + offset; - const double *const p = p_hl + offset; - const double *const ta = ta_fl + offset; + auto offset = ngp * (k - 1); + auto gh = gheight + offset; + const auto p = p_hl + offset; + const auto ta = ta_fl + offset; for (long i = 0; i < ngp; ++i) gh[i] = gh[i + ngp] + PlanetRD * ta[i] * std::log(p[i + ngp] / p[i]); } @@ -993,10 +977,10 @@ geopot_height_fulllevel(double *gheight, const double *const ta_fl, const double for (long k = 1; k < nlev; ++k) { - long offset = ngp * k; - double *gh = gheight + offset; - const double *const p = p_hl + offset; - const double *const ta = ta_fl + offset; + auto offset = ngp * k; + auto gh = gheight + offset; + const auto p = p_hl + offset; + const auto ta = ta_fl + offset; for (long i = 0; i < ngp; ++i) gh[i] = gh[i + ngp] + PlanetRD * ta[i] * (1.0 - (p[i] / (p[i + ngp] - p[i])) * std::log(p[i + ngp] / p[i])); } @@ -1013,7 +997,7 @@ constexpr double SCALESLP = 101325.0; /* ======================================== */ void -LayerWater(double *ww, double *ll, double pmax, double pmin, int DimGP, int HalfLevels, double *vct) +LayerWater(double *ww, double *ll, double pmax, double pmin, int DimGP, int HalfLevels, const double *vct) { double pph[MaxLevel]{}; @@ -1026,7 +1010,7 @@ LayerWater(double *ww, double *ll, double pmax, double pmin, int DimGP, int Half if (pph[k] < pmin) break; auto MinLev = k; - varray_fill(DimGP, ll, 0.0); + ranges::fill_n(ll, DimGP, 0.0); for (k = MaxLev; k <= MinLev; ++k) { @@ -1040,7 +1024,7 @@ LayerWater(double *ww, double *ll, double pmax, double pmin, int DimGP, int Half /* ================================================= */ void -LayerCloud(double *cc, double *ll, double pmax, double pmin, int DimGP, int HalfLevels, double *vct) +LayerCloud(double *cc, double *ll, double pmax, double pmin, int DimGP, int HalfLevels, const double *vct) { double pph[MaxLevel]{}; constexpr double ZEPSEC = 1.0e-12; @@ -1081,43 +1065,46 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) if (vars[HALF_PRESS].hybrid == nullptr) vars[HALF_PRESS].hybrid = alloc_dp(globs.Dim3GP + globs.DimGP, "vars[HALF_PRESS].hybrid"); - vct_to_hybrid_pressure(vars[FULL_PRESS].hybrid, vars[HALF_PRESS].hybrid, globs.vct, vars[PS_PROG].hybrid, globs.NumLevel, - globs.DimGP); + vct_to_hybrid_pressure(vars[FULL_PRESS].hybrid, vars[HALF_PRESS].hybrid, globs.vct.data(), vars[PS_PROG].hybrid, + globs.NumLevel, globs.DimGP); } - if (globs.unitsel > 2) vars[FULL_PRESS].hybrid = (double *) FreeMemory(vars[FULL_PRESS].hybrid); + if (globs.unitsel > 2) FreeMemory(vars[FULL_PRESS].hybrid); if (vars[THETAF].needed) { - vars[THETAF].hlev = globs.NumLevel; - vars[THETAF].plev = globs.NumLevelRequest; - vars[THETAF].sfit = true; - if (vars[THETAF].hybrid == nullptr) vars[THETAF].hybrid = alloc_dp(globs.Dim3GP, "vars[THETAF].hybrid"); + auto &thetaf = vars[THETAF]; + thetaf.hlev = globs.NumLevel; + thetaf.plev = globs.NumLevelRequest; + thetaf.sfit = true; + if (thetaf.hybrid == nullptr) thetaf.hybrid = alloc_dp(globs.Dim3GP, "vars[THETAF].hybrid"); if (vars[THETAH].hybrid == nullptr) vars[THETAH].hybrid = alloc_dp(globs.Dim3GP, "vars[THETAH].hybrid"); - theta(vars[THETAF].hybrid, vars[THETAH].hybrid, vars[HALF_PRESS].hybrid, vars[PS_PROG].hybrid, vars[TEMPERATURE].hybrid, + theta(thetaf.hybrid, vars[THETAH].hybrid, vars[HALF_PRESS].hybrid, vars[PS_PROG].hybrid, vars[TEMPERATURE].hybrid, vars[TS].hybrid, globs.NumLevel, globs.DimGP, globs.Dim3GP); } if (vars[GEOPOTHEIGHT].comp) { - vars[GEOPOTHEIGHT].hlev = globs.NumLevel + 1; - vars[GEOPOTHEIGHT].plev = globs.NumLevelRequest; - vars[GEOPOTHEIGHT].sfit = true; - vars[GEOPOTHEIGHT].hybrid = alloc_dp(globs.Dim3GP + globs.DimGP, "vars[GEOPOTHEIGHT].hybrid"); + auto &geopotheight = vars[GEOPOTHEIGHT]; + geopotheight.hlev = globs.NumLevel + 1; + geopotheight.plev = globs.NumLevelRequest; + geopotheight.sfit = true; + geopotheight.hybrid = alloc_dp(globs.Dim3GP + globs.DimGP, "vars[GEOPOTHEIGHT].hybrid"); - array_copy(globs.DimGP, globs.Orography, vars[GEOPOTHEIGHT].hybrid + globs.Dim3GP); - geopot_height_fulllevel(vars[GEOPOTHEIGHT].hybrid, vars[TEMPERATURE].hybrid, vars[HUMIDITY].hybrid, vars[HALF_PRESS].hybrid, - globs.DimGP, globs.NumLevel); + array_copy(globs.DimGP, globs.orography.data(), geopotheight.hybrid + globs.Dim3GP); + geopot_height_half(geopotheight.hybrid, vars[TEMPERATURE].hybrid, vars[HUMIDITY].hybrid, vars[HALF_PRESS].hybrid, globs.DimGP, + globs.NumLevel); vars[HUMIDITY].needed = vars[HUMIDITY].selected; } else if (vars[GEOPOTHEIGHT].hybrid && vars[GEOPOTHEIGHT].hlev == globs.NumLevel) { - vars[GEOPOTHEIGHT].hlev = globs.NumLevel + 1; - vars[GEOPOTHEIGHT].sfit = true; - vars[GEOPOTHEIGHT].hybrid = (double *) Realloc(vars[GEOPOTHEIGHT].hybrid, (globs.Dim3GP + globs.DimGP) * sizeof(double)); - array_copy(globs.DimGP, globs.Orography, vars[GEOPOTHEIGHT].hybrid + globs.Dim3GP); - for (int i = 0; i < globs.DimGP; ++i) vars[GEOPOTHEIGHT].hybrid[globs.Dim3GP + i] /= PlanetGrav; + auto &geopotheight = vars[GEOPOTHEIGHT]; + geopotheight.hlev = globs.NumLevel + 1; + geopotheight.sfit = true; + geopotheight.hybrid = (double *) realloc(geopotheight.hybrid, (globs.Dim3GP + globs.DimGP) * sizeof(double)); + array_copy(globs.DimGP, globs.orography.data(), geopotheight.hybrid + globs.Dim3GP); + for (int i = 0; i < globs.DimGP; ++i) geopotheight.hybrid[globs.Dim3GP + i] /= PlanetGrav; } if (vars[DPSDX].needed || vars[DPSDY].needed) @@ -1129,13 +1116,14 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) if (vars[OMEGA].comp) { - vars[OMEGA].hlev = globs.NumLevel + 1; - vars[OMEGA].plev = globs.NumLevelRequest; - vars[OMEGA].sfit = true; - vars[OMEGA].hybrid = alloc_dp(globs.Dim3GP + globs.DimGP, "OMEGA.hybrid"); + auto &omega = vars[OMEGA]; + omega.hlev = globs.NumLevel + 1; + omega.plev = globs.NumLevelRequest; + omega.sfit = true; + omega.hybrid = alloc_dp(globs.Dim3GP + globs.DimGP, "omega.hybrid"); - Omega(vars[OMEGA].hybrid, vars[DIVERGENCE].hybrid, vars[U_WIND].hybrid, vars[V_WIND].hybrid, vars[HALF_PRESS].hybrid, - vars[FULL_PRESS].hybrid, vars[DPSDX].hybrid, vars[DPSDY].hybrid, globs.vct, globs.DimGP, globs.NumLevel); + Omega(omega.hybrid, vars[DIVERGENCE].hybrid, vars[U_WIND].hybrid, vars[V_WIND].hybrid, vars[HALF_PRESS].hybrid, + vars[FULL_PRESS].hybrid, vars[DPSDX].hybrid, vars[DPSDY].hybrid, globs.vct.data(), globs.DimGP, globs.NumLevel); vars[DPSDX].needed = vars[DPSDX].selected; vars[DPSDY].needed = vars[DPSDY].selected; @@ -1143,23 +1131,25 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) if (vars[WINDSPEED].comp) { - vars[WINDSPEED].hlev = globs.NumLevel; - vars[WINDSPEED].plev = globs.NumLevelRequest; - vars[WINDSPEED].sfit = true; - vars[WINDSPEED].hybrid = alloc_dp(globs.Dim3GP, "vars[WINDSPEED].hybrid"); + auto &windspeed = vars[WINDSPEED]; + windspeed.hlev = globs.NumLevel; + windspeed.plev = globs.NumLevelRequest; + windspeed.sfit = true; + windspeed.hybrid = alloc_dp(globs.Dim3GP, "windspeed.hybrid"); - windSpeed(vars[WINDSPEED].hybrid, vars[U_WIND].hybrid, vars[V_WIND].hybrid, globs.Dim3GP); + windSpeed(windspeed.hybrid, vars[U_WIND].hybrid, vars[V_WIND].hybrid, globs.Dim3GP); } if (vars[RHUMIDITY].comp) { - vars[RHUMIDITY].hlev = globs.NumLevel; - vars[RHUMIDITY].plev = globs.NumLevelRequest; - vars[RHUMIDITY].sfit = false; - vars[RHUMIDITY].hybrid = alloc_dp(globs.Dim3GP, "vars[RHUMIDITY].hybrid"); + auto &rhumidity = vars[RHUMIDITY]; + rhumidity.hlev = globs.NumLevel; + rhumidity.plev = globs.NumLevelRequest; + rhumidity.sfit = false; + rhumidity.hybrid = alloc_dp(globs.Dim3GP, "rhumidity.hybrid"); - sh2rh(globs.AnalysisData, vars[HUMIDITY].hybrid, vars[RHUMIDITY].hybrid, vars[TEMPERATURE].hybrid, globs.NumLevel, - globs.DimGP, globs.LevelRequest, vars[FULL_PRESS].hybrid); + sh2rh(globs.AnalysisData, vars[HUMIDITY].hybrid, rhumidity.hybrid, vars[TEMPERATURE].hybrid, globs.NumLevel, globs.DimGP, + globs.LevelRequest, vars[FULL_PRESS].hybrid); vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; vars[HUMIDITY].needed = vars[HUMIDITY].selected; @@ -1167,86 +1157,93 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) if (vars[PS].comp) { - vars[PS].hlev = 1; - vars[PS].plev = 1; - vars[PS].sfit = true; // ??? - vars[PS].hybrid = alloc_dp(globs.DimGP, "vars[PS].hybrid"); - for (int l = 0; l < globs.DimGP; ++l) vars[PS].hybrid[l] = std::exp(vars[LNPS].hybrid[l]); + auto &ps = vars[PS]; + ps.hlev = 1; + ps.plev = 1; + ps.sfit = true; // ??? + ps.hybrid = alloc_dp(globs.DimGP, "ps.hybrid"); + for (int l = 0; l < globs.DimGP; ++l) ps.hybrid[l] = std::exp(vars[LNPS].hybrid[l]); } if (vars[SLP].comp) { - vars[SLP].hlev = 1; - vars[SLP].plev = 1; - vars[SLP].sfit = true; - vars[SLP].hybrid = alloc_dp(globs.DimGP, "vars[SLP].hybrid"); + auto &slp = vars[SLP]; + slp.hlev = 1; + slp.plev = 1; + slp.sfit = true; + slp.hybrid = alloc_dp(globs.DimGP, "slp.hybrid"); - extrapolate_P(vars[SLP].hybrid, vars[HALF_PRESS].hybrid + globs.Dim3GP, vars[FULL_PRESS].hybrid + globs.Dim3GP - globs.DimGP, - globs.Orography, vars[TEMPERATURE].hybrid + globs.Dim3GP - globs.DimGP, globs.DimGP); + extrapolate_P(slp.hybrid, vars[HALF_PRESS].hybrid + globs.Dim3GP, vars[FULL_PRESS].hybrid + globs.Dim3GP - globs.DimGP, + globs.orography.data(), vars[TEMPERATURE].hybrid + globs.Dim3GP - globs.DimGP, globs.DimGP); vars[TEMPERATURE].needed = vars[TEMPERATURE].selected || vars[GEOPOTHEIGHT].selected; } if (vars[PRECIP].comp) { - vars[PRECIP].hlev = vars[PRECIP].plev = 1; - vars[PRECIP].sfit = false; - vars[PRECIP].hybrid = alloc_dp(globs.DimGP, "PRECIP.hybrid"); - Add2Vectors(vars[PRECIP].hybrid, vars[142].hybrid, vars[143].hybrid, globs.DimGP); + auto &precip = vars[PRECIP]; + precip.hlev = precip.plev = 1; + precip.sfit = false; + precip.hybrid = alloc_dp(globs.DimGP, "precip.hybrid"); + Add2Vectors(precip.hybrid, vars[142].hybrid, vars[143].hybrid, globs.DimGP); } if (vars[NET_TOP].comp) { - vars[NET_TOP].hlev = vars[NET_TOP].plev = 1; - vars[NET_TOP].sfit = false; - vars[NET_TOP].hybrid = alloc_dp(globs.DimGP, "NET_TOP.hybrid"); - Add2Vectors(vars[NET_TOP].hybrid, vars[178].hybrid, vars[179].hybrid, globs.DimGP); + auto &net_top = vars[NET_TOP]; + net_top.hlev = net_top.plev = 1; + net_top.sfit = false; + net_top.hybrid = alloc_dp(globs.DimGP, "net_top.hybrid"); + Add2Vectors(net_top.hybrid, vars[178].hybrid, vars[179].hybrid, globs.DimGP); } if (vars[NET_BOT].comp) { - vars[NET_BOT].hlev = vars[NET_BOT].plev = 1; - vars[NET_BOT].sfit = false; - vars[NET_BOT].hybrid = alloc_dp(globs.DimGP, "NET_BOT.hybrid"); - Add2Vectors(vars[NET_BOT].hybrid, vars[176].hybrid, vars[177].hybrid, globs.DimGP); + auto &net_bot = vars[NET_BOT]; + net_bot.hlev = net_bot.plev = 1; + net_bot.sfit = false; + net_bot.hybrid = alloc_dp(globs.DimGP, "net_bot.hybrid"); + Add2Vectors(net_bot.hybrid, vars[176].hybrid, vars[177].hybrid, globs.DimGP); } if (vars[NET_HEAT].comp) { - vars[NET_HEAT].hlev = vars[NET_HEAT].plev = 1; - vars[NET_HEAT].sfit = false; - vars[NET_HEAT].hybrid = alloc_dp(globs.DimGP, "NET_HEAT.hybrid"); + auto &net_heat = vars[NET_HEAT]; + net_heat.hlev = net_heat.plev = 1; + net_heat.sfit = false; + net_heat.hybrid = alloc_dp(globs.DimGP, "net_heat.hybrid"); /* - if (Source == S_ECHAM5) + if (Source == ECHAM5_Source) { - MultVectorScalar(vars[NET_HEAT].hybrid, vars[218].hybrid, (-3.345e5), globs.DimGP, vars[218].nmiss, vars[218].missval); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[176].hybrid, globs.DimGP); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[177].hybrid, globs.DimGP); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[146].hybrid, globs.DimGP); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[147].hybrid, globs.DimGP); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[206].hybrid, globs.DimGP); - Sub2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[208].hybrid, globs.DimGP); - Sub2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[209].hybrid, globs.DimGP); + MultVectorScalar(net_heat.hybrid, vars[218].hybrid, (-3.345e5), globs.DimGP, vars[218].numMissVals, vars[218].missval); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[176].hybrid, globs.DimGP); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[177].hybrid, globs.DimGP); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[146].hybrid, globs.DimGP); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[147].hybrid, globs.DimGP); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[206].hybrid, globs.DimGP); + Sub2Vectors(net_heat.hybrid, net_heat.hybrid, vars[208].hybrid, globs.DimGP); + Sub2Vectors(net_heat.hybrid, net_heat.hybrid, vars[209].hybrid, globs.DimGP); } else */ { - MultVectorScalar(vars[NET_HEAT].hybrid, vars[218].hybrid, C_TIMES_RHOH2O, globs.DimGP, vars[218].nmiss, vars[218].missval); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[176].hybrid, globs.DimGP); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[177].hybrid, globs.DimGP); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[146].hybrid, globs.DimGP); - Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[147].hybrid, globs.DimGP); - Sub2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[220].hybrid, globs.DimGP); + MultVectorScalar(net_heat.hybrid, vars[218].hybrid, C_TIMES_RHOH2O, globs.DimGP, vars[218].numMissVals, vars[218].missval); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[176].hybrid, globs.DimGP); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[177].hybrid, globs.DimGP); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[146].hybrid, globs.DimGP); + Add2Vectors(net_heat.hybrid, net_heat.hybrid, vars[147].hybrid, globs.DimGP); + Sub2Vectors(net_heat.hybrid, net_heat.hybrid, vars[220].hybrid, globs.DimGP); } } if (vars[NET_WATER].comp) { - vars[NET_WATER].hlev = vars[NET_WATER].plev = 1; - vars[NET_WATER].sfit = false; - vars[NET_WATER].hybrid = alloc_dp(globs.DimGP, "NET_WATER.hybrid"); - Sub2Vectors(vars[NET_WATER].hybrid, vars[182].hybrid, vars[160].hybrid, globs.DimGP); - Add2Vectors(vars[NET_WATER].hybrid, vars[NET_WATER].hybrid, vars[142].hybrid, globs.DimGP); - Add2Vectors(vars[NET_WATER].hybrid, vars[NET_WATER].hybrid, vars[143].hybrid, globs.DimGP); + auto &net_water = vars[NET_WATER]; + net_water.hlev = net_water.plev = 1; + net_water.sfit = false; + net_water.hybrid = alloc_dp(globs.DimGP, "net_water.hybrid"); + Sub2Vectors(net_water.hybrid, vars[182].hybrid, vars[160].hybrid, globs.DimGP); + Add2Vectors(net_water.hybrid, net_water.hybrid, vars[142].hybrid, globs.DimGP); + Add2Vectors(net_water.hybrid, net_water.hybrid, vars[143].hybrid, globs.DimGP); } if (vars[LOW_WATER].comp) @@ -1254,7 +1251,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) vars[LOW_WATER].hlev = vars[LOW_WATER].plev = 1; vars[LOW_WATER].sfit = false; vars[LOW_WATER].hybrid = alloc_dp(globs.DimGP, "vars[LOW_WATER].hybrid"); - LayerWater(vars[222].hybrid, vars[LOW_WATER].hybrid, 75000., 101300., globs.DimGP, globs.HalfLevels, globs.vct); + LayerWater(vars[222].hybrid, vars[LOW_WATER].hybrid, 75000., 101300., globs.DimGP, globs.HalfLevels, globs.vct.data()); } if (vars[MID_WATER].comp) @@ -1262,7 +1259,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) vars[MID_WATER].hlev = vars[MID_WATER].plev = 1; vars[MID_WATER].sfit = false; vars[MID_WATER].hybrid = alloc_dp(globs.DimGP, "vars[MID_WATER].hybrid"); - LayerWater(vars[222].hybrid, vars[MID_WATER].hybrid, 46000., 73000., globs.DimGP, globs.HalfLevels, globs.vct); + LayerWater(vars[222].hybrid, vars[MID_WATER].hybrid, 46000., 73000., globs.DimGP, globs.HalfLevels, globs.vct.data()); } if (vars[HIH_WATER].comp) @@ -1270,7 +1267,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) vars[HIH_WATER].hlev = vars[HIH_WATER].plev = 1; vars[HIH_WATER].sfit = false; vars[HIH_WATER].hybrid = alloc_dp(globs.DimGP, "vars[HIH_WATER].hybrid"); - LayerWater(vars[222].hybrid, vars[HIH_WATER].hybrid, 5000., 44000., globs.DimGP, globs.HalfLevels, globs.vct); + LayerWater(vars[222].hybrid, vars[HIH_WATER].hybrid, 5000., 44000., globs.DimGP, globs.HalfLevels, globs.vct.data()); } if (vars[ALL_WATER].comp) @@ -1278,7 +1275,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) vars[ALL_WATER].hlev = vars[ALL_WATER].plev = 1; vars[ALL_WATER].sfit = false; vars[ALL_WATER].hybrid = alloc_dp(globs.DimGP, "vars[ALL_WATER].hybrid"); - LayerWater(vars[222].hybrid, vars[ALL_WATER].hybrid, 5000., 101300., globs.DimGP, globs.HalfLevels, globs.vct); + LayerWater(vars[222].hybrid, vars[ALL_WATER].hybrid, 5000., 101300., globs.DimGP, globs.HalfLevels, globs.vct.data()); } if (vars[LOW_CLOUD].comp) @@ -1286,7 +1283,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) vars[LOW_CLOUD].hlev = vars[LOW_CLOUD].plev = 1; vars[LOW_CLOUD].sfit = false; vars[LOW_CLOUD].hybrid = alloc_dp(globs.DimGP, "vars[LOW_CLOUD].hybrid"); - LayerCloud(vars[223].hybrid, vars[LOW_CLOUD].hybrid, 75000., 101300., globs.DimGP, globs.HalfLevels, globs.vct); + LayerCloud(vars[223].hybrid, vars[LOW_CLOUD].hybrid, 75000., 101300., globs.DimGP, globs.HalfLevels, globs.vct.data()); } if (vars[MID_CLOUD].comp) @@ -1294,7 +1291,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) vars[MID_CLOUD].hlev = vars[MID_CLOUD].plev = 1; vars[MID_CLOUD].sfit = false; vars[MID_CLOUD].hybrid = alloc_dp(globs.DimGP, "vars[MID_CLOUD].hybrid"); - LayerCloud(vars[223].hybrid, vars[MID_CLOUD].hybrid, 46000., 73000., globs.DimGP, globs.HalfLevels, globs.vct); + LayerCloud(vars[223].hybrid, vars[MID_CLOUD].hybrid, 46000., 73000., globs.DimGP, globs.HalfLevels, globs.vct.data()); } if (vars[HIH_CLOUD].comp) @@ -1302,7 +1299,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) vars[HIH_CLOUD].hlev = vars[HIH_CLOUD].plev = 1; vars[HIH_CLOUD].sfit = false; vars[HIH_CLOUD].hybrid = alloc_dp(globs.DimGP, "vars[HIH_CLOUD].hybrid"); - LayerCloud(vars[223].hybrid, vars[HIH_CLOUD].hybrid, 5000., 44000., globs.DimGP, globs.HalfLevels, globs.vct); + LayerCloud(vars[223].hybrid, vars[HIH_CLOUD].hybrid, 5000., 44000., globs.DimGP, globs.HalfLevels, globs.vct.data()); } if (vars[SW_CLF].comp) @@ -1410,7 +1407,7 @@ after_EchamCompGP(const AfterControl &globs, struct Variable *vars) } static void -Derivate(double field[], double derilam[], long nlevels, long Waves, long Latitudes, double DerivationFactor[]) +Derivate(double field[], double derilam[], long nlevels, long Waves, long Latitudes, const Varray<double> &derivationFactor) { long i = 0; for (long lev = 0; lev < nlevels; lev++) @@ -1418,12 +1415,12 @@ Derivate(double field[], double derilam[], long nlevels, long Waves, long Latitu { for (long l = 0; l < Latitudes; ++l) { - derilam[i] = -n * field[i + Latitudes] * DerivationFactor[l]; + derilam[i] = -n * field[i + Latitudes] * derivationFactor[l]; i++; } for (long l = 0; l < Latitudes; ++l) { - derilam[i] = n * field[i - Latitudes] * DerivationFactor[l]; + derilam[i] = n * field[i - Latitudes] * derivationFactor[l]; i++; } } @@ -1434,7 +1431,7 @@ void after_processML(AfterControl &globs, struct Variable *vars) { int leveltype; - size_t nmiss; + size_t numMissVals; double *pressureLevel = nullptr; globs.MeanCount++; @@ -1463,8 +1460,8 @@ after_processML(AfterControl &globs, struct Variable *vars) if (vars[DIVERGENCE].spectral == nullptr) after_gp2sp(globs, vars, DIVERGENCE); if (vars[VORTICITY].spectral == nullptr) after_gp2sp(globs, vars, VORTICITY); - dv2uv(vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, vars[U_WIND].spectral, vars[V_WIND].spectral, globs.dv2uv_f1, - globs.dv2uv_f2, globs.Truncation, globs.DimSP, vars[DIVERGENCE].hlev); + dv2uv(vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, vars[U_WIND].spectral, vars[V_WIND].spectral, + globs.dv2uv_f1.data(), globs.dv2uv_f2.data(), globs.Truncation, globs.DimSP, vars[DIVERGENCE].hlev); } if (vars[VELOPOT].comp && globs.Type < 30) @@ -1489,11 +1486,8 @@ after_processML(AfterControl &globs, struct Variable *vars) dv2ps(vars[VORTICITY].spectral, vars[STREAM].spectral, vars[VORTICITY].hlev, globs.Truncation); } - if (vars[VORTICITY].spectral && !vars[VORTICITY].needed) - vars[VORTICITY].spectral = (double *) FreeMemory(vars[VORTICITY].spectral); - - if (vars[DIVERGENCE].spectral && !vars[DIVERGENCE].needed) - vars[DIVERGENCE].spectral = (double *) FreeMemory(vars[DIVERGENCE].spectral); + if (!vars[VORTICITY].needed) FreeMemory(vars[VORTICITY].spectral); + if (!vars[DIVERGENCE].needed) FreeMemory(vars[DIVERGENCE].spectral); /* --------------------------- */ /* Output of spectral fields */ @@ -1532,16 +1526,16 @@ after_processML(AfterControl &globs, struct Variable *vars) { auto fieldSize = vars[code].hlev * globs.DimFC; vars[code].fourier = alloc_dp(fieldSize, FieldName(code, "fourier")); - sp2fc(vars[code].spectral, vars[code].fourier, globs.poli, vars[code].hlev, globs.Latitudes, globs.Fouriers, + sp2fc(vars[code].spectral, vars[code].fourier, globs.poli.data(), vars[code].hlev, globs.Latitudes, globs.Fouriers, globs.Truncation); } - if (code != LNPS) vars[code].spectral = (double *) FreeMemory(vars[code].spectral); + if (code != LNPS) FreeMemory(vars[code].spectral); } if (vars[U_WIND].needed && vars[U_WIND].fourier) - scaluv(vars[U_WIND].fourier, globs.rcoslat, globs.Latitudes, globs.Fouriers * globs.NumLevel); + scaluv(vars[U_WIND].fourier, globs.rcoslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevel); if (vars[V_WIND].needed && vars[V_WIND].fourier) - scaluv(vars[V_WIND].fourier, globs.rcoslat, globs.Latitudes, globs.Fouriers * globs.NumLevel); + scaluv(vars[V_WIND].fourier, globs.rcoslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevel); if (vars[DPSDX].needed) { @@ -1550,7 +1544,7 @@ after_processML(AfterControl &globs, struct Variable *vars) vars[DPSDX].sfit = false; vars[DPSDX].fourier = alloc_dp(globs.DimFC, "vars[DPSDX].fourier"); if (vars[LNPS].fourier == nullptr) after_gp2sp(globs, vars, LNPS); - Derivate(vars[LNPS].fourier, vars[DPSDX].fourier, 1, globs.Waves, globs.Latitudes, globs.DerivationFactor); + Derivate(vars[LNPS].fourier, vars[DPSDX].fourier, 1, globs.Waves, globs.Latitudes, globs.derivationFactor); } if (vars[DPSDY].needed) { @@ -1559,7 +1553,7 @@ after_processML(AfterControl &globs, struct Variable *vars) vars[DPSDY].sfit = false; vars[DPSDY].fourier = alloc_dp(globs.DimFC, "vars[DPSDY].fourier"); if (vars[LNPS].spectral == nullptr) after_gp2sp(globs, vars, LNPS); - sp2fc(vars[LNPS].spectral, vars[DPSDY].fourier, globs.pdev, vars[DPSDY].hlev, globs.Latitudes, globs.Fouriers, + sp2fc(vars[LNPS].spectral, vars[DPSDY].fourier, globs.pdev.data(), vars[DPSDY].hlev, globs.Latitudes, globs.Fouriers, globs.Truncation); } } @@ -1630,7 +1624,7 @@ after_processML(AfterControl &globs, struct Variable *vars) after_FC2GP(vars[code].fourier, vars[code].hybrid, globs.Latitudes, globs.Longitudes, vars[code].hlev, globs.Fouriers); } - vars[code].fourier = (double *) FreeMemory(vars[code].fourier); + FreeMemory(vars[code].fourier); } if (vars[PS_PROG].comp && vars[PS_PROG].hybrid == nullptr) @@ -1645,24 +1639,21 @@ after_processML(AfterControl &globs, struct Variable *vars) cdo_warning("log surface pressure (code 152) not found - using surface pressure (code 134)!"); array_copy(globs.DimGP, vars[PS].hybrid, vars[PS_PROG].hybrid); } - else - { - afterAbort("surface pressure not found!"); - } + else { afterAbort("surface pressure not found!"); } } vars[LNPS].needed = vars[LNPS].selected; - if (globs.Orography == nullptr) + if (globs.orography.size() == 0) { - globs.Orography = alloc_dp(globs.DimGP, "Orography"); + globs.orography.resize(globs.DimGP); if (vars[GEOPOTENTIAL].hybrid) - array_copy(globs.DimGP, vars[GEOPOTENTIAL].hybrid, globs.Orography); + array_copy(globs.DimGP, vars[GEOPOTENTIAL].hybrid, globs.orography.data()); else { if (vars[GEOPOTENTIAL].selected || globs.Type >= 30) { cdo_warning("Orography not found - using zero orography!"); - varray_fill(globs.DimGP, globs.Orography, 0.0); + ranges::fill(globs.orography, 0.0); } } } @@ -1699,17 +1690,17 @@ after_processML(AfterControl &globs, struct Variable *vars) } else { - AddVector(vars[code].mean, vars[code].hybrid, fieldSize, &vars[code].nmiss, vars[code].missval); + AddVector(vars[code].mean, vars[code].hybrid, fieldSize, &vars[code].numMissVals, vars[code].missval); if (globs.Mean > 1) AddQuaSum(vars[code].variance, vars[code].hybrid, fieldSize); } if (globs.EndOfInterval) { if (vars[code].samp == nullptr) - MultVectorScalar(vars[code].hybrid, vars[code].mean, 1.0 / globs.MeanCount, fieldSize, vars[code].nmiss, - vars[code].missval); + MultVectorScalar(vars[code].hybrid, vars[code].mean, 1.0 / globs.MeanCount, fieldSize, + vars[code].numMissVals, vars[code].missval); else - DivVectorIvector(vars[code].hybrid, vars[code].mean, vars[code].samp, fieldSize, &vars[code].nmiss, + DivVectorIvector(vars[code].hybrid, vars[code].mean, vars[code].samp, fieldSize, &vars[code].numMissVals, vars[code].missval); if (globs.Mean > 1) VarQuaSum(vars[code].variance, vars[code].hybrid, fieldSize, globs.MeanCount); @@ -1736,12 +1727,12 @@ after_processML(AfterControl &globs, struct Variable *vars) if (globs.Mean != 2) { streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].hybrid + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].hybrid + offset, vars[code].numMissVals); } if (globs.Mean >= 2) { streamDefRecord(globs.ostreamID2, vars[code].ovarID2, k); - streamWriteRecord(globs.ostreamID2, vars[code].variance + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID2, vars[code].variance + offset, vars[code].numMissVals); } } } @@ -1759,27 +1750,26 @@ after_processML(AfterControl &globs, struct Variable *vars) if (globs.Type >= 30) { - if (globs.vertIndex == nullptr) globs.vertIndex = (int *) Malloc(globs.NumLevelRequest * globs.DimGP * sizeof(int)); + if (globs.vertIndex.size() == 0) globs.vertIndex.resize(globs.NumLevelRequest * globs.DimGP); if (globs.unitsel) { - if (globs.p_of_height == nullptr) globs.p_of_height = alloc_dp(globs.NumLevelRequest, "p_of_height"); - height_to_pressure(globs.LevelRequest, globs.p_of_height, globs.NumLevelRequest); - pressureLevel = globs.p_of_height; - } - else - { - pressureLevel = globs.LevelRequest; + if (globs.p_of_height.size() == 0) globs.p_of_height.resize(globs.NumLevelRequest); + height_to_pressure(globs.LevelRequest, globs.p_of_height.data(), globs.NumLevelRequest); + pressureLevel = globs.p_of_height.data(); } + else { pressureLevel = globs.LevelRequest; } - gen_vert_index(globs.vertIndex, pressureLevel, vars[FULL_PRESS].hybrid, globs.DimGP, globs.NumLevelRequest, globs.NumLevel); + gen_vert_index(globs.vertIndex.data(), pressureLevel, vars[FULL_PRESS].hybrid, globs.DimGP, globs.NumLevelRequest, + globs.NumLevel); - nmiss = 0; + numMissVals = 0; if (!globs.extrapolate) { - if (globs.pnmiss == nullptr) globs.pnmiss = (size_t *) Malloc(globs.NumLevelRequest * sizeof(size_t)); - gen_vert_index_mv(globs.vertIndex, pressureLevel, globs.DimGP, globs.NumLevelRequest, vars[PS_PROG].hybrid, globs.pnmiss); - for (int i = 0; i < globs.NumLevelRequest; ++i) nmiss += globs.pnmiss[i]; + Varray<size_t> pnumMissVals(globs.NumLevelRequest); + gen_vert_index_mv(globs.vertIndex.data(), pressureLevel, globs.DimGP, globs.NumLevelRequest, vars[PS_PROG].hybrid, + pnumMissVals.data()); + for (int i = 0; i < globs.NumLevelRequest; ++i) numMissVals += pnumMissVals[i]; } for (int code = 0; code < MaxCodes; ++code) @@ -1788,7 +1778,7 @@ after_processML(AfterControl &globs, struct Variable *vars) leveltype = zaxisInqType(vars[code].izaxisID); if (vars[code].hlev == 1 || leveltype != ZAXIS_HYBRID || (vars[code].hlev < globs.NumLevel)) { - if (vars[code].grid) FreeMemory(vars[code].grid); + FreeMemory(vars[code].grid); vars[code].grid = vars[code].hybrid; vars[code].hybrid = nullptr; } @@ -1802,16 +1792,17 @@ after_processML(AfterControl &globs, struct Variable *vars) if (code == TEMPERATURE) { - vertical_interp_T(globs.Orography, vars[TEMPERATURE].hybrid, vars[TEMPERATURE].grid, vars[FULL_PRESS].hybrid, - vars[HALF_PRESS].hybrid, globs.vertIndex, pressureLevel, globs.NumLevelRequest, globs.DimGP, - globs.NumLevel, vars[code].missval); + vertical_interp_T(globs.orography.data(), vars[TEMPERATURE].hybrid, vars[TEMPERATURE].grid, + vars[FULL_PRESS].hybrid, vars[HALF_PRESS].hybrid, globs.vertIndex.data(), pressureLevel, + globs.NumLevelRequest, globs.DimGP, globs.NumLevel, vars[code].missval); } else if (code == GEOPOTHEIGHT) { if (vars[TEMPERATURE].hybrid == nullptr) afterAbort("Code 130 not found!"); - vertical_interp_Z(globs.Orography, vars[GEOPOTHEIGHT].hybrid, vars[GEOPOTHEIGHT].grid, vars[FULL_PRESS].hybrid, - vars[HALF_PRESS].hybrid, globs.vertIndex, vars[TEMPERATURE].hybrid, pressureLevel, - globs.NumLevelRequest, globs.DimGP, globs.NumLevel, vars[code].missval); + vertical_interp_Z(globs.orography.data(), vars[GEOPOTHEIGHT].hybrid, vars[GEOPOTHEIGHT].grid, + vars[FULL_PRESS].hybrid, vars[HALF_PRESS].hybrid, globs.vertIndex.data(), + vars[TEMPERATURE].hybrid, pressureLevel, globs.NumLevelRequest, globs.DimGP, globs.NumLevel, + vars[code].missval); } else { @@ -1820,20 +1811,20 @@ after_processML(AfterControl &globs, struct Variable *vars) double *hyb_press = vars[FULL_PRESS].hybrid; if (numlevel == (globs.NumLevel + 1)) hyb_press = vars[HALF_PRESS].hybrid; - vertical_interp_X(vars[code].hybrid, vars[code].grid, hyb_press, globs.vertIndex, pressureLevel, + vertical_interp_X(vars[code].hybrid, vars[code].grid, hyb_press, globs.vertIndex.data(), pressureLevel, globs.NumLevelRequest, globs.DimGP, numlevel, vars[code].missval); } - if (!globs.extrapolate) vars[code].nmiss = nmiss; + if (!globs.extrapolate) vars[code].numMissVals = numMissVals; - if (code != TEMPERATURE) vars[code].hybrid = (double *) FreeMemory(vars[code].hybrid); + if (code != TEMPERATURE) FreeMemory(vars[code].hybrid); } } } vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; FreeHybrid(vars); - if (vars[HALF_PRESS].hybrid) vars[HALF_PRESS].hybrid = (double *) FreeMemory(vars[HALF_PRESS].hybrid); + FreeMemory(vars[HALF_PRESS].hybrid); /* -------------------------------- */ /* Output of pressure level grids */ @@ -1851,7 +1842,7 @@ after_processML(AfterControl &globs, struct Variable *vars) { auto offset = k * globs.DimGP; streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].grid + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].grid + offset, vars[code].numMissVals); } } } @@ -1875,15 +1866,15 @@ after_processML(AfterControl &globs, struct Variable *vars) if (globs.MeanCount == 1) array_copy(fieldSize, vars[code].grid, vars[code].mean); else - AddVector(vars[code].mean, vars[code].grid, fieldSize, &vars[code].nmiss, vars[code].missval); + AddVector(vars[code].mean, vars[code].grid, fieldSize, &vars[code].numMissVals, vars[code].missval); if (globs.EndOfInterval) { if (vars[code].samp == nullptr) - MultVectorScalar(vars[code].mean, vars[code].mean, 1.0 / globs.MeanCount, fieldSize, vars[code].nmiss, + MultVectorScalar(vars[code].mean, vars[code].mean, 1.0 / globs.MeanCount, fieldSize, vars[code].numMissVals, vars[code].missval); else - DivVectorIvector(vars[code].mean, vars[code].mean, vars[code].samp, fieldSize, &vars[code].nmiss, + DivVectorIvector(vars[code].mean, vars[code].mean, vars[code].samp, fieldSize, &vars[code].numMissVals, vars[code].missval); } } @@ -1930,12 +1921,12 @@ after_processML(AfterControl &globs, struct Variable *vars) if (globs.Mean != 2) { streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].mean + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].mean + offset, vars[code].numMissVals); } if (globs.Mean >= 2) { streamDefRecord(globs.ostreamID2, vars[code].ovarID2, k); - streamWriteRecord(globs.ostreamID2, vars[code].variance + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID2, vars[code].variance + offset, vars[code].numMissVals); } } } @@ -1953,8 +1944,8 @@ after_processML(AfterControl &globs, struct Variable *vars) for (int code = 0; code < MaxCodes; ++code) if (vars[code].mean) { - if (vars[code].variance) vars[code].variance = (double *) FreeMemory(vars[code].variance); - if (vars[code].grid) vars[code].grid = (double *) FreeMemory(vars[code].grid); + FreeMemory(vars[code].variance); + FreeMemory(vars[code].grid); vars[code].grid = vars[code].mean; vars[code].mean = nullptr; } @@ -1968,7 +1959,7 @@ after_processML(AfterControl &globs, struct Variable *vars) for (int code = 0; code < MaxCodes; ++code) if (vars[code].needed && vars[code].grid && (vars[code].sfit || globs.Type < 70)) { - if (vars[code].nmiss) afterAbort("Missing values for code %d unsupported with TYPE > 30!", code); + if (vars[code].numMissVals) afterAbort("Missing values for code %d unsupported with TYPE > 30!", code); if (vars[code].fourier == nullptr) { @@ -1978,12 +1969,12 @@ after_processML(AfterControl &globs, struct Variable *vars) after_GP2FC(vars[code].grid, vars[code].fourier, globs.Latitudes, globs.Longitudes, vars[code].plev, globs.Fouriers); - if (vars[code].grid && (vars[code].sfit || globs.Type < 70)) vars[code].grid = (double *) FreeMemory(vars[code].grid); + if (vars[code].sfit || globs.Type < 70) FreeMemory(vars[code].grid); } } for (int code = 0; code < MaxCodes; ++code) - if (vars[code].grid && (vars[code].sfit || globs.Type < 70)) vars[code].grid = (double *) FreeMemory(vars[code].grid); + if (vars[code].sfit || globs.Type < 70) FreeMemory(vars[code].grid); /* -------------------------- */ /* Output of fourier fields */ @@ -2001,7 +1992,7 @@ after_processML(AfterControl &globs, struct Variable *vars) { auto offset = k * globs.DimFC; streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].fourier + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].fourier + offset, vars[code].numMissVals); } } @@ -2025,7 +2016,7 @@ after_processML(AfterControl &globs, struct Variable *vars) { auto offset = k * globs.DimFC; streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].fourier + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].fourier + offset, vars[code].numMissVals); } } @@ -2040,9 +2031,9 @@ after_processML(AfterControl &globs, struct Variable *vars) if (globs.Type >= 50) { if (vars[U_WIND].needed && vars[U_WIND].fourier) - scaluv(vars[U_WIND].fourier, globs.coslat, globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); + scaluv(vars[U_WIND].fourier, globs.coslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); if (vars[V_WIND].needed && vars[V_WIND].fourier) - scaluv(vars[V_WIND].fourier, globs.coslat, globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); + scaluv(vars[V_WIND].fourier, globs.coslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); for (int code = 0; code < MaxCodes; ++code) if (vars[code].needed && vars[code].fourier) @@ -2053,7 +2044,7 @@ after_processML(AfterControl &globs, struct Variable *vars) vars[code].spectral = alloc_dp(fieldSize, FieldName(code, "spectral")); } - fc2sp(vars[code].fourier, vars[code].spectral, globs.pold, vars[code].plev, globs.Latitudes, globs.Fouriers, + fc2sp(vars[code].fourier, vars[code].spectral, globs.pold.data(), vars[code].plev, globs.Latitudes, globs.Fouriers, globs.Truncation); } @@ -2065,8 +2056,8 @@ after_processML(AfterControl &globs, struct Variable *vars) vars[VORTICITY].spectral = alloc_dp(globs.DimSP * globs.NumLevelRequest, "vars[VORTICITY].spectral"); if ((vars[U_WIND].fourier == 0 || vars[V_WIND].fourier == 0) && globs.NumLevelRequest) afterAbort("uwind or vwind missing!"); - uv2dv(vars[U_WIND].fourier, vars[V_WIND].fourier, vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, globs.pol2, - globs.pol3, globs.NumLevelRequest, globs.Latitudes, globs.Truncation); + uv2dv(vars[U_WIND].fourier, vars[V_WIND].fourier, vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, globs.pol2.data(), + globs.pol3.data(), globs.NumLevelRequest, globs.Latitudes, globs.Truncation); } if (vars[VELOPOT].needed) @@ -2091,7 +2082,7 @@ after_processML(AfterControl &globs, struct Variable *vars) } for (int code = 0; code < MaxCodes; ++code) - if (vars[code].fourier && (vars[code].sfit || globs.Type < 61)) vars[code].fourier = (double *) FreeMemory(vars[code].fourier); + if (vars[code].sfit || globs.Type < 61) FreeMemory(vars[code].fourier); /* --------------------------- */ /* Output of spectral fields */ @@ -2129,13 +2120,13 @@ after_processML(AfterControl &globs, struct Variable *vars) auto fieldSize = vars[code].plev * globs.DimFC; vars[code].fourier = alloc_dp(fieldSize, FieldName(code, "fourier")); } - sp2fc(vars[code].spectral, vars[code].fourier, globs.poli, vars[code].plev, globs.Latitudes, globs.Fouriers, + sp2fc(vars[code].spectral, vars[code].fourier, globs.poli.data(), vars[code].plev, globs.Latitudes, globs.Fouriers, globs.Truncation); } if (vars[U_WIND].needed && vars[U_WIND].fourier) - scaluv(vars[U_WIND].fourier, globs.rcoslat, globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); + scaluv(vars[U_WIND].fourier, globs.rcoslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); if (vars[V_WIND].needed && vars[V_WIND].fourier) - scaluv(vars[V_WIND].fourier, globs.rcoslat, globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); + scaluv(vars[V_WIND].fourier, globs.rcoslat.data(), globs.Latitudes, globs.Fouriers * globs.NumLevelRequest); } FreeSpectral(vars); @@ -2180,7 +2171,7 @@ after_processML(AfterControl &globs, struct Variable *vars) { auto offset = k * globs.DimFC; streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].fourier + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].fourier + offset, vars[code].numMissVals); } } @@ -2220,7 +2211,7 @@ after_processML(AfterControl &globs, struct Variable *vars) { auto offset = k * globs.DimGP; streamDefRecord(globs.ostreamID, vars[code].ovarID, k); - streamWriteRecord(globs.ostreamID, vars[code].grid + offset, vars[code].nmiss); + streamWriteRecord(globs.ostreamID, vars[code].grid + offset, vars[code].numMissVals); } } @@ -2232,7 +2223,7 @@ after_processML(AfterControl &globs, struct Variable *vars) void after_AnalysisAddRecord(const AfterControl *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, - size_t nmiss) + size_t numMissVals) { int truncation; @@ -2243,7 +2234,7 @@ after_AnalysisAddRecord(const AfterControl *globs, struct Variable *vars, int co auto dataSize = gridSize * nlevel; auto dataOffset = gridSize * levelID; - vars[code].nmiss0 += nmiss; + vars[code].numMissVals0 += numMissVals; if (gridtype == GRID_SPECTRAL) { @@ -2257,13 +2248,13 @@ after_AnalysisAddRecord(const AfterControl *globs, struct Variable *vars, int co auto fieldSize = globs->Dim3SP; if (vars[code].spectral0 == nullptr) vars[code].spectral0 = alloc_dp(fieldSize, FieldName(code, "spectral")); truncation = gridInqTrunc(gridID); - sp2sp(globs->Field, truncation, vars[code].spectral0 + levelID * globs->DimSP, globs->Truncation); + sp2sp(globs->varray.data(), truncation, vars[code].spectral0 + levelID * globs->DimSP, globs->Truncation); } else { auto fieldSize = globs->Dim3SP; if (vars[code].spectral0 == nullptr) vars[code].spectral0 = alloc_dp(fieldSize, FieldName(code, "spectral")); - array_copy(globs->DimSP, globs->Field, vars[code].spectral0 + levelID * globs->DimSP); + array_copy(globs->DimSP, globs->varray.data(), vars[code].spectral0 + levelID * globs->DimSP); } } else @@ -2278,7 +2269,7 @@ after_AnalysisAddRecord(const AfterControl *globs, struct Variable *vars, int co vars[code].hlev = globs->NumLevelRequest; vars[code].plev = globs->NumLevelRequest; if (vars[code].grid0 == nullptr) vars[code].grid0 = alloc_dp(fieldSize, FieldName(code, "grid0")); - array_copy(globs->DimGP, globs->Field, vars[code].grid0 + levelID * globs->DimGP); + array_copy(globs->DimGP, globs->varray.data(), vars[code].grid0 + levelID * globs->DimGP); } else { @@ -2287,19 +2278,19 @@ after_AnalysisAddRecord(const AfterControl *globs, struct Variable *vars, int co vars[code].hlev = 1; vars[code].plev = 1; if (vars[code].grid0 == nullptr) vars[code].grid0 = alloc_dp(fieldSize, FieldName(code, "grid0")); - array_copy(globs->DimGP, globs->Field, vars[code].grid0); + array_copy(globs->DimGP, globs->varray.data(), vars[code].grid0); } - if (globs->Mean > 0 && (nmiss || vars[code].samp)) + if (globs->Mean > 0 && (numMissVals || vars[code].samp)) { if (vars[code].samp == nullptr) { - vars[code].samp = (int *) Malloc(dataSize * sizeof(int)); + vars[code].samp = (int *) malloc(dataSize * sizeof(int)); for (size_t i = 0; i < dataSize; ++i) vars[code].samp[i] = globs->MeanCount0; } for (size_t i = 0; i < gridSize; ++i) - if (is_not_equal(globs->Field[i], vars[code].missval)) vars[code].samp[i + dataOffset]++; + if (is_not_equal(globs->varray[i], vars[code].missval)) vars[code].samp[i + dataOffset]++; } } } @@ -2332,7 +2323,8 @@ after_get_dataptr(struct Variable *vars, int code, int gridID, int zaxisID, int } void -after_EchamAddRecord(const AfterControl *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, size_t nmiss) +after_EchamAddRecord(const AfterControl *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, + size_t numMissVals) { auto gridtype = gridInqType(gridID); auto leveltype = zaxisInqType(zaxisID); @@ -2341,7 +2333,7 @@ after_EchamAddRecord(const AfterControl *globs, struct Variable *vars, int code, auto dataSize = gridSize * nlevel; auto dataOffset = gridSize * levelID; - vars[code].nmiss0 += nmiss; + vars[code].numMissVals0 += numMissVals; if (gridtype == GRID_SPECTRAL) { @@ -2364,11 +2356,11 @@ after_EchamAddRecord(const AfterControl *globs, struct Variable *vars, int code, vars[code].sfit = true; } - if (globs->Mean > 0 && (nmiss || vars[code].samp)) + if (globs->Mean > 0 && (numMissVals || vars[code].samp)) { if (vars[code].samp == nullptr) { - vars[code].samp = (int *) Malloc(dataSize * sizeof(int)); + vars[code].samp = (int *) malloc(dataSize * sizeof(int)); for (size_t i = 0; i < dataSize; ++i) vars[code].samp[i] = globs->MeanCount0; } @@ -2412,7 +2404,7 @@ MakeDependencies(struct Variable *vars, int varcode, int depcode) vars[varcode].igridID = vars[depcode].igridID; vars[varcode].ogridID = vars[depcode].ogridID; vars[varcode].izaxisID = vars[depcode].izaxisID; - vars[varcode].ozaxisID = vars[depcode].ozaxisID; + if (varcode != GEOPOTHEIGHT) vars[varcode].ozaxisID = vars[depcode].ozaxisID; } } } @@ -2479,10 +2471,6 @@ CheckDependencies(struct Variable *vars, int analysisdata) MakeDependencies(vars, SW_TOP_CLF, 187); MakeDependencies(vars, LW_TOP_CLF, 179); MakeDependencies(vars, LW_TOP_CLF, 188); - MakeDependencies(vars, NET_TOP_CLF, 178); - MakeDependencies(vars, NET_TOP_CLF, 179); - MakeDependencies(vars, NET_TOP_CLF, 187); - MakeDependencies(vars, NET_TOP_CLF, 188); MakeDependencies(vars, ALL_WATER, 222); MakeDependencies(vars, LOW_WATER, 222); @@ -2580,7 +2568,7 @@ after_EchamDependencies(struct Variable *vars, int ncodes, int type, int source) MakeDependencies(vars, PRECIP, 142); MakeDependencies(vars, PRECIP, 143); - if (source != S_ECHAM5) + if (source != ECHAM5_Source) { MakeDependencies(vars, NET_WATER, 142); MakeDependencies(vars, NET_WATER, 143); @@ -2599,7 +2587,7 @@ after_EchamDependencies(struct Variable *vars, int ncodes, int type, int source) MakeDependencies(vars, NET_HEAT, 177); MakeDependencies(vars, NET_HEAT, 218); /* - if ( source == S_ECHAM5 ) + if ( source == ECHAM5_Source ) { MakeDependencies(vars, NET_HEAT, 206); MakeDependencies(vars, NET_HEAT, 208); @@ -2638,43 +2626,32 @@ after_legini_setup(AfterControl &globs, struct Variable *vars) long dimsp = (ntr + 1) * (ntr + 2); long pdim = (dimsp / 2) * nlat; - globs.poli = (double *) Malloc(pdim * sizeof(double)); + globs.poli.resize(pdim); if (!globs.AnalysisData) { - if (globs.Type >= 20) globs.pold = (double *) Malloc(pdim * sizeof(double)); - if (vars[DPSDY].needed) globs.pdev = (double *) Malloc(pdim * sizeof(double)); + if (globs.Type >= 20) globs.pold.resize(pdim); + if (vars[DPSDY].needed) globs.pdev.resize(pdim); } if ((vars[DIVERGENCE].needed || vars[VORTICITY].needed || vars[VELOPOT].needed || vars[STREAM].needed) && globs.Type > 20) { - globs.pol2 = (double *) Malloc(pdim * sizeof(double)); - globs.pol3 = (double *) Malloc(pdim * sizeof(double)); + globs.pol2.resize(pdim); + globs.pol3.resize(pdim); } if (globs.AnalysisData && (globs.Type == 70) && globs.Gaussian && !globs.Spectral) { - if (globs.poli) - { - Free(globs.poli); - globs.poli = nullptr; - } - if (globs.pol2) - { - Free(globs.pol2); - globs.pol2 = nullptr; - } - if (globs.pol3) - { - Free(globs.pol3); - globs.pol3 = nullptr; - } + if (globs.poli.size()) varray_free(globs.poli); + if (globs.pol2.size()) varray_free(globs.pol2); + if (globs.pol3.size()) varray_free(globs.pol3); return; } - after_legini_full(ntr, nlat, globs.poli, globs.pold, globs.pdev, globs.pol2, globs.pol3, globs.coslat); + after_legini_full(ntr, nlat, globs.poli.data(), globs.pold.data(), globs.pdev.data(), globs.pol2.data(), globs.pol3.data(), + globs.coslat.data()); for (long jgl = 0; jgl < nlat; ++jgl) globs.rcoslat[jgl] = 1.0 / globs.coslat[jgl]; - for (long jgl = 0; jgl < nlat; ++jgl) globs.DerivationFactor[jgl] = globs.rcoslat[jgl] / PlanetRadius; + for (long jgl = 0; jgl < nlat; ++jgl) globs.derivationFactor[jgl] = globs.rcoslat[jgl] / PlanetRadiusDefault; } diff --git a/src/bitinformation.h b/src/bitinformation.h index 6bd8d2e09a1150789ba4d1aaa26e6716a099b582..41d38fe164bd993744a541227788337bd6c28283 100644 --- a/src/bitinformation.h +++ b/src/bitinformation.h @@ -1,6 +1,8 @@ #ifndef BITINFORMATION_H #define BITINFORMATION_H +#include <cstddef> + constexpr int NBITS = 32; // Number of bits in type `float` struct MutualInformation diff --git a/src/cdi_lockedIO.cc b/src/cdi_lockedIO.cc index 823e3b310b535e23cef2dbb69b6a3ea8a3ac1128..862a1bca698db5024388cce93bc0b236dc86e0a5 100644 --- a/src/cdi_lockedIO.cc +++ b/src/cdi_lockedIO.cc @@ -14,14 +14,14 @@ #include <mutex> -static std::mutex streamOpenReadMutex; +static std::mutex streamOpenMutex; static std::mutex streamMutex; int stream_open_read_locked(const char *const p_filename) { open_lock(); - const auto streamID = streamOpenRead(p_filename); + auto streamID = streamOpenRead(p_filename); open_unlock(); if (streamID < 0) cdi_open_error(streamID, "Open failed on >%s<", p_filename); @@ -29,7 +29,7 @@ stream_open_read_locked(const char *const p_filename) } void -stream_close_locked(const int p_fileID) +stream_close_locked(int p_fileID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); streamClose(p_fileID); @@ -37,7 +37,7 @@ stream_close_locked(const int p_fileID) } void -stream_inq_rec_locked(const int p_fileID, int *const p_varID, int *const p_levelID) +stream_inq_rec_locked(int p_fileID, int *const p_varID, int *const p_levelID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); streamInqRecord(p_fileID, p_varID, p_levelID); @@ -45,7 +45,7 @@ stream_inq_rec_locked(const int p_fileID, int *const p_varID, int *const p_level } void -stream_def_rec_locked(const int p_fileID, const int p_varID, const int p_levelID) +stream_def_rec_locked(int p_fileID, int p_varID, int p_levelID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); streamDefRecord(p_fileID, p_varID, p_levelID); @@ -53,23 +53,23 @@ stream_def_rec_locked(const int p_fileID, const int p_varID, const int p_levelID } void -stream_readrecord_float_locked(const int p_fileID, float *const p_data, size_t *const p_nmiss) +stream_readrecord_float_locked(int p_fileID, float *const p_data, size_t *const p_numMissVals) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); - streamReadRecordF(p_fileID, p_data, p_nmiss); + streamReadRecordF(p_fileID, p_data, p_numMissVals); if (Threading::cdoLockIO) cthread_mutex_unlock(streamMutex); } void -stream_readrecord_double_locked(const int p_fileID, double *const p_data, size_t *const p_nmiss) +stream_readrecord_double_locked(int p_fileID, double *const p_data, size_t *const p_numMissVals) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); - streamReadRecord(p_fileID, p_data, p_nmiss); + streamReadRecord(p_fileID, p_data, p_numMissVals); if (Threading::cdoLockIO) cthread_mutex_unlock(streamMutex); } void -stream_def_vlist_locked(const int p_fileID, const int p_vlistID) +stream_def_vlist_locked(int p_fileID, int p_vlistID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); streamDefVlist(p_fileID, p_vlistID); @@ -77,52 +77,52 @@ stream_def_vlist_locked(const int p_fileID, const int p_vlistID) } int -stream_inq_vlist_locked(const int p_fileID) +stream_inq_vlist_locked(int p_fileID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); - const auto vlistID = streamInqVlist(p_fileID); + auto vlistID = streamInqVlist(p_fileID); if (Threading::cdoLockIO) cthread_mutex_unlock(streamMutex); return vlistID; } void -stream_write_record_double_locked(const int p_fileID, const double *const p_data, const size_t p_nmiss) +stream_write_record_double_locked(int p_fileID, const double *const p_data, const size_t p_numMissVals) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); - streamWriteRecord(p_fileID, p_data, p_nmiss); + streamWriteRecord(p_fileID, p_data, p_numMissVals); if (Threading::cdoLockIO) cthread_mutex_unlock(streamMutex); } void -stream_write_record_float_locked(const int p_fileID, const float *const p_data, const size_t p_nmiss) +stream_write_record_float_locked(int p_fileID, const float *const p_data, const size_t p_numMissVals) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); - streamWriteRecordF(p_fileID, p_data, p_nmiss); + streamWriteRecordF(p_fileID, p_data, p_numMissVals); if (Threading::cdoLockIO) cthread_mutex_unlock(streamMutex); } int -stream_inq_time_step_locked(const int p_fileID, const int p_tsID) +stream_inq_time_step_locked(int p_fileID, int p_tsID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); - const auto nrecs = streamInqTimestep(p_fileID, p_tsID); + auto nrecs = streamInqTimestep(p_fileID, p_tsID); if (Threading::cdoLockIO) cthread_mutex_unlock(streamMutex); return nrecs; } int -stream_def_time_step_locked(const int p_fileID, const int p_tsID) +stream_def_time_step_locked(int p_fileID, int p_tsID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); - const auto success = streamDefTimestep(p_fileID, p_tsID); + auto success = streamDefTimestep(p_fileID, p_tsID); if (Threading::cdoLockIO) cthread_mutex_unlock(streamMutex); return success; } int -stream_copy_record_locked(const int p_fileID, const int p_targetFileID) +stream_copy_record_locked(int p_fileID, int p_targetFileID) { if (Threading::cdoLockIO) cthread_mutex_lock(streamMutex); streamCopyRecord(p_fileID, p_targetFileID); @@ -131,7 +131,7 @@ stream_copy_record_locked(const int p_fileID, const int p_targetFileID) } void -vlist_copy_flag_locked(const int p_vlistID2, const int p_vlistID1) +vlist_copy_flag_locked(int p_vlistID2, int p_vlistID1) { cthread_mutex_lock(streamMutex); vlistCopyFlag(p_vlistID2, p_vlistID1); @@ -141,17 +141,17 @@ vlist_copy_flag_locked(const int p_vlistID2, const int p_vlistID1) void open_lock(void) { - cthread_mutex_lock(Threading::cdoLockIO ? streamMutex : streamOpenReadMutex); + cthread_mutex_lock(Threading::cdoLockIO ? streamMutex : streamOpenMutex); } void open_unlock(void) { - cthread_mutex_unlock(Threading::cdoLockIO ? streamMutex : streamOpenReadMutex); + cthread_mutex_unlock(Threading::cdoLockIO ? streamMutex : streamOpenMutex); } void -cdo_vlist_copy_flag(const int vlistID2, const int vlistID1) +cdo_vlist_copy_flag(int vlistID2, int vlistID1) { vlist_copy_flag_locked(vlistID2, vlistID1); } diff --git a/src/cdi_lockedIO.h b/src/cdi_lockedIO.h index 2ea22bb35fd863b692ad2ce475f802232d8a0102..47742ca329f250c061c7d8f23bec218675eb9bac 100644 --- a/src/cdi_lockedIO.h +++ b/src/cdi_lockedIO.h @@ -1,16 +1,18 @@ #ifndef CDI_LOCKEDIO_H #define CDI_LOCKEDIO_H +#include <cstddef> + int stream_open_read_locked(const char *filename); void stream_close_locked(int p_fileID); void stream_inq_rec_locked(int p_fileID, int *p_varID, int *p_levelID); void stream_def_rec_locked(int p_fileID, int p_varID, int levelID); -void stream_readrecord_float_locked(int p_fileID, float *p_data, size_t *p_nmiss); -void stream_readrecord_double_locked(int p_fileID, double *p_data, size_t *p_nmiss); +void stream_readrecord_float_locked(int p_fileID, float *p_data, size_t *p_numMissVals); +void stream_readrecord_double_locked(int p_fileID, double *p_data, size_t *p_numMissVals); void stream_def_vlist_locked(int p_fileID, int p_vlistID); int stream_inq_vlist_locked(int p_fileID); -void stream_write_record_double_locked(int p_fileID, const double *const p_data, size_t p_nmiss); -void stream_write_record_float_locked(int p_fileID, const float *const p_data, size_t p_nmiss); +void stream_write_record_double_locked(int p_fileID, const double *const p_data, size_t p_numMissVals); +void stream_write_record_float_locked(int p_fileID, const float *const p_data, size_t p_numMissVals); int stream_inq_time_step_locked(int p_fileID, int p_tsID); int stream_def_time_step_locked(int p_fileID, int p_tsID); int stream_copy_record_locked(int p_fileID, int p_targetFileID); diff --git a/src/cdo.cc b/src/cdo.cc index 9e19c5defd270c324c099354f4a95de27aff4a1d..09cf0149452afd0f936947d159f62cb78a923946 100644 --- a/src/cdo.cc +++ b/src/cdo.cc @@ -29,8 +29,10 @@ #endif #include <cfenv> #include <sys/stat.h> +#include <sys/resource.h> // getrlimit #include <unistd.h> /* sysconf */ #include <cstring> +#include <cstdlib> #include <csignal> #include <cdi.h> @@ -43,12 +45,12 @@ #include "param_conversion.h" #include "progress.h" -#include "module_list.h" #include "module_info.h" #include "percentiles.h" #include "util_wildcards.h" #include "util_string.h" #include "process_int.h" +#include "processManager.h" #include "cdo_options.h" #include "timer.h" #include "commandline.h" @@ -57,14 +59,13 @@ #include "cdo_features.h" #include "cdo_zaxis.h" #include "compare.h" -#include "dmemory.h" #include "table.h" #include "datetime.h" #include "remap_grid_cell_search.h" #include "cdo_pthread.h" #include "institution.h" -#include "cdo_apply.h" #include "parser.h" +#include "factory.h" static ProcessManager g_processManager; @@ -278,7 +279,7 @@ cdo_usage() */ pad = CLIOptions::pad_size_terminal('='); fprintf(target, "%s\n", pad.c_str()); - fprintf(target, " CDO version %s, Copyright (C) 2002-2023 MPI für Meteorologie\n", VERSION); + fprintf(target, " CDO version %s, Copyright (C) 2002-2024 MPI für Meteorologie\n", VERSION); fprintf(target, " This is free software and comes with ABSOLUTELY NO WARRANTY\n"); fprintf(target, " Report bugs to <https://mpimet.mpg.de/cdo>\n\n"); pad = CLIOptions::pad_size_terminal('='); @@ -301,40 +302,6 @@ cdo_init_is_tty() if (S_ISCHR(statbuf.st_mode)) cdo::stderrIsTerminal = true; } -static void -cdo_print_help(const char **help) -{ - if (!help) - fprintf(stderr, "No help available for this operator!\n"); - else - { - size_t help_size = 0; - while (help[help_size]) help_size++; - for (size_t i = 0; i < help_size; ++i) - { - auto doPrint = !(help[i][0] == '\0' && help[i + 1][0] == ' '); - if (doPrint) - { - if (color_enabled()) - { - if (cdo_cmpstr(help[i], "NAME") || cdo_cmpstr(help[i], "SYNOPSIS") || cdo_cmpstr(help[i], "DESCRIPTION") - || cdo_cmpstr(help[i], "OPERATORS") || cdo_cmpstr(help[i], "NAMELIST") || cdo_cmpstr(help[i], "PARAMETER") - || cdo_cmpstr(help[i], "ENVIRONMENT") || cdo_cmpstr(help[i], "NOTE") || cdo_cmpstr(help[i], "EXAMPLES")) - { - set_text_color(stdout, BRIGHT); - fprintf(stdout, "%s", help[i]); - reset_text_color(stdout); - fprintf(stdout, "\n"); - } - else - fprintf(stdout, "%s\n", help[i]); - } - else { fprintf(stdout, "%s\n", help[i]); } - } - } - } -} - #undef IsBigendian #define IsBigendian() (u_byteorder.c[sizeof(long) - 1]) @@ -763,10 +730,10 @@ print_system_info() fprintf(stderr, "STD ANSI C = %d\n", __STDC__); #endif #ifdef __STD_VERSION__ - fprintf(stderr, "STD VERSION = %ld\n", (long)__STD_VERSION__); + fprintf(stderr, "STD VERSION = %ld\n", (long) __STD_VERSION__); #endif #ifdef __STDC_VERSION__ - fprintf(stderr, "STDC VERSION = %ld\n", (long)__STDC_VERSION__); + fprintf(stderr, "STDC VERSION = %ld\n", (long) __STDC_VERSION__); #endif #ifdef __STD_HOSTED__ fprintf(stderr, "STD HOSTED = %d\n", __STD_HOSTED__); @@ -818,6 +785,8 @@ cdo_set_options() fprintf(stderr, "\n"); } + if (Options::test) cdiDefGlobal("THREADSAFE", 1); + if (Options::CMOR_Mode) cdiDefGlobal("CMOR_MODE", Options::CMOR_Mode); // TODO maybe reposition into effect of "cmor" if (Options::CDO_Reduce_Dim) cdiDefGlobal("REDUCE_DIM", Options::CDO_Reduce_Dim); if (CDO_netcdf_hdr_pad > 0) cdiDefGlobal("NETCDF_HDR_PAD", CDO_netcdf_hdr_pad); @@ -848,7 +817,11 @@ evaluate_except_options(const std::string &arg) // clang-format on return except; } - +/* +#if defined(__APPLE__) && defined(__MACH__) +#include <libproc.h> +#endif +*/ static void cdo_rusage(void) { @@ -869,6 +842,20 @@ cdo_rusage(void) fprintf(stderr, " Swaps: %5ld\n", ru.ru_nswap); fprintf(stderr, " Disk read: %5ld block%s\n", ru.ru_inblock, ADD_PLURAL(ru.ru_inblock)); fprintf(stderr, " Disk Write: %5ld block%s\n", ru.ru_oublock, ADD_PLURAL(ru.ru_oublock)); + /* +#if defined(__APPLE__) && defined(__MACH__) +#ifdef RUSAGE_INFO_CURRENT + pid_t pid = fork(); + rusage_info_current ruinfo; + int rusage_ret = proc_pid_rusage(pid, RUSAGE_INFO_CURRENT, (void **)&ruinfo); + if (rusage_ret >= 0 && ruinfo.ri_lifetime_max_phys_footprint > 0) + { + fprintf(stderr, " Peak memory: %.2f MBytes\n", ruinfo.ri_lifetime_max_phys_footprint / 1.0); + fprintf(stderr, " Peak memory: %.2f MBytes\n", ruinfo.ri_lifetime_max_phys_footprint / (1024.0 * 1024.0)); + } +#endif +#endif + */ } #endif } @@ -930,7 +917,9 @@ static void print_operator_attributes(const std::string &argument) { ModListOptions local_modListOpt; + local_modListOpt.parse_request(argument); + operator_print_list(local_modListOpt); } @@ -983,10 +972,10 @@ predefined_tables(int p_padding) constexpr int id_padding = 4; int padding = p_padding + id_padding; int numTables = tableInqNumber(); - std::string tables = std::string("Predefined tables: "); + std::string tables{"Predefined tables: "}; for (int id = 0; id < numTables; id++) { - if (id % 7 == 6) tables += "\n" + std::string(padding, ' '); + if (id % 7 == 6) tables += std::string("\n") + std::string(padding, ' '); if ((name = tableInqNamePtr(id))) tables += std::string(name); if (id < numTables - 1) tables += ","; } @@ -1050,6 +1039,11 @@ setup_cli_options() }) ->add_effect([&](const std::string &argument) { auto [success, tokens] = tokenize_comma_seperated_int_list(argument); + if (tokens.empty()) + { + print_debug_options(); + exit(EXIT_SUCCESS); + } unsigned cdoDebugLevel = 0; unsigned cdiDebugLevel = 0; @@ -1210,7 +1204,7 @@ setup_cli_options() ->describe_argument("module name") ->set_category("Info") ->add_effect([&](const std::string &argument) { - auto names = get_module_operator_names(argument); + auto names = Factory::get_module_operator_names(argument); if (names.empty()) { std::string errstr = "Module " + argument + " not found\n"; @@ -1252,7 +1246,7 @@ setup_cli_options() CLIOptions::option("help", "h") ->describe_argument("operator") - ->add_effect([&](const std::string &argument) { cdo_print_help(operator_help(argument)); }) + ->add_effect([&](const std::string &operator_name) { cdo_print_help(Factory::get_help(operator_name)); }) ->on_empty_argument([]() { cdo_usage(); }) ->aborts_program(true) ->set_category("Help") @@ -1308,7 +1302,7 @@ setup_cli_options() CLIOptions::option("institution", "i") ->describe_argument("institute_name") - ->add_effect([&](const std::string &argument) { define_institution(argument.c_str()); }) + ->add_effect([&](const std::string &argument) { define_institution(argument); }) ->add_help("Sets institution name."); CLIOptions::option("chunktype", "k") @@ -1550,8 +1544,6 @@ main(int argc, char *argv[]) cdo_init_is_tty(); - memExitOnError(); - Options::CDO_Reduce_Dim = 0; // mallopt(M_MMAP_MAX, 0); diff --git a/src/cdoStream.cc b/src/cdoStream.cc index 99df8188ab970eab15b2c48ed02152333aa644e4..dcd2e113f8c6ede90bbc309f70ecbf2aae048083 100644 --- a/src/cdoStream.cc +++ b/src/cdoStream.cc @@ -5,13 +5,6 @@ */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <string> -#include <cassert> - #include "cdoStream.h" #include "cdo_options.h" @@ -31,16 +24,3 @@ CdoStream::getTsID() { return m_tsID; } - -int -CdoStream::getVarID() -{ - return m_varID; -} - -int -CdoStream::getVlistID() -{ - return m_vlistID; -} - diff --git a/src/cdoStream.h b/src/cdoStream.h index 756c8c82c63a9e2d76ee7e177369a91f279c2cb2..394a80f4412781eba72ef80403d68434cbcbcd8a 100644 --- a/src/cdoStream.h +++ b/src/cdoStream.h @@ -1,11 +1,6 @@ #ifndef CDOSTREAM_H #define CDOSTREAM_H -#ifdef HAVE_CONFIG_H -#include "config.h" /* _FILE_OFFSET_BITS influence off_t */ -#endif - -#include <sys/types.h> /* off_t */ #include <vector> #include <memory> @@ -34,13 +29,13 @@ public: virtual void inq_record(int *varID, int *levelID) = 0; virtual void defRecord(int varID, int levelID) = 0; - virtual void read_record(float *const p_data, size_t *nmiss) = 0; - virtual void read_record(double *const p_data, size_t *nmiss) = 0; - virtual void read_record(Field *const p_field, size_t *nmiss) = 0; + virtual void read_record(float *const p_data, size_t *numMissVals) = 0; + virtual void read_record(double *const p_data, size_t *numMissVals) = 0; + virtual void read_record(Field *const p_field, size_t *numMissVals) = 0; - virtual void write_record(const float *const p_data, size_t nmiss) = 0; - virtual void write_record(const double *const p_data, size_t nmiss) = 0; - virtual void write_record(const Field *const p_field, size_t nmiss) = 0; + virtual void write_record(const float *const p_data, size_t numMissVals) = 0; + virtual void write_record(const double *const p_data, size_t numMissVals) = 0; + virtual void write_record(const Field *const p_field, size_t numMissVals) = 0; virtual void copyRecord(CdoStreamID dest) = 0; @@ -56,8 +51,6 @@ public: int get_id(); int getTsID(); - int getVarID(); - int getVlistID(); int m_cdoStreamID = -1; // aka the id of the pstream int m_filetype = CDI_UNDEFID; diff --git a/src/cdo_apply.cc b/src/cdo_apply.cc deleted file mode 100644 index 71913aa59702995806d1a7311e7e9422dbd2a408..0000000000000000000000000000000000000000 --- a/src/cdo_apply.cc +++ /dev/null @@ -1,176 +0,0 @@ -/* - This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. - - Author: Uwe Schulzweida - Oliver Heidmann - -*/ - -#include <vector> -#include <iostream> -#include "modules.h" -#include "cdo_output.h" -#include "cdo_apply.h" - -static ApplyStatus errState = ApplyStatus::OK; - -static std::string -parse_arg(const std::string &oper) -{ - if (oper == "") - { - fprintf(stderr, "cdo apply: no operator given for apply.\n"); - errState = ApplyStatus::MISSING_ARG; - } - - const auto mod = get_module(oper); - if (mod.get_stream_in_cnt() != 1) - { - fprintf(stderr, "cdo apply: operator %s can not be used with apply.\n", oper.c_str()); - if (mod.get_stream_in_cnt() == -1) - { - fprintf(stderr, " %s has variable input.\n", oper.c_str()); - errState = ApplyStatus::ARG_VARIABLE_INPUT; - } - - if (mod.get_stream_in_cnt() == 0) - { - fprintf(stderr, " %s has no input.\n", oper.c_str()); - errState = ApplyStatus::ARG_NO_INPUT; - } - } - if (mod.get_stream_in_cnt() > 1) - { - fprintf(stderr, " %s has more than one output.\n", oper.c_str()); - errState = ApplyStatus::ARG_TOO_MANY_OUT; - } - - return oper; -} - -static std::vector<std::string> -generate_tokens(const std::string &p_oper) -{ - std::vector<std::string> result; - - auto end = p_oper.find(' '); - auto start = 0; - while (end != std::string::npos && errState == ApplyStatus::OK) - { - auto oper = p_oper.substr(start, end - start); - if (oper[0] == '-') oper = parse_arg(oper); - result.push_back(oper); - start = end + 1; - end = p_oper.find(' ', start); - } - auto oper = p_oper.substr(start, end - start); - if (oper[0] == '-') oper = parse_arg(oper); - result.push_back(oper); - - return result; -} - -static std::vector<std::string>::iterator -expand(const std::vector<std::string> &p_oper, std::vector<std::string> &p_result, std::vector<std::string> &p_argv, - std::vector<std::string>::iterator p_start) -{ - auto argvIter = p_start; - while (argvIter != p_argv.end() && (*(argvIter))[0] != ']') - { - auto currentArg = (*(argvIter)); - if (currentArg[0] == '[') - { - fprintf(stderr, "cdo apply: brackets not allowed for command apply.\n"); - errState = ApplyStatus::BRACKET_USED; - return argvIter; - } - if (currentArg[0] == '-') - { - const auto mod = get_module(currentArg.c_str()); - if (mod.get_stream_in_cnt() > 0) - { - fprintf(stderr, "cdo apply: operators with inputs are not allowed for command apply.\n"); - errState = ApplyStatus::OPER_WITH_INPUT_USED; - return argvIter; - } - } - for (auto &oper : p_oper) { p_result.push_back(oper); } - p_result.push_back(*argvIter); - ++argvIter; - } - - if (argvIter == p_argv.end() || (*(argvIter))[0] != ']') - { - fprintf(stderr, "cdo apply: missing closing bracket.\n"); - errState = ApplyStatus::MISSING_CLOSING_BRACKET; - } - - return argvIter; -} - -static std::vector<std::string> -scan(std::vector<std::string> p_argv) -{ - std::vector<std::string> newArgv = {}; - if (p_argv[0].compare(0, strlen("-apply,"), "-apply,") == 0) - { - fprintf(stderr, "cdo apply: apply can not be first.\n"); - errState = ApplyStatus::APPLY_USED_FIRST; - return p_argv; - } - for (auto argvIter = p_argv.begin(); argvIter < p_argv.end() && errState == ApplyStatus::OK; argvIter++) - { - std::string currentArgv = *argvIter; - if (currentArgv.compare(0, 6, "-apply") == 0) - { - ++argvIter; - if ((*(argvIter))[0] == '[') - { - const auto pos = currentArgv.find(','); - if (pos != std::string::npos) - { - auto parameter = currentArgv.substr(pos + 1); - if (parameter.empty()) - { - fprintf(stderr, "cdo apply: missing argument for apply.\n"); - errState = ApplyStatus::MISSING_ARG; - break; - } - else if (parameter[0] != '-') - { - fprintf(stderr, "cdo apply: missing pipe symbol in apply argument: %s\n", parameter.c_str()); - errState = ApplyStatus::MISSING_PIPE_SYM; - break; - } - auto tokens = generate_tokens(parameter); - if (errState != ApplyStatus::OK) break; - argvIter = expand(tokens, newArgv, p_argv, ++argvIter); - if (errState != ApplyStatus::OK) break; - } - else - { - fprintf(stderr, "cdo apply: missing argument for apply.\n"); - errState = ApplyStatus::MISSING_ARG; - break; - } - } - else - { - fprintf(stderr, "cdo apply: Missing bracket after apply, apply can only be used with [].\n"); - errState = ApplyStatus::MISSING_BRACKET; - } - } - else { newArgv.push_back(*argvIter); } - } - - return newArgv; -} - -std::vector<std::string> -expand_apply(const std::vector<std::string> &p_argv, ApplyStatus &expandSuccess) -{ - errState = ApplyStatus::OK; - auto result = scan(p_argv); - expandSuccess = errState; - return result; -} diff --git a/src/cdo_apply.h b/src/cdo_apply.h deleted file mode 100644 index e0fe7640fccaef4e576790a2bbd7748cc5611a8f..0000000000000000000000000000000000000000 --- a/src/cdo_apply.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CDO_APPLY_H -#define CDO_APPLY_H - -#include <vector> - -/* - * this feature of cdo allows the use of the -apply keyword. - * When used all files that are inside the ][ brackets of apply are prepended with given operator. - */ - -/* - * checks for: - * missing bracket at pos after -apply -> error - * checks for new bracket -> error - * checks for no closing bracket -> error - * checks for apply not beeing at the first position in the argument string -> error - * checks for missing argument for apply - * checks for operators that are used within the apply brackets -> error - */ - -/* - * supports: - * operators with number of inputs = 1 (no others) - * operators with arguments: written as -apply,-OPERNAME,arguments - */ -enum class ApplyStatus : int -{ - OK = 0, - ARG_TOO_MANY_OUT = 1, - ARG_NO_INPUT = 2, - ARG_VARIABLE_INPUT = 3, - BRACKET_USED = 4, - OPER_WITH_INPUT_USED = 5, - MISSING_CLOSING_BRACKET = 6, - APPLY_USED_FIRST = 7, - MISSING_ARG = 8, - MISSING_BRACKET = 9, - MISSING_PIPE_SYM = 10 -}; - -std::vector<std::string> expand_apply(const std::vector<std::string> &p_argv, ApplyStatus &p_status); - -#endif diff --git a/src/cdo_cdi_wrapper.cc b/src/cdo_cdi_wrapper.cc index f0c6de33e9c6b6e535a3a95928cf9262c35c347f..697f22fd472e1355eb14d241d33f4aee7bcf9bde 100644 --- a/src/cdo_cdi_wrapper.cc +++ b/src/cdo_cdi_wrapper.cc @@ -16,7 +16,7 @@ filetype_to_cstr(int filetype) { switch (filetype) { - // clang-format off + // clang-format off case CDI_FILETYPE_GRB: return "GRIB"; case CDI_FILETYPE_GRB2: return "GRIB2"; case CDI_FILETYPE_NC: return "NetCDF"; @@ -29,7 +29,7 @@ filetype_to_cstr(int filetype) case CDI_FILETYPE_EXT: return "EXTRA"; case CDI_FILETYPE_IEG: return "IEG"; default: return ""; - // clang-format on + // clang-format on } } @@ -101,8 +101,6 @@ get_steptype_name(int tsteptype) return "unknown"; } - - } // namespace cdo int @@ -215,4 +213,4 @@ get_healpix_params(int gridID) return std::make_pair(nside, hpOrder); } -} +} // namespace cdo diff --git a/src/cdo_cdi_wrapper.h b/src/cdo_cdi_wrapper.h index d0d8712dd08658339aeeb91f8f78bad2b013d1b9..5bd90c7b364c89933ba3df27c997978feaf087cf 100644 --- a/src/cdo_cdi_wrapper.h +++ b/src/cdo_cdi_wrapper.h @@ -19,8 +19,7 @@ int str_to_datatype(const std::string &datatypeStr); const char *get_steptype_name(int tsteptype); -} - +} // namespace cdo // create Taxis(cdi) with added check/setting of taxisType int cdo_taxis_create(int taxisType); @@ -45,6 +44,6 @@ std::string inq_var_units(int vlistID, int varID); std::pair<int, HpOrder> get_healpix_params(int gridID); -} +} // namespace cdo #endif diff --git a/src/cdo_exception.h b/src/cdo_exception.h index 6a97164f449a10f76d1487869a3d17f0d5c5923f..6b858720c03c568353a68190a93db410409174cd 100644 --- a/src/cdo_exception.h +++ b/src/cdo_exception.h @@ -6,7 +6,10 @@ struct CdoException : std::logic_error { - CdoException(const std::string &p_msg, const std::string &p_file, const std::string &p_line) : std::logic_error(p_msg), file(p_file), line(p_line) {} + CdoException(const std::string &p_msg, const std::string &p_file, const std::string &p_line) + : std::logic_error(p_msg), file(p_file), line(p_line) + { + } std::string file; std::string line; }; diff --git a/src/cdo_fctrans.cc b/src/cdo_fctrans.cc index c5db60a8c91b31665ea0aa94746332355fe2290c..fee1fd52bc8450b26b985c59f2320cbed78f6869 100644 --- a/src/cdo_fctrans.cc +++ b/src/cdo_fctrans.cc @@ -76,6 +76,7 @@ fc2gp(const double *fc, double *gp, long nlat, long nlon, long nlev, long nfc) { fftw_free(ompmem[i].in_fft); fftw_free(ompmem[i].out_fft); + std::scoped_lock lock(fftwMutex); fftw_destroy_plan(ompmem[i].plan); } #else @@ -137,6 +138,7 @@ gp2fc(const double *gp, double *fc, long nlat, long nlon, long nlev, long nfc) { fftw_free(ompmem[i].in_fft); fftw_free(ompmem[i].out_fft); + std::scoped_lock lock(fftwMutex); fftw_destroy_plan(ompmem[i].plan); } #else diff --git a/src/cdo_fftw3.cc b/src/cdo_fftw3.cc index 8b2c22d89701320259b8a38d0614ea527cc5d8f7..3cedd09dba0362692171661fe5c3dee714374837 100644 --- a/src/cdo_fftw3.cc +++ b/src/cdo_fftw3.cc @@ -59,6 +59,7 @@ fourier2grid(int gridID1, const Varray<double> &array1, Varray<double> &array2) { fftw_free(ompmem[i].in_fft); fftw_free(ompmem[i].out_fft); + std::scoped_lock lock(fftwMutex); fftw_destroy_plan(ompmem[i].plan); } } @@ -114,9 +115,11 @@ grid2fourier(int gridID1, const Varray<double> &array1, int gridID2, Varray<doub { fftw_free(ompmem[i].in_fft); fftw_free(ompmem[i].out_fft); + std::scoped_lock lock(fftwMutex); fftw_destroy_plan(ompmem[i].plan); } } + void filter_fftw(int nts, const std::vector<int> &fmasc, fftw_complex *fft_out, fftw_plan *p_T2S, fftw_plan *p_S2T) { @@ -133,7 +136,9 @@ filter_fftw(int nts, const std::vector<int> &fmasc, fftw_complex *fft_out, fftw_ return; } + #else + #include "cdo_output.h" void fourier2grid(int gridID1, const Varray<double> &array1, Varray<double> &array2) diff --git a/src/cdo_fftw3.h b/src/cdo_fftw3.h index b5248526d53add50ab678f1e17e7c23f8dca2f38..4e7a94fc5171d1a42013b19d35ac661c570bcfbd 100644 --- a/src/cdo_fftw3.h +++ b/src/cdo_fftw3.h @@ -7,17 +7,13 @@ #include "varray.h" +void fourier2grid(int gridID1, const Varray<double> &array1, Varray<double> &array2); -void -fourier2grid(int gridID1, const Varray<double> &array1, Varray<double> &array2); - -void -grid2fourier(int gridID1, const Varray<double> &array1, int gridID2, Varray<double> &array2); +void grid2fourier(int gridID1, const Varray<double> &array1, int gridID2, Varray<double> &array2); #ifdef HAVE_LIBFFTW3 #include <fftw3.h> -void -filter_fftw(int nts, const std::vector<int> &fmasc, fftw_complex *fft_out, fftw_plan *p_T2S, fftw_plan *p_S2T); +void filter_fftw(int nts, const std::vector<int> &fmasc, fftw_complex *fft_out, fftw_plan *p_T2S, fftw_plan *p_S2T); #endif #endif diff --git a/src/cdo_getopt.cc b/src/cdo_getopt.cc index 158fc9886634d2e79a8f967d64088753ad9e124d..83f3ad3016d0439bea19429a2f95e080a5b952a3 100644 --- a/src/cdo_getopt.cc +++ b/src/cdo_getopt.cc @@ -288,7 +288,7 @@ CLIOptions::option_from_envvar(const std::string &p_envvarName) std::string ENVVAR_SUFFIX = "CDO_"; std::string optionName = p_envvarName.substr(ENVVAR_SUFFIX.size(), p_envvarName.size()); - std::transform(optionName.begin(), optionName.end(), optionName.begin(), [](unsigned char c) { return std::tolower(c); }); + std::ranges::transform(optionName, optionName.begin(), ::tolower); optionName = "--" + optionName; diff --git a/src/cdo_getopt.h b/src/cdo_getopt.h index 1f85b7b25735b63954dd2498786dc064d865dd1a..e5e26d5c4d89b84499c354cc183b8e7b5cfaac35 100644 --- a/src/cdo_getopt.h +++ b/src/cdo_getopt.h @@ -61,11 +61,10 @@ struct cdo_option_2 cdo_option_2 * on_empty_argument(const std::function<void()> p_on_empty_argument) { - argument.on_empty_argument = [p_on_empty_argument](std::string){p_on_empty_argument();}; + argument.on_empty_argument = [p_on_empty_argument](std::string) { p_on_empty_argument(); }; return this; } - cdo_option_2 * add_effect(const std::function<void(std::string argument)> p_effect) { @@ -95,7 +94,6 @@ struct cdo_option_2 return this; } - cdo_option_2 * describe_argument(const std::string &desc) { diff --git a/src/cdo_module.cc b/src/cdo_module.cc new file mode 100644 index 0000000000000000000000000000000000000000..dc408d9638fdd6b8a9fab5f3cf9d3cf1d16332ad --- /dev/null +++ b/src/cdo_module.cc @@ -0,0 +1,107 @@ +#include "cdo_module.h" + +oper_t::oper_t() : help(default_help) {} + +oper_t::oper_t(const char *_name, int _f1, int _f2, const char *_enter) + : name(_name), f1(_f1), f2(_f2), enter(_enter), help(default_help) +{ +} + +oper_t::oper_t(const char *_name, int _f1, int _f2) : name(_name), f1(_f1), f2(_f2), enter(nullptr), help(default_help) {} + +oper_t::oper_t(const char *_name, int _f1, int _f2, const char *_enter, const CdoHelp &p_help) + : name(_name), f1(_f1), f2(_f2), enter(_enter), help(p_help) +{ +} +oper_t::oper_t(const char *_name, int _f1, int _f2, const CdoHelp &p_help) + : name(_name), f1(_f1), f2(_f2), enter(nullptr), help(p_help) +{ +} +oper_t::oper_t(const char *_name) : name(_name), help(default_help) {} + +oper_t::oper_t(const char *_name, const CdoHelp &p_help) : name(_name), enter(nullptr), help(p_help) {} + +int +CdoModule::get_id(const std::string &oper) const +{ + for (size_t i = 0; i < operators.size(); i++) + { + if (oper == operators[i].name) { return i; } + } + return -1; +} + +std::string +CdoModule::toString() const +{ + std::string inp = (constraints.streamInCnt >= 0) ? std::to_string(get_stream_in_cnt()) : "Arbitrary"; + std::string out = (constraints.streamOutCnt >= 0) ? std::to_string(get_stream_out_cnt()) : "Output base"; + std::string restriction = "none"; + + if (get_pos_restriction() == OnlyFirst) restriction = "Can only be the first operator"; + if (get_pos_restriction() == FilesOnly) + (restriction != Green("none")) ? restriction = Yellow("Can only use files as input.") + : restriction += Yellow(", Can only use files as input"); + + std::string desc = "Input: " + inp + ", Ouput: " + out + ", Restricton: " + restriction; + + return desc; +} + +int +CdoModule::get_stream_in_cnt() const +{ + return constraints.streamInCnt; +} + +int +CdoModule::get_stream_out_cnt() const +{ + return constraints.streamOutCnt; +} + +int +CdoModule::get_number() const +{ + return number; +} + +int +CdoModule::get_mode() const +{ + return mode; +} + +int +CdoModule::get_pos_restriction() const +{ + return constraints.pos_restriction; +} + +int +CdoModule::is_alias(const std::string &subject) const +{ + for (size_t i = 0; i < aliases.size(); i++) + { + if (aliases[i].alias == subject) { return i; } + } + return -1; +} + +std::vector<oper_t>::const_iterator +CdoModule::find_operator(const std::string &p_operatorName) const +{ + + auto res + = std::find_if(begin(operators), end(operators), [&p_operatorName](const oper_t &o) { return o.name == p_operatorName; }); + return res; +} + +const CdoHelp & +CdoModule::get_help(const std::string &p_operatorName) const +{ + auto oper_iter = find_operator(p_operatorName); + if (oper_iter == operators.end()) cdo_abort("Help for %s in module %s not found", p_operatorName, name); + + return oper_iter->help; +} diff --git a/src/cdo_module.h b/src/cdo_module.h new file mode 100644 index 0000000000000000000000000000000000000000..4fce514a429d8feb42dd98cab2ebc2b5524249f7 --- /dev/null +++ b/src/cdo_module.h @@ -0,0 +1,95 @@ +/* + This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. + + Author: Uwe Schulzweida + Oliver Heidmann + +*/ +#ifndef CDO_MODULE_H +#define CDO_MODULE_H + +#include <string> +#include <vector> +#include <map> + +#include "cdo_output.h" +#include "operator_help.h" + +// Obase uses input name as base name for files e.g 'test' gets used as test_001 test_002 which are created inside the operator +#define OBASE -1 +#define INTERNAL 0 +#define EXPOSED 1 + +struct Alias +{ + Alias(const std::string &_alias, const std::string &_original) : alias(_alias), original(_original) {} + std::string alias; + std::string original; +}; + +enum PositionRestrictions +{ + NoRestriction = 0, + FilesOnly = 1, + OnlyFirst = 2 +}; + +struct module_constraints +{ + short streamInCnt; // Number of input streams + short streamOutCnt; // Number of output streams + PositionRestrictions pos_restriction = NoRestriction; +}; + +class oper_t +{ + inline static const CdoHelp default_help = {}; + +public: + std::string name; + int f1 = 0; + int f2 = 0; + const char *enter = nullptr; + const CdoHelp &help = default_help; + oper_t(); + oper_t(const char *_name); + oper_t(const char *_name, int _f1, int _f2, const char *_enter); + oper_t(const char *_name, int _f1, int _f2); + oper_t(const char *_name, int _f1, int _f2, const CdoHelp &p_help); + oper_t(const char *_name, int _f1, int _f2, const char *_enter, const CdoHelp &p_help); + oper_t(const char *_name, const CdoHelp &p_help); + oper_t(const char *_name, int _f1, int _f2, const CdoHelp &&p_help) = delete; + oper_t(const char *_name, int _f1, int _f2, const char *_enter, const CdoHelp &&p_help) = delete; + oper_t(const char *_name, const CdoHelp &&p_help) = delete; + + oper_t(int _f1, int _f2, const char *_name, const char *_enter); +}; + +struct CdoModule +{ + +public: + std::string name; + std::vector<oper_t> operators; // Operator names + std::vector<Alias> aliases; + short mode; // Module mode: 0:intern 1:extern + short number; // Allowed number type + module_constraints constraints; + + std::string toString() const; + + int get_id(const std::string &oper) const; + int get_stream_in_cnt() const; + int get_stream_out_cnt() const; + int get_number() const; + int get_mode() const; + int get_pos_restriction() const; + + // returns the alias id or if not found1 + int is_alias(const std::string &subject) const; + + std::vector<oper_t>::const_iterator find_operator(const std::string &p_operatorName) const; + const CdoHelp &get_help(const std::string &p_operatorName) const; +}; + +#endif diff --git a/src/cdo_node_attach_exception.h b/src/cdo_node_attach_exception.h index 7364f33647050605a8c4f5542c2bb0c860468fad..9d22c235020299b7c7fdf3d2f56af4c2ce3f9543 100644 --- a/src/cdo_node_attach_exception.h +++ b/src/cdo_node_attach_exception.h @@ -4,6 +4,7 @@ #include <vector> #include <string> #include <memory> +#include "node.h" #include "cdo_exception.h" struct NodeAttachException : public CdoException diff --git a/src/cdo_options.cc b/src/cdo_options.cc index ea4f46d4a30e9503090c8463b40f743fbcb8c664..465f1f9768bdc41676c9a0fd984da905defb76ff 100644 --- a/src/cdo_options.cc +++ b/src/cdo_options.cc @@ -146,11 +146,11 @@ set_compression(int streamID, int filetype) if (Options::filterId != 0) { - streamDefFilter(streamID, Options::filterId, (int)Options::filterParams.size(), Options::filterParams.data()); + streamDefFilter(streamID, Options::filterId, (int) Options::filterParams.size(), Options::filterParams.data()); } } -static double pointSearchRadius = 180.0; // default point search radius in degrees +static double pointSearchRadius = 180.0; // default point search radius in degrees // set point search radius in degrees void diff --git a/src/cdo_output.cc b/src/cdo_output.cc index 72c54dc4d3f7751edb69cf13ac15f42441345b55..da3b94c7bf1908cf45e4f8633cfb86dba1d5c08c 100644 --- a/src/cdo_output.cc +++ b/src/cdo_output.cc @@ -32,6 +32,10 @@ unsigned PROCESS_MANAGER = 0; unsigned CDO_NODE = 0; unsigned PARSER = 0; unsigned PROCESS_INT = 0; +unsigned FACTORY = 0; +unsigned KVLIST = 0; +unsigned MODULE_INFO = 0; + std::string debug_option_string = "DebugLevels:\n" " 0: off \n" @@ -51,7 +55,10 @@ std::string debug_option_string = "DebugLevels:\n" " 12: Process manager\n" " 13: CDO nodes\n" " 14: Parser\n" - " 15: Process interface\n"; + " 15: Process interface\n" + " 16: Factory\n" + " 17: KVList\n" + " 16: Module Info\n"; void print_debug_options() @@ -65,7 +72,7 @@ void parse_debug_arguments(const std::vector<std::string> &tokens, unsigned &cdoDebugLevel, unsigned &cdiDebugLevel) { - for (std::string t : tokens) + for (const auto &t : tokens) { if (t.substr(0, 4).compare("ext=") == 0) { @@ -88,10 +95,7 @@ parse_debug_arguments(const std::vector<std::string> &tokens, unsigned &cdoDebug default: if (int_token > 6) { cdoDebugLevel = (cdoDebugLevel | (1 << (int_token))); } - else - { - cdiDebugLevel = (cdiDebugLevel | (1 << (int_token - 1))); - } + else { cdiDebugLevel = (cdiDebugLevel | (1 << (int_token - 1))); } } } } @@ -110,7 +114,10 @@ print_debug_levels(const unsigned cdoDebugLevel, const unsigned cdiDebugLevel) + "PROCESS_MANAGER: " + std::string(PROCESS_MANAGER ? "ON" : "OFF") + "\n" + "CDO_NODE: " + std::string(CDO_NODE ? "ON" : "OFF") + "\n" + "PARSER: " + std::string(PARSER ? "ON" : "OFF") + "\n" - + "PROCESS_INT: " + std::string(PROCESS_INT ? "ON" : "OFF") + "\n"; + + "PROCESS_INT: " + std::string(PROCESS_INT ? "ON" : "OFF") + "\n" + + "FACTORY: " + std::string(FACTORY ? "ON" : "OFF") + "\n" + + "KVLIST: " + std::string(KVLIST ? "ON" : "OFF") + "\n" + + "MODULE_INFO: " + std::string(MODULE_INFO ? "ON" : "OFF") + "\n"; std::cout << deb_level << std::endl; if (cdoDebugLevel == 1) @@ -141,6 +148,9 @@ set_debug(unsigned p_debug_level) if (p_debug_level & (1u << 13)) CDO_NODE = 1; if (p_debug_level & (1u << 14)) PARSER = 1; if (p_debug_level & (1u << 15)) PROCESS_INT = 1; + if (p_debug_level & (1u << 16)) FACTORY = 1; + if (p_debug_level & (1u << 17)) KVLIST = 1; + if (p_debug_level & (1u << 18)) MODULE_INFO = 1; MpMO::DebugLevel = p_debug_level; cdoDebug = (p_debug_level > 0); } @@ -183,7 +193,7 @@ getGRB2ErrStr(const char *progname) const char *format = "To create a %s application with GRIB2 support use: ./configure --with-eccodes=<ECCODES root directory> ..."; const size_t finalSize = std::snprintf(nullptr, 0, format, progname); char *errStr = (char *) malloc(finalSize + 1); - sprintf(errStr, format, progname); + std::snprintf(errStr, finalSize + 1, format, progname); return errStr; } @@ -198,13 +208,13 @@ getNCErrString(int filetype, const char *progname) const char *format = "%s was build with a NetCDF version which doesn't support NetCDF%s data!"; const size_t finalSize = std::snprintf(nullptr, 0, format, progname, ncv); char *errStr = (char *) malloc(finalSize + 1); - sprintf(errStr, format, progname, ncv); + std::snprintf(errStr, finalSize + 1, format, progname, ncv); #else const char *format = "To create a %s application with NetCDF%s support use: ./configure --with-netcdf=<NetCDF%s root directory> ..."; const size_t finalSize = std::snprintf(nullptr, 0, format, progname, ncv, ncv); char *errStr = (char *) malloc(finalSize + 1); - sprintf(errStr, format, progname, ncv, ncv); + std::snprintf(errStr, finalSize + 1, format, progname, ncv, ncv); #endif return errStr; diff --git a/src/cdo_output.h b/src/cdo_output.h index 440cd87dda5d2b23ef4bf123db266af4bcda0472..761848ed204449344ebabe8cae070664502c4a88 100644 --- a/src/cdo_output.h +++ b/src/cdo_output.h @@ -19,6 +19,9 @@ extern unsigned CDO_NODE; extern unsigned PARSER; extern unsigned PROCESS_INT; extern unsigned CDO_DEBUG; +extern unsigned FACTORY; +extern unsigned KVLIST; +extern unsigned MODULE_INFO; extern std::string debug_option_string; diff --git a/src/cdo_query.cc b/src/cdo_query.cc index 5bc424f18ac066432ad2938971c69b843d5dc55f..1986e90320bc3820f2ed9a6999a64f2afff40e21 100644 --- a/src/cdo_query.cc +++ b/src/cdo_query.cc @@ -104,7 +104,7 @@ set_query_parameter(const std::string ¶ms, CdiQuery *query) KVList kvlist; kvlist.name = "QUERY"; - if (kvlist.parse_arguments(paramsArgv.size(), paramsArgv) != 0) cdo_abort("Parse error!"); + if (kvlist.parse_arguments(paramsArgv) != 0) cdo_abort("Parse error!"); if (Options::cdoVerbose) kvlist.print(); return set_query_parameter(kvlist, query); diff --git a/src/cdo_read.cc b/src/cdo_read.cc index 9466d922642ec2a7fe5f0cbd0721925c931b29df..8c57716fb32b362cbd64b1dd1818787c436ef224 100644 --- a/src/cdo_read.cc +++ b/src/cdo_read.cc @@ -53,12 +53,12 @@ cdo_read_timestepmask(const char *maskfile, std::vector<bool> &imask) if (nrecs != 1) cdo_abort("Internal error; unexprected number of records!"); int varID, levelID; - size_t nmiss; + size_t numMissVals; double value; streamInqRecord(streamID, &varID, &levelID); - streamReadRecord(streamID, &value, &nmiss); + streamReadRecord(streamID, &value, &numMissVals); - imask[tsID] = !(nmiss || IS_EQUAL(value, 0)); + imask[tsID] = !(numMissVals || IS_EQUAL(value, 0)); tsID++; } @@ -87,9 +87,9 @@ read_one_field(const char *text, const char *filename, Varray<double> &array) array.resize(gridsize); int varID, levelID; - size_t nmiss; + size_t numMissVals; streamInqRecord(streamID, &varID, &levelID); - streamReadRecord(streamID, array.data(), &nmiss); + streamReadRecord(streamID, array.data(), &numMissVals); streamClose(streamID); } diff --git a/src/cdo_varlist.cc b/src/cdo_varlist.cc index b8d6a628a66905d7b4cb070ffb4fcd42d93575f1..e59854ba4319cb8f7585168f95aa0d2cb8e430fb 100644 --- a/src/cdo_varlist.cc +++ b/src/cdo_varlist.cc @@ -58,7 +58,7 @@ varList_init(VarList &varList, int vlistID) auto haveAddoffset = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_ADDOFFSET, &addoffset) == CDI_NOERR); auto haveScalefactor = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_SCALEFACTOR, &scalefactor) == CDI_NOERR); auto isPacked = (haveAddoffset || haveScalefactor); - auto useFloatType = isFloatType(var.datatype) || (isIntType(var.datatype) && !isPacked); + auto useFloatType = (var.datatype == CDI_UNDEFID) || isFloatType(var.datatype) || (isIntType(var.datatype) && !isPacked); var.memType = useFloatType ? MemType::Float : MemType::Double; } else { var.memType = Options::CDO_Memtype; } @@ -198,6 +198,7 @@ search_varIDs(const VarList &varList, int vlistID, int numFullLevels) else if (code == gribcodes.lsp && nlevels == 1) varIDs.lnpsID = varID; else if (code == 777 && nlevels == 1) varIDs.lnpsID2 = varID; else if (code == gribcodes.gheight && nlevels == numFullLevels) varIDs.gheightID = varID; + else if (code == gribcodes.gheight && nlevels == numFullLevels + 1) varIDs.gheightID = varID; else if (code == gribcodes.hum && nlevels == numFullLevels) varIDs.humID = varID; // else if (code == 246 && nlevels == numFullLevels) varIDs.clwcID = varID; // else if (code == 247 && nlevels == numFullLevels) varIDs.ciwcID = varID; @@ -224,10 +225,7 @@ varList_map(const VarList &varList1, const VarList &varList2, CmpVlist cmpFlag, if (varList1[varID1].name == varList2[varID2].name) break; } if (varID1 == nvars1) { cdo_abort("Variable %s not found in first input stream!", varList2[varID2].name); } - else - { - mapOfVarIDs[varID1] = varID2; - } + else { mapOfVarIDs[varID1] = varID2; } } } else @@ -244,10 +242,7 @@ varList_map(const VarList &varList1, const VarList &varList2, CmpVlist cmpFlag, if (mapFlag == 3) continue; cdo_abort("Variable %s not found in second input stream!", varList1[varID1].name); } - else - { - mapOfVarIDs[varID1] = varID2; - } + else { mapOfVarIDs[varID1] = varID2; } } } @@ -280,8 +275,7 @@ varList_map(const VarList &varList1, const VarList &varList2, CmpVlist cmpFlag, if (flag & static_cast<int>(CmpVlist::GridSize)) { - if (varList1[varID1].gridsize != varList2[varID2].gridsize) - cdo_abort("Grid size of the input fields do not match!"); + if (varList1[varID1].gridsize != varList2[varID2].gridsize) cdo_abort("Grid size of the input fields do not match!"); } if (flag & static_cast<int>(CmpVlist::NumLevels)) @@ -324,8 +318,8 @@ varList_check_names(const VarList &varList1, const VarList &varList2) for (int varID = 0; varID < numVars; ++varID) names1[varID] = varList1[varID].name; for (int varID = 0; varID < numVars; ++varID) names2[varID] = varList2[varID].name; - std::sort(names1.begin(), names1.end()); - std::sort(names2.begin(), names2.end()); + ranges::sort(names1); + ranges::sort(names2); int varID; for (varID = 0; varID < numVars; ++varID) @@ -382,7 +376,7 @@ varList_compare(const VarList &varList1, const VarList &varList2, CmpVlist cmpFl int numVars = varList1.size(); - if (numVars != (int)varList2.size()) + if (numVars != (int) varList2.size()) { varList_print_missing_vars(varList1, varList2); cdo_abort("Input streams have different number of variables per timestep!"); diff --git a/src/cdo_varlist.h b/src/cdo_varlist.h index 41ac122768e176eee3fc8b589071beb0c1085d37..a345de25bb7626a3c84263ad8d9f36e9d3da583f 100644 --- a/src/cdo_varlist.h +++ b/src/cdo_varlist.h @@ -20,7 +20,11 @@ enum class CmpVlist All = Name | Dim }; -inline CmpVlist operator | (CmpVlist lhs, CmpVlist rhs) { return (CmpVlist) (static_cast<int>(lhs) | static_cast<int>(rhs)); } +inline CmpVlist +operator|(CmpVlist lhs, CmpVlist rhs) +{ + return (CmpVlist) (static_cast<int>(lhs) | static_cast<int>(rhs)); +} struct CdoVar { diff --git a/src/cdo_vlist.cc b/src/cdo_vlist.cc index 5d23cd3bd015bd90e46b4be3849851286b513048..87666c43d28fe59d62935595eddd464946d915ec 100644 --- a/src/cdo_vlist.cc +++ b/src/cdo_vlist.cc @@ -167,10 +167,7 @@ cdo_compare_grids(int gridID1, int gridID2) else cdo_warning("xsize of input grids differ!"); } - else if (gridType1 == GRID_CURVILINEAR || gridType2 == GRID_UNSTRUCTURED) - { - compare_grid_unstructured(gridID1, gridID2); - } + else if (gridType1 == GRID_CURVILINEAR || gridType2 == GRID_UNSTRUCTURED) { compare_grid_unstructured(gridID1, gridID2); } } else if (gridInqSize(gridID1) > 1) { diff --git a/src/cdo_zaxis.cc b/src/cdo_zaxis.cc index fd9c3a7f2d72a6ce41e476417a37a7dcbb0e34d4..7a71ee4cdb659b983f6b231ba989b3b5e25c4248 100644 --- a/src/cdo_zaxis.cc +++ b/src/cdo_zaxis.cc @@ -277,7 +277,7 @@ zaxis_from_file(FILE *zfp, const char *filename) } static void -gen_zaxis_height(ZaxisDesciption& zaxis, const std::string& zaxisname) +gen_zaxis_height(ZaxisDesciption &zaxis, const std::string &zaxisname) { int zaxistype = ZAXIS_HEIGHT; @@ -308,7 +308,7 @@ gen_zaxis_height(ZaxisDesciption& zaxis, const std::string& zaxisname) } int -zaxis_from_name(const std::string& zaxisname) +zaxis_from_name(const std::string &zaxisname) { int zaxisID = CDI_UNDEFID; diff --git a/src/cdo_zaxis.h b/src/cdo_zaxis.h index 030a5c694e6118a1caed2bd2d5127536d38eeae0..8c1fc2893bb96caf6d790dfc1e0ad585ea42d4ab 100644 --- a/src/cdo_zaxis.h +++ b/src/cdo_zaxis.h @@ -3,18 +3,19 @@ #include <string> #include "varray.h" +#include "cdi.h" -int cdo_define_zaxis(const std::string& zaxisfile); -void define_zaxis(const char* zaxisarg); -int zaxis_from_name(const std::string& zaxisname); -int zaxis_from_file(FILE* zfp, const char* filename); +int cdo_define_zaxis(const std::string &zaxisfile); +void define_zaxis(const char *zaxisarg); +int zaxis_from_name(const std::string &zaxisname); +int zaxis_from_file(FILE *zfp, const char *filename); int zaxis_to_ltype(int zaxisID); double cdo_zaxis_inq_level(int zaxisID, int levelID); -int cdo_zaxis_inq_levels(int zaxisID, double* levels); +int cdo_zaxis_inq_levels(int zaxisID, double *levels); -void gen_layer_bounds(int nlev, const Varray<double>& levels, Varray<double>& lbounds, Varray<double>& ubounds); -int get_layer_thickness(bool useWeights, bool genBounds, int index, int zaxisID, int nlev, Varray<double>& thickness, - Varray<double>& weights); +void gen_layer_bounds(int nlev, const Varray<double> &levels, Varray<double> &lbounds, Varray<double> &ubounds); +int get_layer_thickness(bool useWeights, bool genBounds, int index, int zaxisID, int nlev, Varray<double> &thickness, + Varray<double> &weights); static inline bool positive_is_down(int zaxisID) diff --git a/src/cdotest.cc b/src/cdotest.cc index 29b565e49886da71d05325c0273e418a3ab92e3f..e0c5b1afed1f8397b56cfffd6d3178a26d0038d4 100644 --- a/src/cdotest.cc +++ b/src/cdotest.cc @@ -62,8 +62,8 @@ read_file(const char path[], Varray2D<double> &vars, int nvars, int nts) // auto vDateTime = taxisInqVdatetime(taxisID); - size_t nmiss; - for (int varID = 0; varID < nvars; ++varID) streamReadVar(streamID, varID, &vars[varID][tsID], &nmiss); + size_t numMissVals; + for (int varID = 0; varID < nvars; ++varID) streamReadVar(streamID, varID, &vars[varID][tsID], &numMissVals); } streamClose(streamID); @@ -114,9 +114,9 @@ write_file(const char path[], const double array[], int length) streamDefTimestep(streamID, tsID); auto value = array[tsID]; - size_t nmiss = dbl_is_equal(value, MISSVAL) ? 1 : 0; + size_t numMissVals = dbl_is_equal(value, MISSVAL) ? 1 : 0; - streamWriteVar(streamID, varID, &value, nmiss); + streamWriteVar(streamID, varID, &value, numMissVals); } streamClose(streamID); diff --git a/src/cmortable_parser.cc b/src/cmortable_parser.cc index 6c0ddeca175e83da2a6552ba744eadea270742a2..19d755be2ce967ec45c6836f8b48ea02c1db6f09 100644 --- a/src/cmortable_parser.cc +++ b/src/cmortable_parser.cc @@ -51,9 +51,9 @@ readLineFromBuffer(char *buffer, size_t *buffersize, char *line, size_t len) static char * skipSeparator(char *pline) { - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; if (*pline == '=' || *pline == ':') pline++; - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; return pline; } @@ -61,10 +61,10 @@ skipSeparator(char *pline) static char * getElementName(char *pline, char *name) { - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; auto len = strlen(pline); size_t pos = 0; - while (pos < len && !isspace((int) *(pline + pos)) && *(pline + pos) != '=' && *(pline + pos) != ':') pos++; + while (pos < len && !std::isspace((int) *(pline + pos)) && *(pline + pos) != '=' && *(pline + pos) != ':') pos++; strncpy(name, pline, pos); name[pos] = 0; @@ -76,7 +76,7 @@ getElementName(char *pline, char *name) static char * getElementValue(char *pline) { - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; auto len = strlen(pline); if (*pline != '"' && *pline != '\'') for (size_t i = 1; i < len; ++i) @@ -86,7 +86,7 @@ getElementValue(char *pline) len = i; break; } - while (isspace((int) *(pline + len - 1)) && len) + while (std::isspace((int) *(pline + len - 1)) && len) { *(pline + len - 1) = 0; len--; @@ -108,7 +108,7 @@ parse_cmortable_buffer(PMList &pmlist, size_t buffersize, char *buffer) { // linenumber++; auto pline = line; - while (isspace((int) *pline)) pline++; + while (std::isspace((int) *pline)) pline++; if (*pline == '#' || *pline == '!' || *pline == '\0') continue; // len = (int) strlen(pline); diff --git a/src/compare.h b/src/compare.h index d1bc0089d9a6a510988fe71ba10b6090932e0b1e..465967936c7a240aaeaaa4c8aff492dd31376e91 100644 --- a/src/compare.h +++ b/src/compare.h @@ -12,16 +12,15 @@ const auto is_equal = [](auto a, auto b) noexcept { return !(a < b || b < a) const auto dbl_is_equal = [](auto a, auto b) noexcept { return (std::isnan(a) || std::isnan(b) ? (std::isnan(a) && std::isnan(b)) : is_equal(a, b)); }; // clang-format on - -//#define DBL_IS_EQUAL(x,y) (!(x < y || y < x)) -//#define DBL_IS_EQUAL(x, y) (std::isnan(x) || std::isnan(y) ? (std::isnan(x) && std::isnan(y) ? 1 : 0) : !(x < y || y < x)) +// #define DBL_IS_EQUAL(x,y) (!(x < y || y < x)) +// #define DBL_IS_EQUAL(x, y) (std::isnan(x) || std::isnan(y) ? (std::isnan(x) && std::isnan(y) ? 1 : 0) : !(x < y || y < x)) static inline bool DBL_IS_EQUAL(double x, double y) { return (std::isnan(x) || std::isnan(y) ? (std::isnan(x) && std::isnan(y)) : !(x < y || y < x)); } -//#define IS_EQUAL(x, y) (!IS_NOT_EQUAL(x, y)) +// #define IS_EQUAL(x, y) (!IS_NOT_EQUAL(x, y)) constexpr bool IS_NOT_EQUAL(double x, double y) noexcept { @@ -45,5 +44,10 @@ cdo_cmpstr(const std::string &lhs, const std::string &rhs) { return (lhs.compare(rhs) == 0); } +static inline bool +cdo_cmpstr(const std::string_view &lhs, const std::string &rhs) +{ + return (lhs.compare(rhs) == 0); +} #endif /* COMPARE_H */ diff --git a/src/constants.h b/src/constants.h index c61cdba7467880af111e3e265dc254cb34025e2d..4536cc3da1a2f0d327a0c1e40a6adb90a8849839 100644 --- a/src/constants.h +++ b/src/constants.h @@ -17,7 +17,7 @@ constexpr double C_EARTH_GRAV = 9.80665; #define C_RG (1.0 / PlanetGrav) constexpr double C_RCPV = 4.0 * C_RV; -#define C_RETV (C_RV / PlanetRD - 1.) +#define C_RETV (C_RV / PlanetRD - 1.0) constexpr double C_RCW = 4218.; // specific water heat capacity ?? constexpr double C_RCS = 2106.; // specific ice heat capacity ?? constexpr double C_RTT = 273.16; // melting temperature of ice/snow @@ -28,6 +28,10 @@ constexpr double C_RESTT = 611.14; constexpr double C_TIMES_RHOH2O = -333700000.0; +constexpr double PlanetRDDefault = C_EARTH_RD; +constexpr double PlanetRadiusDefault = C_EARTH_RADIUS; +constexpr double PlanetGravDefault = C_EARTH_GRAV; + extern double PlanetRD; extern double PlanetRadius; extern double PlanetGrav; diff --git a/src/datarangelist.h b/src/datarangelist.h index cf497a18eeabc2a9614c7b8b3024f8b9f1224d61..278aa131efc8ccabf7f619a020f18519f2895ce3 100644 --- a/src/datarangelist.h +++ b/src/datarangelist.h @@ -26,10 +26,10 @@ struct Datarange template <typename T> void - check_datarange(T *array, size_t nmiss) + check_datarange(T *array, size_t numMissVals) { - const auto mm = nmiss ? varray_min_max_mv(gridsize, array, (T) missval) : varray_min_max(gridsize, array); - const auto numberOfValues = nmiss ? mm.n : gridsize; + const auto mm = numMissVals ? varray_min_max_mv(gridsize, array, (T) missval) : varray_min_max(gridsize, array); + const auto numberOfValues = numMissVals ? mm.n : gridsize; if (numberOfValues > 0) { diff --git a/src/datetime.cc b/src/datetime.cc index 09a3568473d67ff5aefc1c83152f07863b89f9cb..e1b41d9116448edc73ff69c209ee7c02b8e91f87 100644 --- a/src/datetime.cc +++ b/src/datetime.cc @@ -36,18 +36,18 @@ time_units_cstr(TimeUnits timeUnit) } void -set_timestat_date(const std::string &optarg) +set_timestat_date(const std::string &p_optarg) { TimeStat timestatdate = TimeStat::UNDEF; // clang-format off - if (optarg == "first") timestatdate = TimeStat::FIRST; - else if (optarg == "last") timestatdate = TimeStat::LAST; - else if (optarg == "middle") timestatdate = TimeStat::MEAN; - else if (optarg == "midhigh") timestatdate = TimeStat::MIDHIGH; + if (p_optarg == "first") timestatdate = TimeStat::FIRST; + else if (p_optarg == "last") timestatdate = TimeStat::LAST; + else if (p_optarg == "middle") timestatdate = TimeStat::MEAN; + else if (p_optarg == "midhigh") timestatdate = TimeStat::MIDHIGH; // clang-format on - if (timestatdate == TimeStat::UNDEF) cdo_abort("option --%s: unsupported argument: %s", "timestat_date", optarg); + if (timestatdate == TimeStat::UNDEF) cdo_abort("option --%s: unsupported argument: %s", "timestat_date", p_optarg); CDO_Timestat_Date = timestatdate; } @@ -186,10 +186,7 @@ DateTimeList::mean(int nsteps) this->timestat.v = julianDate_decode(this->calendar, julianDatem); #endif } - else - { - this->timestat.v = this->dtInfo[nsteps / 2].v; - } + else { this->timestat.v = this->dtInfo[nsteps / 2].v; } } void @@ -250,10 +247,7 @@ datetime_avg(int calendar, int ndates, const std::vector<CdiDateTime> &cdiDateTi auto julianDatem = julianDate_add_seconds(julianDate1, std::lround(seconds)); return julianDate_decode(calendar, julianDatem); } - else - { - return cdiDateTimes[ndates / 2]; - } + else { return cdiDateTimes[ndates / 2]; } } void @@ -307,31 +301,16 @@ get_time_increment(double jdelta, CdiDate vDate0, CdiDate vDate1) if (deltam == 0) deltam = 1; TimeIncrement timeIncr; - if (seconds >= (3600 * 24 * 30 * 12)) - { - timeIncr = { deltay, TimeUnits::YEARS }; - } - else if (seconds >= (3600 * 24 * 30) && seconds / (3600 * 24 * 30) < 12) - { - timeIncr = { deltam, TimeUnits::MONTHS }; - } + if (seconds >= (3600 * 24 * 30 * 12)) { timeIncr = { deltay, TimeUnits::YEARS }; } + else if (seconds >= (3600 * 24 * 30) && seconds / (3600 * 24 * 30) < 12) { timeIncr = { deltam, TimeUnits::MONTHS }; } else if (seconds >= (3600 * 24) && seconds / (3600 * 24) < 32) { timeIncr = { seconds / (3600 * 24), TimeUnits::DAYS }; if (timeIncr.period >= 27 && deltam == 1) timeIncr = { 1, TimeUnits::MONTHS }; } - else if (seconds >= 3600 && seconds % 3600 == 0) - { - timeIncr = { seconds / 3600, TimeUnits::HOURS }; - } - else if (seconds >= 60 && seconds % 60 == 0) - { - timeIncr = { seconds / 60, TimeUnits::MINUTES }; - } - else - { - timeIncr = { seconds, TimeUnits::SECONDS }; - } + else if (seconds >= 3600 && seconds % 3600 == 0) { timeIncr = { seconds / 3600, TimeUnits::HOURS }; } + else if (seconds >= 60 && seconds % 60 == 0) { timeIncr = { seconds / 60, TimeUnits::MINUTES }; } + else { timeIncr = { seconds, TimeUnits::SECONDS }; } timeIncr.period *= sign; @@ -470,10 +449,7 @@ decode_datestring(const std::string &dateString) std::sscanf(dateString.c_str(), "%d-%d-%d", &year, &month, &day); return cdiDate_encode(year, month, day); } - else - { - return cdiDate_set(parameter_to_long(dateString)); - } + else { return cdiDate_set(parameter_to_long(dateString)); } } CdiTime @@ -488,10 +464,7 @@ decode_timestring(const std::string &timeString) ms = (fseconds - second) * 1000; return cdiTime_encode(hour, minute, second, ms); } - else - { - return cdiTime_set(parameter_to_int(timeString)); - } + else { return cdiTime_set(parameter_to_int(timeString)); } } void diff --git a/src/dcw_reader.cc b/src/dcw_reader.cc index 2c1349ab0e4039b54402a0cf2b7d58b8a7f0e0a5..ffb4a59dd47b93585c3dc90c58f8faa976fcc411 100644 --- a/src/dcw_reader.cc +++ b/src/dcw_reader.cc @@ -45,7 +45,7 @@ dcw_get_path(const char *name, const char *suffix, char *path) if (DCW_Dir) { - sprintf(path, "%s/%s%s", DCW_Dir, name, suffix); + std::snprintf(path, PATH_MAX, "%s/%s%s", DCW_Dir, name, suffix); if (access(path, R_OK) == 0) found = true; } else @@ -184,7 +184,7 @@ dcw_find_country(const std::string &code, const std::vector<DCW_Country> &list) static int dcw_find_state(const std::string &code, const std::vector<DCW_State> &list) { - auto country = code.substr(0,2); + auto country = code.substr(0, 2); auto state = code.substr(2); for (size_t i = 0, n = list.size(); i < n; ++i) { @@ -543,7 +543,7 @@ dcw_print_polygons(const DCW_Lists &dcw_lists, const std::vector<std::string> &c void dcw_sort_countries(DCW_Lists &dcw_lists) { - std::sort(dcw_lists.countries.begin(), dcw_lists.countries.end(), compare_code); + std::ranges::sort(dcw_lists.countries, compare_code); } /* diff --git a/src/ecacore.cc b/src/ecacore.cc index ea8863c9ff31ff6f05158ae30e13ff34433416e0..f00e7f1e521b1dc6ef53114cdefffa5de7b45dd8 100644 --- a/src/ecacore.cc +++ b/src/ecacore.cc @@ -163,7 +163,7 @@ eca1(const ECA_REQUEST_1 &request) if (request.var1.f2 != &vfarnum2) { field_fill(var12[levelID], missval); - var12[levelID].nmiss = gridsize; + var12[levelID].numMissVals = gridsize; } field_fill(samp1[levelID], missval); if (!samp2[levelID].empty()) field_fill(samp2[levelID], 0.0); @@ -171,13 +171,13 @@ eca1(const ECA_REQUEST_1 &request) if (IS_SET(request.var2.h2)) field_fill(var21[levelID], missval); if (IS_SET(request.var2.h3)) field_fill(var23[levelID], missval); - samp1[levelID].nmiss = gridsize; - if (IS_SET(request.var1.f3)) var13[levelID].nmiss = gridsize; - if (IS_SET(request.var2.h2)) var21[levelID].nmiss = gridsize; - if (IS_SET(request.var2.h3)) var23[levelID].nmiss = gridsize; + samp1[levelID].numMissVals = gridsize; + if (IS_SET(request.var1.f3)) var13[levelID].numMissVals = gridsize; + if (IS_SET(request.var2.h2)) var21[levelID].numMissVals = gridsize; + if (IS_SET(request.var2.h3)) var23[levelID].numMissVals = gridsize; } - cdo_read_record(istreamID, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(istreamID, field1.vec_d.data(), &field1.numMissVals); field1.grid = var12[levelID].grid; field1.missval = var12[levelID].missval; @@ -186,14 +186,14 @@ eca1(const ECA_REQUEST_1 &request) if (IS_SET(request.var2.h2)) { field2.vec_d = field1.vec_d; - field2.nmiss = field1.nmiss; + field2.numMissVals = field1.numMissVals; field2.grid = field1.grid; field2.missval = field1.missval; } if (IS_SET(request.var1.f1)) request.var1.f1(field1, request.var1.f1arg); - if (field1.nmiss || !samp2[levelID].empty()) + if (field1.numMissVals || !samp2[levelID].empty()) { if (samp2[levelID].empty()) { @@ -213,7 +213,7 @@ eca1(const ECA_REQUEST_1 &request) if (IS_SET(request.var1.f3) && request.var1.f2 == &vfarnum2) { varray_copy(gridsize, var12[levelID].vec_d, field3.vec_d); - field3.nmiss = var12[levelID].nmiss; + field3.numMissVals = var12[levelID].numMissVals; field3.grid = var12[levelID].grid; field3.missval = var12[levelID].missval; } @@ -226,7 +226,7 @@ eca1(const ECA_REQUEST_1 &request) if (IS_NOT_SET(request.var2.h2)) { varray_copy(gridsize, var12[levelID].vec_d, field2.vec_d); - field2.nmiss = var12[levelID].nmiss; + field2.numMissVals = var12[levelID].numMissVals; field2.grid = var12[levelID].grid; field2.missval = var12[levelID].missval; } @@ -253,7 +253,7 @@ eca1(const ECA_REQUEST_1 &request) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field2.nmiss) + if (field2.numMissVals) { for (size_t i = 0; i < len; ++i) { @@ -337,7 +337,7 @@ eca1(const ECA_REQUEST_1 &request) vfarsel(rvar, samp1[levelID]); cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.nmiss); + cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.numMissVals); } if (IS_SET(request.var2.h2) || IS_SET(request.var2.h3)) @@ -350,7 +350,7 @@ eca1(const ECA_REQUEST_1 &request) vfarsel(rvar, samp1[levelID]); cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.nmiss); + cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.numMissVals); } } @@ -469,7 +469,7 @@ eca2(const ECA_REQUEST_2 &request) cdo_inq_record(istreamID2, &varID, &levelID); if (varID != FIRST_VAR_ID) continue; auto &rvar = vars2[dayOfYear][0][levelID]; - cdo_read_record(istreamID2, rvar.vec_d.data(), &rvar.nmiss); + cdo_read_record(istreamID2, rvar.vec_d.data(), &rvar.numMissVals); } itsID++; @@ -512,7 +512,7 @@ eca2(const ECA_REQUEST_2 &request) if (request.var1.f4 != &vfarnum2) { field_fill(var14[levelID], missval1); - var14[levelID].nmiss = gridsize; + var14[levelID].numMissVals = gridsize; } field_fill(samp1[levelID], missval1); field_fill(samp2[levelID], missval1); @@ -521,18 +521,18 @@ eca2(const ECA_REQUEST_2 &request) if (IS_SET(request.var1.f5)) field_fill(var15[levelID], missval1); if (IS_SET(request.var2.h2)) field_fill(var22[levelID], missval1); - samp1[levelID].nmiss = gridsize; - samp2[levelID].nmiss = gridsize; - if (request.var1.epilog == PERCENT_OF_TOTAL_AMOUNT) total[levelID].nmiss = gridsize; - if (IS_SET(request.var1.f5)) var15[levelID].nmiss = gridsize; - if (IS_SET(request.var2.h2)) var22[levelID].nmiss = gridsize; + samp1[levelID].numMissVals = gridsize; + samp2[levelID].numMissVals = gridsize; + if (request.var1.epilog == PERCENT_OF_TOTAL_AMOUNT) total[levelID].numMissVals = gridsize; + if (IS_SET(request.var1.f5)) var15[levelID].numMissVals = gridsize; + if (IS_SET(request.var2.h2)) var22[levelID].numMissVals = gridsize; } - cdo_read_record(istreamID1, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(istreamID1, field1.vec_d.data(), &field1.numMissVals); field1.grid = gridID; field1.missval = missval1; field2.grid = vars2[dayOfYear][0][levelID].grid; - field2.nmiss = vars2[dayOfYear][0][levelID].nmiss; + field2.numMissVals = vars2[dayOfYear][0][levelID].numMissVals; field2.missval = missval2; field_copy(vars2[dayOfYear][0][levelID], field2); @@ -544,7 +544,7 @@ eca2(const ECA_REQUEST_2 &request) if (IS_SET(request.var1.f1)) request.var1.f1(field1, request.var1.f1arg); if (IS_SET(request.var1.f2)) request.var1.f2(field2, request.var1.f2arg); - if (field1.nmiss || !samp3[levelID].empty()) + if (field1.numMissVals || !samp3[levelID].empty()) { if (samp3[levelID].empty()) { @@ -561,7 +561,7 @@ eca2(const ECA_REQUEST_2 &request) if (IS_SET(request.var1.f5) && request.var1.f4 == &vfarnum2) { varray_copy(gridsize, var14[levelID].vec_d, field3.vec_d); - field3.nmiss = var14[levelID].nmiss; + field3.numMissVals = var14[levelID].numMissVals; field3.grid = var14[levelID].grid; field3.missval = var14[levelID].missval; } @@ -572,7 +572,7 @@ eca2(const ECA_REQUEST_2 &request) if (IS_SET(request.var2.h2)) { varray_copy(gridsize, var14[levelID].vec_d, field2.vec_d); - field2.nmiss = var14[levelID].nmiss; + field2.numMissVals = var14[levelID].numMissVals; field2.grid = var14[levelID].grid; field2.missval = var14[levelID].missval; @@ -592,7 +592,7 @@ eca2(const ECA_REQUEST_2 &request) auto len = field1.size; if (len != field3.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss) + if (field1.numMissVals) { for (size_t i = 0; i < len; ++i) { @@ -684,7 +684,7 @@ eca2(const ECA_REQUEST_2 &request) vfarsel(rvar, samp2[levelID]); cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.nmiss); + cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.numMissVals); } if (IS_SET(request.var2.h2)) @@ -698,7 +698,7 @@ eca2(const ECA_REQUEST_2 &request) vfarsel(rvar, samp2[levelID]); cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.nmiss); + cdo_write_record(ostreamID, rvar.vec_d.data(), rvar.numMissVals); } } @@ -823,15 +823,15 @@ eca3(const ECA_REQUEST_3 &request) var1[levelID].vec_d[i] = missval; var2[levelID].vec_d[i] = missval; } - var1[levelID].nmiss = gridsize; - var2[levelID].nmiss = gridsize; + var1[levelID].numMissVals = gridsize; + var2[levelID].numMissVals = gridsize; } - cdo_read_record(istreamID1, field1.vec_d.data(), &field1.nmiss); + cdo_read_record(istreamID1, field1.vec_d.data(), &field1.numMissVals); field1.grid = var1[levelID].grid; field1.missval = var1[levelID].missval; - cdo_read_record(istreamID2, field2.vec_d.data(), &field2.nmiss); + cdo_read_record(istreamID2, field2.vec_d.data(), &field2.numMissVals); field2.grid = var1[levelID].grid; field2.missval = var1[levelID].missval; @@ -867,7 +867,7 @@ eca3(const ECA_REQUEST_3 &request) for (int levelID = 0; levelID < nlevels; ++levelID) { cdo_def_record(ostreamID, varID, levelID); - cdo_write_record(ostreamID, var1[levelID].vec_d.data(), var1[levelID].nmiss); + cdo_write_record(ostreamID, var1[levelID].vec_d.data(), var1[levelID].numMissVals); } if (nrecs == 0) break; @@ -885,7 +885,7 @@ fldhvs(const FieldVector &fieldVector, const size_t nlevels) { for (size_t level = 0; level < nlevels; level++) { - if (fieldVector[level].nmiss != fieldVector[level].size) return true; + if (fieldVector[level].numMissVals != fieldVector[level].size) return true; } return false; @@ -1008,7 +1008,7 @@ eca4(const ECA_REQUEST_4 &request) { int levelID; cdo_inq_record(istreamID2, &varID, &levelID); - cdo_read_record(istreamID2, mask.vec_d.data(), &mask.nmiss); + cdo_read_record(istreamID2, mask.vec_d.data(), &mask.numMissVals); mask.grid = gridID; mask.missval = vlistInqVarMissval(ivlistID2, 0); @@ -1057,11 +1057,11 @@ eca4(const ECA_REQUEST_4 &request) field_fill(startDateWithHist[0][levelID], missval); field_fill(endDateWithHist[0][levelID], missval); - gslDuration[levelID].nmiss = 0; - gslFirstDay[levelID].nmiss = 0; + gslDuration[levelID].numMissVals = 0; + gslFirstDay[levelID].numMissVals = 0; // reinitialize the current year - startDateWithHist[0][levelID].nmiss = gridsize; - endDateWithHist[0][levelID].nmiss = gridsize; + startDateWithHist[0][levelID].numMissVals = gridsize; + endDateWithHist[0][levelID].numMissVals = gridsize; } // init the history ONCE if (0 == itsID) @@ -1069,13 +1069,13 @@ eca4(const ECA_REQUEST_4 &request) field_fill(startDateWithHist[1][levelID], missval); field_fill(endDateWithHist[1][levelID], missval); - startDateWithHist[1][levelID].nmiss = gridsize; - endDateWithHist[1][levelID].nmiss = gridsize; + startDateWithHist[1][levelID].numMissVals = gridsize; + endDateWithHist[1][levelID].numMissVals = gridsize; } - cdo_read_record(istreamID1, fieldGt.vec_d.data(), &fieldGt.nmiss); + cdo_read_record(istreamID1, fieldGt.vec_d.data(), &fieldGt.numMissVals); fieldLt.vec_d = fieldGt.vec_d; - fieldLt.nmiss = fieldGt.nmiss; + fieldLt.numMissVals = fieldGt.numMissVals; fieldGt.grid = startCount[levelID].grid; fieldGt.missval = startCount[levelID].missval; fieldLt.grid = startCount[levelID].grid; @@ -1091,7 +1091,7 @@ eca4(const ECA_REQUEST_4 &request) if (!dbl_is_equal(startCount[levelID].vec_d[i], missval)) { startCount[levelID].vec_d[i] = missval; - startCount[levelID].nmiss++; + startCount[levelID].numMissVals++; } } // reset southern endCount @@ -1101,7 +1101,7 @@ eca4(const ECA_REQUEST_4 &request) if (!dbl_is_equal(endCount[levelID].vec_d[i], missval)) { endCount[levelID].vec_d[i] = missval; - endCount[levelID].nmiss++; + endCount[levelID].numMissVals++; } } @@ -1125,7 +1125,7 @@ eca4(const ECA_REQUEST_4 &request) if (!dbl_is_equal(endCount[levelID].vec_d[i], missval)) { endCount[levelID].vec_d[i] = missval; - endCount[levelID].nmiss++; + endCount[levelID].numMissVals++; } } } @@ -1142,7 +1142,7 @@ eca4(const ECA_REQUEST_4 &request) if (!dbl_is_equal(startCount[levelID].vec_d[i], missval)) { startCount[levelID].vec_d[i] = missval; - startCount[levelID].nmiss++; + startCount[levelID].numMissVals++; } } } @@ -1236,13 +1236,13 @@ eca4(const ECA_REQUEST_4 &request) } } } - // update nmiss for saving data in GRIB - startCount[levelID].nmiss = field_num_miss(startCount[levelID]); - endCount[levelID].nmiss = field_num_miss(endCount[levelID]); - startDateWithHist[1][levelID].nmiss = field_num_miss(startDateWithHist[1][levelID]); - startDateWithHist[0][levelID].nmiss = field_num_miss(startDateWithHist[0][levelID]); - endDateWithHist[1][levelID].nmiss = field_num_miss(endDateWithHist[1][levelID]); - endDateWithHist[0][levelID].nmiss = field_num_miss(endDateWithHist[0][levelID]); + // update numMissVals for saving data in GRIB + startCount[levelID].numMissVals = field_num_miss(startCount[levelID]); + endCount[levelID].numMissVals = field_num_miss(endCount[levelID]); + startDateWithHist[1][levelID].numMissVals = field_num_miss(startDateWithHist[1][levelID]); + startDateWithHist[0][levelID].numMissVals = field_num_miss(startDateWithHist[0][levelID]); + endDateWithHist[1][levelID].numMissVals = field_num_miss(endDateWithHist[1][levelID]); + endDateWithHist[0][levelID].numMissVals = field_num_miss(endDateWithHist[0][levelID]); } ovDateTime = ivDateTime; diff --git a/src/ecautil.cc b/src/ecautil.cc index 483e1c141d84cfebeab841e8d4199aa74cb8d1b9..f2970b504616978d4aca569897094151a38631c9 100644 --- a/src/ecautil.cc +++ b/src/ecautil.cc @@ -19,7 +19,7 @@ #include "ecautil.h" /** - * Counts the number of nonmissing values. The result of the operation + * Counts the number of nonumMissValsing values. The result of the operation * is computed according to the following rules: * * field1 field2 mode result @@ -53,7 +53,7 @@ count(Field &field1, const Field &field2, double mode) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss) + if (field1.numMissVals) { for (size_t i = 0; i < len; ++i) { @@ -81,11 +81,11 @@ count(Field &field1, const Field &field2, double mode) } } - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } else { - if (field2.nmiss) + if (field2.numMissVals) { for (size_t i = 0; i < len; ++i) { @@ -138,7 +138,7 @@ selcomp(Field &field1, const Field &field2, int (*compare)(double, double)) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { for (size_t i = 0; i < len; ++i) if (dbl_is_equal(array1[i], missval1) || dbl_is_equal(array2[i], missval2) || !compare(array1[i], array2[i])) @@ -150,7 +150,7 @@ selcomp(Field &field1, const Field &field2, int (*compare)(double, double)) if (!compare(array1[i], array2[i])) array1[i] = missval1; } - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } /** @@ -180,7 +180,7 @@ selcompc(Field &field, double c, int (*compare)(double, double)) { for (size_t i = 0; i < len; ++i) array[i] = missval; } - else if (field.nmiss) + else if (field.numMissVals) { for (size_t i = 0; i < len; ++i) if (dbl_is_equal(array[i], missval) || !compare(array[i], c)) array[i] = missval; @@ -191,7 +191,7 @@ selcompc(Field &field, double c, int (*compare)(double, double)) if (!compare(array[i], c)) array[i] = missval; } - field.nmiss = field_num_miss(field); + field.numMissVals = field_num_miss(field); } static int @@ -259,7 +259,7 @@ vfarsel(Field &field1, const Field &field2) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different gridsize (%s)", __func__); - if (field2.nmiss) + if (field2.numMissVals) { for (size_t i = 0; i < len; ++i) if (dbl_is_equal(array2[i], missval2) || dbl_is_equal(array2[i], 0.0)) array1[i] = missval1; @@ -270,7 +270,7 @@ vfarsel(Field &field1, const Field &field2) if (is_equal(array2[i], 0.0)) array1[i] = missval1; } - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } void @@ -493,8 +493,8 @@ compute_gsl(int nlevels, size_t gridsize, std::vector<double> &yvals, double mis for (int levelID = 0; levelID < nlevels; ++levelID) { - gslDuration[levelID].nmiss = field_num_miss(gslDuration[levelID]); - gslFirstDay[levelID].nmiss = field_num_miss(gslFirstDay[levelID]); + gslDuration[levelID].numMissVals = field_num_miss(gslDuration[levelID]); + gslFirstDay[levelID].numMissVals = field_num_miss(gslFirstDay[levelID]); } } @@ -511,12 +511,12 @@ write_gsl_stream(CdoStreamID ostreamID, int otaxisID, int otsID, int ovarID1, in for (int levelID = 0; levelID < nlevels; ++levelID) { cdo_def_record(ostreamID, ovarID1, levelID); - cdo_write_record(ostreamID, gslDuration[levelID].vec_d.data(), gslDuration[levelID].nmiss); + cdo_write_record(ostreamID, gslDuration[levelID].vec_d.data(), gslDuration[levelID].numMissVals); } for (int levelID = 0; levelID < nlevels; ++levelID) { cdo_def_record(ostreamID, ovarID2, levelID); - cdo_write_record(ostreamID, gslFirstDay[levelID].vec_d.data(), gslFirstDay[levelID].nmiss); + cdo_write_record(ostreamID, gslFirstDay[levelID].vec_d.data(), gslFirstDay[levelID].numMissVals); } } diff --git a/src/ecautil.h b/src/ecautil.h index be0d35cb2ae087f73712ef5662c965d4a3ba083f..b72a5d108f6790a347a3f1ceaf10cabdfd45bdde 100644 --- a/src/ecautil.h +++ b/src/ecautil.h @@ -10,6 +10,7 @@ #define ECAUTIL_H_ #include "field.h" +#include "cdoStream.h" /** * Computes the day-of-year correspnding a given Gregorian date. @@ -21,7 +22,7 @@ unsigned long day_of_year(int date); /** - * Counts the number of nonmissing values in a field. The result + * Counts the number of nonumMissValsing values in a field. The result * of the operation is computed according to the following rules: * * field1 field2 result @@ -36,7 +37,7 @@ unsigned long day_of_year(int date); void vfarnum(Field &field1, const Field &field2); /** - * Counts the number of consecutive nonmissing values in a field. + * Counts the number of consecutive nonumMissValsing values in a field. * The result of the operation is computed according to the following * rules: * @@ -53,7 +54,7 @@ void vfarnum2(Field &field1, const Field &field2); /** * Counts the number of values in series of at least n consecutive - * nonmissing values. The result of the operation is computed according + * nonumMissValsing values. The result of the operation is computed according * to the following rules: * * field1 field2 result diff --git a/src/expr.cc b/src/expr.cc index 694f821e8258289201f03f327b99d1d2a15896d1..f5a376fb74353d8f28eae97f95d6ca55d588c4e5 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -260,7 +260,7 @@ param_meta_copy(ParamEntry &out, const ParamEntry &in) out.nlat = in.nlat; out.nlev = in.nlev; out.missval = in.missval; - out.nmiss = 0; + out.numMissVals = 0; out.coord = 0; out.hasMV = true; out.name = ""; @@ -274,7 +274,7 @@ expr_con_var(int init, int oper, const nodeType *p1, const nodeType *p2) { auto ngp = (p2->param.ngp > 0) ? p2->param.ngp : 1; auto nlev = (p2->param.nlev > 0) ? p2->param.nlev : 1; - auto hasMV = (p2->param.nmiss > 0); + auto hasMV = (p2->param.numMissVals > 0); auto datatype = p2->param.datatype; auto missval2 = p2->param.missval; @@ -298,7 +298,7 @@ expr_con_var(int init, int oper, const nodeType *p1, const nodeType *p2) oper_expr_con_var(oper, hasMV, n, missval2, odat, cval, idat); - p->param.nmiss = array_num_mv(n, odat, missval2); + p->param.numMissVals = array_num_mv(n, odat, missval2); } return p; @@ -309,7 +309,7 @@ expr_var_con(int init, int oper, const nodeType *p1, const nodeType *p2) { auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; - auto hasMV = (p1->param.nmiss > 0); + auto hasMV = (p1->param.numMissVals > 0); auto datatype = p1->param.datatype; auto missval1 = p1->param.missval; @@ -333,7 +333,7 @@ expr_var_con(int init, int oper, const nodeType *p1, const nodeType *p2) oper_expr_var_con(oper, hasMV, n, missval1, odat, idat, cval); - p->param.nmiss = array_num_mv(n, odat, missval1); + p->param.numMissVals = array_num_mv(n, odat, missval1); } return p; @@ -343,8 +343,8 @@ static nodeType * expr_var_var(int init, int oper, nodeType *p1, nodeType *p2) { auto px = p1; - auto nmiss1 = p1->param.nmiss; - auto nmiss2 = p2->param.nmiss; + auto numMissVals1 = p1->param.numMissVals; + auto numMissVals2 = p2->param.numMissVals; auto missval1 = p1->param.missval; auto missval2 = p2->param.missval; @@ -411,7 +411,7 @@ expr_var_var(int init, int oper, nodeType *p1, nodeType *p2) } p->param.name = tmpVarName; - // printf("%s %s nmiss %zu %zu\n", p->u.var.name.c_str(), px->param.name.c_str(), nmiss1, nmiss2); + // printf("%s %s numMissVals %zu %zu\n", p->u.var.name.c_str(), px->param.name.c_str(), numMissVals1, numMissVals2); if (!init) { @@ -426,7 +426,7 @@ expr_var_var(int init, int oper, nodeType *p1, nodeType *p2) const auto idat1 = p1->param.data + loff1; const auto idat2 = p2->param.data + loff2; auto odat = p->param.data + loff; - auto hasMV = (nmiss1 > 0 || nmiss2 > 0); + auto hasMV = (numMissVals1 > 0 || numMissVals2 > 0); if (ngp1 != ngp2) { @@ -447,7 +447,7 @@ expr_var_var(int init, int oper, nodeType *p1, nodeType *p2) else { oper_expr_var_var(oper, hasMV, ngp, missval1, missval2, odat, idat1, idat2); } } - p->param.nmiss = array_num_mv(ngp * nlev, p->param.data, missval1); + p->param.numMissVals = array_num_mv(ngp * nlev, p->param.data, missval1); } return p; @@ -480,12 +480,12 @@ ex_copy_var(int init, nodeType *p2, const nodeType *p1) if (!init) { - if (copyConstValue1) { varray_fill(ngp2 * nlev2, p2->param.data, p1->param.data[0]); } + if (copyConstValue1) { ranges::fill_n(p2->param.data, ngp2 * nlev2, p1->param.data[0]); } else { array_copy(ngp2 * nlev2, p1->param.data, p2->param.data); p2->param.missval = p1->param.missval; - p2->param.nmiss = p1->param.nmiss; + p2->param.numMissVals = p1->param.numMissVals; } } } @@ -518,7 +518,7 @@ ex_copy_con(int init, nodeType *p2, const nodeType *p1) if (!init) { assert(p2->param.data != nullptr); - varray_fill(ngp * nlev, p2->param.data, cval); + ranges::fill_n(p2->param.data, ngp * nlev, cval); } } @@ -670,8 +670,7 @@ ex_fun_std(int funcID, size_t n, bool hasMV, double mv, const double *p1data, do } void -func_expr_con_var(int funcID, bool hasMV, size_t n, double mv, double *odat, double cval, - const double *idat) +func_expr_con_var(int funcID, bool hasMV, size_t n, double mv, double *odat, double cval, const double *idat) { auto &funcEntry = funcSymbolTable[funcID]; auto exprfunc = (double (*)(double, double)) funcEntry.func; @@ -697,8 +696,7 @@ func_expr_con_var(int funcID, bool hasMV, size_t n, double mv, double *odat, dou } void -func_expr_var_con(int funcID, bool hasMV, size_t n, double mv, double *odat, const double *idat, - double cval) +func_expr_var_con(int funcID, bool hasMV, size_t n, double mv, double *odat, const double *idat, double cval) { auto &funcEntry = funcSymbolTable[funcID]; auto exprfunc = (double (*)(double, double)) funcEntry.func; @@ -724,8 +722,7 @@ func_expr_var_con(int funcID, bool hasMV, size_t n, double mv, double *odat, con } void -func_expr_var_var(int funcID, bool hasMV, size_t n, double mv1, double mv2, double *odat, - const double *idat1, const double *idat2) +func_expr_var_var(int funcID, bool hasMV, size_t n, double mv1, double mv2, double *odat, const double *idat1, const double *idat2) { auto &funcEntry = funcSymbolTable[funcID]; auto exprfunc = (double (*)(double, double)) funcEntry.func; @@ -762,7 +759,7 @@ ex_fun_var(int init, int funcID, nodeType *p1) auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; auto nlat = p1->param.nlat; - auto nmiss = p1->param.nmiss; + auto numMissVals = p1->param.numMissVals; auto missval = p1->param.missval; auto p = new nodeType; @@ -806,7 +803,7 @@ ex_fun_var(int init, int funcID, nodeType *p1) double *pdata = p->param.data; double *p1data = p1->param.data; - if (functype == FT_STD) { ex_fun_std(funcID, ngp * nlev, nmiss, missval, p1data, pdata); } + if (functype == FT_STD) { ex_fun_std(funcID, ngp * nlev, numMissVals, missval, p1data, pdata); } else if (functype == FT_FLD) { Field field; @@ -820,7 +817,7 @@ ex_fun_var(int init, int funcID, nodeType *p1) auto exprfunc = (double (*)(const Field &)) funcEntry.func; for (size_t k = 0; k < nlev; ++k) { - fld_field_init(field, nmiss, missval, ngp, p1data + k * ngp, p1->param.weight); + fld_field_init(field, numMissVals, missval, ngp, p1data + k * ngp, p1->param.weight); pdata[k] = exprfunc(field); } } @@ -832,9 +829,9 @@ ex_fun_var(int init, int funcID, nodeType *p1) auto exprfunc = (void (*)(const Field &, Field &)) funcEntry.func; for (size_t k = 0; k < nlev; ++k) { - fld_field_init(field1, nmiss, missval, ngp, &p1data[k * ngp], nullptr); + fld_field_init(field1, numMissVals, missval, ngp, &p1data[k * ngp], nullptr); field1.grid = gridID; - fld_field_init(field2, nmiss, missval, nlat, &pdata[k * nlat], nullptr); + fld_field_init(field2, numMissVals, missval, nlat, &pdata[k * nlat], nullptr); exprfunc(field1, field2); array_copy(nlat, field2.vec_d.data(), &pdata[k * nlat]); } @@ -848,7 +845,7 @@ ex_fun_var(int init, int funcID, nodeType *p1) for (size_t i = 0; i < ngp; ++i) { for (size_t k = 0; k < nlev; ++k) field.vec_d[k] = p1data[k * ngp + i]; - fld_field_init(field, nmiss, missval, nlev, nullptr, nullptr); + fld_field_init(field, numMissVals, missval, nlev, nullptr, nullptr); pdata[i] = exprfunc(field); } } @@ -856,7 +853,7 @@ ex_fun_var(int init, int funcID, nodeType *p1) else cdo_abort("Intermal error, wrong function type (%d) for %s()!", functype, funcname); - if (pdata) p->param.nmiss = array_num_mv(p->param.ngp * p->param.nlev, pdata, missval); + if (pdata) p->param.numMissVals = array_num_mv(p->param.ngp * p->param.nlev, pdata, missval); } if (p1->isTmpObj) node_delete(p1); @@ -894,7 +891,7 @@ func_con_var(int init, int funcID, const nodeType *p1, const nodeType *p2) auto ngp = (p2->param.ngp > 0) ? p2->param.ngp : 1; auto nlev = (p2->param.nlev > 0) ? p2->param.nlev : 1; - auto hasMV = (p2->param.nmiss > 0); + auto hasMV = (p2->param.numMissVals > 0); auto missval2 = p2->param.missval; auto n = ngp * nlev; @@ -916,7 +913,7 @@ func_con_var(int init, int funcID, const nodeType *p1, const nodeType *p2) func_expr_con_var(funcID, hasMV, n, missval2, odat, cval, idat); - p->param.nmiss = array_num_mv(n, odat, missval2); + p->param.numMissVals = array_num_mv(n, odat, missval2); } return p; @@ -931,7 +928,7 @@ func_var_con(int init, int funcID, const nodeType *p1, const nodeType *p2) auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; - auto hasMV = (p1->param.nmiss > 0); + auto hasMV = (p1->param.numMissVals > 0); auto missval1 = p1->param.missval; auto n = ngp * nlev; @@ -953,7 +950,7 @@ func_var_con(int init, int funcID, const nodeType *p1, const nodeType *p2) func_expr_var_con(funcID, hasMV, n, missval1, odat, idat, cval); - p->param.nmiss = array_num_mv(n, odat, missval1); + p->param.numMissVals = array_num_mv(n, odat, missval1); } return p; @@ -967,8 +964,8 @@ func_var_var(int init, int funcID, nodeType *p1, nodeType *p2) if (functype != FT_STD) cdo_abort("Intermal error, wrong function type (%d) for %s()!", functype, funcEntry.name); auto px = p1; - auto nmiss1 = p1->param.nmiss; - auto nmiss2 = p2->param.nmiss; + auto numMissVals1 = p1->param.numMissVals; + auto numMissVals2 = p2->param.numMissVals; auto missval1 = p1->param.missval; auto missval2 = p2->param.missval; @@ -1035,7 +1032,7 @@ func_var_var(int init, int funcID, nodeType *p1, nodeType *p2) } p->param.name = tmpVarName; - // printf("%s %s nmiss %zu %zu\n", p->u.var.name.c_str(), px->param.name.c_str(), nmiss1, nmiss2); + // printf("%s %s numMissVals %zu %zu\n", p->u.var.name.c_str(), px->param.name.c_str(), numMissVals1, numMissVals2); if (!init) { @@ -1050,7 +1047,7 @@ func_var_var(int init, int funcID, nodeType *p1, nodeType *p2) const auto idat1 = p1->param.data + loff1; const auto idat2 = p2->param.data + loff2; auto odat = p->param.data + loff; - auto hasMV = (nmiss1 > 0 || nmiss2 > 0); + auto hasMV = (numMissVals1 > 0 || numMissVals2 > 0); if (ngp1 != ngp2) { @@ -1071,7 +1068,7 @@ func_var_var(int init, int funcID, nodeType *p1, nodeType *p2) else { func_expr_var_var(funcID, hasMV, ngp, missval1, missval2, odat, idat1, idat2); } } - p->param.nmiss = array_num_mv(ngp * nlev, p->param.data, missval1); + p->param.numMissVals = array_num_mv(ngp * nlev, p->param.data, missval1); } return p; @@ -1141,7 +1138,7 @@ ex_remap(int init, int funcID, nodeType *p1, nodeType *p2) auto gridID = p1->param.gridID; auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; - auto nmiss = p1->param.nmiss; + auto numMissVals = p1->param.numMissVals; auto missval = p1->param.missval; auto p = new nodeType; @@ -1173,10 +1170,10 @@ ex_remap(int init, int funcID, nodeType *p1, nodeType *p2) auto exprfunc = (void (*)(const Field &, Field &)) funcEntry.func; for (size_t k = 0; k < nlev; ++k) { - fld_field_init(field1, nmiss, missval, ngp, &p1data[k * ngp], nullptr); + fld_field_init(field1, numMissVals, missval, ngp, &p1data[k * ngp], nullptr); field1.grid = gridID; field2.grid = gridID2; - fld_field_init(field2, nmiss, missval, ngp2, &pdata[k * ngp2], nullptr); + fld_field_init(field2, numMissVals, missval, ngp2, &pdata[k * ngp2], nullptr); exprfunc(field1, field2); array_copy(ngp2, field2.vec_d.data(), &pdata[k * ngp2]); } @@ -1253,7 +1250,7 @@ ex_fun1c(int init, int funcID, nodeType *p1, nodeType *p2, ParseParamType &parse auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; - auto nmiss = p1->param.nmiss; + auto numMissVals = p1->param.numMissVals; auto missval = p1->param.missval; auto p = new nodeType; @@ -1314,8 +1311,8 @@ ex_fun1c(int init, int funcID, nodeType *p1, nodeType *p2, ParseParamType &parse pdata = p->param.data; const auto p1data = p1->param.data + ngp * levidx; array_copy(ngp, p1data, pdata); - if (nmiss) nmiss = array_num_mv(ngp, pdata, missval); - p->param.nmiss = nmiss; + if (numMissVals) numMissVals = array_num_mv(ngp, pdata, missval); + p->param.numMissVals = numMissVals; } if (p1->isTmpObj) node_delete(p1); @@ -1341,7 +1338,7 @@ ex_fun2c(int init, int funcID, nodeType *p1, nodeType *p2, nodeType *p3, ParsePa auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; - auto nmiss = p1->param.nmiss; + auto numMissVals = p1->param.numMissVals; auto missval = p1->param.missval; auto p = new nodeType; @@ -1420,8 +1417,8 @@ ex_fun2c(int init, int funcID, nodeType *p1, nodeType *p2, nodeType *p3, ParsePa auto paramdata = p->param.data; const auto p1data = p1->param.data + ngp * levidx1; array_copy(ngp * nlevout, p1data, paramdata); - if (nmiss) nmiss = array_num_mv(ngp * nlevout, paramdata, missval); - p->param.nmiss = nmiss; + if (numMissVals) numMissVals = array_num_mv(ngp * nlevout, paramdata, missval); + p->param.numMissVals = numMissVals; } if (p1->isTmpObj) node_delete(p1); @@ -1476,7 +1473,7 @@ ex_uminus_var(int init, nodeType *p1) { auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; - auto nmiss = p1->param.nmiss; + auto numMissVals = p1->param.numMissVals; auto missval = p1->param.missval; auto p = new nodeType; @@ -1493,7 +1490,7 @@ ex_uminus_var(int init, nodeType *p1) double *pdata = p->param.data; const double *p1data = p1->param.data; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = dbl_is_equal(p1data[i], missval) ? missval : -(p1data[i]); } @@ -1502,7 +1499,7 @@ ex_uminus_var(int init, nodeType *p1) for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = -(p1data[i]); } - p->param.nmiss = nmiss; + p->param.numMissVals = numMissVals; } return p; @@ -1549,7 +1546,7 @@ ex_not_var(int init, nodeType *p1) { auto ngp = (p1->param.ngp > 0) ? p1->param.ngp : 1; auto nlev = (p1->param.nlev > 0) ? p1->param.nlev : 1; - auto nmiss = p1->param.nmiss; + auto numMissVals = p1->param.numMissVals; auto missval = p1->param.missval; auto p = new nodeType; @@ -1566,7 +1563,7 @@ ex_not_var(int init, nodeType *p1) double *pdata = p->param.data; const double *p1data = p1->param.data; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = dbl_is_equal(p1data[i], missval) ? missval : unary_op_not(p1data[i]); } @@ -1575,7 +1572,7 @@ ex_not_var(int init, nodeType *p1) for (size_t i = 0; i < ngp * nlev; ++i) pdata[i] = unary_op_not(p1data[i]); } - p->param.nmiss = nmiss; + p->param.numMissVals = numMissVals; } return p; @@ -1621,14 +1618,8 @@ static void str_add_node_info(char *string, size_t stringlen, nodeType *p, const char *ext) { auto len = strlen(string); - if (p->type == NodeEnum::typeCon) - { - snprintf(string + len, stringlen - len, "%g%s", p->con().value, ext); - } - else - { - snprintf(string + len, stringlen - len, "%s[N%zu][L%zu]%s", p->var().name.c_str(), p->param.ngp, p->param.nlev, ext); - } + if (p->type == NodeEnum::typeCon) { snprintf(string + len, stringlen - len, "%g%s", p->con().value, ext); } + else { snprintf(string + len, stringlen - len, "%s[N%zu][L%zu]%s", p->var().name.c_str(), p->param.ngp, p->param.nlev, ext); } } static nodeType * @@ -1660,19 +1651,16 @@ ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3) auto nlev = (p0->param.nlev > 0) ? p0->param.nlev : 1; auto px = p0; - size_t nmiss1 = 0; + size_t numMissVals1 = 0; auto missval1 = missval; const double *pdata1 = nullptr; size_t ngp1 = 1; size_t nlev1 = 1; - if (p1->type == NodeEnum::typeCon) - { - pdata1 = &p1->con().value; - } + if (p1->type == NodeEnum::typeCon) { pdata1 = &p1->con().value; } else { - nmiss1 = p1->param.nmiss; + numMissVals1 = p1->param.numMissVals; ngp1 = (p1->param.ngp > 0) ? p1->param.ngp : 1; nlev1 = (p1->param.nlev > 0) ? p1->param.nlev : 1; missval1 = p1->param.missval; @@ -1700,10 +1688,7 @@ ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3) size_t ngp2 = 1; size_t nlev2 = 1; - if (p2->type == NodeEnum::typeCon) - { - pdata2 = &p2->con().value; - } + if (p2->type == NodeEnum::typeCon) { pdata2 = &p2->con().value; } else { ngp2 = (p2->param.ngp > 0) ? p2->param.ngp : 1; @@ -1733,10 +1718,7 @@ ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3) size_t ngp3 = 1; size_t nlev3 = 1; - if (p3->type == NodeEnum::typeCon) - { - pdata3 = &p3->con().value; - } + if (p3->type == NodeEnum::typeCon) { pdata3 = &p3->con().value; } else { ngp3 = (p3->param.ngp > 0) ? p3->param.ngp : 1; @@ -1771,7 +1753,7 @@ ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3) if (!init) { - size_t nmiss = 0; + size_t numMissVals = 0; p->param.data = new double[ngp * nlev]; @@ -1796,7 +1778,7 @@ ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3) auto ival2 = idat2[(ngp2 > 1) ? i : 0]; auto ival3 = idat3[(ngp3 > 1) ? i : 0]; - if (nmiss1 && dbl_is_equal(ival1, missval1)) + if (numMissVals1 && dbl_is_equal(ival1, missval1)) odat[i] = missval1; else if (is_not_equal(ival1, 0.0)) odat[i] = dbl_is_equal(ival2, missval2) ? missval1 : ival2; @@ -1804,10 +1786,10 @@ ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3) odat[i] = dbl_is_equal(ival3, missval3) ? missval1 : ival3; } - nmiss += array_num_mv(ngp, odat, missval1); + numMissVals += array_num_mv(ngp, odat, missval1); } - p->param.nmiss = nmiss; + p->param.numMissVals = numMissVals; } if (p1->isTmpObj) node_delete(p1); @@ -1895,7 +1877,7 @@ add_new_constant(const std::string &varname, ParseParamType &parseArg, std::vect params[varID].nlat = 0; params[varID].nlev = 0; params[varID].missval = -9.e33; - params[varID].nmiss = 0; + params[varID].numMissVals = 0; params[varID].name = varname; parseArg.nparams++; parseArg.cnparams++; @@ -1911,7 +1893,7 @@ add_new_param(const std::string &varname, ParseParamType &parseArg, std::vector< params[varID].isValid = true; params[varID].hasMV = param.hasMV; params[varID].name = varname; - params[varID].nmiss = param.nmiss; + params[varID].numMissVals = param.numMissVals; if (param.units.size()) params[varID].units = param.units; if (param.longname.size()) params[varID].longname = param.longname; parseArg.nparams++; @@ -1955,7 +1937,7 @@ expr_run_var_grid(const std::string &vnm, int coord, ParseParamType &parseArg) { auto ¶ms = parseArg.params; - auto varname = vnm.substr(0, vnm.size() -2); + auto varname = vnm.substr(0, vnm.size() - 2); auto varID = param_search_name(parseArg.nparams, params, varname); if (varID == -1) cdo_abort("Coordinate %c: variable >%s< not found!", coord, varname); @@ -1991,7 +1973,7 @@ expr_run_var_zaxis(const std::string &vnm, int coord, ParseParamType &parseArg) { auto ¶ms = parseArg.params; - auto varname = vnm.substr(0, vnm.size() -2); + auto varname = vnm.substr(0, vnm.size() - 2); auto varID = param_search_name(parseArg.nparams, params, varname); if (varID == -1) cdo_abort("Coordinate %c: variable >%s< not found!", coord, varname); @@ -2060,7 +2042,7 @@ expr_run_var(nodeType *p, ParseParamType &parseArg) if (!init) { p->param.data = params[varID].data; - p->param.nmiss = params[varID].nmiss; + p->param.numMissVals = params[varID].numMissVals; } if (parseArg.debug) @@ -2227,7 +2209,7 @@ expr_run_opr(nodeType *p, ParseParamType &parseArg) p->isTmpObj = false; ex_copy(init, p, rnode); - params[varID].nmiss = p->param.nmiss; + params[varID].numMissVals = p->param.numMissVals; } if (rnode && rnode->isTmpObj) diff --git a/src/expr.h b/src/expr.h index 3f9b6c8c04e2c80aacff54b802af8f1f3192bb95..ce354ac123e977dc8ca78373c660e96aa63e4fbb 100644 --- a/src/expr.h +++ b/src/expr.h @@ -4,6 +4,8 @@ Author: Uwe Schulzweida */ +#ifndef CDO_EXPR_H +#define CDO_EXPR_H #include <cstdio> #include <cstdarg> #include <cassert> @@ -26,8 +28,8 @@ enum CoordIndex MINUTE, HOUR, CALENDAR, - DOY, // day of year - DPY, // days per year + DOY, // day of year + DPY, // days per year LEN }; @@ -117,7 +119,7 @@ struct ParamEntry size_t ngp = 0; size_t nlat = 0; size_t nlev = 0; - size_t nmiss = 0; + size_t numMissVals = 0; std::string name; std::string longname; std::string stdname; @@ -198,3 +200,4 @@ void yyset_extra(YY_EXTRA_TYPE, void *); nodeType *expr_run(nodeType *p, ParseParamType &parseArg); int params_get_coord_ID(const ParseParamType &parseArg, int coord, int cdiID); +#endif diff --git a/src/expr_fun.cc b/src/expr_fun.cc index 3a10f0e6c7c71234998a31540852749f08e2aca0..22364ddca79a48499a86ab84a13ea2d79e4fcbd6 100644 --- a/src/expr_fun.cc +++ b/src/expr_fun.cc @@ -350,10 +350,10 @@ oper_expr_var_var(int oper, bool hasMV, size_t n, double mv1, double mv2, double } void -fld_field_init(Field &field, size_t nmiss, double missval, size_t ngp, double *array, double *w) +fld_field_init(Field &field, size_t numMissVals, double missval, size_t ngp, double *array, double *w) { field.size = ngp; - field.nmiss = nmiss; + field.numMissVals = numMissVals; field.missval = missval; if (array != nullptr) array_copy(ngp, array, field.vec_d.data()); if (w != nullptr) array_copy(ngp, w, field.weightv.data()); @@ -384,8 +384,7 @@ void vert_weights(int zaxisID, size_t nlev, Varray<double> &weights) { Varray<double> thickness(nlev); - weights.resize(nlev); - varray_fill(nlev, weights, 1.0); + weights.resize(nlev, 1.0); if (nlev > 1) { diff --git a/src/expr_fun.h b/src/expr_fun.h index 509b4a268a8112df88f8444411890dbbad1a79c9..a0e2216100cb6be5b9bc78493ecc7d9076656ff3 100644 --- a/src/expr_fun.h +++ b/src/expr_fun.h @@ -9,13 +9,14 @@ #include <cstddef> #include "field.h" +#include "expr.h" nodeType *expr_con_con(int oper, const nodeType *p1, const nodeType *p2); void oper_expr_con_var(int oper, bool hasMV, size_t n, double mv, double *odat, double cval, const double *idat); void oper_expr_var_con(int oper, bool hasMV, size_t n, double mv, double *odat, const double *idat, double cval); void oper_expr_var_var(int oper, bool hasMV, size_t n, double mv1, double mv2, double *odat, const double *idat1, double *idat2); -void fld_field_init(Field &field, size_t nmiss, double missval, size_t ngp, double *array, double *w); +void fld_field_init(Field &field, size_t numMissVals, double missval, size_t ngp, double *array, double *w); void vert_weights(int zaxisID, size_t nlev, Varray<double> &weights); #endif diff --git a/src/expr_yacc.cc b/src/expr_yacc.cc index 986e9ec29b5b851d9cd44e2fd91d88de51e24256..14e3fec83385f4a189b054d8f4e93c5c1ac879b1 100644 --- a/src/expr_yacc.cc +++ b/src/expr_yacc.cc @@ -1507,7 +1507,7 @@ yyreduce: case 9: /* stmt: VARIABLE ';' */ #line 70 "expr_yacc.y" - { (yyval.nPtr) = expr_opr('=', 2, expr_var((yyvsp[-1].varnm)), expr_var((yyvsp[-1].varnm))); } + { char *v = strdup((yyvsp[-1].varnm)); (yyval.nPtr) = expr_opr('=', 2, expr_var((yyvsp[-1].varnm)), expr_var(v)); } #line 1512 "expr_yacc.cc" break; diff --git a/src/expr_yacc.y b/src/expr_yacc.y index 576dcd2f4382dba37ed17b4560a9f305c55356f4..207e9693af694b719008d1dcd8848fff96de5ace 100644 --- a/src/expr_yacc.y +++ b/src/expr_yacc.y @@ -67,7 +67,7 @@ stmt: | expr ';' { $$ = $1; } | VARIABLE '=' expr ';' { $$ = expr_opr('=', 2, expr_var($1), $3); } | VARIABLE '=' ternary ';' { $$ = expr_opr('=', 2, expr_var($1), $3); } - | VARIABLE ';' { $$ = expr_opr('=', 2, expr_var($1), expr_var($1)); } /* conflicts: 1 shift/reduce */ + | VARIABLE ';' { char *v = strdup($1); $$ = expr_opr('=', 2, expr_var($1), expr_var(v)); } /* conflicts: 1 shift/reduce */ | REMOVE VARIABLE ')' ';' { $$ = expr_cmd("remove", $2); } | PRINT VARIABLE ')' ';' { $$ = expr_cmd("print", $2); } | '{' stmt_list '}' { $$ = $2; } diff --git a/src/factory.cc b/src/factory.cc index aaf311fe5e4c3a7440c0a147e8b6dacf6c1b6ec7..ca4706ae070a8883da84005ffadb0d0fa5bc57f2 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1,14 +1,232 @@ +/* + This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. + + Author: Uwe Schulzweida + Oliver Heidmann + +*/ #include <map> #include <string> #include <algorithm> +#include <functional> + #include "process.h" +#include "factory.h" +#include "util_string.h" -std::map<const std::string, std::function<std::shared_ptr<Process>(int p_ID, const std::string &p_operatorNamme, - const std::vector<std::string> &operatorArguments)>> & -get_factory() +namespace Factory { - static std::map<const std::string, std::function<std::shared_ptr<Process>(int p_ID, const std::string &p_operatorNamme, - const std::vector<std::string> &operatorArguments)>> - factory; +OperatorMap & +get() +{ + static OperatorMap factory; return factory; } + +OperatorMap::iterator +find(const std::string &p_operName) +{ + return find(p_operName, [&p_operName]() { cdo_abort("Operator >%s< not found!", p_operName); }); +} + +OperatorMap::iterator +find(const std::string &p_operName, std::function<void()> p_onError) +{ + auto &operator_map = get(); + auto it = operator_map.find(p_operName); + if (it == operator_map.end()) { p_onError(); } + return it; +} + +const CdoModule & +get_module(const std::string &p_operName) +{ + auto it = find(p_operName); + return it->second.module; +} +const CdoModule & +get_module(const OperatorMap::iterator &it) +{ + return it->second.module; +} + +ModuleConstructor +get_constructor(const std::string &p_operName) +{ + auto it = find(p_operName); + return it->second.constructor; +} + +ModuleConstructor +get_constructor(const OperatorMap::iterator it) +{ + return it->second.constructor; +} + +const CdoHelp & +get_help(const std::string &p_operName) +{ + auto it = find(p_operName); + return get_help(it); +}; + +const CdoHelp & +get_help(OperatorMap::iterator p_it) +{ + auto &mod = get_module(p_it); + auto &help_iter = mod.get_help(p_it->first); + return help_iter; +} + +/** + * @param a pointer to a string/substring + * @param b pointer to a string/substring + * @param alen length of string a + * @param blen length of string b + * @retval true if a is similar to b + * @retval false if a is not similar to b + * + * Recursive function for finding substrings of a operator name that match other operators. + */ +static bool +similar(const char *a, const char *b, unsigned long alen, unsigned long blen) +{ + if (alen > 2 && blen > 2 && strstr(b, a)) return true; + + while (*a && *b && *a == *b) + { + a++; + b++; + } + if (!*a && !*b) return true; + + // printf("%d %d %s %s\n", alen, blen, a, b); + + if (alen >= 2 && blen >= 1 && *a && similar(a + 1, b, alen - 2, blen - 1)) return true; + + if (alen >= 1 && blen >= 2 && *b && similar(a, b + 1, alen - 1, blen - 2)) return true; + + return false; +} + +/** + * @param original string tested for similarity to \p other + * @param other string that \p original will be compared to + * @retval true if original and other are similar + * @retval false if not + * + * Wrapper function for #similar() to parse c++ strings to c strings + */ +static bool +similar(const std::string &original, const std::string &other) +{ + return (similar(original.c_str(), other.c_str(), original.size(), other.size())); +} + +/*** + * function for finding similar operator names for the given string + * @param operatorName operator name to find similar operators for + * @returns A string with all found names. The string is seqmented into lines + * with a max length of 75 characters + */ +std::string +find_similar_operators(const std::string &operatorName) +{ + std::string found_similar_operators = ""; + size_t lines = 1; + constexpr size_t line_length = 105; + + if (operatorName != "") + { + // Searching for similar operator names in operator to module map + for (const auto &str : Factory::get()) + { + if (similar(string_to_lower(operatorName), str.first)) + { + if (found_similar_operators.size() + str.first.size() > lines * line_length) + { + found_similar_operators += "\n"; + lines++; + } + found_similar_operators += str.first; + found_similar_operators += " "; + } + } + } + + if (found_similar_operators.size() == 0) { found_similar_operators = "(not found)"; } + return found_similar_operators; +} + +/*** + * Creates a sorted vector with all operator names and alisases excluding all modules that are marked as internal + * @return a sorted std::vector containing all operator names and aliases + * excluding all operators which modules are marked as internal + */ +std::vector<std::string> +get_sorted_operator_name_list() +{ + std::vector<std::string> names; + + auto &factory = Factory::get(); + + for (const auto &factory_entry : factory) + { + auto &module = factory_entry.second.module; + if (module.mode == 1) { names.push_back(factory_entry.first); } + } + + std::ranges::sort(names); + + return names; +} + +std::string +get_original(const std::string &operator_name) +{ + auto module = Factory::get_module(operator_name); + auto index = module.is_alias(operator_name); + if (index != -1) return module.aliases[index].original; + return operator_name; +} + +/*** + * Prints all operator names and their short descriptions + * Aliases are listed and point to their original operator name. + * If the module is not documented the description is empty + * If a module has only one operator the short module description is listed + * If the operator is not documented the description is empty + */ + +OperatorMap::iterator +find_module(const std::string &operator_name) +{ + return Factory::find(operator_name); +} + +std::vector<std::string> +get_module_operator_names(const std::string &module_name) +{ + + std::vector<std::string> operator_names; + + auto &modules = Factory::get(); + + std::string lower_name = ""; + for (auto c : module_name) { lower_name += c; } + + for (auto ®istered_mod : modules) + { + const CdoModule &mod = registered_mod.second.module; + + std::string lower_registered_name = ""; + for (auto c : mod.name) { lower_registered_name += c; } + + if (lower_registered_name == lower_name) + { + for (const oper_t &oper : mod.operators) { operator_names.push_back(oper.name); } + } + } + return operator_names; +} +}; // namespace Factory diff --git a/src/factory.h b/src/factory.h index 6f91629366e6bcbf92c530f118927c010f728012..7cf4a5375a25d464d46832a211ab5d644ec54a41 100644 --- a/src/factory.h +++ b/src/factory.h @@ -1,3 +1,10 @@ +/* + This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. + + Author: Uwe Schulzweida + Oliver Heidmann + +*/ #ifndef FACTORY_H #define FACTORY_H #include <vector> @@ -5,58 +12,75 @@ #include <map> #include <memory> #include <functional> -#include "modules.h" +#include <map> + +#include "cdo_module.h" +#include "cdo_output.h" #include "process.h" -std::map<const std::string, std::function<std::shared_ptr<Process>(int p_ID, const std::string &p_operatorNamme, - const std::vector<std::string> &operatorArguments)>> & -get_factory(); +namespace Factory +{ +// string -> pair(CdoModule,std::function) +typedef std::function<std::shared_ptr<Process>(int, const std::string &, const std::vector<std::string> &)> ModuleConstructor; -template <typename T> -struct CdoModule +struct FactoryEntry { + const CdoModule &module; + Factory::ModuleConstructor constructor; + + FactoryEntry(const CdoModule &mod, Factory::ModuleConstructor con) : module(mod), constructor(con) {} +}; +typedef std::map<std::string, FactoryEntry> OperatorMap; + +std::string find_similar_operators(const std::string &operatorName); + +std::vector<std::string> get_module_operator_names(const std::string &module_name); + +std::string get_original(const std::string &operatorName); + +std::vector<std::string> get_sorted_operator_name_list(); - std::string name; - std::vector<oper_t> operators; // Operator names - std::vector<Alias> aliases; - std::vector<char **> help; - short mode; // Module mode: 0:intern 1:extern - short number; // Allowed number type - module_constraints constraints; +OperatorMap &get(); // Factory::get() - struct RegisterEntry +OperatorMap::iterator find_module(const std::string &operatorName); +OperatorMap::iterator find(const std::string &p_opername); +OperatorMap::iterator find(const std::string &p_opername, std::function<void()> p_onError); + +const CdoModule &get_module(const std::string &p_operName); +const CdoModule &get_module(const OperatorMap::iterator &it); + +ModuleConstructor get_constructor(const std::string &p_operName); +ModuleConstructor get_constructor(const OperatorMap::iterator it); + +const CdoHelp &get_help(const std::string &p_operName); +const CdoHelp &get_help(OperatorMap::iterator p_it); +}; // namespace Factory + +template <typename T> +struct RegisterEntry +{ + Factory::ModuleConstructor + create_constructor(const CdoModule &mod) { - public: - RegisterEntry(CdoModule *t) - { - for (auto &oper : t->operators) - { - get_factory()[oper.name] = [](int p_ID, const std::string &p_operatorNamme, - const std::vector<std::string> &operatorArguments) -> std::shared_ptr<T> { - auto new_mod = std::make_shared<T>(); - new_mod->m_ID = p_ID; - new_mod->operatorName = p_operatorNamme; - new_mod->init_process(p_operatorNamme, operatorArguments); - /* START Temporary workaround, replace by proper sys */ - /* END Temporary workaround, replace by proper sys */ - return new_mod; - }; - std::cerr << "added " << oper.name << std::endl; - } - }; - }; + return + [&mod](int p_ID, const std::string &p_operName, const std::vector<std::string> &p_operatorArguments) -> std::shared_ptr<T> { - int - get_id(std::string oper) + Debug(FACTORY,"Creating process via factory function, %d = ID, %s = name, %s = mod_name", p_ID, p_operName, mod.name); + auto new_process = std::make_shared<T>(p_ID, p_operName, p_operatorArguments, mod); + return new_process; + }; + } + void + register_operator(const CdoModule &mod, std::string &p_oper_name) { - for (size_t i = 0; i < operators.size(); i++) - { - if (oper == operators[i].name) { return i; } - } - return -1; + Factory::get().insert(std::make_pair(p_oper_name, Factory::FactoryEntry(mod, create_constructor(mod)))); } - RegisterEntry registration = RegisterEntry(this); +public: + RegisterEntry(CdoModule &module) + { + for (auto &oper : module.operators) { register_operator(module, oper.name); } + for (auto &alias : module.aliases) { register_operator(module, alias.alias); } + }; }; - #endif diff --git a/src/field.cc b/src/field.cc index 988431e2fc8a02ef19b60bd371794b1577400bfd..1e240fceb9ad23657766fa99e245f776cb00840a 100644 --- a/src/field.cc +++ b/src/field.cc @@ -23,7 +23,7 @@ Field::init(const CdoVar &var) nwpv = 1; grid = var.gridID; gridsize = var.gridsize; - nmiss = 0; + numMissVals = 0; missval = var.missval; memType = var.memType; size = var.gridsize * var.nwpv; @@ -115,7 +115,7 @@ field_ncopy(size_t n, const Field &fieldIn, Field &fieldOut) if (n > fieldIn.size) cdo_abort("Source field to small (%s)", __func__); if (n > fieldOut.size) cdo_abort("Target field to small (%s)", __func__); - fieldOut.nmiss = fieldIn.nmiss; + fieldOut.numMissVals = fieldIn.numMissVals; // clang-format off if (memtype_is_float_float (fieldIn.memType, fieldOut.memType)) varray_copy(n, fieldIn.vec_f, fieldOut.vec_f); @@ -131,7 +131,7 @@ field_copy(const Field &fieldIn, Field &fieldOut) { if (fieldIn.size > fieldOut.size) cdo_abort("Target field to small (%s)", __func__); - fieldOut.nmiss = fieldIn.nmiss; + fieldOut.numMissVals = fieldIn.numMissVals; if (fieldIn.memType == MemType::Float) fieldOut.vec_f = fieldIn.vec_f; @@ -144,7 +144,7 @@ field_copy(const Field3D &fieldIn, Field3D &fieldOut) { if (fieldIn.size > fieldOut.size) cdo_abort("Target field to small (%s)", __func__); - fieldOut.nmiss = fieldIn.nmiss; + fieldOut.numMissVals = fieldIn.numMissVals; if (fieldIn.memType == MemType::Float) fieldOut.vec_f = fieldIn.vec_f; @@ -220,75 +220,75 @@ size_t field_num_mv(Field &field) { if (field.memType == MemType::Float) - field.nmiss = varray_num_mv(field.size, field.vec_f, (float) field.missval); + field.numMissVals = varray_num_mv(field.size, field.vec_f, (float) field.missval); else - field.nmiss = varray_num_mv(field.size, field.vec_d, field.missval); + field.numMissVals = varray_num_mv(field.size, field.vec_d, field.missval); - return field.nmiss; + return field.numMissVals; } MinMax field_min_max(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_min_max_mv(field.size, field.vec_f, (float) field.missval) : varray_min_max(field.vec_f); + return field.numMissVals ? varray_min_max_mv(field.size, field.vec_f, (float) field.missval) : varray_min_max(field.vec_f); else - return field.nmiss ? varray_min_max_mv(field.size, field.vec_d, field.missval) : varray_min_max(field.vec_d); + return field.numMissVals ? varray_min_max_mv(field.size, field.vec_d, field.missval) : varray_min_max(field.vec_d); } double field_min(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_min_mv(field.size, field.vec_f, (float) field.missval) : varray_min(field.size, field.vec_f); + return field.numMissVals ? varray_min_mv(field.size, field.vec_f, (float) field.missval) : varray_min(field.size, field.vec_f); else - return field.nmiss ? varray_min_mv(field.size, field.vec_d, field.missval) : varray_min(field.size, field.vec_d); + return field.numMissVals ? varray_min_mv(field.size, field.vec_d, field.missval) : varray_min(field.size, field.vec_d); } double field_max(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_max_mv(field.size, field.vec_f, (float) field.missval) : varray_max(field.size, field.vec_f); + return field.numMissVals ? varray_max_mv(field.size, field.vec_f, (float) field.missval) : varray_max(field.size, field.vec_f); else - return field.nmiss ? varray_max_mv(field.size, field.vec_d, field.missval) : varray_max(field.size, field.vec_d); + return field.numMissVals ? varray_max_mv(field.size, field.vec_d, field.missval) : varray_max(field.size, field.vec_d); } double field_range(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_range_mv(field.size, field.vec_f, (float) field.missval) : varray_range(field.size, field.vec_f); + return field.numMissVals ? varray_range_mv(field.size, field.vec_f, (float) field.missval) : varray_range(field.size, field.vec_f); else - return field.nmiss ? varray_range_mv(field.size, field.vec_d, field.missval) : varray_range(field.size, field.vec_d); + return field.numMissVals ? varray_range_mv(field.size, field.vec_d, field.missval) : varray_range(field.size, field.vec_d); } double field_sum(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_sum_mv(field.size, field.vec_f, (float) field.missval) : varray_sum(field.size, field.vec_f); + return field.numMissVals ? varray_sum_mv(field.size, field.vec_f, (float) field.missval) : varray_sum(field.size, field.vec_f); else - return field.nmiss ? varray_sum_mv(field.size, field.vec_d, field.missval) : varray_sum(field.size, field.vec_d); + return field.numMissVals ? varray_sum_mv(field.size, field.vec_d, field.missval) : varray_sum(field.size, field.vec_d); } double field_mean(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_mean_mv(field.size, field.vec_f, (float) field.missval) : varray_mean(field.size, field.vec_f); + return field.numMissVals ? varray_mean_mv(field.size, field.vec_f, (float) field.missval) : varray_mean(field.size, field.vec_f); else - return field.nmiss ? varray_mean_mv(field.size, field.vec_d, field.missval) : varray_mean(field.size, field.vec_d); + return field.numMissVals ? varray_mean_mv(field.size, field.vec_d, field.missval) : varray_mean(field.size, field.vec_d); } double field_meanw(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_weighted_mean_mv(field.size, field.vec_f, field.weightv, (float) field.missval) + return field.numMissVals ? varray_weighted_mean_mv(field.size, field.vec_f, field.weightv, (float) field.missval) : varray_weighted_mean(field.size, field.vec_f, field.weightv, (float) field.missval); else - return field.nmiss ? varray_weighted_mean_mv(field.size, field.vec_d, field.weightv, field.missval) + return field.numMissVals ? varray_weighted_mean_mv(field.size, field.vec_d, field.weightv, field.missval) : varray_weighted_mean(field.size, field.vec_d, field.weightv, field.missval); } @@ -296,19 +296,19 @@ double field_avg(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_avg_mv(field.size, field.vec_f, (float) field.missval) : varray_mean(field.size, field.vec_f); + return field.numMissVals ? varray_avg_mv(field.size, field.vec_f, (float) field.missval) : varray_mean(field.size, field.vec_f); else - return field.nmiss ? varray_avg_mv(field.size, field.vec_d, field.missval) : varray_mean(field.size, field.vec_d); + return field.numMissVals ? varray_avg_mv(field.size, field.vec_d, field.missval) : varray_mean(field.size, field.vec_d); } double field_avgw(const Field &field) { if (field.memType == MemType::Float) - return field.nmiss ? varray_weighted_avg_mv(field.size, field.vec_f, field.weightv, (float) field.missval) + return field.numMissVals ? varray_weighted_avg_mv(field.size, field.vec_f, field.weightv, (float) field.missval) : varray_weighted_mean(field.size, field.vec_f, field.weightv, (float) field.missval); else - return field.nmiss ? varray_weighted_avg_mv(field.size, field.vec_d, field.weightv, field.missval) + return field.numMissVals ? varray_weighted_avg_mv(field.size, field.vec_d, field.weightv, field.missval) : varray_weighted_mean(field.size, field.vec_d, field.weightv, field.missval); } @@ -316,72 +316,72 @@ double field_var(const Field &field) { if (field.memType == MemType::Float) - return varray_var(field.size, field.vec_f, field.nmiss, (float) field.missval); + return varray_var(field.size, field.vec_f, field.numMissVals, (float) field.missval); else - return varray_var(field.size, field.vec_d, field.nmiss, field.missval); + return varray_var(field.size, field.vec_d, field.numMissVals, field.missval); } double field_var1(const Field &field) { if (field.memType == MemType::Float) - return varray_var_1(field.size, field.vec_f, field.nmiss, (float) field.missval); + return varray_var_1(field.size, field.vec_f, field.numMissVals, (float) field.missval); else - return varray_var_1(field.size, field.vec_d, field.nmiss, field.missval); + return varray_var_1(field.size, field.vec_d, field.numMissVals, field.missval); } double field_skew(const Field &field) { if (field.memType == MemType::Float) - return varray_skew(field.size, field.vec_f, field.nmiss, (float) field.missval); + return varray_skew(field.size, field.vec_f, field.numMissVals, (float) field.missval); else - return varray_skew(field.size, field.vec_d, field.nmiss, field.missval); + return varray_skew(field.size, field.vec_d, field.numMissVals, field.missval); } double field_kurt(const Field &field) { if (field.memType == MemType::Float) - return varray_kurt(field.size, field.vec_f, field.nmiss, (float) field.missval); + return varray_kurt(field.size, field.vec_f, field.numMissVals, (float) field.missval); else - return varray_kurt(field.size, field.vec_d, field.nmiss, field.missval); + return varray_kurt(field.size, field.vec_d, field.numMissVals, field.missval); } double field_median(const Field &field) { if (field.memType == MemType::Float) - return varray_median(field.size, field.vec_f, field.nmiss, (float) field.missval); + return varray_median(field.size, field.vec_f, field.numMissVals, (float) field.missval); else - return varray_median(field.size, field.vec_d, field.nmiss, field.missval); + return varray_median(field.size, field.vec_d, field.numMissVals, field.missval); } double field_count(const Field &field) { if (field.memType == MemType::Float) - return varray_count(field.size, field.vec_f, field.nmiss, (float) field.missval); + return varray_count(field.size, field.vec_f, field.numMissVals, (float) field.missval); else - return varray_count(field.size, field.vec_d, field.nmiss, field.missval); + return varray_count(field.size, field.vec_d, field.numMissVals, field.missval); } double field_varw(const Field &field) { if (field.memType == MemType::Float) - return varray_weighted_var(field.size, field.vec_f, field.weightv, field.nmiss, (float) field.missval); + return varray_weighted_var(field.size, field.vec_f, field.weightv, field.numMissVals, (float) field.missval); else - return varray_weighted_var(field.size, field.vec_d, field.weightv, field.nmiss, field.missval); + return varray_weighted_var(field.size, field.vec_d, field.weightv, field.numMissVals, field.missval); } double field_var1w(const Field &field) { if (field.memType == MemType::Float) - return varray_weighted_var_1(field.size, field.vec_f, field.weightv, field.nmiss, (float) field.missval); + return varray_weighted_var_1(field.size, field.vec_f, field.weightv, field.numMissVals, (float) field.missval); else - return varray_weighted_var_1(field.size, field.vec_d, field.weightv, field.nmiss, field.missval); + return varray_weighted_var_1(field.size, field.vec_d, field.weightv, field.numMissVals, field.missval); } double @@ -419,12 +419,12 @@ field_std1w(const Field &field) void field_rms(const Field &field, const Field &field2, Field &field3) { - size_t rnmiss = 0; + size_t rnumMissVals = 0; auto grid1 = field.grid; - // size_t nmiss1 = field.nmiss; + // size_t numMissVals1 = field.numMissVals; const auto array1 = field.vec_d.data(); auto grid2 = field2.grid; - // size_t nmiss2 = field2.nmiss; + // size_t numMissVals2 = field2.numMissVals; const auto array2 = field2.vec_d.data(); auto missval1 = field.missval; auto missval2 = field2.missval; @@ -435,7 +435,7 @@ field_rms(const Field &field, const Field &field2, Field &field3) auto len = gridInqSize(grid1); if (len != gridInqSize(grid2)) cdo_abort("fields have different size!"); - // if ( nmiss1 ) + // if ( numMissVals1 ) { for (size_t i = 0; i < len; ++i) if (!is_EQ(w[i], missval1)) @@ -457,21 +457,21 @@ else auto ravg = SQRTM(DIVM(rsum, rsumw)); - if (is_EQ(ravg, missval1)) rnmiss++; + if (is_EQ(ravg, missval1)) rnumMissVals++; field3.vec_d[0] = ravg; - field3.nmiss = rnmiss; + field3.numMissVals = rnumMissVals; } template <typename T> double -array_pctl(size_t len, T *array, size_t nmiss, T missval, double pn) +array_pctl(size_t len, T *array, size_t numMissVals, T missval, double pn) { double pctl = missval; - if (len != nmiss) + if (len != numMissVals) { - if (nmiss) + if (numMissVals) { Varray<T> v(len); @@ -479,8 +479,8 @@ array_pctl(size_t len, T *array, size_t nmiss, T missval, double pn) for (size_t i = 0; i < len; ++i) if (!dbl_is_equal(array[i], missval)) v[j++] = array[i]; - if (nmiss != len - j) - cdo_warning("Internal problem, inconsistent number of missing values (nmiss: exprected=%zu found=%zu!)", nmiss, + if (numMissVals != len - j) + cdo_warning("Internal problem, inconsistent number of missing values (numMissVals: exprected=%zu found=%zu!)", numMissVals, len - j); pctl = percentile(v.data(), j, pn); @@ -495,9 +495,9 @@ double field_pctl(Field &field, double pn) { if (field.memType == MemType::Float) - return array_pctl(field.size, field.vec_f.data(), field.nmiss, (float) field.missval, pn); + return array_pctl(field.size, field.vec_f.data(), field.numMissVals, (float) field.missval, pn); else - return array_pctl(field.size, field.vec_d.data(), field.nmiss, field.missval, pn); + return array_pctl(field.size, field.vec_d.data(), field.numMissVals, field.missval, pn); } static int @@ -517,7 +517,7 @@ field_rank(Field &field) const auto array = &field.vec_d[1]; auto len = field.size - 1; - if (field.nmiss) return field.missval; + if (field.numMissVals) return field.missval; std::qsort(array, len, sizeof(double), compare_double); diff --git a/src/field.h b/src/field.h index 0b6ab0b85e4da4966d532c7957a39da1de00f672..870a5b43c52f169f235ec0ea23946bb0209db650 100644 --- a/src/field.h +++ b/src/field.h @@ -47,7 +47,7 @@ public: size_t size = 0; size_t nsamp = 0; - size_t nmiss = 0; + size_t numMissVals = 0; double missval = 0; Varray<float> vec_f; @@ -92,8 +92,17 @@ struct RecordInfo { int varID = 0; int levelID = 0; - void set(int _varID, int _levelID) { this->varID = _varID; this->levelID = _levelID; } - std::pair<int, int> get() const { return std::make_pair(varID, levelID); } + void + set(int _varID, int _levelID) + { + this->varID = _varID; + this->levelID = _levelID; + } + std::pair<int, int> + get() const + { + return std::make_pair(varID, levelID); + } }; using FieldVector = std::vector<Field>; diff --git a/src/field2.cc b/src/field2.cc index 9bf4f885ad9e14ba613b9cc59d1568f8d80588bb..ee80cd65ed4b07ad70f1616c51e497757ac6f559 100644 --- a/src/field2.cc +++ b/src/field2.cc @@ -126,7 +126,7 @@ field2_vinit(Field &field1, const Field &field2) else varray2_arith_mv(field1.size, field1.vec_d, field2.vec_d, field1.missval, field2.missval, arith_vinit_mv); - field1.nmiss = field2.nmiss; + field1.numMissVals = field2.numMissVals; } // increment valid values @@ -144,7 +144,7 @@ field2_vincr(Field &field1, const Field &field2) else varray2_arith_mv(field1.size, field1.vec_d, field2.vec_d, field1.missval, field2.missval, arith_vincr_mv); - field1.nmiss = field2.nmiss; + field1.numMissVals = field2.numMissVals; } // init valid values @@ -169,7 +169,7 @@ field2_vinit(Field &field1, const Field &field2, int vinit) else field2_vinit(field1.size, field1.vec_d, field2.vec_d, field1.missval, vinit); - field1.nmiss = field2.nmiss; + field1.numMissVals = field2.numMissVals; } // increment valid values @@ -195,7 +195,7 @@ field2_vincr(Field &field1, const Field &field2, int vincr) else field2_vincr(field1.size, field1.vec_d, field2.vec_d, field1.missval, vincr); - field1.nmiss = field2.nmiss; + field1.numMissVals = field2.numMissVals; } void @@ -203,7 +203,7 @@ field2_add(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_add_mv); @@ -234,7 +234,7 @@ field2_sum(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_sum_mv); @@ -271,7 +271,7 @@ field2_sumw(Field &field1, const Field &field2, double w) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { #ifdef _OPENMP #pragma omp parallel for default(shared) schedule(static) @@ -285,7 +285,7 @@ field2_sumw(Field &field1, const Field &field2, double w) array1[i] = w * array2[i]; } - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } else { @@ -314,7 +314,7 @@ field2_sumtr(Field &occur, const Field &field, double refval) auto len = occur.size; if (len != field.size) cdo_abort("Fields have different size (%s)", __func__); - if (occur.nmiss || field.nmiss) + if (occur.numMissVals || field.numMissVals) { #ifdef _OPENMP #pragma omp parallel for default(shared) schedule(static) @@ -332,7 +332,7 @@ field2_sumtr(Field &occur, const Field &field, double refval) if (!dbl_is_equal(oarray[i], omissval)) oarray[i] = 0.0; } - occur.nmiss = field_num_miss(occur); + occur.numMissVals = field_num_miss(occur); } else { @@ -348,7 +348,7 @@ field2_sumq(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_sumq_mv); @@ -392,7 +392,7 @@ field2_sumqw(Field &field1, const Field &field2, double w) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { #ifdef _OPENMP #pragma omp parallel for default(shared) schedule(static) @@ -406,7 +406,7 @@ field2_sumqw(Field &field1, const Field &field2, double w) array1[i] = w * array2[i] * array2[i]; } - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } else { @@ -422,7 +422,7 @@ field2_sub(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_sub_mv); @@ -453,7 +453,7 @@ field2_mul(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_mul_mv); @@ -484,7 +484,7 @@ field2_div(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_div_mv); @@ -539,11 +539,11 @@ field2_set_miss(Field &field1, const Field &field2) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss) + if (field1.numMissVals) { for (size_t i = 0; i < len; ++i) array1[i] = dbl_is_equal(array1[i], missval1) ? array2[i] : array1[i]; - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } } @@ -552,7 +552,7 @@ field2_min(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_min_mv); @@ -583,7 +583,7 @@ field2_max(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_arith_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval, arith_max_mv); @@ -623,14 +623,14 @@ auto field2_set_index = [](auto &v1, auto &v2, auto v3, auto idx) { template <typename T> void -field2_minidx(size_t nmiss3, size_t len, double missval3, Field &field1, Field &field2, const Varray<T> &v3, int idx) +field2_minidx(size_t numMissVals3, size_t len, double missval3, Field &field1, Field &field2, const Varray<T> &v3, int idx) { auto missval1 = field1.missval; auto missval2 = field2.missval; auto &v1 = field1.vec_d; auto &v2 = field2.vec_d; - if (field2.nmiss || nmiss3) + if (field2.numMissVals || numMissVals3) { for (size_t i = 0; i < len; ++i) { @@ -660,21 +660,21 @@ field2_minidx(Field &field1, Field &field2, const Field &field3, int idx) if (field2.size != field3.size) cdo_abort("Fields have different size (%s)", __func__); if (field3.memType == MemType::Float) - field2_minidx(field3.nmiss, field3.size, field3.missval, field1, field2, field3.vec_f, idx); + field2_minidx(field3.numMissVals, field3.size, field3.missval, field1, field2, field3.vec_f, idx); else - field2_minidx(field3.nmiss, field3.size, field3.missval, field1, field2, field3.vec_d, idx); + field2_minidx(field3.numMissVals, field3.size, field3.missval, field1, field2, field3.vec_d, idx); } template <typename T> void -field2_maxidx(size_t nmiss3, size_t len, double missval3, Field &field1, Field &field2, const Varray<T> &v3, int idx) +field2_maxidx(size_t numMissVals3, size_t len, double missval3, Field &field1, Field &field2, const Varray<T> &v3, int idx) { auto missval1 = field1.missval; auto missval2 = field2.missval; auto &v1 = field1.vec_d; auto &v2 = field2.vec_d; - if (field2.nmiss || nmiss3) + if (field2.numMissVals || numMissVals3) { for (size_t i = 0; i < len; ++i) { @@ -704,15 +704,15 @@ field2_maxidx(Field &field1, Field &field2, const Field &field3, int idx) if (field2.size != field3.size) cdo_abort("Fields have different size (%s)", __func__); if (field3.memType == MemType::Float) - field2_maxidx(field3.nmiss, field3.size, field3.missval, field1, field2, field3.vec_f, idx); + field2_maxidx(field3.numMissVals, field3.size, field3.missval, field1, field2, field3.vec_f, idx); else - field2_maxidx(field3.nmiss, field3.size, field3.missval, field1, field2, field3.vec_d, idx); + field2_maxidx(field3.numMissVals, field3.size, field3.missval, field1, field2, field3.vec_d, idx); } static size_t -field_set_nmiss(size_t len, Varray<double> &v, double missval) +field_set_numMissVals(size_t len, Varray<double> &v, double missval) { - size_t nmiss = 0; + size_t numMissVals = 0; if (std::isnan(missval)) { @@ -720,7 +720,7 @@ field_set_nmiss(size_t len, Varray<double> &v, double missval) if (dbl_is_equal(v[i], missval) || v[i] < 0) { v[i] = missval; - nmiss++; + numMissVals++; } } else @@ -729,11 +729,11 @@ field_set_nmiss(size_t len, Varray<double> &v, double missval) if (is_equal(v[i], missval) || v[i] < 0) { v[i] = missval; - nmiss++; + numMissVals++; } } - return nmiss; + return numMissVals; } void @@ -748,7 +748,7 @@ field2_var(Field &field1, const Field &field2, const Field &field3, int divisor) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { auto is_EQ = dbl_is_equal; for (size_t i = 0; i < len; ++i) @@ -768,7 +768,7 @@ field2_var(Field &field1, const Field &field2, const Field &field3, int divisor) } } - field1.nmiss = field_set_nmiss(len, array1, missval1); + field1.numMissVals = field_set_numMissVals(len, array1, missval1); } void @@ -782,15 +782,15 @@ field2_std(Field &field1, const Field &field2, const Field &field3, int divisor) field2_var(field1, field2, field3, divisor); - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < len; ++i) if (dbl_is_equal(array1[i], missval1) || array1[i] < 0) { array1[i] = missval1; - nmiss++; + numMissVals++; } else { array1[i] = is_not_equal(array1[i], 0) ? std::sqrt(array1[i]) : 0; } - field1.nmiss = nmiss; + field1.numMissVals = numMissVals; } void @@ -809,7 +809,7 @@ fieldc_var(Field &field1, const Field &field2, int numSets, int divisor) { for (size_t i = 0; i < len; ++i) array1[i] = missval1; } - else if (field1.nmiss || field2.nmiss) + else if (field1.numMissVals || field2.numMissVals) { auto is_EQ = dbl_is_equal; for (size_t i = 0; i < len; ++i) @@ -829,7 +829,7 @@ fieldc_var(Field &field1, const Field &field2, int numSets, int divisor) } } - field1.nmiss = field_set_nmiss(len, array1, missval1); + field1.numMissVals = field_set_numMissVals(len, array1, missval1); } void @@ -843,16 +843,16 @@ fieldc_std(Field &field1, const Field &field2, int numSets, int divisor) fieldc_var(field1, field2, numSets, divisor); - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < len; ++i) if (dbl_is_equal(array1[i], missval1) || array1[i] < 0) { array1[i] = missval1; - nmiss++; + numMissVals++; } else { array1[i] = is_not_equal(array1[i], 0) ? std::sqrt(array1[i]) : 0; } - field1.nmiss = nmiss; + field1.numMissVals = numMissVals; } void @@ -866,7 +866,7 @@ field2_moq(Field &field1, const Field &field2) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field2.nmiss) + if (field2.numMissVals) { for (size_t i = 0; i < len; ++i) if (!dbl_is_equal(array2[i], missval2)) @@ -874,7 +874,7 @@ field2_moq(Field &field1, const Field &field2) else array1[i] = missval1; - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } else { @@ -893,7 +893,7 @@ field2_moqw(Field &field1, const Field &field2, double w) auto len = field1.size; if (len != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field2.nmiss) + if (field2.numMissVals) { for (size_t i = 0; i < len; ++i) if (!dbl_is_equal(array2[i], missval2)) @@ -901,7 +901,7 @@ field2_moqw(Field &field1, const Field &field2, double w) else array1[i] = missval1; - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } else { @@ -910,7 +910,7 @@ field2_moqw(Field &field1, const Field &field2, double w) } /** - * Counts the number of nonmissing values. The result of the operation is computed according to the following rules: + * Counts the number of nonumMissValsing values. The result of the operation is computed according to the following rules: * * field1 field2 result * a b a + 1 @@ -955,7 +955,7 @@ field2_count(Field &field1, const Field &field2) { if (field1.size != field2.size) cdo_abort("Fields have different size (%s)", __func__); - if (field1.nmiss || field2.nmiss) + if (field1.numMissVals || field2.numMissVals) { if (memtype_is_float_float(field1.memType, field2.memType)) varray2_count_mv(field1.size, field1.vec_f, field2.vec_f, field1.missval, field2.missval); @@ -966,7 +966,7 @@ field2_count(Field &field1, const Field &field2) else varray2_count_mv(field1.size, field1.vec_d, field2.vec_d, field1.missval, field2.missval); - field1.nmiss = field_num_miss(field1); + field1.numMissVals = field_num_miss(field1); } else { diff --git a/src/field_meridional.cc b/src/field_meridional.cc index 6b40579662a57428ecd69bf47964433aac053383..afac0b9dee7539b5922a967216012d289b09f695 100644 --- a/src/field_meridional.cc +++ b/src/field_meridional.cc @@ -28,8 +28,8 @@ varray_copy_meridional(size_t i, size_t nx, size_t ny, const Varray<T> &v1, Varr static void meridional_kernel_1(const Field &field1, Field &field2, funcType1 func, funcTypeMV1 funcMV) { - size_t rnmiss = 0; - auto nmiss = field1.nmiss; + size_t rnumMissVals = 0; + auto numMissVals = field1.numMissVals; auto missval = field1.missval; auto nx = gridInqXsize(field1.grid); auto ny = gridInqYsize(field1.grid); @@ -43,19 +43,19 @@ meridional_kernel_1(const Field &field1, Field &field2, funcType1 func, funcType else varray_copy_meridional(i, nx, ny, field1.vec_d, v); - auto result = nmiss ? funcMV(ny, v, missval) : func(ny, v); - if (dbl_is_equal(result, missval)) rnmiss++; + auto result = numMissVals ? funcMV(ny, v, missval) : func(ny, v); + if (dbl_is_equal(result, missval)) rnumMissVals++; field2.vec_d[i] = result; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } static void meridional_kernel_2(const Field &field1, Field &field2, funcType2 func, funcTypeMV2 funcMV) { - size_t rnmiss = 0; - auto nmiss = field1.nmiss; + size_t rnumMissVals = 0; + auto numMissVals = field1.numMissVals; auto missval = field1.missval; auto nx = gridInqXsize(field1.grid); auto ny = gridInqYsize(field1.grid); @@ -70,19 +70,19 @@ meridional_kernel_2(const Field &field1, Field &field2, funcType2 func, funcType else varray_copy_meridional(i, nx, ny, field1.vec_d, v); - auto result = nmiss ? funcMV(ny, v, w, missval) : func(ny, v, w, missval); - if (dbl_is_equal(result, missval)) rnmiss++; + auto result = numMissVals ? funcMV(ny, v, w, missval) : func(ny, v, w, missval); + if (dbl_is_equal(result, missval)) rnumMissVals++; field2.vec_d[i] = result; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } static void meridional_kernel_3(const Field &field1, Field &field2, funcType3 func) { - size_t rnmiss = 0; - auto nmiss = field1.nmiss; + size_t rnumMissVals = 0; + auto numMissVals = field1.numMissVals; auto missval = field1.missval; auto nx = gridInqXsize(field1.grid); auto ny = gridInqYsize(field1.grid); @@ -97,19 +97,19 @@ meridional_kernel_3(const Field &field1, Field &field2, funcType3 func) else varray_copy_meridional(i, nx, ny, field1.vec_d, v); - auto result = func(ny, v, w, nmiss, missval); - if (dbl_is_equal(result, missval)) rnmiss++; + auto result = func(ny, v, w, numMissVals, missval); + if (dbl_is_equal(result, missval)) rnumMissVals++; field2.vec_d[i] = result; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } static void meridional_kernel_4(const Field &field1, Field &field2, funcType4 func) { - size_t rnmiss = 0; - auto nmiss = field1.nmiss; + size_t rnumMissVals = 0; + auto numMissVals = field1.numMissVals; auto missval = field1.missval; auto nx = gridInqXsize(field1.grid); auto ny = gridInqYsize(field1.grid); @@ -123,13 +123,13 @@ meridional_kernel_4(const Field &field1, Field &field2, funcType4 func) else varray_copy_meridional(i, nx, ny, field1.vec_d, v); - auto numMissval = ny - varray_count(ny, v, nmiss, missval); + auto numMissval = ny - varray_count(ny, v, numMissVals, missval); auto result = func(ny, v, numMissval, missval); - if (dbl_is_equal(result, missval)) rnmiss++; + if (dbl_is_equal(result, missval)) rnumMissVals++; field2.vec_d[i] = result; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } static void @@ -183,7 +183,7 @@ meridional_var1w(const Field &field1, Field &field2) static void meridional_stdw(const Field &field1, Field &field2) { - size_t rnmiss = 0; + size_t rnumMissVals = 0; auto missval = field1.missval; auto nx = gridInqXsize(field1.grid); @@ -193,17 +193,17 @@ meridional_stdw(const Field &field1, Field &field2) for (size_t i = 0; i < nx; ++i) { auto rstd = var_to_std(field2.vec_d[i], missval); - if (dbl_is_equal(rstd, missval)) rnmiss++; + if (dbl_is_equal(rstd, missval)) rnumMissVals++; field2.vec_d[i] = rstd; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } static void meridional_std1w(const Field &field1, Field &field2) { - size_t rnmiss = 0; + size_t rnumMissVals = 0; auto missval = field1.missval; auto nx = gridInqXsize(field1.grid); @@ -213,11 +213,11 @@ meridional_std1w(const Field &field1, Field &field2) for (size_t i = 0; i < nx; ++i) { auto rstd = var_to_std(field2.vec_d[i], missval); - if (dbl_is_equal(rstd, missval)) rnmiss++; + if (dbl_is_equal(rstd, missval)) rnumMissVals++; field2.vec_d[i] = rstd; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } static void @@ -241,7 +241,7 @@ meridional_median(const Field &field1, Field &field2) void meridional_pctl(const Field &field1, Field &field2, double pn) { - size_t rnmiss = 0; + size_t rnumMissVals = 0; auto missval = field1.missval; auto nx = gridInqXsize(field1.grid); @@ -249,7 +249,7 @@ meridional_pctl(const Field &field1, Field &field2, double pn) Varray<double> v(ny); - if (field1.nmiss) + if (field1.numMissVals) { for (size_t i = 0; i < nx; ++i) { @@ -269,7 +269,7 @@ meridional_pctl(const Field &field1, Field &field2, double pn) else { field2.vec_d[i] = missval; - rnmiss++; + rnumMissVals++; } } } @@ -289,12 +289,12 @@ meridional_pctl(const Field &field1, Field &field2, double pn) else { field2.vec_d[i] = missval; - rnmiss++; + rnumMissVals++; } } } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } void diff --git a/src/field_vinterp.cc b/src/field_vinterp.cc index d5e0d529e7c779cf5a2598c2dc5dee40d383db4a..f46b63847f783aa9da178395fb11a525e994d2b1 100644 --- a/src/field_vinterp.cc +++ b/src/field_vinterp.cc @@ -19,14 +19,14 @@ gen_vert_index(std::vector<int> &vertIndex, Varray<double> &plev, Field3D &full_ } void -gen_vert_index_mv(std::vector<int> &vertIndex, Varray<double> &plev, size_t gridsize, Field &level0, Varray<size_t> &pnmiss, +gen_vert_index_mv(std::vector<int> &vertIndex, Varray<double> &plev, size_t gridsize, Field &level0, Varray<size_t> &pnumMissVals, bool lreverse) { auto nplev = plev.size(); if (level0.memType == MemType::Float) - gen_vert_index_mv(vertIndex.data(), plev.data(), gridsize, nplev, level0.vec_f.data(), pnmiss.data(), lreverse); + gen_vert_index_mv(vertIndex.data(), plev.data(), gridsize, nplev, level0.vec_f.data(), pnumMissVals.data(), lreverse); else - gen_vert_index_mv(vertIndex.data(), plev.data(), gridsize, nplev, level0.vec_d.data(), pnmiss.data(), lreverse); + gen_vert_index_mv(vertIndex.data(), plev.data(), gridsize, nplev, level0.vec_d.data(), pnumMissVals.data(), lreverse); } void diff --git a/src/field_vinterp.h b/src/field_vinterp.h index 8e9ff78e3c8b9e2a911fb316166a3bc730ea12fa..7c0416b3477443ba07ca0f5563c04740c65664da 100644 --- a/src/field_vinterp.h +++ b/src/field_vinterp.h @@ -12,7 +12,7 @@ void gen_vert_index(std::vector<int> &vertIndex, Varray<double> &plev, Field3D &full_level, size_t gridsize, bool lreverse = false); -void gen_vert_index_mv(std::vector<int> &vertIndex, Varray<double> &plev, size_t gridsize, Field &level0, Varray<size_t> &pnmiss, +void gen_vert_index_mv(std::vector<int> &vertIndex, Varray<double> &plev, size_t gridsize, Field &level0, Varray<size_t> &pnumMissVals, bool lreverse = false); void vertical_interp_T(size_t nlevels, Field3D &full_level, Field3D &half_level, Field3D &field1, Field3D &field2, Field &sgeopot, diff --git a/src/field_zonal.cc b/src/field_zonal.cc index 7c0db28becf58c839f443482e700738fb3f2f198..7ba5239a7cf01156c15ba4e1bc3e8b421b93630a 100644 --- a/src/field_zonal.cc +++ b/src/field_zonal.cc @@ -51,8 +51,8 @@ using funcTypeNmissMV = double(size_t, const Varray<double> &, size_t, double); static void zonal_kernel_1(const Field &field1, Field &field2, funcTypeNmissMV funcNmissMV) { - size_t rnmiss = 0; - auto nmiss = field1.nmiss; + size_t rnumMissVals = 0; + auto numMissVals = field1.numMissVals; auto missval = field1.missval; auto ny = gridInqYsize(field1.grid); @@ -68,20 +68,20 @@ zonal_kernel_1(const Field &field1, Field &field2, funcTypeNmissMV funcNmissMV) size_t offset = isReducedGrid ? cumreducedPoints[j] : j * nx; copy_latitude_row(offset, nx, field1, v); - auto numMissval = nx - varray_count(nx, v, nmiss, missval); + auto numMissval = nx - varray_count(nx, v, numMissVals, missval); auto result = funcNmissMV(nx, v, numMissval, missval); - if (dbl_is_equal(result, missval)) rnmiss++; + if (dbl_is_equal(result, missval)) rnumMissVals++; field2.vec_d[j] = result; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } static void zonal_kernel_2(const Field &field1, Field &field2, funcType func, funcTypeMV funcMV) { - size_t rnmiss = 0; - auto nmiss = field1.nmiss; + size_t rnumMissVals = 0; + auto numMissVals = field1.numMissVals; auto missval = field1.missval; auto ny = gridInqYsize(field1.grid); @@ -97,12 +97,12 @@ zonal_kernel_2(const Field &field1, Field &field2, funcType func, funcTypeMV fun size_t offset = isReducedGrid ? cumreducedPoints[j] : j * nx; copy_latitude_row(offset, nx, field1, v); - auto result = nmiss ? funcMV(nx, v, missval) : func(nx, v); - if (dbl_is_equal(result, missval)) rnmiss++; + auto result = numMissVals ? funcMV(nx, v, missval) : func(nx, v); + if (dbl_is_equal(result, missval)) rnumMissVals++; field2.vec_d[j] = result; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } void @@ -156,7 +156,7 @@ zonal_var1(const Field &field1, Field &field2) void zonal_std(const Field &field1, Field &field2) { - size_t rnmiss = 0; + size_t rnumMissVals = 0; auto missval = field2.missval; auto ny = gridInqYsize(field2.grid); @@ -165,17 +165,17 @@ zonal_std(const Field &field1, Field &field2) for (size_t j = 0; j < ny; ++j) { auto rstd = var_to_std(field2.vec_d[j], missval); - if (dbl_is_equal(rstd, missval)) rnmiss++; + if (dbl_is_equal(rstd, missval)) rnumMissVals++; field2.vec_d[j] = rstd; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } void zonal_std1(const Field &field1, Field &field2) { - size_t rnmiss = 0; + size_t rnumMissVals = 0; auto missval = field2.missval; auto ny = gridInqYsize(field2.grid); @@ -184,11 +184,11 @@ zonal_std1(const Field &field1, Field &field2) for (size_t j = 0; j < ny; ++j) { auto rstd = var_to_std(field2.vec_d[j], missval); - if (dbl_is_equal(rstd, missval)) rnmiss++; + if (dbl_is_equal(rstd, missval)) rnumMissVals++; field2.vec_d[j] = rstd; } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } void @@ -212,7 +212,7 @@ zonal_median(const Field &field1, Field &field2) void zonal_pctl(const Field &field1, Field &field2, double pn) { - size_t rnmiss = 0; + size_t rnumMissVals = 0; auto missval = field2.missval; auto ny = gridInqYsize(field1.grid); @@ -222,7 +222,7 @@ zonal_pctl(const Field &field1, Field &field2, double pn) Varray<double> v(nx); - if (field1.nmiss) + if (field1.numMissVals) { for (size_t j = 0; j < ny; ++j) { @@ -238,7 +238,7 @@ zonal_pctl(const Field &field1, Field &field2, double pn) else { field2.vec_d[j] = missval; - rnmiss++; + rnumMissVals++; } } } @@ -254,12 +254,12 @@ zonal_pctl(const Field &field1, Field &field2, double pn) else { field2.vec_d[j] = missval; - rnmiss++; + rnumMissVals++; } } } - field2.nmiss = rnmiss; + field2.numMissVals = rnumMissVals; } void diff --git a/src/fieldc.cc b/src/fieldc.cc index e6735a82113ef83e61eee400d5364a9bb86ae743..eece907208488ba479bc05f0a8e64877052d1499 100644 --- a/src/fieldc.cc +++ b/src/fieldc.cc @@ -11,13 +11,13 @@ template <typename T> static void -fieldc_mul(size_t len, size_t nmiss, Varray<T> &v, T missval, double rconst) +fieldc_mul(size_t len, size_t numMissVals, Varray<T> &v, T missval, double rconst) { auto is_EQ = dbl_is_equal; auto missval1 = missval; auto missval2 = missval; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < len; ++i) v[i] = MULM(v[i], rconst); } @@ -31,51 +31,51 @@ void fieldc_mul(Field &field, double rconst) { if (field.memType == MemType::Float) - fieldc_mul(field.size, field.nmiss, field.vec_f, (float) field.missval, rconst); + fieldc_mul(field.size, field.numMissVals, field.vec_f, (float) field.missval, rconst); else - fieldc_mul(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_mul(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } template <typename T> static size_t -fieldc_div(size_t len, size_t nmiss, Varray<T> &v, T missval, double rconst) +fieldc_div(size_t len, size_t numMissVals, Varray<T> &v, T missval, double rconst) { auto is_EQ = dbl_is_equal; auto missval1 = missval; auto missval2 = missval; - if (nmiss || is_equal(rconst, 0)) + if (numMissVals || is_equal(rconst, 0)) { for (size_t i = 0; i < len; ++i) v[i] = DIVM(v[i], rconst); - if (is_equal(rconst, 0)) nmiss = len; + if (is_equal(rconst, 0)) numMissVals = len; } else { for (size_t i = 0; i < len; ++i) v[i] /= rconst; } - return nmiss; + return numMissVals; } void fieldc_div(Field &field, double rconst) { if (field.memType == MemType::Float) - field.nmiss = fieldc_div(field.size, field.nmiss, field.vec_f, (float) field.missval, rconst); + field.numMissVals = fieldc_div(field.size, field.numMissVals, field.vec_f, (float) field.missval, rconst); else - field.nmiss = fieldc_div(field.size, field.nmiss, field.vec_d, field.missval, rconst); + field.numMissVals = fieldc_div(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } template <typename T> static void -fieldc_add(size_t len, size_t nmiss, Varray<T> &v, T missval, double rconst) +fieldc_add(size_t len, size_t numMissVals, Varray<T> &v, T missval, double rconst) { auto is_EQ = dbl_is_equal; auto missval1 = missval; auto missval2 = missval; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < len; ++i) v[i] = ADDM(v[i], rconst); } @@ -89,9 +89,9 @@ void fieldc_add(Field &field, double rconst) { if (field.memType == MemType::Float) - fieldc_add(field.size, field.nmiss, field.vec_f, (float) field.missval, rconst); + fieldc_add(field.size, field.numMissVals, field.vec_f, (float) field.missval, rconst); else - fieldc_add(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_add(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } void @@ -102,12 +102,12 @@ fieldc_sub(Field &field, const double rconst) template <typename T> static void -fieldc_min(size_t len, size_t nmiss, Varray<T> &v, T missval, T rconst) +fieldc_min(size_t len, size_t numMissVals, Varray<T> &v, T missval, T rconst) { auto is_EQ = dbl_is_equal; auto missval1 = missval; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < len; ++i) if (is_EQ(v[i], missval1) || v[i] > rconst) v[i] = rconst; @@ -123,19 +123,19 @@ void fieldc_min(Field &field, double rconst) { if (field.memType == MemType::Float) - fieldc_min(field.size, field.nmiss, field.vec_f, (float) field.missval, (float) rconst); + fieldc_min(field.size, field.numMissVals, field.vec_f, (float) field.missval, (float) rconst); else - fieldc_min(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_min(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } template <typename T> static void -fieldc_max(size_t len, size_t nmiss, Varray<T> &v, T missval, T rconst) +fieldc_max(size_t len, size_t numMissVals, Varray<T> &v, T missval, T rconst) { auto is_EQ = dbl_is_equal; auto missval1 = missval; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < len; ++i) if (is_EQ(v[i], missval1) || v[i] < rconst) v[i] = rconst; @@ -151,17 +151,17 @@ void fieldc_max(Field &field, double rconst) { if (field.memType == MemType::Float) - fieldc_max(field.size, field.nmiss, field.vec_f, (float) field.missval, (float) rconst); + fieldc_max(field.size, field.numMissVals, field.vec_f, (float) field.missval, (float) rconst); else - fieldc_max(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_max(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } template <typename T> static void -fieldc_mod(size_t len, size_t nmiss, Varray<T> &v, T missval, double divisor) +fieldc_mod(size_t len, size_t numMissVals, Varray<T> &v, T missval, double divisor) { - (void) nmiss; - auto is_EQ = dbl_is_equal; + (void) numMissVals; + auto is_EQ = dbl_is_equal; auto missval1 = missval; for (size_t i = 0; i < len; ++i) { v[i] = is_EQ(v[i], missval1) ? missval1 : std::fmod((double) v[i], divisor); } @@ -171,9 +171,9 @@ void fieldc_mod(Field &field, double divisor) { if (field.memType == MemType::Float) - fieldc_mod(field.size, field.nmiss, field.vec_f, (float) field.missval, divisor); + fieldc_mod(field.size, field.numMissVals, field.vec_f, (float) field.missval, divisor); else - fieldc_mod(field.size, field.nmiss, field.vec_d, field.missval, divisor); + fieldc_mod(field.size, field.numMissVals, field.vec_d, field.missval, divisor); } void diff --git a/src/fieldc_complex.cc b/src/fieldc_complex.cc index 9c97402259dccc6347d7b40f76cc70c915087c03..d27581e1bf589549ce6ed9c310ab4950b7459a87 100644 --- a/src/fieldc_complex.cc +++ b/src/fieldc_complex.cc @@ -13,9 +13,9 @@ template <typename T> static void -fieldc_mul_complex(size_t len, size_t nmiss, Varray<T> &v, double missval, const double rconst[2]) +fieldc_mul_complex(size_t len, size_t numMissVals, Varray<T> &v, double missval, const double rconst[2]) { - (void) nmiss; + (void) numMissVals; // z1 x z2 = (x1x2 - y1y2) + i(x1y2 + x2y1) auto is_EQ = dbl_is_equal; auto missval1 = missval; @@ -33,16 +33,16 @@ static void fieldc_mul_complex(Field &field, const double rconst[2]) { if (field.memType == MemType::Float) - fieldc_mul_complex(field.size, field.nmiss, field.vec_f, field.missval, rconst); + fieldc_mul_complex(field.size, field.numMissVals, field.vec_f, field.missval, rconst); else - fieldc_mul_complex(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_mul_complex(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } template <typename T> static void -fieldc_div_complex(size_t len, size_t nmiss, Varray<T> &v, double missval, const double rconst[2]) +fieldc_div_complex(size_t len, size_t numMissVals, Varray<T> &v, double missval, const double rconst[2]) { - (void) nmiss; + (void) numMissVals; // z1 / z2 = (x1x2 + y1y2) / (x2x2 + y2y2) + i (y1x2 - x1y2) / (x2x2 + y2y2) auto is_EQ = dbl_is_equal; auto missval1 = missval; @@ -61,16 +61,16 @@ static void fieldc_div_complex(Field &field, const double rconst[2]) { if (field.memType == MemType::Float) - fieldc_div_complex(field.size, field.nmiss, field.vec_f, field.missval, rconst); + fieldc_div_complex(field.size, field.numMissVals, field.vec_f, field.missval, rconst); else - fieldc_div_complex(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_div_complex(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } template <typename T> static void -fieldc_add_complex(size_t len, size_t nmiss, Varray<T> &v, double missval, const double rconst[2]) +fieldc_add_complex(size_t len, size_t numMissVals, Varray<T> &v, double missval, const double rconst[2]) { - (void) nmiss; + (void) numMissVals; auto is_EQ = dbl_is_equal; auto missval1 = missval; auto missval2 = missval; @@ -85,16 +85,16 @@ static void fieldc_add_complex(Field &field, const double rconst[2]) { if (field.memType == MemType::Float) - fieldc_add_complex(field.size, field.nmiss, field.vec_f, field.missval, rconst); + fieldc_add_complex(field.size, field.numMissVals, field.vec_f, field.missval, rconst); else - fieldc_add_complex(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_add_complex(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } template <typename T> static void -fieldc_sub_complex(size_t len, size_t nmiss, Varray<T> &v, double missval, const double rconst[2]) +fieldc_sub_complex(size_t len, size_t numMissVals, Varray<T> &v, double missval, const double rconst[2]) { - (void) nmiss; + (void) numMissVals; auto is_EQ = dbl_is_equal; auto missval1 = missval; auto missval2 = missval; @@ -109,9 +109,9 @@ static void fieldc_sub_complex(Field &field, const double rconst[2]) { if (field.memType == MemType::Float) - fieldc_sub_complex(field.size, field.nmiss, field.vec_f, field.missval, rconst); + fieldc_sub_complex(field.size, field.numMissVals, field.vec_f, field.missval, rconst); else - fieldc_sub_complex(field.size, field.nmiss, field.vec_d, field.missval, rconst); + fieldc_sub_complex(field.size, field.numMissVals, field.vec_d, field.missval, rconst); } void diff --git a/src/fileStream.cc b/src/fileStream.cc index 620ace68799b76ecc0f56a4aa2ff9a1754adaf82..03cde10d0d3f4d531facab949c8c8ff9e88c6534 100644 --- a/src/fileStream.cc +++ b/src/fileStream.cc @@ -51,10 +51,7 @@ FileStream::open_read() fileID = streamOpenReadQuery(path.c_str(), query); } - else - { - fileID = streamOpenRead(m_filename.c_str()); - } + else { fileID = streamOpenRead(m_filename.c_str()); } if (fileID < 0) cdi_open_error(fileID, "Open failed on >%s<", m_filename.c_str()); isopen = true; @@ -252,59 +249,59 @@ FileStream::defRecord(int varID, int levelID) } void -FileStream::read_record(float *const p_data, size_t *const nmiss) +FileStream::read_record(float *const p_data, size_t *const numMissVals) { if (FileStream::timersEnabled()) timer_start(timer_read); - stream_readrecord_float_locked(m_fileID, p_data, nmiss); + stream_readrecord_float_locked(m_fileID, p_data, numMissVals); if (FileStream::timersEnabled()) timer_stop(timer_read); } void -FileStream::read_record(double *const p_data, size_t *const nmiss) +FileStream::read_record(double *const p_data, size_t *const numMissVals) { if (FileStream::timersEnabled()) timer_start(timer_read); - stream_readrecord_double_locked(m_fileID, p_data, nmiss); + stream_readrecord_double_locked(m_fileID, p_data, numMissVals); if (FileStream::timersEnabled()) timer_stop(timer_read); } void -FileStream::read_record(Field *const p_field, size_t *const nmiss) +FileStream::read_record(Field *const p_field, size_t *const numMissVals) { - read_record(p_field->vec_d.data(), nmiss); + read_record(p_field->vec_d.data(), numMissVals); } void -FileStream::write_record(const float *const p_data, size_t p_nmiss) +FileStream::write_record(const float *const p_data, size_t p_numMissVals) { if (FileStream::timersEnabled()) timer_start(timer_write); auto varID = m_varID; if (varID < (int) m_datarangelist.size()) - if (m_datarangelist[varID].checkDatarange) m_datarangelist[varID].check_datarange(p_data, p_nmiss); + if (m_datarangelist[varID].checkDatarange) m_datarangelist[varID].check_datarange(p_data, p_numMissVals); - stream_write_record_float_locked(m_fileID, p_data, p_nmiss); + stream_write_record_float_locked(m_fileID, p_data, p_numMissVals); if (FileStream::timersEnabled()) timer_stop(timer_write); } void -FileStream::write_record(const double *const p_data, size_t p_nmiss) +FileStream::write_record(const double *const p_data, size_t p_numMissVals) { if (FileStream::timersEnabled()) timer_start(timer_write); auto varID = m_varID; if (varID < (int) m_datarangelist.size()) - if (m_datarangelist[varID].checkDatarange) m_datarangelist[varID].check_datarange(p_data, p_nmiss); + if (m_datarangelist[varID].checkDatarange) m_datarangelist[varID].check_datarange(p_data, p_numMissVals); - stream_write_record_double_locked(m_fileID, p_data, p_nmiss); + stream_write_record_double_locked(m_fileID, p_data, p_numMissVals); if (FileStream::timersEnabled()) timer_stop(timer_write); } void -FileStream::write_record(const Field *const p_field, size_t p_nmiss) +FileStream::write_record(const Field *const p_field, size_t p_numMissVals) { - write_record(p_field->vec_d.data(), p_nmiss); + write_record(p_field->vec_d.data(), p_numMissVals); } void @@ -446,10 +443,7 @@ FileStream::defDatarangeList(int p_vlistID) || datatype == CDI_DATATYPE_UINT16) m_datarangelist[varID].checkDatarange = true; } - else if (Options::CheckDatarange) - { - m_datarangelist[varID].checkDatarange = true; - } + else if (Options::CheckDatarange) { m_datarangelist[varID].checkDatarange = true; } } } diff --git a/src/fileStream.h b/src/fileStream.h index f12b9c8f1b640a72f9bbf17ef6829bfbe40d97bd..7c210295692a40c0de9194d3a1470f43e3b0e49b 100644 --- a/src/fileStream.h +++ b/src/fileStream.h @@ -22,13 +22,13 @@ public: void inq_record(int *varID, int *levelID) override; void defRecord(int varID, int levelID) override; - void read_record(float *const p_data, size_t *nmiss) override; - void read_record(double *const p_data, size_t *nmiss) override; - void read_record(Field *const p_field, size_t *nmiss) override; + void read_record(float *const p_data, size_t *numMissVals) override; + void read_record(double *const p_data, size_t *numMissVals) override; + void read_record(Field *const p_field, size_t *numMissVals) override; - void write_record(const float *const p_data, size_t nmiss) override; - void write_record(const double *const p_data, size_t nmiss) override; - void write_record(const Field *const p_field, size_t nmiss) override; + void write_record(const float *const p_data, size_t numMissVals) override; + void write_record(const double *const p_data, size_t numMissVals) override; + void write_record(const Field *const p_field, size_t numMissVals) override; void copyRecord(CdoStreamID p_fileStream) override; @@ -64,7 +64,7 @@ protected: private: FileStream() = delete; std::string m_filename; - void checkDatarange(int varID, double *array, size_t nmiss); + void checkDatarange(int varID, double *array, size_t numMissVals); }; #endif diff --git a/src/fill_1d.cc b/src/fill_1d.cc index 7b5d08ebf0a46b4cd0798938d9c53ef6110a2141..a1a711c517a2390cd50c47b99b9f33cf58bd174b 100644 --- a/src/fill_1d.cc +++ b/src/fill_1d.cc @@ -24,7 +24,8 @@ string_to_fillmethod(const std::string &methodStr) } static void -nearest_neighbour_with_lowest_delta(const Varray<double> &xValues, Varray<double> &yValues, int firstIndex, int lastIndex, int limit) +nearest_neighbour_with_lowest_delta(const Varray<double> &xValues, Varray<double> &yValues, int firstIndex, int lastIndex, + int limit) { auto startIndex = firstIndex + 1; auto endIndex = (limit > 0) ? std::min(lastIndex, startIndex + limit) : lastIndex; @@ -89,15 +90,9 @@ fill_1d_nearest(int numValues, const Varray<double> &timeValues, Varray<double> for (int k = startIndex; k < endIndex; ++k) dataValues[k] = dataValues[firstIndex]; break; } - else if (firstIndex == UndefIndex && lastIndex == UndefIndex) - { - break; - } - } - else - { - firstIndex = i; + else if (firstIndex == UndefIndex && lastIndex == UndefIndex) { break; } } + else { firstIndex = i; } } } @@ -148,15 +143,9 @@ fill_1d_linear(int numValues, const Varray<double> &timeValues, Varray<double> & firstIndex = lastIndex; lastIndex = UndefIndex; } - else if (lastIndex == UndefIndex) - { - break; - } - } - else - { - firstIndex = i; + else if (lastIndex == UndefIndex) { break; } } + else { firstIndex = i; } } } @@ -208,15 +197,9 @@ fill_1d_forward(int numValues, Varray<double> &dataValues, double missval, int l for (int k = startIndex; k < endIndex; ++k) dataValues[k] = dataValues[firstIndex]; break; } - else if (firstIndex == UndefIndex && lastIndex == UndefIndex) - { - break; - } - } - else - { - firstIndex = i; + else if (firstIndex == UndefIndex && lastIndex == UndefIndex) { break; } } + else { firstIndex = i; } } } @@ -263,14 +246,8 @@ fill_1d_backward(int numValues, Varray<double> &dataValues, double missval, int firstIndex = lastIndex; lastIndex = UndefIndex; } - else if (lastIndex == UndefIndex) - { - break; - } - } - else - { - firstIndex = i; + else if (lastIndex == UndefIndex) { break; } } + else { firstIndex = i; } } } diff --git a/src/fill_1d.h b/src/fill_1d.h index bd854be3edb14a95682eff4090e28320ceac2007..a6a3d3a8b4ee14c96d99db93212adcc62e266ecb 100644 --- a/src/fill_1d.h +++ b/src/fill_1d.h @@ -20,8 +20,10 @@ enum class FillMethod FillMethod string_to_fillmethod(const std::string &methodStr); -void fill_1d_nearest(int numValues, const Varray<double> &timeValues, Varray<double> &dataValues, double missval, int limit, int maxGaps); -void fill_1d_linear(int numValues, const Varray<double> &timeValues, Varray<double> &dataValues, double missval, int limit, int maxGaps); +void fill_1d_nearest(int numValues, const Varray<double> &timeValues, Varray<double> &dataValues, double missval, int limit, + int maxGaps); +void fill_1d_linear(int numValues, const Varray<double> &timeValues, Varray<double> &dataValues, double missval, int limit, + int maxGaps); void fill_1d_forward(int numValues, Varray<double> &dataValues, double missval, int limit, int maxGaps); void fill_1d_backward(int numValues, Varray<double> &dataValues, double missval, int limit, int maxGaps); diff --git a/src/grid_area.cc b/src/grid_area.cc index 6b8d02db42be54b1c2e210f302b776f29ee29be7..6e7ee2d1ac52899a5471c5e7c8fdbb592bdc1a32 100644 --- a/src/grid_area.cc +++ b/src/grid_area.cc @@ -502,19 +502,13 @@ gridGenArea(int gridID, double *area) bool lweights = false; status = gen_gridcellarea_reg2d(gridID, area, lweights); } - else if (is_healpix_grid(gridID)) - { - status = gen_gridcellarea_healpix(gridID, area); - } + else if (is_healpix_grid(gridID)) { status = gen_gridcellarea_healpix(gridID, area); } else if (gridProjIsSupported(gridID) || gridtype == GRID_GME || gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED || gridtype == GRID_GAUSSIAN_REDUCED) { status = gen_gridcellarea_unstruct(gridID, area); } - else - { - cdo_abort("Internal error! Unsupported gridtype: %s", gridNamePtr(gridtype)); - } + else { cdo_abort("Internal error! Unsupported gridtype: %s", gridNamePtr(gridtype)); } if (gridVerbose) cdo_print("Total area = %g steradians", array_sum(gridsize, area)); diff --git a/src/grid_from_name.cc b/src/grid_from_name.cc index a4b7ed15b9209a8ebb695d1c1a5a09064d158d02..72a435e414898e4cf2fcda5543747efaba16cd38 100644 --- a/src/grid_from_name.cc +++ b/src/grid_from_name.cc @@ -93,7 +93,8 @@ generate_grid_zonal(GridDesciption &grid, const std::string &gridname, double in } static void -generate_grid_lonlat(GridDesciption &grid, const std::string &gridname, double inc, double lon1, double lon2, double lat1, double lat2) +generate_grid_lonlat(GridDesciption &grid, const std::string &gridname, double inc, double lon1, double lon2, double lat1, + double lat2) { int gridtype = GRID_LONLAT; bool withBounds = true; diff --git a/src/grid_point_search.cc b/src/grid_point_search.cc index 0207e25144cd502cb8ce09175975103664dace4a..aff11900aa98252c398f6f7fa4edd9001bb1f67e 100644 --- a/src/grid_point_search.cc +++ b/src/grid_point_search.cc @@ -21,6 +21,7 @@ #include "nanoflann.hpp" extern "C" { +#include "lib/yac/grid_cell.h" #include "lib/yac/sphere_part.h" } @@ -695,7 +696,8 @@ grid_point_search_nearest(const GridPointSearch &gps, double lon, double lat, si } static size_t -gps_qnearest_kdtree(const GridPointSearch &gps, double lon, double lat, double searchRadius, size_t nnn, size_t *indices, double *dist) +gps_qnearest_kdtree(const GridPointSearch &gps, double lon, double lat, double searchRadius, size_t nnn, size_t *indices, + double *dist) { size_t numIndices = 0; diff --git a/src/grid_print.cc b/src/grid_print.cc index 5ecf44f7ada43ae4263cebefa70644f74bafb441..c9cfba6d1b55b42ca65beed0440b2ae82c0c1661 100644 --- a/src/grid_print.cc +++ b/src/grid_print.cc @@ -136,7 +136,6 @@ grid_print_attributes(FILE *fp, int gridID) static void grid_print_kernel(int gridID, int opt, FILE *fp) { - size_t xdim, ydim; auto nxvals = gridInqXvals(gridID, nullptr); auto nyvals = gridInqYvals(gridID, nullptr); auto nxbounds = gridInqXbounds(gridID, nullptr); @@ -200,28 +199,36 @@ grid_print_kernel(int gridID, int opt, FILE *fp) if (ysize > 0) fprintf(fp, "ysize = %zu\n", ysize); } + auto xdimname = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_DIMNAME); if (nxvals > 0 || xcvals) { - auto name = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_NAME); - auto dimname = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_DIMNAME); - auto longname = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_LONGNAME); - auto units = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_UNITS); - if (name.size()) fprintf(fp, "xname = %s\n", name.c_str()); - if (dimname.size() && dimname != name) fprintf(fp, "xdimname = %s\n", dimname.c_str()); - if (longname.size()) fprintf(fp, "xlongname = \"%s\"\n", longname.c_str()); - if (units.size()) fprintf(fp, "xunits = \"%s\"\n", units.c_str()); + auto xname = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_NAME); + auto xlongname = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_LONGNAME); + auto xunits = cdo::inq_key_string(gridID, CDI_XAXIS, CDI_KEY_UNITS); + if (xname.size()) fprintf(fp, "xname = %s\n", xname.c_str()); + if (xdimname.size() && xdimname != xname) fprintf(fp, "xdimname = %s\n", xdimname.c_str()); + if (xlongname.size()) fprintf(fp, "xlongname = \"%s\"\n", xlongname.c_str()); + if (xunits.size()) fprintf(fp, "xunits = \"%s\"\n", xunits.c_str()); + } + else if (xsize > 0) + { + if (xdimname.size()) fprintf(fp, "xdimname = %s\n", xdimname.c_str()); } + auto ydimname = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_DIMNAME); if (nyvals > 0 || ycvals) { - auto name = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_NAME); - auto dimname = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_DIMNAME); - auto longname = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_LONGNAME); - auto units = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_UNITS); - if (name.size()) fprintf(fp, "yname = %s\n", name.c_str()); - if (dimname.size() && dimname != name) fprintf(fp, "ydimname = %s\n", dimname.c_str()); - if (longname.size()) fprintf(fp, "ylongname = \"%s\"\n", longname.c_str()); - if (units.size()) fprintf(fp, "yunits = \"%s\"\n", units.c_str()); + auto yname = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_NAME); + auto ylongname = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_LONGNAME); + auto yunits = cdo::inq_key_string(gridID, CDI_YAXIS, CDI_KEY_UNITS); + if (yname.size()) fprintf(fp, "yname = %s\n", yname.c_str()); + if (ydimname.size() && ydimname != yname) fprintf(fp, "ydimname = %s\n", ydimname.c_str()); + if (ylongname.size()) fprintf(fp, "ylongname = \"%s\"\n", ylongname.c_str()); + if (yunits.size()) fprintf(fp, "yunits = \"%s\"\n", yunits.c_str()); + } + else if (ysize > 0) + { + if (ydimname.size()) fprintf(fp, "ydimname = %s\n", ydimname.c_str()); } if (type == GRID_UNSTRUCTURED || type == GRID_CURVILINEAR) @@ -244,6 +251,8 @@ grid_print_kernel(int gridID, int opt, FILE *fp) case GRID_TRAJECTORY: case GRID_CHARXY: { + size_t xdim, ydim; + if (type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED) fprintf(fp, "numLPE = %d\n", gridInqNP(gridID)); if (type == GRID_CURVILINEAR || type == GRID_UNSTRUCTURED) diff --git a/src/grid_read.cc b/src/grid_read.cc index b3d21fa72cac33e8e061b30f5c63d85279c757d8..862284100f6d4fa13be879ccfb32fd505811df30 100644 --- a/src/grid_read.cc +++ b/src/grid_read.cc @@ -9,7 +9,6 @@ #include "cdi_uuid.h" #include "cdo_output.h" -#include "readline.h" #include "param_conversion.h" #include "griddes.h" #include "parse_literals.h" diff --git a/src/grid_read_pingo.cc b/src/grid_read_pingo.cc index 0f9ac9e5b3ee7c434e15f7f09899b6f11049ee7c..0c2370db1ef62859cac748d9536bed98266eaec5 100644 --- a/src/grid_read_pingo.cc +++ b/src/grid_read_pingo.cc @@ -25,7 +25,7 @@ skip_nondigit_lines(FILE *gfp) while (1) { do c = fgetc(gfp); - while ((isspace(c) || c == ',') && c != EOF); + while ((std::isspace(c) || c == ',') && c != EOF); if (c == EOF || std::isdigit(c) || c == '.' || c == '+' || c == '-' || c == 'N') break; // N: for NaN diff --git a/src/griddes.cc b/src/griddes.cc index 82e31e10e4ce31b90795025f001ea5af3e6c1928..66f6f0b79da7f5ef4c4fd1f61a3a3553a5e0806d 100644 --- a/src/griddes.cc +++ b/src/griddes.cc @@ -350,16 +350,16 @@ gridFromMPAS(const char *filename) auto nrecs = streamInqTimestep(streamID, 0); for (int recID = 0; recID < nrecs; ++recID) { - size_t nmiss; + size_t numMissVals; int varID, levelID; streamInqRecord(streamID, &varID, &levelID); // clang-format off - if (varID == latCellID) streamReadRecord(streamID, latCell.data(), &nmiss); - else if (varID == lonCellID) streamReadRecord(streamID, lonCell.data(), &nmiss); - else if (varID == latVertexID) streamReadRecord(streamID, latVertex.data(), &nmiss); - else if (varID == lonVertexID) streamReadRecord(streamID, lonVertex.data(), &nmiss); - else if (varID == areaCellID) streamReadRecord(streamID, areaCell.data(), &nmiss); - else if (varID == verticesOnCellID) streamReadRecord(streamID, verticesOnCell.data(), &nmiss); + if (varID == latCellID) streamReadRecord(streamID, latCell.data(), &numMissVals); + else if (varID == lonCellID) streamReadRecord(streamID, lonCell.data(), &numMissVals); + else if (varID == latVertexID) streamReadRecord(streamID, latVertex.data(), &numMissVals); + else if (varID == lonVertexID) streamReadRecord(streamID, lonVertex.data(), &numMissVals); + else if (varID == areaCellID) streamReadRecord(streamID, areaCell.data(), &numMissVals); + else if (varID == verticesOnCellID) streamReadRecord(streamID, verticesOnCell.data(), &numMissVals); // clang-format on } streamClose(streamID); @@ -398,10 +398,7 @@ gridFromMPAS(const char *filename) xc[k] = xc[k - 1]; yc[k] = yc[k - 1]; } - else - { - withBounds = false; - } + else { withBounds = false; } } else { @@ -482,7 +479,7 @@ cdo_define_grid(const char *pgridfile) close(fileno); - if (buffer[0] == 'C' && buffer[1] == 'D' && buffer[2] == 'F') // CDF + if (buffer[0] == 'C' && buffer[1] == 'D' && buffer[2] == 'F') // CDF { Debug(cdoDebug, "Grid from NetCDF file"); gridID = grid_from_nc_file(filename); @@ -490,7 +487,7 @@ cdo_define_grid(const char *pgridfile) if (gridID == -1) { - if (buffer[1] == 'H' && buffer[2] == 'D' && buffer[3] == 'F') // HDF + if (buffer[1] == 'H' && buffer[2] == 'D' && buffer[3] == 'F') // HDF { Debug(cdoDebug, "Grid from HDF5 file"); gridID = grid_from_h5_file(filename); @@ -499,7 +496,7 @@ cdo_define_grid(const char *pgridfile) if (gridID == -1) { - if (buffer[1] == 'H' && buffer[2] == 'D' && buffer[3] == 'F') // HDF + if (buffer[1] == 'H' && buffer[2] == 'D' && buffer[3] == 'F') // HDF { Debug(cdoDebug, "Grid from NetCDF4 file"); gridID = grid_from_nc_file(filename); diff --git a/src/griddes_h5.cc b/src/griddes_h5.cc index 87f17dc3080bd7ad731f3332bd67ac2a69ff5f3c..658e4dc68e4ae618d41a6b831d58dede6e3b9f79 100644 --- a/src/griddes_h5.cc +++ b/src/griddes_h5.cc @@ -242,7 +242,7 @@ grid_from_h5_file(const char *gridfile) hid_t lat_id = -1; hid_t att_id; hid_t dataspace; - hsize_t dims_out[9]; // dataset dimensions + hsize_t dims_out[9]; // dataset dimensions [[maybe_unused]] herr_t status; int rank; GridDesciption grid; diff --git a/src/hetaeta.cc b/src/hetaeta.cc index 0a6704b12cb783b54e5668f02aabefe4f03066d2..90302290020457f7d3c9a95ac648524bc1796e8d 100644 --- a/src/hetaeta.cc +++ b/src/hetaeta.cc @@ -5,7 +5,7 @@ */ -//#define OUTPUT 1 +// #define OUTPUT 1 #ifdef _OPENMP #include <omp.h> diff --git a/src/hetaeta.h b/src/hetaeta.h index 7042b38d0c898cb2589de902b6c2453cccf5e919..8696be341e9fd92db5a8ee34aec92686eda4e637 100644 --- a/src/hetaeta.h +++ b/src/hetaeta.h @@ -1,6 +1,8 @@ #ifndef _HETAETA_H #define _HETAETA_H +#include "varray.h" + template <typename T> void hetaeta(bool ltq, int ngp, const int *imiss, int nlev1, const double *ah1, const double *bh1, const Varray<double> &fis1, const Varray<double> &ps1, const Varray<T> &t1, const Varray<T> &q1, int nlev2, const double *ah2, const double *bh2, diff --git a/src/institution.cc b/src/institution.cc index 8e1668b9f2f28167c6947019fe63d141cd27de65..8a74c8e16b2586f038d7ac4d1a85279706c5c3b6 100644 --- a/src/institution.cc +++ b/src/institution.cc @@ -5,67 +5,66 @@ */ +#include <fstream> + #include <cdi.h> #include "process_int.h" -#include "readline.h" #include "cdo_default_values.h" static int -readInstitution(const char *instfile) +read_institution(const std::string &filename) { - char line[1024]; int lnr = 0; int nvar = 0, maxvar = 4; - char name[1024], longname[1024]; int center = CDI_UNDEFID, subcenter = CDI_UNDEFID; + std::string name, longname; - auto instfp = std::fopen(instfile, "r"); - if (instfp == nullptr) return CDI_UNDEFID; + std::ifstream file(filename); + if (!file.is_open()) cdo_abort("Open failed on: %s\n", filename); - while (cdo::readline(instfp, line, 1024)) + std::string line; + while (std::getline(file, line)) { lnr++; if (line[0] == '#') continue; if (nvar == maxvar) break; nvar++; - char *pline = line; - while (isspace((int) *pline)) pline++; + while (std::isspace((int) line[0])) line.erase(0, 1); - if (nvar == 1) maxvar = std::isdigit((int) pline[0]) ? 4 : 2; + if (nvar == 1) maxvar = std::isdigit((int) line[0]) ? 4 : 2; - if (nvar == 1 && maxvar == 4) center = atoi(pline); + if (nvar == 1 && maxvar == 4) center = atoi(line.c_str()); if (nvar == 2 && maxvar == 4) { - if (!std::isdigit((int) pline[0])) cdo_abort("wrong format in line %d. Missing subcenter!", lnr); + if (!std::isdigit((int) line[0])) cdo_abort("wrong format in line %d. Missing subcenter!", lnr); - subcenter = atoi(pline); + subcenter = atoi(line.c_str()); } - if ((nvar == 3 && maxvar == 4) || (nvar == 1 && maxvar == 2)) std::strcpy(name, pline); + if ((nvar == 3 && maxvar == 4) || (nvar == 1 && maxvar == 2)) name = line; - if ((nvar == 4 && maxvar == 4) || (nvar == 2 && maxvar == 2)) std::strcpy(longname, pline); + if ((nvar == 4 && maxvar == 4) || (nvar == 2 && maxvar == 2)) longname = line; } - std::fclose(instfp); + file.close(); - auto instID = institutInq(center, subcenter, name, longname); - if (instID == CDI_UNDEFID) instID = institutDef(center, subcenter, name, longname); + auto instID = institutInq(center, subcenter, name.c_str(), longname.c_str()); + if (instID == CDI_UNDEFID) instID = institutDef(center, subcenter, name.c_str(), longname.c_str()); return instID; } void -define_institution(const char *instarg) +define_institution(const std::string &instString) { - const char *instname = instarg; - int instID = readInstitution(instname); + int instID = read_institution(instString); - if (instID == CDI_UNDEFID) instID = institutInq(0, 0, instname, nullptr); + if (instID == CDI_UNDEFID) instID = institutInq(0, 0, instString.c_str(), nullptr); - if (instID == CDI_UNDEFID) cdo_abort("institution <%s> not found", instname); + if (instID == CDI_UNDEFID) cdo_abort("institution <%s> not found", instString); CdoDefault::InstID = instID; } diff --git a/src/institution.h b/src/institution.h index 327d1b7c023e17148567dc2d398acb9116abf7ea..3c27a3163ff26d64d68c09f9e60032d9c699f9a6 100644 --- a/src/institution.h +++ b/src/institution.h @@ -1,6 +1,8 @@ #ifndef CDO_INSTITUTION #define CDO_INSTITUTION -void define_institution(const char *instarg); +#include <string> + +void define_institution(const std::string &instString); #endif diff --git a/src/interpol.cc b/src/interpol.cc index be819b67a7cb482f3ab01811b5c15a3c4b4ff3b9..3ed2a32d9f2eb91df6ee5408e9c094d7b611657e 100644 --- a/src/interpol.cc +++ b/src/interpol.cc @@ -178,7 +178,7 @@ rect_grid_search2(long &imin, long &imax, double xmin, double xmax, long nxm, co return lfound; } -static double +double intlinarr2p(long nxm, long nym, double **fieldm, const Varray<double> &xm, const Varray<double> &ym, double x, double y) { long ii, jj; @@ -811,5 +811,5 @@ interpolate(const Field &field1, Field &field2) } } - field2.nmiss = varray_num_mv(gridsize_o, arrayOut, missval); + field2.numMissVals = varray_num_mv(gridsize_o, arrayOut, missval); } diff --git a/src/lib/gradsdes/CMakeLists.txt b/src/lib/gradsdes/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3b7ec43fac5059c27e678ac58f0693089af6096 --- /dev/null +++ b/src/lib/gradsdes/CMakeLists.txt @@ -0,0 +1,8 @@ +list( APPEND gradsdes_src_files + gradsdes.c + gradsdes.h +) + +add_library(gradsdes + ${gradsdes_src_files} +) diff --git a/src/lib/gradsdes/gradsdes.c b/src/lib/gradsdes/gradsdes.c index 2f62a1f85edc9624514de4ef447dc294978a50b3..2b29cdfdcade2011f2c9726432f474772489c628 100644 --- a/src/lib/gradsdes/gradsdes.c +++ b/src/lib/gradsdes/gradsdes.c @@ -464,7 +464,7 @@ adtprs(char *ch, struct dt *def, struct dt *dtim) if (val > 23) { gaprnt(0, "Syntax Error: Invalid Date/Time value.\n"); - sprintf(pout, " Hour = %i -- greater than 23\n", val); + snprintf(pout, sizeof(pout), " Hour = %i -- greater than 23\n", val); gaprnt(0, pout); return (NULL); } @@ -478,7 +478,7 @@ adtprs(char *ch, struct dt *def, struct dt *dtim) if (val > 59) { gaprnt(0, "Syntax Error: Invalid Date/Time value.\n"); - sprintf(pout, " Minute = %i -- greater than 59\n", val); + snprintf(pout, sizeof(pout), " Minute = %i -- greater than 59\n", val); gaprnt(0, pout); return (NULL); } @@ -583,7 +583,7 @@ adtprs(char *ch, struct dt *def, struct dt *dtim) if (dtim->dy > i) { gaprnt(0, "Syntax Error: Invalid Date/Time value.\n"); - sprintf(pout, " Day = %i -- greater than %i \n", dtim->dy, i); + snprintf(pout, sizeof(pout), " Day = %i -- greater than %i \n", dtim->dy, i); gaprnt(0, pout); return (NULL); } @@ -634,7 +634,7 @@ rdtprs(char *ch, struct dt *dtim) else { gaprnt(0, "Syntax Error: Invalid Date/Time offset.\n"); - sprintf(pout, " Expecting yr/mo/dy/hr/mn, found %s\n", id); + snprintf(pout, sizeof(pout), " Expecting yr/mo/dy/hr/mn, found %s\n", id); gaprnt(0, pout); return (NULL); } @@ -1155,6 +1155,7 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs olen = 0; while (*(fn + olen)) olen++; olen += 5; + size_t outLen = olen; fnout = (char *) galloc(olen, "fnout"); if (fnout == NULL) return (NULL); @@ -1171,13 +1172,18 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs tused = 1; if (*(in + 2) == 'x' && *(in + 3) == '1') { - sprintf(out, "%i", dtimi->yr / 10); - while (*out) out++; + snprintf(out, outLen, "%i", dtimi->yr / 10); + while (*out) + { + outLen--; + out++; + } in += 4; } else if (*(in + 2) == 'x' && *(in + 3) == '3') { - sprintf(out, "%03i", dtimi->yr / 10); + snprintf(out, outLen, "%03i", dtimi->yr / 10); + outLen -= 3; out += 3; in += 4; } @@ -1185,25 +1191,32 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs { iv = dtimi->yr / 100; iv = dtimi->yr - iv * 100; - sprintf(out, "%02i", iv); + snprintf(out, outLen, "%02i", iv); + outLen -= 2; out += 2; in += 4; } else if (*(in + 2) == 'y' && *(in + 3) == '4') { - sprintf(out, "%04i", dtimi->yr); + snprintf(out, outLen, "%04i", dtimi->yr); + outLen -= 4; out += 4; in += 4; } else if (*(in + 2) == 'm' && *(in + 3) == '1') { - sprintf(out, "%i", dtimi->mo); - while (*out) out++; + snprintf(out, outLen, "%i", dtimi->mo); + while (*out) + { + outLen--; + out++; + } in += 4; } else if (*(in + 2) == 'm' && *(in + 3) == '2') { - sprintf(out, "%02i", dtimi->mo); + snprintf(out, outLen, "%02i", dtimi->mo); + outLen -= 2; out += 2; in += 4; } @@ -1213,6 +1226,7 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs *out = 'a'; else *out = 'b'; + outLen -= 1; out += 1; in += 4; } @@ -1222,6 +1236,7 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs *out = 'A'; else *out = 'B'; + outLen -= 1; out += 1; in += 4; } @@ -1230,42 +1245,55 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs *out = *(mons[dtimi->mo - 1]); *(out + 1) = *(mons[dtimi->mo - 1] + 1); *(out + 2) = *(mons[dtimi->mo - 1] + 2); + outLen -= 3; out += 3; in += 4; } else if (*(in + 2) == 'd' && *(in + 3) == '1') { - sprintf(out, "%i", dtimi->dy); - while (*out) out++; + snprintf(out, outLen, "%i", dtimi->dy); + while (*out) + { + outLen--; + out++; + } in += 4; } else if (*(in + 2) == 'd' && *(in + 3) == '2') { - sprintf(out, "%02i", dtimi->dy); + snprintf(out, outLen, "%02i", dtimi->dy); + outLen -= 2; out += 2; in += 4; } else if (*(in + 2) == 'h' && *(in + 3) == '1') { - sprintf(out, "%i", dtimi->hr); - while (*out) out++; + snprintf(out, outLen, "%i", dtimi->hr); + while (*out) + { + outLen--; + out++; + } in += 4; } else if (*(in + 2) == 'h' && *(in + 3) == '2') { - sprintf(out, "%02i", dtimi->hr); + snprintf(out, outLen, "%02i", dtimi->hr); + outLen -= 2; out += 2; in += 4; } else if (*(in + 2) == 'h' && *(in + 3) == '3') { - sprintf(out, "%03i", dtimi->hr); + snprintf(out, outLen, "%03i", dtimi->hr); + outLen -= 3; out += 3; in += 4; } else if (*(in + 2) == 'n' && *(in + 3) == '2') { - sprintf(out, "%02i", dtimi->mn); + snprintf(out, outLen, "%02i", dtimi->mn); + outLen -= 2; out += 2; in += 4; } @@ -1280,14 +1308,19 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs else if (*in == '%' && *(in + 1) == 'x' && *(in + 2) == '1') { /* x: decades */ tused = 1; - sprintf(out, "%i", dtim->yr / 10); - while (*out) out++; + snprintf(out, outLen, "%i", dtim->yr / 10); + while (*out) + { + outLen--; + out++; + } in += 3; } else if (*in == '%' && *(in + 1) == 'x' && *(in + 2) == '3') { tused = 1; - sprintf(out, "%03i", dtim->yr / 10); + snprintf(out, outLen, "%03i", dtim->yr / 10); + outLen -= 3; out += 3; in += 3; } @@ -1296,28 +1329,35 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs tused = 1; iv = dtim->yr / 100; iv = dtim->yr - iv * 100; - sprintf(out, "%02i", iv); + snprintf(out, outLen, "%02i", iv); + outLen -= 2; out += 2; in += 3; } else if (*in == '%' && *(in + 1) == 'y' && *(in + 2) == '4') { tused = 1; - sprintf(out, "%04i", dtim->yr); + snprintf(out, outLen, "%04i", dtim->yr); + outLen -= 4; out += 4; in += 3; } else if (*in == '%' && *(in + 1) == 'm' && *(in + 2) == '1') { tused = 1; - sprintf(out, "%i", dtim->mo); - while (*out) out++; + snprintf(out, outLen, "%i", dtim->mo); + while (*out) + { + outLen--; + out++; + } in += 3; } else if (*in == '%' && *(in + 1) == 'm' && *(in + 2) == '2') { tused = 1; - sprintf(out, "%02i", dtim->mo); + snprintf(out, outLen, "%02i", dtim->mo); + outLen -= 2; out += 2; in += 3; } @@ -1328,6 +1368,7 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs *out = 'a'; else *out = 'b'; + outLen -= 1; out += 1; in += 3; } @@ -1338,6 +1379,7 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs *out = 'A'; else *out = 'B'; + outLen -= 1; out += 1; in += 3; } @@ -1347,48 +1389,61 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs *out = *(mons[dtim->mo - 1]); *(out + 1) = *(mons[dtim->mo - 1] + 1); *(out + 2) = *(mons[dtim->mo - 1] + 2); + outLen -= 3; out += 3; in += 3; } else if (*in == '%' && *(in + 1) == 'd' && *(in + 2) == '1') { tused = 1; - sprintf(out, "%i", dtim->dy); - while (*out) out++; + snprintf(out, outLen, "%i", dtim->dy); + while (*out) + { + outLen--; + out++; + } in += 3; } else if (*in == '%' && *(in + 1) == 'd' && *(in + 2) == '2') { tused = 1; - sprintf(out, "%02i", dtim->dy); + snprintf(out, outLen, "%02i", dtim->dy); + outLen -= 2; out += 2; in += 3; } else if (*in == '%' && *(in + 1) == 'h' && *(in + 2) == '1') { tused = 1; - sprintf(out, "%i", dtim->hr); - while (*out) out++; + snprintf(out, outLen, "%i", dtim->hr); + while (*out) + { + outLen--; + out++; + } in += 3; } else if (*in == '%' && *(in + 1) == 'h' && *(in + 2) == '2') { tused = 1; - sprintf(out, "%02i", dtim->hr); + snprintf(out, outLen, "%02i", dtim->hr); + outLen -= 2; out += 2; in += 3; } else if (*in == '%' && *(in + 1) == 'h' && *(in + 2) == '3') { tused = 1; - sprintf(out, "%03i", dtim->hr); + snprintf(out, outLen, "%03i", dtim->hr); + outLen -= 3; out += 3; in += 3; } else if (*in == '%' && *(in + 1) == 'n' && *(in + 2) == '2') { tused = 1; - sprintf(out, "%02i", dtim->mn); + snprintf(out, outLen, "%02i", dtim->mn); + outLen -= 2; out += 2; in += 3; } @@ -1399,10 +1454,14 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs tdif = timdif(dtimi, dtim); tdif = (tdif + 30) / 60; if (tdif < 99) - sprintf(out, "%02i", tdif); + snprintf(out, outLen, "%02i", tdif); else - sprintf(out, "%i", tdif); - while (*out) out++; + snprintf(out, outLen, "%i", tdif); + while (*out) + { + outLen--; + out++; + } in += 3; } else if (*in == '%' && *(in + 1) == 'f' && *(in + 2) == '3') @@ -1411,10 +1470,14 @@ gafndt(char *fn, struct dt *dtim, struct dt *dtimi, gadouble *vals, struct gachs tdif = timdif(dtimi, dtim); tdif = (tdif + 30) / 60; if (tdif < 999) - sprintf(out, "%03i", tdif); + snprintf(out, outLen, "%03i", tdif); else - sprintf(out, "%i", tdif); - while (*out) out++; + snprintf(out, outLen, "%i", tdif); + while (*out) + { + outLen--; + out++; + } in += 3; } /* string substitution */ @@ -1850,8 +1913,8 @@ read_gradsdes(char *filename, dsets_t *pfi) if ((pos = intprs(ch, &(pfi->dnum[0]))) == NULL) goto err1; if (pfi->dnum[0] < 1) { - sprintf(pout, "Warning: Invalid XDEF syntax in %s -- Changing size of X axis from %d to 1 \n", pfi->dnam, - pfi->dnum[0]); + snprintf(pout, sizeof(pout), "Warning: Invalid XDEF syntax in %s -- Changing size of X axis from %d to 1 \n", + pfi->dnam, pfi->dnum[0]); gaprnt(1, pout); pfi->dnum[0] = 1; } @@ -1884,8 +1947,8 @@ read_gradsdes(char *filename, dsets_t *pfi) if ((pos = intprs(ch, &(pfi->dnum[1]))) == NULL) goto err1; if (pfi->dnum[1] < 1) { - sprintf(pout, "Warning: Invalid YDEF syntax in %s -- Changing size of Y axis from %d to 1 \n", pfi->dnam, - pfi->dnum[1]); + snprintf(pout, sizeof(pout), "Warning: Invalid YDEF syntax in %s -- Changing size of Y axis from %d to 1 \n", + pfi->dnam, pfi->dnum[1]); gaprnt(1, pout); pfi->dnum[1] = 1; } @@ -1911,8 +1974,8 @@ read_gradsdes(char *filename, dsets_t *pfi) if ((pos = intprs(ch, &(pfi->dnum[2]))) == NULL) goto err1; if (pfi->dnum[2] < 1) { - sprintf(pout, "Warning: Invalid ZDEF syntax in %s -- Changing size of Z axis from %d to 1 \n", pfi->dnam, - pfi->dnum[2]); + snprintf(pout, sizeof(pout), "Warning: Invalid ZDEF syntax in %s -- Changing size of Z axis from %d to 1 \n", + pfi->dnam, pfi->dnum[2]); gaprnt(1, pout); pfi->dnum[2] = 1; } @@ -1939,8 +2002,8 @@ read_gradsdes(char *filename, dsets_t *pfi) if ((pos = intprs(ch, &(pfi->dnum[3]))) == NULL) goto err1; if (pfi->dnum[3] < 1) { - sprintf(pout, "Warning: Invalid TDEF syntax in %s -- Changing size of T axis from %d to 1 \n", pfi->dnam, - pfi->dnum[3]); + snprintf(pout, sizeof(pout), "Warning: Invalid TDEF syntax in %s -- Changing size of T axis from %d to 1 \n", + pfi->dnam, pfi->dnum[3]); gaprnt(1, pout); pfi->dnum[3] = 1; } @@ -2006,7 +2069,7 @@ read_gradsdes(char *filename, dsets_t *pfi) if (fgets(rec, 512, descr) == NULL) { gaprnt(0, "Open Error: Unexpected EOF reading variables\n"); - sprintf(pout, "Was expecting %i records. Found %i.\n", pfi->vnum, i); + snprintf(pout, sizeof(pout), "Was expecting %i records. Found %i.\n", pfi->vnum, i); gaprnt(2, pout); goto retrn; } @@ -2045,7 +2108,7 @@ read_gradsdes(char *filename, dsets_t *pfi) if (cmpwrd("endvars", rec)) { gaprnt(0, "Open Error: Unexpected ENDVARS record\n"); - sprintf(pout, "Was expecting %i records. Found %i.\n", pfi->vnum, i); + snprintf(pout, sizeof(pout), "Was expecting %i records. Found %i.\n", pfi->vnum, i); gaprnt(2, pout); goto err9; } @@ -2201,7 +2264,7 @@ read_gradsdes(char *filename, dsets_t *pfi) } else { - sprintf(pout, "Open Error: Looking for \"endvars\", found \"%s\" instead.\n", rec); + snprintf(pout, sizeof(pout), "Open Error: Looking for \"endvars\", found \"%s\" instead.\n", rec); gaprnt(0, pout); goto err9; } @@ -2274,7 +2337,7 @@ read_gradsdes(char *filename, dsets_t *pfi) goto err8; } pfi->ens1 = ens; - sprintf(ens->name, "1"); + snprintf(ens->name, sizeof(ens->name), "1"); ens->length = pfi->dnum[3]; ens->gt = 1; gr2t(pfi->grvals[3], 1, &ens->tinit); @@ -2510,7 +2573,7 @@ read_gradsdes(char *filename, dsets_t *pfi) ch = gafndt(pfi->name, &tdefe, &tdefe, pfi->abvals[3], pfi->pchsub1, pfi->ens1, ens->gt, e, &flag); if (ch == NULL) { - sprintf(pout, "Open Error: couldn't determine data file name for e=%d t=%d\n", e, ens->gt); + snprintf(pout, sizeof(pout), "Open Error: couldn't determine data file name for e=%d t=%d\n", e, ens->gt); gaprnt(0, pout); goto err8; } @@ -2562,7 +2625,7 @@ read_gradsdes(char *filename, dsets_t *pfi) pos = gafndt(pfi->name, &tdef, &tdefe, pfi->abvals[3], pfi->pchsub1, pfi->ens1, t, e, &flag); if (pos == NULL) { - sprintf(pout, "Open Error: couldn't determine data file name for e=%d t=%d\n", e, t); + snprintf(pout, sizeof(pout), "Open Error: couldn't determine data file name for e=%d t=%d\n", e, t); gaprnt(0, pout); goto err8; } diff --git a/src/lib/healpix/CMakeLists.txt b/src/lib/healpix/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1bdadb5eec784b5747d5518633c1448b256c3e15 --- /dev/null +++ b/src/lib/healpix/CMakeLists.txt @@ -0,0 +1,32 @@ +list( APPEND healpix_src_files + an-bool.h + bl-nl.h + bl-nl.inc + bl-nl.ph + bl.c + bl.h + bl.inc + bl.ph + healpix-utils.c + healpix-utils.h + healpix.c + healpix.h + keywords.h + mathutil.c + mathutil.h + mathutil.inc + os-features.h + permutedsort.c + permutedsort.h + qsort_reentrant.c + starutil.c + starutil.h + starutil.inc + interpolation.c + interpolation.h + stdint_msc.h +) + +add_library(healpix + ${healpix_src_files} +) diff --git a/src/lib/yac/CMakeLists.txt b/src/lib/yac/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d373f3c7899feb33df08023c1208da3aee5e0ac --- /dev/null +++ b/src/lib/yac/CMakeLists.txt @@ -0,0 +1,35 @@ +list( APPEND yac_src_files + area.c + area.h + basic_grid.h + basic_grid_data.h + bnd_circle.c + check_overlap.c + clipping.c + clipping.h + ensure_array_size.c + ensure_array_size.h + field_data.h + geometry.h + grid.h + grid_cell.c + grid_cell.h + intersection.c + interval_tree.c + interval_tree.h + location.h + sphere_part.c + sphere_part.h + utils_core.c + utils_core.h + utils_common.h + yac_ld_interface.h + yac_types.h + yac_version.h +) + +add_library(yac + ${yac_src_files} +) + +target_compile_definitions(yac PUBLIC YAC_FOR_CDO) diff --git a/src/lib/yac/Makefile.am b/src/lib/yac/Makefile.am index 4eef78764dcc9733153b8ee2e4ed335fe239cdc8..d4c28558db79313dd05525e81c47884444608a25 100644 --- a/src/lib/yac/Makefile.am +++ b/src/lib/yac/Makefile.am @@ -4,24 +4,29 @@ noinst_LTLIBRARIES = libyac.la libyac_la_SOURCES = \ area.c \ area.h \ + basic_grid.h \ + basic_grid_data.h \ bnd_circle.c \ check_overlap.c \ clipping.c \ clipping.h \ ensure_array_size.c \ ensure_array_size.h \ + field_data.h \ geometry.h \ - grid.h \ grid_cell.c \ grid_cell.h \ intersection.c \ interval_tree.c \ interval_tree.h \ + location.h \ sphere_part.c \ sphere_part.h \ - utils.c \ - utils.h \ + utils_core.c \ + utils_core.h \ + utils_common.h \ yac_ld_interface.h \ + yac_types.h \ yac_version.h # CPPFLAGS += -DYAC_FOR_CDO diff --git a/src/lib/yac/area.c b/src/lib/yac/area.c index be414c6568b4d3f461b12905be80aae338cefbe8..367a574da15ddd9927717d65a4293660ab98f808 100644 --- a/src/lib/yac/area.c +++ b/src/lib/yac/area.c @@ -1,48 +1,6 @@ -/** - * @file area.c - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #include <stdlib.h> #include <stdio.h> @@ -50,10 +8,10 @@ #include <float.h> #include "area.h" -#include "grid.h" +#include "basic_grid.h" #include "clipping.h" #include "geometry.h" -#include "utils.h" +#include "utils_core.h" #include "ensure_array_size.h" static inline double scalar_product(double a[], double b[]); @@ -83,9 +41,9 @@ double yac_triangle_area ( struct grid_cell cell ) { /* First, compute cross products Uij = Vi x Vj. */ - crossproduct_ld(triangle[0], triangle[1], u01); - crossproduct_ld(triangle[1], triangle[2], u12); - crossproduct_ld(triangle[2], triangle[0], u20); + crossproduct_kahan(triangle[0], triangle[1], u01); + crossproduct_kahan(triangle[1], triangle[2], u12); + crossproduct_kahan(triangle[2], triangle[0], u20); /* Normalize Uij to unit vectors. */ @@ -237,7 +195,7 @@ static double tri_area(double u[3], double v[3], double w[3]) { static inline int compute_norm_vector(double a[], double b[], double norm[]) { - crossproduct_ld(a, b, norm); + crossproduct_kahan(a, b, norm); double scale = sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]); @@ -500,7 +458,7 @@ static double tri_area_info( double cross[3][3]; struct sin_cos_angle angles[3]; for (int i = 0, j = 2; i < 3; j = i++) { - crossproduct_ld(corners[j], corners[i], cross[i]); + crossproduct_kahan(corners[j], corners[i], cross[i]); angles[i] = sin_cos_angle_new(sqrt(cross[i][0]*cross[i][0] + cross[i][1]*cross[i][1] + @@ -510,8 +468,6 @@ static double tri_area_info( double area = tri_area_(angles[0], angles[1], angles[2]); - if (area < 1e-10) return 0.0; - // the barycenter of the triangle is given by the sum edge norm vector // scaled by half of the associated edge length for (int i = 0; i < 3; ++i) { diff --git a/src/lib/yac/area.h b/src/lib/yac/area.h index aa134f03cd8fd5f27849d08152c11b2ed7b5a728..385bccae9a0e22744fe1bb50b394ecb7ec06c298 100644 --- a/src/lib/yac/area.h +++ b/src/lib/yac/area.h @@ -1,50 +1,11 @@ -/** - * @file area.h - * - * @copyright Copyright (C) 2013 Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #ifndef AREA_H #define AREA_H -#include "grid.h" +#include "basic_grid.h" #include "clipping.h" /** \example test_area.c diff --git a/src/lib/yac/basic_grid.h b/src/lib/yac/basic_grid.h new file mode 100644 index 0000000000000000000000000000000000000000..e68b63d3b9e36dddcbbc9c5d21c707e6b6f81d45 --- /dev/null +++ b/src/lib/yac/basic_grid.h @@ -0,0 +1,92 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef BASIC_GRID_H +#define BASIC_GRID_H + +#include "basic_grid_data.h" +#include "location.h" +#include "field_data.h" + +/** \example test_grid.c + */ + +struct yac_interp_field { + enum yac_location location; + size_t coordinates_idx; + size_t masks_idx; +}; + +struct yac_basic_grid; + +struct yac_basic_grid * yac_basic_grid_new( + char const * name, struct yac_basic_grid_data grid_data); +struct yac_basic_grid * yac_basic_grid_empty_new(char const * name); +yac_const_coordinate_pointer yac_basic_grid_get_field_coordinates( + struct yac_basic_grid * grid, struct yac_interp_field field); +int const * yac_basic_grid_get_field_mask( + struct yac_basic_grid * grid, struct yac_interp_field field); +int const * yac_basic_grid_get_core_mask( + struct yac_basic_grid * grid, enum yac_location location); +char const * yac_basic_grid_get_name(struct yac_basic_grid * grid); +struct yac_basic_grid_data * yac_basic_grid_get_data( + struct yac_basic_grid * grid); +struct yac_field_data * yac_basic_grid_get_field_data( + struct yac_basic_grid * grid, enum yac_location location); +size_t yac_basic_grid_get_data_size( + struct yac_basic_grid * grid, enum yac_location location); +size_t yac_basic_grid_get_named_mask_idx( + struct yac_basic_grid * grid, enum yac_location location, + char const * mask_name); +size_t yac_basic_grid_add_coordinates( + struct yac_basic_grid * grid, enum yac_location location, + yac_coordinate_pointer coordinates, size_t count); +size_t yac_basic_grid_add_coordinates_nocpy( + struct yac_basic_grid * grid, enum yac_location location, + yac_coordinate_pointer coordinates); +size_t yac_basic_grid_add_mask( + struct yac_basic_grid * grid, enum yac_location location, + int const * mask, size_t count, char const * mask_name); +size_t yac_basic_grid_add_mask_nocpy( + struct yac_basic_grid * grid, enum yac_location location, + int const * mask, char const * mask_name); +void yac_basic_grid_delete(struct yac_basic_grid * grid); + +struct yac_basic_grid * yac_basic_grid_reg_2d_new( + char const * name, size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid * yac_basic_grid_reg_2d_deg_new( + char const * name, size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid * yac_basic_grid_curve_2d_new( + char const * name, size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid * yac_basic_grid_curve_2d_deg_new( + char const * name, size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid * yac_basic_grid_unstruct_new( + char const * name, size_t nbr_vertices, size_t nbr_cells, + int *num_vertices_per_cell, double *x_vertices, double *y_vertices, + int *cell_to_vertex); + +struct yac_basic_grid * yac_basic_grid_unstruct_deg_new( + char const * name, size_t nbr_vertices, size_t nbr_cells, + int *num_vertices_per_cell, double *x_vertices, double *y_vertices, + int *cell_to_vertex); + +struct yac_basic_grid * yac_basic_grid_unstruct_ll_new( + char const * name, size_t nbr_vertices, size_t nbr_cells, + int *num_vertices_per_cell, double *x_vertices, double *y_vertices, + int *cell_to_vertex); + +struct yac_basic_grid * yac_basic_grid_unstruct_ll_deg_new( + char const * name, size_t nbr_vertices, size_t nbr_cells, + int *num_vertices_per_cell, double *x_vertices, double *y_vertices, + int *cell_to_vertex); + +#endif // BASIC_GRID_H diff --git a/src/lib/yac/basic_grid_data.h b/src/lib/yac/basic_grid_data.h new file mode 100644 index 0000000000000000000000000000000000000000..992c2d24982993241a7adaf8d9e07ce5338e5bef --- /dev/null +++ b/src/lib/yac/basic_grid_data.h @@ -0,0 +1,70 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef BASIC_GRID_DATA_H +#define BASIC_GRID_DATA_H + +#include "yac_types.h" + +struct yac_basic_grid_data { + yac_coordinate_pointer vertex_coordinates; + yac_int * cell_ids; + yac_int * vertex_ids; + yac_int * edge_ids; + size_t num_cells; // number of local cells (owned by local process) + size_t num_vertices; // number of local vertices (owned by local process) + size_t num_edges; // number of local edges (owned by local process) + int * core_cell_mask; + int * core_vertex_mask; + int * core_edge_mask; + int * num_vertices_per_cell; + int * num_cells_per_vertex; + size_t * cell_to_vertex; + size_t * cell_to_vertex_offsets; + size_t * cell_to_edge; + size_t * cell_to_edge_offsets; + size_t * vertex_to_cell; + size_t * vertex_to_cell_offsets; + yac_size_t_2_pointer edge_to_vertex; + enum yac_edge_type * edge_type; + size_t num_total_cells; // number of locally stored cells + size_t num_total_vertices; // number of locally stored vertices + size_t num_total_edges; // number of locally stored edges +}; + +struct yac_basic_grid_data yac_generate_basic_grid_data_reg_2d( + size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid_data yac_generate_basic_grid_data_reg_2d_deg( + size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid_data yac_generate_basic_grid_data_curve_2d( + size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid_data yac_generate_basic_grid_data_curve_2d_deg( + size_t nbr_vertices[2], int cyclic[2], + double *lon_vertices, double *lat_vertices); + +struct yac_basic_grid_data yac_generate_basic_grid_data_unstruct( + size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, + double *x_vertices, double *y_vertices, int *cell_to_vertex); + +struct yac_basic_grid_data yac_generate_basic_grid_data_unstruct_deg( + size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, + double *x_vertices, double *y_vertices, int *cell_to_vertex); + +struct yac_basic_grid_data yac_generate_basic_grid_data_unstruct_ll( + size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, + double *x_vertices, double *y_vertices, int *cell_to_vertex); + +struct yac_basic_grid_data yac_generate_basic_grid_data_unstruct_ll_deg( + size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, + double *x_vertices, double *y_vertices, int *cell_to_vertex); + +void yac_basic_grid_data_free(struct yac_basic_grid_data grid); + +#endif // BASIC_GRID_DATA_H diff --git a/src/lib/yac/bnd_circle.c b/src/lib/yac/bnd_circle.c index cb21b62a6c11bb74ec21d98cfef5665c9dee831a..d464d5330d76308616772634e39d76d970a2eed8 100644 --- a/src/lib/yac/bnd_circle.c +++ b/src/lib/yac/bnd_circle.c @@ -1,48 +1,6 @@ -/** - * @file bnd_circle.c - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #ifdef HAVE_CONFIG_H // Get the definition of the 'restrict' keyword. @@ -55,8 +13,8 @@ #include <float.h> #include "geometry.h" -#include "utils.h" -#include "grid.h" +#include "utils_core.h" +#include "basic_grid.h" #include "ensure_array_size.h" /** \file bnd_circle.c @@ -92,7 +50,7 @@ void yac_get_cell_circumscribe_circle_unstruct_triangle( ac[3] = {b[0]-c[0], b[1]-c[1], b[2]-c[2]}; // it is assumed that the angles of a triangle do not get too small... - // crossproduct_ld(ab, ac, bnd_circle->base_vector); + // crossproduct_kahan(ab, ac, bnd_circle->base_vector); crossproduct_d(ab, ac, bnd_circle->base_vector); normalise_vector(bnd_circle->base_vector); @@ -123,7 +81,7 @@ static inline double get_sin_vector_angle( double a[3], double b[3]) { double cross_ab[3]; - crossproduct_ld(a, b, cross_ab); + crossproduct_kahan(a, b, cross_ab); return sqrt(cross_ab[0]*cross_ab[0] + cross_ab[1]*cross_ab[1] + diff --git a/src/lib/yac/cdo_remap.cc b/src/lib/yac/cdo_remap.cc index 1902a5c8abc146c8edb5141b0660a27772b5ffe6..323e206bc7e1612d7eea94e10fe336d62bcd80af 100644 --- a/src/lib/yac/cdo_remap.cc +++ b/src/lib/yac/cdo_remap.cc @@ -9,13 +9,13 @@ static void compute_testfield(Varray<double> &array, const Varray<double> &cellCentersLon, const Varray<double> &cellCentersLat) { double xyz[3]; - const auto numCells = array.size(); + auto numCells = array.size(); for (size_t i = 0; i < numCells; ++i) { LL_to_XYZ(cellCentersLon[i], cellCentersLat[i], xyz); - const auto x = xyz[0]; - const auto y = xyz[1]; - const auto z = xyz[2]; + auto x = xyz[0]; + auto y = xyz[1]; + auto z = xyz[2]; array[i] = 1.0 + std::pow(x, 8.0) + std::exp(2.0 * y * y * y) + std::exp(2.0 * x * x) + 10.0 * x * y * z; } } @@ -23,7 +23,7 @@ compute_testfield(Varray<double> &array, const Varray<double> &cellCentersLon, c static void output_ext(const Varray<double> &array) { - const auto numCells = array.size(); + auto numCells = array.size(); fprintf(stdout, "%8d %4d %8g %8zu\n", 010101, 1, 0.0, numCells); int nout = 0; @@ -48,7 +48,7 @@ void grid_init_regular(GridInfo &grid, double increment) int main(void) { - const double missval = -9.e33; + double missval = -9.e33; RemapSearch remapSearch; auto &srcGrid = remapSearch.srcGrid; @@ -67,7 +67,7 @@ int main(void) remap_conserv(NormOpt::FRACAREA, remapSearch, srcArray, tgtArray, missval); //output_ext(srcArray); - //output_ext(tgtArray); + output_ext(tgtArray); gridcell_search_delete(remapSearch.gcs); diff --git a/src/lib/yac/cdo_remap_conserv.cc b/src/lib/yac/cdo_remap_conserv.cc index 36d32011f8aa8598b4197115b7435c1a023ebd2e..7285a1825b8275715db771c018bcaa19fb507877 100644 --- a/src/lib/yac/cdo_remap_conserv.cc +++ b/src/lib/yac/cdo_remap_conserv.cc @@ -1,10 +1,9 @@ -#include <algorithm> // std::sort -#include <numeric> // std::accumulate +#include <algorithm> // std::sort +#include <numeric> // std::accumulate #include "cdo_remap.h" - -const auto is_not_equal = [](auto a, auto b) noexcept { return (a < b || b < a); }; +const auto is_not_equal = [](auto a, auto b) noexcept { return (a < b || b < a); }; const auto is_equal = [](auto a, auto b) noexcept { return !(a < b || b < a); }; extern "C" @@ -88,17 +87,14 @@ cdo_compute_overlap_areas(size_t numSearchCells, CellSearch &search, const GridC } static double -get_edge_direction(double * ref_corner, double * corner_a, double * corner_b) +get_edge_direction(const double *ref_corner, double *corner_a, double *corner_b) { double edge_norm[3]; - crossproduct_ld(corner_a, corner_b, edge_norm); + crossproduct_kahan(corner_a, corner_b, edge_norm); normalise_vector(edge_norm); // sine of the angle between the edge and the reference corner - double angle = - edge_norm[0] * ref_corner[0] + - edge_norm[1] * ref_corner[1] + - edge_norm[2] * ref_corner[2]; + double angle = edge_norm[0] * ref_corner[0] + edge_norm[1] * ref_corner[1] + edge_norm[2] * ref_corner[2]; // if the reference corner is directly on the edge // (for small angles sin(x)==x) @@ -110,7 +106,7 @@ get_edge_direction(double * ref_corner, double * corner_a, double * corner_b) static void cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, const GridCell &gridCell) { - const auto targetCell = gridCell.yacGridCell; + auto targetCell = gridCell.yacGridCell; auto &overlapAreas = search.partialAreas; auto &overlapCells = search.overlapCells; auto &sourceCells = search.gridCells; @@ -121,9 +117,7 @@ cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, con // the triangulation algorithm only works for cells that only have great circle edges enum yac_edge_type edgeTypes[3] = { GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE }; double coordinates_xyz[3][3] = { { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 } }; - coordinates_xyz[0][0] = baseCorner[0]; - coordinates_xyz[0][1] = baseCorner[1]; - coordinates_xyz[0][2] = baseCorner[2]; + for (int k = 0; k < 3; ++k) coordinates_xyz[0][k] = baseCorner[k]; // data structure to hold the triangles of the target cell struct grid_cell partialCell; @@ -142,20 +136,16 @@ cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, con // first corner, therefore we can skip them) for (size_t cornerIdx = 1; cornerIdx < targetCell.num_corners - 1; ++cornerIdx) { - const auto cornerA = targetCell.coordinates_xyz[cornerIdx]; - const auto cornerB = targetCell.coordinates_xyz[(cornerIdx + 1)]; + auto cornerA = targetCell.coordinates_xyz[cornerIdx]; + auto cornerB = targetCell.coordinates_xyz[(cornerIdx + 1)]; // if the current edge has a length of zero if (points_are_identically(cornerA, cornerB)) continue; - const auto edgeDirection = get_edge_direction(baseCorner, cornerA, cornerB); + auto edgeDirection = get_edge_direction(baseCorner, cornerA, cornerB); - partialCell.coordinates_xyz[1][0] = cornerA[0]; - partialCell.coordinates_xyz[1][1] = cornerA[1]; - partialCell.coordinates_xyz[1][2] = cornerA[2]; - partialCell.coordinates_xyz[2][0] = cornerB[0]; - partialCell.coordinates_xyz[2][1] = cornerB[1]; - partialCell.coordinates_xyz[2][2] = cornerB[2]; + for (int k = 0; k < 3; ++k) partialCell.coordinates_xyz[1][k] = cornerA[k]; + for (int k = 0; k < 3; ++k) partialCell.coordinates_xyz[2][k] = cornerB[k]; // clip the current target cell triangle with all source cells yac_cell_clipping(numSearchCells, sourceCells.data(), partialCell, overlapCells.data()); @@ -173,7 +163,7 @@ cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, con { if (overlapAreas[i] < 0.0) overlapAreas[i] = -overlapAreas[i]; } - + #ifdef VERBOSE for (size_t i = 0; i < numSearchCells; i++) printf("overlap area %zu: %lf\n", i, overlapAreas[i]); #endif @@ -183,7 +173,7 @@ static void set_cell_coordinates_yac(const size_t cellIndex, const size_t numCorners, const GridInfo &gridInfo, const struct grid_cell &yacGridCell, double *x, double *y) { - const auto storeXY = (x && y); + auto storeXY = (x && y); auto xyz = yacGridCell.coordinates_xyz; const auto cellCornersLon = &gridInfo.cellCornersLon[cellIndex * numCorners]; @@ -207,24 +197,23 @@ set_cell_coordinates(const size_t cellIndex, const size_t numCorners, const Grid } static void -set_coordinates_yac(const size_t numCells, const Varray<size_t> &cellIndices, - const size_t numCorners, const GridInfo &gridInfo, const Varray<grid_cell> &yacGridCell) +set_coordinates_yac(const size_t numCells, const Varray<size_t> &cellIndices, const size_t numCorners, const GridInfo &gridInfo, + const Varray<grid_cell> &yacGridCell) { for (size_t i = 0; i < numCells; ++i) set_cell_coordinates_yac(cellIndices[i], numCorners, gridInfo, yacGridCell[i], nullptr, nullptr); } static void -set_coordinates_yac(const double (*xyzCoords)[3], const size_t numCells, const Varray<size_t> &cellIndices, - const size_t numCorners, const Varray<grid_cell> &yacGridCell) +set_coordinates_yac(const double (*xyzCoords)[3], const size_t numCells, const Varray<size_t> &cellIndices, const size_t numCorners, + const Varray<grid_cell> &yacGridCell) { for (size_t i = 0; i < numCells; ++i) { - const auto offset = cellIndices[i] * numCorners; + auto offset = cellIndices[i] * numCorners; auto xyz = yacGridCell[i].coordinates_xyz; for (size_t k = 0; k < numCorners; ++k) - for (size_t l = 0; l < 3; ++l) - xyz[k][l] = xyzCoords[offset + k][l]; + for (size_t l = 0; l < 3; ++l) xyz[k][l] = xyzCoords[offset + k][l]; } } @@ -270,7 +259,7 @@ remove_invalid_weights(size_t gridSize, size_t numWeights, Varray<double> &weigh size_t n = 0; for (size_t i = 0; i < numWeights; ++i) { - const auto cellIndex = (weights[i] > 0.0) ? searchIndices[i] : gridSize; + auto cellIndex = (weights[i] > 0.0) ? searchIndices[i] : gridSize; if (cellIndex != gridSize) { weights[n] = weights[i]; @@ -283,13 +272,12 @@ remove_invalid_weights(size_t gridSize, size_t numWeights, Varray<double> &weigh } static size_t -remove_unmask_weights(const Varray<short> &gridMask, size_t numWeights, Varray<double> &weights, - Varray<size_t> &searchIndices) +remove_unmask_weights(const Varray<short> &gridMask, size_t numWeights, Varray<double> &weights, Varray<size_t> &searchIndices) { size_t n = 0; for (size_t i = 0; i < numWeights; ++i) { - const auto cellIndex = searchIndices[i]; + auto cellIndex = searchIndices[i]; /* Store the appropriate addresses and weights. Also add contributions to cell areas. @@ -311,17 +299,15 @@ normalize_weights(NormOpt normOpt, double cellArea, double cellFrac, size_t numW { if (normOpt == NormOpt::DESTAREA) { - const auto normFactor = is_not_equal(cellArea, 0.0) ? 1.0 / cellArea : 0.0; + auto normFactor = is_not_equal(cellArea, 0.0) ? 1.0 / cellArea : 0.0; for (size_t i = 0; i < numWeights; ++i) weights[i] *= normFactor; } else if (normOpt == NormOpt::FRACAREA) { - const auto normFactor = is_not_equal(cellFrac, 0.0) ? 1.0 / cellFrac : 0.0; + auto normFactor = is_not_equal(cellFrac, 0.0) ? 1.0 / cellFrac : 0.0; for (size_t i = 0; i < numWeights; ++i) weights[i] *= normFactor; } - else if (normOpt == NormOpt::NONE) - { - } + else if (normOpt == NormOpt::NONE) {} } static void @@ -379,7 +365,7 @@ get_lonlat_circle_index(size_t numCells, size_t numCorners, const Varray<double> for (size_t i = 0; i < numCells; i += iadd) { - const auto i4 = i * 4; + auto i4 = i * 4; num_i++; // clang-format off if (is_equal(clon[i4 + 1], clon[i4 + 2]) && is_equal(clon[i4 + 3], clon[i4 + 0]) && @@ -420,7 +406,8 @@ conserv_remap(const Varray<double> &srcArray, size_t numWeights, const Varray<do } void -remap_conserv(NormOpt normOpt, const RemapSearch &remapSearch, const Varray<double> &srcArray, Varray<double> &tgtArray, double missval) +remap_conserv(NormOpt normOpt, const RemapSearch &remapSearch, const Varray<double> &srcArray, Varray<double> &tgtArray, + double missval) { auto &srcGrid = remapSearch.srcGrid; auto &tgtGrid = remapSearch.tgtGrid; @@ -444,13 +431,13 @@ remap_conserv(NormOpt normOpt, const RemapSearch &remapSearch, const Varray<doub if (srcNumCorners == 4) { - const auto lonlatCircleIndex = get_lonlat_circle_index(srcGrid); + auto lonlatCircleIndex = get_lonlat_circle_index(srcGrid); if (lonlatCircleIndex >= 0) srcEdgeType = &lonlatCircleType[lonlatCircleIndex]; } if (tgtNumCorners == 4) { - const auto lonlatCircleIndex = get_lonlat_circle_index(tgtGrid); + auto lonlatCircleIndex = get_lonlat_circle_index(tgtGrid); if (lonlatCircleIndex >= 0) { tgtCellType = LON_LAT_CELL; @@ -474,7 +461,7 @@ remap_conserv(NormOpt normOpt, const RemapSearch &remapSearch, const Varray<doub { tgtArray[tgtCellIndex] = missval; - //if (!tgtGrid.mask[tgtCellIndex]) continue; + // if (!tgtGrid.mask[tgtCellIndex]) continue; set_cell_coordinates(tgtCellIndex, tgtNumCorners, tgtGrid, tgtGridCell); @@ -501,14 +488,14 @@ remap_conserv(NormOpt normOpt, const RemapSearch &remapSearch, const Varray<doub auto numWeights = remove_invalid_areas(numSearchCells, partialWeights, searchIndices); - const auto tgtCellArea = gridcell_area(tgtGridCell.yacGridCell); + auto tgtCellArea = gridcell_area(tgtGridCell.yacGridCell); if (normOpt == NormOpt::FRACAREA) correct_weights(tgtCellArea, numWeights, partialWeights); numWeights = remove_invalid_weights(srcNumCells, numWeights, partialWeights, searchIndices); numWeights = remove_unmask_weights(srcGridMask, numWeights, partialWeights, searchIndices); - const auto tgtCellFrac = std::accumulate(partialWeights.begin(), partialWeights.begin() + numWeights, 0.0); + auto tgtCellFrac = std::accumulate(partialWeights.begin(), partialWeights.begin() + numWeights, 0.0); if (numWeights) { diff --git a/src/lib/yac/cdo_remap_conserv2.cc b/src/lib/yac/cdo_remap_conserv2.cc new file mode 100644 index 0000000000000000000000000000000000000000..40430323fdd71adeac433b203e157e77c27a4ff6 --- /dev/null +++ b/src/lib/yac/cdo_remap_conserv2.cc @@ -0,0 +1,728 @@ +#include <algorithm> // std::sort +#include <numeric> // std::accumulate + +#include "cdo_remap.h" + +const auto is_not_equal = [](auto a, auto b) noexcept { return (a < b || b < a); }; +const auto is_equal = [](auto a, auto b) noexcept { return !(a < b || b < a); }; + +extern "C" +{ +#include "clipping.h" +#include "area.h" +#include "geometry.h" +#include "yac_interp_method_conserv.h" +} + +struct CellSearch +{ + enum yac_edge_type *edgeType = nullptr; + size_t numCellCorners = 0; + size_t maxCells = 0; + Varray<double> partialAreas; + Varray<struct grid_cell> gridCells; + Varray<struct grid_cell> overlapCells; +}; + +static void +cellsearch_realloc(size_t numCells, CellSearch &search) +{ + if (numCells > search.maxCells) + { + search.partialAreas.resize(numCells); + search.overlapCells.resize(numCells); + search.gridCells.resize(numCells); + + for (size_t i = search.maxCells; i < numCells; ++i) + { + search.overlapCells[i].array_size = 0; + search.overlapCells[i].num_corners = 0; + search.overlapCells[i].edge_type = nullptr; + search.overlapCells[i].coordinates_xyz = nullptr; + + search.gridCells[i].array_size = search.numCellCorners; + search.gridCells[i].num_corners = search.numCellCorners; + search.gridCells[i].edge_type = search.edgeType; + search.gridCells[i].coordinates_xyz = new double[search.numCellCorners][3]; + } + + search.maxCells = numCells; + } +} + +static void +cellsearch_free(CellSearch &search) +{ + for (size_t i = 0; i < search.maxCells; i++) + { + if (search.overlapCells[i].array_size > 0) + { + if (search.overlapCells[i].coordinates_xyz) free(search.overlapCells[i].coordinates_xyz); + if (search.overlapCells[i].edge_type) free(search.overlapCells[i].edge_type); + } + + delete[] search.gridCells[i].coordinates_xyz; + } +} + +static enum yac_cell_type +get_cell_type(struct grid_cell target_cell) +{ + /* + YAC_ASSERT( + target_cell.num_corners > 0, "ERROR(get_cell_type): CELL without edge") + */ + enum yac_cell_type cell_type = MIXED_CELL; + + // if the cell is a typical lon-lat cell + if ((target_cell.num_corners == 4) + && ((target_cell.edge_type[0] == LAT_CIRCLE_EDGE && target_cell.edge_type[1] == LON_CIRCLE_EDGE + && target_cell.edge_type[2] == LAT_CIRCLE_EDGE && target_cell.edge_type[3] == LON_CIRCLE_EDGE) + || (target_cell.edge_type[0] == LON_CIRCLE_EDGE && target_cell.edge_type[1] == LAT_CIRCLE_EDGE + && target_cell.edge_type[2] == LON_CIRCLE_EDGE && target_cell.edge_type[3] == LAT_CIRCLE_EDGE))) + { + + cell_type = LON_LAT_CELL; + } + else + { + + size_t count_lat_edges = 0, count_great_circle_edges = 0; + + // count the number of edges for each type + // (lon edges are counted as gc ones) + for (size_t i = 0; i < target_cell.num_corners; ++i) + if (target_cell.edge_type[i] == LON_CIRCLE_EDGE || target_cell.edge_type[i] == GREAT_CIRCLE_EDGE) + count_great_circle_edges++; + else + count_lat_edges++; + + // if the cell is a lon lat cell with one lat edge having a length of zero + // due to being at a pole + if ((count_lat_edges == 1) && (count_great_circle_edges == 2)) + { + + size_t i; + for (i = 0; i < 3; ++i) + if (target_cell.edge_type[i] == LAT_CIRCLE_EDGE) break; + size_t pol_index = (3 + i - 1) % 3; + if (fabs(fabs(target_cell.coordinates_xyz[pol_index][2]) - 1.0) < yac_angle_low_tol) cell_type = LON_LAT_CELL; + + // if the cell only consists of great circle edges + } + else if (count_lat_edges == 0) + cell_type = GREAT_CIRCLE_CELL; + + // if the cell only consists of lat circle edges + else if (count_great_circle_edges == 0) + cell_type = LAT_CELL; + } + /* + YAC_ASSERT( + cell_type != MIXED_CELL, + "invalid cell type (cell contains edges consisting " + "of great circles and circles of latitude)") + */ + return cell_type; +} + +static inline double +gridcell_area(const grid_cell &cell) +{ + return yac_huiliers_area(cell); +} + +static void +cdo_compute_overlap_areas(size_t numSearchCells, CellSearch &search, const GridCell &gridCell) +{ + auto &overlapCells = search.overlapCells; + + // Do the clipping and get the cell for the overlapping area + yac_cell_clipping(numSearchCells, search.gridCells.data(), gridCell.yacGridCell, overlapCells.data()); + + // Get the partial areas for the overlapping regions + for (size_t i = 0; i < numSearchCells; i++) search.partialAreas[i] = gridcell_area(overlapCells[i]); + +#ifdef VERBOSE + for (size_t i = 0; i < numSearchCells; i++) printf("overlap area : %lf\n", search.partialAreas[i]); +#endif +} +/* +static void +cdo_compute_concave_overlap_info(size_t numSearchCells, CellSearch &search, const GridCell &gridCell, double tgtLon, double tgtLat, + double *overlapAreas, double (*overlapBarycenters)[3]) +{ + auto &overlapCells = search.overlapCells; + auto &sourceCells = search.gridCells; + auto targetCell = gridCell.yacGridCell; + + if (overlapBarycenters != NULL) + for (size_t i = 0; i < numSearchCells; ++i) + for (int j = 0; j < 3; ++j) overlapBarycenters[i][j] = 0.0; + + auto target_cell_type = (targetCell.num_corners > 3) ? get_cell_type(targetCell) : MIXED_CELL; + + if (targetCell.num_corners < 4 || target_cell_type == LON_LAT_CELL) + { + yac_cell_clipping(numSearchCells, sourceCells.data(), targetCell, overlapCells.data()); + for (size_t i = 0; i < numSearchCells; ++i) + { + if (overlapCells[i].num_corners > 1) + { + if (overlapBarycenters == NULL) + overlapAreas[i] = yac_huiliers_area(overlapCells[i]); + else + { + overlapAreas[i] = yac_huiliers_area_info(overlapCells[i], overlapBarycenters[i]); + normalise_vector(overlapBarycenters[i]); + } + } + else { overlapAreas[i] = 0.0; } + } + return; + } + + double coordinates_xyz[3][3] = { { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 } }; + enum yac_edge_type edgeTypes[3] = { GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE }; + + struct grid_cell targetPartialCell; + targetPartialCell.array_size = 3; + targetPartialCell.num_corners = 3; + targetPartialCell.coordinates_xyz = coordinates_xyz; + targetPartialCell.edge_type = edgeTypes; + + // Do the clipping and get the cell for the overlapping area + + for (size_t i = 0; i < numSearchCells; i++) partialAreas[i] = 0.0; + + // common node point to all partial target cells + auto partial_cell_xyz = targetPartialCell.coordinates_xyz; + auto cell_xyz = targetCell.coordinates_xyz; + + LL_to_XYZ(tgtLon, tgtLat, partial_cell_xyz[0]); + + for (size_t cornerNum = 0; cornerNum < targetCell.num_corners; ++cornerNum) + { + auto cornerA = cornerNum; + auto cornerB = (cornerNum + 1) % targetCell.num_corners; + + // skip clipping and area calculation for degenerated triangles + // + // If this is not sufficient, instead we can try something like: + // + // point_list target_list + // init_point_list(&target_list); + // generate_point_list(&target_list, targetCell); + // grid_cell temp_target_cell; + // generate_overlap_cell(target_list, temp_target_cell); + // free_point_list(&target_list); + // + // and use temp_target_cell for triangulation. + // + // Compared to the if statement below the alternative seems to be quite costly. + + if (points_are_identically(cell_xyz[cornerA], cell_xyz[cornerB])) continue; + + for (int k = 0; k < 3; ++k) partial_cell_xyz[1][k] = cell_xyz[cornerA][k]; + for (int k = 0; k < 3; ++k) partial_cell_xyz[2][k] = cell_xyz[cornerB][k]; + + yac_cell_clipping(numSearchCells, sourceCells.data(), targetPartialCell, overlapCells.data()); + + // Get the partial areas for the overlapping regions as sum over the partial target cells. + for (size_t i = 0; i < numSearchCells; i++) + { + if (overlapCells[i].num_corners == 0) continue; + + if (overlapBarycenters == NULL) + overlapAreas[i] += gridcell_area(overlapCells[i]); + else + overlapAreas[i] += yac_huiliers_area_info(overlapCells[i], overlapBarycenters[i]); + } + } + + if (overlapBarycenters != NULL) + for (size_t i = 0; i < numSearchCells; i++) + if (overlapAreas[i] > 0.0) normalise_vector(overlapBarycenters[i]); + +#ifdef VERBOSE + for (size_t i = 0; i < numSearchCells; i++) printf("overlap area %zu: %lf\n", i, overlapAreas[i]); +#endif +} + +static void +cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, const GridCell &gridCell, double tgtLon, double tgtLat) +{ + auto partialAreas = search.partialAreas.data(); + cdo_compute_concave_overlap_info(numSearchCells, search, gridCell, tgtLon, tgtLat, partialAreas, NULL); +} +*/ + +static double +get_edge_direction(const double *ref_corner, double *corner_a, double *corner_b) +{ + double edge_norm[3]; + crossproduct_kahan(corner_a, corner_b, edge_norm); + normalise_vector(edge_norm); + + // sine of the angle between the edge and the reference corner + double angle = edge_norm[0] * ref_corner[0] + edge_norm[1] * ref_corner[1] + edge_norm[2] * ref_corner[2]; + + // if the reference corner is directly on the edge + // (for small angles sin(x)==x) + if (fabs(angle) < yac_angle_tol) return 0.0; + + return copysign(1.0, angle); +} + +static void +cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, const GridCell &gridCell) +{ + auto targetCell = gridCell.yacGridCell; + auto &overlapAreas = search.partialAreas; + auto &overlapCells = search.overlapCells; + auto &sourceCells = search.gridCells; + + // common node point to all partial target cells + double *baseCorner = targetCell.coordinates_xyz[0]; + + // the triangulation algorithm only works for cells that only have great circle edges + enum yac_edge_type edgeTypes[3] = { GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE }; + double coordinates_xyz[3][3] = { { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 } }; + for (int k = 0; k < 3; ++k) coordinates_xyz[0][k] = baseCorner[k]; + + // data structure to hold the triangles of the target cell + struct grid_cell partialCell; + partialCell.array_size = 3; + partialCell.num_corners = 3; + partialCell.coordinates_xyz = coordinates_xyz; + partialCell.edge_type = edgeTypes; + + // Do the clipping and get the cell for the overlapping area + + for (size_t i = 0; i < numSearchCells; ++i) overlapAreas[i] = 0.0; + + // for all triangles of the target cell + // (triangles a formed by first corner of the target cells and each edge of + // the cell; the first and last edge of the cell already, contain the + // first corner, therefore we can skip them) + for (size_t cornerIdx = 1; cornerIdx < targetCell.num_corners - 1; ++cornerIdx) + { + auto cornerA = targetCell.coordinates_xyz[cornerIdx]; + auto cornerB = targetCell.coordinates_xyz[(cornerIdx + 1)]; + + // if the current edge has a length of zero + if (points_are_identically(cornerA, cornerB)) continue; + + auto edgeDirection = get_edge_direction(baseCorner, cornerA, cornerB); + + for (int k = 0; k < 3; ++k) partialCell.coordinates_xyz[1][k] = cornerA[k]; + for (int k = 0; k < 3; ++k) partialCell.coordinates_xyz[2][k] = cornerB[k]; + + // clip the current target cell triangle with all source cells + yac_cell_clipping(numSearchCells, sourceCells.data(), partialCell, overlapCells.data()); + + // Get the partial areas for the overlapping regions as sum over the partial target cells. + for (size_t i = 0; i < numSearchCells; ++i) + { + if (overlapCells[i].num_corners == 0) continue; + + overlapAreas[i] += gridcell_area(overlapCells[i]) * edgeDirection; + } + } + + for (size_t i = 0; i < numSearchCells; ++i) + { + if (overlapAreas[i] < 0.0) overlapAreas[i] = -overlapAreas[i]; + } + +#ifdef VERBOSE + for (size_t i = 0; i < numSearchCells; i++) printf("overlap area %zu: %lf\n", i, overlapAreas[i]); +#endif +} + +static void +set_cell_coordinates_yac(const size_t cellIndex, const size_t numCorners, const GridInfo &gridInfo, + const struct grid_cell &yacGridCell, double *x, double *y) +{ + auto storeXY = (x && y); + auto xyz = yacGridCell.coordinates_xyz; + + const auto cellCornersLon = &gridInfo.cellCornersLon[cellIndex * numCorners]; + const auto cellCornersLat = &gridInfo.cellCornersLat[cellIndex * numCorners]; + for (size_t i = 0; i < numCorners; ++i) LL_to_XYZ(cellCornersLon[i], cellCornersLat[i], xyz[i]); + + if (storeXY) + { + for (size_t k = 0; k < numCorners; ++k) + { + x[k] = cellCornersLon[k]; + y[k] = cellCornersLat[k]; + } + } +} + +static void +set_cell_coordinates(const size_t cellIndex, const size_t numCorners, const GridInfo &gridInfo, const GridCell &gridCell) +{ + set_cell_coordinates_yac(cellIndex, numCorners, gridInfo, gridCell.yacGridCell, gridCell.coordinates_x, gridCell.coordinates_y); +} + +static void +set_coordinates_yac(const size_t numCells, const Varray<size_t> &cellIndices, const size_t numCorners, const GridInfo &gridInfo, + const Varray<grid_cell> &yacGridCell) +{ + for (size_t i = 0; i < numCells; ++i) + set_cell_coordinates_yac(cellIndices[i], numCorners, gridInfo, yacGridCell[i], nullptr, nullptr); +} + +static void +set_coordinates_yac(const double (*xyzCoords)[3], const size_t numCells, const Varray<size_t> &cellIndices, const size_t numCorners, + const Varray<grid_cell> &yacGridCell) +{ + for (size_t i = 0; i < numCells; ++i) + { + auto offset = cellIndices[i] * numCorners; + auto xyz = yacGridCell[i].coordinates_xyz; + for (size_t k = 0; k < numCorners; ++k) + for (size_t l = 0; l < 3; ++l) xyz[k][l] = xyzCoords[offset + k][l]; + } +} + +static void +gridcell_init_yac(GridCell &gridCell, size_t numCorners, enum yac_edge_type *edgeType) +{ + gridCell.yacGridCell.array_size = numCorners; + gridCell.yacGridCell.num_corners = numCorners; + gridCell.yacGridCell.edge_type = edgeType; + gridCell.yacGridCell.coordinates_xyz = new double[numCorners][3]; + gridCell.coordinates_x = new double[numCorners]; + gridCell.coordinates_y = new double[numCorners]; +} + +static void +gridcell_free_yac(const GridCell &gridCell) +{ + delete[] gridCell.yacGridCell.coordinates_xyz; + delete[] gridCell.coordinates_x; + delete[] gridCell.coordinates_y; +} + +static size_t +remove_invalid_areas(size_t numSearchCells, Varray<double> &areas, Varray<size_t> &searchIndices) +{ + size_t n = 0; + for (size_t i = 0; i < numSearchCells; ++i) + { + if (areas[i] > 0.0) + { + areas[n] = areas[i]; + searchIndices[n] = searchIndices[i]; + n++; + } + } + + return n; +} + +static size_t +remove_invalid_weights(size_t gridSize, size_t numWeights, Varray<double> &weights, Varray<size_t> &searchIndices) +{ + size_t n = 0; + for (size_t i = 0; i < numWeights; ++i) + { + auto cellIndex = (weights[i] > 0.0) ? searchIndices[i] : gridSize; + if (cellIndex != gridSize) + { + weights[n] = weights[i]; + searchIndices[n] = cellIndex; + n++; + } + } + + return n; +} + +static size_t +remove_unmask_weights(const Varray<short> &gridMask, size_t numWeights, Varray<double> &weights, Varray<size_t> &searchIndices) +{ + size_t n = 0; + for (size_t i = 0; i < numWeights; ++i) + { + auto cellIndex = searchIndices[i]; + /* + Store the appropriate addresses and weights. + Also add contributions to cell areas. + The source grid mask is the master mask. + */ + if (gridMask[cellIndex]) + { + weights[n] = weights[i]; + searchIndices[n] = cellIndex; + n++; + } + } + + return n; +} + +static void +normalize_weights(NormOpt normOpt, double cellArea, double cellFrac, size_t numWeights, Varray<double> &weights) +{ + if (normOpt == NormOpt::DESTAREA) + { + auto normFactor = is_not_equal(cellArea, 0.0) ? 1.0 / cellArea : 0.0; + for (size_t i = 0; i < numWeights; ++i) weights[i] *= normFactor; + } + else if (normOpt == NormOpt::FRACAREA) + { + auto normFactor = is_not_equal(cellFrac, 0.0) ? 1.0 / cellFrac : 0.0; + for (size_t i = 0; i < numWeights; ++i) weights[i] *= normFactor; + } + else if (normOpt == NormOpt::NONE) {} +} + +static void +correct_weights(double cellArea, size_t numWeights, Varray<double> &weights) +{ + for (size_t i = 0; i < numWeights; ++i) weights[i] /= cellArea; + yac_correct_weights(numWeights, weights.data()); + for (size_t i = 0; i < numWeights; ++i) weights[i] *= cellArea; +} + +static void +sort_weights(size_t numWeights, Varray<size_t> &searchIndices, Varray<double> &weights) +{ + size_t n; + for (n = 1; n < numWeights; ++n) + if (searchIndices[n] < searchIndices[n - 1]) break; + if (n == numWeights) return; + + if (numWeights > 1) + { + struct IndexWeightX + { + size_t index; + double weight; + }; + + Varray<IndexWeightX> indexWeights(numWeights); + + for (n = 0; n < numWeights; ++n) + { + indexWeights[n].index = searchIndices[n]; + indexWeights[n].weight = weights[n]; + } + + const auto compareIndex = [](const auto &a, const auto &b) noexcept { return a.index < b.index; }; + std::sort(indexWeights.begin(), indexWeights.end(), compareIndex); + + for (n = 0; n < numWeights; ++n) + { + searchIndices[n] = indexWeights[n].index; + weights[n] = indexWeights[n].weight; + } + } +} + +static int +get_lonlat_circle_index(size_t numCells, size_t numCorners, const Varray<double> &clon, const Varray<double> &clat) +{ + int lonlatCircleIndex = -1; + + if (numCorners == 4) + { + size_t iadd = (numCells < 100) ? 1 : numCells / 30 - 1; + size_t num_i = 0, num_eq0 = 0, num_eq1 = 0; + + for (size_t i = 0; i < numCells; i += iadd) + { + auto i4 = i * 4; + num_i++; + // clang-format off + if (is_equal(clon[i4 + 1], clon[i4 + 2]) && is_equal(clon[i4 + 3], clon[i4 + 0]) && + is_equal(clat[i4 + 0], clat[i4 + 1]) && is_equal(clat[i4 + 2], clat[i4 + 3])) + { + num_eq1++; + } + else if (is_equal(clon[i4 + 0], clon[i4 + 1]) && is_equal(clon[i4 + 2], clon[i4 + 3]) && + is_equal(clat[i4 + 1], clat[i4 + 2]) && is_equal(clat[i4 + 3], clat[i4 + 0])) + { + num_eq0++; + } + // clang-format on + } + + if (num_i == num_eq1) lonlatCircleIndex = 1; + if (num_i == num_eq0) lonlatCircleIndex = 0; + } + + // printf("lonlatCircleIndex %d\n", lonlatCircleIndex); + + return lonlatCircleIndex; +} + +static int +get_lonlat_circle_index(const GridInfo &gridInfo) +{ + return get_lonlat_circle_index(gridInfo.numCells, gridInfo.numCorners, gridInfo.cellCornersLon, gridInfo.cellCornersLat); +} + +static double +conserv_remap(const Varray<double> &srcArray, size_t numWeights, const Varray<double> &weights, const Varray<size_t> &srcIndices) +{ + double tgtPoint = 0.0; + for (size_t i = 0; i < numWeights; ++i) tgtPoint += srcArray[srcIndices[i]] * weights[i]; + + return tgtPoint; +} + +void +remap_conserv2(NormOpt normOpt, const RemapSearch &remapSearch, const Varray<double> &srcArray, Varray<double> &tgtArray, + double missval) +{ + auto &srcGrid = remapSearch.srcGrid; + auto &tgtGrid = remapSearch.tgtGrid; + + auto srcNumCells = srcGrid.numCells; + auto tgtNumCells = tgtGrid.numCells; + + Varray<short> srcGridMask(srcNumCells); + for (size_t i = 0; i < srcNumCells; ++i) srcGridMask[i] = !is_equal(srcArray[i], missval); + + auto srcNumCorners = srcGrid.numCorners; + auto tgtNumCorners = tgtGrid.numCorners; + + enum yac_edge_type lonlatCircleType[] = { LON_CIRCLE_EDGE, LAT_CIRCLE_EDGE, LON_CIRCLE_EDGE, LAT_CIRCLE_EDGE, LON_CIRCLE_EDGE }; + Varray<enum yac_edge_type> greatCircleType(std::max(srcNumCorners, tgtNumCorners), GREAT_CIRCLE_EDGE); + + auto srcEdgeType = greatCircleType.data(); + auto tgtEdgeType = greatCircleType.data(); + + enum yac_cell_type tgtCellType = MIXED_CELL; + + if (srcNumCorners == 4) + { + auto lonlatCircleIndex = get_lonlat_circle_index(srcGrid); + if (lonlatCircleIndex >= 0) srcEdgeType = &lonlatCircleType[lonlatCircleIndex]; + } + + if (tgtNumCorners == 4) + { + auto lonlatCircleIndex = get_lonlat_circle_index(tgtGrid); + if (lonlatCircleIndex >= 0) + { + tgtCellType = LON_LAT_CELL; + tgtEdgeType = &lonlatCircleType[lonlatCircleIndex]; + } + } + + GridCell tgtGridCell; + gridcell_init_yac(tgtGridCell, tgtNumCorners, tgtEdgeType); + + CellSearch cellSearch; + cellSearch.numCellCorners = srcNumCorners; + cellSearch.edgeType = srcEdgeType; + + auto numCellCorners = srcNumCorners; // num of corners of search cells + + Varray<size_t> searchIndices(srcNumCells); + + // Loop over target grid + for (size_t tgtCellIndex = 0; tgtCellIndex < tgtNumCells; ++tgtCellIndex) + { + tgtArray[tgtCellIndex] = missval; + + // if (!tgtGrid.mask[tgtCellIndex]) continue; + + set_cell_coordinates(tgtCellIndex, tgtNumCorners, tgtGrid, tgtGridCell); + + // Get search cells + auto numSearchCells = do_gridcell_search(remapSearch.gcs, false, tgtGridCell, searchIndices); + + if (numSearchCells == 0) continue; + + // Create search arrays + + cellsearch_realloc(numSearchCells, cellSearch); + + // set_coordinates_yac(numSearchCells, searchIndices, numCellCorners, srcGrid, cellSearch.gridCells); + if (remapSearch.gcs.xyzCoords) + set_coordinates_yac(remapSearch.gcs.xyzCoords, numSearchCells, searchIndices, numCellCorners, cellSearch.gridCells); + else + set_coordinates_yac(numSearchCells, searchIndices, numCellCorners, srcGrid, cellSearch.gridCells); + + if (tgtNumCorners < 4 || tgtCellType == LON_LAT_CELL) + cdo_compute_overlap_areas(numSearchCells, cellSearch, tgtGridCell); + else + cdo_compute_concave_overlap_areas(numSearchCells, cellSearch, tgtGridCell); + + // For all supermesh cells compute the area and normalised area. + // Additionally, remove all empty supermesh cells. + size_t new_num_super_cells = 0; + size_t tgt_idx = 0; + /* + for (size_t i = 0, j = 0; i < total_num_overlaps;) + { + + // get information about the current target cell + size_t curr_tgt_cell = super_cells[i].tgt.local_id; + yac_const_basic_grid_data_get_grid_cell(tgt_basic_grid_data, curr_tgt_cell, &tgt_grid_cell); + + double curr_tgt_cell_coverage = 0.0; + + // for all supermesh cells overlapping with the current target cell + for (;(i < total_num_overlaps) && (super_cells[i].tgt.local_id == curr_tgt_cell); ++i) + { + + // get the current source cell + yac_const_basic_grid_data_get_grid_cell(src_basic_grid_data, super_cells[i].src.local_id, &src_grid_cell); + + // compute area of the current supermesh cell + double super_cell_area; + double barycenter[3]; + cdo_compute_concave_overlap_info(1, cellSearch, tgtGridCell, + tgtGrid.cellCentersLon[tgtCellIndex], tgtGrid.cellCentersLat[tgtCellIndex], + &super_cell_area, &barycenter); + } + + // if there is an overlap between the current source and target cell + if (super_cell_area > 0.0) + { + super_cells[new_num_super_cells].src = super_cells[i].src; + super_cells[new_num_super_cells].tgt = super_cells[i].tgt; + super_cells[new_num_super_cells].area = super_cell_area; + memcpy(super_cells[new_num_super_cells].barycenter, barycenter, 3 * sizeof(double)); + super_cells[new_num_super_cells].src_cell_gradient = NULL; + ++new_num_super_cells; + + curr_tgt_cell_coverage += super_cell_area; + } + } + */ + auto &partialWeights = cellSearch.partialAreas; + + auto numWeights = remove_invalid_areas(numSearchCells, partialWeights, searchIndices); + + auto tgtCellArea = gridcell_area(tgtGridCell.yacGridCell); + + if (normOpt == NormOpt::FRACAREA) correct_weights(tgtCellArea, numWeights, partialWeights); + + numWeights = remove_invalid_weights(srcNumCells, numWeights, partialWeights, searchIndices); + numWeights = remove_unmask_weights(srcGridMask, numWeights, partialWeights, searchIndices); + + auto tgtCellFrac = std::accumulate(partialWeights.begin(), partialWeights.begin() + numWeights, 0.0); + + if (numWeights) + { + sort_weights(numWeights, searchIndices, partialWeights); + // Normalize weights using target cell area if requested + normalize_weights(normOpt, tgtCellArea, tgtCellFrac, numWeights, partialWeights); + tgtArray[tgtCellIndex] = conserv_remap(srcArray, numWeights, partialWeights, searchIndices); + } + } + + // Finished with all cells: deallocate search arrays + + cellsearch_free(cellSearch); + gridcell_free_yac(tgtGridCell); +} // remap_conserv2 diff --git a/src/lib/yac/cdo_remap_conserv_test.cc b/src/lib/yac/cdo_remap_conserv_test.cc index a99fdf169ef03c53e6d4a2ba587386462ac2b20f..883dbad660523cb41bfd8208cc812ee910a02e06 100644 --- a/src/lib/yac/cdo_remap_conserv_test.cc +++ b/src/lib/yac/cdo_remap_conserv_test.cc @@ -1,6 +1,6 @@ /* gcc -DYAC_FOR_CDO -Wall -g -O3 -c *.c - g++ -DYAC_FOR_CDO -Drestrict= -Wall -g -O3 cdo_remap_conserv_test.cc cdo_grid.cc cdo_cell_search.cc cdo_remap_conserv.cc *.o + g++ -DYAC_FOR_CDO -Drestrict= -Wall -g -O3 cdo_remap_conserv_test.cc cdo_grid.cc cdo_cell_search.cc cdo_remap_conserv.cc cdo_remap_conserv2.cc *.o */ #include "cdo_remap.h" @@ -13,7 +13,7 @@ cdo_generate_grid_reg2d(GridInfo &grid, double *coordinates_x, double *coordinat static void test1() { - const double missval = -1.0; + double missval = -1.0; RemapSearch remapSearch; auto &srcGrid = remapSearch.srcGrid; @@ -74,7 +74,7 @@ static void test1() static void test3() { - const double missval = -1.0; + double missval = -1.0; RemapSearch remapSearch; auto &srcGrid = remapSearch.srcGrid; @@ -152,7 +152,7 @@ static void test3() static void test4() { - const double missval = -1.0; + double missval = -1.0; RemapSearch remapSearch; auto &srcGrid = remapSearch.srcGrid; @@ -258,7 +258,7 @@ static void test4() static void test6() { - const double missval = -1.0; + double missval = -1.0; RemapSearch remapSearch; auto &srcGrid = remapSearch.srcGrid; @@ -331,7 +331,7 @@ static void test6() gridcell_search_create(remapSearch.gcs, srcGrid.numCells, srcGrid.numCorners, srcGrid.cellCornersLon, srcGrid.cellCornersLat); - //remap_conserv2(NormOpt::DESTAREA, remapSearch, srcField, tgtField, missval); + remap_conserv2(NormOpt::DESTAREA, remapSearch, srcField, tgtField, missval); gridcell_search_delete(remapSearch.gcs); @@ -364,7 +364,7 @@ int main(void) test4(); // 2nd order conservativ remapping - // test6(); + //test6(); return 0; } diff --git a/src/lib/yac/cdo_remap_conserv_test2.cc b/src/lib/yac/cdo_remap_conserv_test2.cc deleted file mode 100644 index 037d97c12863b2a0b363db44c78b6eebdb4659fa..0000000000000000000000000000000000000000 --- a/src/lib/yac/cdo_remap_conserv_test2.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - gcc -DYAC_FOR_CDO -Wall -g -O3 -c *.c - g++ -DYAC_FOR_CDO -Drestrict= -Wall -g -O3 *.cc *.o - */ - -#include "cdo_remap.h" - -static void -compute_testfield(Varray<double> &array, const Varray<double> &cellCentersLon, const Varray<double> &cellCentersLat) -{ - double xyz[3]; - const auto numCells = array.size(); - for (size_t i = 0; i < numCells; ++i) - { - LL_to_XYZ(cellCentersLon[i], cellCentersLat[i], xyz); - const auto x = xyz[0]; - const auto y = xyz[1]; - const auto z = xyz[2]; - array[i] = 1.0 + std::pow(x, 8.0) + std::exp(2.0 * y * y * y) + std::exp(2.0 * x * x) + 10.0 * x * y * z; - } -} - -static -void output_ext(const Varray<double> &array) -{ - const auto numCells = array.size(); - fprintf(stdout, "%8d %4d %8g %8zu\n", 010101, 1, 0.0, numCells); - - int nout = 0; - for (size_t i = 0; i < numCells; i++) - { - if (nout == 6) - { - nout = 0; - fprintf(stdout, "\n"); - } - fprintf(stdout, " %12.6g", array[i]); - nout++; - } - fprintf(stdout, "\n"); -} - -static -void grid_init_regular(GridInfo &grid, double increment) -{ - generate_grid_lonlat(grid, increment, -180, 180, -90, 90); -} - -int main(void) -{ - const double missval = -9.e33; - RemapSearch remapSearch; - - auto &srcGrid = remapSearch.srcGrid; - auto &tgtGrid = remapSearch.tgtGrid; - - grid_init_regular(srcGrid, 0.5); - grid_init_regular(tgtGrid, 2.5); - - Varray<double> srcArray(srcGrid.numCells); - Varray<double> tgtArray(tgtGrid.numCells); - - compute_testfield(srcArray, srcGrid.cellCentersLon, srcGrid.cellCentersLat); - - gridcell_search_create(remapSearch.gcs, srcGrid.numCells, srcGrid.numCorners, srcGrid.cellCornersLon, srcGrid.cellCornersLat); - - remap_conserv(NormOpt::FRACAREA, remapSearch, srcArray, tgtArray, missval); - - // output_ext(srcArray); - // output_ext(tgtArray); - - gridcell_search_delete(remapSearch.gcs); - - return 0; -} diff --git a/src/lib/yac/check_overlap.c b/src/lib/yac/check_overlap.c index f8cab00a6dd19b31196abd165027ee0616afb4d3..863c030547f4ff48ab00f20d7175c82907912745 100644 --- a/src/lib/yac/check_overlap.c +++ b/src/lib/yac/check_overlap.c @@ -1,62 +1,10 @@ -/** - * @file check_overlap.c - * @brief Set of functions to determine an overlap between any two cells - * - * Compared to \ref check_overlap.c these routine take care of how vertex - * points of a cell are connected, either by great circles or along the loxodrome. - * - * very interesting literature: - * - http://geospatialmethods.org/spheres/GCIntersect.html - * - * Note: Not all functions are documented by Doxygen. See the source code - * and \ref geometry.h for further details. - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #include <stdlib.h> #include <math.h> -#include "utils.h" +#include "utils_core.h" #include "geometry.h" #include "grid_cell.h" @@ -170,9 +118,9 @@ static int point_in_cell_unstruct_triangle( double cross_edges[3][3]; - crossproduct_ld(a, b, &(cross_edges[0][0])); - crossproduct_ld(b, c, &(cross_edges[1][0])); - crossproduct_ld(c, a, &(cross_edges[2][0])); + crossproduct_kahan(a, b, &(cross_edges[0][0])); + crossproduct_kahan(b, c, &(cross_edges[1][0])); + crossproduct_kahan(c, a, &(cross_edges[2][0])); double sq_sin_edge[3] = { cross_edges[0][0] * cross_edges[0][0] + @@ -274,9 +222,9 @@ static int point_in_cell_unstruct_triangle( // double cross_edges[3][3]; - // crossproduct_ld(a, b, &(cross_edges[0][0])); - // crossproduct_ld(b, c, &(cross_edges[1][0])); - // crossproduct_ld(c, a, &(cross_edges[2][0])); + // crossproduct_kahan(a, b, &(cross_edges[0][0])); + // crossproduct_kahan(b, c, &(cross_edges[1][0])); + // crossproduct_kahan(c, a, &(cross_edges[2][0])); // double sq_sin_edge[3] = { // cross_edges[0][0] * cross_edges[0][0] + @@ -396,10 +344,10 @@ static int point_in_cell_unstruct_quad( double cross[4][3]; - crossproduct_ld(a, b, &(cross[0][0])); - crossproduct_ld(b, c, &(cross[1][0])); - crossproduct_ld(c, d, &(cross[2][0])); - crossproduct_ld(d, a, &(cross[3][0])); + crossproduct_kahan(a, b, &(cross[0][0])); + crossproduct_kahan(b, c, &(cross[1][0])); + crossproduct_kahan(c, d, &(cross[2][0])); + crossproduct_kahan(d, a, &(cross[3][0])); double sq_sin_edge[4] = { cross[0][0]*cross[0][0]+cross[0][1]*cross[0][1]+cross[0][2]*cross[0][2], @@ -456,10 +404,10 @@ static int point_in_cell_unstruct_quad( // double cross[4][3]; - // crossproduct_ld(a, b, &(cross[0][0])); - // crossproduct_ld(b, c, &(cross[1][0])); - // crossproduct_ld(c, d, &(cross[2][0])); - // crossproduct_ld(d, a, &(cross[3][0])); + // crossproduct_kahan(a, b, &(cross[0][0])); + // crossproduct_kahan(b, c, &(cross[1][0])); + // crossproduct_kahan(c, d, &(cross[2][0])); + // crossproduct_kahan(d, a, &(cross[3][0])); // double sq_sin_edge[4] = { // cross[0][0]*cross[0][0]+cross[0][1]*cross[0][1]+cross[0][2]*cross[0][2], diff --git a/src/lib/yac/clipping.c b/src/lib/yac/clipping.c index 9c12446ee1cf984a026ba9c05a781615a09cb9e0..f941ba3eb24f1cbf660643b3636aa7a12a053037 100644 --- a/src/lib/yac/clipping.c +++ b/src/lib/yac/clipping.c @@ -1,48 +1,6 @@ -/** - * @file clipping.c - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #ifdef HAVE_CONFIG_H // Get the definition of the 'restrict' keyword. @@ -54,12 +12,11 @@ #include <string.h> #include <math.h> -#include "yac_ld_interface.h" #include "geometry.h" #include "clipping.h" #include "area.h" #include "ensure_array_size.h" -#include "utils.h" +#include "utils_core.h" //#define YAC_VERBOSE_CLIPPING @@ -133,7 +90,7 @@ static double get_edge_direction( double * ref_corner, double * corner_a, double * corner_b) { double edge_norm[3]; - crossproduct_ld(corner_a, corner_b, edge_norm); + crossproduct_kahan(corner_a, corner_b, edge_norm); normalise_vector(edge_norm); // sine of the angle between the edge and the reference corner @@ -317,7 +274,7 @@ void yac_compute_overlap_areas (size_t N, static enum yac_cell_type get_cell_type(struct grid_cell target_cell) { YAC_ASSERT( - target_cell.num_corners > 0, "ERROR(get_cell_type): CELL without edge") + target_cell.num_corners > 0, "ERROR(get_cell_type): cell without edge") enum yac_cell_type cell_type = MIXED_CELL; @@ -396,34 +353,20 @@ int yac_circle_compare(void const * a, void const * b) { default: case (GREAT_CIRCLE): for (int i = 0; !ret && (i < 3); ++i) { -#ifndef USE_MPF ret = (circle_a->data.gc.norm_vector[i] > circle_b->data.gc.norm_vector[i]) - (circle_a->data.gc.norm_vector[i] < circle_b->data.gc.norm_vector[i]); -#else - ret = (mpf_cmp(circle_a->data.gc.norm_vector[i], - circle_b->data.gc.norm_vector[i]) > 0) - - (mpf_cmp(circle_a->data.gc.norm_vector[i], - circle_b->data.gc.norm_vector[i]) < 0); -#endif } break; case (LON_CIRCLE): for (int i = 0; !ret && (i < 3); ++i) { -#ifndef USE_MPF ret = (circle_a->data.lon.norm_vector[i] > circle_b->data.lon.norm_vector[i]) - (circle_a->data.lon.norm_vector[i] < circle_b->data.lon.norm_vector[i]); -#else - ret = (mpf_cmp(circle_a->data.lon.norm_vector[i], - circle_b->data.lon.norm_vector[i]) > 0) - - (mpf_cmp(circle_a->data.lon.norm_vector[i], - circle_b->data.lon.norm_vector[i]) < 0); -#endif } break; case (LAT_CIRCLE): @@ -443,86 +386,19 @@ int yac_circle_compare(void const * a, void const * b) { return ret; } -#ifndef USE_MPF -static void compute_norm_vector_ld( - double const a[3], double const b[3], long double norm_vector[3]) { - long double const a_[3] = {a[0], a[1], a[2]}; - long double const b_[3] = {b[0], b[1], b[2]}; +static void compute_norm_vector_kahan( + double const a[3], double const b[3], double norm_vector[3]) { - norm_vector[0] = a_[1] * b_[2] - a_[2] * b_[1]; - norm_vector[1] = a_[2] * b_[0] - a_[0] * b_[2]; - norm_vector[2] = a_[0] * b_[1] - a_[1] * b_[0]; + crossproduct_kahan(a, b, norm_vector); - long double scale = 1.0 / sqrtl(norm_vector[0] * norm_vector[0] + - norm_vector[1] * norm_vector[1] + - norm_vector[2] * norm_vector[2]); + double scale = 1.0 / sqrt(norm_vector[0] * norm_vector[0] + + norm_vector[1] * norm_vector[1] + + norm_vector[2] * norm_vector[2]); norm_vector[0] *= scale; norm_vector[1] *= scale; norm_vector[2] *= scale; } -#else -static void compute_norm_vector_ld( - double const a[3], double const b[3], mpf_t norm_vector[3]) { - - mpf_t a_[3], b_[3]; - yac_mpf_set_vector_d(a_, a); - yac_mpf_set_vector_d(b_, b); - - // norm_vector = a_[1] * b_[2] - mpf_mul(norm_vector[0], a_[1], b_[2]); - // norm_vector = a_[2] * b_[0] - mpf_mul(norm_vector[1], a_[2], b_[0]); - // norm_vector = a_[0] * b_[1] - mpf_mul(norm_vector[2], a_[0], b_[1]); - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - - // buf = a_[2] * b_[1] - mpf_mul(buf, a_[2], b_[1]); - // norm_vector[0] -= buf - mpf_sub(norm_vector[0], norm_vector[0], buf); - // buf = a_[0] * b_[2] - mpf_mul(buf, a_[0], b_[2]); - // norm_vector[1] -= buf - mpf_sub(norm_vector[1], norm_vector[1], buf); - // buf = a_[1] * b_[0] - mpf_mul(buf, a_[1], b_[0]); - // norm_vector[2] -= buf - mpf_sub(norm_vector[2], norm_vector[2], buf); - - mpf_t scale; - mpf_init2(scale, YAC_MPF_PRECISION); - - // scale = norm_vector[0] * norm_vector[0] - mpf_mul(scale, norm_vector[0], norm_vector[0]); - // buf = norm_vector[1] * norm_vector[1] - mpf_mul(buf, norm_vector[1], norm_vector[1]); - // scale += buf - mpf_add(scale, scale, buf); - // buf = norm_vector[2] * norm_vector[2] - mpf_mul(buf, norm_vector[2], norm_vector[2]); - // scale += buf - mpf_add(scale, scale, buf); - // scale = sqrt(scale) - mpf_sqrt(scale, scale); - // scale = 1.0 / scale - mpf_ui_div(scale, 1, scale); - - // norm_vector[0] *= scale - mpf_mul(norm_vector[0], norm_vector[0], scale); - // norm_vector[1] *= scale - mpf_mul(norm_vector[1], norm_vector[1], scale); - // norm_vector[2] *= scale - mpf_mul(norm_vector[2], norm_vector[2], scale); - - yac_mpf_clear_vector(a_); - yac_mpf_clear_vector(b_); - mpf_clear(buf); - mpf_clear(scale); -} -#endif void yac_circle_generate( double const * a, double const * b, enum yac_edge_type type, @@ -553,17 +429,11 @@ void yac_circle_generate( default: case(GREAT_CIRCLE_EDGE): circle->type = GREAT_CIRCLE; -#ifdef USE_MPF - yac_mpf_init_vector(circle->data.gc.norm_vector); -#endif - compute_norm_vector_ld(a, b, circle->data.gc.norm_vector); + compute_norm_vector_kahan(a, b, circle->data.gc.norm_vector); break; case(LON_CIRCLE_EDGE): circle->type = LON_CIRCLE; -#ifdef USE_MPF - yac_mpf_init_vector(circle->data.lon.norm_vector); -#endif - compute_norm_vector_ld(a, b, circle->data.lon.norm_vector); + compute_norm_vector_kahan(a, b, circle->data.lon.norm_vector); break; case(LAT_CIRCLE_EDGE): circle->type = LAT_CIRCLE; @@ -586,23 +456,6 @@ static inline struct yac_circle return circle; } -#ifdef USE_MPF -void yac_circles_free(struct yac_circle* circles, size_t size) { - for (size_t i = 0; i < size; ++i) { - switch (circles[i].type) { - case(GREAT_CIRCLE): - yac_mpf_clear_vector(circles[i].data.gc.norm_vector); - break; - case(LON_CIRCLE): - yac_mpf_clear_vector(circles[i].data.lon.norm_vector); - break; - default: - break; - } - } -} -#endif - int yac_circle_point_is_inside( double const point[3], struct yac_circle * circle) { @@ -616,29 +469,17 @@ int yac_circle_point_is_inside( switch (circle->type) { default: case (GREAT_CIRCLE): { -#ifndef USE_MPF - double dot = point[0] * (double)(circle->data.gc.norm_vector[0]) + - point[1] * (double)(circle->data.gc.norm_vector[1]) + - point[2] * (double)(circle->data.gc.norm_vector[2]); -#else - double dot = point[0] * mpf_get_d(circle->data.gc.norm_vector[0]) + - point[1] * mpf_get_d(circle->data.gc.norm_vector[1]) + - point[2] * mpf_get_d(circle->data.gc.norm_vector[2]); -#endif + double dot = point[0] * circle->data.gc.norm_vector[0] + + point[1] * circle->data.gc.norm_vector[1] + + point[2] * circle->data.gc.norm_vector[2]; if (dot < (- yac_angle_tol * 1e-3)) return 0; else if (dot > (+ yac_angle_tol * 1e-3)) return 1; else return 2; } case (LON_CIRCLE): { -#ifndef USE_MPF - double dot = point[0] * (double)(circle->data.lon.norm_vector[0]) + - point[1] * (double)(circle->data.lon.norm_vector[1]) + - point[2] * (double)(circle->data.lon.norm_vector[2]); -#else - double dot = point[0] * mpf_get_d(circle->data.lon.norm_vector[0]) + - point[1] * mpf_get_d(circle->data.lon.norm_vector[1]) + - point[2] * mpf_get_d(circle->data.lon.norm_vector[2]); -#endif + double dot = point[0] * circle->data.lon.norm_vector[0] + + point[1] * circle->data.lon.norm_vector[1] + + point[2] * circle->data.lon.norm_vector[2]; if (dot < (- yac_angle_tol * 1e-3)) return 0; else if (dot > (+ yac_angle_tol * 1e-3)) return 1; else return 2; @@ -667,15 +508,9 @@ int yac_circle_compare_distances( switch (circle->type) { default: case(GREAT_CIRCLE): { -#ifndef USE_MPF - double norm_vector[3] = {(double)(circle->data.gc.norm_vector[0]), - (double)(circle->data.gc.norm_vector[1]), - (double)(circle->data.gc.norm_vector[2])}; -#else - double norm_vector[3] = {mpf_get_d(circle->data.gc.norm_vector[0]), - mpf_get_d(circle->data.gc.norm_vector[1]), - mpf_get_d(circle->data.gc.norm_vector[2])}; -#endif + double norm_vector[3] = {circle->data.gc.norm_vector[0], + circle->data.gc.norm_vector[1], + circle->data.gc.norm_vector[2]}; dist_a = fabs(a[0] * norm_vector[0] + a[1] * norm_vector[1] + a[2] * norm_vector[2]); @@ -685,15 +520,9 @@ int yac_circle_compare_distances( break; } case(LON_CIRCLE): { -#ifndef USE_MPF - double norm_vector[3] = {(double)(circle->data.lon.norm_vector[0]), - (double)(circle->data.lon.norm_vector[1]), - (double)(circle->data.lon.norm_vector[2])}; -#else - double norm_vector[3] = {mpf_get_d(circle->data.lon.norm_vector[0]), - mpf_get_d(circle->data.lon.norm_vector[1]), - mpf_get_d(circle->data.lon.norm_vector[2])}; -#endif + double norm_vector[3] = {circle->data.lon.norm_vector[0], + circle->data.lon.norm_vector[1], + circle->data.lon.norm_vector[2]}; dist_a = fabs(a[0] * norm_vector[0] + a[1] * norm_vector[1] + a[2] * norm_vector[2]); @@ -731,11 +560,7 @@ int yac_circle_contains_north_pole(struct yac_circle * circle) { switch (circle->type) { default: case (GREAT_CIRCLE): -#ifndef USE_MPF return circle->data.gc.norm_vector[2] > 0.0; -#else - return mpf_sgn(circle->data.gc.norm_vector[2]) > 0; -#endif case (LAT_CIRCLE): return !circle->data.lat.north_is_out; case (LON_CIRCLE): @@ -884,28 +709,19 @@ static void circle_clipping( cell_edge_coords[1][0], cell_edge_coords[1][1], cell_edge_coords[1][2], (int)cell_edge_circle->type, -#ifndef USE_MPF - (double)(clipping_circle->data.gc.norm_vector[0]), - (double)(clipping_circle->data.gc.norm_vector[1]), - (double)(clipping_circle->data.gc.norm_vector[2]), - (double)(clipping_circle->data.lon.norm_vector[0]), - (double)(clipping_circle->data.lon.norm_vector[1]), - (double)(clipping_circle->data.lon.norm_vector[2]), -#else - mpf_get_d(clipping_circle->data.gc.norm_vector[0]), - mpf_get_d(clipping_circle->data.gc.norm_vector[1]), - mpf_get_d(clipping_circle->data.gc.norm_vector[2]), - mpf_get_d(clipping_circle->data.lon.norm_vector[0]), - mpf_get_d(clipping_circle->data.lon.norm_vector[1]), - mpf_get_d(clipping_circle->data.lon.norm_vector[2]), -#endif - clipping_circle->data.lat.z, - clipping_circle->data.lat.north_is_out, - clipping_circle->data.p.vec[0], - clipping_circle->data.p.vec[1], - clipping_circle->data.p.vec[2], (int)(clipping_circle->type), - intersection[0][0], intersection[0][1], intersection[0][2], - intersection[1][0], intersection[1][1], intersection[1][2]) + clipping_circle->data.gc.norm_vector[0], + clipping_circle->data.gc.norm_vector[1], + clipping_circle->data.gc.norm_vector[2], + clipping_circle->data.lon.norm_vector[0], + clipping_circle->data.lon.norm_vector[1], + clipping_circle->data.lon.norm_vector[2], + clipping_circle->data.lat.z, + clipping_circle->data.lat.north_is_out, + clipping_circle->data.p.vec[0], + clipping_circle->data.p.vec[1], + clipping_circle->data.p.vec[2], (int)(clipping_circle->type), + intersection[0][0], intersection[0][1], intersection[0][2], + intersection[1][0], intersection[1][1], intersection[1][2]) // if both cell edge vertices are on the same side of the // clipping edge @@ -1359,11 +1175,7 @@ void yac_cell_clipping (size_t N, generate_cell(overlap, overlap_buffer + n); - yac_circles_free(src_circle_buffer, source_cell[n].num_corners); } - - yac_circles_free(circle_buffer, target_cell.num_corners); - free(circle_buffer); free_point_list(&source_list); free_point_list(&target_list); @@ -1611,8 +1423,6 @@ void yac_cell_lat_clipping (size_t N, circle_clipping(&cell_list, num_corners, lat_circles, num_lat_circles); generate_cell(&cell_list, overlap_buffer + n); - - yac_circles_free(circle_buffer, cells[n].num_corners); } } @@ -1884,7 +1694,7 @@ static void free_point_list(struct point_list * list) { static void compute_norm_vector(double a[], double b[], double norm[]) { - crossproduct_ld(a, b, norm); + crossproduct_kahan(a, b, norm); YAC_ASSERT( (fabs(norm[0]) >= tol) || (fabs(norm[1]) >= tol) || (fabs(norm[2]) >= tol), diff --git a/src/lib/yac/clipping.h b/src/lib/yac/clipping.h index 02c0dc382699baf8a7a79496bbe40d18b230f211..660bd4b5432d943bc16e65f8824a5318e3632646 100644 --- a/src/lib/yac/clipping.h +++ b/src/lib/yac/clipping.h @@ -1,49 +1,6 @@ -/** - * @file clipping.h - * @brief Structs and interfaces for cell clipping - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #ifndef CLIPPING_H #define CLIPPING_H @@ -208,18 +165,6 @@ void yac_circle_generate( double const * a, double const * b, enum yac_edge_type type, int edge_ordering, struct yac_circle * circle); -#ifndef USE_MPF -#define yac_circles_free(circles, size) -#else -/** - * Frees memory allocated by an array of yac circles - * - * @param[in] circles yac circles - * @param[in] size number of entries in circles - */ -void yac_circles_free(struct yac_circle * circles, size_t size); -#endif - /** * Compare routine for yac circles (first by type and second parameters * of the circle, if types are identical) diff --git a/src/lib/yac/compare_files b/src/lib/yac/compare_files index ab71dd1401f28b2ec9dbf5d9e55580e24c96f6a4..ab7735010176bed0123dce2fcca05815039077f0 100755 --- a/src/lib/yac/compare_files +++ b/src/lib/yac/compare_files @@ -1,6 +1,6 @@ #!/bin/sh # -YACSRC=/Users/m214003/cdt/work/YAC/YAC-dev/src +YACSRC=/Users/m214003/cdt/work/YAC/YAC-dev/src/core # FILES="*.c *.h" # diff --git a/src/lib/yac/ensure_array_size.c b/src/lib/yac/ensure_array_size.c index 88dde7a346185ae45da40f12136364f979795c00..475bffd4ecb8c655eb20b72218864a056c72ca38 100644 --- a/src/lib/yac/ensure_array_size.c +++ b/src/lib/yac/ensure_array_size.c @@ -1,51 +1,12 @@ -/** - * @file ensure_array_size.c - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #include <stdio.h> #include <stdlib.h> #include "ensure_array_size.h" -#include "utils.h" +#include "utils_core.h" void yac_realloc_array(void **array, size_t elem_size, size_t *curr_array_size, diff --git a/src/lib/yac/ensure_array_size.h b/src/lib/yac/ensure_array_size.h index d98a03daa0bde55f7c422677555b1c77f712d14f..85e54289abebb9d28b4fadb2b2942a3974c6e91f 100644 --- a/src/lib/yac/ensure_array_size.h +++ b/src/lib/yac/ensure_array_size.h @@ -1,48 +1,6 @@ -/** - * @file ensure_array_size.h - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #ifndef ENSURE_ARRAY_SIZE_H #define ENSURE_ARRAY_SIZE_H diff --git a/src/lib/yac/field_data.h b/src/lib/yac/field_data.h new file mode 100644 index 0000000000000000000000000000000000000000..2eedcbc3b3a28a934779aa8a502057f52609b3c8 --- /dev/null +++ b/src/lib/yac/field_data.h @@ -0,0 +1,33 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FIELD_DATA_H +#define FIELD_DATA_H + +#include "yac_types.h" + +struct yac_field_data; + +struct yac_field_data * yac_field_data_empty_new(); +size_t yac_field_data_add_mask_nocpy( + struct yac_field_data * field_data, int const * mask, + char const * mask_name); +size_t yac_field_data_add_coordinates_nocpy( + struct yac_field_data * field_data, yac_coordinate_pointer coordinates); +size_t yac_field_data_get_masks_count(struct yac_field_data * field_data); +int const * yac_field_data_get_mask_data( + struct yac_field_data * field_data, size_t mask_idx); +void yac_field_data_set_mask_data( + struct yac_field_data * field_data, size_t mask_idx, int * mask_data); +char const * yac_field_data_get_mask_name( + struct yac_field_data * field_data, size_t mask_idx); +size_t yac_field_data_get_coordinates_count(struct yac_field_data * field_data); +yac_const_coordinate_pointer yac_field_data_get_coordinates_data( + struct yac_field_data * field_data, size_t coordinates_idx); +void yac_field_data_set_coordinates_data( + struct yac_field_data * field_data, size_t coordinates_idx, + yac_coordinate_pointer coordinates_data); +void yac_field_data_delete(struct yac_field_data * field_data); + +#endif // FIELD_DATA_H diff --git a/src/lib/yac/geometry.h b/src/lib/yac/geometry.h index 72bd2f3f6b6696480a5a85058ee76760e285a552..339f68c5dfffb7496df391ebdfe8608b3134e73a 100644 --- a/src/lib/yac/geometry.h +++ b/src/lib/yac/geometry.h @@ -1,55 +1,6 @@ -/** - * @file geometry.h - * @brief Structs and interfaces for investigating the geometry and relations of cells - * - * The functions are used to determine relations between - * source and target cells. Complete cells are constructed - * on the sphere by connecting cell vertices along either - * great circles (along the orthodrome) or directly (along - * the loxodrome). - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause /** \example test_geometry.c * This contains some tests for basic routines of \ref geometry.h. @@ -72,17 +23,11 @@ #include <math.h> #include <float.h> -#include "yac_ld_interface.h" -#include "grid.h" -#include "utils.h" +#include "basic_grid.h" +#include "grid_cell.h" +#include "utils_core.h" -#ifndef M_SQRT1_2 -#define M_SQRT1_2 (0.707106781186547524401) /* sqrt(0.5) */ -#endif - -#ifndef M_SQRT3_4 -#define M_SQRT3_4 (0.866025403784438646764) /* sqrt(0.75) */ -#endif +#define YAC_RAD (0.01745329251994329576923690768489) // M_PI / 180 // angle tolerance @@ -138,11 +83,7 @@ struct yac_circle { union { struct { // the norm vector points into the inside direction -#ifndef USE_MPF - long double norm_vector[3]; -#else - mpf_t norm_vector[3]; -#endif + double norm_vector[3]; } gc, lon; struct { int north_is_out; @@ -192,6 +133,22 @@ static inline double get_angle (double a_lon, double b_lon) { #endif } +/** + * computes the angle between two longitude coordinates (in deg) \n + * takes into account that longitude have a period of 360 + * @param[in] a_lon + * @param[in] b_lon + * @return angle between both coordinates (in rad) + */ +static inline double get_angle_deg (double a_lon, double b_lon) { + double diff = a_lon - b_lon; +#if defined(CDO) + return diff - lround(diff / 360.0) * (360.0); +#else + return diff - round(diff / 360.0) * (360.0); +#endif +} + /** * computes the intersection points of two edges * @param[in] edge_type_a type of edge a @@ -364,55 +321,28 @@ static inline void XYZtoLL (double const p_in[], double * lon, double * lat) { *lat = M_PI_2 - acos(p_in[2]); } -#ifndef USE_MPF -static inline void crossproduct_ld ( - double const a[], double const b[], double cross[]) { - -/* crossproduct in Cartesian coordinates */ - - long double a_[3] = {a[0], a[1], a[2]}; - long double b_[3] = {b[0], b[1], b[2]}; - - cross[0] = (double)(a_[1] * b_[2] - a_[2] * b_[1]); - cross[1] = (double)(a_[2] * b_[0] - a_[0] * b_[2]); - cross[2] = (double)(a_[0] * b_[1] - a_[1] * b_[0]); +// computation of the determinant of a 2x2 matrix using Kahan summation +static inline double det2_kahan(double a, double b, double c, double d) { + double bc = b*c; + double e_bc = fma(b,c,-bc); // the rounding error of the multiplication + double det = fma(a,d,-bc); + return det + e_bc; } -#else -static void crossproduct_ld ( - double const a[], double const b[], double cross[]) { - mpf_t a_[3], b_[3], cross_[3]; - yac_mpf_set_vector_d(a_, a); - yac_mpf_set_vector_d(b_, b); - yac_mpf_init_vector(cross_); - - mpf_mul(cross_[0], a_[1], b_[2]); - mpf_mul(cross_[1], a_[2], b_[0]); - mpf_mul(cross_[2], a_[0], b_[1]); - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); +static inline void crossproduct_kahan ( + double const a[], double const b[], double cross[]) { - mpf_mul(buf, a_[2], b_[1]); - mpf_sub(cross_[0], cross_[0], buf); - mpf_mul(buf, a_[0], b_[2]); - mpf_sub(cross_[1], cross_[1], buf); - mpf_mul(buf, a_[1], b_[0]); - mpf_sub(cross_[2], cross_[2], buf); + /* crossproduct in Cartesian coordinates */ - cross[0] = mpf_get_d(cross_[0]); - cross[1] = mpf_get_d(cross_[1]); - cross[2] = mpf_get_d(cross_[2]); + cross[0] = det2_kahan(a[1], a[2], b[1], b[2]); + cross[1] = det2_kahan(a[2], a[0], b[2], b[0]); + cross[2] = det2_kahan(a[0], a[1], b[0], b[1]); - yac_mpf_clear_vector(a_); - yac_mpf_clear_vector(b_); - yac_mpf_clear_vector(cross_); } -#endif /** * for small angles <= 1e-?8? the crossproduct is inaccurate\n - * use \ref crossproduct_ld for these cases + * use \ref crossproduct_kahan for these cases */ static inline void crossproduct_d ( const double a[], const double b[], double cross[]) { @@ -440,7 +370,7 @@ static inline double get_vector_angle(double const a[3], double const b[3]) { double cross_ab[3]; - crossproduct_ld(a, b, cross_ab); + crossproduct_kahan(a, b, cross_ab); double asin_tmp = asin(sqrt(cross_ab[0]*cross_ab[0]+ cross_ab[1]*cross_ab[1]+ @@ -460,7 +390,7 @@ static inline double get_vector_angle(double const a[3], double const b[3]) { // this solution is simpler, but has a much worse performance double cross[3], dot, cross_abs; - crossproduct_ld(a, b, cross); + crossproduct_kahan(a, b, cross); dot = a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; cross_abs = sqrt(cross[0]*cross[0] + cross[1]*cross[1] + cross[2]*cross[2]); @@ -483,10 +413,10 @@ static inline struct sin_cos_angle sin_cos_angle_new(double sin, double cos) { } static inline struct sin_cos_angle get_vector_angle_2( - double a[3], double b[3]) { + double const a[3], double const b[3]) { double cross_ab[3]; - crossproduct_ld(a, b, cross_ab); + crossproduct_kahan(a, b, cross_ab); return sin_cos_angle_new(sqrt(cross_ab[0]*cross_ab[0] + cross_ab[1]*cross_ab[1] + @@ -741,7 +671,7 @@ static inline int compare_coords(double const * a, double const * b) { // accuracy double cross_ab[3]; - crossproduct_ld(a, b, cross_ab); + crossproduct_kahan(a, b, cross_ab); // for very small angles: asin(alpha) = ~alpha (alpha in rad) if (sqrt(cross_ab[0]*cross_ab[0] + diff --git a/src/lib/yac/grid.h b/src/lib/yac/grid.h deleted file mode 100644 index fe76627eea6bfbaae9df6d0bec7e0c37e49191af..0000000000000000000000000000000000000000 --- a/src/lib/yac/grid.h +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @file grid.h - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef GRID_H -#define GRID_H - -#include "utils.h" -#include "grid_cell.h" - -#define YAC_MAX_LOC_STR_LEN 10 - -enum yac_location { - - CELL = 0, - CORNER = 1, - EDGE = 2, - LOC_UNDEFINED = 3, -}; - -/** \example test_grid.c - */ - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338327950288 /* pi */ -#endif - -#ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923132169163975144 /* pi/2 */ -#endif - -#define YAC_EARTH_RADIUS (6371.2290) -#define YAC_EARTH_RADIUS2 ((6371.2290 * 6371.2290) * 0.5) -#define YAC_RAD (0.01745329251994329576923690768489) // M_PI / 180 - -typedef size_t (* size_t_2_pointer)[2]; - -struct yac_field_data { - int ** masks; - size_t masks_count; - coordinate_pointer * coordinates; - size_t coordinates_count; -}; - -struct yac_field_data_set { - struct yac_field_data cell, vertex, edge; -}; - -struct interp_field { - enum yac_location location; - size_t coordinates_idx; - size_t masks_idx; -}; - -struct basic_grid_data { - coordinate_pointer vertex_coordinates; - yac_int * cell_ids; - yac_int * vertex_ids; - yac_int * edge_ids; - size_t num_cells; // number of local cells (owned by local process) - size_t num_vertices; // number of local vertices (owned by local process) - size_t num_edges; // number of local edges (owned by local process) - int * core_cell_mask; - int * core_vertex_mask; - int * core_edge_mask; - int * num_vertices_per_cell; - int * num_cells_per_vertex; - size_t * cell_to_vertex; - size_t * cell_to_vertex_offsets; - size_t * cell_to_edge; - size_t * cell_to_edge_offsets; - size_t * vertex_to_cell; - size_t * vertex_to_cell_offsets; - size_t_2_pointer edge_to_vertex; - enum yac_edge_type * edge_type; - size_t num_total_cells; // number of locally stored cells - size_t num_total_vertices; // number of locally stored vertices - size_t num_total_edges; // number of locally stored edges -}; - -struct yac_basic_grid; - -struct basic_grid_data yac_generate_basic_grid_data_reg_2d( - size_t nbr_vertices[2], int cyclic[2], - double *lon_vertices, double *lat_vertices); - -struct basic_grid_data yac_generate_basic_grid_data_reg_2d_deg( - size_t nbr_vertices[2], int cyclic[2], - double *lon_vertices, double *lat_vertices); - -struct basic_grid_data yac_generate_basic_grid_data_curve_2d( - size_t nbr_vertices[2], int cyclic[2], - double *lon_vertices, double *lat_vertices); - -struct basic_grid_data yac_generate_basic_grid_data_curve_2d_deg( - size_t nbr_vertices[2], int cyclic[2], - double *lon_vertices, double *lat_vertices); - -struct basic_grid_data yac_generate_basic_grid_data_unstruct( - size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, - double *x_vertices, double *y_vertices, int *cell_to_vertex); - -struct basic_grid_data yac_generate_basic_grid_data_unstruct_deg( - size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, - double *x_vertices, double *y_vertices, int *cell_to_vertex); - -struct basic_grid_data yac_generate_basic_grid_data_unstruct_ll( - size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, - double *x_vertices, double *y_vertices, int *cell_to_vertex); - -struct basic_grid_data yac_generate_basic_grid_data_unstruct_ll_deg( - size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, - double *x_vertices, double *y_vertices, int *cell_to_vertex); - -struct yac_basic_grid * yac_basic_grid_new( - char const * name, struct basic_grid_data grid_data); -struct yac_basic_grid * yac_basic_grid_empty_new(char const * name); -coordinate_pointer yac_basic_grid_get_field_coordinates( - struct yac_basic_grid * grid, struct interp_field field); -int const * yac_basic_grid_get_field_mask( - struct yac_basic_grid * grid, struct interp_field field); -int const * yac_basic_grid_get_core_mask( - struct yac_basic_grid * grid, enum yac_location location); -char const * yac_basic_grid_get_name(struct yac_basic_grid * grid); -struct basic_grid_data * yac_basic_grid_get_data(struct yac_basic_grid * grid); -struct yac_field_data * yac_basic_grid_get_field_data( - struct yac_basic_grid * grid, enum yac_location location); -size_t yac_basic_grid_get_data_size( - struct yac_basic_grid * grid, enum yac_location location); -size_t yac_basic_grid_add_coordinates( - struct yac_basic_grid * grid, enum yac_location location, - coordinate_pointer coordinates, size_t count); -size_t yac_basic_grid_add_coordinates_nocpy( - struct yac_basic_grid * grid, enum yac_location location, - coordinate_pointer coordinates); -size_t yac_basic_grid_add_mask( - struct yac_basic_grid * grid, enum yac_location location, - int const * mask, size_t count); -size_t yac_basic_grid_add_mask_nocpy( - struct yac_basic_grid * grid, enum yac_location location, - int const * mask); -void yac_basic_grid_delete(struct yac_basic_grid * grid); - -void yac_basic_grid_data_free(struct basic_grid_data grid); - -enum yac_location yac_str2loc(char const * location); -char const * yac_loc2str(enum yac_location location); -enum yac_location yac_get_location(int const location); - -struct yac_field_data yac_field_data_init(); -size_t yac_field_data_add_mask_nocpy( - struct yac_field_data * field_data, int const * mask); -size_t yac_field_data_add_coordinates_nocpy( - struct yac_field_data * field_data, coordinate_pointer coordinates); - -struct yac_field_data_set yac_field_data_set_init(); -size_t yac_field_data_set_add_mask( - struct yac_field_data_set * field_data_set, - enum yac_location location, int const * mask, size_t count); -size_t yac_field_data_set_add_coordinates( - struct yac_field_data_set * field_data_set, - enum yac_location location, coordinate_pointer coordinates, - size_t count); -size_t yac_field_data_set_add_mask_nocpy( - struct yac_field_data_set * field_data_set, - enum yac_location location, int const * mask); -size_t yac_field_data_set_add_coordinates_nocpy( - struct yac_field_data_set * field_data_set, - enum yac_location location, coordinate_pointer coordinates); -void yac_field_data_set_free(struct yac_field_data_set field_data_set); - -#endif // GRID_H - diff --git a/src/lib/yac/grid_cell.c b/src/lib/yac/grid_cell.c index e571c43256f38bf32c0097a1c3e27d2103982332..0f536d7fbef208f2d117bf116f32c1d4856d8dc3 100644 --- a/src/lib/yac/grid_cell.c +++ b/src/lib/yac/grid_cell.c @@ -1,58 +1,13 @@ -/** - * @file grid_cell.c - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * Thomas Jahns <jahns@dkrz.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * Thomas Jahns <jahns@dkrz.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * Thomas Jahns <jahns@dkrz.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #include <stdlib.h> #include <string.h> #include <stdio.h> #include "grid_cell.h" -#include "utils.h" +#include "utils_core.h" #include "ensure_array_size.h" #include "geometry.h" diff --git a/src/lib/yac/grid_cell.h b/src/lib/yac/grid_cell.h index d90aaa0dd24cb402f43f4c843f38acc5eb08376d..46e0980b1b8bceb9dd95682f9bb59a8cec3d2955 100644 --- a/src/lib/yac/grid_cell.h +++ b/src/lib/yac/grid_cell.h @@ -1,49 +1,6 @@ -/** - * @file grid_cell.h - * @brief Structs and interfaces to handle grid cells - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #include <stdio.h> diff --git a/src/lib/yac/intersection.c b/src/lib/yac/intersection.c index 63227accdd65c1d9da6f1005e7117720c207691b..d4478695848da2d4e9e78867d0a5d6c0879d088d 100644 --- a/src/lib/yac/intersection.c +++ b/src/lib/yac/intersection.c @@ -1,66 +1,16 @@ -/** - * @file intersection.c - * @brief Set of functions to determine the intersection between two edges - * - * very interesting literature: - * - http://geospatialmethods.org/spheres/GCIntersect.html - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #include <stdlib.h> #include <math.h> #include <stdio.h> -#include "yac_ld_interface.h" -#include "utils.h" +#include "utils_core.h" #include "geometry.h" // angle tolerance static double const tol = 1.0e-12; -#ifndef USE_MPF -static long double const tol_ld = 1.0e-12; -#endif enum { p_on_a = 1, @@ -86,94 +36,31 @@ enum { * @param[out] q second intersection point * @return -1 if the two circles are identical; 2 otherwise */ -#ifndef USE_MPF static int gcxgc( - long double const norm_vector_a[3], long double const norm_vector_b[3], + double const norm_vector_a[3], double const norm_vector_b[3], double p[3], double q[3]) { // compute p and q // p' = (a X b) X (c X d) // p = p' / length(p') // q = -p - long double temp_p[3] = - {norm_vector_a[1] * norm_vector_b[2] - norm_vector_a[2] * norm_vector_b[1], - norm_vector_a[2] * norm_vector_b[0] - norm_vector_a[0] * norm_vector_b[2], - norm_vector_a[0] * norm_vector_b[1] - norm_vector_a[1] * norm_vector_b[0]}; + double temp_p[3]; + crossproduct_kahan(norm_vector_a, norm_vector_b, temp_p); - long double sq_sin_plane_angle = + double sq_sin_plane_angle = temp_p[0] * temp_p[0] + temp_p[1] * temp_p[1] + temp_p[2] * temp_p[2]; // if both circles are on the same plane if (sq_sin_plane_angle <= yac_sq_angle_tol) return -1; - long double scale = 1.0 / sqrtl(sq_sin_plane_angle); - p[0] = (double)(temp_p[0] * scale); - p[1] = (double)(temp_p[1] * scale); - p[2] = (double)(temp_p[2] * scale); + double scale = 1.0 / sqrt(sq_sin_plane_angle); + p[0] = (temp_p[0] * scale); + p[1] = (temp_p[1] * scale); + p[2] = (temp_p[2] * scale); q[0] = -p[0], q[1] = -p[1], q[2] = -p[2]; return 2; } -#else -static int gcxgc( - mpf_t const norm_vector_a[3], mpf_t const norm_vector_b[3], - double p[3], double q[3]) { - - mpf_t temp_p[3]; - yac_mpf_init_vector(temp_p); - - mpf_mul(temp_p[0], norm_vector_a[1], norm_vector_b[2]); - mpf_mul(temp_p[1], norm_vector_a[2], norm_vector_b[0]); - mpf_mul(temp_p[2], norm_vector_a[0], norm_vector_b[1]); - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - - mpf_mul(buf, norm_vector_a[2], norm_vector_b[1]); - mpf_sub(temp_p[0], temp_p[0], buf); - mpf_mul(buf, norm_vector_a[0], norm_vector_b[2]); - mpf_sub(temp_p[1], temp_p[1], buf); - mpf_mul(buf, norm_vector_a[1], norm_vector_b[0]); - mpf_sub(temp_p[2], temp_p[2], buf); - - mpf_t sq_sin_plane_angle; - mpf_init2(sq_sin_plane_angle, YAC_MPF_PRECISION); - mpf_mul(sq_sin_plane_angle, temp_p[0], temp_p[0]); - mpf_mul(buf, temp_p[1], temp_p[1]); - mpf_add(sq_sin_plane_angle, sq_sin_plane_angle, buf); - mpf_mul(buf, temp_p[2], temp_p[2]); - mpf_add(sq_sin_plane_angle, sq_sin_plane_angle, buf); - - int ret; - - // if both circles are on the same plane - if (mpf_cmp_d(sq_sin_plane_angle, yac_sq_angle_tol) <= 0) { - ret = -1; - } else { - // reuse sq_sin_plane_angle to hold its square root - mpf_sqrt(sq_sin_plane_angle, sq_sin_plane_angle); - // reuse buf to hold the scale - mpf_ui_div(buf, 1, sq_sin_plane_angle); - // scale temp_p in place - mpf_mul(temp_p[0], temp_p[0], buf); - mpf_mul(temp_p[1], temp_p[1], buf); - mpf_mul(temp_p[2], temp_p[2], buf); - - p[0] = mpf_get_d(temp_p[0]); - p[1] = mpf_get_d(temp_p[1]); - p[2] = mpf_get_d(temp_p[2]); - q[0] = -p[0], q[1] = -p[1], q[2] = -p[2]; - ret = 2; - } - - yac_mpf_clear_vector(temp_p); - mpf_clear(buf); - mpf_clear(sq_sin_plane_angle); - return ret; -} -#endif - -#ifndef USE_MPF #if defined __INTEL_COMPILER #pragma intel optimization_level 0 @@ -182,20 +69,20 @@ static int gcxgc( #endif static int loncxlatc( - long double const gc_norm_vector[3], double const z, + double const gc_norm_vector[3], double const z, double p[3], double q[3]) { // based on gcxlatc with some optimisations for circles of longitude // square of z of lat circle - long double sq_z = (long double)(z * z); + double sq_z = z * z; - long double b = sqrt(MAX(1.0 - sq_z,0.0)); - long double b_n0 = b * gc_norm_vector[0]; - long double b_n1 = b * gc_norm_vector[1]; + double b = sqrt(MAX(1.0 - sq_z,0.0)); + double b_n0 = b * gc_norm_vector[0]; + double b_n1 = b * gc_norm_vector[1]; - p[0] = (double)(+ b_n1); - p[1] = (double)(- b_n0); + p[0] = b_n1; + p[1] = -b_n0; p[2] = z; q[0] = -p[0]; q[1] = -p[1]; @@ -204,66 +91,8 @@ static int loncxlatc( return 2; } -#if defined _CRAYC -#pragma _CRI opt -#endif - -#else -static int loncxlatc( - mpf_t const gc_norm_vector[3], double const z, - double p[3], double q[3]) { - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - // buf = z - mpf_set_d(buf, z); - // buf *= buf - mpf_mul(buf, buf, buf); - // buf = 1.0 / buf - mpf_ui_sub(buf, 1, buf); - - if (mpf_sgn(buf) > 0) { - mpf_sqrt(buf, buf); - - mpf_t b; - mpf_init2(b, YAC_MPF_PRECISION); - - mpf_mul(b, buf, gc_norm_vector[1]); - p[0] = mpf_get_d(b); - - mpf_mul(b, buf, gc_norm_vector[0]); - mpf_neg(b, b); - p[1] = mpf_get_d(b); - - p[2] = z; - q[0] = -p[0]; - q[1] = -p[1]; - q[2] = z; - - mpf_clear(b); - } else { - p[0] = 0.0; - p[1] = 0.0; - p[2] = z; - q[0] = 0.0; - q[1] = 0.0; - q[2] = z; - } - - mpf_clear(buf); - - return 2; -} -#endif - -#ifndef USE_MPF - -#if defined _CRAYC -#pragma _CRI noopt -#endif - static int gcxlatc( - long double const gc_norm_vector[3], double const z, + double const gc_norm_vector[3], double const z, double p[3], double q[3]) { /* How to compute intersection point(s) between great circle (given by its @@ -301,22 +130,22 @@ static int gcxlatc( if (fabsl(gc_norm_vector[2]) < yac_angle_low_tol) return loncxlatc(gc_norm_vector, z, p, q); - long double sq_n[3] = {gc_norm_vector[0] * gc_norm_vector[0], - gc_norm_vector[1] * gc_norm_vector[1], - gc_norm_vector[2] * gc_norm_vector[2]}; + double sq_n[3] = {gc_norm_vector[0] * gc_norm_vector[0], + gc_norm_vector[1] * gc_norm_vector[1], + gc_norm_vector[2] * gc_norm_vector[2]}; // square of highest z-value of great circle - long double max_sq_gc_z = sq_n[0] + sq_n[1]; + double max_sq_gc_z = sq_n[0] + sq_n[1]; // square of z of lat circle - long double sq_z = (long double)(z * z); + double sq_z = z * z; // if both circles are the equator -> identical circles if ((max_sq_gc_z < yac_sq_angle_tol) && (sq_z < yac_sq_angle_tol)) return -1; // determine number of intersections int num_intersections = - ((max_sq_gc_z > (sq_z - tol_ld)) - (max_sq_gc_z < (sq_z + tol_ld))) + 1; + ((max_sq_gc_z > (sq_z - tol)) - (max_sq_gc_z < (sq_z + tol))) + 1; switch (num_intersections) { @@ -327,10 +156,10 @@ static int gcxlatc( // ==> (b = 0) case (1): { - long double a = -(gc_norm_vector[2] * z) / max_sq_gc_z; + double a = -(gc_norm_vector[2] * z) / max_sq_gc_z; - p[0] = ((q[0] = (double)(gc_norm_vector[0] * a))); - p[1] = ((q[1] = (double)(gc_norm_vector[1] * a))); + p[0] = ((q[0] = gc_norm_vector[0] * a)); + p[1] = ((q[1] = gc_norm_vector[1] * a)); p[2] = z, q[2] = z; break; } @@ -338,18 +167,18 @@ static int gcxlatc( default: case (2): { - long double a = -(gc_norm_vector[2] * z) / max_sq_gc_z; - long double b = sqrt(max_sq_gc_z - sq_z)/max_sq_gc_z; - long double a_n0 = a * gc_norm_vector[0]; - long double a_n1 = a * gc_norm_vector[1]; - long double b_n0 = b * gc_norm_vector[0]; - long double b_n1 = b * gc_norm_vector[1]; + double a = -(gc_norm_vector[2] * z) / max_sq_gc_z; + double b = sqrt(max_sq_gc_z - sq_z)/max_sq_gc_z; + double a_n0 = a * gc_norm_vector[0]; + double a_n1 = a * gc_norm_vector[1]; + double b_n0 = b * gc_norm_vector[0]; + double b_n1 = b * gc_norm_vector[1]; - p[0] = (double)(a_n0 + b_n1); - p[1] = (double)(a_n1 - b_n0); + p[0] = a_n0 + b_n1; + p[1] = a_n1 - b_n0; p[2] = z; - q[0] = (double)(a_n0 - b_n1); - q[1] = (double)(a_n1 + b_n0); + q[0] = a_n0 - b_n1; + q[1] = a_n1 + b_n0; q[2] = z; break; } @@ -362,146 +191,11 @@ static int gcxlatc( #pragma _CRI opt #endif -#else -static int gcxlatc( - mpf_t const gc_norm_vector[3], double const z, - double p[3], double q[3]) { - - // if the great circle is a circle of longitude - if (mpf_cmp_d(gc_norm_vector[2], -yac_angle_low_tol) > 0 && - mpf_cmp_d(gc_norm_vector[2], yac_angle_low_tol) < 0) { - return loncxlatc(gc_norm_vector, z, p, q); - } - - mpf_t sq_n0, sq_n1; - mpf_init2(sq_n0, YAC_MPF_PRECISION); - mpf_init2(sq_n1, YAC_MPF_PRECISION); - mpf_mul(sq_n0, gc_norm_vector[0], gc_norm_vector[0]); - mpf_mul(sq_n1, gc_norm_vector[1], gc_norm_vector[1]); - - // square of highest z-value of great circle - mpf_t max_sq_gc_z; - mpf_init2(max_sq_gc_z, YAC_MPF_PRECISION); - mpf_add(max_sq_gc_z, sq_n0, sq_n1); - - // square of z of lat circle - mpf_t sq_z; - mpf_init2(sq_z, YAC_MPF_PRECISION); - mpf_set_d(sq_z, z); - mpf_mul(sq_z, sq_z, sq_z); - - int num_intersections; - // if both circles are the equator -> identical circles - if (mpf_cmp_d(max_sq_gc_z, yac_sq_angle_tol) < 0 && - mpf_cmp_d(sq_z, yac_sq_angle_tol) < 0) { - num_intersections = -1; - } else { - // determine number of intersections - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - mpf_sub(buf, max_sq_gc_z, sq_z); - - num_intersections = - ((mpf_cmp_d(buf, -tol) > 0) - (mpf_cmp_d(buf, tol) < 0)) + 1; - - switch (num_intersections) { - - // if no intersection is possible - case (0): break; - - // the great circles touches the circle of latitude in a single point - // ==> (b = 0) - case (1): { - mpf_t a; - mpf_init2(a, YAC_MPF_PRECISION); - mpf_set_d(a, z); - mpf_mul(a, a, gc_norm_vector[2]); - mpf_div(a, a, max_sq_gc_z); - mpf_neg(a, a); - - mpf_mul(buf, gc_norm_vector[0], a); - p[0] = ((q[0] = mpf_get_d(buf))); - - mpf_mul(buf, gc_norm_vector[1], a); - p[1] = ((q[1] = mpf_get_d(buf))); - p[2] = z, q[2] = z; - - mpf_clear(a); - break; - } - - default: - case (2): { - mpf_t a; - mpf_init2(a, YAC_MPF_PRECISION); - mpf_set_d(a, z); - mpf_mul(a, a, gc_norm_vector[2]); - mpf_div(a, a, max_sq_gc_z); - mpf_neg(a, a); - - mpf_t b; - mpf_init2(b, YAC_MPF_PRECISION); - mpf_sub(b, max_sq_gc_z, sq_z); - mpf_sqrt(b, b); - mpf_div(b, b, max_sq_gc_z); - - mpf_t a_n0, a_n1, b_n0, b_n1; - - mpf_init2(a_n0, YAC_MPF_PRECISION); - mpf_mul(a_n0, a, gc_norm_vector[0]); - - mpf_init2(a_n1, YAC_MPF_PRECISION); - mpf_mul(a_n1, a, gc_norm_vector[1]); - - mpf_init2(b_n0, YAC_MPF_PRECISION); - mpf_mul(b_n0, b, gc_norm_vector[0]); - - mpf_init2(b_n1, YAC_MPF_PRECISION); - mpf_mul(b_n1, b, gc_norm_vector[1]); - - mpf_add(buf, a_n0, b_n1); - p[0] = mpf_get_d(buf); - - mpf_sub(buf, a_n1, b_n0); - p[1] = mpf_get_d(buf); - - mpf_sub(buf, a_n0, b_n1); - q[0] = mpf_get_d(buf); - - mpf_add(buf, a_n1, b_n0); - q[1] = mpf_get_d(buf); - - p[2] = z; - q[2] = z; - - mpf_clear(a); - mpf_clear(b); - mpf_clear(a_n0); - mpf_clear(a_n1); - mpf_clear(b_n0); - mpf_clear(b_n1); - break; - } - } - - mpf_clear(buf); - } - - mpf_clear(sq_n0); - mpf_clear(sq_n1); - mpf_clear(max_sq_gc_z); - mpf_clear(sq_z); - - return num_intersections; -} -#endif - -#ifndef USE_MPF static int loncxlonc( - long double const norm_vector_a[3], long double const norm_vector_b[3], + double const norm_vector_a[3], double const norm_vector_b[3], double p[3], double q[3]) { - long double sq_plane_diff = + double sq_plane_diff = MIN((norm_vector_a[0] - norm_vector_b[0]) * (norm_vector_a[0] - norm_vector_b[0]) + (norm_vector_a[1] - norm_vector_b[1]) * @@ -520,59 +214,23 @@ static int loncxlonc( return 2; } -#else -static int loncxlonc( - mpf_t const norm_vector_a[3], mpf_t const norm_vector_b[3], - double p[3], double q[3]) { - - mpf_t sq_plane_diff; - mpf_init2(sq_plane_diff, YAC_MPF_PRECISION); - mpf_sub(sq_plane_diff, norm_vector_a[0], norm_vector_b[0]); - mpf_mul(sq_plane_diff, sq_plane_diff, sq_plane_diff); - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - mpf_sub(buf, norm_vector_a[1], norm_vector_b[1]); - mpf_mul(buf, buf, buf); - - mpf_add(sq_plane_diff, sq_plane_diff, buf); - - int ret; - - // if both circles are on the same circle of longitude - if (mpf_cmp_d(sq_plane_diff, yac_sq_angle_tol) < 0) { - ret = -1; - } else { - mpf_set_d(buf, 4.0); - mpf_sub(buf, buf, sq_plane_diff); - if (mpf_cmp_d(buf, yac_sq_angle_tol) < 0) { - ret = -1; - } else { - // the intersection points of the two circles of longitude are the poles - p[0] = 0, p[1] = 0; p[2] = 1; - q[0] = 0, q[1] = 0; q[2] = -1; - ret = 2; - } - } - - mpf_clear(sq_plane_diff); - mpf_clear(buf); - return ret; -} -#endif /** \example test_pxgc.c * This example contains some tests for the pxgc routine */ -#ifndef USE_MPF static int pxgc( - double const vec[3], long double const norm_vector[3], double p[3], double q[3]) { + double const vec[3], double const norm_vector[3], double p[3], double q[3]) { // compute the angle between the point vector and the norm vector - long double dot = (long double)(vec[0]) * norm_vector[0] + - (long double)(vec[1]) * norm_vector[1] + - (long double)(vec[2]) * norm_vector[2]; + // we use kahan summation to increase precision + double dot = vec[0] * norm_vector[0]; + double err = fma(vec[0], norm_vector[0], -dot); + dot = fma(vec[1], norm_vector[1], dot); + err += fma(vec[1], norm_vector[1], -vec[1]*norm_vector[1]); + dot = fma(vec[2], norm_vector[2], dot); + err += fma(vec[2], norm_vector[2], -vec[2]*norm_vector[2]); + dot += err; // if the point is not on the plane if (fabsl(dot) > yac_angle_tol) return 0; @@ -582,43 +240,6 @@ static int pxgc( q[2] = -((p[2] = vec[2])); return 1; } -#else -static int pxgc( - double const vec[3], mpf_t const norm_vector[3], double p[3], double q[3]) { - - // compute the angle between the point vector and the norm vector - mpf_t dot; - mpf_init2(dot, YAC_MPF_PRECISION); - mpf_set_d(dot, vec[0]); - mpf_mul(dot, dot, norm_vector[0]); - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - mpf_set_d(buf, vec[1]); - mpf_mul(buf, buf, norm_vector[1]); - mpf_add(dot, dot, buf); - mpf_set_d(buf, vec[2]); - mpf_mul(buf, buf, norm_vector[2]); - mpf_add(dot, dot, buf); - - int ret; - - // if the point is not on the plane - if (mpf_cmp_d(dot, -yac_angle_tol) < 0 || - mpf_cmp_d(dot, yac_angle_tol) > 0) { - ret = 0; - } else { - q[0] = -((p[0] = vec[0])); - q[1] = -((p[1] = vec[1])); - q[2] = -((p[2] = vec[2])); - ret = 1; - } - - mpf_clear(dot); - mpf_clear(buf); - return ret; -} -#endif static int pxlatc( double const vec[3], double z, double p[3], double q[3]) { @@ -875,66 +496,20 @@ static int yac_check_pq_gcxgc( (vector_is_between(c, d, q, sq_len_diff_cd) << 3); } -#ifndef USE_MPF -static void compute_norm_vector_ld( - double const a[3], double const b[3], long double norm_vector[3]) { - - long double const a_[3] = {a[0], a[1], a[2]}; - long double const b_[3] = {b[0], b[1], b[2]}; +static void compute_norm_vector( + double const a[3], double const b[3], double norm_vector[3]) { - norm_vector[0] = a_[1] * b_[2] - a_[2] * b_[1]; - norm_vector[1] = a_[2] * b_[0] - a_[0] * b_[2]; - norm_vector[2] = a_[0] * b_[1] - a_[1] * b_[0]; + norm_vector[0] = a[1] * b[2] - a[2] * b[1]; + norm_vector[1] = a[2] * b[0] - a[0] * b[2]; + norm_vector[2] = a[0] * b[1] - a[1] * b[0]; - long double scale = 1.0 / sqrtl(norm_vector[0] * norm_vector[0] + - norm_vector[1] * norm_vector[1] + - norm_vector[2] * norm_vector[2]); + double scale = 1.0 / sqrt(norm_vector[0] * norm_vector[0] + + norm_vector[1] * norm_vector[1] + + norm_vector[2] * norm_vector[2]); norm_vector[0] *= scale; norm_vector[1] *= scale; norm_vector[2] *= scale; } -#else -static void compute_norm_vector_ld( - double const a[3], double const b[3], mpf_t norm_vector[3]) { - mpf_t a_[3], b_[3]; - yac_mpf_set_vector_d(a_, a); - yac_mpf_set_vector_d(b_, b); - - mpf_mul(norm_vector[0], a_[1], b_[2]); - mpf_mul(norm_vector[1], a_[2], b_[0]); - mpf_mul(norm_vector[2], a_[0], b_[1]); - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - - mpf_mul(buf, a_[2], b_[1]); - mpf_sub(norm_vector[0], norm_vector[0], buf); - mpf_mul(buf, a_[0], b_[2]); - mpf_sub(norm_vector[1], norm_vector[1], buf); - mpf_mul(buf, a_[1], b_[0]); - mpf_sub(norm_vector[2], norm_vector[2], buf); - - mpf_t scale; - mpf_init2(scale, YAC_MPF_PRECISION); - - mpf_mul(scale, norm_vector[0], norm_vector[0]); - mpf_mul(buf, norm_vector[1], norm_vector[1]); - mpf_add(scale, scale, buf); - mpf_mul(buf, norm_vector[2], norm_vector[2]); - mpf_add(scale, scale, buf); - mpf_sqrt(scale, scale); - mpf_ui_div(scale, 1, scale); - - mpf_mul(norm_vector[0], norm_vector[0], scale); - mpf_mul(norm_vector[1], norm_vector[1], scale); - mpf_mul(norm_vector[2], norm_vector[2], scale); - - yac_mpf_clear_vector(a_); - yac_mpf_clear_vector(b_); - mpf_clear(buf); - mpf_clear(scale); -} -#endif /** \example test_gcxgc.c * This contains examples on how to use \ref yac_gcxgc_vec @@ -957,15 +532,14 @@ static void compute_norm_vector_ld( * 5th bit will be set if both great circles are identically * @remarks both edges need to have length of at least yac_angle_tol */ -#ifndef USE_MPF static int yac_gcxgc_vec( double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3]) { - long double norm_vector_ab[3], norm_vector_cd[3]; + double norm_vector_ab[3], norm_vector_cd[3]; - compute_norm_vector_ld(a, b, norm_vector_ab); - compute_norm_vector_ld(c, d, norm_vector_cd); + compute_norm_vector(a, b, norm_vector_ab); + compute_norm_vector(c, d, norm_vector_cd); switch (gcxgc(norm_vector_ab, norm_vector_cd, p, q)) { default: @@ -975,36 +549,6 @@ static int yac_gcxgc_vec( return yac_identical_gcxgc_vec(a, b, c, d, p, q); }; } -#else -static int yac_gcxgc_vec( - double const a[3], double const b[3], double const c[3], double const d[3], - double p[3], double q[3]) { - - mpf_t norm_vector_ab[3], norm_vector_cd[3]; - yac_mpf_init_vector(norm_vector_ab); - yac_mpf_init_vector(norm_vector_cd); - - compute_norm_vector_ld(a, b, norm_vector_ab); - compute_norm_vector_ld(c, d, norm_vector_cd); - - int ret; - - switch (gcxgc(norm_vector_ab, norm_vector_cd, p, q)) { - default: - case(2): - ret = yac_check_pq_gcxgc(a, b, c, d, p, q); - break; - case(-1): - ret = yac_identical_gcxgc_vec(a, b, c, d, p, q); - break; - }; - - yac_mpf_clear_vector(norm_vector_ab); - yac_mpf_clear_vector(norm_vector_cd); - - return ret; -} -#endif /** \example test_latcxlatc.c * This contains examples on \ref yac_latcxlatc_vec @@ -1039,59 +583,18 @@ static int yac_latcxlatc_vec( (vector_is_between_lat(a, b, d) << 3)); } -#ifndef USE_MPF -static void compute_lon_norm_vector_ld( - double const a[3], double const b[3], long double norm_vector[3]) { - - long double const a_[3] = {a[0], a[1], a[2]}; - long double const b_[3] = {b[0], b[1], b[2]}; +static void compute_lon_norm_vector( + double const a[3], double const b[3], double norm_vector[3]) { - norm_vector[0] = a_[1] * b_[2] - a_[2] * b_[1]; - norm_vector[1] = a_[2] * b_[0] - a_[0] * b_[2]; + norm_vector[0] = a[1] * b[2] - a[2] * b[1]; + norm_vector[1] = a[2] * b[0] - a[0] * b[2]; norm_vector[2] = 0.0; - long double scale = 1.0 / sqrtl(norm_vector[0] * norm_vector[0] + - norm_vector[1] * norm_vector[1]); + double scale = 1.0 / sqrt(norm_vector[0] * norm_vector[0] + + norm_vector[1] * norm_vector[1]); norm_vector[0] *= scale; norm_vector[1] *= scale; } -#else -static void compute_lon_norm_vector_ld( - double const a[3], double const b[3], mpf_t norm_vector[3]) { - - mpf_t a_[3], b_[3]; - yac_mpf_set_vector_d(a_, a); - yac_mpf_set_vector_d(b_, b); - - mpf_mul(norm_vector[0], a_[1], b_[2]); - mpf_mul(norm_vector[1], a_[2], b_[0]); - - mpf_t buf; - mpf_init2(buf, YAC_MPF_PRECISION); - - mpf_mul(buf, a_[2], b_[1]); - mpf_sub(norm_vector[0], norm_vector[0], buf); - mpf_mul(buf, a_[0], b_[2]); - mpf_sub(norm_vector[1], norm_vector[1], buf); - - mpf_t scale; - mpf_init2(scale, YAC_MPF_PRECISION); - - mpf_mul(scale, norm_vector[0], norm_vector[0]); - mpf_mul(buf, norm_vector[1], norm_vector[1]); - mpf_add(scale, scale, buf); - mpf_sqrt(scale, scale); - mpf_ui_div(scale, 1, scale); - - mpf_mul(norm_vector[0], norm_vector[0], scale); - mpf_mul(norm_vector[1], norm_vector[1], scale); - - yac_mpf_clear_vector(a_); - yac_mpf_clear_vector(b_); - mpf_clear(buf); - mpf_clear(scale); -} -#endif /** \example test_loncxlonc.c * This contains examples on \ref yac_loncxlonc_vec @@ -1110,14 +613,13 @@ static void compute_lon_norm_vector_ld( * - 5th bit will be set if both edges are on the same circle of longitude * @remarks both edges need to have length of at least yac_angle_tol **/ -#ifndef USE_MPF static int yac_loncxlonc_vec( double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3]) { - long double norm_vector_ab[3], norm_vector_cd[3]; - compute_lon_norm_vector_ld(a, b, norm_vector_ab); - compute_lon_norm_vector_ld(c, d, norm_vector_cd); + double norm_vector_ab[3], norm_vector_cd[3]; + compute_lon_norm_vector(a, b, norm_vector_ab); + compute_lon_norm_vector(c, d, norm_vector_cd); switch(loncxlonc(norm_vector_ab, norm_vector_cd, p, q)) { @@ -1128,36 +630,6 @@ static int yac_loncxlonc_vec( return yac_identical_gcxgc_vec(a, b, c, d, p, q); }; } -#else -static int yac_loncxlonc_vec( - double const a[3], double const b[3], double const c[3], double const d[3], - double p[3], double q[3]) { - - mpf_t norm_vector_ab[3], norm_vector_cd[3]; - yac_mpf_init_vector(norm_vector_ab); - yac_mpf_init_vector(norm_vector_cd); - - compute_lon_norm_vector_ld(a, b, norm_vector_ab); - compute_lon_norm_vector_ld(c, d, norm_vector_cd); - - int ret; - - switch(loncxlonc(norm_vector_ab, norm_vector_cd, p, q)) { - - default: - case(2): - ret = yac_check_pq_gcxgc(a, b, c, d, p, q); - break; - case(-1): - ret = yac_identical_gcxgc_vec(a, b, c, d, p, q); - break; - }; - - yac_mpf_clear_vector(norm_vector_ab); - yac_mpf_clear_vector(norm_vector_cd); - return ret; -} -#endif // determines the return value for the provided intersection points p and q static int yac_check_pq_gcxlatc( @@ -1191,35 +663,18 @@ static int yac_check_pq_gcxlatc( * - 4th bit will be set if q is between c and d * @remarks both edges need to have length of at least yac_angle_tol **/ -#ifndef USE_MPF static int yac_loncxlatc_vec ( double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3]) { - long double norm_vector_ab[3]; - compute_lon_norm_vector_ld(a, b, norm_vector_ab); + double norm_vector_ab[3]; + compute_lon_norm_vector(a, b, norm_vector_ab); int num_intersections = loncxlatc(norm_vector_ab, c[2], p, q); YAC_ASSERT(num_intersections == 2, "ERROR(yac_loncxlatc_vec): internal error") return yac_check_pq_gcxlatc(a, b, c, d, p, q); } -#else -static int yac_loncxlatc_vec ( - double const a[3], double const b[3], double const c[3], double const d[3], - double p[3], double q[3]) { - - mpf_t norm_vector_ab[3]; - yac_mpf_init_vector(norm_vector_ab); - compute_lon_norm_vector_ld(a, b, norm_vector_ab); - - int num_intersections = loncxlatc(norm_vector_ab, c[2], p, q); - YAC_ASSERT(num_intersections == 2, "ERROR(yac_loncxlatc_vec): internal error") - - yac_mpf_clear_vector(norm_vector_ab); - return yac_check_pq_gcxlatc(a, b, c, d, p, q); -} -#endif /** \example test_gcxlatc.c * This contains examples on gcxlatc_vec. @@ -1243,7 +698,6 @@ static int yac_loncxlatc_vec ( * p and q will be identically, but only the p bits will be set * @remarks both edges need to have length of at least yac_angle_tol **/ -#ifndef USE_MPF #if defined __INTEL_COMPILER #pragma intel optimization_level 0 @@ -1255,8 +709,8 @@ static int yac_gcxlatc_vec( double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3]) { - long double norm_vector_ab[3]; - compute_norm_vector_ld(a, b, norm_vector_ab); + double norm_vector_ab[3]; + compute_norm_vector(a, b, norm_vector_ab); int num_intersections = gcxlatc(norm_vector_ab, c[2], p, q); @@ -1276,53 +730,19 @@ static int yac_gcxlatc_vec( #pragma _CRI opt #endif -#else -static int yac_gcxlatc_vec( - double const a[3], double const b[3], double const c[3], double const d[3], - double p[3], double q[3]) { - - mpf_t norm_vector_ab[3]; - yac_mpf_init_vector(norm_vector_ab); - - compute_norm_vector_ld(a, b, norm_vector_ab); - - int num_intersections = gcxlatc(norm_vector_ab, c[2], p, q); - - int ret; - - switch (num_intersections) { - default: - case(2): - case(1): - ret = yac_check_pq_gcxlatc(a, b, c, d, p, q); - break; - case(0): - ret = -1; - break; - case(-1): - ret = yac_latcxlatc_vec(a, b, c, d, p, q); - break; - } - - yac_mpf_clear_vector(norm_vector_ab); - return ret; -} -#endif - static int yac_pxp_vec( double const a[3], double const b[3], double p[3], double q[3]) { return (pxp(a, b, p, q))?(p_on_a + p_on_b):-1; } -#ifndef USE_MPF static int yac_pxgc_vec( double const point[3], double const a[3], double const b[3], double p[3], double q[3]) { // compute norm vector for the plane of ab - long double norm_ab[3]; - compute_norm_vector_ld(a, b, norm_ab); + double norm_ab[3]; + compute_norm_vector(a, b, norm_ab); // if the point is on the plane of ab if (pxgc(point, norm_ab, p, q)) { @@ -1339,35 +759,6 @@ static int yac_pxgc_vec( return -1; } } -#else -static int yac_pxgc_vec( - double const point[3], double const a[3], double const b[3], - double p[3], double q[3]) { - - // compute norm vector for the plane of ab - mpf_t norm_ab[3]; - yac_mpf_init_vector(norm_ab); - compute_norm_vector_ld(a, b, norm_ab); - - int ret = pxgc(point, norm_ab, p, q); - yac_mpf_clear_vector(norm_ab); - - // if the point is on the plane of ab - if (ret) { - - int ret_value = p_on_a; - double sq_len_diff_ab = sq_len_diff_vec(a, b); - - if (vector_is_between(a, b, p, sq_len_diff_ab)) ret_value |= p_on_b; - else if (vector_is_between(a, b, q, sq_len_diff_ab)) ret_value |= q_on_b; - - return ret_value; - - } else { - return -1; - } -} -#endif static int yac_pxlat_vec( double const point[3], double const a[3], double const b[3], diff --git a/src/lib/yac/interval_tree.c b/src/lib/yac/interval_tree.c index c42480b9aee3a1874e3add3f72b1863cf776d698..987a9c154026e3480d5125e46b1c11ff0f8df723 100644 --- a/src/lib/yac/interval_tree.c +++ b/src/lib/yac/interval_tree.c @@ -1,54 +1,12 @@ -/** - * @file interval_tree.c - * - * @copyright Copyright (C) 2014 Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #include <stdlib.h> #include "ensure_array_size.h" #include "interval_tree.h" -#include "utils.h" +#include "utils_core.h" static int iv_compar(struct interval_node *a, struct interval_node *b) diff --git a/src/lib/yac/interval_tree.h b/src/lib/yac/interval_tree.h index d2f4a5605f8e7d69d1a8d0c95069088acd5704fc..8092e590e8d75a23a1e194a852e652667eefed89 100644 --- a/src/lib/yac/interval_tree.h +++ b/src/lib/yac/interval_tree.h @@ -1,48 +1,6 @@ -/** - * @file interval_tree.h - * - * @copyright Copyright (C) 2014 Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause /** \example test_interval_tree.c * This contains a test of the interval_tree. diff --git a/src/lib/yac/location.h b/src/lib/yac/location.h new file mode 100644 index 0000000000000000000000000000000000000000..b4556a39dd5edcee68ec4ff4e5b1cd8045a0ed4f --- /dev/null +++ b/src/lib/yac/location.h @@ -0,0 +1,23 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef LOCATION_H +#define LOCATION_H + +#define YAC_MAX_LOC_STR_LEN 10 + +enum yac_location { + + YAC_LOC_CELL = 0, + YAC_LOC_CORNER = 1, + YAC_LOC_EDGE = 2, + YAC_LOC_UNDEFINED = 3, +}; + +enum yac_location yac_str2loc(char const * location); +char const * yac_loc2str(enum yac_location location); +enum yac_location yac_get_location(int const location); + +#endif // LOCATION_H + diff --git a/src/lib/yac/sphere_part.c b/src/lib/yac/sphere_part.c index e42770e14dd8c31cffb5bde6e92d6d37bff084b1..bad6c17ad08c33756f5a6bac37dd9a464ebd1c3c 100644 --- a/src/lib/yac/sphere_part.c +++ b/src/lib/yac/sphere_part.c @@ -1,48 +1,6 @@ -/** - * @file sphere_part.c - * - * @copyright Copyright (C) 2014 Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #ifdef HAVE_CONFIG_H // Get the definition of the 'restrict' keyword. @@ -58,9 +16,9 @@ #include "sphere_part.h" #include "geometry.h" -#include "grid.h" +#include "basic_grid.h" #include "interval_tree.h" -#include "utils.h" +#include "utils_core.h" #include "ensure_array_size.h" union I_list { @@ -202,7 +160,7 @@ static inline void compute_gc_norm_vector( balance_point[2] = prev_gc_norm_vector[1]; } - crossproduct_ld( + crossproduct_kahan( balance_point, prev_gc_norm_vector, gc_norm_vector); if ((fabs(gc_norm_vector[0]) > 1e-9) || @@ -401,9 +359,9 @@ static void partition_data ( // project the base vector of the current bounding circle onto the // current partitioning great circle - crossproduct_ld(parent_node->gc_norm_vector, + crossproduct_kahan(parent_node->gc_norm_vector, curr_bnd_circle.base_vector, GCp); - crossproduct_ld(GCp, parent_node->gc_norm_vector, bVp); + crossproduct_kahan(GCp, parent_node->gc_norm_vector, bVp); YAC_ASSERT( (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) || (fabs(bVp[2]) > 1e-9), @@ -626,7 +584,7 @@ static inline int compare_points_int32_coord( static struct point_id_xyz * get_unique_points( - size_t * num_points, coordinate_pointer coordinates_xyz, + size_t * num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const * ids, int const * mask) { struct point_id_xyz_int32 * points_int32 = @@ -699,7 +657,8 @@ static struct point_id_xyz * } struct point_sphere_part_search * yac_point_sphere_part_search_new ( - size_t num_points, coordinate_pointer coordinates_xyz, yac_int const * ids) { + size_t num_points, yac_const_coordinate_pointer coordinates_xyz, + yac_int const * ids) { if (num_points == 0) return NULL; @@ -724,7 +683,7 @@ struct point_sphere_part_search * yac_point_sphere_part_search_new ( } struct point_sphere_part_search * yac_point_sphere_part_search_mask_new ( - size_t num_points, coordinate_pointer coordinates_xyz, + size_t num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const * ids, int const * mask) { if (num_points == 0) return NULL; @@ -778,8 +737,8 @@ static void search_bnd_circle_I_node( // project the base vector of the current bounding circle onto the // current great circle - crossproduct_ld(node->gc_norm_vector, bnd_circle.base_vector, GCp); - crossproduct_ld(GCp, node->gc_norm_vector, bVp); + crossproduct_kahan(node->gc_norm_vector, bnd_circle.base_vector, GCp); + crossproduct_kahan(GCp, node->gc_norm_vector, bVp); YAC_ASSERT( (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) || (fabs(bVp[2]) > 1e-9), "ERROR(search_bnd_circle_I_node): " @@ -1815,8 +1774,8 @@ static void search_point(struct sphere_part_node * node, // project the point onto the current great circle double GCp[3], bVp[3]; - crossproduct_ld(node->gc_norm_vector, point, GCp); - crossproduct_ld(GCp, node->gc_norm_vector, bVp); + crossproduct_kahan(node->gc_norm_vector, point, GCp); + crossproduct_kahan(GCp, node->gc_norm_vector, bVp); struct interval search_interval; // if the projected point does not coincide with the norm vector of @@ -1862,7 +1821,7 @@ static void search_point(struct sphere_part_node * node, } void yac_bnd_sphere_part_search_do_point_search( - struct bnd_sphere_part_search * search, coordinate_pointer coordinates_xyz, + struct bnd_sphere_part_search * search, yac_coordinate_pointer coordinates_xyz, size_t count, size_t ** cells, size_t * num_cells_per_coordinate) { struct sphere_part_node * base_node = &(search->base_node); diff --git a/src/lib/yac/sphere_part.h b/src/lib/yac/sphere_part.h index 9c320e7be6c20baab4eb89e44d2ee3739787eb8d..a4b1f8a4fb879122d54e2bb9adbc23751df876a5 100644 --- a/src/lib/yac/sphere_part.h +++ b/src/lib/yac/sphere_part.h @@ -1,47 +1,6 @@ -/** - * @file sphere_part.h - * - * @copyright Copyright (C) 2014 Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Thomas Jahns <jahns@dkrz.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause #ifndef SPHERE_PART_H #define SPHERE_PART_H @@ -105,7 +64,7 @@ * - returns list of matching polygons */ -#include "grid.h" +#include "basic_grid.h" #include "geometry.h" /** \example test_bnd_sphere_part.c @@ -115,10 +74,11 @@ struct point_sphere_part_search; struct point_sphere_part_search * yac_point_sphere_part_search_new ( - size_t num_points, coordinate_pointer coordinates_xyz, yac_int const * ids); + size_t num_points, yac_const_coordinate_pointer coordinates_xyz, + yac_int const * ids); struct point_sphere_part_search * yac_point_sphere_part_search_mask_new ( - size_t num_points, coordinate_pointer coordinates_xyz, + size_t num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const * ids, int const * mask); void yac_delete_point_sphere_part_search( @@ -165,7 +125,7 @@ struct bnd_sphere_part_search * yac_bnd_sphere_part_search_new( struct bounding_circle * circles, size_t num_circles); void yac_bnd_sphere_part_search_delete(struct bnd_sphere_part_search * search); void yac_bnd_sphere_part_search_do_point_search( - struct bnd_sphere_part_search * search, coordinate_pointer coordinates_xyz, + struct bnd_sphere_part_search * search, yac_coordinate_pointer coordinates_xyz, size_t count, size_t ** cells, size_t * num_cells_per_coordinate); void yac_bnd_sphere_part_search_do_bnd_circle_search( struct bnd_sphere_part_search * search, struct bounding_circle * bnd_circles, diff --git a/src/lib/yac/utils.c b/src/lib/yac/utils.c deleted file mode 100644 index 484073beb41a1ff6ad7fc6ad1dfe0e875ce6d603..0000000000000000000000000000000000000000 --- a/src/lib/yac/utils.c +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @file utils.c - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> - -#include "utils.h" - -void yac_internal_abort_message( - const char * text, const char * file, int line) { - - fprintf(stderr, "%s \n", text); - fprintf(stderr, "Aborting in file %s, line %i ...\n", file, line ); - exit(EXIT_FAILURE); -} - -void yac_abort_message ( char * text, char * file, int line ) { - yac_internal_abort_message ( text, file, line ); -} - -int yac_file_exists(const char * filename) { - struct stat buffer; - return !stat(filename,&buffer); -} - -char const * yac_name_type_pair_get_name( - struct yac_name_type_pair const * pairs, size_t count, int type) { - - char const * name = NULL; - for (size_t i = 0; (i < count) && (name == NULL); ++i) - if (pairs[i].type == type) name = pairs[i].name; - return name; -} - -int yac_name_type_pair_get_type( - struct yac_name_type_pair const * pairs, size_t count, char const * name) { - - int type = INT_MAX; - if (name != NULL) - for (size_t i = 0; (i < count) && (type == INT_MAX); ++i) - if (!strcmp(pairs[i].name, name)) type = pairs[i].type; - return type; -} diff --git a/src/lib/yac/utils_common.h b/src/lib/yac/utils_common.h new file mode 100644 index 0000000000000000000000000000000000000000..94e9f2232e280d0b241418effed4f49c30e20d1f --- /dev/null +++ b/src/lib/yac/utils_common.h @@ -0,0 +1,95 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef UTILS_COMMON_H +#define UTILS_COMMON_H + +#include <stdlib.h> +#ifdef YAC_FOR_CDO +#include <stdint.h> // uint64_t +#include <limits.h> // SIZE_MAX +#define UNUSED(x) (void)(x) +#define die(msg) abort() +#define xmalloc(size) malloc(size) +#define xrealloc(ptr,size) realloc(ptr,size) +#define xcalloc(nmemb,size) calloc(nmemb,size) +#else +#include "ppm/ppm_xfuncs.h" +#include "ppm/core.h" +#endif +#include "yac_types.h" + +int yac_file_exists(const char * filename); + +/** + * remove duplicated entries from a list of integers + * @param[in,out] array array containing a sorted (ascending) list of integers + * @param[in,out] n number of entries in array + */ +static inline void yac_remove_duplicates_int(int * array, size_t * n) { + + size_t const N = *n; + size_t pos = 0; + + if (N == 0) return; + + int prev = array[0]; + + for (size_t i = 1; i < N; ++i) { + + if (array[i] == prev) continue; + + prev = array[i]; + ++pos; + + if (pos != i) array[pos] = array[i]; + } + + *n = pos + 1; +} + +struct yac_name_type_pair { + const char * name; + int type; +}; + +char const * yac_name_type_pair_get_name( + struct yac_name_type_pair const * pairs, size_t count, int type); +int yac_name_type_pair_get_type( + struct yac_name_type_pair const * pairs, size_t count, char const * name); + +void yac_qsort_index( + void * a, size_t count, size_t size, + int (*compare)(void const *, void const *), size_t * idx); + +/* ======================================================================= + Macros + ======================================================================= */ + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define YAC_ASSERT(exp, msg) \ + {if(!((exp))) die(((msg)));} + +#define YAC_ASSERT_F(exp, format, ...) \ + { \ + if(!((exp))) { \ + char msg_buffer[1024]; \ + int ret = snprintf( \ + msg_buffer, sizeof(msg_buffer), ((format)), __VA_ARGS__); \ + if ((ret >= 0) && ((size_t)ret < sizeof(msg_buffer))) \ + die(((msg_buffer))); \ + else \ + die("an error occured, but error message could not be generated"); \ + } \ + } + +#endif // UTILS_H + diff --git a/src/lib/yac/utils_core.c b/src/lib/yac/utils_core.c new file mode 100644 index 0000000000000000000000000000000000000000..0076c1478bd2bb3e0b71cf291d6173e1c655e99d --- /dev/null +++ b/src/lib/yac/utils_core.c @@ -0,0 +1,34 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> + +#include "utils_core.h" + +int yac_file_exists(const char * filename) { + struct stat buffer; + return !stat(filename,&buffer); +} + +char const * yac_name_type_pair_get_name( + struct yac_name_type_pair const * pairs, size_t count, int type) { + + char const * name = NULL; + for (size_t i = 0; (i < count) && (name == NULL); ++i) + if (pairs[i].type == type) name = pairs[i].name; + return name; +} + +int yac_name_type_pair_get_type( + struct yac_name_type_pair const * pairs, size_t count, char const * name) { + + int type = INT_MAX; + if (name != NULL) + for (size_t i = 0; (i < count) && (type == INT_MAX); ++i) + if (!strcmp(pairs[i].name, name)) type = pairs[i].type; + return type; +} diff --git a/src/lib/yac/utils.h b/src/lib/yac/utils_core.h similarity index 51% rename from src/lib/yac/utils.h rename to src/lib/yac/utils_core.h index 7feca8723b33a856bd0a282a808ab9f2bcd09632..b4879b120ff49fe38bebbda02f30b3847cfc893e 100644 --- a/src/lib/yac/utils.h +++ b/src/lib/yac/utils_core.h @@ -1,115 +1,16 @@ -/** - * @file utils.h - * @brief Utlity functions - * - * Small general utility functions: - * - pointer-id conversion - * - hash - * - sorting - * - * @copyright Copyright (C) 2013 Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * - * @version 1.0 - * @author Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - */ -/* - * Keywords: - * Maintainer: Moritz Hanke <hanke@dkrz.de> - * Rene Redler <rene.redler@mpimet.mpg.de> - * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/ - * - * This file is part of YAC. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the DKRZ GmbH nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause -#ifndef UTILS_H -#define UTILS_H - -#include <stdlib.h> -#ifdef YAC_FOR_CDO -#include <stdint.h> // uint64_t -#include <limits.h> // SIZE_MAX -#define UNUSED(x) (void)(x) -#define xmalloc(size) malloc(size) -#define xrealloc(ptr,size) realloc(ptr,size) -#define xcalloc(nmemb,size) calloc(nmemb,size) -#define XT_INT_MAX SIZE_MAX -typedef size_t yac_int; -#else -#include "core/ppm_xfuncs.h" -#include "core/core.h" -#endif - -typedef double(*coordinate_pointer)[3]; -typedef double const (* const const_coordinate_pointer)[3] ; - -#define YAC_ASSERT(exp, msg) \ - {if(!((exp))) yac_internal_abort_message(((msg)), __FILE__, __LINE__);} - -#define YAC_ASSERT_F(exp, format, ...) \ - { \ - if(!((exp))) { \ - char msg_buffer[1024]; \ - int ret = snprintf( \ - msg_buffer, sizeof(msg_buffer), ((format)), __VA_ARGS__); \ - if ((ret >= 0) && ((size_t)ret < sizeof(msg_buffer))) \ - yac_internal_abort_message(((msg_buffer)), __FILE__, __LINE__); \ - else \ - yac_internal_abort_message( \ - "an error occured, but error message could not be generated", \ - __FILE__, __LINE__); \ - } \ - } +#ifndef UTILS_CORE_H +#define UTILS_CORE_H -/** - * prints a short error message and info from where it was called - * followed by an exit. - */ -void yac_internal_abort_message ( const char * text, const char * file, int line ); - -int yac_file_exists(const char * filename); +#include "utils_common.h" /** \example test_abort_c.c * This contains an example of how to use yac_abort_message. */ -#define YAC_ABORT(msg) \ - {yac_abort_message(((msg)), __FILE__, __LINE__);} - -/** - * prints a short error message and info from where it was called - * followed by an exit. - */ -void yac_abort_message ( char * text, char * file, int line ); - /** \example test_quicksort.c * This contains an example of how to use quicksort_index. */ @@ -136,9 +37,6 @@ void yac_quicksort_index_int_size_t_size_t ( int * a, size_t n, size_t * b, size_t * c ); void yac_quicksort_index_int_size_t_yac_int ( int * a, size_t n, size_t * b, yac_int * c ); -void yac_qsort_index( - void * a, size_t count, size_t size, - int (*compare)(void const *, void const *), size_t * idx); /** \example test_mergesort.c * @@ -148,33 +46,6 @@ void yac_qsort_index( void yac_mergesort(void* base, size_t num, size_t size, int (*compar)(const void*,const void*)); -/** - * remove duplicated entries from a list of integers - * @param[in,out] array array containing a sorted (ascending) list of integers - * @param[in,out] n number of entries in array - */ -static inline void yac_remove_duplicates_int(int * array, size_t * n) { - - size_t const N = *n; - size_t pos = 0; - - if (N == 0) return; - - int prev = array[0]; - - for (size_t i = 1; i < N; ++i) { - - if (array[i] == prev) continue; - - prev = array[i]; - ++pos; - - if (pos != i) array[pos] = array[i]; - } - - *n = pos + 1; -} - /** * remove duplicated entries from a list of integers * @param[in,out] array array containing a sorted (ascending) list of integers @@ -328,24 +199,6 @@ static inline void yac_remove_duplicates_size_t_3( *n = pos + 1; } -struct yac_name_type_pair { - const char * name; - int type; -}; - -char const * yac_name_type_pair_get_name( - struct yac_name_type_pair const * pairs, size_t count, int type); -int yac_name_type_pair_get_type( - struct yac_name_type_pair const * pairs, size_t count, char const * name); - -/* ======================================================================= - Macros - ======================================================================= */ - -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - #define ASSERT(c) \ if (!(c)) {\ fprintf(stderr, "### Assertion violation: %s in %s:%d\n",\ @@ -353,5 +206,10 @@ if (!(c)) {\ abort ();\ } -#endif // UTILS_H +#define COPY_DATA(data, count) \ + (memcpy( \ + xmalloc((size_t)(count) * sizeof(*(data))), \ + (data), (size_t)(count) * sizeof(*(data)))) + +#endif // UTILS_CORE_H diff --git a/src/lib/yac/yac_interp_method_conserv.c b/src/lib/yac/yac_interp_method_conserv.c new file mode 100644 index 0000000000000000000000000000000000000000..bdb0471f6d13940f54a0addc24d7fb431144590a --- /dev/null +++ b/src/lib/yac/yac_interp_method_conserv.c @@ -0,0 +1,1320 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause +/* +#ifdef HAVE_CONFIG_H +// Get the definition of the 'restrict' keyword. +#include "config.h" +#endif +*/ +#include <string.h> +#include <math.h> // abs() +/* +#include "interp_method_internal.h" +#include "interp_method_conserv.h" +*/ +#include "yac_interp_method_conserv.h" +#include "clipping.h" +#include "area.h" +#include "float.h" + +#include "utils_common.h" +#include "geometry.h" + +struct yac_interp_grid { + char * src_grid_name; + char * tgt_grid_name; + //struct yac_dist_grid_pair * grid_pair; + struct yac_interp_field tgt_field; + size_t num_src_fields; + struct yac_interp_field src_fields[]; +}; + +#define AREA_TOL_FACTOR (1e-6) +/* +static size_t do_search_conserv_1st_order(struct interp_method * method, + struct yac_interp_grid * interp_grid, + size_t * tgt_points, size_t count, + struct yac_interp_weights * weights); +static size_t do_search_conserv_2nd_order(struct interp_method * method, + struct yac_interp_grid * interp_grid, + size_t * tgt_points, size_t count, + struct yac_interp_weights * weights); +static void delete_conserv(struct interp_method * method); + +static struct interp_method_vtable + interp_method_conserv_1st_order_vtable = { + .do_search = do_search_conserv_1st_order, + .delete = delete_conserv}; + +static struct interp_method_vtable + interp_method_conserv_2nd_order_vtable = { + .do_search = do_search_conserv_2nd_order, + .delete = delete_conserv}; + +struct interp_method_conserv { + + struct interp_method_vtable * vtable; + int partial_coverage; + enum yac_interp_method_conserv_normalisation normalisation; + int enforced_conserv; +}; +*/ +struct weight_vector_data { + double weight; + size_t local_id; + yac_int global_id; +}; + +struct weight_vector_data_3d { + double weight[3]; + size_t local_id; + yac_int global_id; +}; + +struct weight_vector_3d { + struct weight_vector_data_3d * data; + size_t n; +}; + +struct supermesh_cell { + struct { + size_t local_id; + yac_int global_id; + } src, tgt; + double norm_area; + double area; + double barycenter[3]; + struct weight_vector_3d * src_cell_gradient; +}; + +typedef size_t const (* const const_size_t_2_pointer)[2]; +typedef int const * const const_int_pointer; +typedef size_t const * const const_size_t_pointer; +typedef yac_int const * const const_yac_int_pointer; +typedef enum yac_edge_type const * const const_yac_edge_type_pointer; +typedef struct bounding_circle const * const const_bounding_circle_pointer; +typedef struct remote_point_infos const * const const_remote_point_infos_pointer; + +struct yac_const_basic_grid_data { + yac_const_coordinate_pointer vertex_coordinates; + const_yac_int_pointer ids[3]; + const_int_pointer num_vertices_per_cell; + const_size_t_pointer cell_to_vertex; + const_size_t_pointer cell_to_vertex_offsets; + const_size_t_pointer cell_to_edge; + const_size_t_pointer cell_to_edge_offsets; + const_size_t_2_pointer edge_to_vertex; + const_bounding_circle_pointer cell_bnd_circles; + const_yac_edge_type_pointer edge_type; + const_remote_point_infos_pointer cell_owners; + const_remote_point_infos_pointer vertex_owners; + const_remote_point_infos_pointer edge_owners; + const size_t count[3]; +}; + +static int get_max_num_vertices_per_cell( + struct yac_const_basic_grid_data * basic_grid_data) { + + int max_num_vertices_per_cell = 0; + for (size_t i = 0; i < basic_grid_data->count[YAC_LOC_CELL]; ++i) + if (basic_grid_data->num_vertices_per_cell[i] > + max_num_vertices_per_cell) + max_num_vertices_per_cell = + basic_grid_data->num_vertices_per_cell[i]; + return max_num_vertices_per_cell; +} + +struct yac_const_basic_grid_data * +yac_interp_grid_get_basic_grid_data_src(struct yac_interp_grid * interp_grid) +{ + return NULL; +} + +struct yac_const_basic_grid_data * +yac_interp_grid_get_basic_grid_data_tgt(struct yac_interp_grid * interp_grid) +{ + return NULL; +} + +static void get_cell_buffers( + struct yac_interp_grid * interp_grid, size_t max_num_src_per_tgt, + struct grid_cell * tgt_grid_cell, struct grid_cell ** src_grid_cells) { + + struct yac_const_basic_grid_data * src_basic_grid_data = + yac_interp_grid_get_basic_grid_data_src(interp_grid); + struct yac_const_basic_grid_data * tgt_basic_grid_data = + yac_interp_grid_get_basic_grid_data_tgt(interp_grid); + + *src_grid_cells = xmalloc(max_num_src_per_tgt * sizeof(**src_grid_cells)); + enum yac_edge_type * edge_type_buffer; + double (*coordinates_xyz_buffer)[3]; + + // prepare source grid cell buffer + { + int max_num_vertices_per_cell = + MAX(get_max_num_vertices_per_cell(src_basic_grid_data), + get_max_num_vertices_per_cell(tgt_basic_grid_data)); + + edge_type_buffer = + xmalloc((max_num_src_per_tgt + 1) * (size_t)max_num_vertices_per_cell * + sizeof(*edge_type_buffer)); + coordinates_xyz_buffer = + xmalloc((max_num_src_per_tgt + 1) * (size_t)max_num_vertices_per_cell * + sizeof(*coordinates_xyz_buffer)); + + tgt_grid_cell->coordinates_xyz = coordinates_xyz_buffer; + tgt_grid_cell->edge_type = edge_type_buffer; + tgt_grid_cell->array_size = max_num_vertices_per_cell; + for (size_t i = 0; i < max_num_src_per_tgt; ++i) { + (*src_grid_cells)[i].coordinates_xyz = + coordinates_xyz_buffer + (i + 1) * max_num_vertices_per_cell; + (*src_grid_cells)[i].edge_type = + edge_type_buffer + (i + 1) * max_num_vertices_per_cell; + (*src_grid_cells)[i].array_size = max_num_vertices_per_cell; + } + } +} + +static void get_cell_buffers_( + struct yac_interp_grid * interp_grid, + struct grid_cell * tgt_grid_cell, struct grid_cell * src_grid_cell) { + + struct yac_const_basic_grid_data * src_basic_grid_data = + yac_interp_grid_get_basic_grid_data_src(interp_grid); + struct yac_const_basic_grid_data * tgt_basic_grid_data = + yac_interp_grid_get_basic_grid_data_tgt(interp_grid); + + int max_num_vertices_per_cell = + MAX(get_max_num_vertices_per_cell(src_basic_grid_data), + get_max_num_vertices_per_cell(tgt_basic_grid_data)); + + enum yac_edge_type * edge_type_buffer = + xmalloc(2 * (size_t)max_num_vertices_per_cell * + sizeof(*edge_type_buffer)); + yac_coordinate_pointer coordinates_xyz_buffer = + xmalloc(2 * (size_t)max_num_vertices_per_cell * + sizeof(*coordinates_xyz_buffer)); + + tgt_grid_cell->coordinates_xyz = coordinates_xyz_buffer; + tgt_grid_cell->edge_type = edge_type_buffer; + tgt_grid_cell->array_size = max_num_vertices_per_cell; + + src_grid_cell->coordinates_xyz = + coordinates_xyz_buffer + max_num_vertices_per_cell; + src_grid_cell->edge_type = + edge_type_buffer + max_num_vertices_per_cell; + src_grid_cell->array_size = max_num_vertices_per_cell; +} +/* +static int compute_1st_order_weights( + struct yac_const_basic_grid_data * tgt_basic_grid_data, size_t tgt_cell, + struct yac_const_basic_grid_data * src_basic_grid_data, size_t src_count, + size_t * src_cells, struct grid_cell tgt_grid_cell_buffer, + struct grid_cell * src_grid_cell_buffer, + double * weights, size_t * num_weights, int partial_coverage, + enum yac_interp_method_conserv_normalisation normalisation, + int enforced_conserv) { + + yac_const_basic_grid_data_get_grid_cell( + tgt_basic_grid_data, tgt_cell, &tgt_grid_cell_buffer); + for (size_t i = 0; i < src_count; ++i) + yac_const_basic_grid_data_get_grid_cell( + src_basic_grid_data, src_cells[i], src_grid_cell_buffer + i); + + double * area = weights; + yac_compute_overlap_areas( + src_count, src_grid_cell_buffer, tgt_grid_cell_buffer, area); + + size_t num_valid_weights = 0; + for (size_t i = 0; i < src_count; ++i) { + + if (area[i] > 0.0) { + if (i != num_valid_weights) { + area[num_valid_weights] = area[i]; + src_cells[num_valid_weights] = src_cells[i]; + } + ++num_valid_weights; + } + } + *num_weights = num_valid_weights; + if (num_valid_weights == 0) return 0; + + double tgt_cell_area = yac_huiliers_area(tgt_grid_cell_buffer); + double norm_factor; + + YAC_ASSERT( + (normalisation == YAC_INTERP_CONSERV_DESTAREA) || + (normalisation == YAC_INTERP_CONSERV_FRACAREA), + "ERROR(compute_weights_order_first_conserv_no_partial): " + "invalid normalisation option in conservative remapping") + switch(normalisation) { + case(YAC_INTERP_CONSERV_DESTAREA): + norm_factor = 1.0 / tgt_cell_area; + break; + default: + case(YAC_INTERP_CONSERV_FRACAREA): { + double fracarea = 0.0; + for (size_t i = 0; i < num_valid_weights; ++i) fracarea += area[i]; + norm_factor = 1.0 / fracarea; + break; + } + }; + + if (partial_coverage) { + for (size_t i = 0; i < num_valid_weights; ++i) weights[i] *= norm_factor; + return 1; + } else { + double tgt_cell_area_diff = tgt_cell_area; + double area_tol = tgt_cell_area * AREA_TOL_FACTOR; + for (size_t i = 0; i < num_valid_weights; ++i) { + double curr_area = area[i]; + tgt_cell_area_diff -= curr_area; + weights[i] = curr_area * norm_factor; + } + int successful = fabs(tgt_cell_area_diff) <= area_tol; + if (successful && enforced_conserv) + yac_correct_weights(num_valid_weights, weights); + return successful; + } +} + +static size_t do_search_conserv_1st_order (struct interp_method * method, + struct yac_interp_grid * interp_grid, + size_t * tgt_points, size_t count, + struct yac_interp_weights * weights) { + + struct interp_method_conserv * method_conserv = + (struct interp_method_conserv *)method; + + YAC_ASSERT( + yac_interp_grid_get_num_src_fields(interp_grid) == 1, + "ERROR(do_search_conserv): invalid number of source fields") + + YAC_ASSERT( + yac_interp_grid_get_src_field_location(interp_grid, 0) == YAC_LOC_CELL, + "ERROR(do_search_conserv): unsupported source field location type") + + YAC_ASSERT( + yac_interp_grid_get_tgt_field_location(interp_grid) == YAC_LOC_CELL, + "ERROR(do_search_conserv): unsupported target field location type") + + + size_t * src_cells = NULL; + size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt)); + + // search matching cells + yac_interp_grid_do_cell_search_src( + interp_grid, tgt_points, count, &src_cells, num_src_per_tgt); + + // we did a search on the interp_grid, therefore we have to re-get the basic + // grid data + struct yac_const_basic_grid_data * tgt_basic_grid_data = + yac_interp_grid_get_basic_grid_data_tgt(interp_grid); + struct yac_const_basic_grid_data * src_basic_grid_data = + yac_interp_grid_get_basic_grid_data_src(interp_grid); + + size_t total_num_weights = 0; + size_t max_num_src_per_tgt = 0; + for (size_t i = 0; i < count; ++i) { + size_t curr_num_src_per_tgt = num_src_per_tgt[i]; + if (curr_num_src_per_tgt > max_num_src_per_tgt) + max_num_src_per_tgt = curr_num_src_per_tgt; + total_num_weights += num_src_per_tgt[i]; + } + + // to ensure that the interpolation always procduces the same result, we + // sort the source cells for each target point by their global ids + { + yac_int * temp_src_global_ids = + xmalloc(max_num_src_per_tgt * sizeof(*temp_src_global_ids)); + + for (size_t i = 0, offset = 0; i < count; ++i) { + + size_t curr_num_src_per_tgt = num_src_per_tgt[i]; + size_t * curr_src_cells = src_cells + offset; + offset += curr_num_src_per_tgt; + + for (size_t j = 0; j < curr_num_src_per_tgt; ++j) + temp_src_global_ids[j] = + src_basic_grid_data->ids[YAC_LOC_CELL][curr_src_cells[j]]; + + yac_quicksort_index_yac_int_size_t( + temp_src_global_ids, curr_num_src_per_tgt, curr_src_cells); + } + + free(temp_src_global_ids); + } + + double * w = xmalloc(total_num_weights * sizeof(*w)); + size_t result_count = 0; + size_t * failed_tgt = xmalloc(count * sizeof(*failed_tgt)); + total_num_weights = 0; + + int partial_coverage = method_conserv->partial_coverage; + enum yac_interp_method_conserv_normalisation normalisation = + method_conserv->normalisation; + int enforced_conserv = method_conserv->enforced_conserv; + + struct grid_cell tgt_grid_cell; + struct grid_cell * src_grid_cells; + get_cell_buffers( + interp_grid, max_num_src_per_tgt, &tgt_grid_cell, &src_grid_cells); + + // compute overlaps + for (size_t i = 0, offset = 0, result_offset = 0; i < count; ++i) { + + size_t curr_src_count = num_src_per_tgt[i]; + size_t curr_tgt_point = tgt_points[i]; + size_t num_weights; + + // if weight computation was successful + if (compute_1st_order_weights( + tgt_basic_grid_data, curr_tgt_point, + src_basic_grid_data, curr_src_count, src_cells + offset, + tgt_grid_cell, src_grid_cells, w + result_offset, &num_weights, + partial_coverage, normalisation, enforced_conserv)) { + + if (offset != result_offset) { + + memmove( + src_cells + result_offset, src_cells + offset, + num_weights * sizeof(*src_cells)); + } + tgt_points[result_count] = curr_tgt_point; + num_src_per_tgt[result_count] = num_weights; + result_count++; + result_offset += num_weights; + total_num_weights += num_weights; + } else { + failed_tgt[i - result_count] = curr_tgt_point; + } + + offset += curr_src_count; + } + + free(tgt_grid_cell.edge_type); + free(tgt_grid_cell.coordinates_xyz); + free(src_grid_cells); + + if (result_count != count) + memcpy(tgt_points + result_count, failed_tgt, + (count - result_count) * sizeof(*tgt_points)); + free(failed_tgt); + + struct remote_points tgts = { + .data = + yac_interp_grid_get_tgt_remote_points( + interp_grid, tgt_points, result_count), + .count = result_count}; + struct remote_point * srcs = + yac_interp_grid_get_src_remote_points( + interp_grid, 0, src_cells, total_num_weights); + + // store weights + yac_interp_weights_add_wsum( + weights, &tgts, num_src_per_tgt, srcs, w); + + free(tgts.data); + free(srcs); + free(src_cells); + free(num_src_per_tgt); + free(w); + + return result_count; +} +*/ +static int +compare_supermesh_cell_src_local_ids(const void * a, const void * b) { + + struct supermesh_cell * a_ = (struct supermesh_cell *)a; + struct supermesh_cell * b_ = (struct supermesh_cell *)b; + + int ret = (a_->src.local_id > b_->src.local_id) - + (a_->src.local_id < b_->src.local_id); + if (ret) return ret; + return (a_->tgt.global_id > b_->tgt.global_id) - + (a_->tgt.global_id < b_->tgt.global_id); +} + +static int +compare_supermesh_cell_tgt_local_ids(const void * a, const void * b) { + + struct supermesh_cell * a_ = (struct supermesh_cell *)a; + struct supermesh_cell * b_ = (struct supermesh_cell *)b; + + int ret = (a_->tgt.local_id > b_->tgt.local_id) - + (a_->tgt.local_id < b_->tgt.local_id); + if (ret) return ret; + return (a_->src.global_id > b_->src.global_id) - + (a_->src.global_id < b_->src.global_id); +} + +static inline void orthogonalise_weight_vector( + double * src_cell_centroid, struct weight_vector_3d * G_i, + struct weight_vector_data_3d * buffer) { + + // This routine computes: (I_3 - C_i * C_i^-1) * G_i + // + // O(g_i) = g_i - C_i * (C_i^-1 * g_i) + // where: C_i is the centeroid of a source cell + // g_i is the gradient of the source field in C_i + // O(g_i) is the projection of g_i into the plane perpendicular to C_i + // g_i = G_i * f + // where: G_i is the weight matrix to compute g_i + // f is the source field vector + // => O(g_i) = (I_3 - C_i * C_i^-1) * G_i * f + // where: I_3 is the identity matrix of size 3 x 3 + // + // M = I_3 - C_i * C_i^-1 + + double M[3][3]; + for (size_t k = 0; k < 3; ++k) + for (size_t l = 0; l < 3; ++l) + M[k][l] = - src_cell_centroid[k] * src_cell_centroid[l]; + for (size_t k = 0; k < 3; ++k) + M[k][k] += 1.0; + + struct weight_vector_data_3d * G_i_data = G_i->data; + + size_t N = G_i->n; + for (size_t i = 0; i < N; ++i) { + buffer[i].local_id = G_i_data[i].local_id; + buffer[i].global_id = G_i_data[i].global_id; + for (size_t j = 0; j < 3; ++j) buffer[i].weight[j] = 0.0; + } + + for (size_t n = 0; n < N; ++n) + for (size_t i = 0; i < 3; ++i) + for (size_t j = 0; j < 3; ++j) + buffer[n].weight[i] += G_i_data[n].weight[j] * M[i][j]; + + memcpy(G_i->data, buffer, N * sizeof(*buffer)); +} + +static int compare_weight_vector_data_weight( + void const * a, void const * b) { + + struct weight_vector_data const * weight_a = + (struct weight_vector_data const *)a; + struct weight_vector_data const * weight_b = + (struct weight_vector_data const *)b; + + int ret = weight_a->global_id - weight_b->global_id; + if (ret) return ret; + double abs_weight_a = fabs(weight_a->weight); + double abs_weight_b = fabs(weight_b->weight); + ret = (abs_weight_a > abs_weight_b) - (abs_weight_a < abs_weight_b); + if (ret) return ret; + return (weight_a->weight > weight_b->weight) - + (weight_a->weight < weight_b->weight); +} + +static int compare_weight_vector_data( + void const * a, void const * b) { + + struct weight_vector_data const * weight_a = + (struct weight_vector_data const *)a; + struct weight_vector_data const * weight_b = + (struct weight_vector_data const *)b; + + return weight_a->global_id - weight_b->global_id; +} + +static void compact_weight_vector_data( + struct weight_vector_data * weights, size_t * n) { + + size_t n_ = *n; + + if (n_ <= 1) return; + + // sort weights by global_id then by weight + qsort(weights, n_, sizeof(*weights), compare_weight_vector_data_weight); + + size_t new_n = 1; + struct weight_vector_data * prev_weight_data = weights; + struct weight_vector_data * curr_weight_data = weights + 1; + for (size_t i = 1; i < n_; ++i, ++curr_weight_data) { + + // if both weights refer to the same source point (by global_id) + if (!compare_weight_vector_data(prev_weight_data, curr_weight_data)) { + prev_weight_data->weight += curr_weight_data->weight; + } else { + ++new_n; + ++prev_weight_data; + *prev_weight_data = *curr_weight_data; + } + } + + n_ = new_n; + new_n = 0; + + // check for zero-weights + for (size_t i = 0; i < n_; ++i) { + + if (weights[i].weight == 0.0) continue; + if (i != new_n) weights[new_n] = weights[i]; + ++new_n; + } + + *n = new_n; +} + +static size_t compute_2nd_order_tgt_cell_weights( + struct supermesh_cell * super_cell, struct weight_vector_data * weights) { + + weights[0].weight = super_cell->norm_area; + weights[0].global_id = super_cell->src.global_id; + weights[0].local_id = super_cell->src.local_id; + + struct weight_vector_3d * src_cell_gradient = super_cell->src_cell_gradient; + + size_t N = src_cell_gradient->n; + // in case we have no gradient for the current supermesh cell, + // we assume a constant field across the whole associated source cell + if (N > 0) { + struct weight_vector_data_3d * gradient_weights = src_cell_gradient->data - 1; + double * overlap_barycenter = super_cell->barycenter; + + for (size_t n = 1; n <= N; ++n) { + weights[n].weight = + (gradient_weights[n].weight[0] * overlap_barycenter[0] + + gradient_weights[n].weight[1] * overlap_barycenter[1] + + gradient_weights[n].weight[2] * overlap_barycenter[2]) * + super_cell->norm_area; + weights[n].global_id = gradient_weights[n].global_id; + weights[n].local_id = gradient_weights[n].local_id; + } + } + + return 1 + N; +} + +static void compute_cell_barycenter( + struct yac_const_basic_grid_data * grid_data, size_t cell_idx, + double barycenter[3]) { + + size_t num_vertices = grid_data->num_vertices_per_cell[cell_idx]; + size_t const * vertices = + grid_data->cell_to_vertex + grid_data->cell_to_vertex_offsets[cell_idx]; + + barycenter[0] = 0.0; + barycenter[1] = 0.0; + barycenter[2] = 0.0; + + for (size_t i = 0; i < num_vertices; ++i) { + double const * curr_vertex_coordinate = + grid_data->vertex_coordinates[vertices[i]]; + barycenter[0] += curr_vertex_coordinate[0]; + barycenter[1] += curr_vertex_coordinate[1]; + barycenter[2] += curr_vertex_coordinate[2]; + } + normalise_vector(barycenter); +} + +static void compute_super_cells( + struct yac_interp_grid * interp_grid, size_t * tgt_points, size_t count, + struct supermesh_cell ** super_cells_, size_t * num_super_cells, + int * interp_fail_flag, size_t ** src_cells, size_t * num_src_cells, + enum yac_interp_method_conserv_normalisation normalisation, + int partial_coverage) { + + YAC_ASSERT( + (normalisation == YAC_INTERP_CONSERV_DESTAREA) || + (normalisation == YAC_INTERP_CONSERV_FRACAREA), + "ERROR(compute_super_cells): " + "invalid normalisation option in conservative remapping") + + size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt)); + + // search for all source cell overlapping with the the target cells + printf("yac_interp_grid_do_cell_search_src() missing\n"); + /* + yac_interp_grid_do_cell_search_src( + interp_grid, tgt_points, count, src_cells, num_src_per_tgt); + */ + + // determine the number of unique matching source cells + size_t total_num_overlaps = 0; + for (size_t i = 0; i < count; ++i) total_num_overlaps += num_src_per_tgt[i]; + yac_quicksort_index_size_t_int(*src_cells, total_num_overlaps, NULL); + *num_src_cells = total_num_overlaps; + yac_remove_duplicates_size_t(*src_cells, num_src_cells); + + size_t * num_tgt_per_src = + xrealloc(num_src_per_tgt, *num_src_cells * sizeof(*num_tgt_per_src)); + + // for some required source cells we may have not all required supermesh cells + // in that case we have to find the respective target cells and compute the + // missing supermesh cells from them + size_t * tgt_cells = NULL; + printf("yac_interp_grid_do_cell_search_tgt() missing\n"); + /* + yac_interp_grid_do_cell_search_tgt( + interp_grid, *src_cells, *num_src_cells, &tgt_cells, num_tgt_per_src); + */ + + total_num_overlaps = 0; + for (size_t i = 0; i < *num_src_cells; ++i) + total_num_overlaps += num_tgt_per_src[i]; + + struct supermesh_cell * super_cells = + xmalloc(total_num_overlaps * sizeof(*super_cells)); + + struct yac_const_basic_grid_data * src_basic_grid_data = + yac_interp_grid_get_basic_grid_data_src(interp_grid); + struct yac_const_basic_grid_data * tgt_basic_grid_data = + yac_interp_grid_get_basic_grid_data_tgt(interp_grid); + + for (size_t i = 0, j = 0; i < *num_src_cells; ++i) { + + size_t curr_num_overlaps = num_tgt_per_src[i]; + size_t curr_src_cell = (*src_cells)[i]; + yac_int curr_src_global_id = + src_basic_grid_data->ids[YAC_LOC_CELL][curr_src_cell]; + + for (size_t k = 0; k < curr_num_overlaps; ++k, ++j) { + + size_t curr_tgt_cell = tgt_cells[j]; + struct supermesh_cell * curr_super_cell = super_cells + j; + curr_super_cell->src.local_id = curr_src_cell; + curr_super_cell->src.global_id = curr_src_global_id; + curr_super_cell->tgt.local_id = curr_tgt_cell; + curr_super_cell->tgt.global_id = + tgt_basic_grid_data->ids[YAC_LOC_CELL][curr_tgt_cell]; + } + } + free(tgt_cells); + free(num_tgt_per_src); + + // sort supermesh_cell first by local ids of the target cells and + // second by global cell id + qsort(super_cells, total_num_overlaps, sizeof(*super_cells), + compare_supermesh_cell_tgt_local_ids); + + struct grid_cell tgt_grid_cell; + struct grid_cell src_grid_cell; + get_cell_buffers_(interp_grid, &tgt_grid_cell, &src_grid_cell); + + src_basic_grid_data = yac_interp_grid_get_basic_grid_data_src(interp_grid); + tgt_basic_grid_data = yac_interp_grid_get_basic_grid_data_tgt(interp_grid); + + // For all supermesh cells compute the area and normalised area. + // Additionally, remove all empty supermesh cells. + size_t new_num_super_cells = 0; + size_t tgt_idx = 0; + for (size_t i = 0, j = 0; i < total_num_overlaps;) { + + // get information about the current target cell + size_t curr_tgt_cell = super_cells[i].tgt.local_id; + printf("yac_const_basic_grid_data_get_grid_cell() missing\n"); + /* + yac_const_basic_grid_data_get_grid_cell( + tgt_basic_grid_data, curr_tgt_cell, &tgt_grid_cell); + */ + double curr_tgt_cell_coverage = 0.0; + + // for all supermesh cells overlapping with the current target cell + for (;(i < total_num_overlaps) && + (super_cells[i].tgt.local_id == curr_tgt_cell); ++i) { + + // get the current source cell + printf("yac_const_basic_grid_data_get_grid_cell() missing\n"); + /* + yac_const_basic_grid_data_get_grid_cell( + src_basic_grid_data, super_cells[i].src.local_id, &src_grid_cell); + */ + + // compute area of the current supermesh cell + double super_cell_area; + double barycenter[3]; + yac_compute_overlap_info( + 1, &src_grid_cell, tgt_grid_cell, &super_cell_area, &barycenter); + + // if there is an overlap between the current source and target cell + if (super_cell_area > 0.0) { + + super_cells[new_num_super_cells].src = super_cells[i].src; + super_cells[new_num_super_cells].tgt = super_cells[i].tgt; + super_cells[new_num_super_cells].area = super_cell_area; + memcpy(super_cells[new_num_super_cells].barycenter, barycenter, + 3 * sizeof(double)); + super_cells[new_num_super_cells].src_cell_gradient = NULL; + ++new_num_super_cells; + + curr_tgt_cell_coverage += super_cell_area; + } + } + + double curr_tgt_cell_area = yac_huiliers_area(tgt_grid_cell); + + // if there was an overlap + if (new_num_super_cells != j) { + + double norm_factor; + YAC_ASSERT( + (normalisation == YAC_INTERP_CONSERV_DESTAREA) || + (normalisation == YAC_INTERP_CONSERV_FRACAREA), + "ERROR(compute_super_cells): invalid normalisation") + switch (normalisation) { + default: + case (YAC_INTERP_CONSERV_DESTAREA): + norm_factor = 1.0 / curr_tgt_cell_area; + break; + case (YAC_INTERP_CONSERV_FRACAREA): + norm_factor = 1.0 / curr_tgt_cell_coverage; + break; + } + // compute normalised area + for (; j < new_num_super_cells; ++j) + super_cells[j].norm_area = super_cells[j].area * norm_factor; + } + + + // for target cell that do not overlap with any source cell + while ((tgt_idx < count) && (tgt_points[tgt_idx] < curr_tgt_cell)) + interp_fail_flag[tgt_idx++] = 1; + + if ((tgt_idx < count) && (tgt_points[tgt_idx] == curr_tgt_cell)) { + + double area_tol = curr_tgt_cell_area * AREA_TOL_FACTOR; + + if (partial_coverage) { + interp_fail_flag[tgt_idx] = curr_tgt_cell_coverage < area_tol; + } else { + interp_fail_flag[tgt_idx] = + fabs(curr_tgt_cell_area - curr_tgt_cell_coverage) > area_tol; + } + ++tgt_idx; + } + } + // for all remaining target cell that do not overlap with any source cell + for (; tgt_idx < count; ++tgt_idx) interp_fail_flag[tgt_idx] = 1; + *num_super_cells = new_num_super_cells; + *super_cells_ = + xrealloc(super_cells, new_num_super_cells * sizeof(*super_cells)); + free(tgt_grid_cell.coordinates_xyz); + free(tgt_grid_cell.edge_type); +} + +static yac_coordinate_pointer compute_src_cell_centroids( + struct yac_interp_grid * interp_grid, + size_t * src_cells, int * skip_src_cell, size_t num_src_cells, + struct supermesh_cell * super_cells, size_t num_super_cells) { + + yac_coordinate_pointer src_cell_centroids = + xmalloc(num_src_cells * sizeof(*src_cell_centroids)); + + // sort supermesh cells first by source local id and second by + // target global id + qsort(super_cells, num_super_cells, sizeof(*super_cells), + compare_supermesh_cell_src_local_ids); + + struct grid_cell src_grid_cell, dummy; + get_cell_buffers_(interp_grid, &src_grid_cell, &dummy); + + struct yac_const_basic_grid_data * src_basic_grid_data = + yac_interp_grid_get_basic_grid_data_src(interp_grid); + + // compute centroids of source cells + // C_i = N(S_(U_k) (A_k*C_k)) + // where: N(C) = C*(C*C)^-0.5 // normalisation + // U_k all supermesh cells overlaping with the respective source cell + // A_k area of supermesh cell + // C_k barycenter of supermesh cell (normalisation of the sum of all + // vertices of the cell) + for (size_t i = 0, offset = 0; i < num_src_cells; ++i) { + + if (skip_src_cell[i]) continue; + + size_t curr_src_cell = src_cells[i]; + printf("yac_const_basic_grid_data_get_grid_cell() missing\n"); + /* + yac_const_basic_grid_data_get_grid_cell( + src_basic_grid_data, curr_src_cell, &src_grid_cell); + */ + double src_cell_area = yac_huiliers_area(src_grid_cell); + + struct supermesh_cell * curr_super_cells = super_cells + offset; + size_t curr_num_super_cells = offset; + while ((offset < num_super_cells) && + (super_cells[offset].src.local_id == curr_src_cell)) ++offset; + curr_num_super_cells = offset - curr_num_super_cells; + + double src_cell_area_diff = src_cell_area; + double src_cell_centroid[3] = {0.0, 0.0, 0.0}; + + for (size_t j = 0; j < curr_num_super_cells; ++j) { + + double super_cell_area = curr_super_cells[j].area; + double * super_cell_barycenter = curr_super_cells[j].barycenter; + src_cell_centroid[0] += super_cell_area * super_cell_barycenter[0]; + src_cell_centroid[1] += super_cell_area * super_cell_barycenter[1]; + src_cell_centroid[2] += super_cell_area * super_cell_barycenter[2]; + src_cell_area_diff -= super_cell_area; + } + + normalise_vector(src_cell_centroid); + src_cell_centroids[i][0] = src_cell_centroid[0]; + src_cell_centroids[i][1] = src_cell_centroid[1]; + src_cell_centroids[i][2] = src_cell_centroid[2]; + + } + free(src_grid_cell.coordinates_xyz); + free(src_grid_cell.edge_type); + + return src_cell_centroids; +} + +static struct weight_vector_3d * compute_src_cell_gradients( + struct yac_interp_grid * interp_grid, size_t * src_cells, + yac_coordinate_pointer src_cell_centroids, int * skip_src_cell, + size_t num_src_cells, size_t * src_cell_neighbours) { + + struct weight_vector_3d * src_cell_gradients = + xmalloc(num_src_cells * sizeof(*src_cell_gradients)); + + struct yac_const_basic_grid_data * src_basic_grid_data = + yac_interp_grid_get_basic_grid_data_src(interp_grid); + + size_t total_num_gradient_weights = 0; + size_t max_num_neigh_per_src = 0; + for (size_t i = 0; i < num_src_cells; ++i) { + src_cell_gradients[i].data = NULL; + src_cell_gradients[i].n = 0; + size_t curr_num_neigh = + src_basic_grid_data->num_vertices_per_cell[src_cells[i]]; + total_num_gradient_weights += curr_num_neigh + 1; + if (max_num_neigh_per_src < curr_num_neigh) + max_num_neigh_per_src = curr_num_neigh; + } + struct weight_vector_data_3d * weight_vector_data_buffer = + (total_num_gradient_weights > 0)? + (xmalloc(total_num_gradient_weights * + sizeof(*weight_vector_data_buffer))):NULL; + for (size_t i = 0; i < total_num_gradient_weights; ++i) + for (size_t j = 0; j < 3; ++j) + weight_vector_data_buffer[i].weight[j] = 0.0; + + struct weight_vector_data_3d * orth_buffer = + xmalloc((max_num_neigh_per_src + 1) * sizeof(*orth_buffer)); + + // compute gradient in the centroid for each source cell + // g_i = O_i(g'_i) + // where: O_i(g) = g - C_i*(C_i*g) // makes g orthogonal to C_i + // g'_i = (A_(C_k))^-1 * S_ijk(((f_j + f_k) * 0.5 - f_i) * + // (C_j x C_k) * |C_j x C_k|^-1 * + // asin(|C_j x C_k|)) + // where: g'_i is the estimated centroid gradient + // A_(C_k) is the area of the cell generated by connecting the + // barycenters of all neighbour cells + // S_ijk is the sum of all edges of the previously described cell in + // counterclockwise order + // f_i, f_j, and f_k are the mean values of the field over the area of + // the respective source cell area + // asin(|C_j x C_k|) / |C_j x C_k| ~ 1.0 + // => g'_i = S_ijk(((f_j + f_k) * 0.5 - f_i) * (C_j x C_k)) / A_(C_k) + // + // g_i = G_i * f + // G_i = S_ijk(((I_j + I_k) * 0.5 - I_i) * (C_j x C_k)) / A_(C_k) + // where: G_i is the gradient weight matrix + // I_x is a vector of the same size as f, which is all zero except at + // position x, where it is one + // f is the source field vector + for (size_t i = 0, offset = 0, weight_vector_data_buffer_offset = 0; + i < num_src_cells; ++i) { + + size_t curr_num_neigh = + src_basic_grid_data->num_vertices_per_cell[src_cells[i]]; + size_t * curr_neighs = src_cell_neighbours + offset; + offset += curr_num_neigh; + struct weight_vector_3d * G_i = src_cell_gradients + i; + G_i->data = weight_vector_data_buffer + weight_vector_data_buffer_offset; + + if (skip_src_cell[i]) continue; + + weight_vector_data_buffer_offset += curr_num_neigh + 1; + G_i->n = curr_num_neigh + 1; + G_i->data[0].local_id = src_cells[i]; + G_i->data[0].global_id = + src_basic_grid_data->ids[YAC_LOC_CELL][src_cells[i]]; + for (size_t j = 0; j < curr_num_neigh; ++j) { + size_t curr_neigh = curr_neighs[j]; + // if the current edge has a neighbour + if (curr_neigh != SIZE_MAX) { + G_i->data[j+1].local_id = curr_neigh; + G_i->data[j+1].global_id = + src_basic_grid_data->ids[YAC_LOC_CELL][curr_neigh]; + } else { + // if the current edge has no neighbour, use current cell instead + G_i->data[j+1].local_id = G_i->data[0].local_id; + G_i->data[j+1].global_id = G_i->data[0].global_id; + } + } + + // area of the polygon that is formed by connecting the barycenters of + // the neighbouring cells + double A_C_k = 0.0; + + struct grid_cell centroid_triangle = { + .coordinates_xyz = (double[3][3]){{0}}, + .edge_type = + (enum yac_edge_type[]) {GREAT_CIRCLE_EDGE,GREAT_CIRCLE_EDGE,GREAT_CIRCLE_EDGE}, + .num_corners = 3, .array_size = 0}; + centroid_triangle.coordinates_xyz[0][0] = src_cell_centroids[i][0]; + centroid_triangle.coordinates_xyz[0][1] = src_cell_centroids[i][1]; + centroid_triangle.coordinates_xyz[0][2] = src_cell_centroids[i][2]; + + double edge_direction = 0.0; + + // We split the cell that is comprised of the barycenters of the edge + // neigbours into triangles, which has the centroid of the current cell + // as one corner. The sum of the areas of these triangles is A_C_K. + for (size_t j = 0; j < curr_num_neigh; ++j) { + + size_t neigh_idx[2] = {j + 1, (j+1)%curr_num_neigh+1}; + size_t neigh_local_ids[2] = + {G_i->data[neigh_idx[0]].local_id, + G_i->data[neigh_idx[1]].local_id}; + + if (neigh_local_ids[0] == neigh_local_ids[1]) continue; + + double neigh_cell_barycenters[2][3]; + compute_cell_barycenter( + src_basic_grid_data, neigh_local_ids[0], neigh_cell_barycenters[0]); + compute_cell_barycenter( + src_basic_grid_data, neigh_local_ids[1], neigh_cell_barycenters[1]); + + centroid_triangle.coordinates_xyz[1][0] = neigh_cell_barycenters[0][0]; + centroid_triangle.coordinates_xyz[1][1] = neigh_cell_barycenters[0][1]; + centroid_triangle.coordinates_xyz[1][2] = neigh_cell_barycenters[0][2]; + centroid_triangle.coordinates_xyz[2][0] = neigh_cell_barycenters[1][0]; + centroid_triangle.coordinates_xyz[2][1] = neigh_cell_barycenters[1][1]; + centroid_triangle.coordinates_xyz[2][2] = neigh_cell_barycenters[1][2]; + + A_C_k += yac_huiliers_area(centroid_triangle); + + // C_j x C_k + double C_j_x_C_k[3]; + crossproduct_kahan( + neigh_cell_barycenters[0], neigh_cell_barycenters[1], C_j_x_C_k); + + double curr_edge_direction = + C_j_x_C_k[0] * centroid_triangle.coordinates_xyz[0][0] + + C_j_x_C_k[1] * centroid_triangle.coordinates_xyz[0][1] + + C_j_x_C_k[2] * centroid_triangle.coordinates_xyz[0][2]; + + if (fabs(curr_edge_direction) > fabs(edge_direction)) + edge_direction = curr_edge_direction; + + // -I_i * (C_j x C_k) + G_i->data[0].weight[0] -= C_j_x_C_k[0]; + G_i->data[0].weight[1] -= C_j_x_C_k[1]; + G_i->data[0].weight[2] -= C_j_x_C_k[2]; + + for (size_t l = 0; l < 3; ++l) C_j_x_C_k[l] *= 0.5; + + // 0.5 * I_j * (C_j x C_k) + G_i->data[neigh_idx[0]].weight[0] += C_j_x_C_k[0]; + G_i->data[neigh_idx[0]].weight[1] += C_j_x_C_k[1]; + G_i->data[neigh_idx[0]].weight[2] += C_j_x_C_k[2]; + + // 0.5 * I_k * (C_j x C_k) + G_i->data[neigh_idx[1]].weight[0] += C_j_x_C_k[0]; + G_i->data[neigh_idx[1]].weight[1] += C_j_x_C_k[1]; + G_i->data[neigh_idx[1]].weight[2] += C_j_x_C_k[2]; + } // curr_num_neigh + + // if the neighbours were ordered in the wrong direction + if (edge_direction > 0.0) + for (size_t j = 0; j <= curr_num_neigh; ++j) + for (size_t k = 0; k < 3; ++k) + G_i->data[j].weight[k] *= -1.0; + + double inv_A_C_K = (A_C_k > YAC_AREA_TOL)?(1.0/A_C_k):0.0; + // ((I_j + I_k) * 0.5 - I_i) * (C_j x C_k) / A_(C_k) + for (size_t k = 0; k <= curr_num_neigh; ++k) + for (size_t l = 0; l < 3; ++l) + G_i->data[k].weight[l] *= inv_A_C_K; + + orthogonalise_weight_vector( + src_cell_centroids[i], G_i, orth_buffer); + } // num_src_cells + free(orth_buffer); + + return src_cell_gradients; +} +/* +static size_t compute_2nd_order_weights( + struct yac_interp_grid * interp_grid, size_t * tgt_cells, + int * interp_fail_flag, size_t num_tgt_cells, + struct supermesh_cell * super_cells, size_t num_super_cells, + size_t ** src_per_tgt, double ** weights, size_t * num_src_per_tgt) { + + size_t num_interpolated_tgt = 0; + + // sort supermesh cells first by target local id and second by + // source global id + qsort(super_cells, num_super_cells, sizeof(*super_cells), + compare_supermesh_cell_tgt_local_ids); + + size_t max_num_weights_per_tgt = 0; + size_t max_num_total_weights = 0; + + // count maximum number of weights + for (size_t i = 0, j = 0; i < num_tgt_cells; ++i) { + + if (interp_fail_flag[i]) continue; + + size_t curr_tgt_cell = tgt_cells[i]; + size_t curr_num_weights = 0; + + // skip supermesh cells not overlapping with current target cell + while ((j < num_super_cells) && + (super_cells[j].tgt.local_id < curr_tgt_cell)) ++j; + + // for all supermesh cells overlapping with the current target cell + while ((j < num_super_cells) && + (super_cells[j].tgt.local_id == curr_tgt_cell)) + curr_num_weights += 1 + super_cells[j++].src_cell_gradient->n; + + max_num_total_weights += curr_num_weights; + if (max_num_weights_per_tgt < curr_num_weights) + max_num_weights_per_tgt = curr_num_weights; + num_interpolated_tgt++; + } + + struct weight_vector_data * weight_buffer = + xmalloc(max_num_weights_per_tgt * sizeof(*weight_buffer)); + *weights = xmalloc(max_num_total_weights * sizeof(**weights)); + *src_per_tgt = xmalloc(max_num_total_weights * sizeof(**src_per_tgt)); + + // sort all target points that can be interpolated to the beginning of the + // tgt_cells array + yac_quicksort_index_int_size_t(interp_fail_flag, num_tgt_cells, tgt_cells); + yac_quicksort_index_size_t_int(tgt_cells, num_interpolated_tgt, NULL); + + // compute 2nd order weights + // f_j = SUM(f_k') / A_j + // f_k' = A_k*(f_i + g_i * C_k) + // + // f_k' = A_k * (I_i + C_k * G_i) * f + // where: I_i is a vector of the same length as f, that is all 0.0 except at + // position i, where it is 1.0 + // f is the source field vector + // => f_k' / A_j = M_k * f + // where: M_k = A_k / A_j * (I_i + C_k * G_i) + // => f_j = SUM(M_k) * f + // f_j = M_j * f + // where: M_j = SUM(M_k) + size_t w_idx = 0; + for (size_t i = 0, j = 0; i < num_interpolated_tgt; ++i) { + + size_t curr_tgt_cell = tgt_cells[i]; + + // skip supermesh cells not overlapping with current target cell + while ((j < num_super_cells) && + (super_cells[j].tgt.local_id != curr_tgt_cell)) ++j; + + size_t weight_buffer_offset = 0; + + // for all supermesh cells overlapping with the current target cell + while ((j < num_super_cells) && + (super_cells[j].tgt.local_id == curr_tgt_cell)) { + + size_t num_weights = + compute_2nd_order_tgt_cell_weights( + super_cells + j, weight_buffer + weight_buffer_offset); + weight_buffer_offset += num_weights; + ++j; + } + + // compact weights and sort them by global_id + compact_weight_vector_data(weight_buffer, &weight_buffer_offset); + + num_src_per_tgt[i] = weight_buffer_offset; + + for (size_t k = 0; k < weight_buffer_offset; ++k, ++w_idx) { + (*weights)[w_idx] = weight_buffer[k].weight; + (*src_per_tgt)[w_idx] = weight_buffer[k].local_id; + } + } + free(weight_buffer); + + return num_interpolated_tgt; +} + +static size_t do_search_conserv_2nd_order (struct interp_method * method, + struct yac_interp_grid * interp_grid, + size_t * tgt_points, size_t count, + struct yac_interp_weights * weights) { + + struct interp_method_conserv * method_conserv = + (struct interp_method_conserv *)method; + + YAC_ASSERT( + yac_interp_grid_get_num_src_fields(interp_grid) == 1, + "ERROR(do_search_conserv): invalid number of source fields") + + YAC_ASSERT( + yac_interp_grid_get_src_field_location(interp_grid, 0) == YAC_LOC_CELL, + "ERROR(do_search_conserv): unsupported source field location type") + + YAC_ASSERT( + yac_interp_grid_get_tgt_field_location(interp_grid) == YAC_LOC_CELL, + "ERROR(do_search_conserv): unsupported target field location type") + + // sort target points + yac_quicksort_index_size_t_int(tgt_points, count, NULL); + + int * interp_fail_flag = xmalloc(count * sizeof(*interp_fail_flag)); + struct supermesh_cell * super_cells = NULL; + size_t num_super_cells = 0; + size_t * src_cells = NULL; + size_t num_src_cells = 0; + + // compute the overlaps between the target cells and the source grid + compute_super_cells( + interp_grid, tgt_points, count, &super_cells, &num_super_cells, + interp_fail_flag, &src_cells, &num_src_cells, + method_conserv->normalisation, method_conserv->partial_coverage); + + size_t total_num_src_cell_neighbours = 0; + struct yac_const_basic_grid_data * src_basic_grid_data = + yac_interp_grid_get_basic_grid_data_src(interp_grid); + for (size_t i = 0; i < num_src_cells; ++i) + total_num_src_cell_neighbours += + src_basic_grid_data->num_vertices_per_cell[src_cells[i]]; + size_t * src_cell_neighbours = + xmalloc(total_num_src_cell_neighbours * sizeof(*src_cell_neighbours)); + + // get the neighbours for all source cells overlapping with a target cell + yac_interp_grid_get_src_cell_neighbours( + interp_grid, src_cells, num_src_cells, src_cell_neighbours); + + const_int_pointer src_cell_mask = + yac_interp_grid_get_src_field_mask(interp_grid, 0); + int * skip_src_cell = xmalloc(num_src_cells * sizeof(*skip_src_cell)); + + // check whether any required source cell or any of its neighbours is masked + // out in the field mask (deactivate respective cells) + if (src_cell_mask != NULL) { + for (size_t i = 0, offset = 0; i < num_src_cells; ++i) { + size_t curr_src_cell = src_cells[i]; + if ((skip_src_cell[i] = !src_cell_mask[curr_src_cell])) continue; + size_t * curr_neighbours = src_cell_neighbours + offset; + size_t curr_num_neigh = + src_basic_grid_data->num_vertices_per_cell[curr_src_cell]; + offset += curr_num_neigh; + for (size_t j = 0; j < curr_num_neigh; ++j) + if ((curr_neighbours[j] != SIZE_MAX) && + (!src_cell_mask[curr_neighbours[j]])) + curr_neighbours[j] = SIZE_MAX; + } + } else { + memset(skip_src_cell, 0, num_src_cells * sizeof(*skip_src_cell)); + } + + // compute the centroids of all required source cells + yac_coordinate_pointer src_cell_centroids = + compute_src_cell_centroids(interp_grid, src_cells, skip_src_cell, + num_src_cells, super_cells, num_super_cells); + + // compute the gradients weights for the source cells + struct weight_vector_3d * src_cell_gradients = + compute_src_cell_gradients( + interp_grid, src_cells, src_cell_centroids, + skip_src_cell, num_src_cells, src_cell_neighbours); + free(src_cell_neighbours); + free(src_cell_centroids); + + // sort supermesh cells by local src id + qsort(super_cells, num_super_cells, sizeof(*super_cells), + compare_supermesh_cell_src_local_ids); + for (size_t i = 0, j = 0; i < num_src_cells; ++i) { + size_t curr_src_cell = src_cells[i]; + struct weight_vector_3d * curr_src_cell_gradient = src_cell_gradients + i; + // there should not be any supercell whose source cell is not in the list of + // required source cells + YAC_ASSERT( + (j >= num_super_cells) || + (super_cells[j].src.local_id >= curr_src_cell), + "ERROR(do_search_conserv_2nd_order): internal error"); + while ((j < num_super_cells) && + (super_cells[j].src.local_id == curr_src_cell)) { + super_cells[j++].src_cell_gradient = curr_src_cell_gradient; + } + } + free(skip_src_cell); + free(src_cells); + + size_t * src_per_tgt = NULL; + double * w = NULL; + size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt)); + + // compute the weights for the target points + size_t num_interpolated_tgt = + compute_2nd_order_weights( + interp_grid, tgt_points, interp_fail_flag, count, + super_cells, num_super_cells, &src_per_tgt, &w, num_src_per_tgt); + if (num_src_cells > 0) free(src_cell_gradients->data); + free(src_cell_gradients); + free(super_cells); + free(interp_fail_flag); + + size_t total_num_weights = 0; + for (size_t i = 0; i < num_interpolated_tgt; ++i) + total_num_weights += num_src_per_tgt[i]; + + struct remote_points tgts = { + .data = + yac_interp_grid_get_tgt_remote_points( + interp_grid, tgt_points, num_interpolated_tgt), + .count = num_interpolated_tgt}; + struct remote_point * srcs = + yac_interp_grid_get_src_remote_points( + interp_grid, 0, src_per_tgt, total_num_weights); + + // store weights + yac_interp_weights_add_wsum( + weights, &tgts, num_src_per_tgt, srcs, w); + + free(tgts.data); + free(srcs); + free(w); + free(num_src_per_tgt); + free(src_per_tgt); + + return num_interpolated_tgt; +} +*/ +/* +struct interp_method * yac_interp_method_conserv_new( + int order, int enforced_conserv, int partial_coverage, + enum yac_interp_method_conserv_normalisation normalisation) { + + struct interp_method_conserv * method = xmalloc(1 * sizeof(*method)); + + YAC_ASSERT( + (enforced_conserv != 1) || (order == 1), + "ERROR(yac_interp_method_conserv_new): interp_method_conserv only " + "supports enforced_conserv with first order conservative remapping") + YAC_ASSERT( + (order == 1) || (order == 2), + "ERROR(yac_interp_method_conserv_new): invalid order") + + method->vtable = + (order == 1)? + &interp_method_conserv_1st_order_vtable: + &interp_method_conserv_2nd_order_vtable; + method->partial_coverage = partial_coverage; + method->normalisation = normalisation; + method->enforced_conserv = enforced_conserv; + + return (struct interp_method*)method; +} + +static void delete_conserv(struct interp_method * method) { + free(method); +} +*/ diff --git a/src/lib/yac/yac_interp_method_conserv.h b/src/lib/yac/yac_interp_method_conserv.h new file mode 100644 index 0000000000000000000000000000000000000000..2db1a58384817e60d7b416a7903b22fb8f984929 --- /dev/null +++ b/src/lib/yac/yac_interp_method_conserv.h @@ -0,0 +1,50 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef INTERP_METHOD_CONSERV_H +#define INTERP_METHOD_CONSERV_H +/* +#include "interp_method.h" +*/ +/** \example test_interp_method_conserv_parallel.c + * A test for the parallel conservative‚ interpolation method. + */ + +/** + * normalisation options for conservative interpolation\n + * (see SCRIP user manual for a more detailed description of the options) + */ +enum yac_interp_method_conserv_normalisation { + YAC_INTERP_CONSERV_DESTAREA = 0, //!< interpolation values are normalised by the area of + //!< the respective target cell + //!< (this is the default option) + YAC_INTERP_CONSERV_FRACAREA = 1, //!< interpolation values will be normalised by the area + //!< of the respective target cell that is covered by + //!< non-masked target cells +}; + +#define YAC_INTERP_CONSERV_ORDER_DEFAULT (1) +#define YAC_INTERP_CONSERV_ENFORCED_CONSERV_DEFAULT (0) +#define YAC_INTERP_CONSERV_PARTIAL_COVERAGE_DEFAULT (0) +#define YAC_INTERP_CONSERV_NORMALISATION_DEFAULT (0) + +/** + * constructor for a interpolation method of type interp_method_conserv + * @param[in] order 1st or 2nd order remapping + * @param[in] enforced_conserv enforce conservation by correcting truncation errors + * @param[in] partial_coverage if == 0, target cells that are not completely + * covered by non-masked source cells will not be + * interpolated (this is the default option)\n + * if != 0, for target cells that are only + * partially covered by non-mask source cells the + * interpolation value will be determined by the + * contributions of the respective source cells + * @param[in] normalisation specifies how to do the normalisation + */ +/* +struct interp_method * yac_interp_method_conserv_new( + int order, int enforced_conserv, int partial_coverage, + enum yac_interp_method_conserv_normalisation normalisation); +*/ +#endif // INTERP_METHOD_CONSERV_H diff --git a/src/lib/yac/yac_types.h b/src/lib/yac/yac_types.h new file mode 100644 index 0000000000000000000000000000000000000000..7dab884a025b1e6b77422a4cc533d14e70a8ca0e --- /dev/null +++ b/src/lib/yac/yac_types.h @@ -0,0 +1,25 @@ +// Copyright (c) 2024 The YAC Authors +// +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef YAC_TYPES_H +#define YAC_TYPES_H + +#ifdef YAC_FOR_CDO +typedef size_t yac_int; +#define XT_INT_MAX SIZE_MAX +#else +#include <yaxt.h> +// idxtype from yaxt as global id type in yac +typedef Xt_int yac_int; +#define yac_int_dt Xt_int_dt +#endif + +// types for 3D coordinate arrays +typedef double(*yac_coordinate_pointer)[3]; +typedef double const (* const yac_const_coordinate_pointer)[3] ; + +// type for storing an array for two indices +typedef size_t (* yac_size_t_2_pointer)[2]; + +#endif // YAC_TYPES_H diff --git a/src/lib/yac/yac_version.h b/src/lib/yac/yac_version.h index 15b3a4e9b98d00bc0161f340412c9fee3fe0b616..95501afd72f8d8e09634e70c10e924275fd1f3e2 100644 --- a/src/lib/yac/yac_version.h +++ b/src/lib/yac/yac_version.h @@ -1,6 +1,6 @@ #ifndef YAC_VERSION_H #define YAC_VERSION_H -#define YAC_VERSION "3.0.1" +#define YAC_VERSION "3.1.0" #endif diff --git a/src/mapping.cc b/src/mapping.cc index a6eb68f0a78b61d7a3b7a841737e02257eee018c..32cb2fe31f3a622d6da904f274f161f5dbb3bd8e 100644 --- a/src/mapping.cc +++ b/src/mapping.cc @@ -50,7 +50,7 @@ mapvar(int vlistID, int varID, const KeyValues &kv, const std::string &key, Cmor cdiDefAttTxt(vlistID, varID, "variable_comment", (int) value.size(), value.c_str()); else if (key == "p") { - if (!isspace(value[0])) cdiDefAttTxt(vlistID, varID, "positive", (int) value.size(), value.c_str()); + if (!std::isspace(value[0])) cdiDefAttTxt(vlistID, varID, "positive", (int) value.size(), value.c_str()); } else { diff --git a/src/merge_axis.cc b/src/merge_axis.cc index 2a9e71426b6d8873ba71638c271b76abbf033872..a120b7ede0253f9f38b7cc6575b5166ce6a3b8d5 100644 --- a/src/merge_axis.cc +++ b/src/merge_axis.cc @@ -245,12 +245,12 @@ MergeVarsOnAxis::read_cmor_charvar(const std::vector<int> &axissize, int streamI while (nrecs--) { int varIDrw, levelIDrw; - size_t nmiss; + size_t numMissVals; streamInqRecord(streamID, &varIDrw, &levelIDrw); for (int i = 0; i < this->inputNames.nvalues; ++i) if (varIDrw == this->inputKeys[i].varID) { - streamReadRecord(streamID, buffer_old.data(), &nmiss); + streamReadRecord(streamID, buffer_old.data(), &numMissVals); int newIndex; for (int j = 0; j < oldgridsize; ++j) { diff --git a/src/module_info.cc b/src/module_info.cc index 7e536e93c9ebcadde4adc5eeb8035ede6c9b0996..0423c76d2c325f367cd89b65d1b8297e0e8c1f59 100644 --- a/src/module_info.cc +++ b/src/module_info.cc @@ -3,12 +3,13 @@ #include "mpmo_color.h" #include "modules.h" #include "util_string.h" +#include "factory.h" #include <algorithm> #include <iostream> #include <functional> #include <string> -typedef std::function<bool(module_t &mod)> ModuleQuery; +typedef std::function<bool(const CdoModule &mod)> ModuleQuery; bool ModListOptions::requested(const std::string &name) @@ -34,11 +35,12 @@ ModListOptions::parse_request(const std::string &requestString) all = false; for (size_t i = 0, n = splitString.size(); i < n; ++i) { - auto it = find_module(splitString[i]); - if (it != get_modules().end()) + auto it = Factory::find_module(splitString[i]); + if (it != Factory::get().end()) { + auto &module = Factory::get_module(it); operInfoRequested = true; - std::cerr << splitString[i] << ": " << it->second.toString() << std::endl; + std::cerr << splitString[i] << ": " << module.toString() << std::endl; } else { @@ -56,54 +58,42 @@ ModListOptions::parse_request(const std::string &requestString) return true; } -static std::string -get_operator_description(const std::string &p_current_op_name, const char **help) +std::string +get_operator_description(const std::string &p_current_op_name, const CdoHelp &p_help) { std::string description = ""; - unsigned long cur_help_idx = 0; - std::string line; - unsigned long operator_section = 0; + if (p_help.empty()) return description; // search for operator section - size_t help_size = 0; - while (help[help_size]) help_size++; - if (!help_size) return description; - while (operator_section == 0 && cur_help_idx < help_size - 1) - { - line = help[++cur_help_idx]; - if (line.find("OPERATORS") != std::string::npos) { operator_section = cur_help_idx; } - } + + auto it = std::find_if(begin(p_help), end(p_help), [&](const auto &l) { return l.find("OPERATORS") != std::string::npos; }); // if no operator section is found - if (operator_section == 0) + if (it == end(p_help)) { - cur_help_idx = 0; - line = help[0]; - std::string name_section = help[0]; - bool help_contains_name = false; - // search for the operator name in the description - while (!line.empty()) + std::string name_section = std::string(p_help[0]); + it = std::find_if(begin(p_help), end(p_help), + [&](const auto &l) { return l.find(" " + p_current_op_name) != std::string::npos; }); + + if (it != end(p_help)) { - line = help[++cur_help_idx]; - if (line.find(p_current_op_name) != std::string::npos) { help_contains_name = true; } - name_section += line; + name_section += *it; + description = name_section.substr(name_section.find_first_of('-') + 2, name_section.size()); } - // if the name was found save description for later use - if (help_contains_name) { description = name_section.substr(name_section.find_first_of('-') + 2, name_section.size()); } } else { - line = help[++operator_section]; - // search the operator section for current operator line - while (line.find(p_current_op_name + " ") == std::string::npos && !line.empty() && operator_section < help_size - 1) - { - line = help[++operator_section]; - } - // if operator line found save description for later use - if (!line.empty() && line.find(" " + p_current_op_name + " ") != std::string::npos) + it = std::find_if(++it, end(p_help), + [&](const auto &l) { return l.find(" " + p_current_op_name + " ") != std::string::npos; }); + if (it != p_help.end()) { - auto op_name_start = line.find_first_not_of(" \t"); + std::string line = std::string(*it); + auto pos = line.find(" " + p_current_op_name + " "); + if (pos != std::string::npos) + { + auto op_name_start = line.find_first_not_of(" \t"); - description = line.substr(line.find_first_not_of(" \t", op_name_start + p_current_op_name.size()), line.size()); + description = line.substr(line.find_first_not_of(" \t", op_name_start + p_current_op_name.size()), line.size()); + } } } @@ -120,17 +110,18 @@ get_spacing_for(int p_space, const std::string &str) } static std::string -operatorGetShortInfoString(std::string ¤t_op_name, const module_t &p_module) +operatorGetShortInfoString(std::string ¤t_op_name, const CdoModule &p_module) { std::string shortInfo = current_op_name; - if (get_aliases().find(current_op_name) != get_aliases().end()) + int alias_index = p_module.is_alias(current_op_name); + if (-1 != alias_index) { - shortInfo += std::string(get_spacing_for(16, current_op_name) + "--> " + get_aliases()[current_op_name]); + shortInfo += std::string(get_spacing_for(16, current_op_name) + "--> " + p_module.aliases[alias_index].original); } - else if (p_module.help) + else if (!p_module.get_help(current_op_name).empty()) { // add spaceing and saving output line to the output list - auto description = get_operator_description(current_op_name, p_module.help); + const auto description = get_operator_description(current_op_name, p_module.get_help(current_op_name)); shortInfo += get_spacing_for(16, current_op_name) + description; } std::string in_out_info @@ -140,14 +131,13 @@ operatorGetShortInfoString(std::string ¤t_op_name, const module_t &p_modul } void -operator_print_list(std::function<bool(module_t &)> selectionCriteria) +operator_print_list(std::function<bool(const CdoModule &)> selectionCriteria) { std::vector<std::string> output_list; - // for (size_t out_list_idx = 0; out_list_idx < list_length; out_list_idx++) - for (auto ¤t_op_name : get_sorted_operator_name_list()) + for (auto ¤t_op_name : Factory::get_sorted_operator_name_list()) { - module_t ¤t_module = get_modules()[get_module_name_to(current_op_name)]; + const CdoModule ¤t_module = Factory::get_module(current_op_name); if (selectionCriteria(current_module)) { output_list.push_back(operatorGetShortInfoString(current_op_name, current_module)); } } // print generated output list @@ -161,27 +151,140 @@ operator_print_list(ModListOptions &p_opt) if (p_opt.printAll == true) { - operator_print_list([](module_t &) { return true; }); + operator_print_list([](const CdoModule &) { return true; }); } else { - ModuleQuery defaultModuleQuery = [](module_t &) -> bool { return false; }; - ModuleQuery runquestDefaultModuleQuery = [](module_t &) -> bool { return true; }; + ModuleQuery defaultModuleQuery = [](const CdoModule &) -> bool { return false; }; + ModuleQuery runquestDefaultModuleQuery = [](const CdoModule &) -> bool { return true; }; // clang-format off - ModuleQuery hasObase = p_opt.requested(s_obase) ? [](module_t &mod) -> bool { return mod.get_stream_out_cnt() == -1; } : defaultModuleQuery; - ModuleQuery hasNoOut = p_opt.requested(s_noOutput) ? [](module_t &mod) -> bool { return mod.get_stream_out_cnt() == 0; } : defaultModuleQuery; - ModuleQuery hasArb = p_opt.requested(s_arbIn) ? [](module_t &mod) -> bool { return mod.get_stream_in_cnt() == -1; } : defaultModuleQuery; - ModuleQuery filesOnly = p_opt.requested(s_filesOnly) ? [](module_t &mod) -> bool { return mod.get_pos_restriction() == FilesOnly; } : defaultModuleQuery; - ModuleQuery onlyFirst = p_opt.requested(s_onlyFirst) ? [](module_t &mod) -> bool { return mod.get_pos_restriction() == OnlyFirst; } : defaultModuleQuery; + ModuleQuery hasObase = p_opt.requested(s_obase) ? [](const CdoModule &mod) -> bool { return mod.get_stream_out_cnt() == -1; } : defaultModuleQuery; + ModuleQuery hasNoOut = p_opt.requested(s_noOutput) ? [](const CdoModule &mod) -> bool { return mod.get_stream_out_cnt() == 0; } : defaultModuleQuery; + ModuleQuery hasArb = p_opt.requested(s_arbIn) ? [](const CdoModule &mod) -> bool { return mod.get_stream_in_cnt() == -1; } : defaultModuleQuery; + ModuleQuery filesOnly = p_opt.requested(s_filesOnly) ? [](const CdoModule &mod) -> bool { return mod.get_pos_restriction() == FilesOnly; } : defaultModuleQuery; + ModuleQuery onlyFirst = p_opt.requested(s_onlyFirst) ? [](const CdoModule &mod) -> bool { return mod.get_pos_restriction() == OnlyFirst; } : defaultModuleQuery; // clang-format on - operator_print_list( - [&](module_t &mod) { return (hasObase(mod) || hasArb(mod) || hasNoOut(mod) || filesOnly(mod) || onlyFirst(mod)); }); + operator_print_list([&](const CdoModule &mod) { + return (hasObase(mod) || hasArb(mod) || hasNoOut(mod) || filesOnly(mod) || onlyFirst(mod)); + }); } reset_text_color(stderr); return; } + +std::vector<std::string> +get_no_output_operator_list() +{ + std::vector<std::string> names; + auto &factory = Factory::get(); + for (auto &factory_entry : factory) + { + auto &module = Factory::get_module(factory_entry.first); + if (module.mode == 1 && module.constraints.streamOutCnt == 0) { names.push_back(factory_entry.first); } + } + std::sort(names.begin(), names.end()); + + return names; +} + +void +operatorPrintAll(void) +{ + int number_of_chars = 0; + std::string tab = " "; + int tab_width = tab.size(); + // using a set because it sorts the operators alphabetically on its own + std::vector<std::string> sorted_operator_names = Factory::get_sorted_operator_name_list(); + + std::cout << tab; + for (const auto &operatorName : sorted_operator_names) + { + if (number_of_chars > 85) + { + number_of_chars = tab_width; + std::cerr << std::endl << tab; + } + + std::cerr << " " << operatorName; + number_of_chars += 1 + operatorName.size(); + } + + std::cerr << std::endl; +} + +void +operator_print_list(bool print_no_output) +{ + std::vector<std::string> output_list = print_no_output ? get_no_output_operator_list() : Factory::get_sorted_operator_name_list(); + + auto list_length = output_list.size(); + + // help variables + + for (size_t out_list_idx = 0; out_list_idx < list_length; out_list_idx++) + { + const std::string current_op_name = output_list[out_list_idx]; + auto ¤t_module = Factory::get_module(current_op_name); + if (current_module.is_alias(current_op_name) != -1) + { + output_list[out_list_idx] += get_spacing_for(16, current_op_name) + "--> " + Factory::get_original(current_op_name); + } + else if (current_module.get_help(current_op_name).empty()) + { + // add spaceing and saving output line to the output list + auto description = get_operator_description(current_op_name, current_module.get_help(current_op_name)); + output_list[out_list_idx] += get_spacing_for(16, current_op_name) + description; + } + std::string in_out_info = " (" + std::to_string(current_module.constraints.streamOutCnt) + "|" + + std::to_string(current_module.constraints.streamOutCnt) + ")"; + output_list[out_list_idx] += get_spacing_for(90, output_list[out_list_idx]) + in_out_info; + } + // print generated output list + for (const std::string &str : output_list) { std::cout << str << std::endl; } +} + +void +cdo_print_help(const CdoHelp &p_help) +{ + if (p_help.empty()) + fprintf(stderr, "No help available for this operator!\n"); + else + { + for (size_t i = 0; i < p_help.size(); ++i) + { + auto doPrint = !(p_help[i][0] == '\0' && p_help[i + 1][0] == ' '); + if (doPrint) + { + + //=========================================================================== + // This is necessary as long as we use fprintf. + // Without the string we cant use c_str and as such fprintf throws a seqfault + // As (14.11.2023) CdoHelp is a vector<string_view> and string_view does not + // provide a .c_str() + std::string line = std::string(p_help[i]); + //=========================================================================== + + if (color_enabled()) + { + if (cdo_cmpstr(line, "NAME") || cdo_cmpstr(line, "SYNOPSIS") || cdo_cmpstr(line, "DESCRIPTION") + || cdo_cmpstr(line, "OPERATORS") || cdo_cmpstr(line, "NAMELIST") || cdo_cmpstr(line, "PARAMETER") + || cdo_cmpstr(line, "ENVIRONMENT") || cdo_cmpstr(line, "NOTE") || cdo_cmpstr(line, "EXAMPLES")) + { + set_text_color(stdout, BRIGHT); + fprintf(stdout, "%s", line.c_str()); + reset_text_color(stdout); + fprintf(stdout, "\n"); + } + else + fprintf(stdout, "%s\n", line.c_str()); + } + else { fprintf(stdout, "%s\n", line.c_str()); } + } + } + } +} diff --git a/src/module_info.h b/src/module_info.h index b960537481bc97227be83eb19cd99603c7af0518..792df2da214d402fd5f002bc97a887674506da40 100644 --- a/src/module_info.h +++ b/src/module_info.h @@ -3,6 +3,9 @@ #include <string> #include <map> +#include <vector> + +#include "operator_help.h" // for CdoHelp const std::string s_obase = "obase"; const std::string s_arbIn = "arbitrary"; @@ -22,5 +25,9 @@ struct ModListOptions bool parse_request(const std::string &requestString); }; +std::string get_operator_description(const std::string &p_current_op_name, const std::vector<std::string> &p_help); void operator_print_list(ModListOptions &p_modListOpt); + +void cdo_print_help(const char **help); +void cdo_print_help(const CdoHelp &p_help); #endif diff --git a/src/module_list.h b/src/module_list.h index 42f7b8f2ff683c40f0e940aa1aa048b76d84307f..5a9ff4292c357e5da71dd89bf4913ec3dfc6e0d5 100644 --- a/src/module_list.h +++ b/src/module_list.h @@ -1,325 +1,324 @@ - -#ifndef MODULE_LIST_H -#define MODULE_LIST_H - -#include "cdi.h" -#include "modules.h" -#include "module_definitions.h" -#include "operator_help.h" - +//#ifndef MODULE_LIST_H +//#define MODULE_LIST_H +// +//#include "cdi.h" +//#include "modules.h" +//#include "module_definitions.h" +//#include "operator_help.h" +// // clang-format off - -#define NO_HELP {} - -// FuncName Function Help OperatorList internal RestrictionType -// | | | | | cdi-numbertype | -// | | | | | | in out | -// | | | | | | | | | -static const module_t module_Adisit = {"Adisit" ,Adisit , AdisitHelp , AdisitOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Afterburner = {"Afterburner" ,Afterburner , AfterburnerHelp , AfterburnerOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction, {Alias ("afterburner", "after")}}; -static const module_t module_Arith = {"Arith" ,Arith , ArithHelp , ArithOperators , EXPOSED , CDI_BOTH , 2 , 1 , NoRestriction }; -static const module_t module_Arithc = {"Arithc" ,Arithc , ArithcHelp , ArithcOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Arithdays = {"Arithdays" ,Arithdays , ArithdaysHelp , ArithdaysOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Arithlat = {"Arithlat" ,Arithlat , ArithlatHelp , ArithlatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Apply = {"Apply" ,nullptr , ApplyHelp , {"apply"} , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Bitrounding = {"Bitrounding" ,Bitrounding , BitroundingHelp , BitroundingOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Cat = {"Cat" ,Cat , CopyHelp , CatOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_CDItest = {"CDItest" ,CDItest , NO_HELP , CDItestOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_CDIread = {"CDIread" ,CDIread , NO_HELP , CDIreadOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; -static const module_t module_CDIwrite = {"CDIwrite" ,CDIwrite , NO_HELP , CDIwriteOperators , EXPOSED , CDI_REAL , 0 , 1 , NoRestriction }; -static const module_t module_Change = {"Change" ,Change , ChangeHelp , ChangeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("chvar", "chname")} }; -static const module_t module_Change_e5slm = {"Change_e5slm" ,Change_e5slm , NO_HELP , Change_e5slmOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Cloudlayer = {"Cloudlayer" ,Cloudlayer , NO_HELP , CloudlayerOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_CMOR = {"CMOR" ,CMOR , CMORHelp , CMOROperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; -static const module_t module_CMOR_lite = {"CMORlite" ,CMOR_lite , CMORliteHelp , CMORliteOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_CMOR_table = {"CMORtable" ,CMOR_table , NO_HELP , CMORtableOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; -static const module_t module_Collgrid = {"Collgrid" ,Collgrid , CollgridHelp , CollgridOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_Command = {"Command" ,Command , NO_HELP , CommandOperators , INTERNAL , CDI_REAL , 1 , 0 , NoRestriction }; -static const module_t module_Comp = {"Comp" ,Comp , CompHelp , CompOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Compc = {"Compc" ,Compc , CompcHelp , CompcOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Complextorect = {"Complextorect" ,Complextorect , NO_HELP , ComplextorectOperators , EXPOSED , CDI_COMP , 1 , 2 , OnlyFirst }; -static const module_t module_Cond = {"Cond" ,Cond , CondHelp , CondOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Cond2 = {"Cond2" ,Cond2 , Cond2Help , Cond2Operators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Condc = {"Condc" ,Condc , CondcHelp , CondcOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Consecstat = {"Consecstat" ,Consecstat , ConsecstatHelp , ConsecstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Copy = {"Copy" ,Copy , CopyHelp , CopyOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_DCW_util = {"DCW_util" ,DCW_util , NO_HELP , DCW_utilOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; -static const module_t module_Dayarith = {"Dayarith" ,Dayarith , DayarithHelp , DayarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Deltat = {"Deltat" ,Deltat , DeltatHelp , DeltatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Deltime = {"Deltime" ,Deltime , NO_HELP , DeltimeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Depth = {"Depth" ,Depth , NO_HELP , DepthOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Derivepar = {"Derivepar" ,Derivepar , DeriveparHelp , DeriveparOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction , {Alias ("geopotheight", "gheight")}}; -static const module_t module_Detrend = {"Detrend" ,Detrend , DetrendHelp , DetrendOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Diff = {"Diff" ,Diff , DiffHelp , DiffOperators , EXPOSED , CDI_BOTH , 2 , 0 , NoRestriction, {Alias ("diffv", "diffn")}}; -static const module_t module_Distgrid = {"Distgrid" ,Distgrid , DistgridHelp , DistgridOperators , EXPOSED , CDI_REAL , 1 , OBASE , NoRestriction }; -static const module_t module_Duplicate = {"Duplicate" ,Duplicate , DuplicateHelp , DuplicateOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Echam5ini = {"Echam5ini" ,Echam5ini , NO_HELP , Echam5iniOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Enlarge = {"Enlarge" ,Enlarge , EnlargeHelp , EnlargeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Enlargegrid = {"Enlargegrid" ,Enlargegrid , NO_HELP , EnlargegridOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Ensstat = {"Ensstat" ,Ensstat , EnsstatHelp , EnsstatOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_Ensstat3 = {"Ensstat3" ,Ensstat3 , Ensstat2Help , Ensstat3Operators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_Ensval = {"Ensval" ,Ensval , EnsvalHelp , EnsvalOperators , EXPOSED , CDI_REAL , -1 , OBASE , NoRestriction }; -static const module_t module_Eofcoeff = {"Eofcoeff" ,Eofcoeff , EofcoeffHelp , EofcoeffOperators , EXPOSED , CDI_REAL , 2 , OBASE , NoRestriction }; -static const module_t module_Eofcoeff3d = {"Eofcoeff3d" ,Eofcoeff3d , EofcoeffHelp , Eofcoeff3dOperators , EXPOSED , CDI_REAL , 2 , OBASE , NoRestriction }; -static const module_t module_EOFs = {"EOFs" ,EOFs , EOFsHelp , EOFsOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; -static const module_t module_EOF3d = {"EOF3d" ,EOF3d , EOFsHelp , EOF3dOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; -static const module_t module_EstFreq = {"EstFreq" ,EstFreq , NO_HELP , EstFreqOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Exprf = {"Exprf" ,Exprf , ExprHelp , ExprfOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_FC = {"FC" ,FC , NO_HELP , FCOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Filedes = {"Filedes" ,Filedes , FiledesHelp , FiledesOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction , {Alias ("vardes", "codetab")}}; -static const module_t module_Fillmiss = {"Fillmiss" ,Fillmiss , NO_HELP , FillmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Filter = {"Filter" ,Filter , FilterHelp , FilterOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Fldrms = {"Fldrms" ,Fldrms , NO_HELP , FldrmsOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Fldstat = {"Fldstat" ,Fldstat , FldstatHelp , FldstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("globavg", "fldavg") }}; -static const module_t module_Fldcor = {"Fldcor" ,Fldstat2 , FldcorHelp , FldcorOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Fldcovar = {"Fldcovar" ,Fldstat2 , FldcovarHelp , FldcovarOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Fourier = {"Fourier" ,Fourier , FourierHelp , FourierOperators , EXPOSED , CDI_COMP , 1 , 1 , NoRestriction }; -static const module_t module_Gengrid = {"Gengrid" ,Gengrid , NO_HELP , GengridOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Getgridcell = {"Getgridcell" ,Getgridcell , GetgridcellHelp , GetgridcellOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction }; -static const module_t module_Gradsdes = {"Gradsdes" ,Gradsdes , GradsdesHelp , GradsdesOperators , EXPOSED , CDI_REAL , 1 , 0 , FilesOnly }; -static const module_t module_Gridboxstat = {"Gridboxstat" ,Gridboxstat , GridboxstatHelp , GridboxstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Gridcell = {"Gridcell" ,Gridcell , GridcellHelp , GridcellOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Gridsearch = {"Gridsearch" ,Gridsearch , NO_HELP , GridsearchOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; -static const module_t module_Harmonic = {"Harmonic" ,Harmonic , NO_HELP , HarmonicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Healpix = {"Healpix" ,Healpix , HealpixHelp , HealpixOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Histogram = {"Histogram" ,Histogram , HistogramHelp , HistogramOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Importamsr = {"Importamsr" ,Importamsr , ImportamsrHelp , ImportamsrOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Importbinary = {"Importbinary" ,Importbinary , ImportbinaryHelp , ImportbinaryOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("import_grads", "import_binary")} }; -static const module_t module_Importcmsaf = {"Importcmsaf" ,Importcmsaf , ImportcmsafHelp , ImportcmsafOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Importobs = {"Importobs" ,Importobs , NO_HELP , ImportobsOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Importfv3grid = {"Importfv3grid" ,Importfv3grid , NO_HELP , Importfv3gridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Info = {"Info" ,Info , InfoHelp , InfoOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction }; -static const module_t module_Input = {"Input" ,Input , InputHelp , InputOperators , EXPOSED , CDI_REAL , 0 , 1 , NoRestriction }; -static const module_t module_Intgrid = {"Intgrid" ,Intgrid , NO_HELP , IntgridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction , {Alias ("intgrid", "intgridbil")}}; -static const module_t module_Intgridtraj = {"Intgridtraj" ,Intgridtraj , NO_HELP , IntgridtrajOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Intlevel = {"Intlevel" ,Intlevel , IntlevelHelp , IntlevelOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Intlevel3d = {"Intlevel3d" ,Intlevel3d , Intlevel3dHelp , Intlevel3dOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Inttime = {"Inttime" ,Inttime , InttimeHelp , InttimeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Intntime = {"Intntime" ,Intntime , InttimeHelp , IntntimeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Intyear = {"Intyear" ,Intyear , IntyearHelp , IntyearOperators , EXPOSED , CDI_REAL , 2 , OBASE , NoRestriction }; -static const module_t module_Invert = {"Invert" ,Invert , InvertHelp , InvertOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Invertlev = {"Invertlev" ,Invertlev , InvertlevHelp , InvertlevOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Selsurface = {"Selsurface" ,Selsurface , SelsurfaceHelp , SelsurfaceOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Lic = {"Lic" ,Lic , NO_HELP , LicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Longnfo = {"Longinfo" ,Longinfo , NO_HELP , LonginfoOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; -static const module_t module_MapReduce = {"MapReduce" ,MapReduce , MapReduceHelp , MapReduceOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Maskbox = {"Maskbox" ,Maskbox , MaskboxHelp , MaskboxOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Maskregion = {"Maskregion" ,Maskbox , MaskregionHelp , MaskregionOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Mastrfu = {"Mastrfu" ,Mastrfu , MastrfuHelp , MastrfuOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Math = {"Math" ,Math , MathHelp , MathOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction, {Alias ("log", "ln")} }; -static const module_t module_Merge = {"Merge" ,Merge , MergeHelp , MergeOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_Mergetime = {"Mergetime" ,Mergetime , MergeHelp , MergetimeOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_Mergegrid = {"Mergegrid" ,Mergegrid , MergegridHelp , MergegridOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Merstat = {"Merstat" ,Merstat , MerstatHelp , MerstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Monarith = {"Monarith" ,Monarith , MonarithHelp , MonarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Mrotuv = {"Mrotuv" ,Mrotuv , NO_HELP , MrotuvOperators , EXPOSED , CDI_REAL , 1 , 2 , NoRestriction }; -static const module_t module_Mrotuvb = {"Mrotuvb" ,Mrotuvb , MrotuvbHelp , MrotuvbOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_NCL_wind = {"NCL_wind" ,NCL_wind , NCL_windHelp , NCL_windOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Ninfo = {"Ninfo" ,Ninfo , NinfoHelp , NinfoOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction, {Alias ("nvar", "npar")} }; -static const module_t module_Nmldump = {"Nmldump" ,Nmldump , NO_HELP , NmldumpOperators , INTERNAL , CDI_REAL , 0 , 0 , NoRestriction }; -static const module_t module_Output = {"Output" ,Output , OutputHelp , OutputOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction }; -static const module_t module_Outputtab = {"Outputtab" ,Output , OutputtabHelp , OutputtabOperators , EXPOSED , CDI_REAL , -1 , 0 , NoRestriction, {Alias ("outputkey", "outputtab")} }; -static const module_t module_Outputgmt = {"Outputgmt" ,Outputgmt , OutputgmtHelp , OutputgmtOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction, {Alias ("outputcenter", "gmtxyz"), Alias("outputbounds", "gmtcells")} }; -static const module_t module_Pack = {"Pack" ,Pack , PackHelp , PackOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Pardup = {"Pardup" ,Pardup , NO_HELP , PardupOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Pinfo = {"Pinfo" ,Pinfo , NO_HELP , PinfoOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Query = {"Query" ,Query , NO_HELP , QueryOperators , EXPOSED , CDI_REAL , 1 , 1 , FilesOnly }; -static const module_t module_Pressure = {"Pressure" ,Pressure , NO_HELP , PressureOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("deltap_fl","deltap"),Alias("fpressure", "pressure_fl"), Alias("hpressure", "pressure_hl")}}; -static const module_t module_Recttocomplex = {"Recttocomplex" ,Recttocomplex , NO_HELP , RecttocomplexOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Regres = {"Regres" ,Regres , RegresHelp , RegresOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remap = {"Remap" ,Remapgrid , RemapHelp , RemapOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapbil = {"Remapbil" ,Remapgrid , RemapbilHelp , RemapbilOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapbic = {"Remapbic" ,Remapgrid , RemapbicHelp , RemapbicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapnn = {"Remapnn" ,Remapgrid , RemapnnHelp , RemapnnOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapdis = {"Remapdis" ,Remapgrid , RemapdisHelp , RemapdisOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapcon = {"Remapcon" ,Remapgrid , RemapconHelp , RemapconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("remapycon", "remapcon")} }; -static const module_t module_Remapycon2 = {"Remapycon2" ,Remapgrid , NO_HELP , Remapycon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapscon = {"Remapscon" ,Remapgrid , NO_HELP , RemapsconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapscon2 = {"Remapscon2" ,Remapgrid , NO_HELP , Remapscon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remaplaf = {"Remaplaf" ,Remapgrid , RemaplafHelp , RemaplafOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapavg = {"Remapavg" ,Remapgrid , NO_HELP , RemapavgOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Genbil = {"Genbil" ,Remapweights , RemapbilHelp , GenbilOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Genbic = {"Genbic" ,Remapweights , RemapbicHelp , GenbicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Gennn = {"Gennn" ,Remapweights , RemapnnHelp , GennnOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Gendis = {"Gendis" ,Remapweights , RemapdisHelp , GendisOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Gencon = {"Gencon" ,Remapweights , RemapconHelp , GenconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias("genycon", "gencon")} }; -static const module_t module_Genycon2 = {"Genycon2" ,Remapweights , NO_HELP , Genycon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Genscon = {"Genscon" ,Remapweights , NO_HELP , GensconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Genscon2 = {"Genscon2" ,Remapweights , NO_HELP , Genscon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Genlaf = {"Genlaf" ,Remapweights , RemaplafHelp , GenlafOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapstat = {"Remapstat" ,Remapstat , RemapstatHelp , RemapstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Remapeta = {"Remapeta" ,Remapeta , RemapetaHelp , RemapetaOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Replace = {"Replace" ,Replace , ReplaceHelp , ReplaceOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Replacevalues = {"Replacevalues" ,Replacevalues , ReplacevaluesHelp , ReplacevaluesOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Rhopot = {"Rhopot" ,Rhopot , RhopotHelp , RhopotOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Rotuv = {"Rotuv" ,Rotuv , RotuvbHelp , RotuvOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Runpctl = {"Runpctl" ,Runpctl , RunpctlHelp , RunpctlOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Runstat = {"Runstat" ,Runstat , RunstatHelp , RunstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Samplegridicon = {"Samplegridicon" ,Samplegridicon , NO_HELP , SamplegridiconOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; -static const module_t module_Seascount = {"Seascount" ,Seascount , NO_HELP , SeascountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Seaspctl = {"Seaspctl" ,Seaspctl , SeaspctlHelp , SeaspctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Seasstat = {"Seasstat" ,Seasstat , SeasstatHelp , SeasstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Seasmonstat = {"Seasmonstat" ,Seasmonstat , NO_HELP , SeasmonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Selbox = {"Selbox" ,Selbox , SelboxHelp , SelboxOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Selgridcell = {"Selgridcell" ,Selgridcell , SelgridcellHelp , SelgridcellOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Select = {"Select" ,Select , SelectHelp , SelectOperators , EXPOSED , CDI_BOTH , -1 , 1 , NoRestriction }; -static const module_t module_Selvar = {"Selvar" ,Selvar , SelvarHelp , SelvarOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction, {Alias ("selvar", "selname"), Alias("delvar" , "delname"),Alias("selgridname" , "selgrid")} }; -static const module_t module_Selrec = {"Selrec" ,Selrec , SelvarHelp , SelrecOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Selregion = {"Selregion" ,Selregion , SelregionHelp , SelregionOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Seloperator = {"Seloperator" ,Seloperator , NO_HELP , SeloperatorOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Seltime = {"Seltime" ,Seltime , SeltimeHelp , SeltimeOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction, {Alias ("selseas", "selseason"), Alias("selmon", "selmonth")} }; -static const module_t module_Selyearidx = {"Selyearidx" ,Selyearidx , SelyearidxHelp , SelyearidxOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Set = {"Set" ,Set , SetHelp , SetOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction , {Alias ("setvar", "setname")}}; -static const module_t module_Setattribute = {"Setattribute" ,Setattribute , SetattributeHelp , SetattributeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Setbox = {"Setbox" ,Setbox , SetboxHelp , SetboxOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Setgrid = {"Setgrid" ,Setgrid , SetgridHelp , SetgridOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Setgridcell = {"Setgridcell" ,Setgridcell , SetgridcellHelp , SetgridcellOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Sethalo = {"Sethalo" ,Sethalo , SethaloHelp , SethaloOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Setmiss = {"Setmiss" ,Setmiss , SetmissHelp , SetmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Setmisstonn = {"Setmisstonn" ,Fillmiss , SetmissHelp , SetmisstonnOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Setcodetab = {"Setcodetab" ,Setpartab , SetHelp , SetcodetabOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction , {Alias ("setpartab", "setcodetab")}}; -static const module_t module_Setpartab = {"Setpartab" ,Setpartab , SetpartabHelp , SetpartabOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("setpartabv", "setpartabn")} }; -static const module_t module_Setrcaname = {"Setrcaname" ,Setrcaname , NO_HELP , SetrcanameOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Settime = {"Settime" ,Settime , SettimeHelp , SettimeOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Setzaxis = {"Setzaxis" ,Setzaxis , SetzaxisHelp , SetzaxisOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Shiftxy = {"Shiftxy" ,Shiftxy , ShiftxyHelp , ShiftxyOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Showinfo = {"Showinfo" ,Showinfo , ShowinfoHelp , ShowinfoOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction , {Alias ("showvar", "showname")} }; -static const module_t module_Showattribute = {"Showattribute" ,Showattribute , ShowattributeHelp , ShowattributeOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; -static const module_t module_Sinfo = {"Sinfo" ,Sinfo , SinfoHelp , SinfoOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction, {Alias ("infov", "infon"),Alias("sinfov", "sinfon")} }; -static const module_t module_XSinfo = {"XSinfo" ,Sinfo , XSinfoHelp , XSinfoOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction }; -static const module_t module_Smooth = {"Smooth" ,Smooth , SmoothHelp , SmoothOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Sort = {"Sort" ,Sort , NO_HELP , SortOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("sortvar", "sortname")} }; -static const module_t module_Sorttimestamp = {"Sorttimestamp" ,Sorttimestamp , NO_HELP , SorttimestampOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -static const module_t module_Specinfo = {"Specinfo" ,Specinfo , NO_HELP , SpecinfoOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; -static const module_t module_Spectral = {"Spectral" ,Spectral , SpectralHelp , SpectralOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Specconv = {"Specconv" ,Spectral , SpecconvHelp , SpecconvOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Spectrum = {"Spectrum" ,Spectrum , NO_HELP , SpectrumOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Split = {"Split" ,Split , SplitHelp , SplitOperators , EXPOSED , CDI_BOTH , 1 , OBASE , NoRestriction, {Alias ("splitvar", "splitname")} }; -static const module_t module_Splitdate = {"Splitdate" ,Splitdate , SplitdateHelp , SplitdateOperators , EXPOSED , CDI_BOTH , 1 , OBASE , OnlyFirst }; -static const module_t module_Splitrec = {"Splitrec" ,Splitrec , SplitHelp , SplitrecOperators , EXPOSED , CDI_BOTH , 1 , OBASE , NoRestriction }; -static const module_t module_Splitsel = {"Splitsel" ,Splitsel , SplitselHelp , SplitselOperators , EXPOSED , CDI_BOTH , 1 , OBASE , OnlyFirst }; -static const module_t module_Splittime = {"Splittime" ,Splittime , SplittimeHelp , SplittimeOperators , EXPOSED , CDI_BOTH , 1 , OBASE , OnlyFirst }; -static const module_t module_Splityear = {"Splityear" ,Splityear , SplittimeHelp , SplityearOperators , EXPOSED , CDI_BOTH , 1 , OBASE , NoRestriction }; -static const module_t module_Tee = {"Tee" ,Tee , TeeHelp , TeeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Testdata = {"Testdata" ,Testdata , NO_HELP , TestdataOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Tests = {"Tests" ,Tests , NO_HELP , TestsOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Timcount = {"Timcount" ,Timcount , NO_HELP , TimcountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Yearcount = {"Yearcount" ,Timcount , NO_HELP , YearcountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Moncount = {"Moncount" ,Timcount , NO_HELP , MoncountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Daycount = {"Daycount" ,Timcount , NO_HELP , DaycountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Hourcount = {"Hourcount" ,Timcount , NO_HELP , HourcountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Timcumsum = {"Timcumsum" ,Timcumsum , TimcumsumHelp , TimcumsumOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Timpctl = {"Timpctl" ,Timpctl , TimpctlHelp , TimpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Yearpctl = {"Yearpctl" ,Timpctl , YearpctlHelp , YearpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Monpctl = {"Monpctl" ,Timpctl , MonpctlHelp , MonpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Daypctl = {"Daypctl" ,Timpctl , DaypctlHelp , DaypctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Hourpctl = {"Hourpctl" ,Timpctl , HourpctlHelp , HourpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Timselpctl = {"Timselpctl" ,Timselpctl , TimselpctlHelp , TimselpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Timfillmiss = {"Timfillmiss" ,Timfillmiss , TimfillmissHelp , TimfillmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Timsort = {"Timsort" ,Timsort , TimsortHelp , TimsortOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("sort", "timsort")} }; -static const module_t module_Timselstat = {"Timselstat" ,Timselstat , TimselstatHelp , TimselstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_XTimstat = {"XTimstat" ,XTimstat , NO_HELP , XTimstatOperators , INTERNAL , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Timstat = {"Timstat" ,Timstat , TimstatHelp , TimstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Yearstat = {"Yearstat" ,Timstat , YearstatHelp , YearstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Monstat = {"Monstat" ,Timstat , MonstatHelp , MonstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Daystat = {"Daystat" ,Timstat , DaystatHelp , DaystatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Hourstat = {"Hourstat" ,Timstat , HourstatHelp , HourstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; -static const module_t module_Timcor = {"Timcor" ,Timstat2 , TimcorHelp , TimcorOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Timcovar = {"Timcovar" ,Timstat2 , TimcovarHelp , TimcovarOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Timrmsd = {"Timrmsd" ,Timstat2 , NO_HELP , TimrmsdOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Timstat3 = {"Timstat3" ,Timstat3 , NO_HELP , Timstat3Operators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Tinfo = {"Tinfo" ,Tinfo , NO_HELP , TinfoOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction }; -static const module_t module_Tocomplex = {"Tocomplex" ,Tocomplex , NO_HELP , TocomplexOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Transpose = {"Transpose" ,Transpose , NO_HELP , TransposeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Trend = {"Trend" ,Trend , TrendHelp , TrendOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; -static const module_t module_Trendarith = {"Trendarith" ,Trendarith , TrendarithHelp , TrendarithOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Tstepcount = {"Tstepcount" ,Tstepcount , NO_HELP , TstepcountOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Unpack = {"Unpack" ,Unpack , UnpackHelp , UnpackOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vargen = {"Vargen" ,Vargen , VargenHelp , VargenOperators , EXPOSED , CDI_REAL , 0 , 1 , NoRestriction, {Alias ("for", "seq")} }; -static const module_t module_Varrms = {"Varrms" ,Varrms , NO_HELP , VarrmsOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Varsstat = {"Varsstat" ,Varsstat , VarsstatHelp , VarsstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertfillmiss = {"Vertfillmiss" ,Vertfillmiss , VertfillmissHelp , VertfillmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertintap = {"Vertintap" ,Vertintap , VertintapHelp , VertintapOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertintgh = {"Vertintgh" ,Vertintgh , VertintghHelp , VertintghOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertintml = {"Vertintml" ,Vertintml , VertintmlHelp , VertintmlOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertintzs = {"Vertintzs" ,Vertintzs , NO_HELP , VertintzsOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertstat = {"Vertstat" ,Vertstat , VertstatHelp , VertstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertcum = {"Vertcum" ,Vertcum , NO_HELP , VertcumOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Vertwind = {"Vertwind" ,Vertwind , NO_HELP , VertwindOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Verifygrid = {"Verifygrid" ,Verifygrid , VerifygridHelp , VerifygridOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; -static const module_t module_Verifyweights = {"Verifyweights" ,Verifyweights , NO_HELP , VerifyweightsOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; -static const module_t module_Wind = {"Wind" ,Wind , WindHelp , WindOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Wind2 = {"Wind2" ,Wind , Wind2Help , Wind2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Writegrid = {"Writegrid" ,Writegrid , NO_HELP , WritegridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Writerandom = {"Writerandom" ,Writerandom , NO_HELP , WriterandomOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Yeararith = {"Yeararith" ,Yeararith , YeararithHelp , YeararithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Yearmonstat = {"Yearmonstat" ,Yearmonstat , YearmonstatHelp , YearmonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Ydayarith = {"Ydayarith" ,Ydayarith , YdayarithHelp , YdayarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Ydaypctl = {"Ydaypctl" ,Ydaypctl , YdaypctlHelp , YdaypctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Ydaystat = {"Ydaystat" ,Ydaystat , YdaystatHelp , YdaystatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Ydrunpctl = {"Ydrunpctl" ,Ydrunpctl , YdrunpctlHelp , YdrunpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Ydrunstat = {"Ydrunstat" ,Ydrunstat , YdrunstatHelp , YdrunstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Yhourarith = {"Yhourarith" ,Yhourarith , YhourarithHelp , YhourarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Yhourstat = {"Yhourstat" ,Yhourstat , YhourstatHelp , YhourstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Dhourstat = {"Dhourstat" ,Yhourstat , DhourstatHelp , DhourstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Ymonarith = {"Ymonarith" ,Ymonarith , YmonarithHelp , YmonarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction, {Alias ("anomaly","ymonsub")}}; -static const module_t module_Yseasarith = {"Yseasarith" ,Ymonarith , YseasarithHelp , YseasarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Ymoncomp = {"Ymoncomp" ,Ymoncomp , YmoncompHelp , YmoncompOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Yseascomp = {"Yseascomp" ,Ymoncomp , NO_HELP , YseascompOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Ymonpctl = {"Ymonpctl" ,Ymonpctl , YmonpctlHelp , YmonpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Ymonstat = {"Ymonstat" ,Ymonstat , YmonstatHelp , YmonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Yseaspctl = {"Yseaspctl" ,Yseaspctl , YseaspctlHelp , YseaspctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Yseasstat = {"Yseasstat" ,Yseasstat , YseasstatHelp , YseasstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Zonstat = {"Zonstat" ,Zonstat , ZonstatHelp , ZonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaCfd = {"EcaCfd" ,EcaCfd , EcaCfdHelp , EcaCfdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaCsu = {"EcaCsu" ,EcaCsu , EcaCsuHelp , EcaCsuOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaCwdi = {"EcaCwdi" ,EcaCwdi , EcaCwdiHelp , EcaCwdiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaCwfi = {"EcaCwfi" ,EcaCwfi , EcaCwfiHelp , EcaCwfiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaEtr = {"EcaEtr" ,EcaEtr , EcaEtrHelp , EcaEtrOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaEtccdi = {"EcaEtccdi" ,EcaEtccdi , EcaEtccdiHelp , EcaEtccdiOperators , EXPOSED , CDI_REAL , 3 , 1 , FilesOnly }; -static const module_t module_EcaFd = {"EcaFd" ,EcaFd , EcaFdHelp , EcaFdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaGsl = {"EcaGsl" ,EcaGsl , EcaGslHelp , EcaGslOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaHd = {"EcaHd" ,EcaHd , EcaHdHelp , EcaHdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaHwdi = {"EcaHwdi" ,EcaHwdi , EcaHwdiHelp , EcaHwdiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaHwfi = {"EcaHwfi" ,EcaHwfi , EcaHwfiHelp , EcaHwfiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaId = {"EcaId" ,EcaId , EcaIdHelp , EcaIdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaSu = {"EcaSu" ,EcaSu , EcaSuHelp , EcaSuOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaTr = {"EcaTr" ,EcaTr , EcaTrHelp , EcaTrOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaTg10p = {"EcaTg10p" ,EcaTg10p , EcaTg10pHelp , EcaTg10pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaTg90p = {"EcaTg90p" ,EcaTg90p , EcaTg90pHelp , EcaTg90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaTn10p = {"EcaTn10p" ,EcaTn10p , EcaTn10pHelp , EcaTn10pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaTn90p = {"EcaTn90p" ,EcaTn90p , EcaTn90pHelp , EcaTn90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaTx10p = {"EcaTx10p" ,EcaTx10p , EcaTx10pHelp , EcaTx10pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaTx90p = {"EcaTx90p" ,EcaTx90p , EcaTx90pHelp , EcaTx90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaCdd = {"EcaCdd" ,EcaCdd , EcaCddHelp , EcaCddOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaCwd = {"EcaCwd" ,EcaCwd , EcaCwdHelp , EcaCwdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaRr1 = {"EcaRr1" ,EcaRr1 , EcaRr1Help , EcaRr1Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("eca_r1mm", "eca_rr1")} }; -static const module_t module_EcaPd = {"EcaPd" ,EcaPd , EcaPdHelp , EcaPdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaR75p = {"EcaR75p" ,EcaR75p , EcaR75pHelp , EcaR75pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaR75ptot = {"EcaR75ptot" ,EcaR75ptot , EcaR75ptotHelp , EcaR75ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaR90p = {"EcaR90p" ,EcaR90p , EcaR90pHelp , EcaR90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaR90ptot = {"EcaR90ptot" ,EcaR90ptot , EcaR90ptotHelp , EcaR90ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaR95p = {"EcaR95p" ,EcaR95p , EcaR95pHelp , EcaR95pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaR95ptot = {"EcaR95ptot" ,EcaR95ptot , EcaR95ptotHelp , EcaR95ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaR99p = {"EcaR99p" ,EcaR99p , EcaR99pHelp , EcaR99pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaR99ptot = {"EcaR99ptot" ,EcaR99ptot , EcaR99ptotHelp , EcaR99ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_EcaRx1day = {"EcaRx1day" ,EcaRx1day , EcaRx1dayHelp , EcaRx1dayOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaRx5day = {"EcaRx5day" ,EcaRx5day , EcaRx5dayHelp , EcaRx5dayOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_EcaSdii = {"EcaSdii" ,EcaSdii , EcaSdiiHelp , EcaSdiiOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Fdns = {"Fdns" ,Fdns , FdnsHelp , FdnsOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Strwin = {"Strwin" ,Strwin , StrwinHelp , StrwinOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Strbre = {"Strbre" ,Strbre , StrbreHelp , StrbreOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Strgal = {"Strgal" ,Strgal , StrgalHelp , StrgalOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Hurr = {"Hurr" ,Hurr , HurrHelp , HurrOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -//static const module_t module_Hi = {"Hi" , Hi , NO_HELP , HiOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; -static const module_t module_Wct = {"Wct" ,Wct , WctHelp , WctOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; -static const module_t module_Magplot = {"Magplot" ,Magplot , MagplotHelp , MagplotOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Magvector = {"Magvector" ,Magvector , MagvectorHelp , MagvectorOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Maggraph = {"Maggraph" ,Maggraph , MaggraphHelp , MaggraphOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; -// HIRLAM_EXTENSIONS {" -static const module_t module_Samplegrid = {"Samplegrid" ,Samplegrid , SamplegridHelp , SamplegridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_Selmulti = {"Selmulti" ,Selmulti , SelmultiHelp , SelmultiOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -static const module_t module_WindTrans = {"WindTrans" ,WindTrans , WindTransHelp , WindTransOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; -// clang-format on - -#endif +// +//#define NO_HELP {} +// +//// FuncName Function Help OperatorList internal RestrictionType +//// | | | | | cdi-numbertype | +//// | | | | | | in out | +//// | | | | | | | | | +//static const module_t module_Adisit = {"Adisit" ,Adisit , AdisitHelp , AdisitOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Afterburner = {"Afterburner" ,Afterburner , AfterburnerHelp , AfterburnerOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction, {Alias ("afterburner", "after")}}; +//static const module_t module_Arith = {"Arith" ,Arith , ArithHelp , ArithOperators , EXPOSED , CDI_BOTH , 2 , 1 , NoRestriction }; +//static const module_t module_Arithc = {"Arithc" ,Arithc , ArithcHelp , ArithcOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Arithdays = {"Arithdays" ,Arithdays , ArithdaysHelp , ArithdaysOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Arithlat = {"Arithlat" ,Arithlat , ArithlatHelp , ArithlatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Apply = {"Apply" ,nullptr , ApplyHelp , {"apply"} , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Bitrounding = {"Bitrounding" ,Bitrounding , BitroundingHelp , BitroundingOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Cat = {"Cat" ,Cat , CopyHelp , CatOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_CDItest = {"CDItest" ,CDItest , NO_HELP , CDItestOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_CDIread = {"CDIread" ,CDIread , NO_HELP , CDIreadOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; +//static const module_t module_CDIwrite = {"CDIwrite" ,CDIwrite , NO_HELP , CDIwriteOperators , EXPOSED , CDI_REAL , 0 , 1 , NoRestriction }; +//static const module_t module_Change = {"Change" ,Change , ChangeHelp , ChangeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("chvar", "chname")} }; +//static const module_t module_Change_e5slm = {"Change_e5slm" ,Change_e5slm , NO_HELP , Change_e5slmOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Cloudlayer = {"Cloudlayer" ,Cloudlayer , NO_HELP , CloudlayerOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_CMOR = {"CMOR" ,CMOR , CMORHelp , CMOROperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; +//static const module_t module_CMOR_lite = {"CMORlite" ,CMOR_lite , CMORliteHelp , CMORliteOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_CMOR_table = {"CMORtable" ,CMOR_table , NO_HELP , CMORtableOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; +//static const module_t module_Collgrid = {"Collgrid" ,Collgrid , CollgridHelp , CollgridOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_Command = {"Command" ,Command , NO_HELP , CommandOperators , INTERNAL , CDI_REAL , 1 , 0 , NoRestriction }; +//static const module_t module_Comp = {"Comp" ,Comp , CompHelp , CompOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Compc = {"Compc" ,Compc , CompcHelp , CompcOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Complextorect = {"Complextorect" ,Complextorect , NO_HELP , ComplextorectOperators , EXPOSED , CDI_COMP , 1 , 2 , OnlyFirst }; +//static const module_t module_Cond = {"Cond" ,Cond , CondHelp , CondOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Cond2 = {"Cond2" ,Cond2 , Cond2Help , Cond2Operators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Condc = {"Condc" ,Condc , CondcHelp , CondcOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Consecstat = {"Consecstat" ,Consecstat , ConsecstatHelp , ConsecstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Copy = {"Copy" ,Copy , CopyHelp , CopyOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_DCW_util = {"DCW_util" ,DCW_util , NO_HELP , DCW_utilOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; +//static const module_t module_Dayarith = {"Dayarith" ,Dayarith , DayarithHelp , DayarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Deltat = {"Deltat" ,Deltat , DeltatHelp , DeltatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Deltime = {"Deltime" ,Deltime , NO_HELP , DeltimeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Depth = {"Depth" ,Depth , NO_HELP , DepthOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Derivepar = {"Derivepar" ,Derivepar , DeriveparHelp , DeriveparOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction , {Alias ("geopotheight", "gheight")}}; +//static const module_t module_Detrend = {"Detrend" ,Detrend , DetrendHelp , DetrendOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Diff = {"Diff" ,Diff , DiffHelp , DiffOperators , EXPOSED , CDI_BOTH , 2 , 0 , NoRestriction, {Alias ("diffv", "diffn")}}; +//static const module_t module_Distgrid = {"Distgrid" ,Distgrid , DistgridHelp , DistgridOperators , EXPOSED , CDI_REAL , 1 , OBASE , NoRestriction }; +//static const module_t module_Duplicate = {"Duplicate" ,Duplicate , DuplicateHelp , DuplicateOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Echam5ini = {"Echam5ini" ,Echam5ini , NO_HELP , Echam5iniOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Enlarge = {"Enlarge" ,Enlarge , EnlargeHelp , EnlargeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Enlargegrid = {"Enlargegrid" ,Enlargegrid , NO_HELP , EnlargegridOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Ensstat = {"Ensstat" ,Ensstat , EnsstatHelp , EnsstatOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_Ensstat3 = {"Ensstat3" ,Ensstat3 , Ensstat2Help , Ensstat3Operators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_Ensval = {"Ensval" ,Ensval , EnsvalHelp , EnsvalOperators , EXPOSED , CDI_REAL , -1 , OBASE , NoRestriction }; +//static const module_t module_Eofcoeff = {"Eofcoeff" ,Eofcoeff , EofcoeffHelp , EofcoeffOperators , EXPOSED , CDI_REAL , 2 , OBASE , NoRestriction }; +//static const module_t module_Eofcoeff3d = {"Eofcoeff3d" ,Eofcoeff3d , EofcoeffHelp , Eofcoeff3dOperators , EXPOSED , CDI_REAL , 2 , OBASE , NoRestriction }; +//static const module_t module_EOFs = {"EOFs" ,EOFs , EOFsHelp , EOFsOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; +//static const module_t module_EOF3d = {"EOF3d" ,EOF3d , EOFsHelp , EOF3dOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; +//static const module_t module_EstFreq = {"EstFreq" ,EstFreq , NO_HELP , EstFreqOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Exprf = {"Exprf" ,Exprf , ExprHelp , ExprfOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_FC = {"FC" ,FC , NO_HELP , FCOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Filedes = {"Filedes" ,Filedes , FiledesHelp , FiledesOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction , {Alias ("vardes", "codetab")}}; +//static const module_t module_Fillmiss = {"Fillmiss" ,Fillmiss , NO_HELP , FillmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Filter = {"Filter" ,Filter , FilterHelp , FilterOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Fldrms = {"Fldrms" ,Fldrms , NO_HELP , FldrmsOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Fldstat = {"Fldstat" ,Fldstat , FldstatHelp , FldstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("globavg", "fldavg") }}; +//static const module_t module_Fldcor = {"Fldcor" ,Fldstat2 , FldcorHelp , FldcorOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Fldcovar = {"Fldcovar" ,Fldstat2 , FldcovarHelp , FldcovarOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Fourier = {"Fourier" ,Fourier , FourierHelp , FourierOperators , EXPOSED , CDI_COMP , 1 , 1 , NoRestriction }; +//static const module_t module_Gengrid = {"Gengrid" ,Gengrid , NO_HELP , GengridOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Getgridcell = {"Getgridcell" ,Getgridcell , GetgridcellHelp , GetgridcellOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction }; +//static const module_t module_Gradsdes = {"Gradsdes" ,Gradsdes , GradsdesHelp , GradsdesOperators , EXPOSED , CDI_REAL , 1 , 0 , FilesOnly }; +//static const module_t module_Gridboxstat = {"Gridboxstat" ,Gridboxstat , GridboxstatHelp , GridboxstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Gridcell = {"Gridcell" ,Gridcell , GridcellHelp , GridcellOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Gridsearch = {"Gridsearch" ,Gridsearch , NO_HELP , GridsearchOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; +//static const module_t module_Harmonic = {"Harmonic" ,Harmonic , NO_HELP , HarmonicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Healpix = {"Healpix" ,Healpix , HealpixHelp , HealpixOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Histogram = {"Histogram" ,Histogram , HistogramHelp , HistogramOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Importamsr = {"Importamsr" ,Importamsr , ImportamsrHelp , ImportamsrOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Importbinary = {"Importbinary" ,Importbinary , ImportbinaryHelp , ImportbinaryOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("import_grads", "import_binary")} }; +//static const module_t module_Importcmsaf = {"Importcmsaf" ,Importcmsaf , ImportcmsafHelp , ImportcmsafOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Importobs = {"Importobs" ,Importobs , NO_HELP , ImportobsOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Importfv3grid = {"Importfv3grid" ,Importfv3grid , NO_HELP , Importfv3gridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Info = {"Info" ,Info , InfoHelp , InfoOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction }; +//static const module_t module_Input = {"Input" ,Input , InputHelp , InputOperators , EXPOSED , CDI_REAL , 0 , 1 , NoRestriction }; +//static const module_t module_Intgrid = {"Intgrid" ,Intgrid , NO_HELP , IntgridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction , {Alias ("intgrid", "intgridbil")}}; +//static const module_t module_Intgridtraj = {"Intgridtraj" ,Intgridtraj , NO_HELP , IntgridtrajOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Intlevel = {"Intlevel" ,Intlevel , IntlevelHelp , IntlevelOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Intlevel3d = {"Intlevel3d" ,Intlevel3d , Intlevel3dHelp , Intlevel3dOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Inttime = {"Inttime" ,Inttime , InttimeHelp , InttimeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Intntime = {"Intntime" ,Intntime , InttimeHelp , IntntimeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Intyear = {"Intyear" ,Intyear , IntyearHelp , IntyearOperators , EXPOSED , CDI_REAL , 2 , OBASE , NoRestriction }; +//static const module_t module_Invert = {"Invert" ,Invert , InvertHelp , InvertOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Invertlev = {"Invertlev" ,Invertlev , InvertlevHelp , InvertlevOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Selsurface = {"Selsurface" ,Selsurface , SelsurfaceHelp , SelsurfaceOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Lic = {"Lic" ,Lic , NO_HELP , LicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Longnfo = {"Longinfo" ,Longinfo , NO_HELP , LonginfoOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; +//static const module_t module_MapReduce = {"MapReduce" ,MapReduce , MapReduceHelp , MapReduceOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Maskbox = {"Maskbox" ,Maskbox , MaskboxHelp , MaskboxOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Maskregion = {"Maskregion" ,Maskbox , MaskregionHelp , MaskregionOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Mastrfu = {"Mastrfu" ,Mastrfu , MastrfuHelp , MastrfuOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Math = {"Math" ,Math , MathHelp , MathOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction, {Alias ("log", "ln")} }; +//static const module_t module_Merge = {"Merge" ,Merge , MergeHelp , MergeOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_Mergetime = {"Mergetime" ,Mergetime , MergeHelp , MergetimeOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_Mergegrid = {"Mergegrid" ,Mergegrid , MergegridHelp , MergegridOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Merstat = {"Merstat" ,Merstat , MerstatHelp , MerstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Monarith = {"Monarith" ,Monarith , MonarithHelp , MonarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Mrotuv = {"Mrotuv" ,Mrotuv , NO_HELP , MrotuvOperators , EXPOSED , CDI_REAL , 1 , 2 , NoRestriction }; +//static const module_t module_Mrotuvb = {"Mrotuvb" ,Mrotuvb , MrotuvbHelp , MrotuvbOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_NCL_wind = {"NCL_wind" ,NCL_wind , NCL_windHelp , NCL_windOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Ninfo = {"Ninfo" ,Ninfo , NinfoHelp , NinfoOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction, {Alias ("nvar", "npar")} }; +//static const module_t module_Nmldump = {"Nmldump" ,Nmldump , NO_HELP , NmldumpOperators , INTERNAL , CDI_REAL , 0 , 0 , NoRestriction }; +//static const module_t module_Output = {"Output" ,Output , OutputHelp , OutputOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction }; +//static const module_t module_Outputtab = {"Outputtab" ,Output , OutputtabHelp , OutputtabOperators , EXPOSED , CDI_REAL , -1 , 0 , NoRestriction, {Alias ("outputkey", "outputtab")} }; +//static const module_t module_Outputgmt = {"Outputgmt" ,Outputgmt , OutputgmtHelp , OutputgmtOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction, {Alias ("outputcenter", "gmtxyz"), Alias("outputbounds", "gmtcells")} }; +//static const module_t module_Pack = {"Pack" ,Pack , PackHelp , PackOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Pardup = {"Pardup" ,Pardup , NO_HELP , PardupOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Pinfo = {"Pinfo" ,Pinfo , NO_HELP , PinfoOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Query = {"Query" ,Query , NO_HELP , QueryOperators , EXPOSED , CDI_REAL , 1 , 1 , FilesOnly }; +//static const module_t module_Pressure = {"Pressure" ,Pressure , NO_HELP , PressureOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("deltap_fl","deltap"),Alias("fpressure", "pressure_fl"), Alias("hpressure", "pressure_hl")}}; +//static const module_t module_Recttocomplex = {"Recttocomplex" ,Recttocomplex , NO_HELP , RecttocomplexOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Regres = {"Regres" ,Regres , RegresHelp , RegresOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remap = {"Remap" ,Remapgrid , RemapHelp , RemapOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapbil = {"Remapbil" ,Remapgrid , RemapbilHelp , RemapbilOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapbic = {"Remapbic" ,Remapgrid , RemapbicHelp , RemapbicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapnn = {"Remapnn" ,Remapgrid , RemapnnHelp , RemapnnOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapdis = {"Remapdis" ,Remapgrid , RemapdisHelp , RemapdisOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapcon = {"Remapcon" ,Remapgrid , RemapconHelp , RemapconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("remapycon", "remapcon")} }; +//static const module_t module_Remapycon2 = {"Remapycon2" ,Remapgrid , NO_HELP , Remapycon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapscon = {"Remapscon" ,Remapgrid , NO_HELP , RemapsconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapscon2 = {"Remapscon2" ,Remapgrid , NO_HELP , Remapscon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remaplaf = {"Remaplaf" ,Remapgrid , RemaplafHelp , RemaplafOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapavg = {"Remapavg" ,Remapgrid , NO_HELP , RemapavgOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Genbil = {"Genbil" ,Remapweights , RemapbilHelp , GenbilOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Genbic = {"Genbic" ,Remapweights , RemapbicHelp , GenbicOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Gennn = {"Gennn" ,Remapweights , RemapnnHelp , GennnOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Gendis = {"Gendis" ,Remapweights , RemapdisHelp , GendisOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Gencon = {"Gencon" ,Remapweights , RemapconHelp , GenconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias("genycon", "gencon")} }; +//static const module_t module_Genycon2 = {"Genycon2" ,Remapweights , NO_HELP , Genycon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Genscon = {"Genscon" ,Remapweights , NO_HELP , GensconOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Genscon2 = {"Genscon2" ,Remapweights , NO_HELP , Genscon2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Genlaf = {"Genlaf" ,Remapweights , RemaplafHelp , GenlafOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapstat = {"Remapstat" ,Remapstat , RemapstatHelp , RemapstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Remapeta = {"Remapeta" ,Remapeta , RemapetaHelp , RemapetaOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Replace = {"Replace" ,Replace , ReplaceHelp , ReplaceOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Replacevalues = {"Replacevalues" ,Replacevalues , ReplacevaluesHelp , ReplacevaluesOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Rhopot = {"Rhopot" ,Rhopot , RhopotHelp , RhopotOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Rotuv = {"Rotuv" ,Rotuv , RotuvbHelp , RotuvOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Runpctl = {"Runpctl" ,Runpctl , RunpctlHelp , RunpctlOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Runstat = {"Runstat" ,Runstat , RunstatHelp , RunstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Samplegridicon = {"Samplegridicon" ,Samplegridicon , NO_HELP , SamplegridiconOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; +//static const module_t module_Seascount = {"Seascount" ,Seascount , NO_HELP , SeascountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Seaspctl = {"Seaspctl" ,Seaspctl , SeaspctlHelp , SeaspctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Seasstat = {"Seasstat" ,Seasstat , SeasstatHelp , SeasstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Seasmonstat = {"Seasmonstat" ,Seasmonstat , NO_HELP , SeasmonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Selbox = {"Selbox" ,Selbox , SelboxHelp , SelboxOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Selgridcell = {"Selgridcell" ,Selgridcell , SelgridcellHelp , SelgridcellOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Select = {"Select" ,Select , SelectHelp , SelectOperators , EXPOSED , CDI_BOTH , -1 , 1 , NoRestriction }; +//static const module_t module_Selvar = {"Selvar" ,Selvar , SelvarHelp , SelvarOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction, {Alias ("selvar", "selname"), Alias("delvar" , "delname"),Alias("selgridname" , "selgrid")} }; +//static const module_t module_Selrec = {"Selrec" ,Selrec , SelvarHelp , SelrecOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Selregion = {"Selregion" ,Selregion , SelregionHelp , SelregionOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Seloperator = {"Seloperator" ,Seloperator , NO_HELP , SeloperatorOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Seltime = {"Seltime" ,Seltime , SeltimeHelp , SeltimeOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction, {Alias ("selseas", "selseason"), Alias("selmon", "selmonth")} }; +//static const module_t module_Selyearidx = {"Selyearidx" ,Selyearidx , SelyearidxHelp , SelyearidxOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Set = {"Set" ,Set , SetHelp , SetOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction , {Alias ("setvar", "setname")}}; +//static const module_t module_Setattribute = {"Setattribute" ,Setattribute , SetattributeHelp , SetattributeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Setbox = {"Setbox" ,Setbox , SetboxHelp , SetboxOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Setgrid = {"Setgrid" ,Setgrid , SetgridHelp , SetgridOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Setgridcell = {"Setgridcell" ,Setgridcell , SetgridcellHelp , SetgridcellOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Sethalo = {"Sethalo" ,Sethalo , SethaloHelp , SethaloOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Setmiss = {"Setmiss" ,Setmiss , SetmissHelp , SetmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Setmisstonn = {"Setmisstonn" ,Fillmiss , SetmissHelp , SetmisstonnOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Setcodetab = {"Setcodetab" ,Setpartab , SetHelp , SetcodetabOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction , {Alias ("setpartab", "setcodetab")}}; +//static const module_t module_Setpartab = {"Setpartab" ,Setpartab , SetpartabHelp , SetpartabOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("setpartabv", "setpartabn")} }; +//static const module_t module_Setrcaname = {"Setrcaname" ,Setrcaname , NO_HELP , SetrcanameOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Settime = {"Settime" ,Settime , SettimeHelp , SettimeOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Setzaxis = {"Setzaxis" ,Setzaxis , SetzaxisHelp , SetzaxisOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Shiftxy = {"Shiftxy" ,Shiftxy , ShiftxyHelp , ShiftxyOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Showinfo = {"Showinfo" ,Showinfo , ShowinfoHelp , ShowinfoOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction , {Alias ("showvar", "showname")} }; +//static const module_t module_Showattribute = {"Showattribute" ,Showattribute , ShowattributeHelp , ShowattributeOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; +//static const module_t module_Sinfo = {"Sinfo" ,Sinfo , SinfoHelp , SinfoOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction, {Alias ("infov", "infon"),Alias("sinfov", "sinfon")} }; +//static const module_t module_XSinfo = {"XSinfo" ,Sinfo , XSinfoHelp , XSinfoOperators , EXPOSED , CDI_BOTH , -1 , 0 , NoRestriction }; +//static const module_t module_Smooth = {"Smooth" ,Smooth , SmoothHelp , SmoothOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Sort = {"Sort" ,Sort , NO_HELP , SortOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("sortvar", "sortname")} }; +//static const module_t module_Sorttimestamp = {"Sorttimestamp" ,Sorttimestamp , NO_HELP , SorttimestampOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//static const module_t module_Specinfo = {"Specinfo" ,Specinfo , NO_HELP , SpecinfoOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; +//static const module_t module_Spectral = {"Spectral" ,Spectral , SpectralHelp , SpectralOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Specconv = {"Specconv" ,Spectral , SpecconvHelp , SpecconvOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Spectrum = {"Spectrum" ,Spectrum , NO_HELP , SpectrumOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Split = {"Split" ,Split , SplitHelp , SplitOperators , EXPOSED , CDI_BOTH , 1 , OBASE , NoRestriction, {Alias ("splitvar", "splitname")} }; +//static const module_t module_Splitdate = {"Splitdate" ,Splitdate , SplitdateHelp , SplitdateOperators , EXPOSED , CDI_BOTH , 1 , OBASE , OnlyFirst }; +//static const module_t module_Splitrec = {"Splitrec" ,Splitrec , SplitHelp , SplitrecOperators , EXPOSED , CDI_BOTH , 1 , OBASE , NoRestriction }; +//static const module_t module_Splitsel = {"Splitsel" ,Splitsel , SplitselHelp , SplitselOperators , EXPOSED , CDI_BOTH , 1 , OBASE , OnlyFirst }; +//static const module_t module_Splittime = {"Splittime" ,Splittime , SplittimeHelp , SplittimeOperators , EXPOSED , CDI_BOTH , 1 , OBASE , OnlyFirst }; +//static const module_t module_Splityear = {"Splityear" ,Splityear , SplittimeHelp , SplityearOperators , EXPOSED , CDI_BOTH , 1 , OBASE , NoRestriction }; +//static const module_t module_Tee = {"Tee" ,Tee , TeeHelp , TeeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Testdata = {"Testdata" ,Testdata , NO_HELP , TestdataOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Tests = {"Tests" ,Tests , NO_HELP , TestsOperators , INTERNAL , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Timcount = {"Timcount" ,Timcount , NO_HELP , TimcountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Yearcount = {"Yearcount" ,Timcount , NO_HELP , YearcountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Moncount = {"Moncount" ,Timcount , NO_HELP , MoncountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Daycount = {"Daycount" ,Timcount , NO_HELP , DaycountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Hourcount = {"Hourcount" ,Timcount , NO_HELP , HourcountOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Timcumsum = {"Timcumsum" ,Timcumsum , TimcumsumHelp , TimcumsumOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Timpctl = {"Timpctl" ,Timpctl , TimpctlHelp , TimpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Yearpctl = {"Yearpctl" ,Timpctl , YearpctlHelp , YearpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Monpctl = {"Monpctl" ,Timpctl , MonpctlHelp , MonpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Daypctl = {"Daypctl" ,Timpctl , DaypctlHelp , DaypctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Hourpctl = {"Hourpctl" ,Timpctl , HourpctlHelp , HourpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Timselpctl = {"Timselpctl" ,Timselpctl , TimselpctlHelp , TimselpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Timfillmiss = {"Timfillmiss" ,Timfillmiss , TimfillmissHelp , TimfillmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Timsort = {"Timsort" ,Timsort , TimsortHelp , TimsortOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("sort", "timsort")} }; +//static const module_t module_Timselstat = {"Timselstat" ,Timselstat , TimselstatHelp , TimselstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_XTimstat = {"XTimstat" ,XTimstat , NO_HELP , XTimstatOperators , INTERNAL , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Timstat = {"Timstat" ,Timstat , TimstatHelp , TimstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Yearstat = {"Yearstat" ,Timstat , YearstatHelp , YearstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Monstat = {"Monstat" ,Timstat , MonstatHelp , MonstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Daystat = {"Daystat" ,Timstat , DaystatHelp , DaystatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Hourstat = {"Hourstat" ,Timstat , HourstatHelp , HourstatOperators , EXPOSED , CDI_BOTH , 1 , 1 , NoRestriction }; +//static const module_t module_Timcor = {"Timcor" ,Timstat2 , TimcorHelp , TimcorOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Timcovar = {"Timcovar" ,Timstat2 , TimcovarHelp , TimcovarOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Timrmsd = {"Timrmsd" ,Timstat2 , NO_HELP , TimrmsdOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Timstat3 = {"Timstat3" ,Timstat3 , NO_HELP , Timstat3Operators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Tinfo = {"Tinfo" ,Tinfo , NO_HELP , TinfoOperators , EXPOSED , CDI_BOTH , 1 , 0 , NoRestriction }; +//static const module_t module_Tocomplex = {"Tocomplex" ,Tocomplex , NO_HELP , TocomplexOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Transpose = {"Transpose" ,Transpose , NO_HELP , TransposeOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Trend = {"Trend" ,Trend , TrendHelp , TrendOperators , EXPOSED , CDI_REAL , 1 , 2 , OnlyFirst }; +//static const module_t module_Trendarith = {"Trendarith" ,Trendarith , TrendarithHelp , TrendarithOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Tstepcount = {"Tstepcount" ,Tstepcount , NO_HELP , TstepcountOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Unpack = {"Unpack" ,Unpack , UnpackHelp , UnpackOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vargen = {"Vargen" ,Vargen , VargenHelp , VargenOperators , EXPOSED , CDI_REAL , 0 , 1 , NoRestriction, {Alias ("for", "seq")} }; +//static const module_t module_Varrms = {"Varrms" ,Varrms , NO_HELP , VarrmsOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Varsstat = {"Varsstat" ,Varsstat , VarsstatHelp , VarsstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertfillmiss = {"Vertfillmiss" ,Vertfillmiss , VertfillmissHelp , VertfillmissOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertintap = {"Vertintap" ,Vertintap , VertintapHelp , VertintapOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertintgh = {"Vertintgh" ,Vertintgh , VertintghHelp , VertintghOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertintml = {"Vertintml" ,Vertintml , VertintmlHelp , VertintmlOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertintzs = {"Vertintzs" ,Vertintzs , NO_HELP , VertintzsOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertstat = {"Vertstat" ,Vertstat , VertstatHelp , VertstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertcum = {"Vertcum" ,Vertcum , NO_HELP , VertcumOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Vertwind = {"Vertwind" ,Vertwind , NO_HELP , VertwindOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Verifygrid = {"Verifygrid" ,Verifygrid , VerifygridHelp , VerifygridOperators , EXPOSED , CDI_REAL , 1 , 0 , NoRestriction }; +//static const module_t module_Verifyweights = {"Verifyweights" ,Verifyweights , NO_HELP , VerifyweightsOperators , EXPOSED , CDI_REAL , 0 , 0 , NoRestriction }; +//static const module_t module_Wind = {"Wind" ,Wind , WindHelp , WindOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Wind2 = {"Wind2" ,Wind , Wind2Help , Wind2Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Writegrid = {"Writegrid" ,Writegrid , NO_HELP , WritegridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Writerandom = {"Writerandom" ,Writerandom , NO_HELP , WriterandomOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Yeararith = {"Yeararith" ,Yeararith , YeararithHelp , YeararithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Yearmonstat = {"Yearmonstat" ,Yearmonstat , YearmonstatHelp , YearmonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Ydayarith = {"Ydayarith" ,Ydayarith , YdayarithHelp , YdayarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Ydaypctl = {"Ydaypctl" ,Ydaypctl , YdaypctlHelp , YdaypctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Ydaystat = {"Ydaystat" ,Ydaystat , YdaystatHelp , YdaystatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Ydrunpctl = {"Ydrunpctl" ,Ydrunpctl , YdrunpctlHelp , YdrunpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Ydrunstat = {"Ydrunstat" ,Ydrunstat , YdrunstatHelp , YdrunstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Yhourarith = {"Yhourarith" ,Yhourarith , YhourarithHelp , YhourarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Yhourstat = {"Yhourstat" ,Yhourstat , YhourstatHelp , YhourstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Dhourstat = {"Dhourstat" ,Yhourstat , DhourstatHelp , DhourstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Ymonarith = {"Ymonarith" ,Ymonarith , YmonarithHelp , YmonarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction, {Alias ("anomaly","ymonsub")}}; +//static const module_t module_Yseasarith = {"Yseasarith" ,Ymonarith , YseasarithHelp , YseasarithOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Ymoncomp = {"Ymoncomp" ,Ymoncomp , YmoncompHelp , YmoncompOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Yseascomp = {"Yseascomp" ,Ymoncomp , NO_HELP , YseascompOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Ymonpctl = {"Ymonpctl" ,Ymonpctl , YmonpctlHelp , YmonpctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Ymonstat = {"Ymonstat" ,Ymonstat , YmonstatHelp , YmonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Yseaspctl = {"Yseaspctl" ,Yseaspctl , YseaspctlHelp , YseaspctlOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Yseasstat = {"Yseasstat" ,Yseasstat , YseasstatHelp , YseasstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Zonstat = {"Zonstat" ,Zonstat , ZonstatHelp , ZonstatOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaCfd = {"EcaCfd" ,EcaCfd , EcaCfdHelp , EcaCfdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaCsu = {"EcaCsu" ,EcaCsu , EcaCsuHelp , EcaCsuOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaCwdi = {"EcaCwdi" ,EcaCwdi , EcaCwdiHelp , EcaCwdiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaCwfi = {"EcaCwfi" ,EcaCwfi , EcaCwfiHelp , EcaCwfiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaEtr = {"EcaEtr" ,EcaEtr , EcaEtrHelp , EcaEtrOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaEtccdi = {"EcaEtccdi" ,EcaEtccdi , EcaEtccdiHelp , EcaEtccdiOperators , EXPOSED , CDI_REAL , 3 , 1 , FilesOnly }; +//static const module_t module_EcaFd = {"EcaFd" ,EcaFd , EcaFdHelp , EcaFdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaGsl = {"EcaGsl" ,EcaGsl , EcaGslHelp , EcaGslOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaHd = {"EcaHd" ,EcaHd , EcaHdHelp , EcaHdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaHwdi = {"EcaHwdi" ,EcaHwdi , EcaHwdiHelp , EcaHwdiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaHwfi = {"EcaHwfi" ,EcaHwfi , EcaHwfiHelp , EcaHwfiOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaId = {"EcaId" ,EcaId , EcaIdHelp , EcaIdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaSu = {"EcaSu" ,EcaSu , EcaSuHelp , EcaSuOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaTr = {"EcaTr" ,EcaTr , EcaTrHelp , EcaTrOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaTg10p = {"EcaTg10p" ,EcaTg10p , EcaTg10pHelp , EcaTg10pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaTg90p = {"EcaTg90p" ,EcaTg90p , EcaTg90pHelp , EcaTg90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaTn10p = {"EcaTn10p" ,EcaTn10p , EcaTn10pHelp , EcaTn10pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaTn90p = {"EcaTn90p" ,EcaTn90p , EcaTn90pHelp , EcaTn90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaTx10p = {"EcaTx10p" ,EcaTx10p , EcaTx10pHelp , EcaTx10pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaTx90p = {"EcaTx90p" ,EcaTx90p , EcaTx90pHelp , EcaTx90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaCdd = {"EcaCdd" ,EcaCdd , EcaCddHelp , EcaCddOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaCwd = {"EcaCwd" ,EcaCwd , EcaCwdHelp , EcaCwdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaRr1 = {"EcaRr1" ,EcaRr1 , EcaRr1Help , EcaRr1Operators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction, {Alias ("eca_r1mm", "eca_rr1")} }; +//static const module_t module_EcaPd = {"EcaPd" ,EcaPd , EcaPdHelp , EcaPdOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaR75p = {"EcaR75p" ,EcaR75p , EcaR75pHelp , EcaR75pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaR75ptot = {"EcaR75ptot" ,EcaR75ptot , EcaR75ptotHelp , EcaR75ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaR90p = {"EcaR90p" ,EcaR90p , EcaR90pHelp , EcaR90pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaR90ptot = {"EcaR90ptot" ,EcaR90ptot , EcaR90ptotHelp , EcaR90ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaR95p = {"EcaR95p" ,EcaR95p , EcaR95pHelp , EcaR95pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaR95ptot = {"EcaR95ptot" ,EcaR95ptot , EcaR95ptotHelp , EcaR95ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaR99p = {"EcaR99p" ,EcaR99p , EcaR99pHelp , EcaR99pOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaR99ptot = {"EcaR99ptot" ,EcaR99ptot , EcaR99ptotHelp , EcaR99ptotOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_EcaRx1day = {"EcaRx1day" ,EcaRx1day , EcaRx1dayHelp , EcaRx1dayOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaRx5day = {"EcaRx5day" ,EcaRx5day , EcaRx5dayHelp , EcaRx5dayOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_EcaSdii = {"EcaSdii" ,EcaSdii , EcaSdiiHelp , EcaSdiiOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Fdns = {"Fdns" ,Fdns , FdnsHelp , FdnsOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Strwin = {"Strwin" ,Strwin , StrwinHelp , StrwinOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Strbre = {"Strbre" ,Strbre , StrbreHelp , StrbreOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Strgal = {"Strgal" ,Strgal , StrgalHelp , StrgalOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Hurr = {"Hurr" ,Hurr , HurrHelp , HurrOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +////static const module_t module_Hi = {"Hi" , Hi , NO_HELP , HiOperators , EXPOSED , CDI_REAL , 3 , 1 , NoRestriction }; +//static const module_t module_Wct = {"Wct" ,Wct , WctHelp , WctOperators , EXPOSED , CDI_REAL , 2 , 1 , NoRestriction }; +//static const module_t module_Magplot = {"Magplot" ,Magplot , MagplotHelp , MagplotOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Magvector = {"Magvector" ,Magvector , MagvectorHelp , MagvectorOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Maggraph = {"Maggraph" ,Maggraph , MaggraphHelp , MaggraphOperators , EXPOSED , CDI_REAL , -1 , 1 , NoRestriction }; +//// HIRLAM_EXTENSIONS {" +//static const module_t module_Samplegrid = {"Samplegrid" ,Samplegrid , SamplegridHelp , SamplegridOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_Selmulti = {"Selmulti" ,Selmulti , SelmultiHelp , SelmultiOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +//static const module_t module_WindTrans = {"WindTrans" ,WindTrans , WindTransHelp , WindTransOperators , EXPOSED , CDI_REAL , 1 , 1 , NoRestriction }; +// clang-format on +// +//#endif diff --git a/src/module_static_maps.cc b/src/module_static_maps.cc deleted file mode 100644 index 552bff45e1dd4d2a5a8a0ef3d5d3022e87b5efd7..0000000000000000000000000000000000000000 --- a/src/module_static_maps.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include "module_static_maps.h" -#include "modules.h" - -std::map<std::string, module_t> & -get_modules() -{ - static std::map<std::string, module_t> modules; - return modules; -}; - -std::map<std::string, std::string> & -get_aliases() -{ - static std::map<std::string, std::string> aliases; - return aliases; -} - -std::map<std::string, std::string> & -get_module_map() -{ - static std::map<std::string, std::string> modules_map; - return modules_map; -} diff --git a/src/module_static_maps.h b/src/module_static_maps.h deleted file mode 100644 index b26e0165012d924cb5592589ddf9ea7fdd6a77ce..0000000000000000000000000000000000000000 --- a/src/module_static_maps.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MODULE_STATIC_MAPS_H -#define MODULE_STATIC_MAPS_H - -#include <map> -#include <string> - -struct module_t; - -/* - * This file serves no purpose but to make these "hidden" static definitions more visible for - * future developers. - */ - -/** - * ========================================================================================== - * Functions Containing static structures for static initaializaton of modules, - * aliases and operators. All static maps contained within the following - * functions are necessary to not encounter problems with the non guaranteed - * order of initalization of static variables. - * ========================================================================================== - */ -std::map<std::string, module_t> &get_modules(); - -std::map<std::string, std::string> &get_aliases(); - -std::map<std::string, std::string> &get_module_map(); -//========================================================================================== -// -#endif diff --git a/src/modules.cc b/src/modules.cc index 995f480b7b3d4fd33ef6c30e9b29b16cf8861d1b..a0bcad121655df52331fff785ebffd92cf521079 100644 --- a/src/modules.cc +++ b/src/modules.cc @@ -1,4 +1,5 @@ /* + * #include "util_string.h" This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. Author: Uwe Schulzweida @@ -7,14 +8,6 @@ */ #include "modules.h" -#include "util_string.h" -#include "cdo_output.h" - -#include <cstring> -#include <algorithm> // for std::sort() - -int add_alias(const std::string &alias, const std::string &original); -void add_module(const std::string &module_name, const module_t &new_module); /* removes '-' from operator string and returns copy of parameter operatorCommand */ /*** @@ -25,560 +18,3 @@ std::vector<void *> custom_modules_lib_handles; /*** Contains added modules as values and their names as key */ - -Alias::Alias(const std::string &_alias, const std::string &_original) : alias(_alias), original(_original) {} - -// clang-format off -module_t::module_t(const std::string &p_mod_name, - void *(*p_func)(void *), - const char **p_help, - const std::vector<std::string> &p_opers, - short p_m, short p_n, short p_siC, short p_soC, - PositionRestrictions p_pos_restriction, - const std::vector<Alias> &p_aliases) - - : mod_name(p_mod_name), - func(p_func), - help(p_help), - mode(p_m), - number(p_n), - operators(p_opers), - constraints({p_siC, p_soC, p_pos_restriction}), - aliases(p_aliases) -{ - add_module(p_mod_name, *this); - for (const auto &al : aliases) add_alias(al.alias, al.original); -} -// clang-format on - -std::string -module_t::toString() -{ - std::string inp = (get_stream_in_cnt() >= 0) ? std::to_string(get_stream_in_cnt()) : "Arbitrary"; - std::string out = (get_stream_out_cnt() >= 0) ? std::to_string(get_stream_out_cnt()) : "Output base"; - std::string restriction = "none"; - - if (get_pos_restriction() == OnlyFirst) restriction = "Can only be the first operator"; - if (get_pos_restriction() == FilesOnly) - (restriction != Green("none")) ? restriction = Yellow("Can only use files as input.") - : restriction += Yellow(", Can only use files as input"); - - std::string desc = "Input: " + inp + ", Ouput: " + out + ", Restricton: " + restriction; - - return desc; -} - -void -extract_name_and_argument(const std::string &command, std::string &operatorName, std::string &operatorArgument) -{ - constexpr char delimiter = ','; - - const size_t start = (command[0] == '-') ? 1 : 0; - - size_t len = command.find(delimiter); - if (len == std::string::npos) - { - len = command.size(); - operatorArgument = ""; - } - else { operatorArgument = command.substr(len + 1, std::string::npos); } - - operatorName = command.substr(start, len - start); -} - -std::string -extract_operator_name(const std::string &operatorCommand) -{ - constexpr char delimiter = ','; - - const size_t start = (operatorCommand[0] == '-') ? 1 : 0; - - size_t len = operatorCommand.find(delimiter); - if (len == std::string::npos) len = operatorCommand.size(); - - std::string oper_name = operatorCommand.substr(start, len - start); - return oper_name; -} - -bool -is_alias(const std::string &operatorName) -{ - return (get_aliases().find(operatorName) != get_aliases().end()); -} - -std::string -get_original(const std::string &operatorName) -{ - std::string name = extract_operator_name(operatorName); - return (is_alias(name) ? get_aliases()[name] : name); -} -/** - * @param a pointer to a string/substring - * @param b pointer to a string/substring - * @param alen length of string a - * @param blen length of string b - * @retval true if a is similar to b - * @retval false if a is not similar to b - * - * Recursive function for finding substrings of a operator name that match other operators. - */ -static bool -similar(const char *a, const char *b, unsigned long alen, unsigned long blen) -{ - if (alen > 2 && blen > 2 && strstr(b, a)) return true; - - while (*a && *b && *a == *b) - { - a++; - b++; - } - if (!*a && !*b) return true; - - // printf("%d %d %s %s\n", alen, blen, a, b); - - if (alen >= 2 && blen >= 1 && *a && similar(a + 1, b, alen - 2, blen - 1)) return true; - - if (alen >= 1 && blen >= 2 && *b && similar(a, b + 1, alen - 1, blen - 2)) return true; - - return false; -} - -/** - * @param original string tested for similarity to \p other - * @param other string that \p original will be compared to - * @retval true if original and other are similar - * @retval false if not - * - * Wrapper function for #similar() to parse c++ strings to c strings - */ -static bool -similar(const std::string &original, const std::string &other) -{ - return (similar(original.c_str(), other.c_str(), original.size(), other.size())); -} - -/** - * @param operatorName operator name - * @retval true if #modules_map contains \p operatorName - * @retval false if not - */ -bool -operator_name_exists(const std::string &operatorName) -{ - if (get_module_map().find(operatorName) != get_module_map().end()) return true; - - if (get_aliases().find(operatorName) != get_aliases().end()) return true; - - return false; -} - -/*** - * function for finding similar operator names for the given string - * @param operatorName operator name to find similar operators for - * @returns A string with all found names. The string is seqmented into lines - * with a max length of 75 characters - */ -std::string -find_similar_operators(const std::string &operatorName) -{ - std::string found_similar_operators = ""; - size_t lines = 1; - constexpr size_t line_length = 105; - - if (operatorName != "") - { - // Searching for similar operator names in operator to module map - for (const auto &str : get_module_map()) - { - if (similar(string_to_lower(operatorName), str.first)) - { - if (found_similar_operators.size() + str.first.size() > lines * line_length) - { - found_similar_operators += "\n"; - lines++; - } - found_similar_operators += str.first; - found_similar_operators += " "; - } - } - // Searching for similar operator names in aliases to original map - for (const auto &str : get_aliases()) - { - if (similar(string_to_lower(operatorName), str.first)) - { - if (found_similar_operators.size() + str.first.size() > lines * line_length) - { - found_similar_operators += "\n"; - lines++; - } - found_similar_operators += str.first; - found_similar_operators += " "; - } - } - } - - return found_similar_operators; -} - -/** - * @param operatorName operator name. - * @retval true if \p operatorName exists. - * @retval false if \p operatorName is not in #modules_map - * - * Checks if given \p operatorName is in #modules_map. Else returns false. - - * Checks if \p operatorName is not a file. - - * If no matching operator is found checks for similar operators using find_similar_operators(). - * - * \note If \p operatorName is a file name the program will exit. - */ -static bool -check_operator(const std::string &operatorName) -{ - if (operator_name_exists(operatorName)) { return true; } - else if (operatorName == "") { cdo_abort("Operator name missing!"); } - else - { - // Checking if the operatorname is an existing file name - auto fp = std::fopen(operatorName.c_str(), "r"); - if (fp) - { - std::fclose(fp); - fprintf(stderr, "Use commandline option -h for help.\n"); - cdo_abort("Operator missing, %s is a file on disk!", operatorName); - } - // Operator is no filename - // Checking for similar operators - fprintf(stderr, "Operator >%s< not found!\n", operatorName.c_str()); - fprintf(stderr, "Similar operators are:\n"); - const auto found_similar_operators = find_similar_operators(operatorName); - - if (found_similar_operators.size() > 0) { std::cerr << found_similar_operators << std::endl; } - else { fprintf(stderr, "(not found)\n"); } - - exit(EXIT_FAILURE); - } - - return false; -} - -/*** - * Adds a module and its operators to cdo. - * Adds the module to modules - * Adds the operators of modules to modules_map - * @param new_module newly constructed module - * @note: if an error happens while adding the new module cdo will exit. - */ -void -add_module(const std::string &module_name, const module_t &new_module) -{ - if (get_modules().find(module_name) == get_modules().end()) - { - get_modules()[module_name] = new_module; - for (const auto &operatorName : new_module.operators) - { - // if the operator name is not already in the map or in the aliases - if (!operator_name_exists(operatorName)) { get_module_map()[operatorName] = module_name; } - else { cdo_abort("Tried to add operator but the operator name already exists"); } - } - } - else { cdo_abort("Module %s name already exists", module_name); } -} - -/** - * adds an key value pair to #modules_map with alias as key and originals name as value - * @param alias new alias to be added - * @param original original operator name - */ -int -add_alias(const std::string &alias, const std::string &original) -{ - auto iter_original = get_module_map().find(original); - auto iter_alias = get_aliases().find(alias); - - if (iter_alias != get_aliases().end()) - { - printf("WARNING: alias %s could not be added: it already exists\n", alias.c_str()); - return -1; - } - - if (iter_original == get_module_map().end()) - { - printf("ERROR: alias %s could not be added: operator %s does not exist\n", alias.c_str(), original.c_str()); - return -2; - } - - if (get_module_map().find(alias) != get_module_map().end()) - { - printf("ERROR alias %s could not be added: alias name already exists as an operator\n", alias.c_str()); - return -3; - } - - get_aliases()[alias] = original; - - return 0; -} - -/*** - * returns the module of given operator - * - * parameters: - * std::string operatorName -> name of the operator - * return value: - * std::string -> name of the operators module - */ -std::string -get_module_name_to(const std::string &operatorName) -{ - // if not true the programm will exit in function check_operator - if (check_operator(operatorName)) - { - if (get_module_map().count(operatorName) > 0) { return get_module_map()[operatorName]; } - else if (get_aliases().count(operatorName) > 0) { return get_module_map()[get_aliases()[operatorName]]; } - } - // Only to quell the warning. Function should never reach this. - return ""; -} - -/** - * @fn void *(*operatorModule(const char *operatorName))(void *) - - * returns the function of the module of \a operatorName - * @param operatorName name of the operator - * @returns the function of the #module_t of \a operatorName - */ -/* not used -void *(*operatorModule(const std::string &operatorName))(void *) -{ - std::string operator_name = std::string(operatorName); - return get_modules()[get_module_name_to(operatorName)].func; -} -*/ - -/*** - * returns help for given operator name - * if there is no help nullptr will be returned - * @param operatorName operator name - * @return vector of strings containing the help - */ -const char ** -operator_help(const std::string &operatorName) -{ - return get_modules()[get_module_name_to(get_original(operatorName))].help; -} - -/*** - * Returns the number type this operator works with - * @param operatorName operator name - * @reval short - */ -int -operator_stream_number(std::string &p_operatorName) -{ - return get_modules()[get_module_name_to(p_operatorName)].get_number(); -} - -/*** - * Creates a sorted vector with all operator names and alisases excluding all modules that are marked as internal - * @return a sorted std::vector containing all operator names and aliases - * excluding all operators which modules are marked as internal - */ -std::vector<std::string> -get_sorted_operator_name_list() -{ - std::vector<std::string> names; - for (const auto &operator_module_names_pair : get_module_map()) - { - if (get_modules()[operator_module_names_pair.second].get_mode() == 1) { names.push_back(operator_module_names_pair.first); } - } - // adding operators names from alias_map - for (const auto &alias : get_aliases()) { names.push_back(alias.first); } - - std::sort(names.begin(), names.end()); - - return names; -} - -std::vector<std::string> -get_no_output_operator_list() -{ - std::vector<std::string> names; - for (const auto &operator_module_names_pair : get_module_map()) - { - if (get_modules()[operator_module_names_pair.second].get_mode() == 1 - && get_modules()[operator_module_names_pair.second].get_stream_out_cnt() == 0) - { - names.push_back(operator_module_names_pair.first); - } - } - // adding operators names from alias_map - for (const auto &alias : get_aliases()) - { - const auto &original = alias.second; - if (get_modules()[get_module_map()[original]].get_mode() == 1 - && get_modules()[get_module_map()[original]].get_stream_out_cnt() == 0) - { - names.push_back(alias.first); - } - } - - std::sort(names.begin(), names.end()); - - return names; -} - -void -operatorPrintAll(void) -{ - int number_of_chars = 0; - std::string tab = " "; - int tab_width = tab.size(); - // using a set because it sorts the operators alphabetically on its own - std::vector<std::string> sorted_operator_names = get_sorted_operator_name_list(); - - std::cout << tab; - for (const auto &operatorName : sorted_operator_names) - { - if (number_of_chars > 85) - { - number_of_chars = tab_width; - std::cerr << std::endl << tab; - } - - std::cerr << " " << operatorName; - number_of_chars += 1 + operatorName.size(); - } - - std::cerr << std::endl; -} - -// helper function for setting the spacing in operator_print_list -static std::string -get_spacing_for(int p_space, const std::string &str) -{ - std::string spacing = ""; - for (int i = str.size(); i <= p_space; ++i) spacing += " "; - return spacing; -} - -static std::string -get_operator_description(const std::string &p_current_op_name, const char **help) -{ - std::string description = ""; - unsigned long cur_help_idx = 0; - std::string line; - unsigned long operator_section = 0; - - // search for operator section - size_t help_size = 0; - while (help[help_size]) help_size++; - if (!help_size) return description; - while (operator_section == 0 && cur_help_idx < help_size - 1) - { - line = help[++cur_help_idx]; - if (line.find("OPERATORS") != std::string::npos) { operator_section = cur_help_idx; } - } - // if no operator section is found - if (operator_section == 0) - { - cur_help_idx = 0; - line = help[0]; - std::string name_section = help[0]; - bool help_contains_name = false; - // search for the operator name in the description - while (!line.empty()) - { - line = help[++cur_help_idx]; - if (line.find(p_current_op_name) != std::string::npos) { help_contains_name = true; } - name_section += line; - } - // if the name was found save description for later use - if (help_contains_name) { description = name_section.substr(name_section.find('-') + 2, name_section.size()); } - } - else - { - line = help[++operator_section]; - // search the operator section for current operator line - while (line.find(p_current_op_name + " ") == std::string::npos && !line.empty() && operator_section < help_size - 1) - { - line = help[++operator_section]; - } - // if operator line found save description for later use - if (!line.empty() && line.find(" " + p_current_op_name + " ") != std::string::npos) - { - auto op_name_start = line.find_first_not_of(" \t"); - - description = line.substr(line.find_first_not_of(" \t", op_name_start + p_current_op_name.size()), line.size()); - } - } - - return description; -} - -/*** - * Prints all operator names and their short descriptions - * Aliases are listed and point to their original operator name. - * If the module is not documented the description is empty - * If a module has only one operator the short module description is listed - * If the operator is not documented the description is empty - */ -void -operator_print_list(bool print_no_output) -{ - std::vector<std::string> output_list = print_no_output ? get_no_output_operator_list() : get_sorted_operator_name_list(); - - auto list_length = output_list.size(); - - // help variables - - for (size_t out_list_idx = 0; out_list_idx < list_length; out_list_idx++) - { - auto ¤t_op_name = output_list[out_list_idx]; - const auto *current_module = &get_modules()[get_module_name_to(current_op_name)]; - if (get_aliases().find(current_op_name) != get_aliases().end()) - { - output_list[out_list_idx] += get_spacing_for(16, current_op_name) + "--> " + get_aliases()[current_op_name]; - } - else if (current_module->help) - { - // add spaceing and saving output line to the output list - auto description = get_operator_description(current_op_name, current_module->help); - output_list[out_list_idx] += get_spacing_for(16, current_op_name) + description; - } - std::string in_out_info = " (" + std::to_string(current_module->get_stream_in_cnt()) + "|" - + std::to_string(current_module->get_stream_out_cnt()) + ")"; - output_list[out_list_idx] += get_spacing_for(90, output_list[out_list_idx]) + in_out_info; - } - // print generated output list - for (const std::string &str : output_list) { std::cout << str << std::endl; } -} - -std::map<std::string, module_t>::iterator -find_module(const std::string &operator_name) -{ - std::string operName = operator_name; - - auto it = get_aliases().find(operName); - if (it != get_aliases().end()) { operName = it->second; } - - auto modMapIter = get_module_map().find(operName); - auto modIter = get_modules().end(); - if (!(modMapIter == get_module_map().end())) { modIter = get_modules().find(modMapIter->second); } - return modIter; -} - -std::vector<std::string> -get_module_operator_names(std::string module_name) -{ - auto &modules = get_modules(); - if (std::islower(static_cast<unsigned char>(module_name[0]))) {module_name[0] = std::toupper(module_name[0]); } - if (modules.find(module_name) == modules.end()) { return std::vector<std::string>(); } - return modules[module_name].operators; -} - -module_t & -get_module(const std::string &operator_name) -{ - return get_modules()[get_module_name_to(get_original(operator_name))]; -} diff --git a/src/modules.h b/src/modules.h index 29a88ee6b28562988ba462f2cdcd2e236ddc061d..e1c425e44298e81a552ceacfac37483334e0e746 100644 --- a/src/modules.h +++ b/src/modules.h @@ -12,104 +12,19 @@ #include <array> #include <vector> -#include "module_static_maps.h" - -// Obase uses input name as base name for files e.g 'test' gets used as test_001 test_002 which are created inside the operator -#define OBASE -1 -#define INTERNAL 0 -#define EXPOSED 1 +#include <functional> +#include <memory> +#include "cdo_module.h" +#include "process.h" /*** type definition for module functions loaded from a custom module */ using dyn_oper_t = void (*)(void *arg); -enum PositionRestrictions -{ - NoRestriction = 0, - FilesOnly = 1, - OnlyFirst = 2 -}; - -struct Alias -{ - Alias(const std::string &_alias, const std::string &_original); - std::string alias; - std::string original; -}; - -struct module_constraints -{ - short streamInCnt; // Number of input streams - short streamOutCnt; // Number of output streams - PositionRestrictions pos_restriction = NoRestriction; -}; - -struct module_t -{ - std::string mod_name; - void *(*func)(void *); // Module - const char **help; // Help - short mode; // Module mode: 0:intern 1:extern - short number; // Allowed number type - std::vector<std::string> operators; // Operator names - module_constraints constraints; - std::vector<Alias> aliases; - - module_t(const std::string &mod_name, void *(*p_func)(void *), const char **p_help, const std::vector<std::string> &p_opers, - short p_m, short p_n, short p_siC, short p_soC, PositionRestrictions p_pos_restriction, - const std::vector<Alias> &p_aliases = {}); - module_t(){}; - std::string toString(); - int - get_stream_in_cnt() const - { - return constraints.streamInCnt; - } - int - get_stream_out_cnt() const - { - return constraints.streamOutCnt; - } - int - get_number() const - { - return number; - } - int - get_mode() const - { - return mode; - } - int - get_pos_restriction() - { - return constraints.pos_restriction; - } -}; - /*** vector for library handles for loaded custom modules */ extern std::vector<void *> custom_modules_lib_handles; -std::string extract_operator_name(const std::string &operatorCommand); -void extract_name_and_argument(const std::string &command, std::string &operatorName, std::string &operatorArgument); - -std::string find_similar_operators(const std::string &operatorName); - -std::map<std::string, module_t>::iterator find_module(const std::string &operatorName); -std::vector<std::string> get_module_operator_names(std::string module_name); -module_t &get_module(const std::string &operatorName); - -std::string get_original(const std::string &operatorName); - -void init_modules(); - -const char **operator_help(const std::string &operatorName); -int operator_stream_number(std::string &operatorName); - -std::string get_module_name_to(const std::string &operatorName); -std::vector<std::string> get_sorted_operator_name_list(); - #endif /* MODULES_H */ diff --git a/src/mpim_grid/grid_healpix.cc b/src/mpim_grid/grid_healpix.cc index c11ab7de2f9978b12d531ef239edb17873bc15b6..9c2fd62d198fde141cd925aece791569db9347f1 100644 --- a/src/mpim_grid/grid_healpix.cc +++ b/src/mpim_grid/grid_healpix.cc @@ -160,7 +160,7 @@ hp_generate_ring_indices(HpOrder order, int nside, size_t gridsize, std::vector< // clang-format on int numRows = 4 * nside - 1; - if (ringRows.size() < (size_t)numRows) ringRows.resize(numRows); + if (ringRows.size() < (size_t) numRows) ringRows.resize(numRows); if (order != HpOrder::Ring && ringIndices.size() < gridsize) ringIndices.resize(gridsize); int index = 0; @@ -183,7 +183,8 @@ hp_generate_ring_indices(HpOrder order, int nside, size_t gridsize, std::vector< } template <typename T> -void hp_ring_to_nested(int nside, size_t gridsize, T *arrayIn, T *arrayOut) +void +hp_ring_to_nested(int nside, size_t gridsize, T *arrayIn, T *arrayOut) { assert(gridsize <= INT_MAX && "Large grid size unsupported!"); @@ -198,9 +199,9 @@ void hp_ring_to_nested(int nside, size_t gridsize, T *arrayIn, T *arrayOut) template void hp_ring_to_nested(int nside, size_t gridsize, float *arrayIn, float *arrayOut); template void hp_ring_to_nested(int nside, size_t gridsize, double *arrayIn, double *arrayOut); - template <typename T> -void hp_nested_to_ring(int nside, size_t gridsize, T *arrayIn, T *arrayOut) +void +hp_nested_to_ring(int nside, size_t gridsize, T *arrayIn, T *arrayOut) { assert(gridsize <= INT_MAX && "Large grid size unsupported!"); diff --git a/src/mpim_grid/grid_proj.cc b/src/mpim_grid/grid_proj.cc index be8d23f5c3a33bedd6cc0ee1612eaf03eb8fddf6..54ecd3c8ae31dd23d647b6f9de3941e44d52969b 100644 --- a/src/mpim_grid/grid_proj.cc +++ b/src/mpim_grid/grid_proj.cc @@ -53,12 +53,13 @@ check_xyvals(size_t nvals, double *xvals, double *yvals) static std::string gen_param(const char *fmt, ...) { - va_list args; - char str[256]; + constexpr size_t len = 256; + char str[len]; + va_list args; va_start(args, fmt); - vsprintf(str, fmt, args); + vsnprintf(str, len, fmt, args); va_end(args); @@ -610,22 +611,6 @@ cdo_proj_to_lonlat(char *proj_params, size_t nvals, double *xvals, double *yvals double gridGetPlanetRadius(int gridID) { - double planetRadius = 0.0; - - auto gridtype = gridInqType(gridID); - auto projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1; - if (projtype == CDI_PROJ_LCC) - { - CDI_GridProjParams gpp; - gridInqParamsLCC(gridID, &gpp); - if (IS_EQUAL(gpp.b, gpp.mv)) planetRadius = gpp.a; - } - else if (projtype == CDI_PROJ_STERE) - { - CDI_GridProjParams gpp; - gridInqParamsSTERE(gridID, &gpp); - if (IS_EQUAL(gpp.b, gpp.mv)) planetRadius = gpp.a; - } - - return planetRadius; + double radius{ 0 }; + return (CDI_NOERR == cdiInqAttFlt(gridID, CDI_GLOBAL, "earth_radius", 1, &radius) && radius > 1) ? radius : 0.0; } diff --git a/src/mpim_grid/grid_rot.cc b/src/mpim_grid/grid_rot.cc index c3b2c55fe352e6bfebf826ca4b2477d3289d7b4d..361ad67630b0265c0a9003710c0cdde244b1b7ef 100644 --- a/src/mpim_grid/grid_rot.cc +++ b/src/mpim_grid/grid_rot.cc @@ -38,6 +38,7 @@ lamrot_to_lam(double phirot, double lamrot, double polphi, double pollam, double if (lamrot > 180.0) lamrot -= 360.0; double zlamrot = DEG2RAD * lamrot; + if (polgam < 0) polgam += 360.0; if (polgam > 0) { double zgam = DEG2RAD * polgam; @@ -95,6 +96,7 @@ phirot_to_phi(double phirot, double lamrot, double polphi, double polgam) if (lamrot > 180.0) lamrot -= 360.0; double zlamrot = DEG2RAD * lamrot; + if (polgam < 0) polgam += 360.0; if (polgam > 0) { double zgam = DEG2RAD * polgam; @@ -131,7 +133,7 @@ lam_to_lamrot(double phi, double rla, double polphi, double pollam) double zrla = DEG2RAD * rla; double zphi = DEG2RAD * phi; - double zarg1 = -sin(zrla - zlampol) * std::cos(zphi); + double zarg1 = -std::sin(zrla - zlampol) * std::cos(zphi); double zarg2 = -zsinpol * std::cos(zphi) * std::cos(zrla - zlampol) + zcospol * std::sin(zphi); if (std::fabs(zarg2) < 1.0e-20) zarg2 = 1.0e-20; @@ -200,7 +202,7 @@ usvs_to_uv(double us, double vs, double phi, double rla, double polphi, double p double zrlas = lam_to_lamrot(phi, rla, polphi, pollam) * DEG2RAD; // winkel zbeta berechen (schnittwinkel der breitenkreise) - double zarg = -sin(zpolphi) * std::sin(zrla - zpollam) * std::sin(zrlas) - std::cos(zrla - zpollam) * std::cos(zrlas); + double zarg = -std::sin(zpolphi) * std::sin(zrla - zpollam) * std::sin(zrlas) - std::cos(zrla - zpollam) * std::cos(zrlas); if (zarg > 1.0) zarg = 1.0; if (zarg < -1.0) zarg = -1.0; /* diff --git a/src/mpim_grid/mpim_grid.cc b/src/mpim_grid/mpim_grid.cc index 8322a63bf05feddd6d9d98280db6251d704aab63..4c8f082885897b759ba3ba0ab4724915aa814de6 100644 --- a/src/mpim_grid/mpim_grid.cc +++ b/src/mpim_grid/mpim_grid.cc @@ -208,10 +208,7 @@ gridToZonal(int gridID1) gridDefXvals(gridID2, &xval); gridDefYvals(gridID2, latitudes.data()); } - else - { - cdo_abort("Gridtype %s unsupported!", gridNamePtr(gridtype)); - } + else { cdo_abort("Gridtype %s unsupported!", gridNamePtr(gridtype)); } return gridID2; } @@ -238,10 +235,7 @@ gridToMeridional(int gridID1) double yval = 0.0; gridDefYvals(gridID2, &yval); } - else - { - cdo_abort("Gridtype %s unsupported!", gridNamePtr(gridtype)); - } + else { cdo_abort("Gridtype %s unsupported!", gridNamePtr(gridtype)); } return gridID2; } @@ -630,7 +624,7 @@ reduced_grid_is_global(int np, int nxmax, double xfirst, double xlast) } void -field2regular(int gridID1, int gridID2, double missval, double *array, size_t nmiss, int lnearest) +field2regular(int gridID1, int gridID2, double missval, double *array, size_t numMissVals, int lnearest) { auto gridtype = gridInqType(gridID1); if (gridtype != GRID_GAUSSIAN_REDUCED) cdo_abort("Not a reduced Gaussian grid!"); @@ -648,7 +642,7 @@ field2regular(int gridID1, int gridID2, double missval, double *array, size_t nm int nxmax = 0; for (size_t i = 0; i < ny; ++i) nxmax = std::max(nxmax, reducedPoints[i]); - int lmiss = (nmiss > 0); + int lmiss = (numMissVals > 0); int lperio = 1; int iret; @@ -1241,10 +1235,7 @@ gridToUnstructuredGaussianReduced(int gridID1, int gridID2, size_t gridsize, int gridDefYvals(gridID2, yvals2D.data()); } - else - { - cdo_abort("%s: latitude coordinates missing!", gridNamePtr(gridInqType(gridID1))); - } + else { cdo_abort("%s: latitude coordinates missing!", gridNamePtr(gridInqType(gridID1))); } std::vector<double> xvals(gridsize); @@ -1392,14 +1383,8 @@ gridToUnstructured(int gridID1, NeedCorners needCorners) gridtype = GRID_LONLAT; isProjRLL = true; } - else if (projType == CDI_PROJ_HEALPIX) - { - isProjHealpix = true; - } - else - { - cdo_abort("Projection unsupported!"); - } + else if (projType == CDI_PROJ_HEALPIX) { isProjHealpix = true; } + else { cdo_abort("Projection unsupported!"); } } switch (gridtype) @@ -1520,6 +1505,36 @@ gridCurvilinearToRegular(int gridID1) return gridID2; } +int +gridProjectionToRegular(int gridID1) +{ + int gridID2 = -1; + + auto gridtype = gridInqType(gridID1); + auto xunits = cdo::inq_key_string(gridID1, CDI_XAXIS, CDI_KEY_UNITS); + auto yunits = cdo::inq_key_string(gridID1, CDI_YAXIS, CDI_KEY_UNITS); + + if (gridtype == GRID_PROJECTION && xunits.rfind("deg", 0) == 0 && yunits.rfind("deg", 0) == 0) + { + auto gridsize = gridInqSize(gridID1); + auto nx = gridInqXsize(gridID1); + auto ny = gridInqYsize(gridID1); + + std::vector<double> xvals(nx), yvals(ny); + gridInqXvals(gridID1, xvals.data()); + gridInqYvals(gridID1, yvals.data()); + + gridID2 = gridCreate(GRID_LONLAT, gridsize); + gridDefXsize(gridID2, nx); + gridDefYsize(gridID2, ny); + + gridDefXvals(gridID2, xvals.data()); + gridDefYvals(gridID2, yvals.data()); + } + + return gridID2; +} + static int compute_gridcell_weights(int gridID, const Varray<double> &gridCellArea, Varray<double> &gridCellWeights) { @@ -1587,10 +1602,7 @@ gridcell_weights(int gridID, Varray<double> &gridCellWeights) if (areaStatus != 0 && (gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN)) areaStatus = gridGenAreaReg2Dweights(gridID, gridCellArea.data()); } - else - { - areaStatus = 1; - } + else { areaStatus = 1; } } if (areaStatus == 0) { weightStatus = compute_gridcell_weights(gridID, gridCellArea, gridCellWeights); } @@ -1735,7 +1747,7 @@ LonLatUnits string_to_LonLatUnits(const std::string &units, const std::string &description) { if (units.rfind("rad", 0) == 0) { return LonLatUnits::Rad; } - else if (units.rfind("deg", 0) == 0) { return LonLatUnits::Deg; } + else if (units.rfind("deg", 0) == 0) { return LonLatUnits::Deg; } static bool warn = true; if (warn) @@ -1751,5 +1763,4 @@ LonLatUnits cdo_grid_get_units(int gridID, int varID, const std::string &description) { return string_to_LonLatUnits(cdo::inq_key_string(gridID, varID, CDI_KEY_UNITS), description); -; } diff --git a/src/mpim_grid/mpim_grid.h b/src/mpim_grid/mpim_grid.h index 3951ed2aa8b8e01f00ca55cf5dbd8d2b5eab1ccb..2539bd0b6ed28cae7d64c06aef329033f86f9a06 100644 --- a/src/mpim_grid/mpim_grid.h +++ b/src/mpim_grid/mpim_grid.h @@ -20,7 +20,6 @@ #include "grid_convert.h" #include "varray.h" - enum class LonLatUnits { Deg, @@ -106,8 +105,9 @@ int gridToUnstructured(int gridID, NeedCorners needCorners = NeedCorners::No); int gridToUnstructuredSelecton(int gridID1, const std::vector<size_t> &selectionIndexList, int nocoords, int nobounds); int gridToCurvilinear(int gridID, NeedCorners needCorners = NeedCorners::No); int gridCurvilinearToRegular(int gridID); +int gridProjectionToRegular(int gridID); int gridToRegular(int gridID); -void field2regular(int gridID1, int gridID2, double missval, double *array, size_t nmiss, int lnearest); +void field2regular(int gridID1, int gridID2, double missval, double *array, size_t numMissVals, int lnearest); // GME grid void gme_factorni(int kni, int *kni2, int *kni3); diff --git a/src/namelist.cc b/src/namelist.cc index 8f6caa21ade00e9b3a3451e0adbbcc284d353f9b..979dad95a34ddf70dd1352a4f6670648d8518162 100644 --- a/src/namelist.cc +++ b/src/namelist.cc @@ -148,11 +148,11 @@ NamelistParser::checkKeyname(const char *buf, NamelistToken *t) switch (t->type) { case NamelistType::STRING: - while (isspace((int) buf[t->start]) && t->start < t->end) t->start++; - while (isspace((int) buf[t->end - 1]) && t->start < t->end) t->end--; + while (std::isspace((int) buf[t->start]) && t->start < t->end) t->start++; + while (std::isspace((int) buf[t->end - 1]) && t->start < t->end) t->end--; if ((t->end - t->start) < 1) return NamelistError::EMKEY; for (long i = t->start; i < t->end; ++i) - if (isspace((int) buf[i])) return NamelistError::INKEY; + if (std::isspace((int) buf[i])) return NamelistError::INKEY; t->type = NamelistType::KEY; break; case NamelistType::WORD: t->type = NamelistType::KEY; break; diff --git a/src/node.cc b/src/node.cc index f57619f9fa1453d8b0eef04730d70174f18c68c7..8873b7ffe20b2aa9723424abaabc75cdc6d2a756 100644 --- a/src/node.cc +++ b/src/node.cc @@ -38,8 +38,8 @@ Node::is_done() { bool done = false; - if (constraints.streamInCnt == -1) { done = false; } // varibale inputs always false - else if (isFile && !isOutFile) { done = true; } // files always true + if (constraints.streamInCnt == -1) { done = false; } // varibale inputs always false + else if (isFile && !isOutFile) { done = true; } // files always true else if ((int) children.size() == constraints.streamInCnt) { done = true; } Debug(CDO_NODE, "%s is done: %s", oper, done ? "true" : "false"); diff --git a/src/node.h b/src/node.h index c62b66772faf2231860909f449fd7163cabe1853..e3b49aab1d2f26d7b52624a3647dc499ec399a64 100644 --- a/src/node.h +++ b/src/node.h @@ -5,11 +5,11 @@ #include <string> #include <memory> #include <iostream> -#include "modules.h" +#include "cdo_module.h" static std::string errmsg_node_to_many_inputs = "To many inputs"; -static std::string errmsg_node_no_output= "Operator has no output, cannot be used with pipes unless used first"; -static std::string errmsg_node_unassigned ="Could not be assigned, leftover input"; +static std::string errmsg_node_no_output = "Operator has no output, cannot be used with pipes unless used first"; +static std::string errmsg_node_unassigned = "Could not be assigned, leftover input"; static std::string errmsg_node_file_to_file = "Attempted to attach file to file"; static std::string errmsg_node_only_accepts_files = "Operator cannot be piped into an operator that takes only files"; @@ -60,5 +60,4 @@ public: std::string to_string(); }; - #endif diff --git a/src/operator_help.cc b/src/operator_help.cc new file mode 100644 index 0000000000000000000000000000000000000000..ef680ef478e4e58058f44ab6e0768d8d31b97b5b --- /dev/null +++ b/src/operator_help.cc @@ -0,0 +1,7105 @@ +// Automatically created with makedoc, don't edit! + +#include "operator_help.h" + +// clang-format off + +const CdoHelp InfoHelp = { + "NAME", + " info, infon, 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 ", + " the same structure with the same variables on different timesteps.", + " The information displayed depends on the chosen operator.", + "", + "OPERATORS", + " info Dataset information listed by parameter identifier", + " Prints information and simple statistics for each field of all input datasets.", + " For each field the operator prints one line with the following elements:", + " - Date and Time", + " - Level, Gridsize and number of Missing values", + " - Minimum, Mean and Maximum \\", + " The mean value is computed without the use of area weights!", + " - Parameter identifier", + " infon Dataset information listed by parameter name", + " The same as operator info but using the name instead of the", + " identifier to label the parameter.", + " 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.", +}; + +const CdoHelp SinfoHelp = { + "NAME", + " sinfo, sinfon - Short information", + "", + "SYNOPSIS", + " <operator> infiles", + "", + "DESCRIPTION", + " This module writes information about the structure of infiles to standard output.", + " infiles is an arbitrary number of input files. All input files need to have ", + " the same structure with the same variables on different timesteps.", + " The information displayed depends on the chosen operator.", + "", + "OPERATORS", + " sinfo Short information listed by parameter identifier", + " Prints short information of a dataset. The information is divided into 4 sections.", + " Section 1 prints one line per parameter with the following information:", + " - institute and source", + " - time c=constant v=varying", + " - type of statistical processing", + " - number of levels and z-axis number", + " - horizontal grid size and number", + " - data type", + " - parameter identifier", + " Section 2 and 3 gives a short overview of all grid and vertical coordinates.", + " And the last section contains short information of the time coordinate.", + " sinfon Short information listed by parameter name", + " The same as operator sinfo but using the name instead of the identifier to label the parameter.", +}; + +const CdoHelp XSinfoHelp = { + "NAME", + " xsinfo, xsinfop - Extra short information", + "", + "SYNOPSIS", + " <operator> infiles", + "", + "DESCRIPTION", + " This module writes information about the structure of infiles to standard output.", + " infiles is an arbitrary number of input files. All input files need to have ", + " the same structure with the same variables on different timesteps.", + " The information displayed depends on the chosen operator.", + "", + "OPERATORS", + " xsinfo Extra short information listed by parameter name", + " Prints short information of a dataset. The information is divided into 4 sections.", + " Section 1 prints one line per parameter with the following information:", + " - institute and source", + " - time c=constant v=varying", + " - type of statistical processing", + " - number of levels and z-axis number", + " - horizontal grid size and number", + " - data type", + " - memory type (float or double)", + " - parameter name", + " Section 2 to 4 gives a short overview of all grid, vertical and time coordinates.", + " xsinfop Extra short information listed by parameter identifier", + " The same as operator xsinfo but using the identifier instead of the name to label the parameter.", +}; + +const CdoHelp DiffHelp = { + "NAME", + " diff, diffn - Compare two datasets field by field", + "", + "SYNOPSIS", + " <operator>[,options] infile1 infile2", + "", + "DESCRIPTION", + " Compares the contents of two datasets field by field. The input datasets need", + " to have the same structure and its fields need to have the dimensions.", + " Try the option names if the number of variables differ.", + " Exit status is 0 if inputs are the same and 1 if they differ.", + "", + "OPERATORS", + " diff Compare two datasets listed by parameter id", + " Provides statistics on differences between two datasets.", + " For each pair of fields the operator prints one line with the following information:", + " - Date and Time", + " - Level, Gridsize and number of Missing values", + " - Number of different values", + " - Occurrence of coefficient pairs with different signs (S)", + " - Occurrence of zero values (Z)", + " - Maxima of absolute difference of coefficient pairs", + " - Maxima of relative difference of non-zero coefficient pairs with equal signs", + " - Parameter identifier", + " diffn Compare two datasets listed by parameter name", + " The same as operator diff. Using the name instead of the", + " identifier to label the parameter.", + "", + "PARAMETER", + " maxcount INTEGER Stop after maxcount different fields", + " abslim FLOAT Limit of the maximum absolute difference (default: 0)", + " rellim FLOAT Limit of the maximum relative difference (default: 1)", + " names STRING Consideration of the variable names of only one input file (left/right) or the intersection of both (intersect).", + " ", +}; + +const CdoHelp NinfoHelp = { + "NAME", + " npar, nlevel, nyear, nmon, ndate, ntime, ngridpoints, ngrids - ", + " Print the number of parameters, levels or times", + "", + "SYNOPSIS", + " <operator> infile", + "", + "DESCRIPTION", + " This module prints the number of variables, levels or times of the ", + " input dataset.", + "", + "OPERATORS", + " npar Number of parameters", + " Prints the number of parameters (variables).", + " nlevel Number of levels", + " Prints the number of levels for each variable.", + " nyear Number of years", + " Prints the number of different years.", + " nmon Number of months", + " Prints the number of different combinations of years and months.", + " ndate Number of dates", + " Prints the number of different dates.", + " ntime Number of timesteps", + " Prints the number of timesteps.", + " ngridpoints Number of gridpoints", + " Prints the number of gridpoints for each variable.", + " ngrids Number of horizontal grids", + " Prints the number of horizontal grids.", +}; + +const CdoHelp ShowinfoHelp = { + "NAME", + " showformat, showcode, showname, showstdname, showlevel, showltype, showyear, ", + " showmon, showdate, showtime, showtimestamp - Show variables, levels or times", + "", + "SYNOPSIS", + " <operator> infile", + "", + "DESCRIPTION", + " This module prints the format, variables, levels or times of the input dataset.", + "", + "OPERATORS", + " showformat Show file format", + " Prints the file format of the input dataset.", + " showcode Show code numbers", + " Prints the code number of all variables.", + " showname Show variable names", + " Prints the name of all variables.", + " showstdname Show standard names", + " Prints the standard name of all variables.", + " showlevel Show levels", + " Prints all levels for each variable.", + " showltype Show GRIB level types", + " Prints the GRIB level type for all z-axes.", + " showyear Show years", + " Prints all years.", + " showmon Show months", + " Prints all months.", + " showdate Show date information", + " Prints date information of all timesteps (format YYYY-MM-DD).", + " showtime Show time information", + " Prints time information of all timesteps (format hh:mm:ss).", + " showtimestamp Show timestamp", + " Prints timestamp of all timesteps (format YYYY-MM-DDThh:mm:ss).", +}; + +const CdoHelp ShowattributeHelp = { + "NAME", + " showattribute - Show attributes", + "", + "SYNOPSIS", + " showattribute[,attributes] infile", + "", + "DESCRIPTION", + " This operator prints the attributes of the data variables of a dataset.", + " ", + " Each attribute has the following structure:", + " ", + " [var_nm@][att_nm]", + " ", + " var_nm Variable name (optional). Example: pressure", + " att_nm Attribute name (optional). Example: units", + " ", + " The value of var_nm is the name of the variable containing the attribute (named att_nm) that", + " you want to print. Use wildcards to print the attribute att_nm of more than one variable.", + " A value of var_nm of '*' will print the attribute att_nm of all data variables.", + " If var_nm is missing then att_nm refers to a global attribute.", + " ", + " The value of att_nm is the name of the attribute you want to print. Use wildcards to print more than", + " one attribute. A value of att_nm of '*' will print all attributes.", + "", + "PARAMETER", + " attributes STRING Comma-separated list of attributes. ", +}; + +const CdoHelp FiledesHelp = { + "NAME", + " partab, codetab, griddes, zaxisdes, vct - Dataset description", + "", + "SYNOPSIS", + " <operator> infile", + "", + "DESCRIPTION", + " This module provides operators to print meta information about a dataset.", + " The printed meta-data depends on the chosen operator.", + "", + "OPERATORS", + " partab Parameter table", + " Prints all available meta information of the variables.", + " codetab Parameter code table", + " Prints a code table with a description of all variables.", + " For each variable the operator prints one line listing the", + " code, name, description and units.", + " griddes Grid description", + " Prints the description of all grids.", + " zaxisdes Z-axis description", + " Prints the description of all z-axes.", + " vct Vertical coordinate table", + " Prints the vertical coordinate table.", +}; + +const CdoHelp ApplyHelp = { + "NAME", + " apply - Apply operators", + "", + "SYNOPSIS", + " apply,operators infiles", + "", + "DESCRIPTION", + " The apply utility runs the named operators on each input file. The input files must be enclosed in square brackets.", + " This utility can only be used on a series of input files. These are all operators with more than one input file (infiles).", + " Here is an incomplete list of these operators: copy, cat, merge, mergetime, select, ENSSTAT.", + " The parameter operators is a blank-separated list of CDO operators. Use quotation marks if more than one operator is needed.", + " Each operator may have only one input and output stream.", + "", + "PARAMETER", + " operators STRING Blank-separated list of CDO operators.", +}; + +const CdoHelp CopyHelp = { + "NAME", + " copy, clone, cat - Copy datasets", + "", + "SYNOPSIS", + " <operator> infiles outfile", + "", + "DESCRIPTION", + " This module contains operators to copy, clone or concatenate datasets.", + " infiles is an arbitrary number of input files. All input files need to have ", + " the same structure with the same variables on different timesteps.", + "", + "OPERATORS", + " copy Copy datasets", + " Copies all input datasets to outfile. ", + " clone Clone datasets", + " Copies all input datasets to outfile. In contrast to the copy operator, clone tries", + " not to change the input data. GRIB records are neither decoded nor decompressed.", + " cat Concatenate datasets", + " Concatenates all input datasets and appends the result to the end ", + " of outfile. If outfile does not exist it will be created.", +}; + +const CdoHelp TeeHelp = { + "NAME", + " tee - Duplicate a data stream and write it to file", + "", + "SYNOPSIS", + " tee,outfile2 infile outfile1", + "", + "DESCRIPTION", + " This operator copies the input dataset to outfile1 and outfile2. The first output stream", + " in outfile1 can be further processesd with other cdo operators. The second output outfile2", + " is written to disk. It can be used to store intermediate results to a file.", + "", + "PARAMETER", + " outfile2 STRING Destination filename for the copy of the input file", +}; + +const CdoHelp PackHelp = { + "NAME", + " pack - Pack data", + "", + "SYNOPSIS", + " pack[,parameter] infile outfile", + "", + "DESCRIPTION", + " Packing reduces the data volume by reducing the precision of the stored numbers.", + " It is implemented using the NetCDF attributes add_offset and scale_factor.", + " The operator pack calculates the attributes add_offset and scale_factor for all variables.", + " The default data type for all variables is automatically changed to 16-bit integer.", + " Use the CDO option -b to change the data type to a different integer precision, if needed.", + " Missing values are automatically transformed to the current data type.", + " ", + " Alternatively, the pack parameters add_offset and scale_factor can be read from a file for each variable.", + "", + "PARAMETER", + " printparam BOOL Print pack parameters to stdout for each variable", + " filename STRING Read pack parameters from file for each variable[format: name=<> add_offset=<> scale_factor=<>]", +}; + +const CdoHelp UnpackHelp = { + "NAME", + " unpack - Unpack data", + "", + "SYNOPSIS", + " unpack infile outfile", + "", + "DESCRIPTION", + " Packing reduces the data volume by reducing the precision of the stored numbers.", + " It is implemented using the NetCDF attributes add_offset and scale_factor.", + " The operator unpack unpack all packed variables.", + " The default data type for all variables is automatically changed to 32-bit floats.", + " Use the CDO option -b F64 to change the data type to 64-bit floats, if needed.", +}; + +const CdoHelp BitroundingHelp = { + "NAME", + " bitrounding - Bit rounding", + "", + "SYNOPSIS", + " bitrounding[,parameter] infile outfile", + "", + "DESCRIPTION", + " This operator calculates for each field the number of necessary mantissa bits to get a certain", + " information level in the data. With this number of significant bits (numbits) a rounding of the data is performed.", + " This allows the data to be compressed to a higher level.", + " ", + " The default value of the information level is 0.9999 and can be adjusted with the parameter inflevel.", + " That means 99.99% of the information in the mantissa bits is preserved.", + " ", + " Alternatively, the number of significant bits can be set for all variables with the numbits parameter.", + " Furthermore, numbits can be assigned for each variable via the filename parameter. In this case, numbits is still", + " calculated for all variables if they are not present in the file.", + " ", + " The analysis of the bit information is based on the Julia library BitInformation.jl (https://github.com/milankl/BitInformation.jl).", + " The procedure to derive the number of significant mantissa bits was adapted from the Python library xbitinfo (https://github.com/observingClouds/xbitinfo).", + " Quantize to the number of mantissa bits is done with IEEE rounding using code from NetCDF 4.9.0.", + " ", + " Currently only 32-bit float data is rounded. Data with missing values are not yet supported for the calculation of significant bits.", + "", + "PARAMETER", + " inflevel FLOAT Information level (0 - 1) [default: 0.9999]", + " addbits INTEGER Add bits to the number of significant bits [default: 0]", + " minbits INTEGER Minimum value of the number of bits [default: 1]", + " maxbits INTEGER Maximum value of the number of bits [default: 23]", + " numsteps INTEGER Set to 1 to run the calculation only in the first time step", + " numbits INTEGER Set number of significant bits", + " printbits BOOL Print max. numbits per variable of 1st timestep to stdout [format: name=numbits]", + " filename STRING Read number of significant bits per variable from file [format: name=numbits]", +}; + +const CdoHelp ReplaceHelp = { + "NAME", + " replace - Replace variables", + "", + "SYNOPSIS", + " replace infile1 infile2 outfile", + "", + "DESCRIPTION", + " This operator replaces variables in infile1 by variables from infile2 and write", + " the result to outfile. Both input datasets need to have the same number of timesteps.", + " All variable names may only occur once!", +}; + +const CdoHelp DuplicateHelp = { + "NAME", + " duplicate - Duplicates a dataset", + "", + "SYNOPSIS", + " duplicate[,ndup] infile outfile", + "", + "DESCRIPTION", + " This operator duplicates the contents of infile and writes the result to outfile.", + " The optional parameter sets the number of duplicates, the default is 2.", + "", + "PARAMETER", + " ndup INTEGER Number of duplicates, default is 2.", +}; + +const CdoHelp MergegridHelp = { + "NAME", + " mergegrid - Merge grid", + "", + "SYNOPSIS", + " mergegrid infile1 infile2 outfile", + "", + "DESCRIPTION", + " Merges grid points of all variables from infile2 to infile1 and write the result to outfile.", + " Only the non missing values of infile2 will be used. The horizontal grid of infile2 should ", + " be smaller or equal to the grid of infile1 and the resolution must be the same.", + " Only rectilinear grids are supported. Both input files need to have the same variables ", + " and the same number of timesteps.", +}; + +const CdoHelp MergeHelp = { + "NAME", + " merge, mergetime - Merge datasets", + "", + "SYNOPSIS", + " <operator> infiles outfile", + "", + "DESCRIPTION", + " This module reads datasets from several input files, merges them and writes the resulting dataset to outfile.", + "", + "OPERATORS", + " merge Merge datasets with different fields", + " Merges time series of different fields from several input datasets. The number ", + " of fields per timestep written to outfile is the sum of the field numbers ", + " per timestep in all input datasets. The time series on all input datasets are ", + " required to have different fields and the same number of timesteps.", + " The fields in each different input file either have to be different variables", + " or different levels of the same variable. A mixture of different variables on", + " different levels in different input files is not allowed.", + " mergetime Merge datasets sorted by date and time", + " Merges all timesteps of all input files sorted by date and time.", + " All input files need to have the same structure with the same variables on ", + " different timesteps. After this operation every input timestep is in outfile ", + " and all timesteps are sorted by date and time.", + "", + "ENVIRONMENT", + " SKIP_SAME_TIME", + " If set to 1, skips all consecutive timesteps with a double entry of the same timestamp.", + "", + "NOTE", + " Operators of this module need to open all input files simultaneously.", + " The maximum number of open files depends on the operating system!", +}; + +const CdoHelp SplitHelp = { + "NAME", + " splitcode, splitparam, splitname, splitlevel, splitgrid, splitzaxis, ", + " splittabnum - Split a dataset", + "", + "SYNOPSIS", + " <operator>[,parameter] infile obase", + "", + "DESCRIPTION", + " This module splits infile into pieces. The output files will be named <obase><xxx><suffix>", + " where suffix is the filename extension derived from the file format. xxx and the contents ", + " of the output files depends on the chosen operator. ", + " params is a comma-separated list of processing parameters.", + "", + "OPERATORS", + " splitcode Split code numbers", + " Splits a dataset into pieces, one for each different code number.", + " xxx will have three digits with the code number.", + " splitparam Split parameter identifiers", + " Splits a dataset into pieces, one for each different parameter identifier.", + " xxx will be a string with the parameter identifier.", + " splitname Split variable names", + " Splits a dataset into pieces, one for each variable name.", + " xxx will be a string with the variable name.", + " splitlevel Split levels", + " Splits a dataset into pieces, one for each different level.", + " xxx will have six digits with the level.", + " splitgrid Split grids", + " Splits a dataset into pieces, one for each different grid.", + " xxx will have two digits with the grid number.", + " splitzaxis Split z-axes", + " Splits a dataset into pieces, one for each different z-axis.", + " xxx will have two digits with the z-axis number.", + " splittabnum Split parameter table numbers", + " Splits a dataset into pieces, one for each GRIB1 parameter table number.", + " xxx will have three digits with the GRIB1 parameter table number.", + "", + "PARAMETER", + " swap STRING Swap the position of obase and xxx in the output filename", + " uuid=<attname> STRING Add a UUID as global attribute <attname> to each output file", + "", + "ENVIRONMENT", + " CDO_FILE_SUFFIX", + " Set the default file suffix. This suffix will be added to the output file ", + " names instead of the filename extension derived from the file format. ", + " Set this variable to NULL to disable the adding of a file suffix.", + "", + "NOTE", + " Operators of this module need to open all output files simultaneously.", + " The maximum number of open files depends on the operating system!", +}; + +const CdoHelp SplittimeHelp = { + "NAME", + " splithour, splitday, splitseas, splityear, splityearmon, splitmon - ", + " Split timesteps of a dataset", + "", + "SYNOPSIS", + " <operator> infile obase", + " splitmon[,format] infile obase", + "", + "DESCRIPTION", + " This module splits infile into timesteps pieces. The output files will be named", + " <obase><xxx><suffix> where suffix is the filename extension derived from the file format. ", + " xxx and the contents of the output files depends on the chosen operator. ", + "", + "OPERATORS", + " splithour Split hours", + " Splits a file into pieces, one for each different hour.", + " xxx will have two digits with the hour.", + " splitday Split days", + " Splits a file into pieces, one for each different day.", + " xxx will have two digits with the day.", + " splitseas Split seasons", + " Splits a file into pieces, one for each different season.", + " xxx will have three characters with the season.", + " splityear Split years", + " Splits a file into pieces, one for each different year.", + " xxx will have four digits with the year (YYYY).", + " splityearmon Split in years and months", + " Splits a file into pieces, one for each different year and month.", + " xxx will have six digits with the year and month (YYYYMM).", + " splitmon Split months", + " Splits a file into pieces, one for each different month.", + " xxx will have two digits with the month.", + "", + "PARAMETER", + " format STRING C-style format for strftime() (e.g. %B for the full month name)", + "", + "ENVIRONMENT", + " CDO_FILE_SUFFIX", + " Set the default file suffix. This suffix will be added to the output file ", + " names instead of the filename extension derived from the file format. ", + " Set this variable to NULL to disable the adding of a file suffix.", + "", + "NOTE", + " Operators of this module need to open all output files simultaneously.", + " The maximum number of open files depends on the operating system!", +}; + +const CdoHelp SplitselHelp = { + "NAME", + " splitsel - Split selected timesteps", + "", + "SYNOPSIS", + " splitsel,nsets[,noffset[,nskip]] infile obase", + "", + "DESCRIPTION", + " This operator splits infile into pieces, one for each adjacent", + " sequence t_1, ...., t_n of timesteps of the same selected time range.", + " The output files will be named <obase><nnnnnn><suffix> where nnnnnn is the ", + " sequence number and suffix is the filename extension derived from the file format.", + "", + "PARAMETER", + " nsets INTEGER Number of input timesteps for each output file", + " noffset INTEGER Number of input timesteps skipped before the first timestep range (optional)", + " nskip INTEGER Number of input timesteps skipped between timestep ranges (optional)", + "", + "ENVIRONMENT", + " CDO_FILE_SUFFIX", + " Set the default file suffix. This suffix will be added to the output file ", + " names instead of the filename extension derived from the file format. ", + " Set this variable to NULL to disable the adding of a file suffix.", +}; + +const CdoHelp SplitdateHelp = { + "NAME", + " splitdate - Splits a file into dates", + "", + "SYNOPSIS", + " splitdate infile obase", + "", + "DESCRIPTION", + " This operator splits infile into pieces, one for each different date.", + " The output files will be named <obase><YYYY-MM-DD><suffix> where YYYY-MM-DD is the ", + " date and suffix is the filename extension derived from the file format.", + "", + "ENVIRONMENT", + " CDO_FILE_SUFFIX", + " Set the default file suffix. This suffix will be added to the output file ", + " names instead of the filename extension derived from the file format. ", + " Set this variable to NULL to disable the adding of a file suffix.", +}; + +const CdoHelp DistgridHelp = { + "NAME", + " distgrid - Distribute horizontal grid", + "", + "SYNOPSIS", + " distgrid,nx[,ny] infile obase", + "", + "DESCRIPTION", + " This operator distributes a dataset into smaller pieces. Each output file contains a different region of the", + " horizontal source grid. 2D Lon/Lat grids can be split into nx*ny pieces, where a target grid region contains", + " a structured longitude/latitude box of the source grid. Data on an unstructured grid is split into nx pieces.", + " The output files will be named <obase><xxx><suffix> where suffix is the filename extension derived from the", + " file format. xxx will have five digits with the number of the target region.", + "", + "PARAMETER", + " nx INTEGER Number of regions in x direction, or number of pieces for unstructured grids", + " ny INTEGER Number of regions in y direction [default: 1]", + "", + "NOTE", + " This operator needs to open all output files simultaneously.", + " The maximum number of open files depends on the operating system!", +}; + +const CdoHelp CollgridHelp = { + "NAME", + " collgrid - Collect horizontal grid", + "", + "SYNOPSIS", + " collgrid[,nx[,names]] infiles outfile", + "", + "DESCRIPTION", + " This operator collects the data of the input files to one output file. All input files need", + " to have the same variables and the same number of timesteps on a different horizonal grid region.", + " If the source regions are on a structured lon/lat grid, all regions together must result in a", + " new structured lat/long grid box. Data on an unstructured grid is concatenated in the order of", + " the input files. The parameter nx needs to be specified only for curvilinear grids.", + "", + "PARAMETER", + " nx INTEGER Number of regions in x direction [default: number of input files]", + " names STRING Comma-separated list of variable names [default: all variables]", + "", + "NOTE", + " This operator needs to open all input files simultaneously.", + " The maximum number of open files depends on the operating system!", +}; + +const CdoHelp SelectHelp = { + "NAME", + " select, delete - Select fields", + "", + "SYNOPSIS", + " <operator>,parameter infiles outfile", + "", + "DESCRIPTION", + " This module selects some fields from infiles and writes them to outfile.", + " infiles is an arbitrary number of input files. All input files need to have ", + " the same structure with the same variables on different timesteps.", + " The fields selected depends on the chosen parameters. Parameter is a comma-separated list", + " of \"key=value\" pairs. A range of integer values can be specified by first/last[/inc].", + " Wildcards are supported for string values.", + "", + "OPERATORS", + " select Select fields", + " Selects all fields with parameters in a user given list.", + " delete Delete fields", + " Deletes all fields with parameters in a user given list.", + "", + "PARAMETER", + " name STRING Comma-separated list of variable names.", + " param STRING Comma-separated list of parameter identifiers.", + " code INTEGER Comma-separated list or first/last[/inc] range of code numbers.", + " level FLOAT Comma-separated list of vertical levels.", + " levrange FLOAT First and last value of the level range.", + " levidx INTEGER Comma-separated list or first/last[/inc] range of index of levels.", + " zaxisname STRING Comma-separated list of zaxis names.", + " zaxisnum INTEGER Comma-separated list or first/last[/inc] range of zaxis numbers.", + " ltype INTEGER Comma-separated list or first/last[/inc] range of GRIB level types.", + " gridname STRING Comma-separated list of grid names.", + " gridnum INTEGER Comma-separated list or first/last[/inc] range of grid numbers.", + " steptype STRING Comma-separated list of timestep types (constant, avg, accum, min, max, range, diff, sum)", + " date STRING Comma-separated list of dates (format YYYY-MM-DDThh:mm:ss).", + " startdate STRING Start date (format YYYY-MM-DDThh:mm:ss).", + " enddate STRING End date (format YYYY-MM-DDThh:mm:ss).", + " minute INTEGER Comma-separated list or first/last[/inc] range of minutes.", + " hour INTEGER Comma-separated list or first/last[/inc] range of hours.", + " day INTEGER Comma-separated list or first/last[/inc] range of days.", + " month INTEGER Comma-separated list or first/last[/inc] range of months.", + " season STRING Comma-separated list of seasons (substring of DJFMAMJJASOND or ANN).", + " year INTEGER Comma-separated list or first/last[/inc] range of years.", + " dom STRING Comma-separated list of the day of month (e.g. 29feb).", + " timestep INTEGER Comma-separated list or first/last[/inc] range of timesteps. Negative values select timesteps from the end (NetCDF only).", + " timestep_of_year INTEGER Comma-separated list or first/last[/inc] range of timesteps of year.", + " timestepmask STRING Read timesteps from a mask file.", +}; + +const CdoHelp SelmultiHelp = { + "NAME", + " selmulti, delmulti, changemulti - Select multiple fields via GRIB1 parameters", + "", + "SYNOPSIS", + " <operator>,selection-specification infile outfile", + "", + "DESCRIPTION", + " This module selects multiple fields from infile and writes them to outfile.", + " selection-specification is a filename or in-place string with the selection specification.", + " Each selection-specification has the following compact notation format: ", + " ", + " <type>(parameters; leveltype(s); levels)", + " ", + " type " " sel for select or del for delete (optional)", + " parameters" " GRIB1 parameter code number", + " leveltype " " GRIB1 level type", + " levels " " value of each level", + " ", + " Examples:", + " ", + " (1; 103; 0) ", + " (33,34; 105; 10) ", + " (11,17; 105; 2) ", + " (71,73,74,75,61,62,65,117,67,122,121,11,131,66,84,111,112; 105; 0) ", + " ", + " The following descriptive notation can also be used for selection specification from a file:", + " ", + " SELECT/DELETE, PARAMETER=parameters, LEVTYPE=leveltye(s), LEVEL=levels", + " ", + " Examples:", + " ", + " SELECT, PARAMETER=1, LEVTYPE=103, LEVEL=0 ", + " SELECT, PARAMETER=33/34, LEVTYPE=105, LEVEL=10 ", + " SELECT, PARAMETER=11/17, LEVTYPE=105, LEVEL=2 ", + " SELECT, PARAMETER=71/73/74/75/61/62/65/117/67/122, LEVTYPE=105, LEVEL=0 ", + " DELETE, PARAMETER=128, LEVTYPE=109, LEVEL=* ", + " ", + " The following will convert Pressure from Pa into hPa; Temp from Kelvin to Celsius: ", + " SELECT, PARAMETER=1, LEVTYPE= 103, LEVEL=0, SCALE=0.01 ", + " SELECT, PARAMETER=11, LEVTYPE=105, LEVEL=2, OFFSET=273.15 ", + " If SCALE and/or OFFSET are defined, then the data values are scaled as SCALE*(VALUE-OFFSET).", + "", + "OPERATORS", + " selmulti Select multiple fields", + " delmulti Delete multiple fields", + " changemulti Change identication of multiple fields", +}; + +const CdoHelp SelvarHelp = { + "NAME", + " selparam, delparam, selcode, delcode, selname, delname, selstdname, sellevel, ", + " sellevidx, selgrid, selzaxis, selzaxisname, selltype, seltabnum - Select fields", + "", + "SYNOPSIS", + " <operator>,parameter infile outfile", + " selcode,codes infile outfile", + " delcode,codes infile outfile", + " selname,names infile outfile", + " delname,names infile outfile", + " selstdname,stdnames infile outfile", + " sellevel,levels infile outfile", + " sellevidx,levidx infile outfile", + " selgrid,grids infile outfile", + " selzaxis,zaxes infile outfile", + " selzaxisname,zaxisnames infile outfile", + " selltype,ltypes infile outfile", + " seltabnum,tabnums infile outfile", + "", + "DESCRIPTION", + " This module selects some fields from infile and writes them to outfile.", + " The fields selected depends on the chosen operator and the parameters. A range of integer", + " values can be specified by first/last[/inc].", + "", + "OPERATORS", + " selparam Select parameters by identifier", + " Selects all fields with parameter identifiers in a user given list.", + " delparam Delete parameters by identifier", + " Deletes all fields with parameter identifiers in a user given list.", + " selcode Select parameters by code number", + " Selects all fields with code numbers in a user given list or range.", + " delcode Delete parameters by code number", + " Deletes all fields with code numbers in a user given list or range.", + " selname Select parameters by name", + " Selects all fields with parameter names in a user given list.", + " delname Delete parameters by name", + " Deletes all fields with parameter names in a user given list.", + " selstdname Select parameters by standard name", + " Selects all fields with standard names in a user given list.", + " sellevel Select levels", + " Selects all fields with levels in a user given list.", + " sellevidx Select levels by index", + " Selects all fields with index of levels in a user given list or range.", + " selgrid Select grids", + " Selects all fields with grids in a user given list.", + " selzaxis Select z-axes", + " Selects all fields with z-axes in a user given list.", + " selzaxisname Select z-axes by name", + " Selects all fields with z-axis names in a user given list.", + " selltype Select GRIB level types", + " Selects all fields with GRIB level type in a user given list or range.", + " seltabnum Select parameter table numbers", + " Selects all fields with parameter table numbers in a user given list or range.", + "", + "PARAMETER", + " parameter STRING Comma-separated list of parameter identifiers.", + " codes INTEGER Comma-separated list or first/last[/inc] range of code numbers.", + " names STRING Comma-separated list of variable names.", + " stdnames STRING Comma-separated list of standard names.", + " levels FLOAT Comma-separated list of vertical levels.", + " levidx INTEGER Comma-separated list or first/last[/inc] range of index of levels.", + " ltypes INTEGER Comma-separated list or first/last[/inc] range of GRIB level types.", + " grids STRING Comma-separated list of grid names or numbers.", + " zaxes STRING Comma-separated list of z-axis types or numbers.", + " zaxisnames STRING Comma-separated list of z-axis names.", + " tabnums INTEGER Comma-separated list or range of parameter table numbers.", +}; + +const CdoHelp SeltimeHelp = { + "NAME", + " seltimestep, seltime, selhour, selday, selmonth, selyear, selseason, seldate, ", + " selsmon - Select timesteps", + "", + "SYNOPSIS", + " seltimestep,timesteps infile outfile", + " seltime,times infile outfile", + " selhour,hours infile outfile", + " selday,days infile outfile", + " selmonth,months infile outfile", + " selyear,years infile outfile", + " selseason,seasons infile outfile", + " seldate,startdate[,enddate] infile outfile", + " selsmon,month[,nts1[,nts2]] infile outfile", + "", + "DESCRIPTION", + " This module selects user specified timesteps from infile and writes them to outfile.", + " The timesteps selected depends on the chosen operator and the parameters. A range of integer values", + " can be specified by first/last[/inc].", + "", + "OPERATORS", + " seltimestep Select timesteps", + " Selects all timesteps with a timestep in a user given list or range.", + " seltime Select times", + " Selects all timesteps with a time in a user given list or range.", + " selhour Select hours", + " Selects all timesteps with a hour in a user given list or range.", + " selday Select days", + " Selects all timesteps with a day in a user given list or range.", + " selmonth Select months", + " Selects all timesteps with a month in a user given list or range.", + " selyear Select years", + " Selects all timesteps with a year in a user given list or range.", + " selseason Select seasons", + " Selects all timesteps with a month of a season in a user given list.", + " seldate Select dates", + " Selects all timesteps with a date in a user given range.", + " selsmon Select single month", + " Selects a month and optional an arbitrary number of timesteps before and after this month.", + "", + "PARAMETER", + " timesteps INTEGER Comma-separated list or first/last[/inc] range of timesteps. Negative values select timesteps from the end (NetCDF only).", + " times STRING Comma-separated list of times (format hh:mm:ss).", + " hours INTEGER Comma-separated list or first/last[/inc] range of hours.", + " days INTEGER Comma-separated list or first/last[/inc] range of days.", + " months INTEGER Comma-separated list or first/last[/inc] range of months.", + " years INTEGER Comma-separated list or first/last[/inc] range of years.", + " seasons STRING Comma-separated list of seasons (substring of DJFMAMJJASOND or ANN).", + " startdate STRING Start date (format YYYY-MM-DDThh:mm:ss).", + " enddate STRING End date (format YYYY-MM-DDThh:mm:ss) [default: startdate].", + " nts1 INTEGER Number of timesteps before the selected month [default: 0].", + " nts2 INTEGER Number of timesteps after the selected month [default: nts1].", +}; + +const CdoHelp SelboxHelp = { + "NAME", + " sellonlatbox, selindexbox - Select a box", + "", + "SYNOPSIS", + " sellonlatbox,lon1,lon2,lat1,lat2 infile outfile", + " selindexbox,idx1,idx2,idy1,idy2 infile outfile", + "", + "DESCRIPTION", + " Selects grid cells inside a lon/lat or index box.", + "", + "OPERATORS", + " sellonlatbox Select a longitude/latitude box", + " Selects grid cells inside a lon/lat box. The user must specify the longitude and latitude of the edges of the box.", + " Only those grid cells are considered whose grid center lies within the lon/lat box.", + " For rotated lon/lat grids the parameters must be specified in rotated coordinates.", + " selindexbox Select an index box", + " Selects grid cells within an index box. The user must specify the indices of the edges of the box.", + " The index of the left edge can be greater then the one of the right edge. Use negative indexing to", + " start from the end. The input grid must be a regular lon/lat or a 2D curvilinear grid.", + "", + "PARAMETER", + " lon1 FLOAT Western longitude in degrees", + " lon2 FLOAT Eastern longitude in degrees", + " lat1 FLOAT Southern or northern latitude in degrees", + " lat2 FLOAT Northern or southern latitude in degrees", + " idx1 INTEGER Index of first longitude (1 - nlon)", + " idx2 INTEGER Index of last longitude (1 - nlon)", + " idy1 INTEGER Index of first latitude (1 - nlat)", + " idy2 INTEGER Index of last latitude (1 - nlat)", +}; + +const CdoHelp SelregionHelp = { + "NAME", + " selregion, selcircle - Select horizontal regions", + "", + "SYNOPSIS", + " selregion,regions infile outfile", + " selcircle[,parameter] infile outfile", + "", + "DESCRIPTION", + " Selects all grid cells with the center point inside user defined regions or a circle.", + " The resulting grid is unstructured.", + "", + "OPERATORS", + " selregion Select cells inside regions", + " Selects all grid cells with the center point inside the regions.", + " Regions can be defined by the user via an ASCII file.", + " Each region consists of the geographic coordinates of a convex polygon.", + " Each line of a polygon description file contains the longitude and latitude of one point.", + " Each polygon description file can contain one or more polygons separated by a line with the character \\&.", + " ", + " Predefined regions of countries can be specified via the country codes.", + " A country is specified with dcw:<CountryCode>. Country codes can be combined with the plus sign.", + " selcircle Select cells inside a circle", + " Selects all grid cells with the center point inside a circle. The circle is described by geographic coordinates", + " of the center and the radius of the circle.", + "", + "PARAMETER", + " regions STRING Comma-separated list of ASCII formatted files with different regions", + " lon FLOAT Longitude of the center of the circle in degrees, default lon=0.0", + " lat FLOAT Latitude of the center of the circle in degrees, default lat=0.0", + " radius STRING Radius of the circle, default radius=1deg (units: deg, rad, km, m)", +}; + +const CdoHelp SelgridcellHelp = { + "NAME", + " selgridcell, delgridcell - Select grid cells", + "", + "SYNOPSIS", + " <operator>,indices infile outfile", + "", + "DESCRIPTION", + " The operator selects grid cells of all fields from infile. The user must specify the index of each grid cell.", + " The resulting grid in outfile is unstructured.", + "", + "OPERATORS", + " selgridcell Select grid cells", + " delgridcell Delete grid cells", + "", + "PARAMETER", + " indices INTEGER Comma-separated list or first/last[/inc] range of indices", +}; + +const CdoHelp SamplegridHelp = { + "NAME", + " samplegrid - Resample grid", + "", + "SYNOPSIS", + " samplegrid,factor infile outfile", + "", + "DESCRIPTION", + " This is a special operator for resampling the horizontal grid.", + " No interpolation takes place. Resample factor=2 means every second grid point is removed.", + " Only rectilinear and curvilinear source grids are supported by this operator.", + "", + "PARAMETER", + " factor INTEGER Resample factor, typically 2, which will half the resolution", +}; + +const CdoHelp SelyearidxHelp = { + "NAME", + " selyearidx - Select year by index", + "", + "SYNOPSIS", + " selyearidx infile1 infile2 outfile", + "", + "DESCRIPTION", + " Selects field elements from infile2 by a yearly time index from infile1.", + " The yearly indices in infile1 should be the result of corresponding yearminidx and yearmaxidx operations, respectively.", +}; + +const CdoHelp SelsurfaceHelp = { + "NAME", + " bottomvalue, topvalue, isosurface - Extract surface", + "", + "SYNOPSIS", + " <operator> infile outfile", + " isosurface,isovalue infile outfile", + "", + "DESCRIPTION", + " This module computes a surface from all 3D variables. The result is a horizonal 2D field.", + "", + "OPERATORS", + " bottomvalue Extract bottom level", + " This operator selects the valid values at the bottom level.", + " The NetCDF CF compliant attribute positive is used to determine where top and bottom are.", + " If this attribute is missing, low values are bottom and high values are top.", + " topvalue Extract top level", + " This operator selects the valid values at the top level.", + " The NetCDF CF compliant attribute positive is used to determine where top and bottom are.", + " If this attribute is missing, low values are bottom and high values are top.", + " isosurface Extract isosurface", + " This operator computes an isosurface. The value of the isosurfce is specified by the parameter isovalue.", + " The isosurface is calculated by linear interpolation between two layers.", + "", + "PARAMETER", + " isovalue FLOAT Isosurface value", +}; + +const CdoHelp CondHelp = { + "NAME", + " ifthen, ifnotthen - Conditional select one field", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module selects field elements from infile2 with respect to infile1 and writes them ", + " to outfile. The fields in infile1 are handled as a mask. A value ", + " not equal to zero is treated as \"true\", zero is treated as \"false\".", + " The number of fields in infile1 has either to be the same as in infile2 or the", + " same as in one timestep of infile2 or only one.", + " The fields in outfile inherit the meta data from infile2.", + "", + "OPERATORS", + " ifthen If then", + " / i_2(t,x) if i_1(t,x) NE 0 AND i_1(t,x) NE miss", + " o(t,x) =", + " \\ miss if i_1(t,x) EQ 0 OR i_1(t,x) EQ miss", + " ifnotthen If not then", + " / i_2(t,x) if i_1(t,x) EQ 0 AND i_1(t,x) NE miss", + " o(t,x) = ", + " \\ miss if i_1(t,x) NE 0 OR i_1(t,x) EQ miss", +}; + +const CdoHelp Cond2Help = { + "NAME", + " ifthenelse - Conditional select two fields", + "", + "SYNOPSIS", + " ifthenelse infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator selects field elements from infile2 or infile3 with respect to", + " infile1 and writes them to outfile. The fields in infile1 are handled as a mask.", + " A value not equal to zero is treated as \"true\", zero is treated as \"false\".", + " The number of fields in infile1 has either to be the same as in infile2 or the ", + " same as in one timestep of infile2 or only one.", + " infile2 and infile3 need to have the same number of fields.", + " The fields in outfile inherit the meta data from infile2.", + " ", + " / i_2(t,x) if i_1(t,x) NE 0 AND i_1(t,x) NE miss", + " o(t,x) = < i_3(t,x) if i_1(t,x) EQ 0 AND i_1[t,x) NE miss", + " \\ miss if i_1(t,x) EQ miss", +}; + +const CdoHelp CondcHelp = { + "NAME", + " ifthenc, ifnotthenc - Conditional select a constant", + "", + "SYNOPSIS", + " <operator>,c infile outfile", + "", + "DESCRIPTION", + " This module creates fields with a constant value or missing value.", + " The fields in infile are handled as a mask. A value not equal ", + " to zero is treated as \"true\", zero is treated as \"false\".", + "", + "OPERATORS", + " ifthenc If then constant", + " / c if i(t,x) NE 0 AND i(t,x) NE miss", + " o(t,x) =", + " \\ miss if i(t,x) EQ 0 OR i(t,x) EQ miss", + " ifnotthenc If not then constant", + " / c if i(t,x) EQ 0 AND i(t,x) NE miss", + " o(t,x) =", + " \\ miss if i(t,x) NE 0 OR i(t,x) EQ miss", + "", + "PARAMETER", + " c FLOAT Constant", +}; + +const CdoHelp MapReduceHelp = { + "NAME", + " reducegrid - Reduce fields to user-defined mask", + "", + "SYNOPSIS", + " reducegrid,mask[,limitCoordsOutput] infile outfile", + "", + "DESCRIPTION", + " This module holds an operator for data reduction based on a user defined mask.", + " The output grid is unstructured and includes coordinate bounds. Bounds can be", + " avoided by using the additional 'nobounds' keyword. With 'nocoords' given,", + " coordinates a completely suppressed.", + "", + "PARAMETER", + " mask STRING file which holds the mask field", + " limitCoordsOutput STRING optional parameter to limit coordinates output: 'nobounds' disables coordinate bounds, 'nocoords' avoids all coordinate information", +}; + +const CdoHelp CompHelp = { + "NAME", + " eq, ne, le, lt, ge, gt - Comparison of two fields", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module compares two datasets field by field.", + " The resulting field is a mask containing 1 if the comparison is true and 0 if not.", + " The number of fields in infile1 should be the same as in infile2.", + " One of the input files can contain only one timestep or one field.", + " The fields in outfile inherit the meta data from infile1 or infile2.", + " The type of comparison depends on the chosen operator.", + "", + "OPERATORS", + " eq Equal", + " / 1 if i_1(t,x) EQ i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " o(t,x) = < 0 if i_1(t,x) NE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", + " ne Not equal", + " / 1 if i_1(t,x) NE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " o(t,x) = < 0 if i_1(t,x) EQ i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", + " le Less equal", + " / 1 if i_1(t,x) LE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " o(t,x) = < 0 if i_1(t,x) GT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", + " lt Less than", + " / 1 if i_1(t,x) LT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " o(t,x) = < 0 if i_1(t,x) GE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", + " ge Greater equal", + " / 1 if i_1(t,x) GE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " o(t,x) = < 0 if i_1(t,x) LT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", + " gt Greater than", + " / 1 if i_1(t,x) GT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " o(t,x) = < 0 if i_1(t,x) LE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", + " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", +}; + +const CdoHelp CompcHelp = { + "NAME", + " eqc, nec, lec, ltc, gec, gtc - Comparison of a field with a constant", + "", + "SYNOPSIS", + " <operator>,c infile outfile", + "", + "DESCRIPTION", + " This module compares all fields of a dataset with a constant. The resulting", + " field is a mask containing 1 if the comparison is true and 0 if not.", + " The type of comparison depends on the chosen operator.", + "", + "OPERATORS", + " eqc Equal constant", + " / 1 if i(t,x) EQ c AND i(t,x),c NE miss", + " o(t,x) = < 0 if i(t,x) NE c AND i(t,x),c NE miss", + " \\ miss if i(t,x) EQ miss OR c EQ miss", + " nec Not equal constant", + " / 1 if i(t,x) NE c AND i(t,x),c NE miss", + " o(t,x) = < 0 if i(t,x) EQ c AND i(t,x),c NE miss", + " \\ miss if i(t,x) EQ miss OR c EQ miss", + " lec Less equal constant", + " / 1 if i(t,x) LE c AND i(t,x),c NE miss", + " o(t,x) = < 0 if i(t,x) GT c AND i(t,x),c NE miss", + " \\ miss if i(t,x) EQ miss OR c EQ miss", + " ltc Less than constant", + " / 1 if i(t,x) LT c AND i(t,x),c NE miss", + " o(t,x) = < 0 if i(t,x) GE c AND i(t,x),c NE miss", + " \\ miss if i(t,x) EQ miss OR c EQ miss", + " gec Greater equal constant", + " / 1 if i(t,x) GE c AND i(t,x),c NE miss", + " o(t,x) = < 0 if i(t,x) LT c AND i(t,x),c NE miss", + " \\ miss if i(t,x) EQ miss OR c EQ miss", + " gtc Greater than constant", + " / 1 if i(t,x) GT c AND i(t,x),c NE miss", + " o(t,x) = < 0 if i(t,x) LE c AND i(t,x),c NE miss", + " \\ miss if i(t,x) EQ miss OR c EQ miss", + "", + "PARAMETER", + " c FLOAT Constant", +}; + +const CdoHelp YmoncompHelp = { + "NAME", + " ymoneq, ymonne, ymonle, ymonlt, ymonge, ymongt - Multi-year monthly comparison", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs compaisons of a time series and one timestep with the same month of year.", + " For each field in infile1 the corresponding field of the timestep in infile2 with the same month of year is used.", + " The resulting field is a mask containing 1 if the comparison is true and 0 if not. ", + " The type of comparison depends on the chosen operator.", + " The input files need to have the same structure with the same variables.", + " Usually infile2 is generated by an operator of the module YMONSTAT.", + "", + "OPERATORS", + " ymoneq Compare time series with Equal", + " Compares whether a time series is equal to a multi-year monthly time series.", + " ymonne Compare time series with NotEqual", + " Compares whether a time series is not equal to a multi-year monthly time series.", + " ymonle Compare time series with LessEqual", + " Compares whether a time series is less than or equal to a multi-year monthly time series.", + " ymonlt Compares if time series with LessThan", + " Compares whether a time series is less than a multi-year monthly time series.", + " ymonge Compares if time series with GreaterEqual", + " Compares whether a time series is greater than or equal to a multi-year monthly time series.", + " ymongt Compares if time series with GreaterThan", + " Compares whether a time series is greater than a multi-year monthly time series.", +}; + +const CdoHelp SetattributeHelp = { + "NAME", + " setattribute - Set attributes", + "", + "SYNOPSIS", + " setattribute,attributes infile outfile", + "", + "DESCRIPTION", + " This operator sets attributes of a dataset and writes the result to outfile.", + " The new attributes are only available in outfile if the file format supports attributes.", + " ", + " Each attribute has the following structure:", + " ", + " [var_nm@]att_nm[:{s|d|i}]=[att_val|{[var_nm@]att_nm}]", + " ", + " var_nm Variable name (optional). Example: pressure", + " att_nm Attribute name. Example: units", + " att_val Comma-separated list of attribute values. Example: pascal", + " ", + " The value of var_nm is the name of the variable containing the attribute (named att_nm) that", + " you want to set. Use wildcards to set the attribute att_nm to more than one variable.", + " A value of var_nm of '*' will set the attribute att_nm to all data variables.", + " If var_nm is missing then att_nm refers to a global attribute.", + " ", + " The value of att_nm is the name of the attribute you want to set. For each attribute a string (att_nm:s),", + " a double (att_nm:d) or an integer (att_nm:i) type can be defined. By default the native type is set.", + " ", + " The value of att_val is the contents of the attribute att_nm. att_val may be a single value", + " or one-dimensional array of elements. The type and the number of elements of an attribute will be detected", + " automatically from the contents of the values. An already existing attribute att_nm will be overwritten", + " or it will be removed if att_val is omitted. Alternatively, the values of an existing attribute can be copied.", + " This attribute must then be enclosed in curly brackets.", + " ", + " A special meaning has the attribute name FILE. If this is the 1st attribute then all attributes", + " are read from a file specified in the value of att_val.", + "", + "PARAMETER", + " attributes STRING Comma-separated list of attributes. ", + "", + "NOTE", + " Attributes are evaluated by CDO when opening infile. Therefor the result of this operator is not available", + " for other operators when this operator is used in chaining operators.", +}; + +const CdoHelp SetpartabHelp = { + "NAME", + " setpartabp, setpartabn - Set parameter table", + "", + "SYNOPSIS", + " <operator>,table[,convert] infile outfile", + "", + "DESCRIPTION", + " This module transforms data and metadata of infile via a parameter table and writes the result to outfile.", + " A parameter table is an ASCII formatted file with a set of parameter entries for each variable. Each new set have to", + " start with \"\\¶meter\" and to end with \"/\".", + " ", + " The following parameter table entries are supported:", + " ", + " Entry & Type & Description ", + " name & WORD & Name of the variable", + " out_name & WORD & New name of the variable", + " param & WORD & Parameter identifier (GRIB1: code[.tabnum]; GRIB2: num[.cat[.dis]])", + " out_param & WORD & New parameter identifier", + " type & WORD & Data type (real or double)", + " standard_name & WORD & As defined in the CF standard name table", + " long_name & STRING & Describing the variable", + " units & STRING & Specifying the units for the variable", + " comment & STRING & Information concerning the variable", + " cell_methods & STRING & Information concerning calculation of means or climatologies", + " cell_measures & STRING & Indicates the names of the variables containing cell areas and volumes", + " missing_value & FLOAT & Specifying how missing data will be identified", + " valid_min & FLOAT & Minimum valid value", + " valid_max & FLOAT & Maximum valid value", + " ok_min_mean_abs & FLOAT & Minimum absolute mean", + " ok_max_mean_abs & FLOAT & Maximum absolute mean", + " factor & FLOAT & Scale factor", + " delete & INTEGER & Set to 1 to delete variable", + " convert & INTEGER & Set to 1 to convert the unit if necessary", + " ", + " Unsupported parameter table entries are stored as variable attributes.", + " The search key for the variable depends on the operator. Use setpartabn to search variables by the name.", + " This is typically used for NetCDF datasets. The operator setpartabp searches variables by the parameter ID.", + "", + "OPERATORS", + " setpartabp Set parameter table", + " Search variables by the parameter identifier.", + " setpartabn Set parameter table", + " Search variables by name.", + "", + "PARAMETER", + " table STRING Parameter table file or name", + " convert STRING Converts the units if necessary", +}; + +const CdoHelp SetHelp = { + "NAME", + " setcodetab, setcode, setparam, setname, setunit, setlevel, setltype, ", + " setmaxsteps - Set field info", + "", + "SYNOPSIS", + " setcodetab,table infile outfile", + " setcode,code infile outfile", + " setparam,param infile outfile", + " setname,name infile outfile", + " setunit,unit infile outfile", + " setlevel,level infile outfile", + " setltype,ltype infile outfile", + " setmaxsteps,maxsteps infile outfile", + "", + "DESCRIPTION", + " This module sets some field information. Depending on the chosen operator the ", + " parameter table, code number, parameter identifier, variable name or level is set.", + "", + "OPERATORS", + " setcodetab Set parameter code table", + " Sets the parameter code table for all variables.", + " setcode Set code number", + " Sets the code number for all variables to the same given value.", + " setparam Set parameter identifier", + " Sets the parameter identifier of the first variable.", + " setname Set variable name", + " Sets the name of the first variable.", + " setunit Set variable unit", + " Sets the unit of the first variable.", + " setlevel Set level", + " Sets the first level of all variables.", + " setltype Set GRIB level type", + " Sets the GRIB level type of all variables.", + " setmaxsteps Set max timesteps", + " Sets maximum number of timesteps", + "", + "PARAMETER", + " table STRING Parameter table file or name", + " code INTEGER Code number", + " param STRING Parameter identifier (GRIB1: code[.tabnum]; GRIB2: num[.cat[.dis]])", + " name STRING Variable name", + " level FLOAT New level", + " ltype INTEGER GRIB level type", + " maxsteps INTEGER Maximum number of timesteps", +}; + +const CdoHelp SettimeHelp = { + "NAME", + " setdate, settime, setday, setmon, setyear, settunits, settaxis, settbounds, ", + " setreftime, setcalendar, shifttime - Set time", + "", + "SYNOPSIS", + " setdate,date infile outfile", + " settime,time infile outfile", + " setday,day infile outfile", + " setmon,month infile outfile", + " setyear,year infile outfile", + " settunits,units infile outfile", + " settaxis,date,time[,inc] infile outfile", + " settbounds,frequency infile outfile", + " setreftime,date,time[,units] infile outfile", + " setcalendar,calendar infile outfile", + " shifttime,shiftValue infile outfile", + "", + "DESCRIPTION", + " This module sets the time axis or part of the time axis. Which part of the time axis is", + " overwritten/created depends on the chosen operator. The number of time steps does not change.", + "", + "OPERATORS", + " setdate Set date", + " Sets the date in every timestep to the same given value.", + " settime Set time of the day", + " Sets the time in every timestep to the same given value.", + " setday Set day", + " Sets the day in every timestep to the same given value.", + " setmon Set month", + " Sets the month in every timestep to the same given value.", + " setyear Set year", + " Sets the year in every timestep to the same given value.", + " settunits Set time units", + " Sets the base units of a relative time axis.", + " settaxis Set time axis", + " Sets the time axis.", + " settbounds Set time bounds", + " Sets the time bounds.", + " setreftime Set reference time", + " Sets the reference time of a relative time axis.", + " setcalendar Set calendar", + " Sets the calendar attribute of a relative time axis.", + " shifttime Shift timesteps", + " Shifts all timesteps by the parameter shiftValue.", + "", + "PARAMETER", + " day INTEGER Value of the new day", + " month INTEGER Value of the new month", + " year INTEGER Value of the new year", + " units STRING Base units of the time axis (seconds, minutes, hours, days, months, years)", + " date STRING Date (format: YYYY-MM-DD)", + " time STRING Time (format: hh:mm:ss)", + " inc STRING Optional increment (seconds, minutes, hours, days, months, years) [default: 1hour]", + " frequency STRING Frequency of the time series (hour, day, month, year)", + " calendar STRING Calendar (standard, proleptic_gregorian, 360_day, 365_day, 366_day)", + " shiftValue STRING Shift value (e.g. -3hour)", +}; + +const CdoHelp ChangeHelp = { + "NAME", + " chcode, chparam, chname, chunit, chlevel, chlevelc, chlevelv - ", + " Change field header", + "", + "SYNOPSIS", + " chcode,oldcode,newcode[,...] infile outfile", + " chparam,oldparam,newparam,... infile outfile", + " chname,oldname,newname,... infile outfile", + " chunit,oldunit,newunit,... infile outfile", + " chlevel,oldlev,newlev,... infile outfile", + " chlevelc,code,oldlev,newlev infile outfile", + " chlevelv,name,oldlev,newlev infile outfile", + "", + "DESCRIPTION", + " This module reads fields from infile, changes some header values", + " and writes the results to outfile. The kind of changes depends on ", + " the chosen operator.", + "", + "OPERATORS", + " chcode Change code number", + " Changes some user given code numbers to new user given values.", + " chparam Change parameter identifier", + " Changes some user given parameter identifiers to new user given values.", + " chname Change variable or coordinate name", + " Changes some user given variable or coordinate names to new user given names.", + " chunit Change variable unit", + " Changes some user given variable units to new user given units.", + " chlevel Change level", + " Changes some user given levels to new user given values.", + " chlevelc Change level of one code", + " Changes one level of a user given code number.", + " chlevelv Change level of one variable", + " Changes one level of a user given variable name.", + "", + "PARAMETER", + " code INTEGER Code number", + " oldcode,newcode,... INTEGER Pairs of old and new code numbers", + " oldparam,newparam,... STRING Pairs of old and new parameter identifiers", + " name STRING Variable name", + " oldname,newname,... STRING Pairs of old and new variable names", + " oldlev FLOAT Old level", + " newlev FLOAT New level", + " oldlev,newlev,... FLOAT Pairs of old and new levels", +}; + +const CdoHelp SetgridHelp = { + "NAME", + " setgrid, setgridtype, setgridarea, setgridmask - Set grid information", + "", + "SYNOPSIS", + " setgrid,grid infile outfile", + " setgridtype,gridtype infile outfile", + " setgridarea,gridarea infile outfile", + " setgridmask,gridmask infile outfile", + "", + "DESCRIPTION", + " This module modifies the metadata of the horizontal grid. Depending on the chosen operator", + " a new grid description is set, the coordinates are converted or the grid cell area is added.", + "", + "OPERATORS", + " setgrid Set grid", + " Sets a new grid description. The input fields need to have the same grid size as the size", + " of the target grid description.", + " setgridtype Set grid type", + " Sets the grid type of all input fields. The following grid types are available:", + " curvilinear " " Converts a regular grid to a curvilinear grid", + " unstructured" " Converts a regular or curvilinear grid to an unstructured grid", + " dereference " " Dereference a reference to a grid", + " regular " " Linear interpolation of a reduced Gaussian grid to a regular Gaussian grid", + " regularnn " " Nearest neighbor interpolation of a reduced Gaussian grid to a regular Gaussian grid", + " lonlat " " Converts a regular lonlat grid stored as a curvilinear grid back to a lonlat grid", + " projection " " Removes the geographical coordinates if projection parameter available", + " setgridarea Set grid cell area", + " Sets the grid cell area. The parameter gridarea is the path to a data file,", + " the first field is used as grid cell area. The input fields need to have the same", + " grid size as the grid cell area. The grid cell area is used to compute", + " the weights of each grid cell if needed by an operator, e.g. for fldmean.", + " setgridmask Set grid mask", + " Sets the grid mask. The parameter gridmask is the path to a data file,", + " the first field is used as the grid mask. The input fields need to have the same", + " grid size as the grid mask. The grid mask is used as the target grid mask for", + " remapping, e.g. for remapbil.", + "", + "PARAMETER", + " grid STRING Grid description file or name", + " gridtype STRING Grid type (curvilinear, unstructured, regular, lonlat, projection or dereference)", + " gridarea STRING Data file, the first field is used as grid cell area", + " gridmask STRING Data file, the first field is used as grid mask", +}; + +const CdoHelp SetzaxisHelp = { + "NAME", + " setzaxis, genlevelbounds - Set z-axis information", + "", + "SYNOPSIS", + " setzaxis,zaxis infile outfile", + " genlevelbounds[,zbot[,ztop]] infile outfile", + "", + "DESCRIPTION", + " This module modifies the metadata of the vertical grid.", + "", + "OPERATORS", + " setzaxis Set z-axis", + " This operator sets the z-axis description of all variables with the same number of level as the new z-axis.", + " genlevelbounds Generate level bounds", + " Generates the layer bounds of the z-axis.", + "", + "PARAMETER", + " zaxis STRING Z-axis description file or name of the target z-axis", + " zbot FLOAT Specifying the bottom of the vertical column. Must have the same units as z-axis. ", + " ztop FLOAT Specifying the top of the vertical column. Must have the same units as z-axis. ", +}; + +const CdoHelp InvertHelp = { + "NAME", + " invertlat - Invert latitudes", + "", + "SYNOPSIS", + " invertlat infile outfile", + "", + "DESCRIPTION", + " This operator inverts the latitudes of all fields on a rectilinear grid. ", +}; + +const CdoHelp InvertlevHelp = { + "NAME", + " invertlev - Invert levels", + "", + "SYNOPSIS", + " invertlev infile outfile", + "", + "DESCRIPTION", + " This operator inverts the levels of all 3D variables.", +}; + +const CdoHelp ShiftxyHelp = { + "NAME", + " shiftx, shifty - Shift field", + "", + "SYNOPSIS", + " <operator>,<nshift>,<cyclic>,<coord> infile outfile", + "", + "DESCRIPTION", + " This module contains operators to shift all fields in x or y direction.", + " All fields need to have the same horizontal rectilinear or curvilinear grid.", + "", + "OPERATORS", + " shiftx Shift x", + " Shifts all fields in x direction.", + " shifty Shift y", + " Shifts all fields in y direction.", + "", + "PARAMETER", + " nshift INTEGER Number of grid cells to shift (default: 1)", + " cyclic STRING If set, cells are filled up cyclic (default: missing value)", + " coord STRING If set, coordinates are also shifted", +}; + +const CdoHelp MaskregionHelp = { + "NAME", + " maskregion - Mask regions", + "", + "SYNOPSIS", + " maskregion,regions infile outfile", + "", + "DESCRIPTION", + " Masks different regions of the input fields.", + " The grid cells inside a region are untouched, the cells outside are set to missing value.", + " Considered are only those grid cells with the grid center inside the regions.", + " All input fields must have the same horizontal grid.", + " ", + " Regions can be defined by the user via an ASCII file.", + " Each region consists of the geographic coordinates of a convex polygon.", + " Each line of a polygon description file contains the longitude and latitude of one point.", + " Each polygon description file can contain one or more polygons separated by a line with the character \\&.", + " ", + " Predefined regions of countries can be specified via the country codes.", + " A country is specified with dcw:<CountryCode>. Country codes can be combined with the plus sign.", + "", + "PARAMETER", + " regions STRING Comma-separated list of ASCII formatted files with different regions", +}; + +const CdoHelp MaskboxHelp = { + "NAME", + " masklonlatbox, maskindexbox - Mask a box", + "", + "SYNOPSIS", + " masklonlatbox,lon1,lon2,lat1,lat2 infile outfile", + " maskindexbox,idx1,idx2,idy1,idy2 infile outfile", + "", + "DESCRIPTION", + " Masks grid cells inside a lon/lat or index box. The elements inside the box are untouched, the ", + " elements outside are set to missing value. All input fields need to have the same horizontal grid.", + " Use sellonlatbox or selindexbox if only the data inside the box are needed.", + "", + "OPERATORS", + " masklonlatbox Mask a longitude/latitude box", + " Masks grid cells inside a lon/lat box. The user must specify the longitude and latitude of the edges of the box.", + " Only those grid cells are considered whose grid center lies within the lon/lat box.", + " For rotated lon/lat grids the parameters must be specified in rotated coordinates.", + " maskindexbox Mask an index box", + " Masks grid cells within an index box. The user must specify the indices of the edges of the box.", + " The index of the left edge can be greater then the one of the right edge. Use negative indexing to", + " start from the end. The input grid must be a regular lon/lat or a 2D curvilinear grid.", + "", + "PARAMETER", + " lon1 FLOAT Western longitude", + " lon2 FLOAT Eastern longitude", + " lat1 FLOAT Southern or northern latitude", + " lat2 FLOAT Northern or southern latitude", + " idx1 INTEGER Index of first longitude", + " idx2 INTEGER Index of last longitude", + " idy1 INTEGER Index of first latitude", + " idy2 INTEGER Index of last latitude", +}; + +const CdoHelp SetboxHelp = { + "NAME", + " setclonlatbox, setcindexbox - Set a box to constant", + "", + "SYNOPSIS", + " setclonlatbox,c,lon1,lon2,lat1,lat2 infile outfile", + " setcindexbox,c,idx1,idx2,idy1,idy2 infile outfile", + "", + "DESCRIPTION", + " Sets a box of the rectangularly understood field to a constant value. The elements outside ", + " the box are untouched, the elements inside are set to the given constant. All input fields ", + " need to have the same horizontal grid.", + "", + "OPERATORS", + " setclonlatbox Set a longitude/latitude box to constant", + " Sets the values of a longitude/latitude box to a constant value. The ", + " user has to give the longitudes and latitudes of the edges of the box.", + " setcindexbox Set an index box to constant", + " Sets the values of an index box to a constant value. The user has to ", + " give the indices of the edges of the box. The index of the left edge ", + " can be greater than the one of the right edge.", + "", + "PARAMETER", + " c FLOAT Constant", + " lon1 FLOAT Western longitude", + " lon2 FLOAT Eastern longitude", + " lat1 FLOAT Southern or northern latitude", + " lat2 FLOAT Northern or southern latitude", + " idx1 INTEGER Index of first longitude", + " idx2 INTEGER Index of last longitude", + " idy1 INTEGER Index of first latitude", + " idy2 INTEGER Index of last latitude", +}; + +const CdoHelp EnlargeHelp = { + "NAME", + " enlarge - Enlarge fields", + "", + "SYNOPSIS", + " enlarge,grid infile outfile", + "", + "DESCRIPTION", + " Enlarge all fields of infile to a user given horizontal grid. Normally only the last ", + " field element is used for the enlargement. If however the input and output", + " grid are regular lon/lat grids, a zonal or meridional enlargement is possible.", + " Zonal enlargement takes place, if the xsize of the input field is 1 and ", + " the ysize of both grids are the same. For meridional enlargement the ysize", + " have to be 1 and the xsize of both grids should have the same size.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", +}; + +const CdoHelp SetmissHelp = { + "NAME", + " setmissval, setctomiss, setmisstoc, setrtomiss, setvrange, setmisstonn, ", + " setmisstodis - Set missing value", + "", + "SYNOPSIS", + " setmissval,newmiss infile outfile", + " setctomiss,c infile outfile", + " setmisstoc,c infile outfile", + " setrtomiss,rmin,rmax infile outfile", + " setvrange,rmin,rmax infile outfile", + " setmisstonn infile outfile", + " setmisstodis[,neighbors] infile outfile", + "", + "DESCRIPTION", + " This module sets part of a field to missing value or missing values", + " to a constant value. Which part of the field is set depends on the ", + " chosen operator.", + "", + "OPERATORS", + " setmissval Set a new missing value", + " / newmiss if i(t,x) EQ miss", + " o(t,x) = ", + " \\ i(t,x) if i(t,x) NE miss", + " setctomiss Set constant to missing value", + " / miss if i(t,x) EQ c", + " o(t,x) = ", + " \\ i(t,x) if i(t,x) NE c", + " setmisstoc Set missing value to constant", + " / c if i(t,x) EQ miss", + " o(t,x) = ", + " \\ i(t,x) if i(t,x) NE miss", + " setrtomiss Set range to missing value", + " / miss if i(t,x) GE rmin AND i(t,x) LE rmax", + " o(t,x) = ", + " \\ i(t,x) if i(t,x) LT rmin OR i(t,x) GT rmax", + " setvrange Set valid range", + " / miss if i(t,x) LT rmin OR i(t,x) GT rmax", + " o(t,x) = ", + " \\ i(t,x) if i(t,x) GE rmin AND i(t,x) LE rmax", + " setmisstonn Set missing value to nearest neighbor", + " Set all missing values to the nearest non missing value.", + " / i(t,y) if i(t,x) EQ miss AND i(t,y) NE miss", + " o(t,x) = ", + " \\ i(t,x) if i(t,x) NE miss", + " setmisstodis Set missing value to distance-weighted average", + " Set all missing values to the distance-weighted average of the nearest non missing values.", + " The default number of nearest neighbors is 4.", + "", + "PARAMETER", + " neighbors INTEGER Number of nearest neighbors", + " newmiss FLOAT New missing value", + " c FLOAT Constant", + " rmin FLOAT Lower bound", + " rmax FLOAT Upper bound", +}; + +const CdoHelp VertfillmissHelp = { + "NAME", + " vertfillmiss - Vertical filling of missing values", + "", + "SYNOPSIS", + " vertfillmiss[,parameter] infile outfile", + "", + "DESCRIPTION", + " This operator fills in vertical missing values.", + " The method parameter can be used to select the filling method.", + " The default method=nearest fills missing values with the nearest neighbor value.", + " Other options are forward and backward to fill missing values by forward or backward propagation of values.", + " Use the limit parameter to set the maximum number of consecutive missing values to fill and max_gaps to set the maximum number of gaps to fill.", + "", + "PARAMETER", + " method STRING Fill method [nearest|linear|forward|backward] (default: nearest)", + " limit INTEGER The maximum number of consecutive missing values to fill (default: all)", + " max_gaps INTEGER The maximum number of gaps to fill (default: all)", +}; + +const CdoHelp TimfillmissHelp = { + "NAME", + " timfillmiss - Temporal filling of missing values", + "", + "SYNOPSIS", + " timfillmiss[,parameter] infile outfile", + "", + "DESCRIPTION", + " This operator fills in temporally missing values.", + " The method parameter can be used to select the filling method.", + " The default method=nearest fills missing values with the nearest neighbor value.", + " Other options are forward and backward to fill missing values by forward or backward propagation of values.", + " Use the limit parameter to set the maximum number of consecutive missing values to fill and max_gaps to set the maximum number of gaps to fill.", + "", + "PARAMETER", + " method STRING Fill method [nearest|linear|forward|backward] (default: nearest)", + " limit INTEGER The maximum number of consecutive missing values to fill (default: all)", + " max_gaps INTEGER The maximum number of gaps to fill (default: all)", +}; + +const CdoHelp SetgridcellHelp = { + "NAME", + " setgridcell - Set the value of a grid cell", + "", + "SYNOPSIS", + " setgridcell,parameter infile outfile", + "", + "DESCRIPTION", + " This operator sets the value of the selected grid cells. The grid cells can be selected by a comma-separated list of grid cell indices", + " or a mask. The mask is read from a data file, which may contain only one field. If no grid cells are selected, all values are set.", + "", + "PARAMETER", + " value FLOAT Value of the grid cell", + " cell INTEGER Comma-separated list of grid cell indices", + " mask STRING Name of the data file which contains the mask", +}; + +const CdoHelp ExprHelp = { + "NAME", + " expr, exprf, aexpr, aexprf - Evaluate expressions", + "", + "SYNOPSIS", + " expr,instr infile outfile", + " exprf,filename infile outfile", + " aexpr,instr infile outfile", + " aexprf,filename infile outfile", + "", + "DESCRIPTION", + " This module arithmetically processes every timestep of the input dataset.", + " Each individual assignment statement have to end with a semi-colon.", + " The special key _ALL_ is used as a template. A statement with a template is replaced for all variable names.", + " Unlike regular variables, temporary variables are never written to the output stream.", + " To define a temporary variable simply prefix the variable name with an underscore (e.g. _varname)", + " when the variable is declared.", + " ", + " The following operators are supported:", + " ", + " Operator & Meaning & Example & Result ", + " = & assignment & x = y & Assigns y to x", + " + & addition & x + y & Sum of x and y", + " - & subtraction & x - y & Difference of x and y ", + " * & multiplication & x * y & Product of x and y ", + " / & division & x / y & Quotient of x and y", + " ^ & exponentiation & x ^y & Exponentiates x with y ", + " == & equal to & x == y & 1, if x equal to y; else 0", + " != & not equal to & x != y & 1, if x not equal to y; else 0", + " > & greater than & x > y & 1, if x greater than y; else 0", + " < & less than & x < y & 1, if x less than y; else 0", + " >= & greater equal & x >= y & 1, if x greater equal y; else 0", + " <= & less equal & x <= y & 1, if x less equal y; else 0", + " <=> & less equal greater & x <=> y & -1, if x less y; 1, if x greater y; else 0 ", + " && & logical AND & x && y & 1, if x and y not equal 0; else 0", + " || & logical OR & x || y & 1, if x or y not equal 0; else 0", + " ! & logical NOT & !x & 1, if x equal 0; else 0", + " ?: & ternary conditional & x ? y : z & y, if x not equal 0, else z ", + " ", + " The following functions are supported:", + " ", + " Math intrinsics:", + " ", + " abs(x) " " Absolute value of x", + " floor(x) " " Round to largest integral value not greater than x", + " ceil(x) " " Round to smallest integral value not less than x", + " float(x) " " 32-bit float value of x", + " int(x) " " Integer value of x", + " nint(x) " " Nearest integer value of x", + " sqr(x) " " Square of x", + " sqrt(x) " " Square Root of x", + " exp(x) " " Exponential of x", + " ln(x) " " Natural logarithm of x", + " log10(x) " " Base 10 logarithm of x", + " sin(x) " " Sine of x, where x is specified in radians", + " cos(x) " " Cosine of x, where x is specified in radians", + " tan(x) " " Tangent of x, where x is specified in radians", + " asin(x) " " Arc-sine of x, where x is specified in radians", + " acos(x) " " Arc-cosine of x, where x is specified in radians", + " atan(x) " " Arc-tangent of x, where x is specified in radians", + " sinh(x) " " Hyperbolic sine of x, where x is specified in radians", + " cosh(x) " " Hyperbolic cosine of x, where x is specified in radians", + " tanh(x) " " Hyperbolic tangent of x, where x is specified in radians", + " asinh(x) " " Inverse hyperbolic sine of x, where x is specified in radians", + " acosh(x) " " Inverse hyperbolic cosine of x, where x is specified in radians", + " atanh(x) " " Inverse hyperbolic tangent of x, where x is specified in radians", + " rad(x) " " Convert x from degrees to radians", + " deg(x) " " Convert x from radians to degrees", + " rand(x) " " Replace x by pseudo-random numbers in the range of 0 to 1 ", + " isMissval(x)" " Returns 1 where x is missing", + " ", + " mod(x,y) " " Floating-point remainder of x/ y", + " min(x,y) " " Minimum value of x and y", + " max(x,y) " " Maximum value of x and y", + " pow(x,y) " " Power function", + " hypot(x,y) " " Euclidean distance function, sqrt(x*x + y*y)", + " atan2(x,y) " " Arc tangent function of y/x, using signs to determine quadrants ", + " ", + " Coordinates:", + " ", + " clon(x) " " Longitude coordinate of x (available only if x has geographical coordinates)", + " clat(x) " " Latitude coordinate of x (available only if x has geographical coordinates)", + " gridarea(x) " " Grid cell area of x (available only if x has geographical coordinates)", + " gridindex(x) " " Grid cell indices of x", + " clev(x) " " Level coordinate of x (0, if x is a 2D surface variable)", + " clevidx(x) " " Level index of x (0, if x is a 2D surface variable)", + " cthickness(x)" " Layer thickness, upper minus lower level bound of x (1, if level bounds are missing)", + " ctimestep() " " Timestep number (1 to N)", + " cdate() " " Verification date as YYYYMMDD", + " ctime() " " Verification time as HHMMSS.millisecond", + " cdeltat() " " Difference between current and last timestep in seconds", + " cday() " " Day as DD", + " cmonth() " " Month as MM", + " cyear() " " Year as YYYY", + " csecond() " " Second as SS.millisecond", + " cminute() " " Minute as MM", + " chour() " " Hour as HH", + " ", + " Constants:", + " ", + " ngp(x) " " Number of horizontal grid points", + " nlev(x) " " Number of vertical levels", + " size(x) " " Total number of elements (ngp(x)*nlev(x))", + " missval(x)" " Returns the missing value of variable x", + " ", + " Statistical values over a field:", + " ", + " fldmin(x), fldmax(x), fldrange(x), fldsum(x), fldmean(x), fldavg(x), fldstd(x), fldstd1(x),", + " fldvar(x), fldvar1(x), fldskew(x), fldkurt(x), fldmedian(x)", + " ", + " Zonal statistical values for regular 2D grids:", + " ", + " zonmin(x), zonmax(x), zonrange(x), zonsum(x), zonmean(x), zonavg(x), zonstd(x), zonstd1(x),", + " zonvar(x), zonvar1(x), zonskew(x), zonkurt(x), zonmedian(x)", + " ", + " Vertical statistical values:", + " ", + " vertmin(x), vertmax(x), vertrange(x), vertsum(x), vertmean(x), vertavg(x), vertstd(x), vertstd1(x),", + " vertvar(x), vertvar1(x)", + " ", + " Miscellaneous:", + " ", + " sellevel(x,k) " " Select level k of variable x", + " sellevidx(x,k) " " Select level index k of variable x", + " sellevelrange(x,k1,k2) " " Select all levels of variable x in the range k1 to k2", + " sellevidxrange(x,k1,k2)" " Select all level indices of variable x in the range k1 to k2", + " remove(x) " " Remove variable x from output stream", + " ", + "", + "OPERATORS", + " expr Evaluate expressions", + " The processing instructions are read from the parameter.", + " exprf Evaluate expressions script", + " Contrary to expr the processing instructions are read from a file.", + " aexpr Evaluate expressions and append results", + " Same as expr, but keep input variables and append results", + " aexprf Evaluate expression script and append results", + " Same as exprf, but keep input variables and append results", + "", + "PARAMETER", + " instr STRING Processing instructions (need to be 'quoted' in most cases)", + " filename STRING File with processing instructions", + "", + "NOTE", + " If the input stream contains duplicate entries of the same variable name then the last one is used.", +}; + +const CdoHelp MathHelp = { + "NAME", + " abs, int, nint, pow, sqr, sqrt, exp, ln, log10, sin, cos, tan, asin, acos, ", + " atan, reci, not - Mathematical functions", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module contains some standard mathematical functions.", + " All trigonometric functions calculate with radians.", + "", + "OPERATORS", + " abs Absolute value", + " o(t,x) = abs(i(t,x))", + " int Integer value", + " o(t,x) = int(i(t,x))", + " nint Nearest integer value", + " o(t,x) = nint(i(t,x))", + " pow Power", + " o(t,x) = i(t,x)^y", + " sqr Square", + " o(t,x) = i(t,x)^2", + " sqrt Square root", + " o(t,x) = sqrt(i(t,x))", + " exp Exponential", + " o(t,x) = e^i(t,x)", + " ln Natural logarithm", + " o(t,x) = ln(i(t,x))", + " log10 Base 10 logarithm", + " o(t,x) = log10(i(t,x))", + " sin Sine", + " o(t,x) = sin(i(t,x))", + " cos Cosine", + " o(t,x) = cos(i(t,x))", + " tan Tangent", + " o(t,x) = tan(i(t,x))", + " asin Arc sine", + " o(t,x) = asin(i(t,x))", + " acos Arc cosine", + " o(t,x) = acos(i(t,x))", + " atan Arc tangent", + " o(t,x) = atan(i(t,x))", + " reci Reciprocal value", + " o(t,x) = 1 / i(t,x)", + " not Logical NOT", + " o(t,x) = 1, if x equal 0; else 0", +}; + +const CdoHelp ArithcHelp = { + "NAME", + " addc, subc, mulc, divc, minc, maxc - Arithmetic with a constant", + "", + "SYNOPSIS", + " <operator>,c infile outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic with all field elements of a dataset and ", + " a constant. The fields in outfile inherit the meta data from infile.", + "", + "OPERATORS", + " addc Add a constant", + " o(t,x) = i(t,x) + c", + " subc Subtract a constant", + " o(t,x) = i(t,x) - c", + " mulc Multiply with a constant", + " o(t,x) = i(t,x) * c", + " divc Divide by a constant", + " o(t,x) = i(t,x) / c", + " minc Minimum of a field and a constant", + " o(t,x) = min(i(t,x), c)", + " maxc Maximum of a field and a constant", + " o(t,x) = max(i(t,x), c)", + "", + "PARAMETER", + " c FLOAT Constant", +}; + +const CdoHelp ArithHelp = { + "NAME", + " add, sub, mul, div, min, max, atan2 - Arithmetic on two datasets", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of two datasets.", + " The number of fields in infile1 should be the same as in infile2.", + " The fields in outfile inherit the meta data from infile1.", + " All operators in this module simply process one field after the other from the two input files.", + " Neither the order of the variables nor the date is checked.", + " One of the input files can contain only one timestep or one variable.", + "", + "OPERATORS", + " add Add two fields", + " o(t,x) = i_1(t,x) + i_2(t,x)", + " sub Subtract two fields", + " o(t,x) = i_1(t,x) - i_2(t,x)", + " mul Multiply two fields", + " o(t,x) = i_1(t,x) * i_2(t,x)", + " div Divide two fields", + " o(t,x) = i_1(t,x) / i_2(t,x)", + " min Minimum of two fields", + " o(t,x) = min(i_1(t,x), i_2(t,x))", + " max Maximum of two fields", + " o(t,x) = max(i_1(t,x), i_2(t,x))", + " atan2 Arc tangent of two fields", + " The atan2 operator calculates the arc tangent of two fields. The result is", + " in radians, which is between -PI and PI (inclusive).", + " ", + " o(t,x) = atan2(i_1(t,x), i_2(t,x))", +}; + +const CdoHelp DayarithHelp = { + "NAME", + " dayadd, daysub, daymul, daydiv - Daily arithmetic", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of a time series and one timestep with the same day, month and year.", + " For each field in infile1 the corresponding field of the timestep in infile2 with the same day, month and year is used.", + " The input files need to have the same structure with the same variables.", + " Usually infile2 is generated by an operator of the module DAYSTAT.", + "", + "OPERATORS", + " dayadd Add daily time series", + " Adds a time series and a daily time series.", + " daysub Subtract daily time series", + " Subtracts a time series and a daily time series.", + " daymul Multiply daily time series", + " Multiplies a time series and a daily time series.", + " daydiv Divide daily time series", + " Divides a time series and a daily time series.", +}; + +const CdoHelp MonarithHelp = { + "NAME", + " monadd, monsub, monmul, mondiv - Monthly arithmetic", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of a time series and one timestep with the same month and year.", + " For each field in infile1 the corresponding field of the timestep in infile2 with the same month and year is used.", + " The input files need to have the same structure with the same variables.", + " Usually infile2 is generated by an operator of the module MONSTAT.", + "", + "OPERATORS", + " monadd Add monthly time series", + " Adds a time series and a monthly time series.", + " monsub Subtract monthly time series", + " Subtracts a time series and a monthly time series.", + " monmul Multiply monthly time series", + " Multiplies a time series and a monthly time series.", + " mondiv Divide monthly time series", + " Divides a time series and a monthly time series.", +}; + +const CdoHelp YeararithHelp = { + "NAME", + " yearadd, yearsub, yearmul, yeardiv - Yearly arithmetic", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of a time series and one timestep", + " with the same year. For each field in infile1 the corresponding", + " field of the timestep in infile2 with the same year is used.", + " The header information in infile1 have to be the same as in infile2.", + " Usually infile2 is generated by an operator of the module YEARSTAT.", + "", + "OPERATORS", + " yearadd Add yearly time series", + " Adds a time series and a yearly time series.", + " yearsub Subtract yearly time series", + " Subtracts a time series and a yearly time series.", + " yearmul Multiply yearly time series", + " Multiplies a time series and a yearly time series.", + " yeardiv Divide yearly time series", + " Divides a time series and a yearly time series.", +}; + +const CdoHelp YhourarithHelp = { + "NAME", + " yhouradd, yhoursub, yhourmul, yhourdiv - Multi-year hourly arithmetic", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of a time series and one timestep with the same hour and day of year.", + " For each field in infile1 the corresponding field of the timestep in infile2 with the same hour and day of year is used.", + " The input files need to have the same structure with the same variables.", + " Usually infile2 is generated by an operator of the module YHOURSTAT.", + "", + "OPERATORS", + " yhouradd Add multi-year hourly time series", + " Adds a time series and a multi-year hourly time series.", + " yhoursub Subtract multi-year hourly time series", + " Subtracts a time series and a multi-year hourly time series.", + " yhourmul Multiply multi-year hourly time series", + " Multiplies a time series and a multi-year hourly time series.", + " yhourdiv Divide multi-year hourly time series", + " Divides a time series and a multi-year hourly time series.", +}; + +const CdoHelp YdayarithHelp = { + "NAME", + " ydayadd, ydaysub, ydaymul, ydaydiv - Multi-year daily arithmetic", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of a time series and one timestep with the same day of year.", + " For each field in infile1 the corresponding field of the timestep in infile2 with the same day of year is used.", + " The input files need to have the same structure with the same variables.", + " Usually infile2 is generated by an operator of the module YDAYSTAT.", + "", + "OPERATORS", + " ydayadd Add multi-year daily time series", + " Adds a time series and a multi-year daily time series.", + " ydaysub Subtract multi-year daily time series", + " Subtracts a time series and a multi-year daily time series.", + " ydaymul Multiply multi-year daily time series", + " Multiplies a time series and a multi-year daily time series.", + " ydaydiv Divide multi-year daily time series", + " Divides a time series and a multi-year daily time series.", +}; + +const CdoHelp YmonarithHelp = { + "NAME", + " ymonadd, ymonsub, ymonmul, ymondiv - Multi-year monthly arithmetic", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of a time series and one timestep with the same month of year.", + " For each field in infile1 the corresponding field of the timestep in infile2 with the same month of year is used.", + " The input files need to have the same structure with the same variables.", + " Usually infile2 is generated by an operator of the module YMONSTAT.", + "", + "OPERATORS", + " ymonadd Add multi-year monthly time series", + " Adds a time series and a multi-year monthly time series.", + " ymonsub Subtract multi-year monthly time series", + " Subtracts a time series and a multi-year monthly time series.", + " ymonmul Multiply multi-year monthly time series", + " Multiplies a time series with a multi-year monthly time series.", + " ymondiv Divide multi-year monthly time series", + " Divides a time series by a multi-year monthly time series.", +}; + +const CdoHelp YseasarithHelp = { + "NAME", + " yseasadd, yseassub, yseasmul, yseasdiv - Multi-year seasonal arithmetic", + "", + "SYNOPSIS", + " <operator> infile1 infile2 outfile", + "", + "DESCRIPTION", + " This module performs simple arithmetic of a time series and one timestep with the same season.", + " For each field in infile1 the corresponding field of the timestep in infile2 with the same season is used.", + " The input files need to have the same structure with the same variables.", + " Usually infile2 is generated by an operator of the module YSEASSTAT.", + "", + "OPERATORS", + " yseasadd Add multi-year seasonal time series", + " Adds a time series and a multi-year seasonal time series.", + " yseassub Subtract multi-year seasonal time series", + " Subtracts a time series and a multi-year seasonal time series.", + " yseasmul Multiply multi-year seasonal time series", + " Multiplies a time series and a multi-year seasonal time series.", + " yseasdiv Divide multi-year seasonal time series", + " Divides a time series and a multi-year seasonal time series.", +}; + +const CdoHelp ArithdaysHelp = { + "NAME", + " muldpm, divdpm, muldpy, divdpy - Arithmetic with days", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module multiplies or divides each timestep of a dataset with the corresponding", + " days per month or days per year. The result of these functions depends on the used", + " calendar of the input data.", + "", + "OPERATORS", + " muldpm Multiply with days per month", + " o(t,x) = i(t,x) * days_per_month", + " divdpm Divide by days per month", + " o(t,x) = i(t,x) / days_per_month", + " muldpy Multiply with days per year", + " o(t,x) = i(t,x) * days_per_year", + " divdpy Divide by days per year", + " o(t,x) = i(t,x) / days_per_year", +}; + +const CdoHelp ArithlatHelp = { + "NAME", + " mulcoslat, divcoslat - Arithmetic with latitude", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module multiplies or divides each field element with the cosine of the latitude.", + "", + "OPERATORS", + " mulcoslat Multiply with the cosine of the latitude", + " o(t,x) = i(t,x) * cos(latitude(x))", + " divcoslat Divide by cosine of the latitude", + " o(t,x) = i(t,x) / cos(latitude(x))", +}; + +const CdoHelp TimcumsumHelp = { + "NAME", + " timcumsum - Cumulative sum over all timesteps", + "", + "SYNOPSIS", + " timcumsum infile outfile", + "", + "DESCRIPTION", + " The timcumsum operator calculates the cumulative sum over all timesteps.", + " Missing values are treated as numeric zero when summing.", + " ", + " o(t,x) = sum{i(t',x), 0<t'<=t}", +}; + +const CdoHelp ConsecstatHelp = { + "NAME", + " consecsum, consects - Consecute timestep periods", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes periods over all timesteps in infile where a", + " certain property is valid. The property can be chosen by creating a mask from", + " the original data, which is the expected input format for operators of this", + " module. Depending on the operator full information about each period or", + " just its length and ending date are computed.", + "", + "OPERATORS", + " consecsum Consecutive Sum", + " This operator computes periods of consecutive timesteps similar to a", + " runsum, but periods are finished, when the mask value is 0. That way", + " multiple periods can be found. Timesteps from the input are preserved. Missing", + " values are handled like 0, i.e. finish periods of consecutive timesteps.", + " consects Consecutive Timesteps", + " In contrast to the operator above consects only computes the length of each", + " period together with its last timestep. To be able to perform statistical", + " analysis like min, max or mean, everything else is set to missing value.", +}; + +const CdoHelp VarsstatHelp = { + "NAME", + " varsmin, varsmax, varsrange, varssum, varsmean, varsavg, varsstd, varsstd1, ", + " varsvar, varsvar1 - Statistical values over all variables", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over all variables for each timestep.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance or", + " standard deviation is written to outfile.", + " All input variables need to have the same gridsize and the same number of levels.", + "", + "OPERATORS", + " varsmin Variables minimum", + " For every timestep the minimum over all variables is computed.", + " varsmax Variables maximum", + " For every timestep the maximum over all variables is computed.", + " varsrange Variables range", + " For every timestep the range over all variables is computed.", + " varssum Variables sum", + " For every timestep the sum over all variables is computed.", + " varsmean Variables mean", + " For every timestep the mean over all variables is computed.", + " varsavg Variables average", + " For every timestep the average over all variables is computed.", + " varsstd Variables standard deviation", + " For every timestep the standard deviation over all variables is computed. Normalize by n.", + " varsstd1 Variables standard deviation (n-1)", + " For every timestep the standard deviation over all variables is computed. Normalize by (n-1).", + " varsvar Variables variance", + " For every timestep the variance over all variables is computed. Normalize by n.", + " varsvar1 Variables variance (n-1)", + " For every timestep the variance over all variables is computed. Normalize by (n-1).", +}; + +const CdoHelp EnsstatHelp = { + "NAME", + " ensmin, ensmax, ensrange, enssum, ensmean, ensavg, ensstd, ensstd1, ensvar, ", + " ensvar1, ensskew, enskurt, ensmedian, enspctl - ", + " Statistical values over an ensemble", + "", + "SYNOPSIS", + " <operator> infiles outfile", + " enspctl,p infiles outfile", + "", + "DESCRIPTION", + " This module computes statistical values over an ensemble of input files.", + " Depending on the chosen operator, the minimum, maximum, range, sum, average, standard deviation, variance,", + " skewness, kurtosis, median or a certain percentile over all input files is written to outfile.", + " All input files need to have the same structure with the same variables.", + " The date information of a timestep in outfile is the date of the first input file.", + "", + "OPERATORS", + " ensmin Ensemble minimum", + " o(t,x) = min{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensmax Ensemble maximum", + " o(t,x) = max{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensrange Ensemble range", + " o(t,x) = range{i1(t,x), i2(t,x), ..., in(t,x)}", + " enssum Ensemble sum", + " o(t,x) = sum{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensmean Ensemble mean", + " o(t,x) = mean{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensavg Ensemble average", + " o(t,x) = avg{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensstd Ensemble standard deviation", + " Normalize by n.", + " ", + " o(t,x) = std{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensstd1 Ensemble standard deviation (n-1)", + " Normalize by (n-1).", + " ", + " o(t,x) = std1{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensvar Ensemble variance", + " Normalize by n.", + " ", + " o(t,x) = var{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensvar1 Ensemble variance (n-1)", + " Normalize by (n-1).", + " ", + " o(t,x) = var1{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensskew Ensemble skewness", + " o(t,x) = skew{i1(t,x), i2(t,x), ..., in(t,x)}", + " enskurt Ensemble kurtosis", + " o(t,x) = kurt{i1(t,x), i2(t,x), ..., in(t,x)}", + " ensmedian Ensemble median", + " o(t,x) = median{i1(t,x), i2(t,x), ..., in(t,x)}", + " enspctl Ensemble percentiles", + " o(t,x) = pth percentile {i1(t,x), i2(t,x), ..., in(t,x)}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "NOTE", + " Operators of this module need to open all input files simultaneously.", + " The maximum number of open files depends on the operating system!", +}; + +const CdoHelp Ensstat2Help = { + "NAME", + " ensrkhistspace, ensrkhisttime, ensroc - Statistical values over an ensemble", + "", + "SYNOPSIS", + " <operator> obsfile ensfiles outfile", + "", + "DESCRIPTION", + " This module computes statistical values over the ensemble of ensfiles using", + " obsfile as a reference. Depending on the operator a ranked Histogram or ", + " a roc-curve over all Ensembles ensfiles", + " with reference to obsfile is written to outfile. ", + " The date and grid information of a timestep in outfile is the date of the ", + " first input file. Thus all input files are required to have the same structure in ", + " terms of the gridsize, variable definitions and number of timesteps. ", + " ", + " All Operators in this module use obsfile as the reference (for instance ", + " an observation) whereas ensfiles are understood as an ensemble consisting ", + " of n (where n is the number of ensfiles) members. ", + " ", + " The operators ensrkhistspace and ensrkhisttime compute Ranked Histograms. ", + " Therefor the vertical axis is utilized as the Histogram axis, which prohibits", + " the use of files containing more than one level. The histogram axis has ", + " nensfiles+1 bins with level 0 containing for each grid point the number of ", + " observations being smaller as all ensembles and level nensfiles+1 indicating", + " the number of observations being larger than all ensembles. ", + " ", + " ensrkhistspace computes a ranked histogram at each timestep reducing each ", + " horizontal grid to a 1x1 grid and keeping the time axis as in obsfile. ", + " Contrary ensrkhistspace computes a histogram at each grid point keeping the ", + " horizontal grid for each variable and reducing the time-axis. The time information", + " is that from the last timestep in obsfile. ", + "", + "OPERATORS", + " ensrkhistspace Ranked Histogram averaged over time", + " ensrkhisttime Ranked Histogram averaged over space", + " ensroc Ensemble Receiver Operating characteristics", +}; + +const CdoHelp EnsvalHelp = { + "NAME", + " enscrps, ensbrs - Ensemble validation tools", + "", + "SYNOPSIS", + " enscrps rfile infiles outfilebase", + " ensbrs,x rfile infiles outfilebase", + "", + "DESCRIPTION", + " This module computes ensemble validation scores and their decomposition such as ", + " the Brier and cumulative ranked probability score (CRPS). ", + " The first file is used as a reference it can be a climatology, observation or ", + " reanalysis against which the skill of the ensembles given in infiles is measured. ", + " Depending on the operator a number of output files is generated each containing ", + " the skill score and its decomposition corresponding to the operator. ", + " The output is averaged over horizontal fields using appropriate weights ", + " for each level and timestep in rfile. ", + " ", + " All input files need to have the same structure with the same variables.", + " The date information of a timestep in outfile is the date of the first input file.", + " The output files are named as ", + " <outfilebase>.<type>.<filesuffix> where <type> depends on the ", + " operator and <filesuffix> is determined from the output file type. ", + " There are three output files for operator enscrps and four output files ", + " for operator ensbrs.", + " ", + " The CRPS and its decomposition into Reliability and the potential ", + " CRPS are calculated by an appropriate averaging over the field ", + " members (note, that the CRPS does *not* average linearly). ", + " In the three output files ", + " <type> has the following meaning:", + " crps for the CRPS, reli for the reliability ", + " and crpspot for the potential crps. The relation ", + " CRPS = CRPS_{pot} + RELI", + " holds. ", + " ", + " The Brier score of the Ensemble given by infiles with respect to the ", + " reference given in rfile and the threshold x is calculated. ", + " In the four output files <type> has the following meaning: ", + " brs for the Brier score wrt threshold x; ", + " brsreli for the Brier score reliability wrt threshold x;", + " brsreso for the Brier score resolution wrt threshold x;", + " brsunct for the Brier score uncertainty wrt threshold x.", + " In analogy to the CRPS the following relation holds:", + " BRS(x) = RELI(x)-RESO(x)+ UNCT(x).", + " ", + " The implementation of the decomposition of the CRPS and Brier Score follows ", + " Hans Hersbach (2000): Decomposition of the Continuous Ranked Probability ", + " Score for Ensemble Prediction Systems, in: Weather and Forecasting (15) ", + " pp. 559-570. ", + " ", + " The CRPS code decomposition has been verified against the CRAN - ensemble ", + " validation package from R. Differences occur when grid-cell area is not ", + " uniform as the implementation in R does not account for that. ", + " ", + "", + "OPERATORS", + " enscrps Ensemble CRPS and decomposition", + " ensbrs Ensemble Brier score", + " Ensemble Brier Score and Decomposition", +}; + +const CdoHelp FldstatHelp = { + "NAME", + " fldmin, fldmax, fldrange, fldsum, fldint, fldmean, fldavg, fldstd, fldstd1, ", + " fldvar, fldvar1, fldskew, fldkurt, fldmedian, fldcount, fldpctl - ", + " Statistical values over a field", + "", + "SYNOPSIS", + " <operator> infile outfile", + " fldint,weights infile outfile", + " fldmean,weights infile outfile", + " fldavg,weights infile outfile", + " fldstd,weights infile outfile", + " fldstd1,weights infile outfile", + " fldvar,weights infile outfile", + " fldvar1,weights infile outfile", + " fldpctl,p infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values of all input fields. A field is a horizontal layer of a data variable.", + " Depending on the chosen operator, the minimum, maximum, range, sum, integral, average, standard deviation, variance,", + " skewness, kurtosis, median or a certain percentile of the field is written to outfile.", + "", + "OPERATORS", + " fldmin Field minimum", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = min{i(t,x'), x_1<x'<=x_n}", + " fldmax Field maximum", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = max{i(t,x'), x_1<x'<=x_n}", + " fldrange Field range", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = range{i(t,x'), x_1<x'<=x_n}", + " fldsum Field sum", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = sum{i(t,x'), x_1<x'<=x_n}", + " fldint Field integral", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = sum{i(t,x')*cellarea(x'), x_1<x'<=x_n}", + " fldmean Field mean", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = mean{i(t,x'), x_1<x'<=x_n}", + " weighted by area weights obtained by the input field.", + " fldavg Field average", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = avg{i(t,x'), x_1<x'<=x_n}", + " weighted by area weights obtained by the input field.", + " fldstd Field standard deviation", + " Normalize by n. For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = std{i(t,x'), x_1<x'<=x_n}", + " weighted by area weights obtained by the input field.", + " fldstd1 Field standard deviation (n-1)", + " Normalize by (n-1). For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = std1{i(t,x'), x_1<x'<=x_n}", + " weighted by area weights obtained by the input field.", + " fldvar Field variance", + " Normalize by n. For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = var{i(t,x'), x_1<x'<=x_n}", + " weighted by area weights obtained by the input field.", + " fldvar1 Field variance (n-1)", + " Normalize by (n-1). For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = var1{i(t,x'), x_1<x'<=x_n}", + " weighted by area weights obtained by the input field.", + " fldskew Field skewness", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = skew{i(t,x'), x_1<x'<=x_n}", + " fldkurt Field kurtosis", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = kurt{i(t,x'), x_1<x'<=x_n}", + " fldmedian Field median", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = median{i(t,x'), x_1<x'<=x_n}", + " fldcount Field count", + " Number of non-missing values of the field.", + " fldpctl Field percentiles", + " For every gridpoint x_1, ..., x_n of the same field it is:", + " ", + " o(t,1) = pth percentile {i(t,x'), x_1<x'<=x_n}", + "", + "PARAMETER", + " weights BOOL weights=FALSE disables weighting by grid cell area [default: weights=TRUE]", + " p FLOAT Percentile number in {0, ..., 100}", +}; + +const CdoHelp ZonstatHelp = { + "NAME", + " zonmin, zonmax, zonrange, zonsum, zonmean, zonavg, zonstd, zonstd1, zonvar, ", + " zonvar1, zonskew, zonkurt, zonmedian, zonpctl - Zonal statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + " zonmean[,zonaldes] infile outfile", + " zonpctl,p infile outfile", + "", + "DESCRIPTION", + " This module computes zonal statistical values of the input fields.", + " Depending on the chosen operator, the zonal minimum, maximum, range, sum, average, standard deviation, variance,", + " skewness, kurtosis, median or a certain percentile of the field is written to outfile.", + " Operators of this module require all variables on the same regular lon/lat grid.", + " Only the zonal mean (zonmean) can be calculated for data on an unstructured grid if the latitude bins are", + " defined with the optional parameter zonaldes.", + "", + "OPERATORS", + " zonmin Zonal minimum", + " For every latitude the minimum over all longitudes is computed.", + " zonmax Zonal maximum", + " For every latitude the maximum over all longitudes is computed.", + " zonrange Zonal range", + " For every latitude the range over all longitudes is computed.", + " zonsum Zonal sum", + " For every latitude the sum over all longitudes is computed.", + " zonmean Zonal mean", + " For every latitude the mean over all longitudes is computed.", + " Use the optional parameter zonaldes for data on an unstructured grid.", + " zonavg Zonal average", + " For every latitude the average over all longitudes is computed.", + " zonstd Zonal standard deviation", + " For every latitude the standard deviation over all longitudes is computed. Normalize by n.", + " zonstd1 Zonal standard deviation (n-1)", + " For every latitude the standard deviation over all longitudes is computed. Normalize by (n-1). ", + " zonvar Zonal variance", + " For every latitude the variance over all longitudes is computed. Normalize by n.", + " zonvar1 Zonal variance (n-1)", + " For every latitude the variance over all longitudes is computed. Normalize by (n-1).", + " zonskew Zonal skewness", + " For every latitude the skewness over all longitudes is computed.", + " zonkurt Zonal kurtosis", + " For every latitude the kurtosis over all longitudes is computed.", + " zonmedian Zonal median", + " For every latitude the median over all longitudes is computed.", + " zonpctl Zonal percentiles", + " For every latitude the pth percentile over all longitudes is computed.", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + " zonaldes STRING Description of the zonal latitude bins needed for data on an unstructured grid. A predefined zonal description is zonal_<DY>. DY is the increment of the latitudes in degrees.", +}; + +const CdoHelp MerstatHelp = { + "NAME", + " mermin, mermax, merrange, mersum, mermean, meravg, merstd, merstd1, mervar, ", + " mervar1, merskew, merkurt, mermedian, merpctl - Meridional statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + " merpctl,p infile outfile", + "", + "DESCRIPTION", + " This module computes meridional statistical values of the input fields.", + " Depending on the chosen operator, the meridional minimum, maximum, range, sum, average, standard deviation, variance,", + " skewness, kurtosis, median or a certain percentile of the field is written to outfile.", + " Operators of this module require all variables on the same regular lon/lat grid.", + "", + "OPERATORS", + " mermin Meridional minimum", + " For every longitude the minimum over all latitudes is computed.", + " mermax Meridional maximum", + " For every longitude the maximum over all latitudes is computed.", + " merrange Meridional range", + " For every longitude the range over all latitudes is computed.", + " mersum Meridional sum", + " For every longitude the sum over all latitudes is computed.", + " mermean Meridional mean", + " For every longitude the area weighted mean over all latitudes is computed.", + " meravg Meridional average", + " For every longitude the area weighted average over all latitudes is computed.", + " merstd Meridional standard deviation", + " For every longitude the standard deviation over all latitudes is computed. Normalize by n.", + " merstd1 Meridional standard deviation (n-1)", + " For every longitude the standard deviation over all latitudes is computed. Normalize by (n-1).", + " mervar Meridional variance", + " For every longitude the variance over all latitudes is computed. Normalize by n.", + " mervar1 Meridional variance (n-1)", + " For every longitude the variance over all latitudes is computed. Normalize by (n-1).", + " merskew Meridional skewness", + " For every longitude the skewness over all latitudes is computed.", + " merkurt Meridional kurtosis", + " For every longitude the kurtosis over all latitudes is computed.", + " mermedian Meridional median", + " For every longitude the median over all latitudes is computed.", + " merpctl Meridional percentiles", + " For every longitude the pth percentile over all latitudes is computed.", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", +}; + +const CdoHelp GridboxstatHelp = { + "NAME", + " gridboxmin, gridboxmax, gridboxrange, gridboxsum, gridboxmean, gridboxavg, ", + " gridboxstd, gridboxstd1, gridboxvar, gridboxvar1, gridboxskew, gridboxkurt, ", + " gridboxmedian - Statistical values over grid boxes", + "", + "SYNOPSIS", + " <operator>,nx,ny infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over surrounding grid boxes.", + " Depending on the chosen operator, the minimum, maximum, range, sum, average, standard deviation, variance,", + " skewness, kurtosis or median of the neighboring grid boxes is written to outfile.", + " All gridbox operators only work on quadrilateral curvilinear grids.", + "", + "OPERATORS", + " gridboxmin Gridbox minimum", + " Minimum value of the selected grid boxes.", + " gridboxmax Gridbox maximum", + " Maximum value of the selected grid boxes.", + " gridboxrange Gridbox range", + " Range (max-min value) of the selected grid boxes.", + " gridboxsum Gridbox sum", + " Sum of the selected grid boxes.", + " gridboxmean Gridbox mean", + " Mean of the selected grid boxes.", + " gridboxavg Gridbox average", + " Average of the selected grid boxes.", + " gridboxstd Gridbox standard deviation", + " Standard deviation of the selected grid boxes. Normalize by n.", + " gridboxstd1 Gridbox standard deviation (n-1)", + " Standard deviation of the selected grid boxes. Normalize by (n-1).", + " gridboxvar Gridbox variance", + " Variance of the selected grid boxes. Normalize by n.", + " gridboxvar1 Gridbox variance (n-1)", + " Variance of the selected grid boxes. Normalize by (n-1).", + " gridboxskew Gridbox skewness", + " Skewness of the selected grid boxes.", + " gridboxkurt Gridbox kurtosis", + " Kurtosis of the selected grid boxes.", + " gridboxmedian Gridbox median", + " Median of the selected grid boxes.", + "", + "PARAMETER", + " nx INTEGER Number of grid boxes in x direction", + " ny INTEGER Number of grid boxes in y direction", +}; + +const CdoHelp RemapstatHelp = { + "NAME", + " remapmin, remapmax, remaprange, remapsum, remapmean, remapavg, remapstd, ", + " remapstd1, remapvar, remapvar1, remapskew, remapkurt, remapmedian - ", + " Remaps source points to target cells", + "", + "SYNOPSIS", + " <operator>,grid infile outfile", + "", + "DESCRIPTION", + " This module maps source points to target cells by calculating a statistical value from the source points.", + " Each target cell contains the statistical value from all source points within that target cell.", + " If there are no source points within a target cell, it gets a missing value.", + " The target grid must be regular lon/lat or Gaussian.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance,", + " standard deviation, skewness, kurtosis or median of source points is computed.", + "", + "OPERATORS", + " remapmin Remap minimum", + " Minimum value of the source points.", + " remapmax Remap maximum", + " Maximum value of the source points.", + " remaprange Remap range", + " Range (max-min value) of the source points.", + " remapsum Remap sum", + " Sum of the source points.", + " remapmean Remap mean", + " Mean of the source points.", + " remapavg Remap average", + " Average of the source points.", + " remapstd Remap standard deviation", + " Standard deviation of the source points. Normalize by n.", + " remapstd1 Remap standard deviation (n-1)", + " Standard deviation of the source points. Normalize by (n-1).", + " remapvar Remap variance", + " Variance of the source points. Normalize by n.", + " remapvar1 Remap variance (n-1)", + " Variance of the source points. Normalize by (n-1).", + " remapskew Remap skewness", + " Skewness of the source points.", + " remapkurt Remap kurtosis", + " Kurtosis of the source points.", + " remapmedian Remap median", + " Median of the source points.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", +}; + +const CdoHelp VertstatHelp = { + "NAME", + " vertmin, vertmax, vertrange, vertsum, vertmean, vertavg, vertstd, vertstd1, ", + " vertvar, vertvar1 - Vertical statistical values", + "", + "SYNOPSIS", + " <operator>,weights infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over all levels of the input variables.", + " According to chosen operator the vertical minimum, maximum, range, sum, average, variance", + " or standard deviation is written to outfile.", + "", + "OPERATORS", + " vertmin Vertical minimum", + " For every gridpoint the minimum over all levels is computed.", + " vertmax Vertical maximum", + " For every gridpoint the maximum over all levels is computed.", + " vertrange Vertical range", + " For every gridpoint the range over all levels is computed.", + " vertsum Vertical sum", + " For every gridpoint the sum over all levels is computed.", + " vertmean Vertical mean", + " For every gridpoint the layer weighted mean over all levels is computed.", + " vertavg Vertical average", + " For every gridpoint the layer weighted average over all levels is computed.", + " vertstd Vertical standard deviation", + " For every gridpoint the standard deviation over all levels is computed. Normalize by n.", + " vertstd1 Vertical standard deviation (n-1)", + " For every gridpoint the standard deviation over all levels is computed. Normalize by (n-1).", + " vertvar Vertical variance", + " For every gridpoint the variance over all levels is computed. Normalize by n.", + " vertvar1 Vertical variance (n-1)", + " For every gridpoint the variance over all levels is computed. Normalize by (n-1).", + "", + "PARAMETER", + " weights BOOL weights=FALSE disables weighting by layer thickness [default: weights=TRUE]", +}; + +const CdoHelp TimselstatHelp = { + "NAME", + " timselmin, timselmax, timselrange, timselsum, timselmean, timselavg, ", + " timselstd, timselstd1, timselvar, timselvar1 - Time range statistical values", + "", + "SYNOPSIS", + " <operator>,nsets[,noffset[,nskip]] infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values for a selected number of timesteps. According to ", + " the chosen operator the minimum, maximum, range, sum, average, variance or standard deviation of ", + " the selected timesteps is written to outfile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " timselmin Time selection minimum", + " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = min{i(t',x), t1 < t' <= tn}", + " timselmax Time selection maximum", + " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = max{i(t',x), t1 < t' <= tn}", + " timselrange Time selection range", + " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = range{i(t',x), t1 < t' <= tn}", + " timselsum Time selection sum", + " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = sum{i(t',x), t1 < t' <= tn}", + " timselmean Time selection mean", + " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = mean{i(t',x), t1 < t' <= tn}", + " timselavg Time selection average", + " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = avg{i(t',x), t1 < t' <= tn}", + " timselstd Time selection standard deviation", + " Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = std{i(t',x), t1 < t' <= tn}", + " timselstd1 Time selection standard deviation (n-1)", + " Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = std1{i(t',x), t1 < t' <= tn}", + " timselvar Time selection variance", + " Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = var{i(t',x), t1 < t' <= tn}", + " timselvar1 Time selection variance (n-1)", + " Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = var1{i(t',x), t1 < t' <= tn}", + "", + "PARAMETER", + " nsets INTEGER Number of input timesteps for each output timestep ", + " noffset INTEGER Number of input timesteps skipped before the first timestep range (optional)", + " nskip INTEGER Number of input timesteps skipped between timestep ranges (optional)", +}; + +const CdoHelp TimselpctlHelp = { + "NAME", + " timselpctl - Time range percentile values", + "", + "SYNOPSIS", + " timselpctl,p,nsets[,noffset[,nskip]] infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator computes percentile values over a selected number of timesteps in infile1.", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,", + " respectively. The default number of histogram bins is 101. The default can be overridden by setting the", + " environment variable CDO_PCTL_NBINS to a different value. The files infile2 and infile3 ", + " should be the result of corresponding timselmin and timselmax operations, respectively.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", + " ", + " o(t,x) = pth percentile {i(t',x), t1 < t' <= tn}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + " nsets INTEGER Number of input timesteps for each output timestep ", + " noffset INTEGER Number of input timesteps skipped before the first timestep range (optional)", + " nskip INTEGER Number of input timesteps skipped between timestep ranges (optional)", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp RunstatHelp = { + "NAME", + " runmin, runmax, runrange, runsum, runmean, runavg, runstd, runstd1, runvar, ", + " runvar1 - Running statistical values", + "", + "SYNOPSIS", + " <operator>,nts infile outfile", + "", + "DESCRIPTION", + " This module computes running statistical values over a selected number of timesteps. Depending on ", + " the chosen operator the minimum, maximum, range, sum, average, variance or standard deviation of a selected ", + " number of consecutive timesteps read from infile is written to outfile. ", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " runmin Running minimum", + " o(t+(nts-1)/2,x) = min{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runmax Running maximum", + " o(t+(nts-1)/2,x) = max{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runrange Running range", + " o(t+(nts-1)/2,x) = range{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runsum Running sum", + " o(t+(nts-1)/2,x) = sum{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runmean Running mean", + " o(t+(nts-1)/2,x) = mean{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runavg Running average", + " o(t+(nts-1)/2,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runstd Running standard deviation", + " Normalize by n. ", + " ", + " o(t+(nts-1)/2,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runstd1 Running standard deviation (n-1)", + " Normalize by (n-1). ", + " ", + " o(t+(nts-1)/2,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runvar Running variance", + " Normalize by n. ", + " ", + " o(t+(nts-1)/2,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + " runvar1 Running variance (n-1)", + " Normalize by (n-1). ", + " ", + " o(t+(nts-1)/2,x) = var1{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + "", + "PARAMETER", + " nts INTEGER Number of timesteps", + "", + "ENVIRONMENT", + " CDO_TIMESTAT_DATE", + " Sets the time stamp in outfile to the \"first\", \"middle\" or \"last\" contributing timestep of infile.", +}; + +const CdoHelp RunpctlHelp = { + "NAME", + " runpctl - Running percentile values", + "", + "SYNOPSIS", + " runpctl,p,nts infile outfile", + "", + "DESCRIPTION", + " This module computes running percentiles over a selected number of timesteps in infile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " ", + " o(t+(nts-1)/2,x) = pth percentile {i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + " nts INTEGER Number of timesteps", +}; + +const CdoHelp TimstatHelp = { + "NAME", + " timmin, timmax, timrange, timsum, timmean, timavg, timstd, timstd1, timvar, ", + " timvar1 - Statistical values over all timesteps", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over all timesteps in infile. Depending on ", + " the chosen operator the minimum, maximum, range, sum, average, variance or standard deviation of ", + " all timesteps read from infile is written to outfile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " timmin Time minimum", + " o(1,x) = min{i(t',x), t_1<t'<=t_n}", + " timmax Time maximum", + " o(1,x) = max{i(t',x), t_1<t'<=t_n}", + " timrange Time range", + " o(1,x) = range{i(t',x), t_1<t'<=t_n}", + " timsum Time sum", + " o(1,x) = sum{i(t',x), t_1<t'<=t_n}", + " timmean Time mean", + " o(1,x) = mean{i(t',x), t_1<t'<=t_n}", + " timavg Time average", + " o(1,x) = avg{i(t',x), t_1<t'<=t_n}", + " timstd Time standard deviation", + " Normalize by n. ", + " ", + " o(1,x) = std{i(t',x), t_1<t'<=t_n}", + " timstd1 Time standard deviation (n-1)", + " Normalize by (n-1). ", + " ", + " o(1,x) = std1{i(t',x), t_1<t'<=t_n}", + " timvar Time variance", + " Normalize by n. ", + " ", + " o(1,x) = var{i(t',x), t_1<t'<=t_n}", + " timvar1 Time variance (n-1)", + " Normalize by (n-1). ", + " ", + " o(1,x) = var1{i(t',x), t_1<t'<=t_n}", +}; + +const CdoHelp TimpctlHelp = { + "NAME", + " timpctl - Percentile values over all timesteps", + "", + "SYNOPSIS", + " timpctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator computes percentiles over all timesteps in infile1. The algorithm uses ", + " histograms with minimum and maximum bounds given in infile2 and infile3, respectively. ", + " The default number of histogram bins is 101. The default can be overridden by defining the", + " environment variable CDO_PCTL_NBINS. The files infile2 and infile3 should be", + " the result of corresponding timmin and timmax operations, respectively.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " ", + " o(1,x) = pth percentile {i(t',x), t_1<t'<=t_n}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp HourstatHelp = { + "NAME", + " hourmin, hourmax, hourrange, hoursum, hourmean, houravg, hourstd, hourstd1, ", + " hourvar, hourvar1 - Hourly statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over timesteps of the same hour.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of timesteps of the same hour is written to outfile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " hourmin Hourly minimum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = min{i(t',x), t_1<t'<=t_n}", + " hourmax Hourly maximum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = max{i(t',x), t_1<t'<=t_n}", + " hourrange Hourly range", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = range{i(t',x), t_1<t'<=t_n}", + " hoursum Hourly sum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", + " hourmean Hourly mean", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", + " houravg Hourly average", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", + " hourstd Hourly standard deviation", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = std{i(t',x), t_1<t'<=t_n}", + " hourstd1 Hourly standard deviation (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = std1{i(t',x), t_1<t'<=t_n}", + " hourvar Hourly variance", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = var{i(t',x), t_1<t'<=t_n}", + " hourvar1 Hourly variance (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = var1{i(t',x), t_1<t'<=t_n}", +}; + +const CdoHelp HourpctlHelp = { + "NAME", + " hourpctl - Hourly percentile values", + "", + "SYNOPSIS", + " hourpctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator computes percentiles over all timesteps of the same hour in infile1.", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", + " infile3, respectively. The default number of histogram bins is 101.", + " The default can be overridden by defining the environment variable CDO_PCTL_NBINS.", + " The files infile2 and infile3 should be the result of corresponding hourmin", + " and hourmax operations, respectively.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", + " ", + " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp DaystatHelp = { + "NAME", + " daymin, daymax, dayrange, daysum, daymean, dayavg, daystd, daystd1, dayvar, ", + " dayvar1 - Daily statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over timesteps of the same day.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of timesteps of the same day is written to outfile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " daymin Daily minimum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = min{i(t',x), t_1<t'<=t_n}", + " daymax Daily maximum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = max{i(t',x), t_1<t'<=t_n}", + " dayrange Daily range", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = range{i(t',x), t_1<t'<=t_n}", + " daysum Daily sum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", + " daymean Daily mean", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", + " dayavg Daily average", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", + " daystd Daily standard deviation", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = std{i(t',x), t_1<t'<=t_n}", + " daystd1 Daily standard deviation (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = std1{i(t',x), t_1<t'<=t_n}", + " dayvar Daily variance", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = var{i(t',x), t_1<t'<=t_n}", + " dayvar1 Daily variance (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = var1{i(t',x), t_1<t'<=t_n}", +}; + +const CdoHelp DaypctlHelp = { + "NAME", + " daypctl - Daily percentile values", + "", + "SYNOPSIS", + " daypctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator computes percentiles over all timesteps of the same day in infile1.", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", + " infile3, respectively. The default number of histogram bins is 101.", + " The default can be overridden by defining the environment variable CDO_PCTL_NBINS.", + " The files infile2 and infile3 should be the result of corresponding daymin", + " and daymax operations, respectively.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", + " ", + " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp MonstatHelp = { + "NAME", + " monmin, monmax, monrange, monsum, monmean, monavg, monstd, monstd1, monvar, ", + " monvar1 - Monthly statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over timesteps of the same month.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of timesteps of the same month is written to outfile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " monmin Monthly minimum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = min{i(t',x), t_1<t'<=t_n}", + " monmax Monthly maximum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = max{i(t',x), t_1<t'<=t_n}", + " monrange Monthly range", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = range{i(t',x), t_1<t'<=t_n}", + " monsum Monthly sum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", + " monmean Monthly mean", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", + " monavg Monthly average", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", + " monstd Monthly standard deviation", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = std{i(t',x), t_1 < t' <= t_n}", + " monstd1 Monthly standard deviation (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = std1{i(t',x), t_1 < t' <= t_n}", + " monvar Monthly variance", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = var{i(t',x), t_1 < t' <= t_n}", + " monvar1 Monthly variance (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = var1{i(t',x), t_1 < t' <= t_n}", +}; + +const CdoHelp MonpctlHelp = { + "NAME", + " monpctl - Monthly percentile values", + "", + "SYNOPSIS", + " monpctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator computes percentiles over all timesteps of the same month in infile1.", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", + " infile3, respectively. The default number of histogram bins is 101.", + " The default can be overridden by defining the environment variable CDO_PCTL_NBINS.", + " The files infile2 and infile3 should be the result of corresponding monmin", + " and monmax operations, respectively.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", + " ", + " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp YearmonstatHelp = { + "NAME", + " yearmonmean - Yearly mean from monthly data", + "", + "SYNOPSIS", + " yearmonmean infile outfile", + "", + "DESCRIPTION", + " This operator computes the yearly mean of a monthly time series.", + " Each month is weighted with the number of days per month. ", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " ", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", + "", + "ENVIRONMENT", + " CDO_TIMESTAT_DATE", + " Sets the date information in outfile to the \"first\", \"middle\" or \"last\" contributing timestep of infile.", +}; + +const CdoHelp YearstatHelp = { + "NAME", + " yearmin, yearmax, yearminidx, yearmaxidx, yearrange, yearsum, yearmean, ", + " yearavg, yearstd, yearstd1, yearvar, yearvar1 - Yearly statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over timesteps of the same year.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of timesteps of the same year is written to outfile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " yearmin Yearly minimum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = min{i(t',x), t_1<t'<=t_n}", + " yearmax Yearly maximum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = max{i(t',x), t_1<t'<=t_n}", + " yearminidx Yearly minimum indices", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = minidx{i(t',x), t_1<t'<=t_n}", + " yearmaxidx Yearly maximum indices", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = maxidx{i(t',x), t_1<t'<=t_n}", + " yearrange Yearly range", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = range{i(t',x), t_1<t'<=t_n}", + " yearsum Yearly sum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", + " yearmean Yearly mean", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", + " yearavg Yearly average", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", + " yearstd Yearly standard deviation", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = std{i(t',x), t_1 < t' <= t_n}", + " yearstd1 Yearly standard deviation (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = std1{i(t',x), t_1 < t' <= t_n}", + " yearvar Yearly variance", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = var{i(t',x), t_1 < t' <= t_n}", + " yearvar1 Yearly variance (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = var1{i(t',x), t_1 < t' <= t_n}", + "", + "NOTE", + " The operators yearmean and yearavg compute only arithmetical means!", +}; + +const CdoHelp YearpctlHelp = { + "NAME", + " yearpctl - Yearly percentile values", + "", + "SYNOPSIS", + " yearpctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator computes percentiles over all timesteps of the same year in infile1.", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", + " infile3, respectively. The default number of histogram bins is 101. The default can be", + " overridden by defining the environment variable CDO_PCTL_NBINS. The files infile2 and", + " infile3 should be the result of corresponding yearmin and yearmax operations, respectively.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", + " ", + " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp SeasstatHelp = { + "NAME", + " seasmin, seasmax, seasrange, seassum, seasmean, seasavg, seasstd, seasstd1, ", + " seasvar, seasvar1 - Seasonal statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values over timesteps of the same season.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of timesteps of the same season is written to outfile.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " Be careful about the first and the last output timestep, they may be incorrect values ", + " if the seasons have incomplete timesteps.", + "", + "OPERATORS", + " seasmin Seasonal minimum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = min{i(t',x), t1 < t' <= tn}", + " seasmax Seasonal maximum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = max{i(t',x), t1 < t' <= tn}", + " seasrange Seasonal range", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = range{i(t',x), t1 < t' <= tn}", + " seassum Seasonal sum", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = sum{i(t',x), t1 < t' <= tn}", + " seasmean Seasonal mean", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = mean{i(t',x), t1 < t' <= tn}", + " seasavg Seasonal average", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = avg{i(t',x), t1 < t' <= tn}", + " seasstd Seasonal standard deviation", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = std{i(t',x), t1 < t' <= tn}", + " seasstd1 Seasonal standard deviation (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = std1{i(t',x), t1 < t' <= tn}", + " seasvar Seasonal variance", + " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = var{i(t',x), t1 < t' <= tn}", + " seasvar1 Seasonal variance (n-1)", + " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = var1{i(t',x), t1 < t' <= tn}", +}; + +const CdoHelp SeaspctlHelp = { + "NAME", + " seaspctl - Seasonal percentile values", + "", + "SYNOPSIS", + " seaspctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator computes percentiles over all timesteps in infile1 of the same season.", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,", + " respectively. The default number of histogram bins is 101. The default can be overridden", + " by defining the environment variable CDO_PCTL_NBINS. The files infile2 and infile3", + " should be the result of corresponding seasmin and seasmax operations, respectively.", + " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + " Be careful about the first and the last output timestep, they may be incorrect values ", + " if the seasons have incomplete timesteps.", + " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", + " ", + " o(t,x) = pth percentile {i(t',x), t1 < t' <= tn}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp YhourstatHelp = { + "NAME", + " yhourmin, yhourmax, yhourrange, yhoursum, yhourmean, yhouravg, yhourstd, ", + " yhourstd1, yhourvar, yhourvar1 - Multi-year hourly statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values of each hour and day of year.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of each hour and day of year in infile is written to outfile.", + " The date information in an output field is the date of the last contributing input field.", + "", + "OPERATORS", + " yhourmin Multi-year hourly minimum", + " o(0001,x) = min{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = min{i(t,x), day(i(t)) = 8784}", + " yhourmax Multi-year hourly maximum", + " o(0001,x) = max{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = max{i(t,x), day(i(t)) = 8784}", + " yhourrange Multi-year hourly range", + " o(0001,x) = range{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = range{i(t,x), day(i(t)) = 8784}", + " yhoursum Multi-year hourly sum", + " o(0001,x) = sum{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = sum{i(t,x), day(i(t)) = 8784}", + " yhourmean Multi-year hourly mean", + " o(0001,x) = mean{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = mean{i(t,x), day(i(t)) = 8784}", + " yhouravg Multi-year hourly average", + " o(0001,x) = avg{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = avg{i(t,x), day(i(t)) = 8784}", + " yhourstd Multi-year hourly standard deviation", + " Normalize by n. ", + " ", + " o(0001,x) = std{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = std{i(t,x), day(i(t)) = 8784}", + " yhourstd1 Multi-year hourly standard deviation (n-1)", + " Normalize by (n-1). ", + " ", + " o(0001,x) = std1{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = std1{i(t,x), day(i(t)) = 8784}", + " yhourvar Multi-year hourly variance", + " Normalize by n. ", + " ", + " o(0001,x) = var{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = var{i(t,x), day(i(t)) = 8784}", + " yhourvar1 Multi-year hourly variance (n-1)", + " Normalize by (n-1). ", + " ", + " o(0001,x) = var1{i(t,x), day(i(t)) = 0001}", + " ...", + " o(8784,x) = var1{i(t,x), day(i(t)) = 8784}", +}; + +const CdoHelp DhourstatHelp = { + "NAME", + " dhourmin, dhourmax, dhourrange, dhoursum, dhourmean, dhouravg, dhourstd, ", + " dhourstd1, dhourvar, dhourvar1 - Multi-day hourly statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values of each hour of day.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of each hour of day in infile is written to outfile.", + " The date information in an output field is the date of the last contributing input field.", + "", + "OPERATORS", + " dhourmin Multi-day hourly minimum", + " o(01,x) = min{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = min{i(t,x), day(i(t)) = 24}", + " dhourmax Multi-day hourly maximum", + " o(01,x) = max{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = max{i(t,x), day(i(t)) = 24}", + " dhourrange Multi-day hourly range", + " o(01,x) = range{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = range{i(t,x), day(i(t)) = 24}", + " dhoursum Multi-day hourly sum", + " o(01,x) = sum{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = sum{i(t,x), day(i(t)) = 24}", + " dhourmean Multi-day hourly mean", + " o(01,x) = mean{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = mean{i(t,x), day(i(t)) = 24}", + " dhouravg Multi-day hourly average", + " o(01,x) = avg{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = avg{i(t,x), day(i(t)) = 24}", + " dhourstd Multi-day hourly standard deviation", + " Normalize by n. ", + " ", + " o(01,x) = std{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = std{i(t,x), day(i(t)) = 24}", + " dhourstd1 Multi-day hourly standard deviation (n-1)", + " Normalize by (n-1). ", + " ", + " o(01,x) = std1{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = std1{i(t,x), day(i(t)) = 24}", + " dhourvar Multi-day hourly variance", + " Normalize by n. ", + " ", + " o(01,x) = var{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = var{i(t,x), day(i(t)) = 24}", + " dhourvar1 Multi-day hourly variance (n-1)", + " Normalize by (n-1). ", + " ", + " o(01,x) = var1{i(t,x), day(i(t)) = 01}", + " ...", + " o(24,x) = var1{i(t,x), day(i(t)) = 24}", +}; + +const CdoHelp YdaystatHelp = { + "NAME", + " ydaymin, ydaymax, ydayrange, ydaysum, ydaymean, ydayavg, ydaystd, ydaystd1, ", + " ydayvar, ydayvar1 - Multi-year daily statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values of each day of year.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of each day of year in infile is written to outfile.", + " The date information in an output field is the date of the last contributing input field.", + "", + "OPERATORS", + " ydaymin Multi-year daily minimum", + " o(001,x) = min{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = min{i(t,x), day(i(t)) = 366}", + " ydaymax Multi-year daily maximum", + " o(001,x) = max{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = max{i(t,x), day(i(t)) = 366}", + " ydayrange Multi-year daily range", + " o(001,x) = range{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = range{i(t,x), day(i(t)) = 366}", + " ydaysum Multi-year daily sum", + " o(001,x) = sum{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = sum{i(t,x), day(i(t)) = 366}", + " ydaymean Multi-year daily mean", + " o(001,x) = mean{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = mean{i(t,x), day(i(t)) = 366}", + " ydayavg Multi-year daily average", + " o(001,x) = avg{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = avg{i(t,x), day(i(t)) = 366}", + " ydaystd Multi-year daily standard deviation", + " Normalize by n. ", + " ", + " o(001,x) = std{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = std{i(t,x), day(i(t)) = 366}", + " ydaystd1 Multi-year daily standard deviation (n-1)", + " Normalize by (n-1). ", + " ", + " o(001,x) = std1{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = std1{i(t,x), day(i(t)) = 366}", + " ydayvar Multi-year daily variance", + " Normalize by n. ", + " ", + " o(001,x) = var{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = var{i(t,x), day(i(t)) = 366}", + " ydayvar1 Multi-year daily variance (n-1)", + " Normalize by (n-1). ", + " ", + " o(001,x) = var1{i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = var1{i(t,x), day(i(t)) = 366}", +}; + +const CdoHelp YdaypctlHelp = { + "NAME", + " ydaypctl - Multi-year daily percentile values", + "", + "SYNOPSIS", + " ydaypctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator writes a certain percentile of each day of year in infile1 to outfile.", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", + " infile3, respectively. The default number of histogram bins is 101. The default can be", + " overridden by setting the environment variable CDO_PCTL_NBINS to a different value.", + " The files infile2 and infile3 should be the result of corresponding ydaymin and", + " ydaymax operations, respectively.", + " The date information in an output field is the date of the last contributing input field.", + " ", + " o(001,x) = pth percentile {i(t,x), day(i(t)) = 001}", + " ...", + " o(366,x) = pth percentile {i(t,x), day(i(t)) = 366}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp YmonstatHelp = { + "NAME", + " ymonmin, ymonmax, ymonrange, ymonsum, ymonmean, ymonavg, ymonstd, ymonstd1, ", + " ymonvar, ymonvar1 - Multi-year monthly statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values of each month of year.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of each month of year in infile is written to outfile.", + " The date information in an output field is the date of the last contributing input field.", + " This can be change with the CDO option --timestat_date <first|middle|last>.", + "", + "OPERATORS", + " ymonmin Multi-year monthly minimum", + " o(01,x) = min{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = min{i(t,x), month(i(t)) = 12}", + " ymonmax Multi-year monthly maximum", + " o(01,x) = max{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = max{i(t,x), month(i(t)) = 12}", + " ymonrange Multi-year monthly range", + " o(01,x) = range{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = range{i(t,x), month(i(t)) = 12}", + " ymonsum Multi-year monthly sum", + " o(01,x) = sum{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = sum{i(t,x), month(i(t)) = 12}", + " ymonmean Multi-year monthly mean", + " o(01,x) = mean{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = mean{i(t,x), month(i(t)) = 12}", + " ymonavg Multi-year monthly average", + " o(01,x) = avg{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = avg{i(t,x), month(i(t)) = 12}", + " ymonstd Multi-year monthly standard deviation", + " Normalize by n. ", + " ", + " o(01,x) = std{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = std{i(t,x), month(i(t)) = 12}", + " ymonstd1 Multi-year monthly standard deviation (n-1)", + " Normalize by (n-1). ", + " ", + " o(01,x) = std1{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = std1{i(t,x), month(i(t)) = 12}", + " ymonvar Multi-year monthly variance", + " Normalize by n. ", + " ", + " o(01,x) = var{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = var{i(t,x), month(i(t)) = 12}", + " ymonvar1 Multi-year monthly variance (n-1)", + " Normalize by (n-1). ", + " ", + " o(01,x) = var1{i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = var1{i(t,x), month(i(t)) = 12}", +}; + +const CdoHelp YmonpctlHelp = { + "NAME", + " ymonpctl - Multi-year monthly percentile values", + "", + "SYNOPSIS", + " ymonpctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator writes a certain percentile of each month of year in infile1 to outfile.", + " The algorithm uses histograms with minimum and maximum bounds given in", + " infile2 and infile3, respectively. The default number of", + " histogram bins is 101. The default can be overridden by setting the", + " environment variable CDO_PCTL_NBINS to a different value. The files", + " infile2 and infile3 should be the result of corresponding", + " ymonmin and ymonmax operations, respectively.", + " The date information in an output field is the date of the last", + " contributing input field.", + " ", + " o(01,x) = pth percentile {i(t,x), month(i(t)) = 01}", + " ...", + " o(12,x) = pth percentile {i(t,x), month(i(t)) = 12}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp YseasstatHelp = { + "NAME", + " yseasmin, yseasmax, yseasrange, yseassum, yseasmean, yseasavg, yseasstd, ", + " yseasstd1, yseasvar, yseasvar1 - Multi-year seasonal statistical values", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module computes statistical values of each season.", + " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", + " or standard deviation of each season in infile is written to outfile.", + " The date information in an output field is the date of the last contributing input field.", + "", + "OPERATORS", + " yseasmin Multi-year seasonal minimum", + " o(1,x) = min{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = min{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = min{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = min{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasmax Multi-year seasonal maximum", + " o(1,x) = max{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = max{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = max{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = max{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasrange Multi-year seasonal range", + " o(1,x) = range{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = range{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = range{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = range{i(t,x), month(i(t)) = 09, 10, 11}", + " yseassum Multi-year seasonal sum", + " o(1,x) = sum{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = sum{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = sum{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = sum{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasmean Multi-year seasonal mean", + " o(1,x) = mean{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = mean{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = mean{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = mean{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasavg Multi-year seasonal average", + " o(1,x) = avg{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = avg{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = avg{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = avg{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasstd Multi-year seasonal standard deviation", + " o(1,x) = std{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = std{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = std{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = std{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasstd1 Multi-year seasonal standard deviation (n-1)", + " o(1,x) = std1{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = std1{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = std1{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = std1{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasvar Multi-year seasonal variance", + " o(1,x) = var{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = var{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = var{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = var{i(t,x), month(i(t)) = 09, 10, 11}", + " yseasvar1 Multi-year seasonal variance (n-1)", + " o(1,x) = var1{i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = var1{i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = var1{i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = var1{i(t,x), month(i(t)) = 09, 10, 11}", +}; + +const CdoHelp YseaspctlHelp = { + "NAME", + " yseaspctl - Multi-year seasonal percentile values", + "", + "SYNOPSIS", + " yseaspctl,p infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator writes a certain percentile of each season in infile1 to outfile.", + " The algorithm uses histograms with minimum and maximum bounds given in", + " infile2 and infile3, respectively. The default number of", + " histogram bins is 101. The default can be overridden by setting the", + " environment variable CDO_PCTL_NBINS to a different value. The files", + " infile2 and infile3 should be the result of corresponding", + " yseasmin and yseasmax operations, respectively.", + " The date information in an output field is the date of the last", + " contributing input field.", + " ", + " o(1,x) = pth percentile {i(t,x), month(i(t)) = 12, 01, 02}", + " o(2,x) = pth percentile {i(t,x), month(i(t)) = 03, 04, 05}", + " o(3,x) = pth percentile {i(t,x), month(i(t)) = 06, 07, 08}", + " o(4,x) = pth percentile {i(t,x), month(i(t)) = 09, 10, 11}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp YdrunstatHelp = { + "NAME", + " ydrunmin, ydrunmax, ydrunsum, ydrunmean, ydrunavg, ydrunstd, ydrunstd1, ", + " ydrunvar, ydrunvar1 - Multi-year daily running statistical values", + "", + "SYNOPSIS", + " <operator>,nts infile outfile", + "", + "DESCRIPTION", + " This module writes running statistical values for each day of year in infile to outfile.", + " Depending on the chosen operator, the minimum, maximum, sum, average, variance or standard deviation ", + " of all timesteps in running windows of which the medium timestep corresponds to a certain day of", + " year is computed. The date information in an output field is the date of the timestep in the middle ", + " of the last contributing running window.", + " Note that the operator have to be applied to a continuous time series of daily measurements in order ", + " to yield physically meaningful results. Also note that the output time series begins (nts-1)/2 timesteps", + " after the first timestep of the input time series and ends (nts-1)/2 timesteps before the last one.", + " For input data which are complete but not continuous, such as time series of daily measurements for ", + " the same month or season within different years, the operator yields physically meaningful results ", + " only if the input time series does include the (nts-1)/2 days before and after each period of interest.", + "", + "OPERATORS", + " ydrunmin Multi-year daily running minimum", + " o(001,x) = min{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = min{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", + " ydrunmax Multi-year daily running maximum", + " o(001,x) = max{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = max{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", + " ydrunsum Multi-year daily running sum", + " o(001,x) = sum{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = sum{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", + " ydrunmean Multi-year daily running mean", + " o(001,x) = mean{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = mean{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", + " ydrunavg Multi-year daily running average", + " o(001,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", + " ydrunstd Multi-year daily running standard deviation", + " Normalize by n. ", + " ", + " o(001,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 366}", + " ydrunstd1 Multi-year daily running standard deviation (n-1)", + " Normalize by (n-1). ", + " ", + " o(001,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 366}", + " ydrunvar Multi-year daily running variance", + " Normalize by n. ", + " ", + " o(001,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", + " ydrunvar1 Multi-year daily running variance (n-1)", + " Normalize by (n-1). ", + " ", + " o(001,x) = var1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " 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", +}; + +const CdoHelp YdrunpctlHelp = { + "NAME", + " ydrunpctl - Multi-year daily running percentile values", + "", + "SYNOPSIS", + " ydrunpctl,p,nts infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This operator writes running percentile values for each day of year in infile1 to outfile. ", + " A certain percentile is computed for all timesteps in running windows of which the medium ", + " timestep corresponds to a certain day of year. ", + " The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,", + " respectively. The default number of histogram bins is 101. The default can be overridden", + " by setting the environment variable CDO_PCTL_NBINS to a different value. The files infile2 ", + " and infile3 should be the result of corresponding ydrunmin and ydrunmax operations, respectively.", + " The date information in an output field is the date of the timestep in the middle of the last contributing running window.", + " Note that the operator have to be applied to a continuous time series of daily measurements ", + " in order to yield physically meaningful results. Also note that the output time series begins", + " (nts-1)/2 timesteps after the first timestep of the input time series and ends (nts-1)/2 ", + " timesteps before the last.", + " For input data which are complete but not continuous, such as time series of daily measurements ", + " for the same month or season within different years, the operator only yields physically meaningful ", + " results if the input time series does include the (nts-1)/2 days before and after each period ", + " of interest.", + " ", + " o(001,x) = pth percentile {i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", + " ...", + " o(366,x) = pth percentile {i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", + "", + "PARAMETER", + " p FLOAT Percentile number in {0, ..., 100}", + " nts INTEGER Number of timesteps", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +const CdoHelp FldcorHelp = { + "NAME", + " fldcor - Correlation in grid space", + "", + "SYNOPSIS", + " fldcor infile1 infile2 outfile", + "", + "DESCRIPTION", + " The correlation coefficient is a quantity that gives the quality of a least ", + " squares fitting to the original data. This operator correlates all gridpoints", + " of two fields for each timestep. With", + " ", + " S(t) = {x, i_1(t,x) != missval and i_2(t,x) != missval}", + " ", + " it is", + " ", + " o(t,1) = Cor{(i_1(t,x), i_2(t,x)), x_1 < x <= x_n}", + " ", + " where w(x) are the area weights obtained by the input streams.", + " For every timestep t only those field elements x belong to the sample,", + " which have i_1(t,x) != missval and i_2(t,x) != missval.", +}; + +const CdoHelp TimcorHelp = { + "NAME", + " timcor - Correlation over time", + "", + "SYNOPSIS", + " timcor infile1 infile2 outfile", + "", + "DESCRIPTION", + " The correlation coefficient is a quantity that gives the quality of a least ", + " squares fitting to the original data. This operator correlates each gridpoint", + " of two fields over all timesteps. With", + " ", + " S(x) = {t, i_1(t,x) != missval and i_2(t,x) != missval}", + " ", + " it is", + " ", + " o(1,x) = Cor{(i_1(t,x), i_2(t,x)), t_1 < t <= t_n}", + " ", + " For every gridpoint x only those timesteps t belong to the sample,", + " which have i_1(t,x) != missval and i_2(t,x) != missval.", +}; + +const CdoHelp FldcovarHelp = { + "NAME", + " fldcovar - Covariance in grid space", + "", + "SYNOPSIS", + " fldcovar infile1 infile2 outfile", + "", + "DESCRIPTION", + " This operator calculates the covariance of two fields over all gridpoints", + " for each timestep. With", + " ", + " S(t) = {x, i_1(t,x) != missval and i_2(t,x) != missval}", + " ", + " it is", + " ", + " o(t,1) = Covar{(i_1(t,x), i_2(t,x)), x_1 < x <= x_n}", + " ", + " where w(x) are the area weights obtained by the input streams.", + " For every timestep t only those field elements x belong to the sample,", + " which have i_1(t,x) != missval and i_2(t,x) != missval.", +}; + +const CdoHelp TimcovarHelp = { + "NAME", + " timcovar - Covariance over time", + "", + "SYNOPSIS", + " timcovar infile1 infile2 outfile", + "", + "DESCRIPTION", + " This operator calculates the covariance of two fields at each gridpoint", + " over all timesteps. With", + " ", + " S(x) = {t, i_1(t,x) != missval and i_2(t,x) != missval}", + " ", + " it is", + " ", + " o(1,x) = Covar{(i_1(t,x), i_2(t,x)), t_1 < t <= t_n}", + " ", + " For every gridpoint x only those timesteps t belong to the sample,", + " which have i_1(t,x) != missval and i_2(t,x) != missval.", +}; + +const CdoHelp RegresHelp = { + "NAME", + " regres - Regression", + "", + "SYNOPSIS", + " regres[,equal] infile outfile", + "", + "DESCRIPTION", + " The values of the input file infile are assumed to be distributed as", + " N(a+b*t,S^2) with unknown a, b and S^2. This operator estimates the", + " parameter b. For every field element x only those timesteps ", + " t belong to the sample S(x), which have i(t,x) NE miss.", + " It is assumed that all timesteps are equidistant, if this is not the case set the parameter equal=false.", + "", + "PARAMETER", + " equal BOOL Set to false for unequal distributed timesteps (default: true)", +}; + +const CdoHelp DetrendHelp = { + "NAME", + " detrend - Detrend time series", + "", + "SYNOPSIS", + " detrend[,equal] infile outfile", + "", + "DESCRIPTION", + " Every time series in infile is linearly detrended. For every field element x ", + " only those timesteps t belong to the sample S(x), which have i(t,x) NE miss.", + " It is assumed that all timesteps are equidistant, if this is not the case set the parameter equal=false.", + "", + "PARAMETER", + " equal BOOL Set to false for unequal distributed timesteps (default: true)", + "", + "NOTE", + " This operator has to keep the fields of all timesteps concurrently in the memory.", + " If not enough memory is available use the operators trend and subtrend.", +}; + +const CdoHelp TrendHelp = { + "NAME", + " trend - Trend of time series", + "", + "SYNOPSIS", + " trend[,equal] infile outfile1 outfile2", + "", + "DESCRIPTION", + " The values of the input file infile are assumed to be distributed as", + " N(a+b*t,S^2) with unknown a, b and S^2. This operator estimates the", + " parameter a and b. For every field element x only those timesteps ", + " t belong to the sample S(x), which have i(t,x) NE miss.", + " Thus the estimation for a is stored in outfile1 and that for b is stored ", + " in outfile2. To subtract the trend from the data see operator subtrend.", + " It is assumed that all timesteps are equidistant, if this is not the case set the parameter equal=false.", + "", + "PARAMETER", + " equal BOOL Set to false for unequal distributed timesteps (default: true)", +}; + +const CdoHelp TrendarithHelp = { + "NAME", + " addtrend, subtrend - Add or subtract a trend", + "", + "SYNOPSIS", + " <operator>[,equal] infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This module is for adding or subtracting a trend computed by the operator trend.", + "", + "OPERATORS", + " addtrend Add trend", + " It is", + " ", + " o(t,x) = i_1(t,x) + (i_2(1,x) + i_3(1,x)*t)", + " where t is the timesteps.", + " subtrend Subtract trend", + " It is", + " ", + " o(t,x) = i_1(t,x) - (i_2(1,x) + i_3(1,x)*t)", + " where t is the timesteps.", + "", + "PARAMETER", + " equal BOOL Set to false for unequal distributed timesteps (default: true)", +}; + +const CdoHelp EOFsHelp = { + "NAME", + " eof, eoftime, eofspatial, eof3d - Empirical Orthogonal Functions", + "", + "SYNOPSIS", + " <operator>,neof infile outfile1 outfile2", + "", + "DESCRIPTION", + " This module calculates empirical orthogonal functions of the data in infile ", + " as the eigen values of the scatter matrix (covariance matrix) S of the data", + " sample z(t). A more detailed description can be found above.", + " ", + " Please note, that the input data are assumed to be anomalies.", + " ", + " If operator eof is chosen, the EOFs are computed in either time or spatial", + " space, whichever is the fastest. If the user already knows, which computation", + " is faster, the module can be forced to perform a computation in time- or gridspace", + " by using the operators eoftime or eofspatial, respectively. This can enhance ", + " performance, especially for very long time series, where the number of timesteps", + " is larger than the number of grid-points. Data in infile are assumed to be anomalies.", + " If they are not, the behavior of this module is not well defined. ", + " After execution outfile1 will contain all eigen-values and outfile2 the", + " eigenvectors e_j. All EOFs and eigen-values are computed. However, only the first ", + " neof EOFs are written to outfile2. Nonetheless, outfile1 contains all eigen-values. ", + " ", + " Missing values are not fully supported. Support is only checked for non-changing", + " masks of missing values in time. Although there still will be results, they are", + " not trustworthy, and a warning will occur. In the latter case we suggest to ", + " replace missing values by 0 in infile. ", + "", + "OPERATORS", + " eof Calculate EOFs in spatial or time space", + " eoftime Calculate EOFs in time space", + " eofspatial Calculate EOFs in spatial space", + " eof3d Calculate 3-Dimensional EOFs in time space", + "", + "PARAMETER", + " neof INTEGER Number of eigen functions", + "", + "ENVIRONMENT", + " CDO_SVD_MODE ", + " Is used to choose the algorithm for eigenvalue calculation. Options are 'jacobi' for ", + " a one-sided parallel jacobi-algorithm (only executed in parallel if -P flag is set)", + " and 'danielson_lanczos' for a non-parallel d/l algorithm. The default setting is 'jacobi'.", + " CDO_WEIGHT_MODE", + " It is used to set the weight mode. The default is 'off'. Set it to 'on' for a weighted version.", + " MAX_JACOBI_ITER", + " Is the maximum integer number of annihilation sweeps that is executed if the ", + " jacobi-algorithm is used to compute the eigen values. The default value is 12.", + " FNORM_PRECISION", + " Is the Frobenius norm of the matrix consisting of an annihilation pair", + " of eigenvectors that is used to determine if the eigenvectors have reached ", + " a sufficient level of convergence. If all annihilation-pairs of vectors have ", + " a norm below this value, the computation is considered to have converged ", + " properly. Otherwise, a warning will occur. The default value 1e-12.", +}; + +const CdoHelp EofcoeffHelp = { + "NAME", + " eofcoeff - Principal coefficients of EOFs", + "", + "SYNOPSIS", + " eofcoeff infile1 infile2 obase", + "", + "DESCRIPTION", + " This module calculates the time series of the principal coefficients for given EOF", + " (empirical orthogonal functions) and data. Time steps in infile1 are assumed to be the EOFs,", + " time steps in infile2 are assumed to be the time series.", + " Note, that this operator calculates a non weighted dot product of the fields in infile1 and infile2.", + " For consistency set the environment variable CDO_WEIGHT_MODE=off when using eof or eof3d.", + " ", + " There will be a separate file containing a time series of principal coefficients", + " with time information from infile2 for each EOF in infile1. Output files will be", + " numbered as <obase><neof><suffix> where neof+1 is the number of the EOF (timestep)", + " in infile1 and suffix is the filename extension derived from the file format. ", + "", + "ENVIRONMENT", + " CDO_FILE_SUFFIX", + " Set the default file suffix. This suffix will be added to the output file ", + " names instead of the filename extension derived from the file format. ", + " Set this variable to NULL to disable the adding of a file suffix.", +}; + +const CdoHelp RemapbilHelp = { + "NAME", + " remapbil, genbil - Bilinear interpolation", + "", + "SYNOPSIS", + " remapbil,grid infile outfile", + " genbil,grid[,map3d] infile outfile", + "", + "DESCRIPTION", + " This module contains operators for a bilinear remapping of fields between grids in spherical coordinates.", + " The interpolation is based on an adapted SCRIP library version. ", + " For a detailed description of the interpolation method see SCRIP.", + " This interpolation method only works on quadrilateral curvilinear source grids.", + "", + "OPERATORS", + " remapbil Bilinear interpolation", + " Performs a bilinear interpolation on all input fields.", + " genbil Generate bilinear interpolation weights", + " Generates bilinear interpolation weights for the first input field and writes the", + " result to a file. The format of this file is NetCDF following the SCRIP convention.", + " Use the operator remap to apply this remapping weights to a data file with the same source grid.", + " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", + " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", + " map3d BOOL Generate all mapfiles of the first 3D field", + "", + "ENVIRONMENT", + " REMAP_EXTRAPOLATE", + " This variable is used to switch the extrapolation feature 'on' or 'off'.", + " By default the extrapolation is enabled for circular grids.", +}; + +const CdoHelp RemapbicHelp = { + "NAME", + " remapbic, genbic - Bicubic interpolation", + "", + "SYNOPSIS", + " remapbic,grid infile outfile", + " genbic,grid[,map3d] infile outfile", + "", + "DESCRIPTION", + " This module contains operators for a bicubic remapping of fields between grids in spherical coordinates.", + " The interpolation is based on an adapted SCRIP library version. ", + " For a detailed description of the interpolation method see SCRIP.", + " This interpolation method only works on quadrilateral curvilinear source grids.", + "", + "OPERATORS", + " remapbic Bicubic interpolation", + " Performs a bicubic interpolation on all input fields.", + " genbic Generate bicubic interpolation weights", + " Generates bicubic interpolation weights for the first input field and writes the", + " result to a file. The format of this file is NetCDF following the SCRIP convention.", + " Use the operator remap to apply this remapping weights to a data file with the same source grid.", + " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", + " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", + " map3d BOOL Generate all mapfiles of the first 3D field", + "", + "ENVIRONMENT", + " REMAP_EXTRAPOLATE", + " This variable is used to switch the extrapolation feature 'on' or 'off'.", + " By default the extrapolation is enabled for circular grids.", +}; + +const CdoHelp RemapnnHelp = { + "NAME", + " remapnn, gennn - Nearest neighbor remapping", + "", + "SYNOPSIS", + " remapnn,grid infile outfile", + " gennn,grid[,map3d] infile outfile", + "", + "DESCRIPTION", + " This module contains operators for a nearest neighbor remapping of fields between grids", + " in spherical coordinates.", + "", + "OPERATORS", + " remapnn Nearest neighbor remapping", + " Performs a nearest neighbor remapping on all input fields.", + " gennn Generate nearest neighbor remap weights", + " Generates nearest neighbor remapping weights for the first input field and writes the result to a file.", + " The format of this file is NetCDF following the SCRIP convention.", + " Use the operator remap to apply this remapping weights to a data file with the same source grid.", + " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", + " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", + " map3d BOOL Generate all mapfiles of the first 3D field", + "", + "ENVIRONMENT", + " REMAP_EXTRAPOLATE ", + " This variable is used to switch the extrapolation feature 'on' or 'off'.", + " By default the extrapolation is enabled for this remapping method.", + " CDO_GRIDSEARCH_RADIUS", + " Grid search radius in degree, default 180 degree.", +}; + +const CdoHelp RemapdisHelp = { + "NAME", + " remapdis, gendis - Distance weighted average remapping", + "", + "SYNOPSIS", + " remapdis,grid[,neighbors] infile outfile", + " gendis,grid[,neighbors[,map3d]] infile outfile", + "", + "DESCRIPTION", + " This module contains operators for an inverse distance weighted average remapping of the four", + " nearest neighbor values of fields between grids in spherical coordinates.", + " The default number of 4 neighbors can be changed with the neighbors parameter.", + "", + "OPERATORS", + " remapdis Distance weighted average remapping", + " Performs an inverse distance weighted averaged remapping of the nearest neighbor values on all input fields.", + " gendis Generate distance weighted average remap weights", + " Generates distance weighted averaged remapping weights of the nearest neighbor values for the first input", + " field and writes the result to a file. The format of this file is NetCDF following the SCRIP convention.", + " Use the operator remap to apply this remapping weights to a data file with the same source grid.", + " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", + " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", + " neighbors INTEGER Number of nearest neighbors [default: 4]", + " map3d BOOL Generate all mapfiles of the first 3D field", + "", + "ENVIRONMENT", + " REMAP_EXTRAPOLATE ", + " This variable is used to switch the extrapolation feature 'on' or 'off'.", + " By default the extrapolation is enabled for this remapping method.", + " CDO_GRIDSEARCH_RADIUS", + " Grid search radius in degree, default 180 degree.", +}; + +const CdoHelp RemapconHelp = { + "NAME", + " remapcon, gencon - First order conservative remapping", + "", + "SYNOPSIS", + " remapcon,grid infile outfile", + " gencon,grid[,map3d] infile outfile", + "", + "DESCRIPTION", + " This module contains operators for a first order conservative remapping of fields between grids in spherical coordinates.", + " The operators in this module uses code from the YAC software package to compute the conservative remapping weights.", + " For a detailed description of the interpolation method see YAC.", + " The interpolation method is completely general and can be used for any grid on a sphere.", + " The search algorithm for the conservative remapping requires that no grid cell occurs more than once. ", + "", + "OPERATORS", + " remapcon First order conservative remapping", + " Performs a first order conservative remapping on all input fields.", + " gencon Generate 1st order conservative remap weights", + " Generates first order conservative remapping weights for the first input field and", + " writes the result to a file. The format of this file is NetCDF following the SCRIP convention.", + " Use the operator remap to apply this remapping weights to a data file with the same source grid.", + " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", + " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", + " map3d BOOL Generate all mapfiles of the first 3D field", + "", + "ENVIRONMENT", + " CDO_REMAP_NORM", + " This variable is used to choose the normalization of the conservative interpolation. ", + " By default CDO_REMAP_NORM is set to 'fracarea'. 'fracarea' uses the sum of the", + " non-masked source cell intersected areas to normalize each target cell field value.", + " This results in a reasonable flux value but the flux is not locally conserved.", + " The option 'destarea' uses the total target cell area to normalize each target cell", + " field value. Local flux conservation is ensured, but unreasonable flux values may result.", + " REMAP_AREA_MIN", + " This variable is used to set the minimum destination area fraction. The default", + " of this variable is 0.0.", +}; + +const CdoHelp RemaplafHelp = { + "NAME", + " remaplaf, genlaf - Largest area fraction remapping", + "", + "SYNOPSIS", + " <operator>,grid infile outfile", + "", + "DESCRIPTION", + " This module contains operators for a largest area fraction remapping of fields between grids in spherical coordinates.", + " The operators in this module uses code from the YAC software package to compute the largest area fraction.", + " For a detailed description of the interpolation method see YAC.", + " The interpolation method is completely general and can be used for any grid on a sphere.", + " The search algorithm for this remapping method requires that no grid cell occurs more than once. ", + "", + "OPERATORS", + " remaplaf Largest area fraction remapping", + " Performs a largest area fraction remapping on all input fields.", + " genlaf Generate largest area fraction remap weights", + " Generates largest area fraction remapping weights for the first input field and", + " writes the result to a file. The format of this file is NetCDF following the SCRIP convention.", + " Use the operator remap to apply this remapping weights to a data file with the same source grid.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", + "", + "ENVIRONMENT", + " REMAP_AREA_MIN", + " This variable is used to set the minimum destination area fraction. The default", + " of this variable is 0.0.", +}; + +const CdoHelp RemapHelp = { + "NAME", + " remap - Grid remapping", + "", + "SYNOPSIS", + " remap,grid,weights infile outfile", + "", + "DESCRIPTION", + " Interpolation between different horizontal grids can be a very time-consuming ", + " process. Especially if the data are on an unstructured and/or a large grid. ", + " In this case the interpolation process can be split into two parts.", + " Firstly the generation of the interpolation weights, which is the most time-consuming part.", + " These interpolation weights can be reused for every remapping process with the operator remap.", + " This operator remaps all input fields to a new horizontal grid. The remap type and ", + " the interpolation weights of one input grid are read from a NetCDF file. More weights ", + " are computed if the input fields are on different grids. The NetCDF file with the ", + " weights should follow the SCRIP convention. Normally these weights come from a previous", + " call to one of the genXXX operators (e.g. genbil) or were created by the original SCRIP package.", + "", + "PARAMETER", + " grid STRING Target grid description file or name", + " weights STRING Interpolation weights (SCRIP NetCDF file)", + "", + "ENVIRONMENT", + " CDO_REMAP_NORM ", + " This variable is used to choose the normalization of the conservative interpolation. ", + " By default CDO_REMAP_NORM is set to 'fracarea'. 'fracarea' uses the sum of the", + " non-masked source cell intersected areas to normalize each target cell field value.", + " This results in a reasonable flux value but the flux is not locally conserved.", + " The option 'destarea' uses the total target cell area to normalize each target cell", + " field value. Local flux conservation is ensured, but unreasonable flux values may result.", + " REMAP_EXTRAPOLATE ", + " This variable is used to switch the extrapolation feature 'on' or 'off'.", + " By default the extrapolation is enabled for remapdis, remapnn and for circular grids.", + " REMAP_AREA_MIN ", + " This variable is used to set the minimum destination area fraction. The default", + " of this variable is 0.0.", + " CDO_GRIDSEARCH_RADIUS", + " Grid search radius in degree, default 180 degree.", +}; + +const CdoHelp RemapetaHelp = { + "NAME", + " remapeta - Remap vertical hybrid level", + "", + "SYNOPSIS", + " remapeta,vct[,oro] infile outfile", + "", + "DESCRIPTION", + " This operator interpolates between different vertical hybrid levels. This include the preparation ", + " of consistent data for the free atmosphere. The procedure for the vertical interpolation is based ", + " on the HIRLAM scheme and was adapted from INTERA.", + " The vertical interpolation is based on the vertical integration of the hydrostatic equation with ", + " few adjustments. The basic tasks are the following one:", + " - at first integration of hydrostatic equation", + " - extrapolation of surface pressure", + " - Planetary Boundary-Layer (PBL) proutfile interpolation", + " - interpolation in free atmosphere", + " - merging of both proutfiles", + " - final surface pressure correction", + " ", + " The vertical interpolation corrects the surface pressure. This is simply a cut-off or an addition ", + " of air mass. This mass correction should not influence the geostrophic velocity field in the middle ", + " troposhere. Therefore the total mass above a given reference level is conserved. As reference level", + " the geopotential height of the 400 hPa level is used. Near the surface the correction can affect ", + " the vertical structure of the PBL. Therefore the interpolation is done using the potential temperature. ", + " But in the free atmosphere above a certain n (n=0.8 defining the top of the PBL) the interpolation ", + " is done linearly. After the interpolation both proutfiles are merged. With the resulting ", + " temperature/pressure correction the hydrostatic equation is integrated again and adjusted to the ", + " reference level finding the final surface pressure correction. A more detailed description of", + " the interpolation can be found in INTERA. This operator requires all variables on the same horizontal grid.", + "", + "PARAMETER", + " vct STRING File name of an ASCII dataset with the vertical coordinate table", + " oro STRING File name with the orography (surf. geopotential) of the target dataset (optional)", + "", + "ENVIRONMENT", + " REMAPETA_PTOP", + " Sets the minimum pressure level for condensation.", + " Above this level the humidity is set to the constant 1.E-6.", + " The default value is 0 Pa.", + "", + "NOTE", + " The code numbers or the variable names of the required parameter have to follow the ECHAM convention.", + " ", + " Use the sinfo command to test if your vertical coordinate system is recognized as hybrid system.", + " ", + " In case remapeta complains about not finding any data on hybrid model levels you may wish", + " to use the setzaxis command to generate a zaxis description which conforms to the ECHAM convention.", + " See section \"1.4 Z-axis description\" for an example how to define a hybrid Z-axis.", +}; + +const CdoHelp VertintmlHelp = { + "NAME", + " ml2pl, ml2hl - Vertical interpolation", + "", + "SYNOPSIS", + " ml2pl,plevels infile outfile", + " ml2hl,hlevels infile outfile", + "", + "DESCRIPTION", + " Interpolates 3D variables on hybrid sigma pressure level to pressure or height levels.", + " To calculate the pressure on model levels, the a and b coefficients defining the model levels and", + " the surface pressure are required. The a and b coefficients are normally part of the model level data.", + " If not available, the surface pressure can be derived from the logarithm of the surface pressure.", + " To extrapolate the temperature, the surface geopotential is also needed.", + " The geopotential height must be present at the hybrid layer interfaces (model half-layers)!", + " All needed variables are identified by their GRIB1 code number or NetCDF CF standard name.", + " Supported parameter tables are: WMO standard table number 2 and ECMWF local table number 128.", + " ", + " Name & Units & GRIB1 code & CF standard name", + " log surface pressure & Pa & 152 &", + " surface pressure & Pa & 134 & surface_air_pressure", + " air temperature & K & 130 & air_temperature", + " surface geopotential & m2 s-2 & 129 & surface_geopotential", + " geopotential height & m & 156 & geopotential_height", + " ", + " Use the alias ml2plx/ml2hlx or the environment variable EXTRAPOLATE to extrapolate", + " missing values. This operator requires all variables on the same horizontal grid.", + " Missing values in the input data are not supported.", + " ", + "", + "OPERATORS", + " ml2pl Model to pressure level interpolation", + " Interpolates 3D variables on hybrid sigma pressure level to pressure level.", + " ml2hl Model to height level interpolation", + " Interpolates 3D variables on hybrid sigma pressure level to height level.", + " The procedure is the same as for the operator ml2pl except for", + " the pressure levels being calculated from the heights by:", + " plevel = 101325*exp(hlevel/-7000)", + "", + "PARAMETER", + " plevels FLOAT Pressure levels in pascal", + " hlevels FLOAT Height levels in meter", + "", + "ENVIRONMENT", + " EXTRAPOLATE", + " If set to 1 extrapolate missing values.", + "", + "NOTE", + " The components of the hybrid coordinate must always be avaiable at the hybrid layer interfaces even if the data is defined at the hybrid layer midpoints.", +}; + +const CdoHelp VertintapHelp = { + "NAME", + " ap2pl - Vertical pressure interpolation", + "", + "SYNOPSIS", + " ap2pl,plevels infile outfile", + "", + "DESCRIPTION", + " Interpolate 3D variables on hybrid sigma height coordinates to pressure levels.", + " The input file must contain the 3D air pressure in pascal. The air pressure is", + " identified by the NetCDF CF standard name air_pressure.", + " Use the alias ap2plx or the environment variable EXTRAPOLATE to extrapolate", + " missing values. This operator requires all variables on the same horizontal grid.", + "", + "PARAMETER", + " plevels FLOAT Comma-separated list of pressure levels in pascal", + "", + "ENVIRONMENT", + " EXTRAPOLATE", + " If set to 1 extrapolate missing values.", + "", + "NOTE", + " This is a specific implementation for NetCDF files from the ICON model, it may not work with data from other sources.", +}; + +const CdoHelp VertintghHelp = { + "NAME", + " gh2hl - Vertical height interpolation", + "", + "SYNOPSIS", + " gh2hl,hlevels infile outfile", + "", + "DESCRIPTION", + " Interpolate 3D variables on hybrid sigma height coordinates to height levels.", + " The input file must contain the 3D geometric height in meter. The geometric height is", + " identified by the NetCDF CF standard name geometric_height_at_full_level_center.", + " Use the alias gh2hlx or the environment variable EXTRAPOLATE to extrapolate", + " missing values. This operator requires all variables on the same horizontal grid.", + "", + "PARAMETER", + " hlevels FLOAT Comma-separated list of height levels in meter", + "", + "ENVIRONMENT", + " EXTRAPOLATE", + " If set to 1 extrapolate missing values.", + "", + "NOTE", + " This is a specific implementation for NetCDF files from the ICON model, it may not work with data from other sources.", +}; + +const CdoHelp IntlevelHelp = { + "NAME", + " intlevel - Linear level interpolation", + "", + "SYNOPSIS", + " intlevel,parameter infile outfile", + "", + "DESCRIPTION", + " This operator performs a linear vertical interpolation of 3D variables. The 1D target levels can be", + " specified with the level parameter or read in via a Z-axis description file.", + "", + "PARAMETER", + " level FLOAT Comma-separated list of target levels", + " zaxisdescription STRING Path to a file containing a description of the Z-axis", + " zvarname STRING Use zvarname as the vertical 3D source coordinate instead of the 1D coordinate variable", +}; + +const CdoHelp Intlevel3dHelp = { + "NAME", + " intlevel3d, intlevelx3d - ", + " Linear level interpolation from/to 3D vertical coordinates", + "", + "SYNOPSIS", + " <operator>,tgtcoordinate infile1 infile2 outfile", + "", + "DESCRIPTION", + " This operator performs a linear vertical interpolation of 3D variables fields with given 3D vertical coordinates.", + " infile1 contains the 3D data variables and infile2 the 3D vertical source coordinate. The parameter tgtcoordinate", + " is a datafile with the 3D vertical target coordinate.", + "", + "OPERATORS", + " intlevel3d Linear level interpolation onto a 3D vertical coordinate", + " intlevelx3d like intlevel3d but with extrapolation", + "", + "PARAMETER", + " tgtcoordinate STRING filename for 3D vertical target coordinates", +}; + +const CdoHelp InttimeHelp = { + "NAME", + " inttime, intntime - Time interpolation", + "", + "SYNOPSIS", + " inttime,date,time[,inc] infile outfile", + " intntime,n infile outfile", + "", + "DESCRIPTION", + " This module performs linear interpolation between timesteps.", + " Interpolation is only performed if both values exist.", + " If both values are missing values, the result is also a missing value.", + " If only one value exists, it is taken if the time weighting is greater than or equal to 0.5.", + " So no new value will be created at existing time steps, if the value is missing there.", + "", + "OPERATORS", + " inttime Interpolation between timesteps", + " This operator creates a new dataset by linear interpolation between timesteps.", + " The user has to define the start date/time with an optional increment.", + " intntime Interpolation between timesteps", + " This operator performs linear interpolation between timesteps.", + " The user has to define the number of timesteps from one timestep to the next.", + "", + "PARAMETER", + " date STRING Start date (format YYYY-MM-DD)", + " time STRING Start time (format hh:mm:ss)", + " inc STRING Optional increment (seconds, minutes, hours, days, months, years) [default: 0hour]", + " n INTEGER Number of timesteps from one timestep to the next", +}; + +const CdoHelp IntyearHelp = { + "NAME", + " intyear - Year interpolation", + "", + "SYNOPSIS", + " intyear,years infile1 infile2 obase", + "", + "DESCRIPTION", + " This operator performs linear interpolation between two years, timestep by timestep.", + " The input files need to have the same structure with the same variables.", + " The output files will be named <obase><yyyy><suffix> where yyyy will be the year and ", + " suffix is the filename extension derived from the file format.", + "", + "PARAMETER", + " years INTEGER Comma-separated list or first/last[/inc] range of years", + "", + "ENVIRONMENT", + " CDO_FILE_SUFFIX", + " Set the default file suffix. This suffix will be added to the output file ", + " names instead of the filename extension derived from the file format. ", + " Set this variable to NULL to disable the adding of a file suffix.", + "", + "NOTE", + " This operator needs to open all output files simultaneously.", + " The maximum number of open files depends on the operating system!", +}; + +const CdoHelp SpectralHelp = { + "NAME", + " sp2gp, gp2sp - Spectral transformation", + "", + "SYNOPSIS", + " <operator>[,type|trunc] infile outfile", + "", + "DESCRIPTION", + " This module transforms fields on a global regular Gaussian grid to spectral coefficients and vice versa.", + " The transformation is achieved by applying Fast Fourier Transformation (FFT) first and direct Legendre", + " Transformation afterwards in gp2sp. In sp2gp the inverse Legendre Transformation and inverse FFT are used.", + " Missing values are not supported.", + " ", + " The relationship between the spectral resolution, governed by the truncation number T, and the grid", + " resolution depends on the number of grid points at which the shortest wavelength field is represented.", + " For a grid with 2N points between the poles (so 4N grid points in total around the globe) the relationship is:", + " ", + " linear grid: the shortest wavelength is represented by 2 grid points → 4N ≃ 2(TL + 1)", + " ", + " quadratic grid: the shortest wavelength is represented by 3 grid points → 4N ≃ 3(TQ + 1)", + " ", + " cubic grid: the shortest wavelength is represented by 4 grid points → 4N ≃ 4(TC + 1)", + " ", + " The quadratic grid is used by ECHAM and ERA15. ERA40 is using a linear Gaussian grid reflected by the TL notation.", + " ", + " The following table shows the calculation of the number of latitudes and the triangular truncation for the different grid types:", + " ", + " Gridtype & Number of latitudes: nlat & Triangular truncation: ntr ", + " linear & NINT((ntr*2 + 1)/2) & (nlat*2 - 1) / 2", + " quadratic & NINT((ntr*3 + 1)/2) & (nlat*2 - 1) / 3", + " cubic & NINT((ntr*4 + 1)/2) & (nlat*2 - 1) / 4", + "", + "OPERATORS", + " sp2gp Spectral to gridpoint", + " Convert all spectral fields to a global regular Gaussian grid.", + " The optional parameter trunc must be greater than the input truncation.", + " gp2sp Gridpoint to spectral", + " Convert all Gaussian gridpoint fields to spectral fields.", + " The optional parameter trunc must be lower than the input truncation.", + "", + "PARAMETER", + " type STRING Type of the grid: quadratic, linear, cubic (default: type=quadratic)", + " trunc STRING Triangular truncation", + "", + "NOTE", + " To speed up the calculations, the Legendre polynoms are kept in memory. This requires a relatively large", + " amount of memory. This is for example 12GB for T1279 data.", +}; + +const CdoHelp SpecconvHelp = { + "NAME", + " sp2sp - Spectral conversion", + "", + "SYNOPSIS", + " sp2sp,trunc infile outfile", + "", + "DESCRIPTION", + " Changed the triangular truncation of all spectral fields. This operator performs downward ", + " conversion by cutting the resolution. Upward conversions are achieved by filling in zeros.", + "", + "PARAMETER", + " trunc INTEGER New spectral resolution", +}; + +const CdoHelp Wind2Help = { + "NAME", + " dv2ps - D and V to velocity potential and stream function", + "", + "SYNOPSIS", + " dv2ps infile outfile", + "", + "DESCRIPTION", + " Calculate spherical harmonic coefficients of velocity potential and stream function from ", + " spherical harmonic coefficients of relative divergence and vorticity. The divergence and ", + " vorticity need to have the names sd and svo or code numbers 155 and 138.", +}; + +const CdoHelp WindHelp = { + "NAME", + " dv2uv, uv2dv - Wind transformation", + "", + "SYNOPSIS", + " <operator>[,gridtype] infile outfile", + "", + "DESCRIPTION", + " This module converts relative divergence and vorticity to U and V wind and vice versa.", + " Divergence and vorticity are spherical harmonic coefficients in spectral space and", + " U and V are on a global regular Gaussian grid. The Gaussian latitudes need to be ordered from", + " north to south. Missing values are not supported.", + " ", + " The relationship between the spectral resolution, governed by the truncation number T, and the grid", + " resolution depends on the number of grid points at which the shortest wavelength field is represented.", + " For a grid with 2N points between the poles (so 4N grid points in total around the globe) the relationship is:", + " ", + " linear grid: the shortest wavelength is represented by 2 grid points → 4N ≃ 2(TL + 1)", + " ", + " quadratic grid: the shortest wavelength is represented by 3 grid points → 4N ≃ 3(TQ + 1)", + " ", + " cubic grid: the shortest wavelength is represented by 4 grid points → 4N ≃ 4(TC + 1)", + " ", + " The quadratic grid is used by ECHAM and ERA15. ERA40 is using a linear Gaussian grid reflected by the TL notation.", + " ", + " The following table shows the calculation of the number of latitudes and the triangular truncation for the different grid types:", + " ", + " Gridtype & Number of latitudes: nlat & Triangular truncation: ntr ", + " linear & NINT((ntr*2 + 1)/2) & (nlat*2 - 1) / 2", + " quadratic & NINT((ntr*3 + 1)/2) & (nlat*2 - 1) / 3", + " cubic & NINT((ntr*4 + 1)/2) & (nlat*2 - 1) / 4", + "", + "OPERATORS", + " dv2uv Divergence and vorticity to U and V wind", + " Calculate U and V wind on a Gaussian grid from spherical harmonic ", + " coefficients of relative divergence and vorticity. The divergence and vorticity ", + " need to have the names sd and svo or code numbers 155 and 138.", + " uv2dv U and V wind to divergence and vorticity", + " Calculate spherical harmonic coefficients of relative divergence and vorticity", + " from U and V wind. The U and V wind need to be on a Gaussian grid and need to have the ", + " names u and v or the code numbers 131 and 132.", + "", + "PARAMETER", + " gridtype STRING Type of the grid: quadratic, linear, cubic (default: quadratic)", + "", + "NOTE", + " To speed up the calculations, the Legendre polynoms are kept in memory. This requires a relatively large", + " amount of memory. This is for example 12GB for T1279 data.", +}; + +const CdoHelp FourierHelp = { + "NAME", + " fourier - Fourier transformation", + "", + "SYNOPSIS", + " fourier,epsilon infile outfile", + "", + "DESCRIPTION", + " The fourier operator performs the fourier transformation or the inverse fourier transformation of all input fields.", + " If the number of timesteps is a power of 2 then the algorithm of the Fast Fourier Transformation (FFT) is used.", + " ", + " ", + " If the input stream infile consists only of complex fields, then the fields of outfile, computed by", + " cdo -f ext fourier,1 -fourier,-1 infile outfile", + " are the same than that of infile. For real input files see function retocomplex.", + "", + "PARAMETER", + " epsilon INTEGER -1: forward transformation; 1: backward transformation", + "", + "NOTE", + " Complex numbers can only be stored in NetCDF4 and EXTRA format.", +}; + +const CdoHelp ImportbinaryHelp = { + "NAME", + " import_binary - Import binary data sets", + "", + "SYNOPSIS", + " import_binary infile outfile", + "", + "DESCRIPTION", + " This operator imports gridded binary data sets via a GrADS data descriptor file.", + " The GrADS data descriptor file contains a complete description of the binary data as well ", + " as instructions on where to find the data and how to read it. The descriptor file is an ASCII ", + " file that can be created easily with a text editor. The general contents of a gridded data ", + " descriptor file are as follows:", + " - Filename for the binary data", + " - Missing or undefined data value", + " - Mapping between grid coordinates and world coordinates", + " - Description of variables in the binary data set ", + " ", + " A detailed description of the components of a GrADS data descriptor file can be found in GrADS.", + " Here is a list of the supported components:", + " BYTESWAPPED, CHSUB, DSET, ENDVARS, FILEHEADER, HEADERBYTES, OPTIONS, TDEF, TITLE, ", + " TRAILERBYTES, UNDEF, VARS, XDEF, XYHEADER, YDEF, ZDEF", + "", + "NOTE", + " Only 32-bit IEEE floats are supported for standard binary files!", +}; + +const CdoHelp ImportcmsafHelp = { + "NAME", + " import_cmsaf - Import CM-SAF HDF5 files", + "", + "SYNOPSIS", + " import_cmsaf infile outfile", + "", + "DESCRIPTION", + " This operator imports gridded CM-SAF (Satellite Application Facility on Climate Monitoring)", + " HDF5 files. CM-SAF exploits data from polar-orbiting and geostationary satellites in order ", + " to provide climate monitoring products of the following parameters: ", + " ", + " Cloud parameters: cloud fraction (CFC), cloud type (CTY), cloud phase (CPH), ", + " cloud top height, pressure and temperature (CTH,CTP,CTT), ", + " cloud optical thickness (COT), cloud water path (CWP).", + " ", + " Surface radiation components: Surface albedo (SAL); surface incoming (SIS) ", + " and net (SNS) shortwave radiation; surface downward (SDL) ", + " and outgoing (SOL) longwave radiation, surface net longwave ", + " radiation (SNL) and surface radiation budget (SRB).", + " ", + " Top-of-atmosphere radiation components: Incoming (TIS) and reflected (TRS) ", + " solar radiative flux at top-of-atmosphere. Emitted thermal ", + " radiative flux at top-of-atmosphere (TET).", + " ", + " Water vapour: Vertically integrated water vapour (HTW), layered vertically ", + " integrated water vapour and layer mean temperature and relative ", + " humidity for 5 layers (HLW), temperature and mixing ratio at ", + " 6 pressure levels. ", + " ", + " Daily and monthly mean products can be ordered via the CM-SAF web page (www.cmsaf.eu). ", + " Products with higher spatial and temporal resolution, i.e. instantaneous swath-based products,", + " are available on request (contact.cmsaf@dwd.de). All products are distributed free-of-charge.", + " More information on the data is available on the CM-SAF homepage (www.cmsaf.eu).", + " ", + " Daily and monthly mean products are provided in equal-area projections. CDO reads the ", + " projection parameters from the metadata in the HDF5-headers in order to allow spatial ", + " operations like remapping. For spatial operations with instantaneous products on original ", + " satellite projection, additional files with arrays of latitudes and longitudes are needed.", + " These can be obtained from CM-SAF together with the data.", + " ", + "", + "NOTE", + " To use this operator, it is necessary to build CDO with HDF5 support (version 1.6 or higher).", + " The PROJ library (version 5.0 or higher) is needed for full support of the remapping", + " functionality. ", +}; + +const CdoHelp ImportamsrHelp = { + "NAME", + " import_amsr - Import AMSR binary files", + "", + "SYNOPSIS", + " import_amsr infile outfile", + "", + "DESCRIPTION", + " This operator imports gridded binary AMSR (Advanced Microwave Scanning Radiometer) data.", + " The binary data files are available from the AMSR ftp site (ftp://ftp.ssmi.com/amsre).", + " Each file consists of twelve (daily) or five (averaged) 0.25 x 0.25 degree ", + " grid (1440,720) byte maps. For daily files, six daytime maps in the following", + " order, Time (UTC), Sea Surface Temperature (SST), 10 meter Surface Wind Speed (WSPD),", + " Atmospheric Water Vapor (VAPOR), Cloud Liquid Water (CLOUD), and Rain Rate (RAIN), ", + " are followed by six nighttime maps in the same order. Time-Averaged files contain ", + " just the geophysical layers in the same order [SST, WSPD, VAPOR, CLOUD, RAIN].", + " More information to the data is available on the AMSR homepage http://www.remss.com/amsr.", +}; + +const CdoHelp InputHelp = { + "NAME", + " input, inputsrv, inputext - Formatted input", + "", + "SYNOPSIS", + " input,grid[,zaxis] outfile", + " inputsrv outfile", + " inputext outfile", + "", + "DESCRIPTION", + " This module reads time series of one 2D variable from standard input.", + " All input fields need to have the same horizontal grid. The format of the ", + " input depends on the chosen operator.", + "", + "OPERATORS", + " input ASCII input", + " Reads fields with ASCII numbers from standard input and stores them", + " in outfile. The numbers read are exactly that ones which are written ", + " out by the output operator.", + " inputsrv SERVICE ASCII input", + " Reads fields with ASCII numbers from standard input and stores them ", + " in outfile. Each field should have a header of 8 integers (SERVICE likely).", + " The numbers that are read are exactly that ones which are written out by ", + " the outputsrv operator.", + " inputext EXTRA ASCII input", + " Read fields with ASCII numbers from standard input and stores them ", + " in outfile. Each field should have header of 4 integers (EXTRA likely).", + " The numbers read are exactly that ones which are written out by ", + " the outputext operator.", + "", + "PARAMETER", + " grid STRING Grid description file or name", + " zaxis STRING Z-axis description file", +}; + +const CdoHelp OutputHelp = { + "NAME", + " output, outputf, outputint, outputsrv, outputext - Formatted output", + "", + "SYNOPSIS", + " output infiles", + " outputf,format[,nelem] infiles", + " outputint infiles", + " outputsrv infiles", + " outputext infiles", + "", + "DESCRIPTION", + " This module prints all values of all input datasets to standard output.", + " All input fields need to have the same horizontal grid. All input files ", + " need to have the same structure with the same variables.", + " The format of the output depends on the chosen operator.", + "", + "OPERATORS", + " output ASCII output", + " Prints all values to standard output.", + " Each row has 6 elements with the C-style format \"%13.6g\".", + " outputf Formatted output", + " Prints all values to standard output.", + " The format and number of elements for each row have to be specified by the parameters", + " format and nelem. The default for nelem is 1.", + " outputint Integer output", + " Prints all values rounded to the nearest integer to standard output.", + " outputsrv SERVICE ASCII output", + " Prints all values to standard output.", + " Each field with a header of 8 integers (SERVICE likely).", + " outputext EXTRA ASCII output", + " Prints all values to standard output.", + " Each field with a header of 4 integers (EXTRA likely).", + "", + "PARAMETER", + " format STRING C-style format for one element (e.g. %13.6g)", + " nelem INTEGER Number of elements for each row (default: nelem = 1)", +}; + +const CdoHelp OutputtabHelp = { + "NAME", + " outputtab - Table output", + "", + "SYNOPSIS", + " outputtab,parameter infiles outfile", + "", + "DESCRIPTION", + " This operator prints a table of all input datasets to standard output.", + " infiles is an arbitrary number of input files. All input files need to have ", + " the same structure with the same variables on different timesteps.", + " All input fields need to have the same horizontal grid.", + " ", + " The contents of the table depends on the chosen parameters. The format of each table parameter is keyname[:len].", + " len is the optional length of a table entry. The number of significant digits of floating point parameters", + " can be set with the CDO option --precision, the default is 7.", + " Here is a list of all valid keynames:", + " ", + " Keyname & Type & Description ", + " value & FLOAT & Value of the variable [len:8]", + " name & STRING & Name of the variable [len:8]", + " param & STRING & Parameter ID (GRIB1: code[.tabnum]; GRIB2: num[.cat[.dis]]) [len:11]", + " code & INTEGER & Code number [len:4]", + " x & FLOAT & X coordinate of the original grid [len:6]", + " y & FLOAT & Y coordinate of the original grid [len:6]", + " lon & FLOAT & Longitude coordinate in degrees [len:6]", + " lat & FLOAT & Latitude coordinate in degrees [len:6]", + " lev & FLOAT & Vertical level [len:6]", + " xind & INTEGER & Grid x index [len:4]", + " yind & INTEGER & Grid y index [len:4]", + " timestep & INTEGER & Timestep number [len:6]", + " date & STRING & Date (format YYYY-MM-DD) [len:10]", + " time & STRING & Time (format hh:mm:ss) [len:8]", + " year & INTEGER & Year [len:5]", + " month & INTEGER & Month [len:2]", + " day & INTEGER & Day [len:2]", + " nohead & INTEGER & Disable output of header line", + "", + "PARAMETER", + " parameter STRING Comma-separated list of keynames, one for each column of the table", +}; + +const CdoHelp OutputgmtHelp = { + "NAME", + " gmtxyz, gmtcells - GMT output", + "", + "SYNOPSIS", + " <operator> infile", + "", + "DESCRIPTION", + " This module prints the first field of the input dataset to standard output.", + " The output can be used to generate 2D Lon/Lat plots with GMT.", + " The format of the output depends on the chosen operator.", + "", + "OPERATORS", + " gmtxyz GMT xyz format", + " The operator exports the first field to the GMT xyz ASCII format.", + " The output can be used to create contour plots with the GMT module pscontour.", + " gmtcells GMT multiple segment format", + " The operator exports the first field to the GMT multiple segment ASCII format.", + " The output can be used to create shaded gridfill plots with the GMT module psxy.", +}; + +const CdoHelp GradsdesHelp = { + "NAME", + " gradsdes - GrADS data descriptor file", + "", + "SYNOPSIS", + " gradsdes[,mapversion] infile", + "", + "DESCRIPTION", + " Creates a GrADS data descriptor file. Supported file formats are GRIB1, NetCDF, SERVICE, ", + " EXTRA and IEG. For GRIB1 files the GrADS map file is also generated. For SERVICE and EXTRA", + " files the grid have to be specified with the CDO option '-g <grid>'. This module takes infile", + " in order to create filenames for the descriptor (infile.ctl) and the map (infile.gmp) file.", + "", + "PARAMETER", + " mapversion INTEGER Format version of the GrADS map file for GRIB1 datasets. Use 1 for a machine", + " specific version 1 GrADS map file, 2 for a machine independent version 2 GrADS map file", + " and 4 to support GRIB files >2GB. ", + " A version 2 map file can be used only with GrADS version 1.8 or newer.", + " A version 4 map file can be used only with GrADS version 2.0 or newer.", + " The default is 4 for files >2GB, otherwise 2.", +}; + +const CdoHelp AfterburnerHelp = { + "NAME", + " after - ECHAM standard post processor", + "", + "SYNOPSIS", + " after[,vct] infiles outfile", + "", + "DESCRIPTION", + " The \"afterburner\" is the standard post processor for ECHAM GRIB and NetCDF data which provides the following operations:", + " ", + " - Extract specified variables and levels", + " - Compute derived variables", + " - Transform spectral data to Gaussian grid representation", + " - Vertical interpolation to pressure levels", + " - Compute temporal means", + " ", + " This operator reads selection parameters as namelist from stdin.", + " Use the UNIX redirection \"<namelistfile\" to read the namelist from file.", + " ", + " The input files can't be combined with other CDO operators because of an optimized reader for this operator.", + "", + "NAMELIST", + " Namelist parameter and there defaults:", + " TYPE=0, CODE=-1, LEVEL=-1, INTERVAL=0, MEAN=0, EXTRAPOLATE=1", + " ", + " TYPE controls the transformation and vertical interpolation. Transforming spectral data to Gaussian grid", + " representation and vertical interpolation to pressure levels are performed in a chain of steps.", + " The TYPE parameter may be used to stop the chain at a certain step. Valid values are:", + " ", + " TYPE = 0 : Hybrid level spectral coefficients", + " TYPE = 10 : Hybrid level fourier coefficients", + " TYPE = 11 : Hybrid level zonal mean sections", + " TYPE = 20 : Hybrid level gauss grids", + " TYPE = 30 : Pressure level gauss grids", + " TYPE = 40 : Pressure level fourier coefficients", + " TYPE = 41 : Pressure level zonal mean sections", + " TYPE = 50 : Pressure level spectral coefficients", + " TYPE = 60 : Pressure level fourier coefficients", + " TYPE = 61 : Pressure level zonal mean sections", + " TYPE = 70 : Pressure level gauss grids", + " ", + " Vorticity, divergence, streamfunction and velocity potential need special treatment in the vertical transformation.", + " They are not available as types 30, 40 and 41. If you select one of these combinations, type is automatically", + " switched to the equivalent types 70, 60 and 61. The type of all other variables will be switched too, because ", + " the type is a global parameter.", + " ", + " CODE selects the variables by the ECHAM GRIB1 code number (1-255). The default value -1 processes all detected codes.", + " Derived variables computed by the afterburner:", + " ", + " Code & Name & Longname & Units & Level & Needed Codes", + " 34 & low_cld & low cloud & & single & 223 on modellevel ", + " 35 & mid_cld & mid cloud & & single & 223 on modellevel ", + " 36 & hih_cld & high cloud & & single & 223 on modellevel ", + " 131 & u & u-velocity & m/s & atm (ml+pl) & 138, 155 ", + " 132 & v & v-velocity & m/s & atm (ml+pl) & 138, 155 ", + " 135 & omega & vertical velocity & Pa/s & atm (ml+pl) & 138, 152, 155 ", + " 148 & stream & streamfunction & m^2/s & atm (ml+pl) & 131, 132 ", + " 149 & velopot & velocity potential & m^2/s & atm (ml+pl) & 131, 132 ", + " 151 & slp & mean sea level pressure & Pa & surface & 129, 130, 152 ", + " 156 & geopoth & geopotential height & m & atm (ml+pl) & 129, 130, 133, 152 ", + " 157 & rhumidity & relative humidity & & atm (ml+pl) & 130, 133, 152 ", + " 189 & sclfs & surface solar cloud forcing & & surface & 176-185 ", + " 190 & tclfs & surface thermal cloud forcing & & surface & 177-186 ", + " 191 & sclf0 & top solar cloud forcing & & surface & 178-187 ", + " 192 & tclf0 & top thermal cloud forcing & & surface & 179-188 ", + " 259 & windspeed & windspeed & m/s & atm (ml+pl) & sqrt(u*u+v*v) ", + " 260 & precip & total precipitation & & surface & 142+143 ", + " ", + " LEVEL selects the hybrid or pressure levels. The allowed values depends on the parameter TYPE.", + " The default value -1 processes all detected levels.", + " ", + " INTERVAL selects the processing interval. The default value 0 process data on monthly intervals.", + " INTERVAL=1 sets the interval to daily.", + " ", + " MEAN=1 compute and write monthly or daily mean fields. The default value 0 writes out all timesteps.", + " ", + " EXTRAPOLATE=0 switch of the extrapolation of missing values during the interpolation from model to pressure", + " level (only available with MEAN=0 and TYPE=30). The default value 1 extrapolate missing values.", + " ", + " Possible combinations of TYPE, CODE and MEAN:", + " ", + " TYPE & CODE & MEAN", + " 0/10/11 & 130 temperature & 0", + " 0/10/11 & 131 u-velocity & 0", + " 0/10/11 & 132 v-velocity & 0", + " 0/10/11 & 133 specific humidity & 0", + " 0/10/11 & 138 vorticity & 0", + " 0/10/11 & 148 streamfunction & 0", + " 0/10/11 & 149 velocity potential & 0", + " 0/10/11 & 152 LnPs & 0", + " 0/10/11 & 155 divergence & 0", + " >11 & all codes & 0/1", + "", + "PARAMETER", + " vct STRING File with VCT in ASCII format", +}; + +const CdoHelp FilterHelp = { + "NAME", + " bandpass, lowpass, highpass - Time series filtering", + "", + "SYNOPSIS", + " bandpass,fmin,fmax infile outfile", + " lowpass,fmax infile outfile", + " highpass,fmin infile outfile", + "", + "DESCRIPTION", + " This module takes the time series for each gridpoint in infile and (fast fourier) transforms it ", + " into the frequency domain. According to the particular operator and its parameters certain frequencies ", + " are filtered (set to zero) in the frequency domain and the spectrum is (inverse fast fourier) transformed ", + " back into the time domain.", + " To determine the frequency the time-axis of infile is used. (Data should have a constant time increment ", + " since this assumption applies for transformation. However, the time increment has to be different from zero.)", + " All frequencies given as parameter are interpreted per year. This is done by the assumption of a 365-day calendar. ", + " Consequently if you want to perform multiyear-filtering accurately you have to delete the 29th of February. ", + " If your infile has a 360 year calendar the frequency parameters fmin respectively fmax should be ", + " multiplied with a factor of 360/365 in order to obtain accurate results. ", + " For the set up of a frequency filter the frequency parameters have to be adjusted to a frequency in the data. ", + " Here fmin is rounded down and fmax is always rounded up. Consequently it is possible to use bandpass with ", + " fmin=fmax without getting a zero-field for outfile. ", + " Hints for efficient usage: ", + " - to get reliable results the time-series has to be detrended (cdo detrend)", + " - the lowest frequency greater zero that can be contained in infile is 1/(N*dT), ", + " - the greatest frequency is 1/(2dT) (Nyquist frequency),", + " with N the number of timesteps and dT the time increment of infile in years.", + " ", + " Missing value support for operators in this module is not implemented, yet!", + "", + "OPERATORS", + " bandpass Bandpass filtering", + " Bandpass filtering (pass for frequencies between fmin and fmax).", + " Suppresses all variability outside the frequency range specified by [fmin,fmax].", + " lowpass Lowpass filtering", + " Lowpass filtering (pass for frequencies lower than fmax).", + " Suppresses all variability with frequencies greater than fmax. ", + " highpass Highpass filtering", + " Highpass filtering (pass for frequencies greater than fmin). ", + " Suppresses all variabilty with frequencies lower than fmin. ", + "", + "PARAMETER", + " fmin FLOAT Minimum frequency per year that passes the filter.", + " fmax FLOAT Maximum frequency per year that passes the filter. ", + "", + "NOTE", + " For better performace of these operators use the CDO configure option --with-fftw3.", +}; + +const CdoHelp GridcellHelp = { + "NAME", + " gridarea, gridweights - Grid cell quantities", + "", + "SYNOPSIS", + " gridarea[,radius] infile outfile", + " gridweights infile outfile", + "", + "DESCRIPTION", + " This module reads the grid cell area of the first grid from the input stream. If the grid cell area is missing it", + " will be computed from the grid coordinates. The area of a grid cell is calculated using spherical triangles from", + " the coordinates of the center and the vertices. The base is a unit sphere which is scaled with the radius of the planet.", + " The default planet radius is 6371000 meter. The parameter radius or the environment variable PLANET_RADIUS can be used to change the default.", + " Depending on the chosen operator the grid cell area or weights are written to the output stream.", + "", + "OPERATORS", + " gridarea Grid cell area", + " Writes the grid cell area to the output stream. If the grid cell area have to", + " be computed it is scaled with the planet radius to square meters.", + " gridweights Grid cell weights", + " Writes the grid cell area weights to the output stream.", + "", + "PARAMETER", + " radius FLOAT Planet radius in meter", + "", + "ENVIRONMENT", + " PLANET_RADIUS", + " This variable is used to scale the computed grid cell areas to square meters. ", + " By default PLANET_RADIUS is set to an earth radius of 6371000 meter.", +}; + +const CdoHelp SmoothHelp = { + "NAME", + " smooth, smooth9 - Smooth grid points", + "", + "SYNOPSIS", + " smooth[,options] infile outfile", + " smooth9 infile outfile", + "", + "DESCRIPTION", + " Smooth all grid points of a horizontal grid.", + " Options is a comma-separated list of \"key=value\" pairs with optional parameters.", + "", + "OPERATORS", + " smooth Smooth grid points", + " Performs a N point smoothing on all input fields. The number of points used depend", + " on the search radius (radius) and the maximum number of points (maxpoints).", + " Per default all points within the search radius of 1degree are used.", + " The weights for the points depend on the form of the curve and the distance.", + " The implemented form of the curve is linear with constant default weights of 0.25", + " at distance 0 (weight0) and at the search radius (weightR).", + " smooth9 9 point smoothing", + " Performs a 9 point smoothing on all fields with a quadrilateral curvilinear grid.", + " The result at each grid point is a weighted average of the grid point plus", + " the 8 surrounding points. The center point receives a weight of 1.0, the ", + " points at each side and above and below receive a weight of 0.5, and corner ", + " points receive a weight of 0.3.", + " All 9 points are multiplied by their weights and summed, then divided by ", + " the total weight to obtain the smoothed value. Any missing data points are ", + " not included in the sum; points beyond the grid boundary are considered to ", + " be missing. Thus the final result may be the result of an averaging with less ", + " than 9 points.", + "", + "PARAMETER", + " nsmooth INTEGER Number of times to smooth, default nsmooth=1", + " radius STRING Search radius, default radius=1deg (units: deg, rad, km, m)", + " maxpoints INTEGER Maximum number of points, default maxpoints=<gridsize>", + " form STRING Form of the curve, default form=linear", + " weight0 FLOAT Weight at distance 0, default weight0=0.25", + " weightR FLOAT Weight at the search radius, default weightR=0.25", +}; + +const CdoHelp DeltatHelp = { + "NAME", + " deltat - Difference between timesteps", + "", + "SYNOPSIS", + " deltat infile outfile", + "", + "DESCRIPTION", + " This operator computes the difference between each timestep.", +}; + +const CdoHelp ReplacevaluesHelp = { + "NAME", + " setvals, setrtoc, setrtoc2 - Replace variable values", + "", + "SYNOPSIS", + " setvals,oldval,newval[,...] infile outfile", + " setrtoc,rmin,rmax,c infile outfile", + " setrtoc2,rmin,rmax,c,c2 infile outfile", + "", + "DESCRIPTION", + " This module replaces old variable values with new values, depending on the operator.", + "", + "OPERATORS", + " setvals Set list of old values to new values", + " Supply a list of n pairs of old and new values.", + " setrtoc Set range to constant", + " / c if i(t,x) GE rmin AND i(t,x) LE rmax", + " o(t,x) = ", + " \\ i(t,x) if i(t,x) LT rmin AND i(t,x) GT rmax", + " setrtoc2 Set range to constant others to constant2", + " / c if i(t,x) GE rmin AND i(t,x) LE rmax", + " o(t,x) = ", + " \\ c2 if i(t,x) LT rmin AND i(t,x) GT rmax", + "", + "PARAMETER", + " oldval,newval,... FLOAT Pairs of old and new values", + " rmin FLOAT Lower bound", + " rmax FLOAT Upper bound", + " c FLOAT New value - inside range", + " c2 FLOAT New value - outside range", +}; + +const CdoHelp GetgridcellHelp = { + "NAME", + " gridcellindex - Get grid cell index", + "", + "SYNOPSIS", + " gridcellindex[,parameter] infile", + "", + "DESCRIPTION", + " Get the grid cell index of one grid point selected by the parameter lon and lat.", + "", + "PARAMETER", + " lon INTEGER Longitude of the grid cell in degree", + " lat INTEGER Latitude of the grid cell in degree", +}; + +const CdoHelp VargenHelp = { + "NAME", + " const, random, topo, seq, stdatm - Generate a field", + "", + "SYNOPSIS", + " const,const,grid outfile", + " random,grid[,seed] outfile", + " topo[,grid] outfile", + " seq,start,end[,inc] outfile", + " stdatm,levels outfile", + "", + "DESCRIPTION", + " Generates a dataset with one or more fields", + "", + "OPERATORS", + " const Create a constant field", + " Creates a constant field. All field elements of the grid have the same value.", + " random Create a field with random numbers", + " Creates a field with rectangularly distrubuted random numbers in the interval [0,1].", + " topo Create a field with topography", + " Creates a field with topography data, per default on a global half degree grid.", + " seq Create a time series", + " Creates a time series with field size 1 and field elements beginning with a start value in time step 1", + " which is increased from one time step to the next.", + " stdatm Create values for pressure and temperature for hydrostatic atmosphere", + " Creates pressure and temperature values for the given list of vertical levels.", + " The formulars are:", + " ", + " P(z) = P_0 * exp(-1 * g/R * H/T_0 * log( (exp(z/H)*T_0 + T_Delta)/(T_0 + T_Delta))", + " T(z) = T_0 + T_Delta * exp(-z/H)", + " ", + " with the following constants", + " ", + " T_0 = 213 K Offset to get a surface temperature of 288K", + " T_Delta = 75 K Temperature lapse rate for 10Km", + " P_0 = 1013.25 hPa Surface pressure", + " H = 10000.0 m Scale height", + " g = 9.80665 m/s**2 Earth gravity", + " R = 287.05 J/kg*K Gas constant for air", + " ", + " This is the solution for the hydrostatic equations and is only valid for the", + " troposphere (constant positive lapse rate). The temperature increase in the", + " stratosphere and other effects of the upper atmosphere are not taken into", + " account.", + "", + "PARAMETER", + " const FLOAT Constant", + " seed INTEGER The seed for a new sequence of pseudo-random numbers [default: 1]", + " grid STRING Target grid description file or name", + " start FLOAT Start value of the loop", + " end FLOAT End value of the loop", + " inc FLOAT Increment of the loop [default: 1]", + " levels FLOAT Target levels in metre above surface", +}; + +const CdoHelp TimsortHelp = { + "NAME", + " timsort - Timsort", + "", + "SYNOPSIS", + " timsort infile outfile", + "", + "DESCRIPTION", + " Sorts the elements in ascending order over all timesteps for every field position.", + " After sorting it is:", + " ", + " o(t_1,x) <= o(t_2,x) forall (t_1<t_2),x", +}; + +const CdoHelp WindTransHelp = { + "NAME", + " uvDestag, rotuvNorth, projuvLatLon - Wind Transformation", + "", + "SYNOPSIS", + " uvDestag,u,v[,-/+0.5[,-/+0.5]] infile outfile", + " rotuvNorth,u,v infile outfile", + " projuvLatLon,u,v infile outfile", + "", + "DESCRIPTION", + " This module contains special operators for datsets with wind components on a rotated lon/lat grid, ", + " e.g. data from the regional model HIRLAM or REMO. ", + "", + "OPERATORS", + " uvDestag Destaggering of u/v wind components", + " This is a special operator for destaggering of wind components.", + " If the file contains a grid with temperature (name='t' or code=11)", + " then grid_temp will be used for destaggered wind.", + " rotuvNorth Rotate u/v wind to North pole.", + " This is an operator for transformation of wind-vectors from grid-relative to north-pole", + " relative for the whole file. (FAST implementation with JACOBIANS)", + " projuvLatLon Cylindrical Equidistant projection", + " Thus is an operator for transformation of wind-vectors from the globe-spherical coordinate system", + " into a flat Cylindrical Equidistant (lat-lon) projection. (FAST JACOBIAN implementation)", + "", + "PARAMETER", + " u,v STRING Pair of u,v wind components (use variable names or code numbers)", + " -/+0.5,-/+0.5 STRING Destaggered grid offsets are optional (default -0.5,-0.5)", +}; + +const CdoHelp RotuvbHelp = { + "NAME", + " rotuvb - Rotation", + "", + "SYNOPSIS", + " rotuvb,u,v,... infile outfile", + "", + "DESCRIPTION", + " This is a special operator for datsets with wind components on a rotated grid, ", + " e.g. data from the regional model REMO. It performs a backward transformation of ", + " velocity components U and V from a rotated spherical system to a geographical system.", + "", + "PARAMETER", + " u,v,... STRING Pairs of zonal and meridional velocity components (use variable names or code numbers)", + "", + "NOTE", + " This is a specific implementation for data from the REMO model, it may not work with data from other sources.", +}; + +const CdoHelp MrotuvbHelp = { + "NAME", + " mrotuvb - Backward rotation of MPIOM data", + "", + "SYNOPSIS", + " mrotuvb infile1 infile2 outfile", + "", + "DESCRIPTION", + " MPIOM data are on a rotated Arakawa C grid. The velocity components U and V are located on", + " the edges of the cells and point in the direction of the grid lines and rows.", + " With mrotuvb the velocity vector is rotated in latitudinal and longitudinal direction.", + " Before the rotation, U and V are interpolated to the scalar points (cell center).", + " U is located with the coordinates for U in infile1 and V in infile2.", + " mrotuvb assumes a positive meridional flow for a flow from grid point(i,j) to grid point(i,j+1)", + " and positive zonal flow for a flow from grid point(i+1,j) to point(i,j).", + "", + "NOTE", + " This is a specific implementation for data from the MPIOM model, it may not work with data from other sources.", +}; + +const CdoHelp MastrfuHelp = { + "NAME", + " mastrfu - Mass stream function", + "", + "SYNOPSIS", + " mastrfu infile outfile", + "", + "DESCRIPTION", + " This is a special operator for the post processing of the atmospheric general circulation", + " model ECHAM. It computes the mass stream function (code=272). The input dataset have ", + " to be a zonal mean of v-velocity [m/s] (code=132) on pressure levels.", +}; + +const CdoHelp PressureHelp = { + "NAME", + " pressure_half, pressure, delta_pressure - Pressure on model levels", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module contains operators to calculate the pressure on model levels.", + " To calculate the pressure on model levels, the a and b coefficients defining the model levels and", + " the surface pressure are required. The a and b coefficients are normally part of the model level data.", + " If not available, the surface pressure can be derived from the logarithm of the surface pressure.", + " The surface pressure is identified by the GRIB1 code number or NetCDF CF standard name.", + " ", + " Name & Units & GRIB1 code & CF standard name", + " log surface pressure & Pa & 152 &", + " surface pressure & Pa & 134 & surface_air_pressure", + " ", + "", + "OPERATORS", + " pressure_half Pressure on half-levels", + " This operator computes the pressure on model half-levels in pascal.", + " The model half-level pressure (p_half) is given by:", + " ", + " ", + " p_half = a + b ∗ sp", + " ", + " with", + " a, b: coefficients defining the model levels", + " sp: surface pressure", + " pressure Pressure on full-levels", + " This operator computes the pressure on model full-levels in pascal.", + " The pressure on model full-levels (p_full) is in the middle of the layers defined by the model half-levels:", + " ", + " p_full = (p_half_above + p_half_below) / 2", + " ", + " delta_pressure Pressure difference of half-levels", + " This operator computes the pressure difference between to model half-levels.", + " ", + " delta_p = p_half_below - p_half_above", + " ", +}; + +const CdoHelp DeriveparHelp = { + "NAME", + " sealevelpressure, gheight, gheight_half - Derived model parameters", + "", + "SYNOPSIS", + " <operator> infile outfile", + "", + "DESCRIPTION", + " This module contains operators that calculate derived model parameters. These are currently the parameters", + " sea level pressure and geopotential height. All necessary input variables are identified by their GRIB1", + " code number or the NetCDF CF standard name.", + " Supported GRIB1 parameter tables are: WMO standard table number 2 and ECMWF local table number 128.", + " ", + " CF standard name & Units & GRIB 1 code ", + " surface_air_pressure & Pa & 134", + " air_temperature & K & 130", + " specific_humidity & kg/kg & 133", + " surface_geopotential & m2 s-2 & 129", + " geopotential_height & m & 156", + " ", + "", + "OPERATORS", + " sealevelpressure Sea level pressure", + " This operator computes the sea level pressure (air_pressure_at_sea_level). Required input fields", + " are surface_air_pressure, surface_geopotential and air_temperature on full hybrid sigma pressure levels.", + " gheight Geopotential height on full-levels", + " This operator computes the geopotential height (geopotential_height) on model full-levels in metres.", + " Required input fields are surface_air_pressure, surface_geopotential, specific_humidity and air_temperature", + " on full hybrid sigma pressure levels. Note, this procedure is an approximation, which doesn't take into", + " account the effects of e.g. cloud ice and water, rain and snow.", + " gheight_half Geopotential height on half-levels", + " This operator computes the geopotential height (geopotential_height) on model half-levels in metres.", + " Required input fields are surface_air_pressure, surface_geopotential, specific_humidity and air_temperature", + " on full hybrid sigma pressure levels. Note, this procedure is an approximation, which doesn't take into", + " account the effects of e.g. cloud ice and water, rain and snow.", +}; + +const CdoHelp AdisitHelp = { + "NAME", + " adisit, adipot - Potential temperature to in-situ temperature and vice versa", + "", + "SYNOPSIS", + " <operator>[,pressure] infile outfile", + "", + "DESCRIPTION", + "", + "OPERATORS", + " adisit Potential temperature to in-situ temperature", + " This is a special operator for the post processing of the ocean and sea ice model MPIOM.", + " It converts potential temperature adiabatically to in-situ temperature to(t, s, p).", + " Required input fields are sea water potential temperature (name=tho; code=2) and sea water salinity (name=sao; code=5).", + " Pressure is calculated from the level information or can be specified by the optional parameter.", + " Output fields are sea water temperature (name=to; code=20) and sea water salinity (name=s; code=5).", + " adipot In-situ temperature to potential temperature", + " This is a special operator for the post processing of the ocean and sea ice model MPIOM.", + " It converts in-situ temperature to potential temperature tho(to, s, p). Required input fields", + " are sea water in-situ temperature (name=t; code=2) and sea water salinity (name=sao,s; code=5).", + " Pressure is calculated from the level information or can be specified by the optional parameter.", + " Output fields are sea water temperature (name=tho; code=2) and sea water salinity (name=s; code=5).", + "", + "PARAMETER", + " pressure FLOAT Pressure in bar (constant value assigned to all levels)", +}; + +const CdoHelp RhopotHelp = { + "NAME", + " rhopot - Calculates potential density", + "", + "SYNOPSIS", + " rhopot[,pressure] infile outfile", + "", + "DESCRIPTION", + " This is a special operator for the post processing of the ocean and sea ice model MPIOM.", + " It calculates the sea water potential density (name=rhopoto; code=18). Required input fields ", + " are sea water in-situ temperature (name=to; code=20) and sea water salinity (name=sao; code=5).", + " Pressure is calculated from the level information or can be specified by the optional parameter.", + "", + "PARAMETER", + " pressure FLOAT Pressure in bar (constant value assigned to all levels)", +}; + +const CdoHelp HistogramHelp = { + "NAME", + " histcount, histsum, histmean, histfreq - Histogram", + "", + "SYNOPSIS", + " <operator>,bounds infile outfile", + "", + "DESCRIPTION", + " This module creates bins for a histogram of the input data.", + " The bins have to be adjacent and have non-overlapping intervals.", + " The user has to define the bounds of the bins. The first value", + " is the lower bound and the second value the upper bound of the", + " first bin. The bounds of the second bin are defined by the", + " second and third value, aso.", + " Only 2-dimensional input fields are allowed. The output file ", + " contains one vertical level for each of the bins requested.", + "", + "OPERATORS", + " histcount Histogram count", + " Number of elements in the bin range.", + " histsum Histogram sum", + " Sum of elements in the bin range.", + " histmean Histogram mean", + " Mean of elements in the bin range.", + " histfreq Histogram frequency", + " Relative frequency of elements in the bin range.", + "", + "PARAMETER", + " bounds FLOAT Comma-separated list of the bin bounds (-inf and inf valid)", +}; + +const CdoHelp SethaloHelp = { + "NAME", + " sethalo - Set the bounds of a field", + "", + "SYNOPSIS", + " sethalo[,parameter] infile outfile", + "", + "DESCRIPTION", + " This operator sets the boundary in the east, west, south and north of the rectangular understood fields.", + " Positive values of the parameters increase the boundary in the selected direction. Negative values", + " decrease the field at the selected boundary. The new rows and columns are filled with the missing value.", + " With the optional parameter value a different fill value can be used. Global cyclic fields are filled", + " cyclically at the east and west borders, if the fill value is not set by the user.", + "", + "PARAMETER", + " east INTEGER East halo", + " west INTEGER West halo", + " south INTEGER South halo", + " north INTEGER North halo", + " value FLOAT Fill value (default is the missing value)", +}; + +const CdoHelp WctHelp = { + "NAME", + " wct - Windchill temperature", + "", + "SYNOPSIS", + " wct infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 and infile2 be time series of temperature and wind", + " speed records, then a corresponding time series of resulting windchill", + " temperatures is written to outfile. The wind chill temperature", + " calculation is only valid for a temperature of T <= 33 °C and a wind speed", + " of v >= 1.39 m/s. Whenever these conditions are not satisfied, a missing", + " value is written to outfile. Note that temperature and wind speed records", + " have to be given in units of °C and m/s, respectively.", +}; + +const CdoHelp FdnsHelp = { + "NAME", + " fdns - Frost days where no snow index per time period", + "", + "SYNOPSIS", + " fdns infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily minimum temperature TN", + " and infile2 be a corresponding series of daily surface snow", + " amounts. Then the number of days where TN < 0 °C and the surface ", + " snow amount is less than 1 cm is counted. The temperature TN", + " have to be given in units of Kelvin.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", +}; + +const CdoHelp StrwinHelp = { + "NAME", + " strwin - Strong wind days index per time period", + "", + "SYNOPSIS", + " strwin[,v] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily maximum horizontal wind speed", + " VX, then the number of days where VX > v is counted. The horizontal wind", + " speed v is an optional parameter with default v = 10.5 m/s. A further", + " output variable is the maximum number of consecutive days with maximum wind", + " speed greater than or equal to v. Note that both VX and v have to be given in", + " units of m/s. Also note that the horizontal wind speed is defined as the", + " square root of the sum of squares of the zonal and meridional wind speeds.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + "", + "PARAMETER", + " v FLOAT Horizontal wind speed threshold (m/s, default v = 10.5 m/s)", +}; + +const CdoHelp StrbreHelp = { + "NAME", + " strbre - Strong breeze days index per time period", + "", + "SYNOPSIS", + " strbre infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily maximum horizontal wind speed", + " VX, then the number of days where VX is greater than or equal to 10.5 m/s ", + " is counted. A further output variable is the maximum number of consecutive", + " days with maximum wind speed greater than or equal to 10.5 m/s. Note that", + " VX is defined as the square root of the sum of squares of the zonal and", + " meridional wind speeds and have to be given in units of m/s.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", +}; + +const CdoHelp StrgalHelp = { + "NAME", + " strgal - Strong gale days index per time period", + "", + "SYNOPSIS", + " strgal infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily maximum horizontal wind speed", + " VX, then the number of days where VX is greater than or equal to 20.5 m/s ", + " is counted. A further output variable is the maximum number of consecutive", + " days with maximum wind speed greater than or equal to 20.5 m/s. Note that", + " VX is defined as the square root of the sum of square of the zonal and", + " meridional wind speeds and have to be given in units of m/s.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", +}; + +const CdoHelp HurrHelp = { + "NAME", + " hurr - Hurricane days index per time period", + "", + "SYNOPSIS", + " hurr infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily maximum horizontal wind speed", + " VX, then the number of days where VX is greater than or equal to 32.5 m/s", + " is counted. A further output variable is the maximum number of consecutive", + " days with maximum wind speed greater than or equal to 32.5 m/s. Note that", + " VX is defined as the square root of the sum of squares of the zonal and", + " meridional wind speeds and have to be given in units of m/s.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", +}; + +const CdoHelp CMORliteHelp = { + "NAME", + " cmorlite - CMOR lite", + "", + "SYNOPSIS", + " cmorlite,table[,convert] infile outfile", + "", + "DESCRIPTION", + " The CMOR (Climate Model Output Rewriter) library comprises a set of", + " functions, that can be used to produce CF-compliant NetCDF files that ", + " fulfill the requirements of many of the climate community's standard", + " model experiments. These experiments are collectively referred to as", + " MIP's. Much of the metadata written to the output files is defined in", + " MIP-specific tables, typically made available from each MIP's web site.", + " ", + " The CDO operator cmorlite process the header and variable section", + " of such MIP tables and writes the result with the internal IO library CDI.", + " In addition to the CMOR 2 and 3 table format, the CDO parameter table format", + " is also supported. The following parameter table entries are available:", + " ", + " Entry & Type & Description ", + " name & WORD & Name of the variable", + " out_name & WORD & New name of the variable", + " type & WORD & Data type (real or double)", + " standard_name & WORD & As defined in the CF standard name table", + " long_name & STRING & Describing the variable", + " units & STRING & Specifying the units for the variable", + " comment & STRING & Information concerning the variable", + " cell_methods & STRING & Information concerning calculation of means or climatologies", + " cell_measures & STRING & Indicates the names of the variables containing cell areas and volumes", + " missing_value & FLOAT & Specifying how missing data will be identified", + " valid_min & FLOAT & Minimum valid value", + " valid_max & FLOAT & Maximum valid value", + " ok_min_mean_abs & FLOAT & Minimum absolute mean", + " ok_max_mean_abs & FLOAT & Maximum absolute mean", + " factor & FLOAT & Scale factor", + " delete & INTEGER & Set to 1 to delete variable", + " convert & INTEGER & Set to 1 to convert the unit if necessary", + " ", + " Most of the above entries are stored as variables attributes, some of them are handled differently.", + " The variable name is used as a search key for the parameter table. valid_min, valid_max,", + " ok_min_mean_abs and ok_max_mean_abs are used to check the range of the data.", + "", + "PARAMETER", + " table STRING Name of the CMOR table as specified from PCMDI", + " convert STRING Converts the units if necessary", +}; + +const CdoHelp VerifygridHelp = { + "NAME", + " verifygrid - Verify grid coordinates", + "", + "SYNOPSIS", + " verifygrid infile", + "", + "DESCRIPTION", + " This operator verifies the coordinates of all horizontal grids found in infile.", + " Among other things, it searches for duplicate cells, non-convex cells,", + " and whether the center is located outside the cell bounds.", + " Use the CDO option -v to output the position of these cells.", + " This information can be useful to avoid problems when interpolating the data.", +}; + +const CdoHelp HealpixHelp = { + "NAME", + " hpdegrade, hpupgrade - Change healpix resolution", + "", + "SYNOPSIS", + " <operator>,parameter infile outfile", + "", + "DESCRIPTION", + " Degrade or upgrade the resolution of a healpix grid.", + "", + "OPERATORS", + " hpdegrade Degrade healpix", + " Degrade the resolution of a healpix grid. The value of the target pixel is the mean of the source pixels.", + " hpupgrade Upgrade healpix", + " Upgrade the resolution of a healpix grid. The values of the target pixels is the value of the source pixel.", + "", + "PARAMETER", + " nside INTEGER The nside of the target healpix, must be a power of two [default: same as input].", + " order STRING Pixel ordering of the target healpix ('nested' or 'ring').", + " power FLOAT If non-zero, divide the result by (nside[in]/nside[out])**power. power=-2 keeps the sum of the map invariant.", +}; + +const CdoHelp NCL_windHelp = { + "NAME", + " uv2vr_cfd, uv2dv_cfd - Wind transformation", + "", + "SYNOPSIS", + " <operator>[,u,v,boundOpt,outMode] infile outfile", + "", + "DESCRIPTION", + " This module contains CDO operators with an interface to NCL functions.", + " The corresponding NCL functions have the same name. A more detailed description", + " of those NCL function can be found on the NCL homepage https://www.ncl.ucar.edu.", + "", + "OPERATORS", + " uv2vr_cfd U and V wind to relative vorticity", + " Computes relative vorticity for a latitude-longitude grid using centered finite differences.", + " The grid need not be global and missing values are allowed.", + " uv2dv_cfd U and V wind to divergence", + " Computes divergence for a latitude-longitude grid using centered finite differences.", + " The grid need not be global and missing values are allowed.", + "", + "PARAMETER", + " u STRING Name of variable u (default: u)", + " v STRING Name of variable v (default: v)", + " boundOpt INTEGER Boundary condition option (0-3) (default: 0/1 for cyclic grids)", + " outMode STRING Output mode new/append (default: new)", +}; + +const CdoHelp CMORHelp = { + "NAME", + " cmor - Climate Model Output Rewriting to produce CMIP-compliant data", + "", + "SYNOPSIS", + " cmor,MIPtable[,cmor_name=VarList[,key=value[,...]]] infile", + "", + "DESCRIPTION", + " ", + " ", + " The CDO operator cmor converts an infile into a CMIP-compliant format", + " by using the CMOR library. Each output file contains a single output variable.", + " The name of the output files are generated by CMOR according to a template based on the", + " DRS (Data reference Syntax) of the project. CMOR checks and applies the information delivered", + " through the project dependend MIPtable on the infile. Additional information", + " which is required for the conversion can be configured via keyvalues as optional parameters.", + " ", + " By specifying a variable selector keyvalue, e.g. cmor_name=tas, the user can", + " pre-select a subset of infile variables. If name or code is specified, a", + " corresponding cmor_name which can also be found in the MIPtable is also", + " required to map the infile variable to the CMOR-variable. For mapping more", + " variables at the operator call, one can specify a mapping table via keyword mapping_table.", + " ", + " Global attributes must be collected in info files and can be specified via keyword", + " info. All required and optional global attributes as well as information", + " about table file formats are given in the 'cdo cmor manual'.", + " ", + " If questions remain, do not hesitate to ask and send an email to wachsmannATdkrz.de.", + " ", + "", + "PARAMETER", + " MIPtable STRING Name of the MIP table as used by CMOR.", + " --------------------------------------------------------------------------------------------", + " cmor_name | cn STRING Variable selector and specified in the MIP table.", + " Comma-separated list of CMOR variable names.", + " Default is to process all variables.", + " name | n STRING Variable selector.", + " Name of a selected @file{infile} variable.", + " code | c INTEGER Variable selector. ", + " Three digits (GRIB) Code of a selected @file{infile} variable.", + " --------------------------------------------------------------------------------------------", + " info | i STRING Preprozessing.", + " Comma-separated list of filenames.", + " Containins global attributes and control keywords.", + " Default: CWD/.cdocmorinfo", + " grid_info | gi STRING Preprozessing.", + " NetCDF or table formatted file with model grid description.", + " Horizontal and vertical axes are substituted with the ones from grid info file.", + " mapping_table | mt STRING Preprozessing.", + " Fortran Namelist containing variable information for e.g. renaming.", + " keep_all_attributes | kaa STRING Preprozessing.", + " 'y' for passing all infile attributes. 'n' for discarding all infile attributes.", + " --------------------------------------------------------------------------------------------", + " drs | d CHARACTER Output control.", + " Do(=y, default) or do not(=n) move output into the project DRS structure.", + " drs_root | dr STRING Output control. CMOR output root directory.", + " Default: CWD.", + " output_mode | om CHARACTER Output control.", + " Either 'r' for replace (default) or 'a' for append mode.", + " last_chunk | lc STRING Output control. Filename of chunk to which shall be appended. ", + " max_size | ms INTEGER Output control. Limit of output file sie in GigaByte.", + " deflate_level | dl INTEGER Output control. Compression level. -1: No compression. 0: Only shuffle.", + " version_date | vd INTEGER Output control. Subdirectory name in CMIP6 DRS.", + " --------------------------------------------------------------------------------------------", + " required_time_units | rtu STRING Temporal description.", + " Time axis reference date specified by the experiment.", + " Format: 'days since YYYY-day-month hh:mm:ss'.", + " cell_methods | cm CHARACTER Temporal description.", + " Cell_methods of time axis.", + " Value is one of 'm' (default) , 'p', 'c', 'n', 'd'", + " --------------------------------------------------------------------------------------------", + " units | u STRING Variable attrbiute. Units of the variable.", + " Must be known by library UDunits.", + " variable_comment | vc STRING Variable attribute. Variable comment.", + " positive | p CHARACTER Variable attrbiute.", + " Positive flux direction, either 'u' for upward or 'd' for downward.", + " z_axis | za STRING Name of the coordinate variable associated with", + " the z-axis of the target variable.", + " character_axis | ca STRING Name of the coordinate variable associated with", + " a character axis of the target variable.", + " Valid axes names are: basin, vegtype or oline. ", + " t_axis | ta STRING Sets time values and time bounds to the nearest value", + " required by the project given by the value of t_axis.", + " Valid value is: cmip", +}; + +const CdoHelp MagplotHelp = { + "NAME", + " contour, shaded, grfill - Lat/Lon plot", + "", + "SYNOPSIS", + " <operator>,parameter infile obase", + "", + "DESCRIPTION", + " The operators in this module generates 2D Lon/Lat plots.", + " The data for the plot is read from infile.", + " Only data on rectilinear Lon/Lat grids are supported.", + " The output file will be named <obase>_<param>.<device> where param is the parameter name and", + " device is the device name. The default output file format is postscript,", + " this can be changed with the device parameter.", + " The type of the plot depends on the choosen operator.", + " ", + " Here is a list of all common plot parameters:", + " ", + " Keyname & Type & Description ", + " device & STRING & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)", + " projection & STRING & Projection (cylindrical, polar_stereographic, robinson, mercator)", + " style & STRING & Contour line style (solid, dash, dot, chain_dash, chain_dot)", + " min & FLOAT & Minimum value", + " max & FLOAT & Maximum value", + " lon_max & FLOAT & Maximum longitude of the image", + " lon_min & FLOAT & Minimum longitude of the image", + " lat_max & FLOAT & Maximum latitude of the image", + " lat_min & FLOAT & Minimum latitude of the image", + " count & INTEGER & Number of Contour levels / Colour bands ", + " interval & FLOAT & Interval in data units between two bands lines", + " list & INTEGER & List of levels to be plotted", + " RGB & STRING & TRUE or FALSE, to indicate, if the input colour is in RGB format", + " step_freq & INTEGER & Frequency of time steps to be considered for making the animation", + " & & (device=gif_animation). Default value is \"1\" (all time steps).", + " & & Will be ignored if input file has multiple variables.", + " file_split & STRING & TRUE or FALSE, to split the output file for each variable, if input has", + " & & multiple variables. Default value is \"FALSE\". Valid only for \"PS\" format.", + "", + "OPERATORS", + " contour Contour plot", + " The operator contour generates the discrete contour lines of the input field values.", + " The following additional parameters are valid for contour operator,", + " module in addition to the common plot parameters:", + " ", + " Keyname & Type & Description ", + " colour & STRING & Colour for drawing the contours", + " thickness & FLOAT & Thickness of the contour line", + " style & STRING & Line Style can be \"SOLID\", \"DASH\", \"DOT\", \"CHAIN_DASH\",", + " & & \"CHAIN_DOT\"", + " shaded Shaded contour plot", + " The operator shaded generates the filled contours of the given input field values.", + " The following additional parameters are valid for shaded contour and gridfill operator,", + " in addition to the common plot parameters.", + " ", + " Keyname & Type & Description ", + " colour_min & STRING & Colour for the Minimum colour band", + " colour_max & STRING & Colour for the Minimum colour band", + " colour_triad & STRING & Direction of colour sequencing for shading \"CW\" or \"ACW\",", + " & & to denote \"clockwise\" and \"anticlockwise\" respectively.", + " & & To be used in conjunction with \"colour_min\", \"colour_max\"", + " & & options. Default is \"ACW\"", + " colour_table & STRING & File with user specified colours with the format as", + " ", + " Example file for 6 colours in RGB format:", + " 6", + " RGB(0.0;0.0;1.0)", + " RGB(0.0;0.0;0.5)", + " RGB(0.0;0.5;0.5)", + " RGB(0.0;1.0;0.0)", + " RGB(0.5;0.5;0.0)", + " RGB(1.0;0.0;0.0)", + " ", + " grfill Shaded gridfill plot", + " The operator grfill is similar to satellite imaging and shades each cell (pixel) according", + " to the value of the field at that cell.", + "", + "PARAMETER", + " parameter STRING Comma-separated list of plot parameters", + "", + "NOTE", + " All colour parameter can be either standard name or in RGB format.", + " The valid standard name strings for \"colour\" are:", + " ", + " \"red\", \"green\", \"blue\", \"yellow\", \"cyan\", \"magenta\", \"black\", \"avocado\", \"beige\",", + " \"brick\", \"brown\", \"burgundy\", \"charcoal\", \"chestnut\", \"coral\", \"cream\", \"evergreen\",", + " \"gold\", \"grey\", \"khaki\", \"kellygreen\", \"lavender\", \"mustard\", \"navy\", \"ochre\",", + " \"olive\", \"peach\", \"pink\", \"rose\", \"rust\", \"sky\", \"tan\", \"tangerine\", \"turquoise\",", + " \"violet\", \"reddishpurple\", \"purplered\", \"purplishred\", \"orangishred\", \"redorange\",", + " \"reddishorange\", \"orange\", \"yellowishorange\", \"orangeyellow\", \"orangishyellow\",", + " \"greenishyellow\", \"yellowgreen\", \"yellowishgreen\", \"bluishgreen\", \"bluegreen\",", + " \"greenishblue\", \"purplishblue\", \"bluepurple\", \"bluishpurple\", \"purple\", \"white\"", +}; + +const CdoHelp MagvectorHelp = { + "NAME", + " vector - Lat/Lon vector plot", + "", + "SYNOPSIS", + " vector,parameter infile obase", + "", + "DESCRIPTION", + " This operator generates 2D Lon/Lat vector plots.", + " The data for the plot is read from infile. The input is expected to contain two velocity", + " components. Only data on rectilinear Lon/Lat grids are supported.", + " The output file will be named <obase>.<device> where device is the device name. ", + " The default output file format is postscript, this can be changed with the device parameter.", + " ", + " Here is a list of all vector plot parameters:", + " ", + " Keyname & Type & Description ", + " device & STRING & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)", + " projection & STRING & Projection (cylindrical, polar_stereographic, robinson, mercator)", + " thin_fac & FLOAT & Controls the actual number of wind arrows or flags plotted (default 2).", + " unit_vec & FLOAT & Wind speed in m/s represented by a unit vector (1.0cm)", + " step_freq & INTEGER & Frequency of time steps to be considered for making the animation", + " & & (device=gif_animation). Default value is \"1\" (all time steps).", + " & & Will be ignored if input file has multiple variables.", + "", + "PARAMETER", + " parameter STRING Comma-separated list of plot parameters", +}; + +const CdoHelp MaggraphHelp = { + "NAME", + " graph - Line graph plot", + "", + "SYNOPSIS", + " graph,parameter infiles outfile", + "", + "DESCRIPTION", + " This operator generates line graph plots.", + " The data for the plot is read from infiles. The result is written to outfile.", + " The default output file format is postscript, this can be changed with the device parameter.", + " ", + " Here is a list of all graph plot parameters:", + " ", + " Keyname & Type & Description ", + " device & STRING & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)", + " ymin & FLOAT & Minimum value of the y-axis data ", + " ymax & FLOAT & Maximum value of the y-axis data ", + " linewidth & INT & Linewidth (default 8)", + " stat & STRING & \"TRUE\" or \"FALSE\", to switch on the mean computation. Default is \"FALSE\".", + " & & Will be overridden to \"FALSE\", if input files have unequal number of time", + " & & steps or different start/end times. ", + " sigma & FLOAT & Standard deviation value for generating shaded back ground around the mean value.", + " & & To be used in conjunction with 'stat=\"TRUE\"' ", + " obsv & STRING & To indicate if the input files have an observation data, by setting to \"TRUE\".", + " & & Default value is \"FALSE\". The observation data should be the first file in the", + " & & input file list. The observation data is always plotted in black colour. ", + "", + "PARAMETER", + " parameter STRING Comma-separated list of plot parameters", +}; + +const CdoHelp EcaCddHelp = { + "NAME", + " eca_cdd, etccdi_cdd - Consecutive dry days index per time period", + "", + "SYNOPSIS", + " <operator>[,R[,N[,params]]] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily precipitation amount RR, then the largest number ", + " of consecutive days where RR is less than R is counted. R is an optional parameter with ", + " default R = 1 mm. A further output variable is the number of dry periods of more than N days.", + " Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_cdd Consecutive dry days index per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_cdd Consecutive dry days index per time period", + " The default output frequency is yearly.", + " Periods within overlapping years are accounted for the first year.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", + " N INTEGER Minimum number of days exceeded (default: N = 5)", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaCfdHelp = { + "NAME", + " eca_cfd - Consecutive frost days index per time period", + "", + "SYNOPSIS", + " eca_cfd[,N] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily minimum temperature TN, then the largest number of", + " consecutive days where TN < 0 °C is counted. Note that TN have to be given in units of Kelvin.", + " A further output variable is the number of frost periods of more than N days.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", + "", + "PARAMETER", + " N INTEGER Minimum number of days exceeded (default: N = 5)", +}; + +const CdoHelp EcaCsuHelp = { + "NAME", + " eca_csu - Consecutive summer days index per time period", + "", + "SYNOPSIS", + " eca_csu[,T[,N]] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily maximum temperature TX, then the largest number of consecutive", + " days where TX > T is counted. The number T is an optional parameter with default T = 25°C.", + " Note that TN have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.", + " A further output variable is the number of summer periods of more than N days.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", + "", + "PARAMETER", + " T FLOAT Temperature threshold (unit: °C; default: T = 25°C)", + " N INTEGER Minimum number of days exceeded (default: N = 5)", +}; + +const CdoHelp EcaCwdHelp = { + "NAME", + " eca_cwd, etccdi_cwd - Consecutive wet days index per time period", + "", + "SYNOPSIS", + " <operator>[,params] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily precipitation amount RR, then the largest number ", + " of consecutive days where RR is at least R is counted. R is an optional parameter with ", + " default R = 1 mm. A further output variable is the number of wet periods of more than N days.", + " Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_cwd Consecutive wet days index per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_cwd Consecutive wet days index per time period", + " The default output frequency is yearly.", + " Periods within overlapping years are accounted for the first year.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", + " N INTEGER Minimum number of days exceeded (default: N = 5)", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaCwdiHelp = { + "NAME", + " eca_cwdi - Cold wave duration index wrt mean of reference period", + "", + "SYNOPSIS", + " eca_cwdi[,nday[,T]] infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily minimum temperature TN, and let infile2 be the mean ", + " TNnorm of daily minimum temperatures for any period used as reference. Then counted is the number of days", + " where, in intervals of at least nday consecutive days, TN < TNnorm - T.", + " The numbers nday and T are optional parameters with default nday = 6 and T = 5°C. ", + " A further output variable is the number of cold waves longer than or equal to nday days.", + " TNnorm is calculated as the mean of minimum temperatures of a five day window centred on each calendar day ", + " of a given climate reference period. Note that both TN and TNnorm have to be given in the same units.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", + "", + "PARAMETER", + " nday INTEGER Number of consecutive days (default: nday = 6)", + " T FLOAT Temperature offset (unit: °C; default: T = 5°C)", +}; + +const CdoHelp EcaCwfiHelp = { + "NAME", + " eca_cwfi, etccdi_csdi - ", + " Cold-spell days index wrt 10th percentile of reference period", + "", + "SYNOPSIS", + " <operator>[,nday[,params]] infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily mean temperature TG, and infile2 be the 10th", + " percentile TGn10 of daily mean temperatures for any period used as reference. ", + " Then counted is the number of days where, in intervals of at least nday consecutive days,", + " TG < TGn10. The number nday is an optional parameter with default nday = 6.", + " A further output variable is the number of cold-spell periods longer than or equal to nday days.", + " TGn10 is calculated as the 10th percentile of daily mean temperatures of a five day window ", + " centred on each calendar day of a given climate reference period. Note that both TG and TGn10 ", + " have to be given in the same units.", + "", + "OPERATORS", + " eca_cwfi Cold-spell days index wrt 10th percentile of reference period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_csdi Cold-spell duration index", + " The default output frequency is yearly.", + " Periods within overlapping years are accounted for the first year.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " nday INTEGER Number of consecutive days (default: nday = 6)", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaEtrHelp = { + "NAME", + " eca_etr - Intra-period extreme temperature range", + "", + "SYNOPSIS", + " eca_etr infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 and infile2 be time series of thr maximum and minimum", + " temperature TX and TN, respectively. Then the extreme temperature", + " range is the difference of the maximum of TX and the minimum of TN.", + " Note that TX and TN have to be given in the same units.", + " The date information of a timestep in outfile is the date of", + " the last contributing timesteps in infile1 and infile2.", +}; + +const CdoHelp EcaFdHelp = { + "NAME", + " eca_fd, etccdi_fd - Frost days index per time period", + "", + "SYNOPSIS", + " <operator>[,parameter] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily minimum temperature TN,", + " then the number of days where TN < 0 °C is counted. Note", + " that TN have to be given in units of Kelvin. Parameter is a", + " comma-separated list of \"key=value\" pairs.", + "", + "OPERATORS", + " eca_fd Frost days index per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_fd Frost days index per time period", + " The default output frequency is yearly.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaGslHelp = { + "NAME", + " eca_gsl - Thermal Growing season length index", + "", + "SYNOPSIS", + " eca_gsl[,nday[,T[,fland]]] infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily mean temperature TG, and infile2 be a land-water mask.", + " Within a period of 12 months, the thermal growing season length is officially defined as the number of days between:", + " - first occurrence of at least nday consecutive days with TG > T", + " - first occurrence of at least nday consecutive days with TG < T within the last 6 months", + " On northern hemisphere, this period corresponds with the regular year, whereas on southern hemisphere, it starts ", + " at July 1st. Please note, that this definition may lead to weird results concerning values TG = T: ", + " In the first half of the period, these days do not contribute to the gsl, but they do within the second half.", + " Moreover this definition could lead to discontinuous values in equatorial regions.", + " ", + " The numbers nday and T are optional parameter with default nday = 6 and T = 5°C. ", + " The number fland is an optional parameter with default value fland = 0.5 and denotes the fraction of ", + " a grid point that have to be covered by land in order to be included in the calculation. A further output variable ", + " is the start day of year of the growing season. Note that TG have to be given in units of Kelvin, whereas T ", + " have to be given in degrees Celsius.", + " ", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", + "", + "PARAMETER", + " nday INTEGER Number of consecutive days (default: nday = 6)", + " T FLOAT Temperature threshold (unit: °C; default: T = 5°C)", + " fland FLOAT Land fraction threshold (default: fland = 0.5)", +}; + +const CdoHelp EcaHdHelp = { + "NAME", + " eca_hd - Heating degree days per time period", + "", + "SYNOPSIS", + " eca_hd[,T1[,T2]] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily mean temperature TG, then the heating degree days ", + " are defined as the sum of T1 - TG, where only values TG < T2 are considered. ", + " If T1 and T2 are omitted, a temperature of 17°C is used for both parameters. ", + " If only T1 is given, T2 is set to T1. Note that TG have to be given in units ", + " of kelvin, whereas T1 and T2 have to be given in degrees Celsius.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", + "", + "PARAMETER", + " T1 FLOAT Temperature limit (unit: °C; default: T1 = 17°C)", + " T2 FLOAT Temperature limit (unit: °C; default: T2 = T1)", +}; + +const CdoHelp EcaHwdiHelp = { + "NAME", + " eca_hwdi - Heat wave duration index wrt mean of reference period", + "", + "SYNOPSIS", + " eca_hwdi[,nday[,T]] infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily maximum temperature TX, and let infile2 be the mean ", + " TXnorm of daily maximum temperatures for any period used as reference. Then counted is the number of days", + " where, in intervals of at least nday consecutive days, TX > TXnorm + T.", + " The numbers nday and T are optional parameters with default nday = 6 and T = 5°C. ", + " A further output variable is the number of heat waves longer than or equal to nday days. ", + " TXnorm is calculated as the mean of maximum temperatures of a five day window centred on each calendar day", + " of a given climate reference period. Note that both TX and TXnorm have to be given in the same units.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", + "", + "PARAMETER", + " nday INTEGER Number of consecutive days (default: nday = 6)", + " T FLOAT Temperature offset (unit: °C; default: T = 5°C)", +}; + +const CdoHelp EcaHwfiHelp = { + "NAME", + " eca_hwfi, etccdi_wsdi - ", + " Warm spell days index wrt 90th percentile of reference period", + "", + "SYNOPSIS", + " <operator>[,params] infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily mean temperature TG, and ", + " infile2 be the 90th percentile TGn90 of daily mean temperatures", + " for any period used as reference. Then counted is the number of days", + " where, in intervals of at least nday consecutive days, TG > TGn90. The", + " number nday is an optional parameter with default nday = 6. A further", + " output variable is the number of warm-spell periods longer than or", + " equal to nday days. ", + " TGn90 is calculated as the 90th percentile of daily mean temperatures of a five ", + " day window centred on each calendar day of a given climate reference period.", + " Note that both TG and TGn90 have to be given in the same units.", + " Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_hwfi Warm spell days index wrt 90th percentile of reference period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_wsdi Warm Spell Duration Index", + " The default output frequency is yearly.", + " Periods within overlapping years are accounted for the first year.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " nday INTEGER Number of consecutive days (default: nday = 6)", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaIdHelp = { + "NAME", + " eca_id, etccdi_id - Ice days index per time period", + "", + "SYNOPSIS", + " <operator>[,parameter] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily maximum temperature TX,", + " then the number of days where TX < 0 °C is counted. Note", + " that TX have to be given in units of Kelvin. Parameter is a", + " comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_id Ice days index per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_id Ice days index per time period", + " The default output frequency is yearly.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaR75pHelp = { + "NAME", + " eca_r75p - Moderate wet days wrt 75th percentile of reference period", + "", + "SYNOPSIS", + " eca_r75p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the percentage of wet days with RR > RRn75 is calculated. ", + " RRn75 is calculated as the 75th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,75.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaR75ptotHelp = { + "NAME", + " eca_r75ptot - Precipitation percent due to R75p days", + "", + "SYNOPSIS", + " eca_r75ptot infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn75 to the total ", + " precipitation sum is calculated. ", + " RRn75 is calculated as the 75th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,75.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaR90pHelp = { + "NAME", + " eca_r90p - Wet days wrt 90th percentile of reference period", + "", + "SYNOPSIS", + " eca_r90p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the percentage of wet days with RR > RRn90 is calculated. ", + " RRn90 is calculated as the 90th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,90.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaR90ptotHelp = { + "NAME", + " eca_r90ptot - Precipitation percent due to R90p days", + "", + "SYNOPSIS", + " eca_r90ptot infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn90 to the total ", + " precipitation sum is calculated. ", + " RRn90 is calculated as the 90th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,90.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaR95pHelp = { + "NAME", + " eca_r95p - Very wet days wrt 95th percentile of reference period", + "", + "SYNOPSIS", + " eca_r95p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the percentage of wet days with RR > RRn95 is calculated. ", + " RRn95 is calculated as the 95th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,95.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaR95ptotHelp = { + "NAME", + " eca_r95ptot - Precipitation percent due to R95p days", + "", + "SYNOPSIS", + " eca_r95ptot infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn95 to the total ", + " precipitation sum is calculated. ", + " RRn95 is calculated as the 95th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,95.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaR99pHelp = { + "NAME", + " eca_r99p - Extremely wet days wrt 99th percentile of reference period", + "", + "SYNOPSIS", + " eca_r99p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the percentage of wet days with RR > RRn99 is calculated. ", + " RRn99 is calculated as the 99th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,99.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaR99ptotHelp = { + "NAME", + " eca_r99ptot - Precipitation percent due to R99p days", + "", + "SYNOPSIS", + " eca_r99ptot infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", + " and infile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ", + " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn99 to the total ", + " precipitation sum is calculated. ", + " RRn99 is calculated as the 99th percentile of all wet days of a given climate reference period.", + " Usually infile2 is generated by the operator ydaypctl,99.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaPdHelp = { + "NAME", + " eca_pd, eca_r10mm, eca_r20mm, etccdi_r1mm - ", + " Precipitation days index per time period", + "", + "SYNOPSIS", + " eca_pd,x infile outfile", + " eca_r10mm infile outfile", + " eca_r20mm infile outfile", + " etccdi_r1mm[,parameter] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]),", + " then the number of days where RR is at least x mm is counted. ", + " eca_r10mm and eca_r20mm are specific ECA operators with a daily precipitation amount of 10 and 20 mm respectively.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile", + " except for the etccdi operator. Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_pd Precipitation days index per time period", + " Generic ECA operator with daily precipitation sum exceeding x mm.", + " eca_r10mm Heavy precipitation days index per time period", + " Specific ECA operator with daily precipitation sum exceeding 10 mm.", + " eca_r20mm Very heavy precipitation days index per time period", + " Specific ECA operator with daily precipitation sum exceeding 20 mm.", + " etccdi_r1mm Precipitation days index per time period", + " The default output frequency is yearly.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " x FLOAT Daily precipitation amount threshold in [mm]", + " freq STRING Output frequency (year, month)", + "", + "NOTE", + " Precipitation rates in [mm/s] have to be converted to precipitation amounts (multiply with 86400 s).", + " Apart from metadata information the result of eca_pd,1 and eca_rr1 is the same.", +}; + +const CdoHelp EcaRr1Help = { + "NAME", + " eca_rr1 - Wet days index per time period", + "", + "SYNOPSIS", + " eca_rr1[,R] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]), then", + " the number of days where RR is at least R is counted. R is an optional parameter with default R = 1 mm. ", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", + "", + "PARAMETER", + " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", +}; + +const CdoHelp EcaRx1dayHelp = { + "NAME", + " eca_rx1day, etccdi_rx1day - ", + " Highest one day precipitation amount per time period", + "", + "SYNOPSIS", + " <operator>[,parameter] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily precipitation amount RR,", + " then the maximum of RR is written to outfile. If the optional", + " parameter mode is set to 'm' the maximum daily precipitation", + " amounts are determined for each month. ", + " Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_rx1day Highest one day precipitation amount per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_rx1day Maximum 1-day Precipitation", + " The default output frequency is yearly.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaRx5dayHelp = { + "NAME", + " eca_rx5day, etccdi_rx5day - ", + " Highest five-day precipitation amount per time period", + "", + "SYNOPSIS", + " <operator>[,x[,params]] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of 5-day precipitation totals RR, then the maximum of RR is written to outfile. ", + " A further output variable is the number of 5 day period with precipitation totals greater than x mm, where x ", + " is an optional parameter with default x = 50 mm.", + " Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_rx5day Highest five-day precipitation amount per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_rx5day Highest five-day precipitation amount per time period", + " The default output frequency is yearly.", + " Periods within overlapping years are accounted for the first year.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " x FLOAT Precipitation threshold (unit: mm; default: x = 50 mm)", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaSdiiHelp = { + "NAME", + " eca_sdii - Simple daily intensity index per time period", + "", + "SYNOPSIS", + " eca_sdii[,R] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily precipitation amount RR, then the mean precipitation amount at ", + " wet days (RR >= R) is written to outfile. R is an optional parameter with default R = 1 mm.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", + "", + "PARAMETER", + " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", +}; + +const CdoHelp EcaSuHelp = { + "NAME", + " eca_su, etccdi_su - Summer days index per time period", + "", + "SYNOPSIS", + " <operator>[,T[,params]] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily maximum temperature TX, then the number of days where ", + " TX > T is counted. The number T is an optional parameter with default T = 25°C. ", + " Note that TX have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.", + " Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_su Summer days index per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_su Summer days index per time period", + " The default output frequency is yearly.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " T FLOAT Temperature threshold (unit: °C; default: T = 25°C)", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaTg10pHelp = { + "NAME", + " eca_tg10p - Cold days percent wrt 10th percentile of reference period", + "", + "SYNOPSIS", + " eca_tg10p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily mean temperature TG, and", + " infile2 be the 10th percentile TGn10 of daily mean temperatures", + " for any period used as reference. Then the percentage of time where ", + " TG < TGn10 is calculated.", + " TGn10 is calculated as the 10th percentile of daily mean temperatures of a five ", + " day window centred on each calendar day of a given climate reference period.", + " Note that both TG and TGn10 have to be given in the same units.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile1.", +}; + +const CdoHelp EcaTg90pHelp = { + "NAME", + " eca_tg90p - Warm days percent wrt 90th percentile of reference period", + "", + "SYNOPSIS", + " eca_tg90p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily mean temperature TG, and", + " infile2 be the 90th percentile TGn90 of daily mean temperatures", + " for any period used as reference. Then the percentage of time where TG > TGn90 ", + " is calculated. ", + " TGn90 is calculated as the 90th percentile of daily mean temperatures of a five ", + " day window centred on each calendar day of a given climate reference period.", + " Note that both TG and TGn90 have to be given in the same units.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile1.", +}; + +const CdoHelp EcaTn10pHelp = { + "NAME", + " eca_tn10p - Cold nights percent wrt 10th percentile of reference period", + "", + "SYNOPSIS", + " eca_tn10p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time serie of the daily minimum temperature TN, and", + " infile2 be the 10th percentile TNn10 of daily minimum temperatures", + " for any period used as reference. Then the percentage of time where TN < TNn10 ", + " is calculated.", + " TNn10 is calculated as the 10th percentile of daily minimum temperatures of a five ", + " day window centred on each calendar day of a given climate reference period.", + " Note that both TN and TNn10 have to be given in the same units.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile1.", +}; + +const CdoHelp EcaTn90pHelp = { + "NAME", + " eca_tn90p - Warm nights percent wrt 90th percentile of reference period", + "", + "SYNOPSIS", + " eca_tn90p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily minimum temperature TN, and infile2 be the ", + " 90th percentile TNn90 of daily minimum temperatures for any period used as reference. ", + " Then the percentage of time where TN > TNn90 is calculated. TNn90 is calculated as the 90th percentile", + " of daily minimum temperatures of a five day window centred on each calendar day of a given climate", + " reference period. Note that both TN and TNn90 have to be given in the same units.", + " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", +}; + +const CdoHelp EcaTrHelp = { + "NAME", + " eca_tr, etccdi_tr - Tropical nights index per time period", + "", + "SYNOPSIS", + " <operator>[,T[,params]] infile outfile", + "", + "DESCRIPTION", + " Let infile be a time series of the daily minimum temperature TN, then the number of days where ", + " TN > T is counted. The number T is an optional parameter with default T = 20°C. ", + " Note that TN have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.", + " Parameter is a comma-separated list of \"key=values\" pairs.", + "", + "OPERATORS", + " eca_tr Tropical nights index per time period", + " The operator counts over the entire time series.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile.", + " etccdi_tr Tropical nights index per time period", + " The default output frequency is yearly.", + " The date information of a timestep in outfile is the mid of", + " the frequency interval.", + "", + "PARAMETER", + " T FLOAT Temperature threshold (unit: °C; default: T = 20°C)", + " freq STRING Output frequency (year, month)", +}; + +const CdoHelp EcaTx10pHelp = { + "NAME", + " eca_tx10p - Very cold days percent wrt 10th percentile of reference period", + "", + "SYNOPSIS", + " eca_tx10p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily maximum temperature TX, and", + " infile2 be the 10th percentile TXn10 of daily maximum temperatures", + " for any period used as reference. Then the percentage of time where TX < TXn10.", + " is calculated.", + " TXn10 is calculated as the 10th percentile of daily maximum temperatures of a five ", + " day window centred on each calendar day of a given climate reference period.", + " Note that both TX and TXn10 have to be givenin the same units.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile1.", +}; + +const CdoHelp EcaTx90pHelp = { + "NAME", + " eca_tx90p - Very warm days percent wrt 90th percentile of reference period", + "", + "SYNOPSIS", + " eca_tx90p infile1 infile2 outfile", + "", + "DESCRIPTION", + " Let infile1 be a time series of the daily maximum temperature TX, and", + " infile2 be the 90th percentile TXn90 of daily maximum temperatures", + " for any period used as reference. Then the percentage of time where TX > TXn90.", + " is calculated.", + " TXn90 is calculated as the 90th percentile of daily maximum temperatures of a five ", + " day window centred on each calendar day of a given climate reference period.", + " Note that both TX and TXn90 have to be given in the same units.", + " The date information of a timestep in outfile is the date of", + " the last contributing timestep in infile1.", +}; + +const CdoHelp EcaEtccdiHelp = { + "NAME", + " etccdi_tx90p, etccdi_tx10p, etccdi_tn90p, etccdi_tn10p, etccdi_r95p, ", + " etccdi_r99p - ", + " ETCCDI conform index for a reference periode calculated with bootstrapping", + "", + "SYNOPSIS", + " <operator>,n,startboot,endboot[,m] infile1 infile2 infile3 outfile", + "", + "DESCRIPTION", + " This module enables to compute Climate Extremes Indices according to the method recommended", + " by the Expert Team on Climate Change Detection and Indices. It differs from the", + " corresponding eca_* indices by applying bootstrapping for a reference period", + " (see Zhang et al. 2005) given by startboot and endboot and using the R-type 8 method ", + " for percentile calculation.", + " A requirement for correct percentile calculation is that", + " CDO_PCTL_NBINS>=window*(endboot-startboot+1)*(sizeof(double)/sizeof(int))+2", + " This demands for high working storage since the entire data of the bootstrapping interval", + " need to be hold in storage. Otherwise, a histogram is used to calculate the percentile.", + " infile2 (infile3) contains the daily minimum (maximum) of the bootstrapping interval.", + " If m=m, the output variable will be saved monthly, otherwise with yearly frequency.", + "", + "OPERATORS", + " etccdi_tx90p Percentage of Days when Daily Maximum Temperature is Above the 90th Percentile", + " etccdi_tx10p Percentage of Days when Daily Maximum Temperature is Below the 10th Percentile", + " etccdi_tn90p Percentage of Days when Daily Minimum Temperature is Above the 90th Percentile", + " etccdi_tn10p Percentage of Days when Daily Minimum Temperature is Below the 10th Percentile", + " etccdi_r95p Annual Total Precipitation when Daily Precipitation Exceeds the 95th Percentile of Wet Day Precipitation", + " etccdi_r99p Annual Total Precipitation when Daily Precipitation Exceeds the 99th Percentile of Wet Day Precipitation", + "", + "PARAMETER", + " n INTEGER Window days, number of timesteps", + " startboot INTEGER First year of bootstrapping interval", + " endboot INTEGER Last year of bootstrapping interval", + " m CHARACTER Output frequency", + "", + "ENVIRONMENT", + " CDO_PCTL_NBINS", + " Sets the number of histogram bins. The default number is 101.", +}; + +// clang-format on + diff --git a/src/operator_help.h b/src/operator_help.h index 44c450995bdc3f30119f4cb34e44f7f98e7a79d7..1815b95ff6ea1601a2be16c0e123ab0251fc9e1f 100644 --- a/src/operator_help.h +++ b/src/operator_help.h @@ -3,7253 +3,227 @@ #ifndef OPERATOR_HELP_H #define OPERATOR_HELP_H -// clang-format off - - -static const char *InfoHelp[] = { - "NAME", - " info, infon, 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 ", - " the same structure with the same variables on different timesteps.", - " The information displayed depends on the chosen operator.", - "", - "OPERATORS", - " info Dataset information listed by parameter identifier", - " Prints information and simple statistics for each field of all input datasets.", - " For each field the operator prints one line with the following elements:", - " - Date and Time", - " - Level, Gridsize and number of Missing values", - " - Minimum, Mean and Maximum \\", - " The mean value is computed without the use of area weights!", - " - Parameter identifier", - " infon Dataset information listed by parameter name", - " The same as operator info but using the name instead of the", - " identifier to label the parameter.", - " 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.", - nullptr -}; - -static const char *SinfoHelp[] = { - "NAME", - " sinfo, sinfon - Short information", - "", - "SYNOPSIS", - " <operator> infiles", - "", - "DESCRIPTION", - " This module writes information about the structure of infiles to standard output.", - " infiles is an arbitrary number of input files. All input files need to have ", - " the same structure with the same variables on different timesteps.", - " The information displayed depends on the chosen operator.", - "", - "OPERATORS", - " sinfo Short information listed by parameter identifier", - " Prints short information of a dataset. The information is divided into 4 sections.", - " Section 1 prints one line per parameter with the following information:", - " - institute and source", - " - time c=constant v=varying", - " - type of statistical processing", - " - number of levels and z-axis number", - " - horizontal grid size and number", - " - data type", - " - parameter identifier", - " Section 2 and 3 gives a short overview of all grid and vertical coordinates.", - " And the last section contains short information of the time coordinate.", - " sinfon Short information listed by parameter name", - " The same as operator sinfo but using the name instead of the identifier to label the parameter.", - nullptr -}; - -static const char *XSinfoHelp[] = { - "NAME", - " xsinfo, xsinfop - Extra short information", - "", - "SYNOPSIS", - " <operator> infiles", - "", - "DESCRIPTION", - " This module writes information about the structure of infiles to standard output.", - " infiles is an arbitrary number of input files. All input files need to have ", - " the same structure with the same variables on different timesteps.", - " The information displayed depends on the chosen operator.", - "", - "OPERATORS", - " xsinfo Extra short information listed by parameter name", - " Prints short information of a dataset. The information is divided into 4 sections.", - " Section 1 prints one line per parameter with the following information:", - " - institute and source", - " - time c=constant v=varying", - " - type of statistical processing", - " - number of levels and z-axis number", - " - horizontal grid size and number", - " - data type", - " - memory type (float or double)", - " - parameter name", - " Section 2 to 4 gives a short overview of all grid, vertical and time coordinates.", - " xsinfop Extra short information listed by parameter identifier", - " The same as operator xsinfo but using the identifier instead of the name to label the parameter.", - nullptr -}; - -static const char *DiffHelp[] = { - "NAME", - " diff, diffn - Compare two datasets field by field", - "", - "SYNOPSIS", - " <operator>[,options] infile1 infile2", - "", - "DESCRIPTION", - " Compares the contents of two datasets field by field. The input datasets need", - " to have the same structure and its fields need to have the dimensions.", - " Try the option names if the number of variables differ.", - " Exit status is 0 if inputs are the same and 1 if they differ.", - "", - "OPERATORS", - " diff Compare two datasets listed by parameter id", - " Provides statistics on differences between two datasets.", - " For each pair of fields the operator prints one line with the following information:", - " - Date and Time", - " - Level, Gridsize and number of Missing values", - " - Number of different values", - " - Occurrence of coefficient pairs with different signs (S)", - " - Occurrence of zero values (Z)", - " - Maxima of absolute difference of coefficient pairs", - " - Maxima of relative difference of non-zero coefficient pairs with equal signs", - " - Parameter identifier", - " diffn Compare two datasets listed by parameter name", - " The same as operator diff. Using the name instead of the", - " identifier to label the parameter.", - "", - "PARAMETER", - " maxcount INTEGER Stop after maxcount different fields", - " abslim FLOAT Limit of the maximum absolute difference (default: 0)", - " rellim FLOAT Limit of the maximum relative difference (default: 1)", - " names STRING Consideration of the variable names of only one input file (left/right) or the intersection of both (intersect).", - " ", - nullptr -}; - -static const char *NinfoHelp[] = { - "NAME", - " npar, nlevel, nyear, nmon, ndate, ntime, ngridpoints, ngrids - ", - " Print the number of parameters, levels or times", - "", - "SYNOPSIS", - " <operator> infile", - "", - "DESCRIPTION", - " This module prints the number of variables, levels or times of the ", - " input dataset.", - "", - "OPERATORS", - " npar Number of parameters", - " Prints the number of parameters (variables).", - " nlevel Number of levels", - " Prints the number of levels for each variable.", - " nyear Number of years", - " Prints the number of different years.", - " nmon Number of months", - " Prints the number of different combinations of years and months.", - " ndate Number of dates", - " Prints the number of different dates.", - " ntime Number of timesteps", - " Prints the number of timesteps.", - " ngridpoints Number of gridpoints", - " Prints the number of gridpoints for each variable.", - " ngrids Number of horizontal grids", - " Prints the number of horizontal grids.", - nullptr -}; - -static const char *ShowinfoHelp[] = { - "NAME", - " showformat, showcode, showname, showstdname, showlevel, showltype, showyear, ", - " showmon, showdate, showtime, showtimestamp - Show variables, levels or times", - "", - "SYNOPSIS", - " <operator> infile", - "", - "DESCRIPTION", - " This module prints the format, variables, levels or times of the input dataset.", - "", - "OPERATORS", - " showformat Show file format", - " Prints the file format of the input dataset.", - " showcode Show code numbers", - " Prints the code number of all variables.", - " showname Show variable names", - " Prints the name of all variables.", - " showstdname Show standard names", - " Prints the standard name of all variables.", - " showlevel Show levels", - " Prints all levels for each variable.", - " showltype Show GRIB level types", - " Prints the GRIB level type for all z-axes.", - " showyear Show years", - " Prints all years.", - " showmon Show months", - " Prints all months.", - " showdate Show date information", - " Prints date information of all timesteps (format YYYY-MM-DD).", - " showtime Show time information", - " Prints time information of all timesteps (format hh:mm:ss).", - " showtimestamp Show timestamp", - " Prints timestamp of all timesteps (format YYYY-MM-DDThh:mm:ss).", - nullptr -}; - -static const char *ShowattributeHelp[] = { - "NAME", - " showattribute - Show attributes", - "", - "SYNOPSIS", - " showattribute[,attributes] infile", - "", - "DESCRIPTION", - " This operator prints the attributes of the data variables of a dataset.", - " ", - " Each attribute has the following structure:", - " ", - " [var_nm@][att_nm]", - " ", - " var_nm Variable name (optional). Example: pressure", - " att_nm Attribute name (optional). Example: units", - " ", - " The value of var_nm is the name of the variable containing the attribute (named att_nm) that", - " you want to print. Use wildcards to print the attribute att_nm of more than one variable.", - " A value of var_nm of '*' will print the attribute att_nm of all data variables.", - " If var_nm is missing then att_nm refers to a global attribute.", - " ", - " The value of att_nm is the name of the attribute you want to print. Use wildcards to print more than", - " one attribute. A value of att_nm of '*' will print all attributes.", - "", - "PARAMETER", - " attributes STRING Comma-separated list of attributes. ", - nullptr -}; - -static const char *FiledesHelp[] = { - "NAME", - " partab, codetab, griddes, zaxisdes, vct - Dataset description", - "", - "SYNOPSIS", - " <operator> infile", - "", - "DESCRIPTION", - " This module provides operators to print meta information about a dataset.", - " The printed meta-data depends on the chosen operator.", - "", - "OPERATORS", - " partab Parameter table", - " Prints all available meta information of the variables.", - " codetab Parameter code table", - " Prints a code table with a description of all variables.", - " For each variable the operator prints one line listing the", - " code, name, description and units.", - " griddes Grid description", - " Prints the description of all grids.", - " zaxisdes Z-axis description", - " Prints the description of all z-axes.", - " vct Vertical coordinate table", - " Prints the vertical coordinate table.", - nullptr -}; - -static const char *ApplyHelp[] = { - "NAME", - " apply - Apply operators", - "", - "SYNOPSIS", - " apply,operators infiles", - "", - "DESCRIPTION", - " The apply utility runs the named operators on each input file. The input files must be enclosed in square brackets.", - " This utility can only be used on a series of input files. These are all operators with more than one input file (infiles).", - " Here is an incomplete list of these operators: copy, cat, merge, mergetime, select, ENSSTAT.", - " The parameter operators is a blank-separated list of CDO operators. Use quotation marks if more than one operator is needed.", - " Each operator may have only one input and output stream.", - "", - "PARAMETER", - " operators STRING Blank-separated list of CDO operators.", - nullptr -}; - -static const char *CopyHelp[] = { - "NAME", - " copy, clone, cat - Copy datasets", - "", - "SYNOPSIS", - " <operator> infiles outfile", - "", - "DESCRIPTION", - " This module contains operators to copy, clone or concatenate datasets.", - " infiles is an arbitrary number of input files. All input files need to have ", - " the same structure with the same variables on different timesteps.", - "", - "OPERATORS", - " copy Copy datasets", - " Copies all input datasets to outfile. ", - " clone Clone datasets", - " Copies all input datasets to outfile. In contrast to the copy operator, clone tries", - " not to change the input data. GRIB records are neither decoded nor decompressed.", - " cat Concatenate datasets", - " Concatenates all input datasets and appends the result to the end ", - " of outfile. If outfile does not exist it will be created.", - nullptr -}; - -static const char *TeeHelp[] = { - "NAME", - " tee - Duplicate a data stream and write it to file", - "", - "SYNOPSIS", - " tee,outfile2 infile outfile1", - "", - "DESCRIPTION", - " This operator copies the input dataset to outfile1 and outfile2. The first output stream", - " in outfile1 can be further processesd with other cdo operators. The second output outfile2", - " is written to disk. It can be used to store intermediate results to a file.", - "", - "PARAMETER", - " outfile2 STRING Destination filename for the copy of the input file", - nullptr -}; - -static const char *PackHelp[] = { - "NAME", - " pack - Pack data", - "", - "SYNOPSIS", - " pack infile outfile", - "", - "DESCRIPTION", - " Packing reduces the data volume by reducing the precision of the stored numbers.", - " It is implemented using the NetCDF attributes add_offset and scale_factor.", - " The operator pack calculates the attributes add_offset and scale_factor for all variables.", - " The default data type for all variables is automatically changed to 16-bit integer.", - " Use the CDO option -b to change the data type to a different integer precision, if needed.", - " Missing values are automatically transformed to the current data type.", - nullptr -}; - -static const char *UnpackHelp[] = { - "NAME", - " unpack - Unpack data", - "", - "SYNOPSIS", - " unpack infile outfile", - "", - "DESCRIPTION", - " Packing reduces the data volume by reducing the precision of the stored numbers.", - " It is implemented using the NetCDF attributes add_offset and scale_factor.", - " The operator unpack unpack all packed variables.", - " The default data type for all variables is automatically changed to 32-bit floats.", - " Use the CDO option -b F64 to change the data type to 64-bit floats, if needed.", - nullptr -}; - -static const char *BitroundingHelp[] = { - "NAME", - " bitrounding - Bit rounding", - "", - "SYNOPSIS", - " bitrounding[,parameter] infile outfile", - "", - "DESCRIPTION", - " This operator calculates for each field the number of necessary mantissa bits to get a certain", - " information level in the data. With this number of significant bits (numbits) a rounding of the data is performed.", - " This allows the data to be compressed to a higher level.", - " ", - " The default value of the information level is 0.9999 and can be adjusted with the parameter inflevel.", - " That means 99.99% of the information in the mantissa bits is preserved.", - " ", - " Alternatively, the number of significant bits can be set for all variables with the numbits parameter.", - " Furthermore, numbits can be assigned for each variable via the filename parameter. In this case, numbits is still", - " calculated for all variables if they are not present in the file.", - " ", - " The analysis of the bit information is based on the Julia library BitInformation.jl (https://github.com/milankl/BitInformation.jl).", - " The procedure to derive the number of significant mantissa bits was adapted from the Python library xbitinfo (https://github.com/observingClouds/xbitinfo).", - " Quantize to the number of mantissa bits is done with IEEE rounding using code from NetCDF 4.9.0.", - " ", - " Currently only 32-bit float data is rounded. Data with missing values are not yet supported for the calculation of significant bits.", - "", - "PARAMETER", - " inflevel FLOAT Information level (0 - 1) [default: 0.9999]", - " addbits INTEGER Add bits to the number of significant bits [default: 0]", - " minbits INTEGER Minimum value of the number of bits [default: 1]", - " maxbits INTEGER Maximum value of the number of bits [default: 23]", - " numsteps INTEGER Set to 1 to run the calculation only in the first time step", - " numbits INTEGER Set number of significant bits", - " printbits BOOL Print max. numbits per variable of 1st timestep to stdout [format: name=numbits]", - " filename STRING Read number of significant bits per variable from file [format: name=numbits]", - nullptr -}; - -static const char *ReplaceHelp[] = { - "NAME", - " replace - Replace variables", - "", - "SYNOPSIS", - " replace infile1 infile2 outfile", - "", - "DESCRIPTION", - " This operator replaces variables in infile1 by variables from infile2 and write", - " the result to outfile. Both input datasets need to have the same number of timesteps.", - " All variable names may only occur once!", - nullptr -}; - -static const char *DuplicateHelp[] = { - "NAME", - " duplicate - Duplicates a dataset", - "", - "SYNOPSIS", - " duplicate[,ndup] infile outfile", - "", - "DESCRIPTION", - " This operator duplicates the contents of infile and writes the result to outfile.", - " The optional parameter sets the number of duplicates, the default is 2.", - "", - "PARAMETER", - " ndup INTEGER Number of duplicates, default is 2.", - nullptr -}; - -static const char *MergegridHelp[] = { - "NAME", - " mergegrid - Merge grid", - "", - "SYNOPSIS", - " mergegrid infile1 infile2 outfile", - "", - "DESCRIPTION", - " Merges grid points of all variables from infile2 to infile1 and write the result to outfile.", - " Only the non missing values of infile2 will be used. The horizontal grid of infile2 should ", - " be smaller or equal to the grid of infile1 and the resolution must be the same.", - " Only rectilinear grids are supported. Both input files need to have the same variables ", - " and the same number of timesteps.", - nullptr -}; - -static const char *MergeHelp[] = { - "NAME", - " merge, mergetime - Merge datasets", - "", - "SYNOPSIS", - " <operator> infiles outfile", - "", - "DESCRIPTION", - " This module reads datasets from several input files, merges them and writes the resulting dataset to outfile.", - "", - "OPERATORS", - " merge Merge datasets with different fields", - " Merges time series of different fields from several input datasets. The number ", - " of fields per timestep written to outfile is the sum of the field numbers ", - " per timestep in all input datasets. The time series on all input datasets are ", - " required to have different fields and the same number of timesteps.", - " The fields in each different input file either have to be different variables", - " or different levels of the same variable. A mixture of different variables on", - " different levels in different input files is not allowed.", - " mergetime Merge datasets sorted by date and time", - " Merges all timesteps of all input files sorted by date and time.", - " All input files need to have the same structure with the same variables on ", - " different timesteps. After this operation every input timestep is in outfile ", - " and all timesteps are sorted by date and time.", - "", - "ENVIRONMENT", - " SKIP_SAME_TIME", - " If set to 1, skips all consecutive timesteps with a double entry of the same timestamp.", - "", - "NOTE", - " Operators of this module need to open all input files simultaneously.", - " The maximum number of open files depends on the operating system!", - nullptr -}; - -static const char *SplitHelp[] = { - "NAME", - " splitcode, splitparam, splitname, splitlevel, splitgrid, splitzaxis, ", - " splittabnum - Split a dataset", - "", - "SYNOPSIS", - " <operator>[,parameter] infile obase", - "", - "DESCRIPTION", - " This module splits infile into pieces. The output files will be named <obase><xxx><suffix>", - " where suffix is the filename extension derived from the file format. xxx and the contents ", - " of the output files depends on the chosen operator. ", - " params is a comma-separated list of processing parameters.", - "", - "OPERATORS", - " splitcode Split code numbers", - " Splits a dataset into pieces, one for each different code number.", - " xxx will have three digits with the code number.", - " splitparam Split parameter identifiers", - " Splits a dataset into pieces, one for each different parameter identifier.", - " xxx will be a string with the parameter identifier.", - " splitname Split variable names", - " Splits a dataset into pieces, one for each variable name.", - " xxx will be a string with the variable name.", - " splitlevel Split levels", - " Splits a dataset into pieces, one for each different level.", - " xxx will have six digits with the level.", - " splitgrid Split grids", - " Splits a dataset into pieces, one for each different grid.", - " xxx will have two digits with the grid number.", - " splitzaxis Split z-axes", - " Splits a dataset into pieces, one for each different z-axis.", - " xxx will have two digits with the z-axis number.", - " splittabnum Split parameter table numbers", - " Splits a dataset into pieces, one for each GRIB1 parameter table number.", - " xxx will have three digits with the GRIB1 parameter table number.", - "", - "PARAMETER", - " swap STRING Swap the position of obase and xxx in the output filename", - " uuid=<attname> STRING Add a UUID as global attribute <attname> to each output file", - "", - "ENVIRONMENT", - " CDO_FILE_SUFFIX", - " Set the default file suffix. This suffix will be added to the output file ", - " names instead of the filename extension derived from the file format. ", - " Set this variable to NULL to disable the adding of a file suffix.", - "", - "NOTE", - " Operators of this module need to open all output files simultaneously.", - " The maximum number of open files depends on the operating system!", - nullptr -}; - -static const char *SplittimeHelp[] = { - "NAME", - " splithour, splitday, splitseas, splityear, splityearmon, splitmon - ", - " Split timesteps of a dataset", - "", - "SYNOPSIS", - " <operator> infile obase", - " splitmon[,format] infile obase", - "", - "DESCRIPTION", - " This module splits infile into timesteps pieces. The output files will be named", - " <obase><xxx><suffix> where suffix is the filename extension derived from the file format. ", - " xxx and the contents of the output files depends on the chosen operator. ", - "", - "OPERATORS", - " splithour Split hours", - " Splits a file into pieces, one for each different hour.", - " xxx will have two digits with the hour.", - " splitday Split days", - " Splits a file into pieces, one for each different day.", - " xxx will have two digits with the day.", - " splitseas Split seasons", - " Splits a file into pieces, one for each different season.", - " xxx will have three characters with the season.", - " splityear Split years", - " Splits a file into pieces, one for each different year.", - " xxx will have four digits with the year (YYYY).", - " splityearmon Split in years and months", - " Splits a file into pieces, one for each different year and month.", - " xxx will have six digits with the year and month (YYYYMM).", - " splitmon Split months", - " Splits a file into pieces, one for each different month.", - " xxx will have two digits with the month.", - "", - "PARAMETER", - " format STRING C-style format for strftime() (e.g. %B for the full month name)", - "", - "ENVIRONMENT", - " CDO_FILE_SUFFIX", - " Set the default file suffix. This suffix will be added to the output file ", - " names instead of the filename extension derived from the file format. ", - " Set this variable to NULL to disable the adding of a file suffix.", - "", - "NOTE", - " Operators of this module need to open all output files simultaneously.", - " The maximum number of open files depends on the operating system!", - nullptr -}; - -static const char *SplitselHelp[] = { - "NAME", - " splitsel - Split selected timesteps", - "", - "SYNOPSIS", - " splitsel,nsets[,noffset[,nskip]] infile obase", - "", - "DESCRIPTION", - " This operator splits infile into pieces, one for each adjacent", - " sequence t_1, ...., t_n of timesteps of the same selected time range.", - " The output files will be named <obase><nnnnnn><suffix> where nnnnnn is the ", - " sequence number and suffix is the filename extension derived from the file format.", - "", - "PARAMETER", - " nsets INTEGER Number of input timesteps for each output file", - " noffset INTEGER Number of input timesteps skipped before the first timestep range (optional)", - " nskip INTEGER Number of input timesteps skipped between timestep ranges (optional)", - "", - "ENVIRONMENT", - " CDO_FILE_SUFFIX", - " Set the default file suffix. This suffix will be added to the output file ", - " names instead of the filename extension derived from the file format. ", - " Set this variable to NULL to disable the adding of a file suffix.", - nullptr -}; - -static const char *SplitdateHelp[] = { - "NAME", - " splitdate - Splits a file into dates", - "", - "SYNOPSIS", - " splitdate infile obase", - "", - "DESCRIPTION", - " This operator splits infile into pieces, one for each different date.", - " The output files will be named <obase><YYYY-MM-DD><suffix> where YYYY-MM-DD is the ", - " date and suffix is the filename extension derived from the file format.", - "", - "ENVIRONMENT", - " CDO_FILE_SUFFIX", - " Set the default file suffix. This suffix will be added to the output file ", - " names instead of the filename extension derived from the file format. ", - " Set this variable to NULL to disable the adding of a file suffix.", - nullptr -}; - -static const char *DistgridHelp[] = { - "NAME", - " distgrid - Distribute horizontal grid", - "", - "SYNOPSIS", - " distgrid,nx[,ny] infile obase", - "", - "DESCRIPTION", - " This operator distributes a dataset into smaller pieces. Each output file contains a different region of the", - " horizontal source grid. 2D Lon/Lat grids can be split into nx*ny pieces, where a target grid region contains", - " a structured longitude/latitude box of the source grid. Data on an unstructured grid is split into nx pieces.", - " The output files will be named <obase><xxx><suffix> where suffix is the filename extension derived from the", - " file format. xxx will have five digits with the number of the target region.", - "", - "PARAMETER", - " nx INTEGER Number of regions in x direction, or number of pieces for unstructured grids", - " ny INTEGER Number of regions in y direction [default: 1]", - "", - "NOTE", - " This operator needs to open all output files simultaneously.", - " The maximum number of open files depends on the operating system!", - nullptr -}; - -static const char *CollgridHelp[] = { - "NAME", - " collgrid - Collect horizontal grid", - "", - "SYNOPSIS", - " collgrid[,nx[,names]] infiles outfile", - "", - "DESCRIPTION", - " This operator collects the data of the input files to one output file. All input files need", - " to have the same variables and the same number of timesteps on a different horizonal grid region.", - " If the source regions are on a structured lon/lat grid, all regions together must result in a", - " new structured lat/long grid box. Data on an unstructured grid is concatenated in the order of", - " the input files. The parameter nx needs to be specified only for curvilinear grids.", - "", - "PARAMETER", - " nx INTEGER Number of regions in x direction [default: number of input files]", - " names STRING Comma-separated list of variable names [default: all variables]", - "", - "NOTE", - " This operator needs to open all input files simultaneously.", - " The maximum number of open files depends on the operating system!", - nullptr -}; - -static const char *SelectHelp[] = { - "NAME", - " select, delete - Select fields", - "", - "SYNOPSIS", - " <operator>,parameter infiles outfile", - "", - "DESCRIPTION", - " This module selects some fields from infiles and writes them to outfile.", - " infiles is an arbitrary number of input files. All input files need to have ", - " the same structure with the same variables on different timesteps.", - " The fields selected depends on the chosen parameters. Parameter is a comma-separated list", - " of \"key=value\" pairs. A range of integer values can be specified by first/last[/inc].", - " Wildcards are supported for string values.", - "", - "OPERATORS", - " select Select fields", - " Selects all fields with parameters in a user given list.", - " delete Delete fields", - " Deletes all fields with parameters in a user given list.", - "", - "PARAMETER", - " name STRING Comma-separated list of variable names.", - " param STRING Comma-separated list of parameter identifiers.", - " code INTEGER Comma-separated list or first/last[/inc] range of code numbers.", - " level FLOAT Comma-separated list of vertical levels.", - " levrange FLOAT First and last value of the level range.", - " levidx INTEGER Comma-separated list or first/last[/inc] range of index of levels.", - " zaxisname STRING Comma-separated list of zaxis names.", - " zaxisnum INTEGER Comma-separated list or first/last[/inc] range of zaxis numbers.", - " ltype INTEGER Comma-separated list or first/last[/inc] range of GRIB level types.", - " gridname STRING Comma-separated list of grid names.", - " gridnum INTEGER Comma-separated list or first/last[/inc] range of grid numbers.", - " steptype STRING Comma-separated list of timestep types (constant, avg, accum, min, max, range, diff, sum)", - " date STRING Comma-separated list of dates (format YYYY-MM-DDThh:mm:ss).", - " startdate STRING Start date (format YYYY-MM-DDThh:mm:ss).", - " enddate STRING End date (format YYYY-MM-DDThh:mm:ss).", - " minute INTEGER Comma-separated list or first/last[/inc] range of minutes.", - " hour INTEGER Comma-separated list or first/last[/inc] range of hours.", - " day INTEGER Comma-separated list or first/last[/inc] range of days.", - " month INTEGER Comma-separated list or first/last[/inc] range of months.", - " season STRING Comma-separated list of seasons (substring of DJFMAMJJASOND or ANN).", - " year INTEGER Comma-separated list or first/last[/inc] range of years.", - " dom STRING Comma-separated list of the day of month (e.g. 29feb).", - " timestep INTEGER Comma-separated list or first/last[/inc] range of timesteps. Negative values select timesteps from the end (NetCDF only).", - " timestep_of_year INTEGER Comma-separated list or first/last[/inc] range of timesteps of year.", - " timestepmask STRING Read timesteps from a mask file.", - nullptr -}; - -static const char *SelmultiHelp[] = { - "NAME", - " selmulti, delmulti, changemulti - Select multiple fields via GRIB1 parameters", - "", - "SYNOPSIS", - " <operator>,selection-specification infile outfile", - "", - "DESCRIPTION", - " This module selects multiple fields from infile and writes them to outfile.", - " selection-specification is a filename or in-place string with the selection specification.", - " Each selection-specification has the following compact notation format: ", - " ", - " <type>(parameters; leveltype(s); levels)", - " ", - " type " " sel for select or del for delete (optional)", - " parameters" " GRIB1 parameter code number", - " leveltype " " GRIB1 level type", - " levels " " value of each level", - " ", - " Examples:", - " ", - " (1; 103; 0) ", - " (33,34; 105; 10) ", - " (11,17; 105; 2) ", - " (71,73,74,75,61,62,65,117,67,122,121,11,131,66,84,111,112; 105; 0) ", - " ", - " The following descriptive notation can also be used for selection specification from a file:", - " ", - " SELECT/DELETE, PARAMETER=parameters, LEVTYPE=leveltye(s), LEVEL=levels", - " ", - " Examples:", - " ", - " SELECT, PARAMETER=1, LEVTYPE=103, LEVEL=0 ", - " SELECT, PARAMETER=33/34, LEVTYPE=105, LEVEL=10 ", - " SELECT, PARAMETER=11/17, LEVTYPE=105, LEVEL=2 ", - " SELECT, PARAMETER=71/73/74/75/61/62/65/117/67/122, LEVTYPE=105, LEVEL=0 ", - " DELETE, PARAMETER=128, LEVTYPE=109, LEVEL=* ", - " ", - " The following will convert Pressure from Pa into hPa; Temp from Kelvin to Celsius: ", - " SELECT, PARAMETER=1, LEVTYPE= 103, LEVEL=0, SCALE=0.01 ", - " SELECT, PARAMETER=11, LEVTYPE=105, LEVEL=2, OFFSET=273.15 ", - " If SCALE and/or OFFSET are defined, then the data values are scaled as SCALE*(VALUE-OFFSET).", - "", - "OPERATORS", - " selmulti Select multiple fields", - " delmulti Delete multiple fields", - " changemulti Change identication of multiple fields", - nullptr -}; - -static const char *SelvarHelp[] = { - "NAME", - " selparam, delparam, selcode, delcode, selname, delname, selstdname, sellevel, ", - " sellevidx, selgrid, selzaxis, selzaxisname, selltype, seltabnum - Select fields", - "", - "SYNOPSIS", - " <operator>,parameter infile outfile", - " selcode,codes infile outfile", - " delcode,codes infile outfile", - " selname,names infile outfile", - " delname,names infile outfile", - " selstdname,stdnames infile outfile", - " sellevel,levels infile outfile", - " sellevidx,levidx infile outfile", - " selgrid,grids infile outfile", - " selzaxis,zaxes infile outfile", - " selzaxisname,zaxisnames infile outfile", - " selltype,ltypes infile outfile", - " seltabnum,tabnums infile outfile", - "", - "DESCRIPTION", - " This module selects some fields from infile and writes them to outfile.", - " The fields selected depends on the chosen operator and the parameters. A range of integer", - " values can be specified by first/last[/inc].", - "", - "OPERATORS", - " selparam Select parameters by identifier", - " Selects all fields with parameter identifiers in a user given list.", - " delparam Delete parameters by identifier", - " Deletes all fields with parameter identifiers in a user given list.", - " selcode Select parameters by code number", - " Selects all fields with code numbers in a user given list or range.", - " delcode Delete parameters by code number", - " Deletes all fields with code numbers in a user given list or range.", - " selname Select parameters by name", - " Selects all fields with parameter names in a user given list.", - " delname Delete parameters by name", - " Deletes all fields with parameter names in a user given list.", - " selstdname Select parameters by standard name", - " Selects all fields with standard names in a user given list.", - " sellevel Select levels", - " Selects all fields with levels in a user given list.", - " sellevidx Select levels by index", - " Selects all fields with index of levels in a user given list or range.", - " selgrid Select grids", - " Selects all fields with grids in a user given list.", - " selzaxis Select z-axes", - " Selects all fields with z-axes in a user given list.", - " selzaxisname Select z-axes by name", - " Selects all fields with z-axis names in a user given list.", - " selltype Select GRIB level types", - " Selects all fields with GRIB level type in a user given list or range.", - " seltabnum Select parameter table numbers", - " Selects all fields with parameter table numbers in a user given list or range.", - "", - "PARAMETER", - " parameter STRING Comma-separated list of parameter identifiers.", - " codes INTEGER Comma-separated list or first/last[/inc] range of code numbers.", - " names STRING Comma-separated list of variable names.", - " stdnames STRING Comma-separated list of standard names.", - " levels FLOAT Comma-separated list of vertical levels.", - " levidx INTEGER Comma-separated list or first/last[/inc] range of index of levels.", - " ltypes INTEGER Comma-separated list or first/last[/inc] range of GRIB level types.", - " grids STRING Comma-separated list of grid names or numbers.", - " zaxes STRING Comma-separated list of z-axis types or numbers.", - " zaxisnames STRING Comma-separated list of z-axis names.", - " tabnums INTEGER Comma-separated list or range of parameter table numbers.", - nullptr -}; - -static const char *SeltimeHelp[] = { - "NAME", - " seltimestep, seltime, selhour, selday, selmonth, selyear, selseason, seldate, ", - " selsmon - Select timesteps", - "", - "SYNOPSIS", - " seltimestep,timesteps infile outfile", - " seltime,times infile outfile", - " selhour,hours infile outfile", - " selday,days infile outfile", - " selmonth,months infile outfile", - " selyear,years infile outfile", - " selseason,seasons infile outfile", - " seldate,startdate[,enddate] infile outfile", - " selsmon,month[,nts1[,nts2]] infile outfile", - "", - "DESCRIPTION", - " This module selects user specified timesteps from infile and writes them to outfile.", - " The timesteps selected depends on the chosen operator and the parameters. A range of integer values", - " can be specified by first/last[/inc].", - "", - "OPERATORS", - " seltimestep Select timesteps", - " Selects all timesteps with a timestep in a user given list or range.", - " seltime Select times", - " Selects all timesteps with a time in a user given list or range.", - " selhour Select hours", - " Selects all timesteps with a hour in a user given list or range.", - " selday Select days", - " Selects all timesteps with a day in a user given list or range.", - " selmonth Select months", - " Selects all timesteps with a month in a user given list or range.", - " selyear Select years", - " Selects all timesteps with a year in a user given list or range.", - " selseason Select seasons", - " Selects all timesteps with a month of a season in a user given list.", - " seldate Select dates", - " Selects all timesteps with a date in a user given range.", - " selsmon Select single month", - " Selects a month and optional an arbitrary number of timesteps before and after this month.", - "", - "PARAMETER", - " timesteps INTEGER Comma-separated list or first/last[/inc] range of timesteps. Negative values select timesteps from the end (NetCDF only).", - " times STRING Comma-separated list of times (format hh:mm:ss).", - " hours INTEGER Comma-separated list or first/last[/inc] range of hours.", - " days INTEGER Comma-separated list or first/last[/inc] range of days.", - " months INTEGER Comma-separated list or first/last[/inc] range of months.", - " years INTEGER Comma-separated list or first/last[/inc] range of years.", - " seasons STRING Comma-separated list of seasons (substring of DJFMAMJJASOND or ANN).", - " startdate STRING Start date (format YYYY-MM-DDThh:mm:ss).", - " enddate STRING End date (format YYYY-MM-DDThh:mm:ss) [default: startdate].", - " nts1 INTEGER Number of timesteps before the selected month [default: 0].", - " nts2 INTEGER Number of timesteps after the selected month [default: nts1].", - nullptr -}; - -static const char *SelboxHelp[] = { - "NAME", - " sellonlatbox, selindexbox - Select a box", - "", - "SYNOPSIS", - " sellonlatbox,lon1,lon2,lat1,lat2 infile outfile", - " selindexbox,idx1,idx2,idy1,idy2 infile outfile", - "", - "DESCRIPTION", - " Selects grid cells inside a lon/lat or index box.", - "", - "OPERATORS", - " sellonlatbox Select a longitude/latitude box", - " Selects grid cells inside a lon/lat box. The user must specify the longitude and latitude of the edges of the box.", - " Only those grid cells are considered whose grid center lies within the lon/lat box.", - " For rotated lon/lat grids the parameters must be specified in rotated coordinates.", - " selindexbox Select an index box", - " Selects grid cells within an index box. The user must specify the indices of the edges of the box.", - " The index of the left edge can be greater then the one of the right edge. Use negative indexing to", - " start from the end. The input grid must be a regular lon/lat or a 2D curvilinear grid.", - "", - "PARAMETER", - " lon1 FLOAT Western longitude in degrees", - " lon2 FLOAT Eastern longitude in degrees", - " lat1 FLOAT Southern or northern latitude in degrees", - " lat2 FLOAT Northern or southern latitude in degrees", - " idx1 INTEGER Index of first longitude (1 - nlon)", - " idx2 INTEGER Index of last longitude (1 - nlon)", - " idy1 INTEGER Index of first latitude (1 - nlat)", - " idy2 INTEGER Index of last latitude (1 - nlat)", - nullptr -}; - -static const char *SelregionHelp[] = { - "NAME", - " selregion, selcircle - Select horizontal regions", - "", - "SYNOPSIS", - " selregion,regions infile outfile", - " selcircle[,parameter] infile outfile", - "", - "DESCRIPTION", - " Selects all grid cells with the center point inside user defined regions or a circle.", - " The resulting grid is unstructured.", - "", - "OPERATORS", - " selregion Select cells inside regions", - " Selects all grid cells with the center point inside the regions.", - " Regions can be defined by the user via an ASCII file.", - " Each region consists of the geographic coordinates of a convex polygon.", - " Each line of a polygon description file contains the longitude and latitude of one point.", - " Each polygon description file can contain one or more polygons separated by a line with the character \\&.", - " ", - " Predefined regions of countries can be specified via the country codes.", - " A country is specified with dcw:<CountryCode>. Country codes can be combined with the plus sign.", - " selcircle Select cells inside a circle", - " Selects all grid cells with the center point inside a circle. The circle is described by geographic coordinates", - " of the center and the radius of the circle.", - "", - "PARAMETER", - " regions STRING Comma-separated list of ASCII formatted files with different regions", - " lon FLOAT Longitude of the center of the circle in degrees, default lon=0.0", - " lat FLOAT Latitude of the center of the circle in degrees, default lat=0.0", - " radius STRING Radius of the circle, default radius=1deg (units: deg, rad, km, m)", - nullptr -}; - -static const char *SelgridcellHelp[] = { - "NAME", - " selgridcell, delgridcell - Select grid cells", - "", - "SYNOPSIS", - " <operator>,indices infile outfile", - "", - "DESCRIPTION", - " The operator selects grid cells of all fields from infile. The user must specify the index of each grid cell.", - " The resulting grid in outfile is unstructured.", - "", - "OPERATORS", - " selgridcell Select grid cells", - " delgridcell Delete grid cells", - "", - "PARAMETER", - " indices INTEGER Comma-separated list or first/last[/inc] range of indices", - nullptr -}; - -static const char *SamplegridHelp[] = { - "NAME", - " samplegrid - Resample grid", - "", - "SYNOPSIS", - " samplegrid,factor infile outfile", - "", - "DESCRIPTION", - " This is a special operator for resampling the horizontal grid.", - " No interpolation takes place. Resample factor=2 means every second grid point is removed.", - " Only rectilinear and curvilinear source grids are supported by this operator.", - "", - "PARAMETER", - " factor INTEGER Resample factor, typically 2, which will half the resolution", - nullptr -}; - -static const char *SelyearidxHelp[] = { - "NAME", - " selyearidx - Select year by index", - "", - "SYNOPSIS", - " selyearidx infile1 infile2 outfile", - "", - "DESCRIPTION", - " Selects field elements from infile2 by a yearly time index from infile1.", - " The yearly indices in infile1 should be the result of corresponding yearminidx and yearmaxidx operations, respectively.", - nullptr -}; - -static const char *SelsurfaceHelp[] = { - "NAME", - " bottomvalue, topvalue, isosurface - Extract surface", - "", - "SYNOPSIS", - " <operator> infile outfile", - " isosurface,isovalue infile outfile", - "", - "DESCRIPTION", - " This module computes a surface from all 3D variables. The result is a horizonal 2D field.", - "", - "OPERATORS", - " bottomvalue Extract bottom level", - " This operator selects the valid values at the bottom level.", - " The NetCDF CF compliant attribute positive is used to determine where top and bottom are.", - " If this attribute is missing, low values are bottom and high values are top.", - " topvalue Extract top level", - " This operator selects the valid values at the top level.", - " The NetCDF CF compliant attribute positive is used to determine where top and bottom are.", - " If this attribute is missing, low values are bottom and high values are top.", - " isosurface Extract isosurface", - " This operator computes an isosurface. The value of the isosurfce is specified by the parameter isovalue.", - " The isosurface is calculated by linear interpolation between two layers.", - "", - "PARAMETER", - " isovalue FLOAT Isosurface value", - nullptr -}; - -static const char *CondHelp[] = { - "NAME", - " ifthen, ifnotthen - Conditional select one field", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module selects field elements from infile2 with respect to infile1 and writes them ", - " to outfile. The fields in infile1 are handled as a mask. A value ", - " not equal to zero is treated as \"true\", zero is treated as \"false\".", - " The number of fields in infile1 has either to be the same as in infile2 or the", - " same as in one timestep of infile2 or only one.", - " The fields in outfile inherit the meta data from infile2.", - "", - "OPERATORS", - " ifthen If then", - " / i_2(t,x) if i_1(t,x) NE 0 AND i_1(t,x) NE miss", - " o(t,x) =", - " \\ miss if i_1(t,x) EQ 0 OR i_1(t,x) EQ miss", - " ifnotthen If not then", - " / i_2(t,x) if i_1(t,x) EQ 0 AND i_1(t,x) NE miss", - " o(t,x) = ", - " \\ miss if i_1(t,x) NE 0 OR i_1(t,x) EQ miss", - nullptr -}; - -static const char *Cond2Help[] = { - "NAME", - " ifthenelse - Conditional select two fields", - "", - "SYNOPSIS", - " ifthenelse infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator selects field elements from infile2 or infile3 with respect to", - " infile1 and writes them to outfile. The fields in infile1 are handled as a mask.", - " A value not equal to zero is treated as \"true\", zero is treated as \"false\".", - " The number of fields in infile1 has either to be the same as in infile2 or the ", - " same as in one timestep of infile2 or only one.", - " infile2 and infile3 need to have the same number of fields.", - " The fields in outfile inherit the meta data from infile2.", - " ", - " / i_2(t,x) if i_1(t,x) NE 0 AND i_1(t,x) NE miss", - " o(t,x) = < i_3(t,x) if i_1(t,x) EQ 0 AND i_1[t,x) NE miss", - " \\ miss if i_1(t,x) EQ miss", - nullptr -}; - -static const char *CondcHelp[] = { - "NAME", - " ifthenc, ifnotthenc - Conditional select a constant", - "", - "SYNOPSIS", - " <operator>,c infile outfile", - "", - "DESCRIPTION", - " This module creates fields with a constant value or missing value.", - " The fields in infile are handled as a mask. A value not equal ", - " to zero is treated as \"true\", zero is treated as \"false\".", - "", - "OPERATORS", - " ifthenc If then constant", - " / c if i(t,x) NE 0 AND i(t,x) NE miss", - " o(t,x) =", - " \\ miss if i(t,x) EQ 0 OR i(t,x) EQ miss", - " ifnotthenc If not then constant", - " / c if i(t,x) EQ 0 AND i(t,x) NE miss", - " o(t,x) =", - " \\ miss if i(t,x) NE 0 OR i(t,x) EQ miss", - "", - "PARAMETER", - " c FLOAT Constant", - nullptr -}; - -static const char *MapReduceHelp[] = { - "NAME", - " reducegrid - Reduce fields to user-defined mask", - "", - "SYNOPSIS", - " reducegrid,mask[,limitCoordsOutput] infile outfile", - "", - "DESCRIPTION", - " This module holds an operator for data reduction based on a user defined mask.", - " The output grid is unstructured and includes coordinate bounds. Bounds can be", - " avoided by using the additional 'nobounds' keyword. With 'nocoords' given,", - " coordinates a completely suppressed.", - "", - "PARAMETER", - " mask STRING file which holds the mask field", - " limitCoordsOutput STRING optional parameter to limit coordinates output: 'nobounds' disables coordinate bounds, 'nocoords' avoids all coordinate information", - nullptr -}; - -static const char *CompHelp[] = { - "NAME", - " eq, ne, le, lt, ge, gt - Comparison of two fields", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module compares two datasets field by field.", - " The resulting field is a mask containing 1 if the comparison is true and 0 if not.", - " The number of fields in infile1 should be the same as in infile2.", - " One of the input files can contain only one timestep or one field.", - " The fields in outfile inherit the meta data from infile1 or infile2.", - " The type of comparison depends on the chosen operator.", - "", - "OPERATORS", - " eq Equal", - " / 1 if i_1(t,x) EQ i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " o(t,x) = < 0 if i_1(t,x) NE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", - " ne Not equal", - " / 1 if i_1(t,x) NE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " o(t,x) = < 0 if i_1(t,x) EQ i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", - " le Less equal", - " / 1 if i_1(t,x) LE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " o(t,x) = < 0 if i_1(t,x) GT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", - " lt Less than", - " / 1 if i_1(t,x) LT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " o(t,x) = < 0 if i_1(t,x) GE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", - " ge Greater equal", - " / 1 if i_1(t,x) GE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " o(t,x) = < 0 if i_1(t,x) LT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", - " gt Greater than", - " / 1 if i_1(t,x) GT i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " o(t,x) = < 0 if i_1(t,x) LE i_2(t,x) AND i_1(t,x),i_2(t,x) NE miss", - " \\ miss if i_1(t,x) EQ miss OR i_2(t,x) EQ miss", - nullptr -}; - -static const char *CompcHelp[] = { - "NAME", - " eqc, nec, lec, ltc, gec, gtc - Comparison of a field with a constant", - "", - "SYNOPSIS", - " <operator>,c infile outfile", - "", - "DESCRIPTION", - " This module compares all fields of a dataset with a constant. The resulting", - " field is a mask containing 1 if the comparison is true and 0 if not.", - " The type of comparison depends on the chosen operator.", - "", - "OPERATORS", - " eqc Equal constant", - " / 1 if i(t,x) EQ c AND i(t,x),c NE miss", - " o(t,x) = < 0 if i(t,x) NE c AND i(t,x),c NE miss", - " \\ miss if i(t,x) EQ miss OR c EQ miss", - " nec Not equal constant", - " / 1 if i(t,x) NE c AND i(t,x),c NE miss", - " o(t,x) = < 0 if i(t,x) EQ c AND i(t,x),c NE miss", - " \\ miss if i(t,x) EQ miss OR c EQ miss", - " lec Less equal constant", - " / 1 if i(t,x) LE c AND i(t,x),c NE miss", - " o(t,x) = < 0 if i(t,x) GT c AND i(t,x),c NE miss", - " \\ miss if i(t,x) EQ miss OR c EQ miss", - " ltc Less than constant", - " / 1 if i(t,x) LT c AND i(t,x),c NE miss", - " o(t,x) = < 0 if i(t,x) GE c AND i(t,x),c NE miss", - " \\ miss if i(t,x) EQ miss OR c EQ miss", - " gec Greater equal constant", - " / 1 if i(t,x) GE c AND i(t,x),c NE miss", - " o(t,x) = < 0 if i(t,x) LT c AND i(t,x),c NE miss", - " \\ miss if i(t,x) EQ miss OR c EQ miss", - " gtc Greater than constant", - " / 1 if i(t,x) GT c AND i(t,x),c NE miss", - " o(t,x) = < 0 if i(t,x) LE c AND i(t,x),c NE miss", - " \\ miss if i(t,x) EQ miss OR c EQ miss", - "", - "PARAMETER", - " c FLOAT Constant", - nullptr -}; - -static const char *YmoncompHelp[] = { - "NAME", - " ymoneq, ymonne, ymonle, ymonlt, ymonge, ymongt - Multi-year monthly comparison", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs compaisons of a time series and one timestep with the same month of year.", - " For each field in infile1 the corresponding field of the timestep in infile2 with the same month of year is used.", - " The resulting field is a mask containing 1 if the comparison is true and 0 if not. ", - " The type of comparison depends on the chosen operator.", - " The input files need to have the same structure with the same variables.", - " Usually infile2 is generated by an operator of the module YMONSTAT.", - "", - "OPERATORS", - " ymoneq Compare time series with Equal", - " Compares whether a time series is equal to a multi-year monthly time series.", - " ymonne Compare time series with NotEqual", - " Compares whether a time series is not equal to a multi-year monthly time series.", - " ymonle Compare time series with LessEqual", - " Compares whether a time series is less than or equal to a multi-year monthly time series.", - " ymonlt Compares if time series with LessThan", - " Compares whether a time series is less than a multi-year monthly time series.", - " ymonge Compares if time series with GreaterEqual", - " Compares whether a time series is greater than or equal to a multi-year monthly time series.", - " ymongt Compares if time series with GreaterThan", - " Compares whether a time series is greater than a multi-year monthly time series.", - nullptr -}; - -static const char *SetattributeHelp[] = { - "NAME", - " setattribute - Set attributes", - "", - "SYNOPSIS", - " setattribute,attributes infile outfile", - "", - "DESCRIPTION", - " This operator sets attributes of a dataset and writes the result to outfile.", - " The new attributes are only available in outfile if the file format supports attributes.", - " ", - " Each attribute has the following structure:", - " ", - " [var_nm@]att_nm[:{s|d|i}]=[att_val|{[var_nm@]att_nm}]", - " ", - " var_nm Variable name (optional). Example: pressure", - " att_nm Attribute name. Example: units", - " att_val Comma-separated list of attribute values. Example: pascal", - " ", - " The value of var_nm is the name of the variable containing the attribute (named att_nm) that", - " you want to set. Use wildcards to set the attribute att_nm to more than one variable.", - " A value of var_nm of '*' will set the attribute att_nm to all data variables.", - " If var_nm is missing then att_nm refers to a global attribute.", - " ", - " The value of att_nm is the name of the attribute you want to set. For each attribute a string (att_nm:s),", - " a double (att_nm:d) or an integer (att_nm:i) type can be defined. By default the native type is set.", - " ", - " The value of att_val is the contents of the attribute att_nm. att_val may be a single value", - " or one-dimensional array of elements. The type and the number of elements of an attribute will be detected", - " automatically from the contents of the values. An already existing attribute att_nm will be overwritten", - " or it will be removed if att_val is omitted. Alternatively, the values of an existing attribute can be copied.", - " This attribute must then be enclosed in curly brackets.", - " ", - " A special meaning has the attribute name FILE. If this is the 1st attribute then all attributes", - " are read from a file specified in the value of att_val.", - "", - "PARAMETER", - " attributes STRING Comma-separated list of attributes. ", - "", - "NOTE", - " Attributes are evaluated by CDO when opening infile. Therefor the result of this operator is not available", - " for other operators when this operator is used in chaining operators.", - nullptr -}; - -static const char *SetpartabHelp[] = { - "NAME", - " setpartabp, setpartabn - Set parameter table", - "", - "SYNOPSIS", - " <operator>,table[,convert] infile outfile", - "", - "DESCRIPTION", - " This module transforms data and metadata of infile via a parameter table and writes the result to outfile.", - " A parameter table is an ASCII formatted file with a set of parameter entries for each variable. Each new set have to", - " start with \"\\¶meter\" and to end with \"/\".", - " ", - " The following parameter table entries are supported:", - " ", - " Entry & Type & Description ", - " name & WORD & Name of the variable", - " out_name & WORD & New name of the variable", - " param & WORD & Parameter identifier (GRIB1: code[.tabnum]; GRIB2: num[.cat[.dis]])", - " out_param & WORD & New parameter identifier", - " type & WORD & Data type (real or double)", - " standard_name & WORD & As defined in the CF standard name table", - " long_name & STRING & Describing the variable", - " units & STRING & Specifying the units for the variable", - " comment & STRING & Information concerning the variable", - " cell_methods & STRING & Information concerning calculation of means or climatologies", - " cell_measures & STRING & Indicates the names of the variables containing cell areas and volumes", - " missing_value & FLOAT & Specifying how missing data will be identified", - " valid_min & FLOAT & Minimum valid value", - " valid_max & FLOAT & Maximum valid value", - " ok_min_mean_abs & FLOAT & Minimum absolute mean", - " ok_max_mean_abs & FLOAT & Maximum absolute mean", - " factor & FLOAT & Scale factor", - " delete & INTEGER & Set to 1 to delete variable", - " convert & INTEGER & Set to 1 to convert the unit if necessary", - " ", - " Unsupported parameter table entries are stored as variable attributes.", - " The search key for the variable depends on the operator. Use setpartabn to search variables by the name.", - " This is typically used for NetCDF datasets. The operator setpartabp searches variables by the parameter ID.", - "", - "OPERATORS", - " setpartabp Set parameter table", - " Search variables by the parameter identifier.", - " setpartabn Set parameter table", - " Search variables by name.", - "", - "PARAMETER", - " table STRING Parameter table file or name", - " convert STRING Converts the units if necessary", - nullptr -}; - -static const char *SetHelp[] = { - "NAME", - " setcodetab, setcode, setparam, setname, setunit, setlevel, setltype, ", - " setmaxsteps - Set field info", - "", - "SYNOPSIS", - " setcodetab,table infile outfile", - " setcode,code infile outfile", - " setparam,param infile outfile", - " setname,name infile outfile", - " setunit,unit infile outfile", - " setlevel,level infile outfile", - " setltype,ltype infile outfile", - " setmaxsteps,maxsteps infile outfile", - "", - "DESCRIPTION", - " This module sets some field information. Depending on the chosen operator the ", - " parameter table, code number, parameter identifier, variable name or level is set.", - "", - "OPERATORS", - " setcodetab Set parameter code table", - " Sets the parameter code table for all variables.", - " setcode Set code number", - " Sets the code number for all variables to the same given value.", - " setparam Set parameter identifier", - " Sets the parameter identifier of the first variable.", - " setname Set variable name", - " Sets the name of the first variable.", - " setunit Set variable unit", - " Sets the unit of the first variable.", - " setlevel Set level", - " Sets the first level of all variables.", - " setltype Set GRIB level type", - " Sets the GRIB level type of all variables.", - " setmaxsteps Set max timesteps", - " Sets maximum number of timesteps", - "", - "PARAMETER", - " table STRING Parameter table file or name", - " code INTEGER Code number", - " param STRING Parameter identifier (GRIB1: code[.tabnum]; GRIB2: num[.cat[.dis]])", - " name STRING Variable name", - " level FLOAT New level", - " ltype INTEGER GRIB level type", - " maxsteps INTEGER Maximum number of timesteps", - nullptr -}; - -static const char *SettimeHelp[] = { - "NAME", - " setdate, settime, setday, setmon, setyear, settunits, settaxis, settbounds, ", - " setreftime, setcalendar, shifttime - Set time", - "", - "SYNOPSIS", - " setdate,date infile outfile", - " settime,time infile outfile", - " setday,day infile outfile", - " setmon,month infile outfile", - " setyear,year infile outfile", - " settunits,units infile outfile", - " settaxis,date,time[,inc] infile outfile", - " settbounds,frequency infile outfile", - " setreftime,date,time[,units] infile outfile", - " setcalendar,calendar infile outfile", - " shifttime,shiftValue infile outfile", - "", - "DESCRIPTION", - " This module sets the time axis or part of the time axis. Which part of the time axis is", - " overwritten/created depends on the chosen operator. The number of time steps does not change.", - "", - "OPERATORS", - " setdate Set date", - " Sets the date in every timestep to the same given value.", - " settime Set time of the day", - " Sets the time in every timestep to the same given value.", - " setday Set day", - " Sets the day in every timestep to the same given value.", - " setmon Set month", - " Sets the month in every timestep to the same given value.", - " setyear Set year", - " Sets the year in every timestep to the same given value.", - " settunits Set time units", - " Sets the base units of a relative time axis.", - " settaxis Set time axis", - " Sets the time axis.", - " settbounds Set time bounds", - " Sets the time bounds.", - " setreftime Set reference time", - " Sets the reference time of a relative time axis.", - " setcalendar Set calendar", - " Sets the calendar attribute of a relative time axis.", - " shifttime Shift timesteps", - " Shifts all timesteps by the parameter shiftValue.", - "", - "PARAMETER", - " day INTEGER Value of the new day", - " month INTEGER Value of the new month", - " year INTEGER Value of the new year", - " units STRING Base units of the time axis (seconds, minutes, hours, days, months, years)", - " date STRING Date (format: YYYY-MM-DD)", - " time STRING Time (format: hh:mm:ss)", - " inc STRING Optional increment (seconds, minutes, hours, days, months, years) [default: 1hour]", - " frequency STRING Frequency of the time series (hour, day, month, year)", - " calendar STRING Calendar (standard, proleptic_gregorian, 360_day, 365_day, 366_day)", - " shiftValue STRING Shift value (e.g. -3hour)", - nullptr -}; - -static const char *ChangeHelp[] = { - "NAME", - " chcode, chparam, chname, chunit, chlevel, chlevelc, chlevelv - ", - " Change field header", - "", - "SYNOPSIS", - " chcode,oldcode,newcode[,...] infile outfile", - " chparam,oldparam,newparam,... infile outfile", - " chname,oldname,newname,... infile outfile", - " chunit,oldunit,newunit,... infile outfile", - " chlevel,oldlev,newlev,... infile outfile", - " chlevelc,code,oldlev,newlev infile outfile", - " chlevelv,name,oldlev,newlev infile outfile", - "", - "DESCRIPTION", - " This module reads fields from infile, changes some header values", - " and writes the results to outfile. The kind of changes depends on ", - " the chosen operator.", - "", - "OPERATORS", - " chcode Change code number", - " Changes some user given code numbers to new user given values.", - " chparam Change parameter identifier", - " Changes some user given parameter identifiers to new user given values.", - " chname Change variable or coordinate name", - " Changes some user given variable or coordinate names to new user given names.", - " chunit Change variable unit", - " Changes some user given variable units to new user given units.", - " chlevel Change level", - " Changes some user given levels to new user given values.", - " chlevelc Change level of one code", - " Changes one level of a user given code number.", - " chlevelv Change level of one variable", - " Changes one level of a user given variable name.", - "", - "PARAMETER", - " code INTEGER Code number", - " oldcode,newcode,... INTEGER Pairs of old and new code numbers", - " oldparam,newparam,... STRING Pairs of old and new parameter identifiers", - " name STRING Variable name", - " oldname,newname,... STRING Pairs of old and new variable names", - " oldlev FLOAT Old level", - " newlev FLOAT New level", - " oldlev,newlev,... FLOAT Pairs of old and new levels", - nullptr -}; - -static const char *SetgridHelp[] = { - "NAME", - " setgrid, setgridtype, setgridarea, setgridmask - Set grid information", - "", - "SYNOPSIS", - " setgrid,grid infile outfile", - " setgridtype,gridtype infile outfile", - " setgridarea,gridarea infile outfile", - " setgridmask,gridmask infile outfile", - "", - "DESCRIPTION", - " This module modifies the metadata of the horizontal grid. Depending on the chosen operator", - " a new grid description is set, the coordinates are converted or the grid cell area is added.", - "", - "OPERATORS", - " setgrid Set grid", - " Sets a new grid description. The input fields need to have the same grid size as the size", - " of the target grid description.", - " setgridtype Set grid type", - " Sets the grid type of all input fields. The following grid types are available:", - " curvilinear " " Converts a regular grid to a curvilinear grid", - " unstructured" " Converts a regular or curvilinear grid to an unstructured grid", - " dereference " " Dereference a reference to a grid", - " regular " " Linear interpolation of a reduced Gaussian grid to a regular Gaussian grid", - " regularnn " " Nearest neighbor interpolation of a reduced Gaussian grid to a regular Gaussian grid", - " lonlat " " Converts a regular lonlat grid stored as a curvilinear grid back to a lonlat grid", - " projection " " Removes the geographical coordinates if projection parameter available", - " setgridarea Set grid cell area", - " Sets the grid cell area. The parameter gridarea is the path to a data file,", - " the first field is used as grid cell area. The input fields need to have the same", - " grid size as the grid cell area. The grid cell area is used to compute", - " the weights of each grid cell if needed by an operator, e.g. for fldmean.", - " setgridmask Set grid mask", - " Sets the grid mask. The parameter gridmask is the path to a data file,", - " the first field is used as the grid mask. The input fields need to have the same", - " grid size as the grid mask. The grid mask is used as the target grid mask for", - " remapping, e.g. for remapbil.", - "", - "PARAMETER", - " grid STRING Grid description file or name", - " gridtype STRING Grid type (curvilinear, unstructured, regular, lonlat, projection or dereference)", - " gridarea STRING Data file, the first field is used as grid cell area", - " gridmask STRING Data file, the first field is used as grid mask", - nullptr -}; - -static const char *SetzaxisHelp[] = { - "NAME", - " setzaxis, genlevelbounds - Set z-axis information", - "", - "SYNOPSIS", - " setzaxis,zaxis infile outfile", - " genlevelbounds[,zbot[,ztop]] infile outfile", - "", - "DESCRIPTION", - " This module modifies the metadata of the vertical grid.", - "", - "OPERATORS", - " setzaxis Set z-axis", - " This operator sets the z-axis description of all variables with the same number of level as the new z-axis.", - " genlevelbounds Generate level bounds", - " Generates the layer bounds of the z-axis.", - "", - "PARAMETER", - " zaxis STRING Z-axis description file or name of the target z-axis", - " zbot FLOAT Specifying the bottom of the vertical column. Must have the same units as z-axis. ", - " ztop FLOAT Specifying the top of the vertical column. Must have the same units as z-axis. ", - nullptr -}; - -static const char *InvertHelp[] = { - "NAME", - " invertlat - Invert latitudes", - "", - "SYNOPSIS", - " invertlat infile outfile", - "", - "DESCRIPTION", - " This operator inverts the latitudes of all fields on a rectilinear grid. ", - nullptr -}; - -static const char *InvertlevHelp[] = { - "NAME", - " invertlev - Invert levels", - "", - "SYNOPSIS", - " invertlev infile outfile", - "", - "DESCRIPTION", - " This operator inverts the levels of all 3D variables.", - nullptr -}; - -static const char *ShiftxyHelp[] = { - "NAME", - " shiftx, shifty - Shift field", - "", - "SYNOPSIS", - " <operator>,<nshift>,<cyclic>,<coord> infile outfile", - "", - "DESCRIPTION", - " This module contains operators to shift all fields in x or y direction.", - " All fields need to have the same horizontal rectilinear or curvilinear grid.", - "", - "OPERATORS", - " shiftx Shift x", - " Shifts all fields in x direction.", - " shifty Shift y", - " Shifts all fields in y direction.", - "", - "PARAMETER", - " nshift INTEGER Number of grid cells to shift (default: 1)", - " cyclic STRING If set, cells are filled up cyclic (default: missing value)", - " coord STRING If set, coordinates are also shifted", - nullptr -}; - -static const char *MaskregionHelp[] = { - "NAME", - " maskregion - Mask regions", - "", - "SYNOPSIS", - " maskregion,regions infile outfile", - "", - "DESCRIPTION", - " Masks different regions of the input fields.", - " The grid cells inside a region are untouched, the cells outside are set to missing value.", - " Considered are only those grid cells with the grid center inside the regions.", - " All input fields must have the same horizontal grid.", - " ", - " Regions can be defined by the user via an ASCII file.", - " Each region consists of the geographic coordinates of a convex polygon.", - " Each line of a polygon description file contains the longitude and latitude of one point.", - " Each polygon description file can contain one or more polygons separated by a line with the character \\&.", - " ", - " Predefined regions of countries can be specified via the country codes.", - " A country is specified with dcw:<CountryCode>. Country codes can be combined with the plus sign.", - "", - "PARAMETER", - " regions STRING Comma-separated list of ASCII formatted files with different regions", - nullptr -}; - -static const char *MaskboxHelp[] = { - "NAME", - " masklonlatbox, maskindexbox - Mask a box", - "", - "SYNOPSIS", - " masklonlatbox,lon1,lon2,lat1,lat2 infile outfile", - " maskindexbox,idx1,idx2,idy1,idy2 infile outfile", - "", - "DESCRIPTION", - " Masks grid cells inside a lon/lat or index box. The elements inside the box are untouched, the ", - " elements outside are set to missing value. All input fields need to have the same horizontal grid.", - " Use sellonlatbox or selindexbox if only the data inside the box are needed.", - "", - "OPERATORS", - " masklonlatbox Mask a longitude/latitude box", - " Masks grid cells inside a lon/lat box. The user must specify the longitude and latitude of the edges of the box.", - " Only those grid cells are considered whose grid center lies within the lon/lat box.", - " For rotated lon/lat grids the parameters must be specified in rotated coordinates.", - " maskindexbox Mask an index box", - " Masks grid cells within an index box. The user must specify the indices of the edges of the box.", - " The index of the left edge can be greater then the one of the right edge. Use negative indexing to", - " start from the end. The input grid must be a regular lon/lat or a 2D curvilinear grid.", - "", - "PARAMETER", - " lon1 FLOAT Western longitude", - " lon2 FLOAT Eastern longitude", - " lat1 FLOAT Southern or northern latitude", - " lat2 FLOAT Northern or southern latitude", - " idx1 INTEGER Index of first longitude", - " idx2 INTEGER Index of last longitude", - " idy1 INTEGER Index of first latitude", - " idy2 INTEGER Index of last latitude", - nullptr -}; - -static const char *SetboxHelp[] = { - "NAME", - " setclonlatbox, setcindexbox - Set a box to constant", - "", - "SYNOPSIS", - " setclonlatbox,c,lon1,lon2,lat1,lat2 infile outfile", - " setcindexbox,c,idx1,idx2,idy1,idy2 infile outfile", - "", - "DESCRIPTION", - " Sets a box of the rectangularly understood field to a constant value. The elements outside ", - " the box are untouched, the elements inside are set to the given constant. All input fields ", - " need to have the same horizontal grid.", - "", - "OPERATORS", - " setclonlatbox Set a longitude/latitude box to constant", - " Sets the values of a longitude/latitude box to a constant value. The ", - " user has to give the longitudes and latitudes of the edges of the box.", - " setcindexbox Set an index box to constant", - " Sets the values of an index box to a constant value. The user has to ", - " give the indices of the edges of the box. The index of the left edge ", - " can be greater than the one of the right edge.", - "", - "PARAMETER", - " c FLOAT Constant", - " lon1 FLOAT Western longitude", - " lon2 FLOAT Eastern longitude", - " lat1 FLOAT Southern or northern latitude", - " lat2 FLOAT Northern or southern latitude", - " idx1 INTEGER Index of first longitude", - " idx2 INTEGER Index of last longitude", - " idy1 INTEGER Index of first latitude", - " idy2 INTEGER Index of last latitude", - nullptr -}; - -static const char *EnlargeHelp[] = { - "NAME", - " enlarge - Enlarge fields", - "", - "SYNOPSIS", - " enlarge,grid infile outfile", - "", - "DESCRIPTION", - " Enlarge all fields of infile to a user given horizontal grid. Normally only the last ", - " field element is used for the enlargement. If however the input and output", - " grid are regular lon/lat grids, a zonal or meridional enlargement is possible.", - " Zonal enlargement takes place, if the xsize of the input field is 1 and ", - " the ysize of both grids are the same. For meridional enlargement the ysize", - " have to be 1 and the xsize of both grids should have the same size.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - nullptr -}; - -static const char *SetmissHelp[] = { - "NAME", - " setmissval, setctomiss, setmisstoc, setrtomiss, setvrange, setmisstonn, ", - " setmisstodis - Set missing value", - "", - "SYNOPSIS", - " setmissval,newmiss infile outfile", - " setctomiss,c infile outfile", - " setmisstoc,c infile outfile", - " setrtomiss,rmin,rmax infile outfile", - " setvrange,rmin,rmax infile outfile", - " setmisstonn infile outfile", - " setmisstodis[,neighbors] infile outfile", - "", - "DESCRIPTION", - " This module sets part of a field to missing value or missing values", - " to a constant value. Which part of the field is set depends on the ", - " chosen operator.", - "", - "OPERATORS", - " setmissval Set a new missing value", - " / newmiss if i(t,x) EQ miss", - " o(t,x) = ", - " \\ i(t,x) if i(t,x) NE miss", - " setctomiss Set constant to missing value", - " / miss if i(t,x) EQ c", - " o(t,x) = ", - " \\ i(t,x) if i(t,x) NE c", - " setmisstoc Set missing value to constant", - " / c if i(t,x) EQ miss", - " o(t,x) = ", - " \\ i(t,x) if i(t,x) NE miss", - " setrtomiss Set range to missing value", - " / miss if i(t,x) GE rmin AND i(t,x) LE rmax", - " o(t,x) = ", - " \\ i(t,x) if i(t,x) LT rmin OR i(t,x) GT rmax", - " setvrange Set valid range", - " / miss if i(t,x) LT rmin OR i(t,x) GT rmax", - " o(t,x) = ", - " \\ i(t,x) if i(t,x) GE rmin AND i(t,x) LE rmax", - " setmisstonn Set missing value to nearest neighbor", - " Set all missing values to the nearest non missing value.", - " / i(t,y) if i(t,x) EQ miss AND i(t,y) NE miss", - " o(t,x) = ", - " \\ i(t,x) if i(t,x) NE miss", - " setmisstodis Set missing value to distance-weighted average", - " Set all missing values to the distance-weighted average of the nearest non missing values.", - " The default number of nearest neighbors is 4.", - "", - "PARAMETER", - " neighbors INTEGER Number of nearest neighbors", - " newmiss FLOAT New missing value", - " c FLOAT Constant", - " rmin FLOAT Lower bound", - " rmax FLOAT Upper bound", - nullptr -}; - -static const char *VertfillmissHelp[] = { - "NAME", - " vertfillmiss - Vertical filling of missing values", - "", - "SYNOPSIS", - " vertfillmiss[,parameter] infile outfile", - "", - "DESCRIPTION", - " This operator fills in vertical missing values.", - " The method parameter can be used to select the filling method.", - " The default method=nearest fills missing values with the nearest neighbor value.", - " Other options are forward and backward to fill missing values by forward or backward propagation of values.", - " Use the limit parameter to set the maximum number of consecutive missing values to fill and max_gaps to set the maximum number of gaps to fill.", - "", - "PARAMETER", - " method STRING Fill method [nearest|linear|forward|backward] (default: nearest)", - " limit INTEGER The maximum number of consecutive missing values to fill (default: all)", - " max_gaps INTEGER The maximum number of gaps to fill (default: all)", - nullptr -}; - -static const char *TimfillmissHelp[] = { - "NAME", - " timfillmiss - Temporal filling of missing values", - "", - "SYNOPSIS", - " timfillmiss[,parameter] infile outfile", - "", - "DESCRIPTION", - " This operator fills in temporally missing values.", - " The method parameter can be used to select the filling method.", - " The default method=nearest fills missing values with the nearest neighbor value.", - " Other options are forward and backward to fill missing values by forward or backward propagation of values.", - " Use the limit parameter to set the maximum number of consecutive missing values to fill and max_gaps to set the maximum number of gaps to fill.", - "", - "PARAMETER", - " method STRING Fill method [nearest|linear|forward|backward] (default: nearest)", - " limit INTEGER The maximum number of consecutive missing values to fill (default: all)", - " max_gaps INTEGER The maximum number of gaps to fill (default: all)", - nullptr -}; - -static const char *SetgridcellHelp[] = { - "NAME", - " setgridcell - Set the value of a grid cell", - "", - "SYNOPSIS", - " setgridcell,parameter infile outfile", - "", - "DESCRIPTION", - " This operator sets the value of the selected grid cells. The grid cells can be selected by a comma-separated list of grid cell indices", - " or a mask. The mask is read from a data file, which may contain only one field. If no grid cells are selected, all values are set.", - "", - "PARAMETER", - " value FLOAT Value of the grid cell", - " cell INTEGER Comma-separated list of grid cell indices", - " mask STRING Name of the data file which contains the mask", - nullptr -}; - -static const char *ExprHelp[] = { - "NAME", - " expr, exprf, aexpr, aexprf - Evaluate expressions", - "", - "SYNOPSIS", - " expr,instr infile outfile", - " exprf,filename infile outfile", - " aexpr,instr infile outfile", - " aexprf,filename infile outfile", - "", - "DESCRIPTION", - " This module arithmetically processes every timestep of the input dataset.", - " Each individual assignment statement have to end with a semi-colon.", - " The special key _ALL_ is used as a template. A statement with a template is replaced for all variable names.", - " Unlike regular variables, temporary variables are never written to the output stream.", - " To define a temporary variable simply prefix the variable name with an underscore (e.g. _varname)", - " when the variable is declared.", - " ", - " The following operators are supported:", - " ", - " Operator & Meaning & Example & Result ", - " = & assignment & x = y & Assigns y to x", - " + & addition & x + y & Sum of x and y", - " - & subtraction & x - y & Difference of x and y ", - " * & multiplication & x * y & Product of x and y ", - " / & division & x / y & Quotient of x and y", - " ^ & exponentiation & x ^y & Exponentiates x with y ", - " == & equal to & x == y & 1, if x equal to y; else 0", - " != & not equal to & x != y & 1, if x not equal to y; else 0", - " > & greater than & x > y & 1, if x greater than y; else 0", - " < & less than & x < y & 1, if x less than y; else 0", - " >= & greater equal & x >= y & 1, if x greater equal y; else 0", - " <= & less equal & x <= y & 1, if x less equal y; else 0", - " <=> & less equal greater & x <=> y & -1, if x less y; 1, if x greater y; else 0 ", - " && & logical AND & x && y & 1, if x and y not equal 0; else 0", - " || & logical OR & x || y & 1, if x or y not equal 0; else 0", - " ! & logical NOT & !x & 1, if x equal 0; else 0", - " ?: & ternary conditional & x ? y : z & y, if x not equal 0, else z ", - " ", - " The following functions are supported:", - " ", - " Math intrinsics:", - " ", - " abs(x) " " Absolute value of x", - " floor(x) " " Round to largest integral value not greater than x", - " ceil(x) " " Round to smallest integral value not less than x", - " float(x) " " 32-bit float value of x", - " int(x) " " Integer value of x", - " nint(x) " " Nearest integer value of x", - " sqr(x) " " Square of x", - " sqrt(x) " " Square Root of x", - " exp(x) " " Exponential of x", - " ln(x) " " Natural logarithm of x", - " log10(x) " " Base 10 logarithm of x", - " sin(x) " " Sine of x, where x is specified in radians", - " cos(x) " " Cosine of x, where x is specified in radians", - " tan(x) " " Tangent of x, where x is specified in radians", - " asin(x) " " Arc-sine of x, where x is specified in radians", - " acos(x) " " Arc-cosine of x, where x is specified in radians", - " atan(x) " " Arc-tangent of x, where x is specified in radians", - " sinh(x) " " Hyperbolic sine of x, where x is specified in radians", - " cosh(x) " " Hyperbolic cosine of x, where x is specified in radians", - " tanh(x) " " Hyperbolic tangent of x, where x is specified in radians", - " asinh(x) " " Inverse hyperbolic sine of x, where x is specified in radians", - " acosh(x) " " Inverse hyperbolic cosine of x, where x is specified in radians", - " atanh(x) " " Inverse hyperbolic tangent of x, where x is specified in radians", - " rad(x) " " Convert x from degrees to radians", - " deg(x) " " Convert x from radians to degrees", - " rand(x) " " Replace x by pseudo-random numbers in the range of 0 to 1 ", - " isMissval(x)" " Returns 1 where x is missing", - " ", - " mod(x,y) " " Floating-point remainder of x/ y", - " min(x,y) " " Minimum value of x and y", - " max(x,y) " " Maximum value of x and y", - " pow(x,y) " " Power function", - " hypot(x,y) " " Euclidean distance function, sqrt(x*x + y*y)", - " atan2(x,y) " " Arc tangent function of y/x, using signs to determine quadrants ", - " ", - " Coordinates:", - " ", - " clon(x) " " Longitude coordinate of x (available only if x has geographical coordinates)", - " clat(x) " " Latitude coordinate of x (available only if x has geographical coordinates)", - " gridarea(x)" " Grid cell area of x (available only if x has geographical coordinates)", - " gridindex(x)" " Grid cell indices of x", - " clev(x) " " Level coordinate of x (0, if x is a 2D surface variable)", - " clevidx(x) " " Level index of x (0, if x is a 2D surface variable)", - " cthickness(x)" " Layer thickness, upper minus lower level bound of x (1, if level bounds are missing)", - " ctimestep()" " Timestep number (1 to N)", - " cdate() " " Verification date as YYYYMMDD", - " ctime() " " Verification time as HHMMSS.millisecond", - " cdeltat() " " Difference between current and last timestep in seconds", - " cday() " " Day as DD", - " cmonth() " " Month as MM", - " cyear() " " Year as YYYY", - " csecond() " " Second as SS.millisecond", - " cminute() " " Minute as MM", - " chour() " " Hour as HH", - " ", - " Constants:", - " ", - " ngp(x) " " Number of horizontal grid points", - " nlev(x) " " Number of vertical levels", - " size(x) " " Total number of elements (ngp(x)*nlev(x))", - " missval(x)" " Returns the missing value of variable x", - " ", - " Statistical values over a field:", - " ", - " fldmin(x), fldmax(x), fldrange(x), fldsum(x), fldmean(x), fldavg(x), fldstd(x), fldstd1(x),", - " fldvar(x), fldvar1(x), fldskew(x), fldkurt(x), fldmedian(x)", - " ", - " Zonal statistical values for regular 2D grids:", - " ", - " zonmin(x), zonmax(x), zonrange(x), zonsum(x), zonmean(x), zonavg(x), zonstd(x), zonstd1(x),", - " zonvar(x), zonvar1(x), zonskew(x), zonkurt(x), zonmedian(x)", - " ", - " Vertical statistical values:", - " ", - " vertmin(x), vertmax(x), vertrange(x), vertsum(x), vertmean(x), vertavg(x), vertstd(x), vertstd1(x),", - " vertvar(x), vertvar1(x)", - " ", - " Miscellaneous:", - " ", - " sellevel(x,k) " " Select level k of variable x", - " sellevidx(x,k) " " Select level index k of variable x", - " sellevelrange(x,k1,k2) " " Select all levels of variable x in the range k1 to k2", - " sellevidxrange(x,k1,k2)" " Select all level indices of variable x in the range k1 to k2", - " remove(x) " " Remove variable x from output stream", - " ", - "", - "OPERATORS", - " expr Evaluate expressions", - " The processing instructions are read from the parameter.", - " exprf Evaluate expressions script", - " Contrary to expr the processing instructions are read from a file.", - " aexpr Evaluate expressions and append results", - " Same as expr, but keep input variables and append results", - " aexprf Evaluate expression script and append results", - " Same as exprf, but keep input variables and append results", - "", - "PARAMETER", - " instr STRING Processing instructions (need to be 'quoted' in most cases)", - " filename STRING File with processing instructions", - "", - "NOTE", - " If the input stream contains duplicate entries of the same variable name then the last one is used.", - nullptr -}; - -static const char *MathHelp[] = { - "NAME", - " abs, int, nint, pow, sqr, sqrt, exp, ln, log10, sin, cos, tan, asin, acos, ", - " atan, reci, not - Mathematical functions", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module contains some standard mathematical functions.", - " All trigonometric functions calculate with radians.", - "", - "OPERATORS", - " abs Absolute value", - " o(t,x) = abs(i(t,x))", - " int Integer value", - " o(t,x) = int(i(t,x))", - " nint Nearest integer value", - " o(t,x) = nint(i(t,x))", - " pow Power", - " o(t,x) = i(t,x)^y", - " sqr Square", - " o(t,x) = i(t,x)^2", - " sqrt Square root", - " o(t,x) = sqrt(i(t,x))", - " exp Exponential", - " o(t,x) = e^i(t,x)", - " ln Natural logarithm", - " o(t,x) = ln(i(t,x))", - " log10 Base 10 logarithm", - " o(t,x) = log10(i(t,x))", - " sin Sine", - " o(t,x) = sin(i(t,x))", - " cos Cosine", - " o(t,x) = cos(i(t,x))", - " tan Tangent", - " o(t,x) = tan(i(t,x))", - " asin Arc sine", - " o(t,x) = asin(i(t,x))", - " acos Arc cosine", - " o(t,x) = acos(i(t,x))", - " atan Arc tangent", - " o(t,x) = atan(i(t,x))", - " reci Reciprocal value", - " o(t,x) = 1 / i(t,x)", - " not Logical NOT", - " o(t,x) = 1, if x equal 0; else 0", - nullptr -}; - -static const char *ArithcHelp[] = { - "NAME", - " addc, subc, mulc, divc, minc, maxc - Arithmetic with a constant", - "", - "SYNOPSIS", - " <operator>,c infile outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic with all field elements of a dataset and ", - " a constant. The fields in outfile inherit the meta data from infile.", - "", - "OPERATORS", - " addc Add a constant", - " o(t,x) = i(t,x) + c", - " subc Subtract a constant", - " o(t,x) = i(t,x) - c", - " mulc Multiply with a constant", - " o(t,x) = i(t,x) * c", - " divc Divide by a constant", - " o(t,x) = i(t,x) / c", - " minc Minimum of a field and a constant", - " o(t,x) = min(i(t,x), c)", - " maxc Maximum of a field and a constant", - " o(t,x) = max(i(t,x), c)", - "", - "PARAMETER", - " c FLOAT Constant", - nullptr -}; - -static const char *ArithHelp[] = { - "NAME", - " add, sub, mul, div, min, max, atan2 - Arithmetic on two datasets", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of two datasets.", - " The number of fields in infile1 should be the same as in infile2.", - " The fields in outfile inherit the meta data from infile1.", - " All operators in this module simply process one field after the other from the two input files.", - " Neither the order of the variables nor the date is checked.", - " One of the input files can contain only one timestep or one variable.", - "", - "OPERATORS", - " add Add two fields", - " o(t,x) = i_1(t,x) + i_2(t,x)", - " sub Subtract two fields", - " o(t,x) = i_1(t,x) - i_2(t,x)", - " mul Multiply two fields", - " o(t,x) = i_1(t,x) * i_2(t,x)", - " div Divide two fields", - " o(t,x) = i_1(t,x) / i_2(t,x)", - " min Minimum of two fields", - " o(t,x) = min(i_1(t,x), i_2(t,x))", - " max Maximum of two fields", - " o(t,x) = max(i_1(t,x), i_2(t,x))", - " atan2 Arc tangent of two fields", - " The atan2 operator calculates the arc tangent of two fields. The result is", - " in radians, which is between -PI and PI (inclusive).", - " ", - " o(t,x) = atan2(i_1(t,x), i_2(t,x))", - nullptr -}; - -static const char *DayarithHelp[] = { - "NAME", - " dayadd, daysub, daymul, daydiv - Daily arithmetic", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of a time series and one timestep with the same day, month and year.", - " For each field in infile1 the corresponding field of the timestep in infile2 with the same day, month and year is used.", - " The input files need to have the same structure with the same variables.", - " Usually infile2 is generated by an operator of the module DAYSTAT.", - "", - "OPERATORS", - " dayadd Add daily time series", - " Adds a time series and a daily time series.", - " daysub Subtract daily time series", - " Subtracts a time series and a daily time series.", - " daymul Multiply daily time series", - " Multiplies a time series and a daily time series.", - " daydiv Divide daily time series", - " Divides a time series and a daily time series.", - nullptr -}; - -static const char *MonarithHelp[] = { - "NAME", - " monadd, monsub, monmul, mondiv - Monthly arithmetic", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of a time series and one timestep with the same month and year.", - " For each field in infile1 the corresponding field of the timestep in infile2 with the same month and year is used.", - " The input files need to have the same structure with the same variables.", - " Usually infile2 is generated by an operator of the module MONSTAT.", - "", - "OPERATORS", - " monadd Add monthly time series", - " Adds a time series and a monthly time series.", - " monsub Subtract monthly time series", - " Subtracts a time series and a monthly time series.", - " monmul Multiply monthly time series", - " Multiplies a time series and a monthly time series.", - " mondiv Divide monthly time series", - " Divides a time series and a monthly time series.", - nullptr -}; - -static const char *YeararithHelp[] = { - "NAME", - " yearadd, yearsub, yearmul, yeardiv - Yearly arithmetic", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of a time series and one timestep", - " with the same year. For each field in infile1 the corresponding", - " field of the timestep in infile2 with the same year is used.", - " The header information in infile1 have to be the same as in infile2.", - " Usually infile2 is generated by an operator of the module YEARSTAT.", - "", - "OPERATORS", - " yearadd Add yearly time series", - " Adds a time series and a yearly time series.", - " yearsub Subtract yearly time series", - " Subtracts a time series and a yearly time series.", - " yearmul Multiply yearly time series", - " Multiplies a time series and a yearly time series.", - " yeardiv Divide yearly time series", - " Divides a time series and a yearly time series.", - nullptr -}; - -static const char *YhourarithHelp[] = { - "NAME", - " yhouradd, yhoursub, yhourmul, yhourdiv - Multi-year hourly arithmetic", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of a time series and one timestep with the same hour and day of year.", - " For each field in infile1 the corresponding field of the timestep in infile2 with the same hour and day of year is used.", - " The input files need to have the same structure with the same variables.", - " Usually infile2 is generated by an operator of the module YHOURSTAT.", - "", - "OPERATORS", - " yhouradd Add multi-year hourly time series", - " Adds a time series and a multi-year hourly time series.", - " yhoursub Subtract multi-year hourly time series", - " Subtracts a time series and a multi-year hourly time series.", - " yhourmul Multiply multi-year hourly time series", - " Multiplies a time series and a multi-year hourly time series.", - " yhourdiv Divide multi-year hourly time series", - " Divides a time series and a multi-year hourly time series.", - nullptr -}; - -static const char *YdayarithHelp[] = { - "NAME", - " ydayadd, ydaysub, ydaymul, ydaydiv - Multi-year daily arithmetic", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of a time series and one timestep with the same day of year.", - " For each field in infile1 the corresponding field of the timestep in infile2 with the same day of year is used.", - " The input files need to have the same structure with the same variables.", - " Usually infile2 is generated by an operator of the module YDAYSTAT.", - "", - "OPERATORS", - " ydayadd Add multi-year daily time series", - " Adds a time series and a multi-year daily time series.", - " ydaysub Subtract multi-year daily time series", - " Subtracts a time series and a multi-year daily time series.", - " ydaymul Multiply multi-year daily time series", - " Multiplies a time series and a multi-year daily time series.", - " ydaydiv Divide multi-year daily time series", - " Divides a time series and a multi-year daily time series.", - nullptr -}; - -static const char *YmonarithHelp[] = { - "NAME", - " ymonadd, ymonsub, ymonmul, ymondiv - Multi-year monthly arithmetic", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of a time series and one timestep with the same month of year.", - " For each field in infile1 the corresponding field of the timestep in infile2 with the same month of year is used.", - " The input files need to have the same structure with the same variables.", - " Usually infile2 is generated by an operator of the module YMONSTAT.", - "", - "OPERATORS", - " ymonadd Add multi-year monthly time series", - " Adds a time series and a multi-year monthly time series.", - " ymonsub Subtract multi-year monthly time series", - " Subtracts a time series and a multi-year monthly time series.", - " ymonmul Multiply multi-year monthly time series", - " Multiplies a time series with a multi-year monthly time series.", - " ymondiv Divide multi-year monthly time series", - " Divides a time series by a multi-year monthly time series.", - nullptr -}; - -static const char *YseasarithHelp[] = { - "NAME", - " yseasadd, yseassub, yseasmul, yseasdiv - Multi-year seasonal arithmetic", - "", - "SYNOPSIS", - " <operator> infile1 infile2 outfile", - "", - "DESCRIPTION", - " This module performs simple arithmetic of a time series and one timestep with the same season.", - " For each field in infile1 the corresponding field of the timestep in infile2 with the same season is used.", - " The input files need to have the same structure with the same variables.", - " Usually infile2 is generated by an operator of the module YSEASSTAT.", - "", - "OPERATORS", - " yseasadd Add multi-year seasonal time series", - " Adds a time series and a multi-year seasonal time series.", - " yseassub Subtract multi-year seasonal time series", - " Subtracts a time series and a multi-year seasonal time series.", - " yseasmul Multiply multi-year seasonal time series", - " Multiplies a time series and a multi-year seasonal time series.", - " yseasdiv Divide multi-year seasonal time series", - " Divides a time series and a multi-year seasonal time series.", - nullptr -}; - -static const char *ArithdaysHelp[] = { - "NAME", - " muldpm, divdpm, muldpy, divdpy - Arithmetic with days", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module multiplies or divides each timestep of a dataset with the corresponding", - " days per month or days per year. The result of these functions depends on the used", - " calendar of the input data.", - "", - "OPERATORS", - " muldpm Multiply with days per month", - " o(t,x) = i(t,x) * days_per_month", - " divdpm Divide by days per month", - " o(t,x) = i(t,x) / days_per_month", - " muldpy Multiply with days per year", - " o(t,x) = i(t,x) * days_per_year", - " divdpy Divide by days per year", - " o(t,x) = i(t,x) / days_per_year", - nullptr -}; - -static const char *ArithlatHelp[] = { - "NAME", - " mulcoslat, divcoslat - Arithmetic with latitude", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module multiplies or divides each field element with the cosine of the latitude.", - "", - "OPERATORS", - " mulcoslat Multiply with the cosine of the latitude", - " o(t,x) = i(t,x) * cos(latitude(x))", - " divcoslat Divide by cosine of the latitude", - " o(t,x) = i(t,x) / cos(latitude(x))", - nullptr -}; - -static const char *TimcumsumHelp[] = { - "NAME", - " timcumsum - Cumulative sum over all timesteps", - "", - "SYNOPSIS", - " timcumsum infile outfile", - "", - "DESCRIPTION", - " The timcumsum operator calculates the cumulative sum over all timesteps.", - " Missing values are treated as numeric zero when summing.", - " ", - " o(t,x) = sum{i(t',x), 0<t'<=t}", - nullptr -}; - -static const char *ConsecstatHelp[] = { - "NAME", - " consecsum, consects - Consecute timestep periods", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes periods over all timesteps in infile where a", - " certain property is valid. The property can be chosen by creating a mask from", - " the original data, which is the expected input format for operators of this", - " module. Depending on the operator full information about each period or", - " just its length and ending date are computed.", - "", - "OPERATORS", - " consecsum Consecutive Sum", - " This operator computes periods of consecutive timesteps similar to a", - " runsum, but periods are finished, when the mask value is 0. That way", - " multiple periods can be found. Timesteps from the input are preserved. Missing", - " values are handled like 0, i.e. finish periods of consecutive timesteps.", - " consects Consecutive Timesteps", - " In contrast to the operator above consects only computes the length of each", - " period together with its last timestep. To be able to perform statistical", - " analysis like min, max or mean, everything else is set to missing value.", - nullptr -}; - -static const char *VarsstatHelp[] = { - "NAME", - " varsmin, varsmax, varsrange, varssum, varsmean, varsavg, varsstd, varsstd1, ", - " varsvar, varsvar1 - Statistical values over all variables", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over all variables for each timestep.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance or", - " standard deviation is written to outfile.", - " All input variables need to have the same gridsize and the same number of levels.", - "", - "OPERATORS", - " varsmin Variables minimum", - " For every timestep the minimum over all variables is computed.", - " varsmax Variables maximum", - " For every timestep the maximum over all variables is computed.", - " varsrange Variables range", - " For every timestep the range over all variables is computed.", - " varssum Variables sum", - " For every timestep the sum over all variables is computed.", - " varsmean Variables mean", - " For every timestep the mean over all variables is computed.", - " varsavg Variables average", - " For every timestep the average over all variables is computed.", - " varsstd Variables standard deviation", - " For every timestep the standard deviation over all variables is computed. Normalize by n.", - " varsstd1 Variables standard deviation (n-1)", - " For every timestep the standard deviation over all variables is computed. Normalize by (n-1).", - " varsvar Variables variance", - " For every timestep the variance over all variables is computed. Normalize by n.", - " varsvar1 Variables variance (n-1)", - " For every timestep the variance over all variables is computed. Normalize by (n-1).", - nullptr -}; - -static const char *EnsstatHelp[] = { - "NAME", - " ensmin, ensmax, ensrange, enssum, ensmean, ensavg, ensstd, ensstd1, ensvar, ", - " ensvar1, ensskew, enskurt, ensmedian, enspctl - ", - " Statistical values over an ensemble", - "", - "SYNOPSIS", - " <operator> infiles outfile", - " enspctl,p infiles outfile", - "", - "DESCRIPTION", - " This module computes statistical values over an ensemble of input files.", - " Depending on the chosen operator, the minimum, maximum, range, sum, average, standard deviation, variance,", - " skewness, kurtosis, median or a certain percentile over all input files is written to outfile.", - " All input files need to have the same structure with the same variables.", - " The date information of a timestep in outfile is the date of the first input file.", - "", - "OPERATORS", - " ensmin Ensemble minimum", - " o(t,x) = min{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensmax Ensemble maximum", - " o(t,x) = max{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensrange Ensemble range", - " o(t,x) = range{i1(t,x), i2(t,x), ..., in(t,x)}", - " enssum Ensemble sum", - " o(t,x) = sum{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensmean Ensemble mean", - " o(t,x) = mean{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensavg Ensemble average", - " o(t,x) = avg{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensstd Ensemble standard deviation", - " Normalize by n.", - " ", - " o(t,x) = std{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensstd1 Ensemble standard deviation (n-1)", - " Normalize by (n-1).", - " ", - " o(t,x) = std1{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensvar Ensemble variance", - " Normalize by n.", - " ", - " o(t,x) = var{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensvar1 Ensemble variance (n-1)", - " Normalize by (n-1).", - " ", - " o(t,x) = var1{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensskew Ensemble skewness", - " o(t,x) = skew{i1(t,x), i2(t,x), ..., in(t,x)}", - " enskurt Ensemble kurtosis", - " o(t,x) = kurt{i1(t,x), i2(t,x), ..., in(t,x)}", - " ensmedian Ensemble median", - " o(t,x) = median{i1(t,x), i2(t,x), ..., in(t,x)}", - " enspctl Ensemble percentiles", - " o(t,x) = pth percentile {i1(t,x), i2(t,x), ..., in(t,x)}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "NOTE", - " Operators of this module need to open all input files simultaneously.", - " The maximum number of open files depends on the operating system!", - nullptr -}; - -static const char *Ensstat2Help[] = { - "NAME", - " ensrkhistspace, ensrkhisttime, ensroc - Statistical values over an ensemble", - "", - "SYNOPSIS", - " <operator> obsfile ensfiles outfile", - "", - "DESCRIPTION", - " This module computes statistical values over the ensemble of ensfiles using", - " obsfile as a reference. Depending on the operator a ranked Histogram or ", - " a roc-curve over all Ensembles ensfiles", - " with reference to obsfile is written to outfile. ", - " The date and grid information of a timestep in outfile is the date of the ", - " first input file. Thus all input files are required to have the same structure in ", - " terms of the gridsize, variable definitions and number of timesteps. ", - " ", - " All Operators in this module use obsfile as the reference (for instance ", - " an observation) whereas ensfiles are understood as an ensemble consisting ", - " of n (where n is the number of ensfiles) members. ", - " ", - " The operators ensrkhistspace and ensrkhisttime compute Ranked Histograms. ", - " Therefor the vertical axis is utilized as the Histogram axis, which prohibits", - " the use of files containing more than one level. The histogram axis has ", - " nensfiles+1 bins with level 0 containing for each grid point the number of ", - " observations being smaller as all ensembles and level nensfiles+1 indicating", - " the number of observations being larger than all ensembles. ", - " ", - " ensrkhistspace computes a ranked histogram at each timestep reducing each ", - " horizontal grid to a 1x1 grid and keeping the time axis as in obsfile. ", - " Contrary ensrkhistspace computes a histogram at each grid point keeping the ", - " horizontal grid for each variable and reducing the time-axis. The time information", - " is that from the last timestep in obsfile. ", - "", - "OPERATORS", - " ensrkhistspace Ranked Histogram averaged over time", - " ensrkhisttime Ranked Histogram averaged over space", - " ensroc Ensemble Receiver Operating characteristics", - nullptr -}; - -static const char *EnsvalHelp[] = { - "NAME", - " enscrps, ensbrs - Ensemble validation tools", - "", - "SYNOPSIS", - " enscrps rfile infiles outfilebase", - " ensbrs,x rfile infiles outfilebase", - "", - "DESCRIPTION", - " This module computes ensemble validation scores and their decomposition such as ", - " the Brier and cumulative ranked probability score (CRPS). ", - " The first file is used as a reference it can be a climatology, observation or ", - " reanalysis against which the skill of the ensembles given in infiles is measured. ", - " Depending on the operator a number of output files is generated each containing ", - " the skill score and its decomposition corresponding to the operator. ", - " The output is averaged over horizontal fields using appropriate weights ", - " for each level and timestep in rfile. ", - " ", - " All input files need to have the same structure with the same variables.", - " The date information of a timestep in outfile is the date of the first input file.", - " The output files are named as ", - " <outfilebase>.<type>.<filesuffix> where <type> depends on the ", - " operator and <filesuffix> is determined from the output file type. ", - " There are three output files for operator enscrps and four output files ", - " for operator ensbrs.", - " ", - " The CRPS and its decomposition into Reliability and the potential ", - " CRPS are calculated by an appropriate averaging over the field ", - " members (note, that the CRPS does *not* average linearly). ", - " In the three output files ", - " <type> has the following meaning:", - " crps for the CRPS, reli for the reliability ", - " and crpspot for the potential crps. The relation ", - " CRPS = CRPS_{pot} + RELI", - " holds. ", - " ", - " The Brier score of the Ensemble given by infiles with respect to the ", - " reference given in rfile and the threshold x is calculated. ", - " In the four output files <type> has the following meaning: ", - " brs for the Brier score wrt threshold x; ", - " brsreli for the Brier score reliability wrt threshold x;", - " brsreso for the Brier score resolution wrt threshold x;", - " brsunct for the Brier score uncertainty wrt threshold x.", - " In analogy to the CRPS the following relation holds:", - " BRS(x) = RELI(x)-RESO(x)+ UNCT(x).", - " ", - " The implementation of the decomposition of the CRPS and Brier Score follows ", - " Hans Hersbach (2000): Decomposition of the Continuous Ranked Probability ", - " Score for Ensemble Prediction Systems, in: Weather and Forecasting (15) ", - " pp. 559-570. ", - " ", - " The CRPS code decomposition has been verified against the CRAN - ensemble ", - " validation package from R. Differences occur when grid-cell area is not ", - " uniform as the implementation in R does not account for that. ", - " ", - "", - "OPERATORS", - " enscrps Ensemble CRPS and decomposition", - " ensbrs Ensemble Brier score", - " Ensemble Brier Score and Decomposition", - nullptr -}; - -static const char *FldstatHelp[] = { - "NAME", - " fldmin, fldmax, fldrange, fldsum, fldint, fldmean, fldavg, fldstd, fldstd1, ", - " fldvar, fldvar1, fldskew, fldkurt, fldmedian, fldcount, fldpctl - ", - " Statistical values over a field", - "", - "SYNOPSIS", - " <operator> infile outfile", - " fldint,weights infile outfile", - " fldmean,weights infile outfile", - " fldavg,weights infile outfile", - " fldstd,weights infile outfile", - " fldstd1,weights infile outfile", - " fldvar,weights infile outfile", - " fldvar1,weights infile outfile", - " fldpctl,p infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values of all input fields. A field is a horizontal layer of a data variable.", - " Depending on the chosen operator, the minimum, maximum, range, sum, integral, average, standard deviation, variance,", - " skewness, kurtosis, median or a certain percentile of the field is written to outfile.", - "", - "OPERATORS", - " fldmin Field minimum", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = min{i(t,x'), x_1<x'<=x_n}", - " fldmax Field maximum", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = max{i(t,x'), x_1<x'<=x_n}", - " fldrange Field range", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = range{i(t,x'), x_1<x'<=x_n}", - " fldsum Field sum", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = sum{i(t,x'), x_1<x'<=x_n}", - " fldint Field integral", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = sum{i(t,x')*cellarea(x'), x_1<x'<=x_n}", - " fldmean Field mean", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = mean{i(t,x'), x_1<x'<=x_n}", - " weighted by area weights obtained by the input field.", - " fldavg Field average", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = avg{i(t,x'), x_1<x'<=x_n}", - " weighted by area weights obtained by the input field.", - " fldstd Field standard deviation", - " Normalize by n. For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = std{i(t,x'), x_1<x'<=x_n}", - " weighted by area weights obtained by the input field.", - " fldstd1 Field standard deviation (n-1)", - " Normalize by (n-1). For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = std1{i(t,x'), x_1<x'<=x_n}", - " weighted by area weights obtained by the input field.", - " fldvar Field variance", - " Normalize by n. For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = var{i(t,x'), x_1<x'<=x_n}", - " weighted by area weights obtained by the input field.", - " fldvar1 Field variance (n-1)", - " Normalize by (n-1). For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = var1{i(t,x'), x_1<x'<=x_n}", - " weighted by area weights obtained by the input field.", - " fldskew Field skewness", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = skew{i(t,x'), x_1<x'<=x_n}", - " fldkurt Field kurtosis", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = kurt{i(t,x'), x_1<x'<=x_n}", - " fldmedian Field median", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = median{i(t,x'), x_1<x'<=x_n}", - " fldcount Field count", - " Number of non-missing values of the field.", - " fldpctl Field percentiles", - " For every gridpoint x_1, ..., x_n of the same field it is:", - " ", - " o(t,1) = pth percentile {i(t,x'), x_1<x'<=x_n}", - "", - "PARAMETER", - " weights BOOL weights=FALSE disables weighting by grid cell area [default: weights=TRUE]", - " p FLOAT Percentile number in {0, ..., 100}", - nullptr -}; - -static const char *ZonstatHelp[] = { - "NAME", - " zonmin, zonmax, zonrange, zonsum, zonmean, zonavg, zonstd, zonstd1, zonvar, ", - " zonvar1, zonskew, zonkurt, zonmedian, zonpctl - Zonal statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - " zonmean[,zonaldes] infile outfile", - " zonpctl,p infile outfile", - "", - "DESCRIPTION", - " This module computes zonal statistical values of the input fields.", - " Depending on the chosen operator, the zonal minimum, maximum, range, sum, average, standard deviation, variance,", - " skewness, kurtosis, median or a certain percentile of the field is written to outfile.", - " Operators of this module require all variables on the same regular lon/lat grid.", - " Only the zonal mean (zonmean) can be calculated for data on an unstructured grid if the latitude bins are", - " defined with the optional parameter zonaldes.", - "", - "OPERATORS", - " zonmin Zonal minimum", - " For every latitude the minimum over all longitudes is computed.", - " zonmax Zonal maximum", - " For every latitude the maximum over all longitudes is computed.", - " zonrange Zonal range", - " For every latitude the range over all longitudes is computed.", - " zonsum Zonal sum", - " For every latitude the sum over all longitudes is computed.", - " zonmean Zonal mean", - " For every latitude the mean over all longitudes is computed.", - " Use the optional parameter zonaldes for data on an unstructured grid.", - " zonavg Zonal average", - " For every latitude the average over all longitudes is computed.", - " zonstd Zonal standard deviation", - " For every latitude the standard deviation over all longitudes is computed. Normalize by n.", - " zonstd1 Zonal standard deviation (n-1)", - " For every latitude the standard deviation over all longitudes is computed. Normalize by (n-1). ", - " zonvar Zonal variance", - " For every latitude the variance over all longitudes is computed. Normalize by n.", - " zonvar1 Zonal variance (n-1)", - " For every latitude the variance over all longitudes is computed. Normalize by (n-1).", - " zonskew Zonal skewness", - " For every latitude the skewness over all longitudes is computed.", - " zonkurt Zonal kurtosis", - " For every latitude the kurtosis over all longitudes is computed.", - " zonmedian Zonal median", - " For every latitude the median over all longitudes is computed.", - " zonpctl Zonal percentiles", - " For every latitude the pth percentile over all longitudes is computed.", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - " zonaldes STRING Description of the zonal latitude bins needed for data on an unstructured grid. A predefined zonal description is zonal_<DY>. DY is the increment of the latitudes in degrees.", - nullptr -}; - -static const char *MerstatHelp[] = { - "NAME", - " mermin, mermax, merrange, mersum, mermean, meravg, merstd, merstd1, mervar, ", - " mervar1, merskew, merkurt, mermedian, merpctl - Meridional statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - " merpctl,p infile outfile", - "", - "DESCRIPTION", - " This module computes meridional statistical values of the input fields.", - " Depending on the chosen operator, the meridional minimum, maximum, range, sum, average, standard deviation, variance,", - " skewness, kurtosis, median or a certain percentile of the field is written to outfile.", - " Operators of this module require all variables on the same regular lon/lat grid.", - "", - "OPERATORS", - " mermin Meridional minimum", - " For every longitude the minimum over all latitudes is computed.", - " mermax Meridional maximum", - " For every longitude the maximum over all latitudes is computed.", - " merrange Meridional range", - " For every longitude the range over all latitudes is computed.", - " mersum Meridional sum", - " For every longitude the sum over all latitudes is computed.", - " mermean Meridional mean", - " For every longitude the area weighted mean over all latitudes is computed.", - " meravg Meridional average", - " For every longitude the area weighted average over all latitudes is computed.", - " merstd Meridional standard deviation", - " For every longitude the standard deviation over all latitudes is computed. Normalize by n.", - " merstd1 Meridional standard deviation (n-1)", - " For every longitude the standard deviation over all latitudes is computed. Normalize by (n-1).", - " mervar Meridional variance", - " For every longitude the variance over all latitudes is computed. Normalize by n.", - " mervar1 Meridional variance (n-1)", - " For every longitude the variance over all latitudes is computed. Normalize by (n-1).", - " merskew Meridional skewness", - " For every longitude the skewness over all latitudes is computed.", - " merkurt Meridional kurtosis", - " For every longitude the kurtosis over all latitudes is computed.", - " mermedian Meridional median", - " For every longitude the median over all latitudes is computed.", - " merpctl Meridional percentiles", - " For every longitude the pth percentile over all latitudes is computed.", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - nullptr -}; - -static const char *GridboxstatHelp[] = { - "NAME", - " gridboxmin, gridboxmax, gridboxrange, gridboxsum, gridboxmean, gridboxavg, ", - " gridboxstd, gridboxstd1, gridboxvar, gridboxvar1, gridboxskew, gridboxkurt, ", - " gridboxmedian - Statistical values over grid boxes", - "", - "SYNOPSIS", - " <operator>,nx,ny infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over surrounding grid boxes.", - " Depending on the chosen operator, the minimum, maximum, range, sum, average, standard deviation, variance,", - " skewness, kurtosis or median of the neighboring grid boxes is written to outfile.", - " All gridbox operators only work on quadrilateral curvilinear grids.", - "", - "OPERATORS", - " gridboxmin Gridbox minimum", - " Minimum value of the selected grid boxes.", - " gridboxmax Gridbox maximum", - " Maximum value of the selected grid boxes.", - " gridboxrange Gridbox range", - " Range (max-min value) of the selected grid boxes.", - " gridboxsum Gridbox sum", - " Sum of the selected grid boxes.", - " gridboxmean Gridbox mean", - " Mean of the selected grid boxes.", - " gridboxavg Gridbox average", - " Average of the selected grid boxes.", - " gridboxstd Gridbox standard deviation", - " Standard deviation of the selected grid boxes. Normalize by n.", - " gridboxstd1 Gridbox standard deviation (n-1)", - " Standard deviation of the selected grid boxes. Normalize by (n-1).", - " gridboxvar Gridbox variance", - " Variance of the selected grid boxes. Normalize by n.", - " gridboxvar1 Gridbox variance (n-1)", - " Variance of the selected grid boxes. Normalize by (n-1).", - " gridboxskew Gridbox skewness", - " Skewness of the selected grid boxes.", - " gridboxkurt Gridbox kurtosis", - " Kurtosis of the selected grid boxes.", - " gridboxmedian Gridbox median", - " Median of the selected grid boxes.", - "", - "PARAMETER", - " nx INTEGER Number of grid boxes in x direction", - " ny INTEGER Number of grid boxes in y direction", - nullptr -}; - -static const char *RemapstatHelp[] = { - "NAME", - " remapmin, remapmax, remaprange, remapsum, remapmean, remapavg, remapstd, ", - " remapstd1, remapvar, remapvar1, remapskew, remapkurt, remapmedian - ", - " Remaps source points to target cells", - "", - "SYNOPSIS", - " <operator>,grid infile outfile", - "", - "DESCRIPTION", - " This module maps source points to target cells by calculating a statistical value from the source points.", - " Each target cell contains the statistical value from all source points within that target cell.", - " If there are no source points within a target cell, it gets a missing value.", - " The target grid must be regular lon/lat or Gaussian.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance,", - " standard deviation, skewness, kurtosis or median of source points is computed.", - "", - "OPERATORS", - " remapmin Remap minimum", - " Minimum value of the source points.", - " remapmax Remap maximum", - " Maximum value of the source points.", - " remaprange Remap range", - " Range (max-min value) of the source points.", - " remapsum Remap sum", - " Sum of the source points.", - " remapmean Remap mean", - " Mean of the source points.", - " remapavg Remap average", - " Average of the source points.", - " remapstd Remap standard deviation", - " Standard deviation of the source points. Normalize by n.", - " remapstd1 Remap standard deviation (n-1)", - " Standard deviation of the source points. Normalize by (n-1).", - " remapvar Remap variance", - " Variance of the source points. Normalize by n.", - " remapvar1 Remap variance (n-1)", - " Variance of the source points. Normalize by (n-1).", - " remapskew Remap skewness", - " Skewness of the source points.", - " remapkurt Remap kurtosis", - " Kurtosis of the source points.", - " remapmedian Remap median", - " Median of the source points.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - nullptr -}; - -static const char *VertstatHelp[] = { - "NAME", - " vertmin, vertmax, vertrange, vertsum, vertmean, vertavg, vertstd, vertstd1, ", - " vertvar, vertvar1 - Vertical statistical values", - "", - "SYNOPSIS", - " <operator>,weights infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over all levels of the input variables.", - " According to chosen operator the vertical minimum, maximum, range, sum, average, variance", - " or standard deviation is written to outfile.", - "", - "OPERATORS", - " vertmin Vertical minimum", - " For every gridpoint the minimum over all levels is computed.", - " vertmax Vertical maximum", - " For every gridpoint the maximum over all levels is computed.", - " vertrange Vertical range", - " For every gridpoint the range over all levels is computed.", - " vertsum Vertical sum", - " For every gridpoint the sum over all levels is computed.", - " vertmean Vertical mean", - " For every gridpoint the layer weighted mean over all levels is computed.", - " vertavg Vertical average", - " For every gridpoint the layer weighted average over all levels is computed.", - " vertstd Vertical standard deviation", - " For every gridpoint the standard deviation over all levels is computed. Normalize by n.", - " vertstd1 Vertical standard deviation (n-1)", - " For every gridpoint the standard deviation over all levels is computed. Normalize by (n-1).", - " vertvar Vertical variance", - " For every gridpoint the variance over all levels is computed. Normalize by n.", - " vertvar1 Vertical variance (n-1)", - " For every gridpoint the variance over all levels is computed. Normalize by (n-1).", - "", - "PARAMETER", - " weights BOOL weights=FALSE disables weighting by layer thickness [default: weights=TRUE]", - nullptr -}; - -static const char *TimselstatHelp[] = { - "NAME", - " timselmin, timselmax, timselrange, timselsum, timselmean, timselavg, ", - " timselstd, timselstd1, timselvar, timselvar1 - Time range statistical values", - "", - "SYNOPSIS", - " <operator>,nsets[,noffset[,nskip]] infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values for a selected number of timesteps. According to ", - " the chosen operator the minimum, maximum, range, sum, average, variance or standard deviation of ", - " the selected timesteps is written to outfile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " timselmin Time selection minimum", - " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = min{i(t',x), t1 < t' <= tn}", - " timselmax Time selection maximum", - " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = max{i(t',x), t1 < t' <= tn}", - " timselrange Time selection range", - " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = range{i(t',x), t1 < t' <= tn}", - " timselsum Time selection sum", - " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = sum{i(t',x), t1 < t' <= tn}", - " timselmean Time selection mean", - " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = mean{i(t',x), t1 < t' <= tn}", - " timselavg Time selection average", - " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = avg{i(t',x), t1 < t' <= tn}", - " timselstd Time selection standard deviation", - " Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = std{i(t',x), t1 < t' <= tn}", - " timselstd1 Time selection standard deviation (n-1)", - " Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = std1{i(t',x), t1 < t' <= tn}", - " timselvar Time selection variance", - " Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = var{i(t',x), t1 < t' <= tn}", - " timselvar1 Time selection variance (n-1)", - " Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = var1{i(t',x), t1 < t' <= tn}", - "", - "PARAMETER", - " nsets INTEGER Number of input timesteps for each output timestep ", - " noffset INTEGER Number of input timesteps skipped before the first timestep range (optional)", - " nskip INTEGER Number of input timesteps skipped between timestep ranges (optional)", - nullptr -}; - -static const char *TimselpctlHelp[] = { - "NAME", - " timselpctl - Time range percentile values", - "", - "SYNOPSIS", - " timselpctl,p,nsets[,noffset[,nskip]] infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator computes percentile values over a selected number of timesteps in infile1.", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,", - " respectively. The default number of histogram bins is 101. The default can be overridden by setting the", - " environment variable CDO_PCTL_NBINS to a different value. The files infile2 and infile3 ", - " should be the result of corresponding timselmin and timselmax operations, respectively.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:", - " ", - " o(t,x) = pth percentile {i(t',x), t1 < t' <= tn}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - " nsets INTEGER Number of input timesteps for each output timestep ", - " noffset INTEGER Number of input timesteps skipped before the first timestep range (optional)", - " nskip INTEGER Number of input timesteps skipped between timestep ranges (optional)", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *RunstatHelp[] = { - "NAME", - " runmin, runmax, runrange, runsum, runmean, runavg, runstd, runstd1, runvar, ", - " runvar1 - Running statistical values", - "", - "SYNOPSIS", - " <operator>,nts infile outfile", - "", - "DESCRIPTION", - " This module computes running statistical values over a selected number of timesteps. Depending on ", - " the chosen operator the minimum, maximum, range, sum, average, variance or standard deviation of a selected ", - " number of consecutive timesteps read from infile is written to outfile. ", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " runmin Running minimum", - " o(t+(nts-1)/2,x) = min{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runmax Running maximum", - " o(t+(nts-1)/2,x) = max{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runrange Running range", - " o(t+(nts-1)/2,x) = range{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runsum Running sum", - " o(t+(nts-1)/2,x) = sum{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runmean Running mean", - " o(t+(nts-1)/2,x) = mean{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runavg Running average", - " o(t+(nts-1)/2,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runstd Running standard deviation", - " Normalize by n. ", - " ", - " o(t+(nts-1)/2,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runstd1 Running standard deviation (n-1)", - " Normalize by (n-1). ", - " ", - " o(t+(nts-1)/2,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runvar Running variance", - " Normalize by n. ", - " ", - " o(t+(nts-1)/2,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - " runvar1 Running variance (n-1)", - " Normalize by (n-1). ", - " ", - " o(t+(nts-1)/2,x) = var1{i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - "", - "PARAMETER", - " nts INTEGER Number of timesteps", - "", - "ENVIRONMENT", - " CDO_TIMESTAT_DATE", - " Sets the time stamp in outfile to the \"first\", \"middle\" or \"last\" contributing timestep of infile.", - nullptr -}; - -static const char *RunpctlHelp[] = { - "NAME", - " runpctl - Running percentile values", - "", - "SYNOPSIS", - " runpctl,p,nts infile outfile", - "", - "DESCRIPTION", - " This module computes running percentiles over a selected number of timesteps in infile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " ", - " o(t+(nts-1)/2,x) = pth percentile {i(t,x), i(t+1,x), ..., i(t+nts-1,x)}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - " nts INTEGER Number of timesteps", - nullptr -}; - -static const char *TimstatHelp[] = { - "NAME", - " timmin, timmax, timrange, timsum, timmean, timavg, timstd, timstd1, timvar, ", - " timvar1 - Statistical values over all timesteps", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over all timesteps in infile. Depending on ", - " the chosen operator the minimum, maximum, range, sum, average, variance or standard deviation of ", - " all timesteps read from infile is written to outfile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " timmin Time minimum", - " o(1,x) = min{i(t',x), t_1<t'<=t_n}", - " timmax Time maximum", - " o(1,x) = max{i(t',x), t_1<t'<=t_n}", - " timrange Time range", - " o(1,x) = range{i(t',x), t_1<t'<=t_n}", - " timsum Time sum", - " o(1,x) = sum{i(t',x), t_1<t'<=t_n}", - " timmean Time mean", - " o(1,x) = mean{i(t',x), t_1<t'<=t_n}", - " timavg Time average", - " o(1,x) = avg{i(t',x), t_1<t'<=t_n}", - " timstd Time standard deviation", - " Normalize by n. ", - " ", - " o(1,x) = std{i(t',x), t_1<t'<=t_n}", - " timstd1 Time standard deviation (n-1)", - " Normalize by (n-1). ", - " ", - " o(1,x) = std1{i(t',x), t_1<t'<=t_n}", - " timvar Time variance", - " Normalize by n. ", - " ", - " o(1,x) = var{i(t',x), t_1<t'<=t_n}", - " timvar1 Time variance (n-1)", - " Normalize by (n-1). ", - " ", - " o(1,x) = var1{i(t',x), t_1<t'<=t_n}", - nullptr -}; - -static const char *TimpctlHelp[] = { - "NAME", - " timpctl - Percentile values over all timesteps", - "", - "SYNOPSIS", - " timpctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator computes percentiles over all timesteps in infile1. The algorithm uses ", - " histograms with minimum and maximum bounds given in infile2 and infile3, respectively. ", - " The default number of histogram bins is 101. The default can be overridden by defining the", - " environment variable CDO_PCTL_NBINS. The files infile2 and infile3 should be", - " the result of corresponding timmin and timmax operations, respectively.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " ", - " o(1,x) = pth percentile {i(t',x), t_1<t'<=t_n}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *HourstatHelp[] = { - "NAME", - " hourmin, hourmax, hourrange, hoursum, hourmean, houravg, hourstd, hourstd1, ", - " hourvar, hourvar1 - Hourly statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over timesteps of the same hour.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of timesteps of the same hour is written to outfile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " hourmin Hourly minimum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = min{i(t',x), t_1<t'<=t_n}", - " hourmax Hourly maximum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = max{i(t',x), t_1<t'<=t_n}", - " hourrange Hourly range", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = range{i(t',x), t_1<t'<=t_n}", - " hoursum Hourly sum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", - " hourmean Hourly mean", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", - " houravg Hourly average", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", - " hourstd Hourly standard deviation", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = std{i(t',x), t_1<t'<=t_n}", - " hourstd1 Hourly standard deviation (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = std1{i(t',x), t_1<t'<=t_n}", - " hourvar Hourly variance", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = var{i(t',x), t_1<t'<=t_n}", - " hourvar1 Hourly variance (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = var1{i(t',x), t_1<t'<=t_n}", - nullptr -}; - -static const char *HourpctlHelp[] = { - "NAME", - " hourpctl - Hourly percentile values", - "", - "SYNOPSIS", - " hourpctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator computes percentiles over all timesteps of the same hour in infile1.", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", - " infile3, respectively. The default number of histogram bins is 101.", - " The default can be overridden by defining the environment variable CDO_PCTL_NBINS.", - " The files infile2 and infile3 should be the result of corresponding hourmin", - " and hourmax operations, respectively.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:", - " ", - " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *DaystatHelp[] = { - "NAME", - " daymin, daymax, dayrange, daysum, daymean, dayavg, daystd, daystd1, dayvar, ", - " dayvar1 - Daily statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over timesteps of the same day.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of timesteps of the same day is written to outfile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " daymin Daily minimum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = min{i(t',x), t_1<t'<=t_n}", - " daymax Daily maximum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = max{i(t',x), t_1<t'<=t_n}", - " dayrange Daily range", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = range{i(t',x), t_1<t'<=t_n}", - " daysum Daily sum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", - " daymean Daily mean", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", - " dayavg Daily average", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", - " daystd Daily standard deviation", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = std{i(t',x), t_1<t'<=t_n}", - " daystd1 Daily standard deviation (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = std1{i(t',x), t_1<t'<=t_n}", - " dayvar Daily variance", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = var{i(t',x), t_1<t'<=t_n}", - " dayvar1 Daily variance (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = var1{i(t',x), t_1<t'<=t_n}", - nullptr -}; - -static const char *DaypctlHelp[] = { - "NAME", - " daypctl - Daily percentile values", - "", - "SYNOPSIS", - " daypctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator computes percentiles over all timesteps of the same day in infile1.", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", - " infile3, respectively. The default number of histogram bins is 101.", - " The default can be overridden by defining the environment variable CDO_PCTL_NBINS.", - " The files infile2 and infile3 should be the result of corresponding daymin", - " and daymax operations, respectively.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:", - " ", - " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *MonstatHelp[] = { - "NAME", - " monmin, monmax, monrange, monsum, monmean, monavg, monstd, monstd1, monvar, ", - " monvar1 - Monthly statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over timesteps of the same month.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of timesteps of the same month is written to outfile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " monmin Monthly minimum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = min{i(t',x), t_1<t'<=t_n}", - " monmax Monthly maximum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = max{i(t',x), t_1<t'<=t_n}", - " monrange Monthly range", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = range{i(t',x), t_1<t'<=t_n}", - " monsum Monthly sum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", - " monmean Monthly mean", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", - " monavg Monthly average", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", - " monstd Monthly standard deviation", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = std{i(t',x), t_1 < t' <= t_n}", - " monstd1 Monthly standard deviation (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = std1{i(t',x), t_1 < t' <= t_n}", - " monvar Monthly variance", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = var{i(t',x), t_1 < t' <= t_n}", - " monvar1 Monthly variance (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = var1{i(t',x), t_1 < t' <= t_n}", - nullptr -}; - -static const char *MonpctlHelp[] = { - "NAME", - " monpctl - Monthly percentile values", - "", - "SYNOPSIS", - " monpctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator computes percentiles over all timesteps of the same month in infile1.", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", - " infile3, respectively. The default number of histogram bins is 101.", - " The default can be overridden by defining the environment variable CDO_PCTL_NBINS.", - " The files infile2 and infile3 should be the result of corresponding monmin", - " and monmax operations, respectively.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:", - " ", - " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *YearmonstatHelp[] = { - "NAME", - " yearmonmean - Yearly mean from monthly data", - "", - "SYNOPSIS", - " yearmonmean infile outfile", - "", - "DESCRIPTION", - " This operator computes the yearly mean of a monthly time series.", - " Each month is weighted with the number of days per month. ", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " ", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", - "", - "ENVIRONMENT", - " CDO_TIMESTAT_DATE", - " Sets the date information in outfile to the \"first\", \"middle\" or \"last\" contributing timestep of infile.", - nullptr -}; - -static const char *YearstatHelp[] = { - "NAME", - " yearmin, yearmax, yearminidx, yearmaxidx, yearrange, yearsum, yearmean, ", - " yearavg, yearstd, yearstd1, yearvar, yearvar1 - Yearly statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over timesteps of the same year.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of timesteps of the same year is written to outfile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " yearmin Yearly minimum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = min{i(t',x), t_1<t'<=t_n}", - " yearmax Yearly maximum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = max{i(t',x), t_1<t'<=t_n}", - " yearminidx Yearly minimum indices", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = minidx{i(t',x), t_1<t'<=t_n}", - " yearmaxidx Yearly maximum indices", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = maxidx{i(t',x), t_1<t'<=t_n}", - " yearrange Yearly range", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = range{i(t',x), t_1<t'<=t_n}", - " yearsum Yearly sum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = sum{i(t',x), t_1<t'<=t_n}", - " yearmean Yearly mean", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = mean{i(t',x), t_1<t'<=t_n}", - " yearavg Yearly average", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = avg{i(t',x), t_1<t'<=t_n}", - " yearstd Yearly standard deviation", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = std{i(t',x), t_1 < t' <= t_n}", - " yearstd1 Yearly standard deviation (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = std1{i(t',x), t_1 < t' <= t_n}", - " yearvar Yearly variance", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = var{i(t',x), t_1 < t' <= t_n}", - " yearvar1 Yearly variance (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = var1{i(t',x), t_1 < t' <= t_n}", - "", - "NOTE", - " The operators yearmean and yearavg compute only arithmetical means!", - nullptr -}; - -static const char *YearpctlHelp[] = { - "NAME", - " yearpctl - Yearly percentile values", - "", - "SYNOPSIS", - " yearpctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator computes percentiles over all timesteps of the same year in infile1.", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", - " infile3, respectively. The default number of histogram bins is 101. The default can be", - " overridden by defining the environment variable CDO_PCTL_NBINS. The files infile2 and", - " infile3 should be the result of corresponding yearmin and yearmax operations, respectively.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:", - " ", - " o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *SeasstatHelp[] = { - "NAME", - " seasmin, seasmax, seasrange, seassum, seasmean, seasavg, seasstd, seasstd1, ", - " seasvar, seasvar1 - Seasonal statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values over timesteps of the same season.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of timesteps of the same season is written to outfile.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " Be careful about the first and the last output timestep, they may be incorrect values ", - " if the seasons have incomplete timesteps.", - "", - "OPERATORS", - " seasmin Seasonal minimum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = min{i(t',x), t1 < t' <= tn}", - " seasmax Seasonal maximum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = max{i(t',x), t1 < t' <= tn}", - " seasrange Seasonal range", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = range{i(t',x), t1 < t' <= tn}", - " seassum Seasonal sum", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = sum{i(t',x), t1 < t' <= tn}", - " seasmean Seasonal mean", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = mean{i(t',x), t1 < t' <= tn}", - " seasavg Seasonal average", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = avg{i(t',x), t1 < t' <= tn}", - " seasstd Seasonal standard deviation", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = std{i(t',x), t1 < t' <= tn}", - " seasstd1 Seasonal standard deviation (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = std1{i(t',x), t1 < t' <= tn}", - " seasvar Seasonal variance", - " Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = var{i(t',x), t1 < t' <= tn}", - " seasvar1 Seasonal variance (n-1)", - " Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = var1{i(t',x), t1 < t' <= tn}", - nullptr -}; - -static const char *SeaspctlHelp[] = { - "NAME", - " seaspctl - Seasonal percentile values", - "", - "SYNOPSIS", - " seaspctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator computes percentiles over all timesteps in infile1 of the same season.", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,", - " respectively. The default number of histogram bins is 101. The default can be overridden", - " by defining the environment variable CDO_PCTL_NBINS. The files infile2 and infile3", - " should be the result of corresponding seasmin and seasmax operations, respectively.", - " The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - " Be careful about the first and the last output timestep, they may be incorrect values ", - " if the seasons have incomplete timesteps.", - " For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:", - " ", - " o(t,x) = pth percentile {i(t',x), t1 < t' <= tn}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *YhourstatHelp[] = { - "NAME", - " yhourmin, yhourmax, yhourrange, yhoursum, yhourmean, yhouravg, yhourstd, ", - " yhourstd1, yhourvar, yhourvar1 - Multi-year hourly statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values of each hour and day of year.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of each hour and day of year in infile is written to outfile.", - " The date information in an output field is the date of the last contributing input field.", - "", - "OPERATORS", - " yhourmin Multi-year hourly minimum", - " o(0001,x) = min{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = min{i(t,x), day(i(t)) = 8784}", - " yhourmax Multi-year hourly maximum", - " o(0001,x) = max{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = max{i(t,x), day(i(t)) = 8784}", - " yhourrange Multi-year hourly range", - " o(0001,x) = range{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = range{i(t,x), day(i(t)) = 8784}", - " yhoursum Multi-year hourly sum", - " o(0001,x) = sum{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = sum{i(t,x), day(i(t)) = 8784}", - " yhourmean Multi-year hourly mean", - " o(0001,x) = mean{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = mean{i(t,x), day(i(t)) = 8784}", - " yhouravg Multi-year hourly average", - " o(0001,x) = avg{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = avg{i(t,x), day(i(t)) = 8784}", - " yhourstd Multi-year hourly standard deviation", - " Normalize by n. ", - " ", - " o(0001,x) = std{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = std{i(t,x), day(i(t)) = 8784}", - " yhourstd1 Multi-year hourly standard deviation (n-1)", - " Normalize by (n-1). ", - " ", - " o(0001,x) = std1{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = std1{i(t,x), day(i(t)) = 8784}", - " yhourvar Multi-year hourly variance", - " Normalize by n. ", - " ", - " o(0001,x) = var{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = var{i(t,x), day(i(t)) = 8784}", - " yhourvar1 Multi-year hourly variance (n-1)", - " Normalize by (n-1). ", - " ", - " o(0001,x) = var1{i(t,x), day(i(t)) = 0001}", - " ...", - " o(8784,x) = var1{i(t,x), day(i(t)) = 8784}", - nullptr -}; - -static const char *DhourstatHelp[] = { - "NAME", - " dhourmin, dhourmax, dhourrange, dhoursum, dhourmean, dhouravg, dhourstd, ", - " dhourstd1, dhourvar, dhourvar1 - Multi-day hourly statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values of each hour of day.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of each hour of day in infile is written to outfile.", - " The date information in an output field is the date of the last contributing input field.", - "", - "OPERATORS", - " dhourmin Multi-day hourly minimum", - " o(01,x) = min{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = min{i(t,x), day(i(t)) = 24}", - " dhourmax Multi-day hourly maximum", - " o(01,x) = max{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = max{i(t,x), day(i(t)) = 24}", - " dhourrange Multi-day hourly range", - " o(01,x) = range{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = range{i(t,x), day(i(t)) = 24}", - " dhoursum Multi-day hourly sum", - " o(01,x) = sum{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = sum{i(t,x), day(i(t)) = 24}", - " dhourmean Multi-day hourly mean", - " o(01,x) = mean{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = mean{i(t,x), day(i(t)) = 24}", - " dhouravg Multi-day hourly average", - " o(01,x) = avg{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = avg{i(t,x), day(i(t)) = 24}", - " dhourstd Multi-day hourly standard deviation", - " Normalize by n. ", - " ", - " o(01,x) = std{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = std{i(t,x), day(i(t)) = 24}", - " dhourstd1 Multi-day hourly standard deviation (n-1)", - " Normalize by (n-1). ", - " ", - " o(01,x) = std1{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = std1{i(t,x), day(i(t)) = 24}", - " dhourvar Multi-day hourly variance", - " Normalize by n. ", - " ", - " o(01,x) = var{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = var{i(t,x), day(i(t)) = 24}", - " dhourvar1 Multi-day hourly variance (n-1)", - " Normalize by (n-1). ", - " ", - " o(01,x) = var1{i(t,x), day(i(t)) = 01}", - " ...", - " o(24,x) = var1{i(t,x), day(i(t)) = 24}", - nullptr -}; - -static const char *YdaystatHelp[] = { - "NAME", - " ydaymin, ydaymax, ydayrange, ydaysum, ydaymean, ydayavg, ydaystd, ydaystd1, ", - " ydayvar, ydayvar1 - Multi-year daily statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values of each day of year.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of each day of year in infile is written to outfile.", - " The date information in an output field is the date of the last contributing input field.", - "", - "OPERATORS", - " ydaymin Multi-year daily minimum", - " o(001,x) = min{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = min{i(t,x), day(i(t)) = 366}", - " ydaymax Multi-year daily maximum", - " o(001,x) = max{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = max{i(t,x), day(i(t)) = 366}", - " ydayrange Multi-year daily range", - " o(001,x) = range{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = range{i(t,x), day(i(t)) = 366}", - " ydaysum Multi-year daily sum", - " o(001,x) = sum{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = sum{i(t,x), day(i(t)) = 366}", - " ydaymean Multi-year daily mean", - " o(001,x) = mean{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = mean{i(t,x), day(i(t)) = 366}", - " ydayavg Multi-year daily average", - " o(001,x) = avg{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = avg{i(t,x), day(i(t)) = 366}", - " ydaystd Multi-year daily standard deviation", - " Normalize by n. ", - " ", - " o(001,x) = std{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = std{i(t,x), day(i(t)) = 366}", - " ydaystd1 Multi-year daily standard deviation (n-1)", - " Normalize by (n-1). ", - " ", - " o(001,x) = std1{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = std1{i(t,x), day(i(t)) = 366}", - " ydayvar Multi-year daily variance", - " Normalize by n. ", - " ", - " o(001,x) = var{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = var{i(t,x), day(i(t)) = 366}", - " ydayvar1 Multi-year daily variance (n-1)", - " Normalize by (n-1). ", - " ", - " o(001,x) = var1{i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = var1{i(t,x), day(i(t)) = 366}", - nullptr -}; - -static const char *YdaypctlHelp[] = { - "NAME", - " ydaypctl - Multi-year daily percentile values", - "", - "SYNOPSIS", - " ydaypctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator writes a certain percentile of each day of year in infile1 to outfile.", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and", - " infile3, respectively. The default number of histogram bins is 101. The default can be", - " overridden by setting the environment variable CDO_PCTL_NBINS to a different value.", - " The files infile2 and infile3 should be the result of corresponding ydaymin and", - " ydaymax operations, respectively.", - " The date information in an output field is the date of the last contributing input field.", - " ", - " o(001,x) = pth percentile {i(t,x), day(i(t)) = 001}", - " ...", - " o(366,x) = pth percentile {i(t,x), day(i(t)) = 366}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *YmonstatHelp[] = { - "NAME", - " ymonmin, ymonmax, ymonrange, ymonsum, ymonmean, ymonavg, ymonstd, ymonstd1, ", - " ymonvar, ymonvar1 - Multi-year monthly statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values of each month of year.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of each month of year in infile is written to outfile.", - " The date information in an output field is the date of the last contributing input field.", - " This can be change with the CDO option --timestat_date <first|middle|last>.", - "", - "OPERATORS", - " ymonmin Multi-year monthly minimum", - " o(01,x) = min{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = min{i(t,x), month(i(t)) = 12}", - " ymonmax Multi-year monthly maximum", - " o(01,x) = max{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = max{i(t,x), month(i(t)) = 12}", - " ymonrange Multi-year monthly range", - " o(01,x) = range{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = range{i(t,x), month(i(t)) = 12}", - " ymonsum Multi-year monthly sum", - " o(01,x) = sum{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = sum{i(t,x), month(i(t)) = 12}", - " ymonmean Multi-year monthly mean", - " o(01,x) = mean{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = mean{i(t,x), month(i(t)) = 12}", - " ymonavg Multi-year monthly average", - " o(01,x) = avg{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = avg{i(t,x), month(i(t)) = 12}", - " ymonstd Multi-year monthly standard deviation", - " Normalize by n. ", - " ", - " o(01,x) = std{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = std{i(t,x), month(i(t)) = 12}", - " ymonstd1 Multi-year monthly standard deviation (n-1)", - " Normalize by (n-1). ", - " ", - " o(01,x) = std1{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = std1{i(t,x), month(i(t)) = 12}", - " ymonvar Multi-year monthly variance", - " Normalize by n. ", - " ", - " o(01,x) = var{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = var{i(t,x), month(i(t)) = 12}", - " ymonvar1 Multi-year monthly variance (n-1)", - " Normalize by (n-1). ", - " ", - " o(01,x) = var1{i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = var1{i(t,x), month(i(t)) = 12}", - nullptr -}; - -static const char *YmonpctlHelp[] = { - "NAME", - " ymonpctl - Multi-year monthly percentile values", - "", - "SYNOPSIS", - " ymonpctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator writes a certain percentile of each month of year in infile1 to outfile.", - " The algorithm uses histograms with minimum and maximum bounds given in", - " infile2 and infile3, respectively. The default number of", - " histogram bins is 101. The default can be overridden by setting the", - " environment variable CDO_PCTL_NBINS to a different value. The files", - " infile2 and infile3 should be the result of corresponding", - " ymonmin and ymonmax operations, respectively.", - " The date information in an output field is the date of the last", - " contributing input field.", - " ", - " o(01,x) = pth percentile {i(t,x), month(i(t)) = 01}", - " ...", - " o(12,x) = pth percentile {i(t,x), month(i(t)) = 12}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *YseasstatHelp[] = { - "NAME", - " yseasmin, yseasmax, yseasrange, yseassum, yseasmean, yseasavg, yseasstd, ", - " yseasstd1, yseasvar, yseasvar1 - Multi-year seasonal statistical values", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module computes statistical values of each season.", - " Depending on the chosen operator the minimum, maximum, range, sum, average, variance", - " or standard deviation of each season in infile is written to outfile.", - " The date information in an output field is the date of the last contributing input field.", - "", - "OPERATORS", - " yseasmin Multi-year seasonal minimum", - " o(1,x) = min{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = min{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = min{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = min{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasmax Multi-year seasonal maximum", - " o(1,x) = max{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = max{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = max{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = max{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasrange Multi-year seasonal range", - " o(1,x) = range{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = range{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = range{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = range{i(t,x), month(i(t)) = 09, 10, 11}", - " yseassum Multi-year seasonal sum", - " o(1,x) = sum{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = sum{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = sum{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = sum{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasmean Multi-year seasonal mean", - " o(1,x) = mean{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = mean{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = mean{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = mean{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasavg Multi-year seasonal average", - " o(1,x) = avg{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = avg{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = avg{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = avg{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasstd Multi-year seasonal standard deviation", - " o(1,x) = std{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = std{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = std{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = std{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasstd1 Multi-year seasonal standard deviation (n-1)", - " o(1,x) = std1{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = std1{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = std1{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = std1{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasvar Multi-year seasonal variance", - " o(1,x) = var{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = var{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = var{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = var{i(t,x), month(i(t)) = 09, 10, 11}", - " yseasvar1 Multi-year seasonal variance (n-1)", - " o(1,x) = var1{i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = var1{i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = var1{i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = var1{i(t,x), month(i(t)) = 09, 10, 11}", - nullptr -}; - -static const char *YseaspctlHelp[] = { - "NAME", - " yseaspctl - Multi-year seasonal percentile values", - "", - "SYNOPSIS", - " yseaspctl,p infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator writes a certain percentile of each season in infile1 to outfile.", - " The algorithm uses histograms with minimum and maximum bounds given in", - " infile2 and infile3, respectively. The default number of", - " histogram bins is 101. The default can be overridden by setting the", - " environment variable CDO_PCTL_NBINS to a different value. The files", - " infile2 and infile3 should be the result of corresponding", - " yseasmin and yseasmax operations, respectively.", - " The date information in an output field is the date of the last", - " contributing input field.", - " ", - " o(1,x) = pth percentile {i(t,x), month(i(t)) = 12, 01, 02}", - " o(2,x) = pth percentile {i(t,x), month(i(t)) = 03, 04, 05}", - " o(3,x) = pth percentile {i(t,x), month(i(t)) = 06, 07, 08}", - " o(4,x) = pth percentile {i(t,x), month(i(t)) = 09, 10, 11}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *YdrunstatHelp[] = { - "NAME", - " ydrunmin, ydrunmax, ydrunsum, ydrunmean, ydrunavg, ydrunstd, ydrunstd1, ", - " ydrunvar, ydrunvar1 - Multi-year daily running statistical values", - "", - "SYNOPSIS", - " <operator>,nts infile outfile", - "", - "DESCRIPTION", - " This module writes running statistical values for each day of year in infile to outfile.", - " Depending on the chosen operator, the minimum, maximum, sum, average, variance or standard deviation ", - " of all timesteps in running windows of which the medium timestep corresponds to a certain day of", - " year is computed. The date information in an output field is the date of the timestep in the middle ", - " of the last contributing running window.", - " Note that the operator have to be applied to a continuous time series of daily measurements in order ", - " to yield physically meaningful results. Also note that the output time series begins (nts-1)/2 timesteps", - " after the first timestep of the input time series and ends (nts-1)/2 timesteps before the last one.", - " For input data which are complete but not continuous, such as time series of daily measurements for ", - " the same month or season within different years, the operator yields physically meaningful results ", - " only if the input time series does include the (nts-1)/2 days before and after each period of interest.", - "", - "OPERATORS", - " ydrunmin Multi-year daily running minimum", - " o(001,x) = min{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = min{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", - " ydrunmax Multi-year daily running maximum", - " o(001,x) = max{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = max{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", - " ydrunsum Multi-year daily running sum", - " o(001,x) = sum{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = sum{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", - " ydrunmean Multi-year daily running mean", - " o(001,x) = mean{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = mean{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", - " ydrunavg Multi-year daily running average", - " o(001,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = avg{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", - " ydrunstd Multi-year daily running standard deviation", - " Normalize by n. ", - " ", - " o(001,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = std{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 366}", - " ydrunstd1 Multi-year daily running standard deviation (n-1)", - " Normalize by (n-1). ", - " ", - " o(001,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = std1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[i(t+(nts-1)/2)] = 366}", - " ydrunvar Multi-year daily running variance", - " Normalize by n. ", - " ", - " o(001,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = var{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", - " ydrunvar1 Multi-year daily running variance (n-1)", - " Normalize by (n-1). ", - " ", - " o(001,x) = var1{i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " 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", - nullptr -}; - -static const char *YdrunpctlHelp[] = { - "NAME", - " ydrunpctl - Multi-year daily running percentile values", - "", - "SYNOPSIS", - " ydrunpctl,p,nts infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This operator writes running percentile values for each day of year in infile1 to outfile. ", - " A certain percentile is computed for all timesteps in running windows of which the medium ", - " timestep corresponds to a certain day of year. ", - " The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,", - " respectively. The default number of histogram bins is 101. The default can be overridden", - " by setting the environment variable CDO_PCTL_NBINS to a different value. The files infile2 ", - " and infile3 should be the result of corresponding ydrunmin and ydrunmax operations, respectively.", - " The date information in an output field is the date of the timestep in the middle of the last contributing running window.", - " Note that the operator have to be applied to a continuous time series of daily measurements ", - " in order to yield physically meaningful results. Also note that the output time series begins", - " (nts-1)/2 timesteps after the first timestep of the input time series and ends (nts-1)/2 ", - " timesteps before the last.", - " For input data which are complete but not continuous, such as time series of daily measurements ", - " for the same month or season within different years, the operator only yields physically meaningful ", - " results if the input time series does include the (nts-1)/2 days before and after each period ", - " of interest.", - " ", - " o(001,x) = pth percentile {i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 001}", - " ...", - " o(366,x) = pth percentile {i(t,x), i(t+1,x), ..., i(t+nts-1,x); day[(i(t+(nts-1)/2)] = 366}", - "", - "PARAMETER", - " p FLOAT Percentile number in {0, ..., 100}", - " nts INTEGER Number of timesteps", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; - -static const char *FldcorHelp[] = { - "NAME", - " fldcor - Correlation in grid space", - "", - "SYNOPSIS", - " fldcor infile1 infile2 outfile", - "", - "DESCRIPTION", - " The correlation coefficient is a quantity that gives the quality of a least ", - " squares fitting to the original data. This operator correlates all gridpoints", - " of two fields for each timestep. With", - " ", - " S(t) = {x, i_1(t,x) != missval and i_2(t,x) != missval}", - " ", - " it is", - " ", - " o(t,1) = Cor{(i_1(t,x), i_2(t,x)), x_1 < x <= x_n}", - " ", - " where w(x) are the area weights obtained by the input streams.", - " For every timestep t only those field elements x belong to the sample,", - " which have i_1(t,x) != missval and i_2(t,x) != missval.", - nullptr -}; - -static const char *TimcorHelp[] = { - "NAME", - " timcor - Correlation over time", - "", - "SYNOPSIS", - " timcor infile1 infile2 outfile", - "", - "DESCRIPTION", - " The correlation coefficient is a quantity that gives the quality of a least ", - " squares fitting to the original data. This operator correlates each gridpoint", - " of two fields over all timesteps. With", - " ", - " S(x) = {t, i_1(t,x) != missval and i_2(t,x) != missval}", - " ", - " it is", - " ", - " o(1,x) = Cor{(i_1(t,x), i_2(t,x)), t_1 < t <= t_n}", - " ", - " For every gridpoint x only those timesteps t belong to the sample,", - " which have i_1(t,x) != missval and i_2(t,x) != missval.", - nullptr -}; - -static const char *FldcovarHelp[] = { - "NAME", - " fldcovar - Covariance in grid space", - "", - "SYNOPSIS", - " fldcovar infile1 infile2 outfile", - "", - "DESCRIPTION", - " This operator calculates the covariance of two fields over all gridpoints", - " for each timestep. With", - " ", - " S(t) = {x, i_1(t,x) != missval and i_2(t,x) != missval}", - " ", - " it is", - " ", - " o(t,1) = Covar{(i_1(t,x), i_2(t,x)), x_1 < x <= x_n}", - " ", - " where w(x) are the area weights obtained by the input streams.", - " For every timestep t only those field elements x belong to the sample,", - " which have i_1(t,x) != missval and i_2(t,x) != missval.", - nullptr -}; - -static const char *TimcovarHelp[] = { - "NAME", - " timcovar - Covariance over time", - "", - "SYNOPSIS", - " timcovar infile1 infile2 outfile", - "", - "DESCRIPTION", - " This operator calculates the covariance of two fields at each gridpoint", - " over all timesteps. With", - " ", - " S(x) = {t, i_1(t,x) != missval and i_2(t,x) != missval}", - " ", - " it is", - " ", - " o(1,x) = Covar{(i_1(t,x), i_2(t,x)), t_1 < t <= t_n}", - " ", - " For every gridpoint x only those timesteps t belong to the sample,", - " which have i_1(t,x) != missval and i_2(t,x) != missval.", - nullptr -}; - -static const char *RegresHelp[] = { - "NAME", - " regres - Regression", - "", - "SYNOPSIS", - " regres[,equal] infile outfile", - "", - "DESCRIPTION", - " The values of the input file infile are assumed to be distributed as", - " N(a+b*t,S^2) with unknown a, b and S^2. This operator estimates the", - " parameter b. For every field element x only those timesteps ", - " t belong to the sample S(x), which have i(t,x) NE miss.", - " It is assumed that all timesteps are equidistant, if this is not the case set the parameter equal=false.", - "", - "PARAMETER", - " equal BOOL Set to false for unequal distributed timesteps (default: true)", - nullptr -}; - -static const char *DetrendHelp[] = { - "NAME", - " detrend - Detrend time series", - "", - "SYNOPSIS", - " detrend[,equal] infile outfile", - "", - "DESCRIPTION", - " Every time series in infile is linearly detrended. For every field element x ", - " only those timesteps t belong to the sample S(x), which have i(t,x) NE miss.", - " It is assumed that all timesteps are equidistant, if this is not the case set the parameter equal=false.", - "", - "PARAMETER", - " equal BOOL Set to false for unequal distributed timesteps (default: true)", - "", - "NOTE", - " This operator has to keep the fields of all timesteps concurrently in the memory.", - " If not enough memory is available use the operators trend and subtrend.", - nullptr -}; - -static const char *TrendHelp[] = { - "NAME", - " trend - Trend of time series", - "", - "SYNOPSIS", - " trend[,equal] infile outfile1 outfile2", - "", - "DESCRIPTION", - " The values of the input file infile are assumed to be distributed as", - " N(a+b*t,S^2) with unknown a, b and S^2. This operator estimates the", - " parameter a and b. For every field element x only those timesteps ", - " t belong to the sample S(x), which have i(t,x) NE miss.", - " Thus the estimation for a is stored in outfile1 and that for b is stored ", - " in outfile2. To subtract the trend from the data see operator subtrend.", - " It is assumed that all timesteps are equidistant, if this is not the case set the parameter equal=false.", - "", - "PARAMETER", - " equal BOOL Set to false for unequal distributed timesteps (default: true)", - nullptr -}; - -static const char *TrendarithHelp[] = { - "NAME", - " addtrend, subtrend - Add or subtract a trend", - "", - "SYNOPSIS", - " <operator>[,equal] infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This module is for adding or subtracting a trend computed by the operator trend.", - "", - "OPERATORS", - " addtrend Add trend", - " It is", - " ", - " o(t,x) = i_1(t,x) + (i_2(1,x) + i_3(1,x)*t)", - " where t is the timesteps.", - " subtrend Subtract trend", - " It is", - " ", - " o(t,x) = i_1(t,x) - (i_2(1,x) + i_3(1,x)*t)", - " where t is the timesteps.", - "", - "PARAMETER", - " equal BOOL Set to false for unequal distributed timesteps (default: true)", - nullptr -}; - -static const char *EOFsHelp[] = { - "NAME", - " eof, eoftime, eofspatial, eof3d - Empirical Orthogonal Functions", - "", - "SYNOPSIS", - " <operator>,neof infile outfile1 outfile2", - "", - "DESCRIPTION", - " This module calculates empirical orthogonal functions of the data in infile ", - " as the eigen values of the scatter matrix (covariance matrix) S of the data", - " sample z(t). A more detailed description can be found above.", - " ", - " Please note, that the input data are assumed to be anomalies.", - " ", - " If operator eof is chosen, the EOFs are computed in either time or spatial", - " space, whichever is the fastest. If the user already knows, which computation", - " is faster, the module can be forced to perform a computation in time- or gridspace", - " by using the operators eoftime or eofspatial, respectively. This can enhance ", - " performance, especially for very long time series, where the number of timesteps", - " is larger than the number of grid-points. Data in infile are assumed to be anomalies.", - " If they are not, the behavior of this module is not well defined. ", - " After execution outfile1 will contain all eigen-values and outfile2 the", - " eigenvectors e_j. All EOFs and eigen-values are computed. However, only the first ", - " neof EOFs are written to outfile2. Nonetheless, outfile1 contains all eigen-values. ", - " ", - " Missing values are not fully supported. Support is only checked for non-changing", - " masks of missing values in time. Although there still will be results, they are", - " not trustworthy, and a warning will occur. In the latter case we suggest to ", - " replace missing values by 0 in infile. ", - "", - "OPERATORS", - " eof Calculate EOFs in spatial or time space", - " eoftime Calculate EOFs in time space", - " eofspatial Calculate EOFs in spatial space", - " eof3d Calculate 3-Dimensional EOFs in time space", - "", - "PARAMETER", - " neof INTEGER Number of eigen functions", - "", - "ENVIRONMENT", - " CDO_SVD_MODE ", - " Is used to choose the algorithm for eigenvalue calculation. Options are 'jacobi' for ", - " a one-sided parallel jacobi-algorithm (only executed in parallel if -P flag is set)", - " and 'danielson_lanczos' for a non-parallel d/l algorithm. The default setting is 'jacobi'.", - " CDO_WEIGHT_MODE", - " It is used to set the weight mode. The default is 'off'. Set it to 'on' for a weighted version.", - " MAX_JACOBI_ITER", - " Is the maximum integer number of annihilation sweeps that is executed if the ", - " jacobi-algorithm is used to compute the eigen values. The default value is 12.", - " FNORM_PRECISION", - " Is the Frobenius norm of the matrix consisting of an annihilation pair", - " of eigenvectors that is used to determine if the eigenvectors have reached ", - " a sufficient level of convergence. If all annihilation-pairs of vectors have ", - " a norm below this value, the computation is considered to have converged ", - " properly. Otherwise, a warning will occur. The default value 1e-12.", - nullptr -}; - -static const char *EofcoeffHelp[] = { - "NAME", - " eofcoeff - Principal coefficients of EOFs", - "", - "SYNOPSIS", - " eofcoeff infile1 infile2 obase", - "", - "DESCRIPTION", - " This module calculates the time series of the principal coefficients for given EOF", - " (empirical orthogonal functions) and data. Time steps in infile1 are assumed to be the EOFs,", - " time steps in infile2 are assumed to be the time series.", - " Note, that this operator calculates a non weighted dot product of the fields in infile1 and infile2.", - " For consistency set the environment variable CDO_WEIGHT_MODE=off when using eof or eof3d.", - " ", - " There will be a separate file containing a time series of principal coefficients", - " with time information from infile2 for each EOF in infile1. Output files will be", - " numbered as <obase><neof><suffix> where neof+1 is the number of the EOF (timestep)", - " in infile1 and suffix is the filename extension derived from the file format. ", - "", - "ENVIRONMENT", - " CDO_FILE_SUFFIX", - " Set the default file suffix. This suffix will be added to the output file ", - " names instead of the filename extension derived from the file format. ", - " Set this variable to NULL to disable the adding of a file suffix.", - nullptr -}; - -static const char *RemapbilHelp[] = { - "NAME", - " remapbil, genbil - Bilinear interpolation", - "", - "SYNOPSIS", - " remapbil,grid infile outfile", - " genbil,grid[,map3d] infile outfile", - "", - "DESCRIPTION", - " This module contains operators for a bilinear remapping of fields between grids in spherical coordinates.", - " The interpolation is based on an adapted SCRIP library version. ", - " For a detailed description of the interpolation method see SCRIP.", - " This interpolation method only works on quadrilateral curvilinear source grids.", - "", - "OPERATORS", - " remapbil Bilinear interpolation", - " Performs a bilinear interpolation on all input fields.", - " genbil Generate bilinear interpolation weights", - " Generates bilinear interpolation weights for the first input field and writes the", - " result to a file. The format of this file is NetCDF following the SCRIP convention.", - " Use the operator remap to apply this remapping weights to a data file with the same source grid.", - " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", - " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - " map3d BOOL Generate all mapfiles of the first 3D field", - "", - "ENVIRONMENT", - " REMAP_EXTRAPOLATE", - " This variable is used to switch the extrapolation feature 'on' or 'off'.", - " By default the extrapolation is enabled for circular grids.", - nullptr -}; - -static const char *RemapbicHelp[] = { - "NAME", - " remapbic, genbic - Bicubic interpolation", - "", - "SYNOPSIS", - " remapbic,grid infile outfile", - " genbic,grid[,map3d] infile outfile", - "", - "DESCRIPTION", - " This module contains operators for a bicubic remapping of fields between grids in spherical coordinates.", - " The interpolation is based on an adapted SCRIP library version. ", - " For a detailed description of the interpolation method see SCRIP.", - " This interpolation method only works on quadrilateral curvilinear source grids.", - "", - "OPERATORS", - " remapbic Bicubic interpolation", - " Performs a bicubic interpolation on all input fields.", - " genbic Generate bicubic interpolation weights", - " Generates bicubic interpolation weights for the first input field and writes the", - " result to a file. The format of this file is NetCDF following the SCRIP convention.", - " Use the operator remap to apply this remapping weights to a data file with the same source grid.", - " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", - " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - " map3d BOOL Generate all mapfiles of the first 3D field", - "", - "ENVIRONMENT", - " REMAP_EXTRAPOLATE", - " This variable is used to switch the extrapolation feature 'on' or 'off'.", - " By default the extrapolation is enabled for circular grids.", - nullptr -}; - -static const char *RemapnnHelp[] = { - "NAME", - " remapnn, gennn - Nearest neighbor remapping", - "", - "SYNOPSIS", - " remapnn,grid infile outfile", - " gennn,grid[,map3d] infile outfile", - "", - "DESCRIPTION", - " This module contains operators for a nearest neighbor remapping of fields between grids", - " in spherical coordinates.", - "", - "OPERATORS", - " remapnn Nearest neighbor remapping", - " Performs a nearest neighbor remapping on all input fields.", - " gennn Generate nearest neighbor remap weights", - " Generates nearest neighbor remapping weights for the first input field and writes the result to a file.", - " The format of this file is NetCDF following the SCRIP convention.", - " Use the operator remap to apply this remapping weights to a data file with the same source grid.", - " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", - " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - " map3d BOOL Generate all mapfiles of the first 3D field", - "", - "ENVIRONMENT", - " REMAP_EXTRAPOLATE ", - " This variable is used to switch the extrapolation feature 'on' or 'off'.", - " By default the extrapolation is enabled for this remapping method.", - " CDO_GRIDSEARCH_RADIUS", - " Grid search radius in degree, default 180 degree.", - nullptr -}; - -static const char *RemapdisHelp[] = { - "NAME", - " remapdis, gendis - Distance weighted average remapping", - "", - "SYNOPSIS", - " remapdis,grid[,neighbors] infile outfile", - " gendis,grid[,neighbors[,map3d]] infile outfile", - "", - "DESCRIPTION", - " This module contains operators for an inverse distance weighted average remapping of the four", - " nearest neighbor values of fields between grids in spherical coordinates.", - " The default number of 4 neighbors can be changed with the neighbors parameter.", - "", - "OPERATORS", - " remapdis Distance weighted average remapping", - " Performs an inverse distance weighted averaged remapping of the nearest neighbor values on all input fields.", - " gendis Generate distance weighted average remap weights", - " Generates distance weighted averaged remapping weights of the nearest neighbor values for the first input", - " field and writes the result to a file. The format of this file is NetCDF following the SCRIP convention.", - " Use the operator remap to apply this remapping weights to a data file with the same source grid.", - " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", - " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - " neighbors INTEGER Number of nearest neighbors [default: 4]", - " map3d BOOL Generate all mapfiles of the first 3D field", - "", - "ENVIRONMENT", - " REMAP_EXTRAPOLATE ", - " This variable is used to switch the extrapolation feature 'on' or 'off'.", - " By default the extrapolation is enabled for this remapping method.", - " CDO_GRIDSEARCH_RADIUS", - " Grid search radius in degree, default 180 degree.", - nullptr -}; - -static const char *RemapconHelp[] = { - "NAME", - " remapcon, gencon - First order conservative remapping", - "", - "SYNOPSIS", - " remapcon,grid infile outfile", - " gencon,grid[,map3d] infile outfile", - "", - "DESCRIPTION", - " This module contains operators for a first order conservative remapping of fields between grids in spherical coordinates.", - " The operators in this module uses code from the YAC software package to compute the conservative remapping weights.", - " For a detailed description of the interpolation method see YAC.", - " The interpolation method is completely general and can be used for any grid on a sphere.", - " The search algorithm for the conservative remapping requires that no grid cell occurs more than once. ", - "", - "OPERATORS", - " remapcon First order conservative remapping", - " Performs a first order conservative remapping on all input fields.", - " gencon Generate 1st order conservative remap weights", - " Generates first order conservative remapping weights for the first input field and", - " writes the result to a file. The format of this file is NetCDF following the SCRIP convention.", - " Use the operator remap to apply this remapping weights to a data file with the same source grid.", - " Set the parameter map3d=true to generate all mapfiles of the first 3D field with variing masks.", - " In this case the mapfiles will be named <outfile><xxx>.nc. xxx will have five digits with the number of the mapfile.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - " map3d BOOL Generate all mapfiles of the first 3D field", - "", - "ENVIRONMENT", - " CDO_REMAP_NORM", - " This variable is used to choose the normalization of the conservative interpolation. ", - " By default CDO_REMAP_NORM is set to 'fracarea'. 'fracarea' uses the sum of the", - " non-masked source cell intersected areas to normalize each target cell field value.", - " This results in a reasonable flux value but the flux is not locally conserved.", - " The option 'destarea' uses the total target cell area to normalize each target cell", - " field value. Local flux conservation is ensured, but unreasonable flux values may result.", - " REMAP_AREA_MIN", - " This variable is used to set the minimum destination area fraction. The default", - " of this variable is 0.0.", - nullptr -}; - -static const char *RemaplafHelp[] = { - "NAME", - " remaplaf, genlaf - Largest area fraction remapping", - "", - "SYNOPSIS", - " <operator>,grid infile outfile", - "", - "DESCRIPTION", - " This module contains operators for a largest area fraction remapping of fields between grids in spherical coordinates.", - " The operators in this module uses code from the YAC software package to compute the largest area fraction.", - " For a detailed description of the interpolation method see YAC.", - " The interpolation method is completely general and can be used for any grid on a sphere.", - " The search algorithm for this remapping method requires that no grid cell occurs more than once. ", - "", - "OPERATORS", - " remaplaf Largest area fraction remapping", - " Performs a largest area fraction remapping on all input fields.", - " genlaf Generate largest area fraction remap weights", - " Generates largest area fraction remapping weights for the first input field and", - " writes the result to a file. The format of this file is NetCDF following the SCRIP convention.", - " Use the operator remap to apply this remapping weights to a data file with the same source grid.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - "", - "ENVIRONMENT", - " REMAP_AREA_MIN", - " This variable is used to set the minimum destination area fraction. The default", - " of this variable is 0.0.", - nullptr -}; - -static const char *RemapHelp[] = { - "NAME", - " remap - Grid remapping", - "", - "SYNOPSIS", - " remap,grid,weights infile outfile", - "", - "DESCRIPTION", - " Interpolation between different horizontal grids can be a very time-consuming ", - " process. Especially if the data are on an unstructured and/or a large grid. ", - " In this case the interpolation process can be split into two parts.", - " Firstly the generation of the interpolation weights, which is the most time-consuming part.", - " These interpolation weights can be reused for every remapping process with the operator remap.", - " This operator remaps all input fields to a new horizontal grid. The remap type and ", - " the interpolation weights of one input grid are read from a NetCDF file. More weights ", - " are computed if the input fields are on different grids. The NetCDF file with the ", - " weights should follow the SCRIP convention. Normally these weights come from a previous", - " call to one of the genXXX operators (e.g. genbil) or were created by the original SCRIP package.", - "", - "PARAMETER", - " grid STRING Target grid description file or name", - " weights STRING Interpolation weights (SCRIP NetCDF file)", - "", - "ENVIRONMENT", - " CDO_REMAP_NORM ", - " This variable is used to choose the normalization of the conservative interpolation. ", - " By default CDO_REMAP_NORM is set to 'fracarea'. 'fracarea' uses the sum of the", - " non-masked source cell intersected areas to normalize each target cell field value.", - " This results in a reasonable flux value but the flux is not locally conserved.", - " The option 'destarea' uses the total target cell area to normalize each target cell", - " field value. Local flux conservation is ensured, but unreasonable flux values may result.", - " REMAP_EXTRAPOLATE ", - " This variable is used to switch the extrapolation feature 'on' or 'off'.", - " By default the extrapolation is enabled for remapdis, remapnn and for circular grids.", - " REMAP_AREA_MIN ", - " This variable is used to set the minimum destination area fraction. The default", - " of this variable is 0.0.", - " CDO_GRIDSEARCH_RADIUS", - " Grid search radius in degree, default 180 degree.", - nullptr -}; - -static const char *RemapetaHelp[] = { - "NAME", - " remapeta - Remap vertical hybrid level", - "", - "SYNOPSIS", - " remapeta,vct[,oro] infile outfile", - "", - "DESCRIPTION", - " This operator interpolates between different vertical hybrid levels. This include the preparation ", - " of consistent data for the free atmosphere. The procedure for the vertical interpolation is based ", - " on the HIRLAM scheme and was adapted from INTERA.", - " The vertical interpolation is based on the vertical integration of the hydrostatic equation with ", - " few adjustments. The basic tasks are the following one:", - " - at first integration of hydrostatic equation", - " - extrapolation of surface pressure", - " - Planetary Boundary-Layer (PBL) proutfile interpolation", - " - interpolation in free atmosphere", - " - merging of both proutfiles", - " - final surface pressure correction", - " ", - " The vertical interpolation corrects the surface pressure. This is simply a cut-off or an addition ", - " of air mass. This mass correction should not influence the geostrophic velocity field in the middle ", - " troposhere. Therefore the total mass above a given reference level is conserved. As reference level", - " the geopotential height of the 400 hPa level is used. Near the surface the correction can affect ", - " the vertical structure of the PBL. Therefore the interpolation is done using the potential temperature. ", - " But in the free atmosphere above a certain n (n=0.8 defining the top of the PBL) the interpolation ", - " is done linearly. After the interpolation both proutfiles are merged. With the resulting ", - " temperature/pressure correction the hydrostatic equation is integrated again and adjusted to the ", - " reference level finding the final surface pressure correction. A more detailed description of", - " the interpolation can be found in INTERA. This operator requires all variables on the same horizontal grid.", - "", - "PARAMETER", - " vct STRING File name of an ASCII dataset with the vertical coordinate table", - " oro STRING File name with the orography (surf. geopotential) of the target dataset (optional)", - "", - "ENVIRONMENT", - " REMAPETA_PTOP", - " Sets the minimum pressure level for condensation.", - " Above this level the humidity is set to the constant 1.E-6.", - " The default value is 0 Pa.", - "", - "NOTE", - " The code numbers or the variable names of the required parameter have to follow the ECHAM convention.", - " ", - " Use the sinfo command to test if your vertical coordinate system is recognized as hybrid system.", - " ", - " In case remapeta complains about not finding any data on hybrid model levels you may wish", - " to use the setzaxis command to generate a zaxis description which conforms to the ECHAM convention.", - " See section \"1.4 Z-axis description\" for an example how to define a hybrid Z-axis.", - nullptr -}; - -static const char *VertintmlHelp[] = { - "NAME", - " ml2pl, ml2hl - Vertical interpolation", - "", - "SYNOPSIS", - " ml2pl,plevels infile outfile", - " ml2hl,hlevels infile outfile", - "", - "DESCRIPTION", - " Interpolates 3D variables on hybrid sigma pressure level to pressure or height levels.", - " The input file should contain the log. surface pressure or the surface pressure.", - " To extrapolate the temperature, the surface geopotential is also needed.", - " It is assumed that the geopotential heights are located at the hybrid layer interfaces.", - " For the lowest layer of geopotential heights the surface geopotential is required.", - " The pressure, temperature, geopotential height, and surface geopotential are identified by", - " their GRIB1 code number or NetCDF CF standard name.", - " Supported parameter tables are: WMO standard table number 2 and ECMWF local table number 128.", - " ", - " CF standard name & Units & GRIB 1 code ", - " surface_air_pressure & Pa & 134", - " air_temperature & K & 130", - " surface_geopotential & m2 s-2 & 129", - " geopotential_height & m & 156", - " ", - " Use the alias ml2plx/ml2hlx or the environment variable EXTRAPOLATE to extrapolate", - " missing values. This operator requires all variables on the same horizontal grid.", - " Missing values in the input data are not supported.", - " ", - "", - "OPERATORS", - " ml2pl Model to pressure level interpolation", - " Interpolates 3D variables on hybrid sigma pressure level to pressure level.", - " ml2hl Model to height level interpolation", - " Interpolates 3D variables on hybrid sigma pressure level to height level.", - " The procedure is the same as for the operator ml2pl except for", - " the pressure levels being calculated from the heights by:", - " plevel = 101325*exp(hlevel/-7000)", - "", - "PARAMETER", - " plevels FLOAT Pressure levels in pascal", - " hlevels FLOAT Height levels in meter", - "", - "ENVIRONMENT", - " EXTRAPOLATE", - " If set to 1 extrapolate missing values.", - "", - "NOTE", - " The components of the hybrid coordinate must always be avaiable at the hybrid layer interfaces even if the data is defined at the hybrid layer midpoints.", - nullptr -}; - -static const char *VertintapHelp[] = { - "NAME", - " ap2pl - Vertical pressure interpolation", - "", - "SYNOPSIS", - " ap2pl,plevels infile outfile", - "", - "DESCRIPTION", - " Interpolate 3D variables on hybrid sigma height coordinates to pressure levels.", - " The input file must contain the 3D air pressure in pascal. The air pressure is", - " identified by the NetCDF CF standard name air_pressure.", - " Use the alias ap2plx or the environment variable EXTRAPOLATE to extrapolate", - " missing values. This operator requires all variables on the same horizontal grid.", - "", - "PARAMETER", - " plevels FLOAT Comma-separated list of pressure levels in pascal", - "", - "ENVIRONMENT", - " EXTRAPOLATE", - " If set to 1 extrapolate missing values.", - "", - "NOTE", - " This is a specific implementation for NetCDF files from the ICON model, it may not work with data from other sources.", - nullptr -}; - -static const char *VertintghHelp[] = { - "NAME", - " gh2hl - Vertical height interpolation", - "", - "SYNOPSIS", - " gh2hl,hlevels infile outfile", - "", - "DESCRIPTION", - " Interpolate 3D variables on hybrid sigma height coordinates to height levels.", - " The input file must contain the 3D geometric height in meter. The geometric height is", - " identified by the NetCDF CF standard name geometric_height_at_full_level_center.", - " Use the alias gh2hlx or the environment variable EXTRAPOLATE to extrapolate", - " missing values. This operator requires all variables on the same horizontal grid.", - "", - "PARAMETER", - " hlevels FLOAT Comma-separated list of height levels in meter", - "", - "ENVIRONMENT", - " EXTRAPOLATE", - " If set to 1 extrapolate missing values.", - "", - "NOTE", - " This is a specific implementation for NetCDF files from the ICON model, it may not work with data from other sources.", - nullptr -}; - -static const char *IntlevelHelp[] = { - "NAME", - " intlevel - Linear level interpolation", - "", - "SYNOPSIS", - " intlevel,parameter infile outfile", - "", - "DESCRIPTION", - " This operator performs a linear vertical interpolation of 3D variables. The target levels can be", - " specified with the level parameter or read in via a Z-axis description file.", - "", - "PARAMETER", - " level FLOAT Comma-separated list of target levels", - " file STRING Path to a file containing a description of the Z-axis", - nullptr -}; - -static const char *Intlevel3dHelp[] = { - "NAME", - " intlevel3d, intlevelx3d - ", - " Linear level interpolation from/to 3D vertical coordinates", - "", - "SYNOPSIS", - " <operator>,tgtcoordinate infile1 infile2 outfile", - "", - "DESCRIPTION", - " This operator performs a linear vertical interpolation of 3D variables fields with given 3D vertical coordinates.", - " infile1 contains the 3D data variables and infile2 the 3D vertical source coordinate. The parameter tgtcoordinate", - " is a datafile with the 3D vertical target coordinate.", - "", - "OPERATORS", - " intlevel3d Linear level interpolation onto a 3D vertical coordinate", - " intlevelx3d like intlevel3d but with extrapolation", - "", - "PARAMETER", - " tgtcoordinate STRING filename for 3D vertical target coordinates", - nullptr -}; - -static const char *InttimeHelp[] = { - "NAME", - " inttime, intntime - Time interpolation", - "", - "SYNOPSIS", - " inttime,date,time[,inc] infile outfile", - " intntime,n infile outfile", - "", - "DESCRIPTION", - " This module performs linear interpolation between timesteps.", - " Interpolation is only performed if both values exist.", - " If both values are missing values, the result is also a missing value.", - " If only one value exists, it is taken if the time weighting is greater than or equal to 0.5.", - " So no new value will be created at existing time steps, if the value is missing there.", - "", - "OPERATORS", - " inttime Interpolation between timesteps", - " This operator creates a new dataset by linear interpolation between timesteps.", - " The user has to define the start date/time with an optional increment.", - " intntime Interpolation between timesteps", - " This operator performs linear interpolation between timesteps.", - " The user has to define the number of timesteps from one timestep to the next.", - "", - "PARAMETER", - " date STRING Start date (format YYYY-MM-DD)", - " time STRING Start time (format hh:mm:ss)", - " inc STRING Optional increment (seconds, minutes, hours, days, months, years) [default: 0hour]", - " n INTEGER Number of timesteps from one timestep to the next", - nullptr -}; - -static const char *IntyearHelp[] = { - "NAME", - " intyear - Year interpolation", - "", - "SYNOPSIS", - " intyear,years infile1 infile2 obase", - "", - "DESCRIPTION", - " This operator performs linear interpolation between two years, timestep by timestep.", - " The input files need to have the same structure with the same variables.", - " The output files will be named <obase><yyyy><suffix> where yyyy will be the year and ", - " suffix is the filename extension derived from the file format.", - "", - "PARAMETER", - " years INTEGER Comma-separated list or first/last[/inc] range of years", - "", - "ENVIRONMENT", - " CDO_FILE_SUFFIX", - " Set the default file suffix. This suffix will be added to the output file ", - " names instead of the filename extension derived from the file format. ", - " Set this variable to NULL to disable the adding of a file suffix.", - "", - "NOTE", - " This operator needs to open all output files simultaneously.", - " The maximum number of open files depends on the operating system!", - nullptr -}; - -static const char *SpectralHelp[] = { - "NAME", - " sp2gp, gp2sp - Spectral transformation", - "", - "SYNOPSIS", - " <operator>[,type|trunc] infile outfile", - "", - "DESCRIPTION", - " This module transforms fields on a global regular Gaussian grid to spectral coefficients and vice versa.", - " The transformation is achieved by applying Fast Fourier Transformation (FFT) first and direct Legendre", - " Transformation afterwards in gp2sp. In sp2gp the inverse Legendre Transformation and inverse FFT are used.", - " Missing values are not supported.", - " ", - " The relationship between the spectral resolution, governed by the truncation number T, and the grid", - " resolution depends on the number of grid points at which the shortest wavelength field is represented.", - " For a grid with 2N points between the poles (so 4N grid points in total around the globe) the relationship is:", - " ", - " linear grid: the shortest wavelength is represented by 2 grid points → 4N ≃ 2(TL + 1)", - " ", - " quadratic grid: the shortest wavelength is represented by 3 grid points → 4N ≃ 3(TQ + 1)", - " ", - " cubic grid: the shortest wavelength is represented by 4 grid points → 4N ≃ 4(TC + 1)", - " ", - " The quadratic grid is used by ECHAM and ERA15. ERA40 is using a linear Gaussian grid reflected by the TL notation.", - " ", - " The following table shows the calculation of the number of latitudes and the triangular truncation for the different grid types:", - " ", - " Gridtype & Number of latitudes: nlat & Triangular truncation: ntr ", - " linear & NINT((ntr*2 + 1)/2) & (nlat*2 - 1) / 2", - " quadratic & NINT((ntr*3 + 1)/2) & (nlat*2 - 1) / 3", - " cubic & NINT((ntr*4 + 1)/2) & (nlat*2 - 1) / 4", - "", - "OPERATORS", - " sp2gp Spectral to gridpoint", - " Convert all spectral fields to a global regular Gaussian grid.", - " The optional parameter trunc must be greater than the input truncation.", - " gp2sp Gridpoint to spectral", - " Convert all Gaussian gridpoint fields to spectral fields.", - " The optional parameter trunc must be lower than the input truncation.", - "", - "PARAMETER", - " type STRING Type of the grid: quadratic, linear, cubic (default: type=quadratic)", - " trunc STRING Triangular truncation", - "", - "NOTE", - " To speed up the calculations, the Legendre polynoms are kept in memory. This requires a relatively large", - " amount of memory. This is for example 12GB for T1279 data.", - nullptr -}; - -static const char *SpecconvHelp[] = { - "NAME", - " sp2sp - Spectral conversion", - "", - "SYNOPSIS", - " sp2sp,trunc infile outfile", - "", - "DESCRIPTION", - " Changed the triangular truncation of all spectral fields. This operator performs downward ", - " conversion by cutting the resolution. Upward conversions are achieved by filling in zeros.", - "", - "PARAMETER", - " trunc INTEGER New spectral resolution", - nullptr -}; - -static const char *Wind2Help[] = { - "NAME", - " dv2ps - D and V to velocity potential and stream function", - "", - "SYNOPSIS", - " dv2ps infile outfile", - "", - "DESCRIPTION", - " Calculate spherical harmonic coefficients of velocity potential and stream function from ", - " spherical harmonic coefficients of relative divergence and vorticity. The divergence and ", - " vorticity need to have the names sd and svo or code numbers 155 and 138.", - nullptr -}; - -static const char *WindHelp[] = { - "NAME", - " dv2uv, uv2dv - Wind transformation", - "", - "SYNOPSIS", - " <operator>[,gridtype] infile outfile", - "", - "DESCRIPTION", - " This module converts relative divergence and vorticity to U and V wind and vice versa.", - " Divergence and vorticity are spherical harmonic coefficients in spectral space and", - " U and V are on a global regular Gaussian grid. The Gaussian latitudes need to be ordered from", - " north to south. Missing values are not supported.", - " ", - " The relationship between the spectral resolution, governed by the truncation number T, and the grid", - " resolution depends on the number of grid points at which the shortest wavelength field is represented.", - " For a grid with 2N points between the poles (so 4N grid points in total around the globe) the relationship is:", - " ", - " linear grid: the shortest wavelength is represented by 2 grid points → 4N ≃ 2(TL + 1)", - " ", - " quadratic grid: the shortest wavelength is represented by 3 grid points → 4N ≃ 3(TQ + 1)", - " ", - " cubic grid: the shortest wavelength is represented by 4 grid points → 4N ≃ 4(TC + 1)", - " ", - " The quadratic grid is used by ECHAM and ERA15. ERA40 is using a linear Gaussian grid reflected by the TL notation.", - " ", - " The following table shows the calculation of the number of latitudes and the triangular truncation for the different grid types:", - " ", - " Gridtype & Number of latitudes: nlat & Triangular truncation: ntr ", - " linear & NINT((ntr*2 + 1)/2) & (nlat*2 - 1) / 2", - " quadratic & NINT((ntr*3 + 1)/2) & (nlat*2 - 1) / 3", - " cubic & NINT((ntr*4 + 1)/2) & (nlat*2 - 1) / 4", - "", - "OPERATORS", - " dv2uv Divergence and vorticity to U and V wind", - " Calculate U and V wind on a Gaussian grid from spherical harmonic ", - " coefficients of relative divergence and vorticity. The divergence and vorticity ", - " need to have the names sd and svo or code numbers 155 and 138.", - " uv2dv U and V wind to divergence and vorticity", - " Calculate spherical harmonic coefficients of relative divergence and vorticity", - " from U and V wind. The U and V wind need to be on a Gaussian grid and need to have the ", - " names u and v or the code numbers 131 and 132.", - "", - "PARAMETER", - " gridtype STRING Type of the grid: quadratic, linear (default: quadratic)", - "", - "NOTE", - " To speed up the calculations, the Legendre polynoms are kept in memory. This requires a relatively large", - " amount of memory. This is for example 12GB for T1279 data.", - nullptr -}; - -static const char *FourierHelp[] = { - "NAME", - " fourier - Fourier transformation", - "", - "SYNOPSIS", - " fourier,epsilon infile outfile", - "", - "DESCRIPTION", - " The fourier operator performs the fourier transformation or the inverse fourier transformation of all input fields.", - " If the number of timesteps is a power of 2 then the algorithm of the Fast Fourier Transformation (FFT) is used.", - " ", - " ", - " If the input stream infile consists only of complex fields, then the fields of outfile, computed by", - " cdo -f ext fourier,1 -fourier,-1 infile outfile", - " are the same than that of infile. For real input files see function retocomplex.", - "", - "PARAMETER", - " epsilon INTEGER -1: forward transformation; 1: backward transformation", - "", - "NOTE", - " Complex numbers can only be stored in NetCDF4 and EXTRA format.", - nullptr -}; - -static const char *ImportbinaryHelp[] = { - "NAME", - " import_binary - Import binary data sets", - "", - "SYNOPSIS", - " import_binary infile outfile", - "", - "DESCRIPTION", - " This operator imports gridded binary data sets via a GrADS data descriptor file.", - " The GrADS data descriptor file contains a complete description of the binary data as well ", - " as instructions on where to find the data and how to read it. The descriptor file is an ASCII ", - " file that can be created easily with a text editor. The general contents of a gridded data ", - " descriptor file are as follows:", - " - Filename for the binary data", - " - Missing or undefined data value", - " - Mapping between grid coordinates and world coordinates", - " - Description of variables in the binary data set ", - " ", - " A detailed description of the components of a GrADS data descriptor file can be found in GrADS.", - " Here is a list of the supported components:", - " BYTESWAPPED, CHSUB, DSET, ENDVARS, FILEHEADER, HEADERBYTES, OPTIONS, TDEF, TITLE, ", - " TRAILERBYTES, UNDEF, VARS, XDEF, XYHEADER, YDEF, ZDEF", - "", - "NOTE", - " Only 32-bit IEEE floats are supported for standard binary files!", - nullptr -}; - -static const char *ImportcmsafHelp[] = { - "NAME", - " import_cmsaf - Import CM-SAF HDF5 files", - "", - "SYNOPSIS", - " import_cmsaf infile outfile", - "", - "DESCRIPTION", - " This operator imports gridded CM-SAF (Satellite Application Facility on Climate Monitoring)", - " HDF5 files. CM-SAF exploits data from polar-orbiting and geostationary satellites in order ", - " to provide climate monitoring products of the following parameters: ", - " ", - " Cloud parameters: cloud fraction (CFC), cloud type (CTY), cloud phase (CPH), ", - " cloud top height, pressure and temperature (CTH,CTP,CTT), ", - " cloud optical thickness (COT), cloud water path (CWP).", - " ", - " Surface radiation components: Surface albedo (SAL); surface incoming (SIS) ", - " and net (SNS) shortwave radiation; surface downward (SDL) ", - " and outgoing (SOL) longwave radiation, surface net longwave ", - " radiation (SNL) and surface radiation budget (SRB).", - " ", - " Top-of-atmosphere radiation components: Incoming (TIS) and reflected (TRS) ", - " solar radiative flux at top-of-atmosphere. Emitted thermal ", - " radiative flux at top-of-atmosphere (TET).", - " ", - " Water vapour: Vertically integrated water vapour (HTW), layered vertically ", - " integrated water vapour and layer mean temperature and relative ", - " humidity for 5 layers (HLW), temperature and mixing ratio at ", - " 6 pressure levels. ", - " ", - " Daily and monthly mean products can be ordered via the CM-SAF web page (www.cmsaf.eu). ", - " Products with higher spatial and temporal resolution, i.e. instantaneous swath-based products,", - " are available on request (contact.cmsaf@dwd.de). All products are distributed free-of-charge.", - " More information on the data is available on the CM-SAF homepage (www.cmsaf.eu).", - " ", - " Daily and monthly mean products are provided in equal-area projections. CDO reads the ", - " projection parameters from the metadata in the HDF5-headers in order to allow spatial ", - " operations like remapping. For spatial operations with instantaneous products on original ", - " satellite projection, additional files with arrays of latitudes and longitudes are needed.", - " These can be obtained from CM-SAF together with the data.", - " ", - "", - "NOTE", - " To use this operator, it is necessary to build CDO with HDF5 support (version 1.6 or higher).", - " The PROJ library (version 5.0 or higher) is needed for full support of the remapping", - " functionality. ", - nullptr -}; - -static const char *ImportamsrHelp[] = { - "NAME", - " import_amsr - Import AMSR binary files", - "", - "SYNOPSIS", - " import_amsr infile outfile", - "", - "DESCRIPTION", - " This operator imports gridded binary AMSR (Advanced Microwave Scanning Radiometer) data.", - " The binary data files are available from the AMSR ftp site (ftp://ftp.ssmi.com/amsre).", - " Each file consists of twelve (daily) or five (averaged) 0.25 x 0.25 degree ", - " grid (1440,720) byte maps. For daily files, six daytime maps in the following", - " order, Time (UTC), Sea Surface Temperature (SST), 10 meter Surface Wind Speed (WSPD),", - " Atmospheric Water Vapor (VAPOR), Cloud Liquid Water (CLOUD), and Rain Rate (RAIN), ", - " are followed by six nighttime maps in the same order. Time-Averaged files contain ", - " just the geophysical layers in the same order [SST, WSPD, VAPOR, CLOUD, RAIN].", - " More information to the data is available on the AMSR homepage http://www.remss.com/amsr.", - nullptr -}; - -static const char *InputHelp[] = { - "NAME", - " input, inputsrv, inputext - Formatted input", - "", - "SYNOPSIS", - " input,grid[,zaxis] outfile", - " inputsrv outfile", - " inputext outfile", - "", - "DESCRIPTION", - " This module reads time series of one 2D variable from standard input.", - " All input fields need to have the same horizontal grid. The format of the ", - " input depends on the chosen operator.", - "", - "OPERATORS", - " input ASCII input", - " Reads fields with ASCII numbers from standard input and stores them", - " in outfile. The numbers read are exactly that ones which are written ", - " out by the output operator.", - " inputsrv SERVICE ASCII input", - " Reads fields with ASCII numbers from standard input and stores them ", - " in outfile. Each field should have a header of 8 integers (SERVICE likely).", - " The numbers that are read are exactly that ones which are written out by ", - " the outputsrv operator.", - " inputext EXTRA ASCII input", - " Read fields with ASCII numbers from standard input and stores them ", - " in outfile. Each field should have header of 4 integers (EXTRA likely).", - " The numbers read are exactly that ones which are written out by ", - " the outputext operator.", - "", - "PARAMETER", - " grid STRING Grid description file or name", - " zaxis STRING Z-axis description file", - nullptr -}; - -static const char *OutputHelp[] = { - "NAME", - " output, outputf, outputint, outputsrv, outputext - Formatted output", - "", - "SYNOPSIS", - " output infiles", - " outputf,format[,nelem] infiles", - " outputint infiles", - " outputsrv infiles", - " outputext infiles", - "", - "DESCRIPTION", - " This module prints all values of all input datasets to standard output.", - " All input fields need to have the same horizontal grid. All input files ", - " need to have the same structure with the same variables.", - " The format of the output depends on the chosen operator.", - "", - "OPERATORS", - " output ASCII output", - " Prints all values to standard output.", - " Each row has 6 elements with the C-style format \"%13.6g\".", - " outputf Formatted output", - " Prints all values to standard output.", - " The format and number of elements for each row have to be specified by the parameters", - " format and nelem. The default for nelem is 1.", - " outputint Integer output", - " Prints all values rounded to the nearest integer to standard output.", - " outputsrv SERVICE ASCII output", - " Prints all values to standard output.", - " Each field with a header of 8 integers (SERVICE likely).", - " outputext EXTRA ASCII output", - " Prints all values to standard output.", - " Each field with a header of 4 integers (EXTRA likely).", - "", - "PARAMETER", - " format STRING C-style format for one element (e.g. %13.6g)", - " nelem INTEGER Number of elements for each row (default: nelem = 1)", - nullptr -}; - -static const char *OutputtabHelp[] = { - "NAME", - " outputtab - Table output", - "", - "SYNOPSIS", - " outputtab,parameter infiles outfile", - "", - "DESCRIPTION", - " This operator prints a table of all input datasets to standard output.", - " infiles is an arbitrary number of input files. All input files need to have ", - " the same structure with the same variables on different timesteps.", - " All input fields need to have the same horizontal grid.", - " ", - " The contents of the table depends on the chosen parameters. The format of each table parameter is keyname[:len].", - " len is the optional length of a table entry. The number of significant digits of floating point parameters", - " can be set with the CDO option --precision, the default is 7.", - " Here is a list of all valid keynames:", - " ", - " Keyname & Type & Description ", - " value & FLOAT & Value of the variable [len:8]", - " name & STRING & Name of the variable [len:8]", - " param & STRING & Parameter ID (GRIB1: code[.tabnum]; GRIB2: num[.cat[.dis]]) [len:11]", - " code & INTEGER & Code number [len:4]", - " x & FLOAT & X coordinate of the original grid [len:6]", - " y & FLOAT & Y coordinate of the original grid [len:6]", - " lon & FLOAT & Longitude coordinate in degrees [len:6]", - " lat & FLOAT & Latitude coordinate in degrees [len:6]", - " lev & FLOAT & Vertical level [len:6]", - " xind & INTEGER & Grid x index [len:4]", - " yind & INTEGER & Grid y index [len:4]", - " timestep & INTEGER & Timestep number [len:6]", - " date & STRING & Date (format YYYY-MM-DD) [len:10]", - " time & STRING & Time (format hh:mm:ss) [len:8]", - " year & INTEGER & Year [len:5]", - " month & INTEGER & Month [len:2]", - " day & INTEGER & Day [len:2]", - " nohead & INTEGER & Disable output of header line", - "", - "PARAMETER", - " parameter STRING Comma-separated list of keynames, one for each column of the table", - nullptr -}; - -static const char *OutputgmtHelp[] = { - "NAME", - " gmtxyz, gmtcells - GMT output", - "", - "SYNOPSIS", - " <operator> infile", - "", - "DESCRIPTION", - " This module prints the first field of the input dataset to standard output.", - " The output can be used to generate 2D Lon/Lat plots with GMT.", - " The format of the output depends on the chosen operator.", - "", - "OPERATORS", - " gmtxyz GMT xyz format", - " The operator exports the first field to the GMT xyz ASCII format.", - " The output can be used to create contour plots with the GMT module pscontour.", - " gmtcells GMT multiple segment format", - " The operator exports the first field to the GMT multiple segment ASCII format.", - " The output can be used to create shaded gridfill plots with the GMT module psxy.", - nullptr -}; - -static const char *GradsdesHelp[] = { - "NAME", - " gradsdes - GrADS data descriptor file", - "", - "SYNOPSIS", - " gradsdes[,mapversion] infile", - "", - "DESCRIPTION", - " Creates a GrADS data descriptor file. Supported file formats are GRIB1, NetCDF, SERVICE, ", - " EXTRA and IEG. For GRIB1 files the GrADS map file is also generated. For SERVICE and EXTRA", - " files the grid have to be specified with the CDO option '-g <grid>'. This module takes infile", - " in order to create filenames for the descriptor (infile.ctl) and the map (infile.gmp) file.", - "", - "PARAMETER", - " mapversion INTEGER Format version of the GrADS map file for GRIB1 datasets. Use 1 for a machine", - " specific version 1 GrADS map file, 2 for a machine independent version 2 GrADS map file", - " and 4 to support GRIB files >2GB. ", - " A version 2 map file can be used only with GrADS version 1.8 or newer.", - " A version 4 map file can be used only with GrADS version 2.0 or newer.", - " The default is 4 for files >2GB, otherwise 2.", - nullptr -}; - -static const char *AfterburnerHelp[] = { - "NAME", - " after - ECHAM standard post processor", - "", - "SYNOPSIS", - " after[,vct] infiles outfile", - "", - "DESCRIPTION", - " The \"afterburner\" is the standard post processor for ECHAM GRIB and NetCDF data which provides the following operations:", - " ", - " - Extract specified variables and levels", - " - Compute derived variables", - " - Transform spectral data to Gaussian grid representation", - " - Vertical interpolation to pressure levels", - " - Compute temporal means", - " ", - " This operator reads selection parameters as namelist from stdin.", - " Use the UNIX redirection \"<namelistfile\" to read the namelist from file.", - " ", - " The input files can't be combined with other CDO operators because of an optimized reader for this operator.", - "", - "NAMELIST", - " Namelist parameter and there defaults:", - " TYPE=0, CODE=-1, LEVEL=-1, INTERVAL=0, MEAN=0, EXTRAPOLATE=1", - " ", - " TYPE controls the transformation and vertical interpolation. Transforming spectral data to Gaussian grid", - " representation and vertical interpolation to pressure levels are performed in a chain of steps.", - " The TYPE parameter may be used to stop the chain at a certain step. Valid values are:", - " ", - " TYPE = 0 : Hybrid level spectral coefficients", - " TYPE = 10 : Hybrid level fourier coefficients", - " TYPE = 11 : Hybrid level zonal mean sections", - " TYPE = 20 : Hybrid level gauss grids", - " TYPE = 30 : Pressure level gauss grids", - " TYPE = 40 : Pressure level fourier coefficients", - " TYPE = 41 : Pressure level zonal mean sections", - " TYPE = 50 : Pressure level spectral coefficients", - " TYPE = 60 : Pressure level fourier coefficients", - " TYPE = 61 : Pressure level zonal mean sections", - " TYPE = 70 : Pressure level gauss grids", - " ", - " Vorticity, divergence, streamfunction and velocity potential need special treatment in the vertical transformation.", - " They are not available as types 30, 40 and 41. If you select one of these combinations, type is automatically", - " switched to the equivalent types 70, 60 and 61. The type of all other variables will be switched too, because ", - " the type is a global parameter.", - " ", - " CODE selects the variables by the ECHAM GRIB1 code number (1-255). The default value -1 processes all detected codes.", - " Derived variables computed by the afterburner:", - " ", - " Code & Name & Longname & Units & Level & Needed Codes", - " 34 & low_cld & low cloud & & single & 223 on modellevel ", - " 35 & mid_cld & mid cloud & & single & 223 on modellevel ", - " 36 & hih_cld & high cloud & & single & 223 on modellevel ", - " 131 & u & u-velocity & m/s & atm (ml+pl) & 138, 155 ", - " 132 & v & v-velocity & m/s & atm (ml+pl) & 138, 155 ", - " 135 & omega & vertical velocity & Pa/s & atm (ml+pl) & 138, 152, 155 ", - " 148 & stream & streamfunction & m^2/s & atm (ml+pl) & 131, 132 ", - " 149 & velopot & velocity potential & m^2/s & atm (ml+pl) & 131, 132 ", - " 151 & slp & mean sea level pressure & Pa & surface & 129, 130, 152 ", - " 156 & geopoth & geopotential height & m & atm (ml+pl) & 129, 130, 133, 152 ", - " 157 & rhumidity & relative humidity & & atm (ml+pl) & 130, 133, 152 ", - " 189 & sclfs & surface solar cloud forcing & & surface & 176-185 ", - " 190 & tclfs & surface thermal cloud forcing & & surface & 177-186 ", - " 191 & sclf0 & top solar cloud forcing & & surface & 178-187 ", - " 192 & tclf0 & top thermal cloud forcing & & surface & 179-188 ", - " 259 & windspeed & windspeed & m/s & atm (ml+pl) & sqrt(u*u+v*v) ", - " 260 & precip & total precipitation & & surface & 142+143 ", - " ", - " LEVEL selects the hybrid or pressure levels. The allowed values depends on the parameter TYPE.", - " The default value -1 processes all detected levels.", - " ", - " INTERVAL selects the processing interval. The default value 0 process data on monthly intervals.", - " INTERVAL=1 sets the interval to daily.", - " ", - " MEAN=1 compute and write monthly or daily mean fields. The default value 0 writes out all timesteps.", - " ", - " EXTRAPOLATE=0 switch of the extrapolation of missing values during the interpolation from model to pressure", - " level (only available with MEAN=0 and TYPE=30). The default value 1 extrapolate missing values.", - " ", - " Possible combinations of TYPE, CODE and MEAN:", - " ", - " TYPE & CODE & MEAN", - " 0/10/11 & 130 temperature & 0", - " 0/10/11 & 131 u-velocity & 0", - " 0/10/11 & 132 v-velocity & 0", - " 0/10/11 & 133 specific humidity & 0", - " 0/10/11 & 138 vorticity & 0", - " 0/10/11 & 148 streamfunction & 0", - " 0/10/11 & 149 velocity potential & 0", - " 0/10/11 & 152 LnPs & 0", - " 0/10/11 & 155 divergence & 0", - " >11 & all codes & 0/1", - "", - "PARAMETER", - " vct STRING File with VCT in ASCII format", - nullptr -}; - -static const char *FilterHelp[] = { - "NAME", - " bandpass, lowpass, highpass - Time series filtering", - "", - "SYNOPSIS", - " bandpass,fmin,fmax infile outfile", - " lowpass,fmax infile outfile", - " highpass,fmin infile outfile", - "", - "DESCRIPTION", - " This module takes the time series for each gridpoint in infile and (fast fourier) transforms it ", - " into the frequency domain. According to the particular operator and its parameters certain frequencies ", - " are filtered (set to zero) in the frequency domain and the spectrum is (inverse fast fourier) transformed ", - " back into the time domain.", - " To determine the frequency the time-axis of infile is used. (Data should have a constant time increment ", - " since this assumption applies for transformation. However, the time increment has to be different from zero.)", - " All frequencies given as parameter are interpreted per year. This is done by the assumption of a 365-day calendar. ", - " Consequently if you want to perform multiyear-filtering accurately you have to delete the 29th of February. ", - " If your infile has a 360 year calendar the frequency parameters fmin respectively fmax should be ", - " multiplied with a factor of 360/365 in order to obtain accurate results. ", - " For the set up of a frequency filter the frequency parameters have to be adjusted to a frequency in the data. ", - " Here fmin is rounded down and fmax is always rounded up. Consequently it is possible to use bandpass with ", - " fmin=fmax without getting a zero-field for outfile. ", - " Hints for efficient usage: ", - " - to get reliable results the time-series has to be detrended (cdo detrend)", - " - the lowest frequency greater zero that can be contained in infile is 1/(N*dT), ", - " - the greatest frequency is 1/(2dT) (Nyquist frequency),", - " with N the number of timesteps and dT the time increment of infile in years.", - " ", - " Missing value support for operators in this module is not implemented, yet!", - "", - "OPERATORS", - " bandpass Bandpass filtering", - " Bandpass filtering (pass for frequencies between fmin and fmax).", - " Suppresses all variability outside the frequency range specified by [fmin,fmax].", - " lowpass Lowpass filtering", - " Lowpass filtering (pass for frequencies lower than fmax).", - " Suppresses all variability with frequencies greater than fmax. ", - " highpass Highpass filtering", - " Highpass filtering (pass for frequencies greater than fmin). ", - " Suppresses all variabilty with frequencies lower than fmin. ", - "", - "PARAMETER", - " fmin FLOAT Minimum frequency per year that passes the filter.", - " fmax FLOAT Maximum frequency per year that passes the filter. ", - "", - "NOTE", - " For better performace of these operators use the CDO configure option --with-fftw3.", - nullptr -}; - -static const char *GridcellHelp[] = { - "NAME", - " gridarea, gridweights - Grid cell quantities", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module reads the grid cell area of the first grid from the input stream. If the grid cell area is missing it", - " will be computed from the grid coordinates. The area of a grid cell is calculated using spherical triangles from", - " the coordinates of the center and the vertices. The base is a unit sphere which is scaled with the radius of the earth.", - " The default earth radius is 6371000 meter. This value can be changed with the environment variable PLANET_RADIUS.", - " Depending on the chosen operator the grid cell area or weights are written to the output stream.", - "", - "OPERATORS", - " gridarea Grid cell area", - " Writes the grid cell area to the output stream. If the grid cell area have to", - " be computed it is scaled with the earth radius to square meters.", - " gridweights Grid cell weights", - " Writes the grid cell area weights to the output stream.", - "", - "ENVIRONMENT", - " PLANET_RADIUS", - " This variable is used to scale the computed grid cell areas to square meters. ", - " By default PLANET_RADIUS is set to an earth radius of 6371000 meter.", - nullptr -}; - -static const char *SmoothHelp[] = { - "NAME", - " smooth, smooth9 - Smooth grid points", - "", - "SYNOPSIS", - " smooth[,options] infile outfile", - " smooth9 infile outfile", - "", - "DESCRIPTION", - " Smooth all grid points of a horizontal grid.", - " Options is a comma-separated list of \"key=value\" pairs with optional parameters.", - "", - "OPERATORS", - " smooth Smooth grid points", - " Performs a N point smoothing on all input fields. The number of points used depend", - " on the search radius (radius) and the maximum number of points (maxpoints).", - " Per default all points within the search radius of 1degree are used.", - " The weights for the points depend on the form of the curve and the distance.", - " The implemented form of the curve is linear with constant default weights of 0.25", - " at distance 0 (weight0) and at the search radius (weightR).", - " smooth9 9 point smoothing", - " Performs a 9 point smoothing on all fields with a quadrilateral curvilinear grid.", - " The result at each grid point is a weighted average of the grid point plus", - " the 8 surrounding points. The center point receives a weight of 1.0, the ", - " points at each side and above and below receive a weight of 0.5, and corner ", - " points receive a weight of 0.3.", - " All 9 points are multiplied by their weights and summed, then divided by ", - " the total weight to obtain the smoothed value. Any missing data points are ", - " not included in the sum; points beyond the grid boundary are considered to ", - " be missing. Thus the final result may be the result of an averaging with less ", - " than 9 points.", - "", - "PARAMETER", - " nsmooth INTEGER Number of times to smooth, default nsmooth=1", - " radius STRING Search radius, default radius=1deg (units: deg, rad, km, m)", - " maxpoints INTEGER Maximum number of points, default maxpoints=<gridsize>", - " form STRING Form of the curve, default form=linear", - " weight0 FLOAT Weight at distance 0, default weight0=0.25", - " weightR FLOAT Weight at the search radius, default weightR=0.25", - nullptr -}; - -static const char *DeltatHelp[] = { - "NAME", - " deltat - Difference between timesteps", - "", - "SYNOPSIS", - " deltat infile outfile", - "", - "DESCRIPTION", - " This operator computes the difference between each timestep.", - nullptr -}; - -static const char *ReplacevaluesHelp[] = { - "NAME", - " setvals, setrtoc, setrtoc2 - Replace variable values", - "", - "SYNOPSIS", - " setvals,oldval,newval[,...] infile outfile", - " setrtoc,rmin,rmax,c infile outfile", - " setrtoc2,rmin,rmax,c,c2 infile outfile", - "", - "DESCRIPTION", - " This module replaces old variable values with new values, depending on the operator.", - "", - "OPERATORS", - " setvals Set list of old values to new values", - " Supply a list of n pairs of old and new values.", - " setrtoc Set range to constant", - " / c if i(t,x) GE rmin AND i(t,x) LE rmax", - " o(t,x) = ", - " \\ i(t,x) if i(t,x) LT rmin AND i(t,x) GT rmax", - " setrtoc2 Set range to constant others to constant2", - " / c if i(t,x) GE rmin AND i(t,x) LE rmax", - " o(t,x) = ", - " \\ c2 if i(t,x) LT rmin AND i(t,x) GT rmax", - "", - "PARAMETER", - " oldval,newval,... FLOAT Pairs of old and new values", - " rmin FLOAT Lower bound", - " rmax FLOAT Upper bound", - " c FLOAT New value - inside range", - " c2 FLOAT New value - outside range", - nullptr -}; - -static const char *GetgridcellHelp[] = { - "NAME", - " gridcellindex - Get grid cell index", - "", - "SYNOPSIS", - " gridcellindex[,parameter] infile", - "", - "DESCRIPTION", - " Get the grid cell index of one grid point selected by the parameter lon and lat.", - "", - "PARAMETER", - " lon INTEGER Longitude of the grid cell in degree", - " lat INTEGER Latitude of the grid cell in degree", - nullptr -}; - -static const char *VargenHelp[] = { - "NAME", - " const, random, topo, seq, stdatm - Generate a field", - "", - "SYNOPSIS", - " const,const,grid outfile", - " random,grid[,seed] outfile", - " topo[,grid] outfile", - " seq,start,end[,inc] outfile", - " stdatm,levels outfile", - "", - "DESCRIPTION", - " Generates a dataset with one or more fields", - "", - "OPERATORS", - " const Create a constant field", - " Creates a constant field. All field elements of the grid have the same value.", - " random Create a field with random numbers", - " Creates a field with rectangularly distrubuted random numbers in the interval [0,1].", - " topo Create a field with topography", - " Creates a field with topography data, per default on a global half degree grid.", - " seq Create a time series", - " Creates a time series with field size 1 and field elements beginning with a start value in time step 1", - " which is increased from one time step to the next.", - " stdatm Create values for pressure and temperature for hydrostatic atmosphere", - " Creates pressure and temperature values for the given list of vertical levels.", - " The formulars are:", - " ", - " P(z) = P_0 * exp(-1 * g/R * H/T_0 * log( (exp(z/H)*T_0 + T_Delta)/(T_0 + T_Delta))", - " T(z) = T_0 + T_Delta * exp(-z/H)", - " ", - " with the following constants", - " ", - " T_0 = 213 K Offset to get a surface temperature of 288K", - " T_Delta = 75 K Temperature lapse rate for 10Km", - " P_0 = 1013.25 hPa Surface pressure", - " H = 10000.0 m Scale height", - " g = 9.80665 m/s**2 Earth gravity", - " R = 287.05 J/kg*K Gas constant for air", - " ", - " This is the solution for the hydrostatic equations and is only valid for the", - " troposphere (constant positive lapse rate). The temperature increase in the", - " stratosphere and other effects of the upper atmosphere are not taken into", - " account.", - "", - "PARAMETER", - " const FLOAT Constant", - " seed INTEGER The seed for a new sequence of pseudo-random numbers [default: 1]", - " grid STRING Target grid description file or name", - " start FLOAT Start value of the loop", - " end FLOAT End value of the loop", - " inc FLOAT Increment of the loop [default: 1]", - " levels FLOAT Target levels in metre above surface", - nullptr -}; - -static const char *TimsortHelp[] = { - "NAME", - " timsort - Timsort", - "", - "SYNOPSIS", - " timsort infile outfile", - "", - "DESCRIPTION", - " Sorts the elements in ascending order over all timesteps for every field position.", - " After sorting it is:", - " ", - " o(t_1,x) <= o(t_2,x) forall (t_1<t_2),x", - nullptr -}; - -static const char *WindTransHelp[] = { - "NAME", - " uvDestag, rotuvNorth, projuvLatLon - Wind Transformation", - "", - "SYNOPSIS", - " uvDestag,u,v[,-/+0.5[,-/+0.5]] infile outfile", - " rotuvNorth,u,v infile outfile", - " projuvLatLon,u,v infile outfile", - "", - "DESCRIPTION", - " This module contains special operators for datsets with wind components on a rotated lon/lat grid, ", - " e.g. data from the regional model HIRLAM or REMO. ", - "", - "OPERATORS", - " uvDestag Destaggering of u/v wind components", - " This is a special operator for destaggering of wind components.", - " If the file contains a grid with temperature (name='t' or code=11)", - " then grid_temp will be used for destaggered wind.", - " rotuvNorth Rotate u/v wind to North pole.", - " This is an operator for transformation of wind-vectors from grid-relative to north-pole", - " relative for the whole file. (FAST implementation with JACOBIANS)", - " projuvLatLon Cylindrical Equidistant projection", - " Thus is an operator for transformation of wind-vectors from the globe-spherical coordinate system", - " into a flat Cylindrical Equidistant (lat-lon) projection. (FAST JACOBIAN implementation)", - "", - "PARAMETER", - " u,v STRING Pair of u,v wind components (use variable names or code numbers)", - " -/+0.5,-/+0.5 STRING Destaggered grid offsets are optional (default -0.5,-0.5)", - nullptr -}; - -static const char *RotuvbHelp[] = { - "NAME", - " rotuvb - Rotation", - "", - "SYNOPSIS", - " rotuvb,u,v,... infile outfile", - "", - "DESCRIPTION", - " This is a special operator for datsets with wind components on a rotated grid, ", - " e.g. data from the regional model REMO. It performs a backward transformation of ", - " velocity components U and V from a rotated spherical system to a geographical system.", - "", - "PARAMETER", - " u,v,... STRING Pairs of zonal and meridional velocity components (use variable names or code numbers)", - "", - "NOTE", - " This is a specific implementation for data from the REMO model, it may not work with data from other sources.", - nullptr -}; - -static const char *MrotuvbHelp[] = { - "NAME", - " mrotuvb - Backward rotation of MPIOM data", - "", - "SYNOPSIS", - " mrotuvb infile1 infile2 outfile", - "", - "DESCRIPTION", - " MPIOM data are on a rotated Arakawa C grid. The velocity components U and V are located on", - " the edges of the cells and point in the direction of the grid lines and rows.", - " With mrotuvb the velocity vector is rotated in latitudinal and longitudinal direction.", - " Before the rotation, U and V are interpolated to the scalar points (cell center).", - " U is located with the coordinates for U in infile1 and V in infile2.", - " mrotuvb assumes a positive meridional flow for a flow from grid point(i,j) to grid point(i,j+1)", - " and positive zonal flow for a flow from grid point(i+1,j) to point(i,j).", - "", - "NOTE", - " This is a specific implementation for data from the MPIOM model, it may not work with data from other sources.", - nullptr -}; - -static const char *MastrfuHelp[] = { - "NAME", - " mastrfu - Mass stream function", - "", - "SYNOPSIS", - " mastrfu infile outfile", - "", - "DESCRIPTION", - " This is a special operator for the post processing of the atmospheric general circulation", - " model ECHAM. It computes the mass stream function (code=272). The input dataset have ", - " to be a zonal mean of v-velocity [m/s] (code=132) on pressure levels.", - nullptr -}; - -static const char *DeriveparHelp[] = { - "NAME", - " sealevelpressure, gheight - Derived model parameters", - "", - "SYNOPSIS", - " <operator> infile outfile", - "", - "DESCRIPTION", - " This module contains operators that calculate derived model parameters. These are currently the parameters", - " sea level pressure and geopotential height. All necessary input parameters are identified by their GRIB1", - " code number or the NetCDF CF standard name.", - " Supported GRIB1 parameter tables are: WMO standard table number 2 and ECMWF local table number 128.", - " ", - " CF standard name & Units & GRIB 1 code ", - " surface_air_pressure & Pa & 134", - " air_temperature & K & 130", - " specific_humidity & kg/kg & 133", - " surface_geopotential & m2 s-2 & 129", - " geopotential_height & m & 156", - " ", - "", - "OPERATORS", - " sealevelpressure Sea level pressure", - " This operator computes the sea level pressure (air_pressure_at_sea_level). Required input fields", - " are surface_air_pressure, surface_geopotential and air_temperature on full hybrid sigma pressure levels.", - " gheight Geopotential height", - " This operator computes the geopotential height (geopotential_height) on full model levels in metres.", - " Required input fields are surface_air_pressure, surface_geopotential, specific_humidity and air_temperature", - " on full hybrid sigma pressure levels. Note, this procedure is an approximation, which doesn't take into", - " account the effects of e.g. cloud ice and water, rain and snow.", - nullptr -}; - -static const char *AdisitHelp[] = { - "NAME", - " adisit, adipot - Potential temperature to in-situ temperature and vice versa", - "", - "SYNOPSIS", - " <operator>[,pressure] infile outfile", - "", - "DESCRIPTION", - "", - "OPERATORS", - " adisit Potential temperature to in-situ temperature", - " This is a special operator for the post processing of the ocean and sea ice model MPIOM.", - " It converts potential temperature adiabatically to in-situ temperature to(t, s, p).", - " Required input fields are sea water potential temperature (name=tho; code=2) and sea water salinity (name=sao; code=5).", - " Pressure is calculated from the level information or can be specified by the optional parameter.", - " Output fields are sea water temperature (name=to; code=20) and sea water salinity (name=s; code=5).", - " adipot In-situ temperature to potential temperature", - " This is a special operator for the post processing of the ocean and sea ice model MPIOM.", - " It converts in-situ temperature to potential temperature tho(to, s, p). Required input fields", - " are sea water in-situ temperature (name=t; code=2) and sea water salinity (name=sao,s; code=5).", - " Pressure is calculated from the level information or can be specified by the optional parameter.", - " Output fields are sea water temperature (name=tho; code=2) and sea water salinity (name=s; code=5).", - "", - "PARAMETER", - " pressure FLOAT Pressure in bar (constant value assigned to all levels)", - nullptr -}; - -static const char *RhopotHelp[] = { - "NAME", - " rhopot - Calculates potential density", - "", - "SYNOPSIS", - " rhopot[,pressure] infile outfile", - "", - "DESCRIPTION", - " This is a special operator for the post processing of the ocean and sea ice model MPIOM.", - " It calculates the sea water potential density (name=rhopoto; code=18). Required input fields ", - " are sea water in-situ temperature (name=to; code=20) and sea water salinity (name=sao; code=5).", - " Pressure is calculated from the level information or can be specified by the optional parameter.", - "", - "PARAMETER", - " pressure FLOAT Pressure in bar (constant value assigned to all levels)", - nullptr -}; - -static const char *HistogramHelp[] = { - "NAME", - " histcount, histsum, histmean, histfreq - Histogram", - "", - "SYNOPSIS", - " <operator>,bounds infile outfile", - "", - "DESCRIPTION", - " This module creates bins for a histogram of the input data.", - " The bins have to be adjacent and have non-overlapping intervals.", - " The user has to define the bounds of the bins. The first value", - " is the lower bound and the second value the upper bound of the", - " first bin. The bounds of the second bin are defined by the", - " second and third value, aso.", - " Only 2-dimensional input fields are allowed. The output file ", - " contains one vertical level for each of the bins requested.", - "", - "OPERATORS", - " histcount Histogram count", - " Number of elements in the bin range.", - " histsum Histogram sum", - " Sum of elements in the bin range.", - " histmean Histogram mean", - " Mean of elements in the bin range.", - " histfreq Histogram frequency", - " Relative frequency of elements in the bin range.", - "", - "PARAMETER", - " bounds FLOAT Comma-separated list of the bin bounds (-inf and inf valid)", - nullptr -}; - -static const char *SethaloHelp[] = { - "NAME", - " sethalo - Set the bounds of a field", - "", - "SYNOPSIS", - " sethalo[,parameter] infile outfile", - "", - "DESCRIPTION", - " This operator sets the boundary in the east, west, south and north of the rectangular understood fields.", - " Positive values of the parameters increase the boundary in the selected direction. Negative values", - " decrease the field at the selected boundary. The new rows and columns are filled with the missing value.", - " With the optional parameter value a different fill value can be used. Global cyclic fields are filled", - " cyclically at the east and west borders, if the fill value is not set by the user.", - "", - "PARAMETER", - " east INTEGER East halo", - " west INTEGER West halo", - " south INTEGER South halo", - " north INTEGER North halo", - " value FLOAT Fill value (default is the missing value)", - nullptr -}; - -static const char *WctHelp[] = { - "NAME", - " wct - Windchill temperature", - "", - "SYNOPSIS", - " wct infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 and infile2 be time series of temperature and wind", - " speed records, then a corresponding time series of resulting windchill", - " temperatures is written to outfile. The wind chill temperature", - " calculation is only valid for a temperature of T <= 33 °C and a wind speed", - " of v >= 1.39 m/s. Whenever these conditions are not satisfied, a missing", - " value is written to outfile. Note that temperature and wind speed records", - " have to be given in units of °C and m/s, respectively.", - nullptr -}; - -static const char *FdnsHelp[] = { - "NAME", - " fdns - Frost days where no snow index per time period", - "", - "SYNOPSIS", - " fdns infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily minimum temperature TN", - " and infile2 be a corresponding series of daily surface snow", - " amounts. Then the number of days where TN < 0 °C and the surface ", - " snow amount is less than 1 cm is counted. The temperature TN", - " have to be given in units of Kelvin.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - nullptr -}; - -static const char *StrwinHelp[] = { - "NAME", - " strwin - Strong wind days index per time period", - "", - "SYNOPSIS", - " strwin[,v] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily maximum horizontal wind speed", - " VX, then the number of days where VX > v is counted. The horizontal wind", - " speed v is an optional parameter with default v = 10.5 m/s. A further", - " output variable is the maximum number of consecutive days with maximum wind", - " speed greater than or equal to v. Note that both VX and v have to be given in", - " units of m/s. Also note that the horizontal wind speed is defined as the", - " square root of the sum of squares of the zonal and meridional wind speeds.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - "", - "PARAMETER", - " v FLOAT Horizontal wind speed threshold (m/s, default v = 10.5 m/s)", - nullptr -}; - -static const char *StrbreHelp[] = { - "NAME", - " strbre - Strong breeze days index per time period", - "", - "SYNOPSIS", - " strbre infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily maximum horizontal wind speed", - " VX, then the number of days where VX is greater than or equal to 10.5 m/s ", - " is counted. A further output variable is the maximum number of consecutive", - " days with maximum wind speed greater than or equal to 10.5 m/s. Note that", - " VX is defined as the square root of the sum of squares of the zonal and", - " meridional wind speeds and have to be given in units of m/s.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - nullptr -}; - -static const char *StrgalHelp[] = { - "NAME", - " strgal - Strong gale days index per time period", - "", - "SYNOPSIS", - " strgal infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily maximum horizontal wind speed", - " VX, then the number of days where VX is greater than or equal to 20.5 m/s ", - " is counted. A further output variable is the maximum number of consecutive", - " days with maximum wind speed greater than or equal to 20.5 m/s. Note that", - " VX is defined as the square root of the sum of square of the zonal and", - " meridional wind speeds and have to be given in units of m/s.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - nullptr -}; - -static const char *HurrHelp[] = { - "NAME", - " hurr - Hurricane days index per time period", - "", - "SYNOPSIS", - " hurr infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily maximum horizontal wind speed", - " VX, then the number of days where VX is greater than or equal to 32.5 m/s", - " is counted. A further output variable is the maximum number of consecutive", - " days with maximum wind speed greater than or equal to 32.5 m/s. Note that", - " VX is defined as the square root of the sum of squares of the zonal and", - " meridional wind speeds and have to be given in units of m/s.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - nullptr -}; - -static const char *CMORliteHelp[] = { - "NAME", - " cmorlite - CMOR lite", - "", - "SYNOPSIS", - " cmorlite,table[,convert] infile outfile", - "", - "DESCRIPTION", - " The CMOR (Climate Model Output Rewriter) library comprises a set of", - " functions, that can be used to produce CF-compliant NetCDF files that ", - " fulfill the requirements of many of the climate community's standard", - " model experiments. These experiments are collectively referred to as", - " MIP's. Much of the metadata written to the output files is defined in", - " MIP-specific tables, typically made available from each MIP's web site.", - " ", - " The CDO operator cmorlite process the header and variable section", - " of such MIP tables and writes the result with the internal IO library CDI.", - " In addition to the CMOR 2 and 3 table format, the CDO parameter table format", - " is also supported. The following parameter table entries are available:", - " ", - " Entry & Type & Description ", - " name & WORD & Name of the variable", - " out_name & WORD & New name of the variable", - " type & WORD & Data type (real or double)", - " standard_name & WORD & As defined in the CF standard name table", - " long_name & STRING & Describing the variable", - " units & STRING & Specifying the units for the variable", - " comment & STRING & Information concerning the variable", - " cell_methods & STRING & Information concerning calculation of means or climatologies", - " cell_measures & STRING & Indicates the names of the variables containing cell areas and volumes", - " missing_value & FLOAT & Specifying how missing data will be identified", - " valid_min & FLOAT & Minimum valid value", - " valid_max & FLOAT & Maximum valid value", - " ok_min_mean_abs & FLOAT & Minimum absolute mean", - " ok_max_mean_abs & FLOAT & Maximum absolute mean", - " factor & FLOAT & Scale factor", - " delete & INTEGER & Set to 1 to delete variable", - " convert & INTEGER & Set to 1 to convert the unit if necessary", - " ", - " Most of the above entries are stored as variables attributes, some of them are handled differently.", - " The variable name is used as a search key for the parameter table. valid_min, valid_max,", - " ok_min_mean_abs and ok_max_mean_abs are used to check the range of the data.", - "", - "PARAMETER", - " table STRING Name of the CMOR table as specified from PCMDI", - " convert STRING Converts the units if necessary", - nullptr -}; - -static const char *VerifygridHelp[] = { - "NAME", - " verifygrid - Verify grid coordinates", - "", - "SYNOPSIS", - " verifygrid infile", - "", - "DESCRIPTION", - " This operator verifies the coordinates of all horizontal grids found in infile.", - " Among other things, it searches for duplicate cells, non-convex cells,", - " and whether the center is located outside the cell bounds.", - " Use the CDO option -v to output the position of these cells.", - " This information can be useful to avoid problems when interpolating the data.", - nullptr -}; - -static const char *HealpixHelp[] = { - "NAME", - " hpdegrade, hpupgrade - Change healpix resolution", - "", - "SYNOPSIS", - " <operator>,parameter infile outfile", - "", - "DESCRIPTION", - " Degrade or upgrade the resolution of a healpix grid.", - "", - "OPERATORS", - " hpdegrade Degrade healpix", - " Degrade the resolution of a healpix grid. The value of the target pixel is the mean of the source pixels.", - " hpupgrade Upgrade healpix", - " Upgrade the resolution of a healpix grid. The values of the target pixels is the value of the source pixel.", - "", - "PARAMETER", - " nside INTEGER The nside of the target healpix, must be a power of two [default: same as input].", - " order STRING Pixel ordering of the target healpix ('nested' or 'ring').", - " power FLOAT If non-zero, divide the result by (nside[in]/nside[out])**power. power=-2 keeps the sum of the map invariant.", - nullptr -}; - -static const char *NCL_windHelp[] = { - "NAME", - " uv2vr_cfd, uv2dv_cfd - Wind transformation", - "", - "SYNOPSIS", - " <operator>[,u,v,boundOpt,outMode] infile outfile", - "", - "DESCRIPTION", - " This module contains CDO operators with an interface to NCL functions.", - " The corresponding NCL functions have the same name. A more detailed description", - " of those NCL function can be found on the NCL homepage https://www.ncl.ucar.edu.", - "", - "OPERATORS", - " uv2vr_cfd U and V wind to relative vorticity", - " Computes relative vorticity for a latitude-longitude grid using centered finite differences.", - " The grid need not be global and missing values are allowed.", - " uv2dv_cfd U and V wind to divergence", - " Computes divergence for a latitude-longitude grid using centered finite differences.", - " The grid need not be global and missing values are allowed.", - "", - "PARAMETER", - " u STRING Name of variable u (default: u)", - " v STRING Name of variable v (default: v)", - " boundOpt INTEGER Boundary condition option (0-3) (default: 0/1 for cyclic grids)", - " outMode STRING Output mode new/append (default: new)", - nullptr -}; - -static const char *CMORHelp[] = { - "NAME", - " cmor - Climate Model Output Rewriting to produce CMIP-compliant data", - "", - "SYNOPSIS", - " cmor,MIPtable[,cmor_name=VarList[,key=value[,...]]] infile", - "", - "DESCRIPTION", - " ", - " ", - " The CDO operator cmor converts an infile into a CMIP-compliant format", - " by using the CMOR library. Each output file contains a single output variable.", - " The name of the output files are generated by CMOR according to a template based on the", - " DRS (Data reference Syntax) of the project. CMOR checks and applies the information delivered", - " through the project dependend MIPtable on the infile. Additional information", - " which is required for the conversion can be configured via keyvalues as optional parameters.", - " ", - " By specifying a variable selector keyvalue, e.g. cmor_name=tas, the user can", - " pre-select a subset of infile variables. If name or code is specified, a", - " corresponding cmor_name which can also be found in the MIPtable is also", - " required to map the infile variable to the CMOR-variable. For mapping more", - " variables at the operator call, one can specify a mapping table via keyword mapping_table.", - " ", - " Global attributes must be collected in info files and can be specified via keyword", - " info. All required and optional global attributes as well as information", - " about table file formats are given in the 'cdo cmor manual'.", - " ", - " If questions remain, do not hesitate to ask and send an email to wachsmannATdkrz.de.", - " ", - "", - "PARAMETER", - " MIPtable STRING Name of the MIP table as used by CMOR.", - " --------------------------------------------------------------------------------------------", - " cmor_name | cn STRING Variable selector and specified in the MIP table.", - " Comma-separated list of CMOR variable names.", - " Default is to process all variables.", - " name | n STRING Variable selector.", - " Name of a selected @file{infile} variable.", - " code | c INTEGER Variable selector. ", - " Three digits (GRIB) Code of a selected @file{infile} variable.", - " --------------------------------------------------------------------------------------------", - " info | i STRING Preprozessing.", - " Comma-separated list of filenames.", - " Containins global attributes and control keywords.", - " Default: CWD/.cdocmorinfo", - " grid_info | gi STRING Preprozessing.", - " NetCDF or table formatted file with model grid description.", - " Horizontal and vertical axes are substituted with the ones from grid info file.", - " mapping_table | mt STRING Preprozessing.", - " Fortran Namelist containing variable information for e.g. renaming.", - " keep_all_attributes | kaa STRING Preprozessing.", - " 'y' for passing all infile attributes. 'n' for discarding all infile attributes.", - " --------------------------------------------------------------------------------------------", - " drs | d CHARACTER Output control.", - " Do(=y, default) or do not(=n) move output into the project DRS structure.", - " drs_root | dr STRING Output control. CMOR output root directory.", - " Default: CWD.", - " output_mode | om CHARACTER Output control.", - " Either 'r' for replace (default) or 'a' for append mode.", - " last_chunk | lc STRING Output control. Filename of chunk to which shall be appended. ", - " max_size | ms INTEGER Output control. Limit of output file sie in GigaByte.", - " deflate_level | dl INTEGER Output control. Compression level. -1: No compression. 0: Only shuffle.", - " version_date | vd INTEGER Output control. Subdirectory name in CMIP6 DRS.", - " --------------------------------------------------------------------------------------------", - " required_time_units | rtu STRING Temporal description.", - " Time axis reference date specified by the experiment.", - " Format: 'days since YYYY-day-month hh:mm:ss'.", - " cell_methods | cm CHARACTER Temporal description.", - " Cell_methods of time axis.", - " Value is one of 'm' (default) , 'p', 'c', 'n', 'd'", - " --------------------------------------------------------------------------------------------", - " units | u STRING Variable attrbiute. Units of the variable.", - " Must be known by library UDunits.", - " variable_comment | vc STRING Variable attribute. Variable comment.", - " positive | p CHARACTER Variable attrbiute.", - " Positive flux direction, either 'u' for upward or 'd' for downward.", - " z_axis | za STRING Name of the coordinate variable associated with", - " the z-axis of the target variable.", - " character_axis | ca STRING Name of the coordinate variable associated with", - " a character axis of the target variable.", - " Valid axes names are: basin, vegtype or oline. ", - " t_axis | ta STRING Sets time values and time bounds to the nearest value", - " required by the project given by the value of t_axis.", - " Valid value is: cmip", - nullptr -}; - -static const char *MagplotHelp[] = { - "NAME", - " contour, shaded, grfill - Lat/Lon plot", - "", - "SYNOPSIS", - " <operator>,parameter infile obase", - "", - "DESCRIPTION", - " The operators in this module generates 2D Lon/Lat plots.", - " The data for the plot is read from infile.", - " Only data on rectilinear Lon/Lat grids are supported.", - " The output file will be named <obase>_<param>.<device> where param is the parameter name and", - " device is the device name. The default output file format is postscript,", - " this can be changed with the device parameter.", - " The type of the plot depends on the choosen operator.", - " ", - " Here is a list of all common plot parameters:", - " ", - " Keyname & Type & Description ", - " device & STRING & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)", - " projection & STRING & Projection (cylindrical, polar_stereographic, robinson, mercator)", - " style & STRING & Contour line style (solid, dash, dot, chain_dash, chain_dot)", - " min & FLOAT & Minimum value", - " max & FLOAT & Maximum value", - " lon_max & FLOAT & Maximum longitude of the image", - " lon_min & FLOAT & Minimum longitude of the image", - " lat_max & FLOAT & Maximum latitude of the image", - " lat_min & FLOAT & Minimum latitude of the image", - " count & INTEGER & Number of Contour levels / Colour bands ", - " interval & FLOAT & Interval in data units between two bands lines", - " list & INTEGER & List of levels to be plotted", - " RGB & STRING & TRUE or FALSE, to indicate, if the input colour is in RGB format", - " step_freq & INTEGER & Frequency of time steps to be considered for making the animation", - " & & (device=gif_animation). Default value is \"1\" (all time steps).", - " & & Will be ignored if input file has multiple variables.", - " file_split & STRING & TRUE or FALSE, to split the output file for each variable, if input has", - " & & multiple variables. Default value is \"FALSE\". Valid only for \"PS\" format.", - "", - "OPERATORS", - " contour Contour plot", - " The operator contour generates the discrete contour lines of the input field values.", - " The following additional parameters are valid for contour operator,", - " module in addition to the common plot parameters:", - " ", - " Keyname & Type & Description ", - " colour & STRING & Colour for drawing the contours", - " thickness & FLOAT & Thickness of the contour line", - " style & STRING & Line Style can be \"SOLID\", \"DASH\", \"DOT\", \"CHAIN_DASH\",", - " & & \"CHAIN_DOT\"", - " shaded Shaded contour plot", - " The operator shaded generates the filled contours of the given input field values.", - " The following additional parameters are valid for shaded contour and gridfill operator,", - " in addition to the common plot parameters.", - " ", - " Keyname & Type & Description ", - " colour_min & STRING & Colour for the Minimum colour band", - " colour_max & STRING & Colour for the Minimum colour band", - " colour_triad & STRING & Direction of colour sequencing for shading \"CW\" or \"ACW\",", - " & & to denote \"clockwise\" and \"anticlockwise\" respectively.", - " & & To be used in conjunction with \"colour_min\", \"colour_max\"", - " & & options. Default is \"ACW\"", - " colour_table & STRING & File with user specified colours with the format as", - " ", - " Example file for 6 colours in RGB format:", - " 6", - " RGB(0.0;0.0;1.0)", - " RGB(0.0;0.0;0.5)", - " RGB(0.0;0.5;0.5)", - " RGB(0.0;1.0;0.0)", - " RGB(0.5;0.5;0.0)", - " RGB(1.0;0.0;0.0)", - " ", - " grfill Shaded gridfill plot", - " The operator grfill is similar to satellite imaging and shades each cell (pixel) according", - " to the value of the field at that cell.", - "", - "PARAMETER", - " parameter STRING Comma-separated list of plot parameters", - "", - "NOTE", - " All colour parameter can be either standard name or in RGB format.", - " The valid standard name strings for \"colour\" are:", - " ", - " \"red\", \"green\", \"blue\", \"yellow\", \"cyan\", \"magenta\", \"black\", \"avocado\", \"beige\",", - " \"brick\", \"brown\", \"burgundy\", \"charcoal\", \"chestnut\", \"coral\", \"cream\", \"evergreen\",", - " \"gold\", \"grey\", \"khaki\", \"kellygreen\", \"lavender\", \"mustard\", \"navy\", \"ochre\",", - " \"olive\", \"peach\", \"pink\", \"rose\", \"rust\", \"sky\", \"tan\", \"tangerine\", \"turquoise\",", - " \"violet\", \"reddishpurple\", \"purplered\", \"purplishred\", \"orangishred\", \"redorange\",", - " \"reddishorange\", \"orange\", \"yellowishorange\", \"orangeyellow\", \"orangishyellow\",", - " \"greenishyellow\", \"yellowgreen\", \"yellowishgreen\", \"bluishgreen\", \"bluegreen\",", - " \"greenishblue\", \"purplishblue\", \"bluepurple\", \"bluishpurple\", \"purple\", \"white\"", - nullptr -}; - -static const char *MagvectorHelp[] = { - "NAME", - " vector - Lat/Lon vector plot", - "", - "SYNOPSIS", - " vector,parameter infile obase", - "", - "DESCRIPTION", - " This operator generates 2D Lon/Lat vector plots.", - " The data for the plot is read from infile. The input is expected to contain two velocity", - " components. Only data on rectilinear Lon/Lat grids are supported.", - " The output file will be named <obase>.<device> where device is the device name. ", - " The default output file format is postscript, this can be changed with the device parameter.", - " ", - " Here is a list of all vector plot parameters:", - " ", - " Keyname & Type & Description ", - " device & STRING & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)", - " projection & STRING & Projection (cylindrical, polar_stereographic, robinson, mercator)", - " thin_fac & FLOAT & Controls the actual number of wind arrows or flags plotted (default 2).", - " unit_vec & FLOAT & Wind speed in m/s represented by a unit vector (1.0cm)", - " step_freq & INTEGER & Frequency of time steps to be considered for making the animation", - " & & (device=gif_animation). Default value is \"1\" (all time steps).", - " & & Will be ignored if input file has multiple variables.", - "", - "PARAMETER", - " parameter STRING Comma-separated list of plot parameters", - nullptr -}; - -static const char *MaggraphHelp[] = { - "NAME", - " graph - Line graph plot", - "", - "SYNOPSIS", - " graph,parameter infiles outfile", - "", - "DESCRIPTION", - " This operator generates line graph plots.", - " The data for the plot is read from infiles. The result is written to outfile.", - " The default output file format is postscript, this can be changed with the device parameter.", - " ", - " Here is a list of all graph plot parameters:", - " ", - " Keyname & Type & Description ", - " device & STRING & Output device (ps, eps, pdf, png, gif, gif_animation, jpeg, svg, kml)", - " ymin & FLOAT & Minimum value of the y-axis data ", - " ymax & FLOAT & Maximum value of the y-axis data ", - " linewidth & INT & Linewidth (default 8)", - " stat & STRING & \"TRUE\" or \"FALSE\", to switch on the mean computation. Default is \"FALSE\".", - " & & Will be overridden to \"FALSE\", if input files have unequal number of time", - " & & steps or different start/end times. ", - " sigma & FLOAT & Standard deviation value for generating shaded back ground around the mean value.", - " & & To be used in conjunction with 'stat=\"TRUE\"' ", - " obsv & STRING & To indicate if the input files have an observation data, by setting to \"TRUE\".", - " & & Default value is \"FALSE\". The observation data should be the first file in the", - " & & input file list. The observation data is always plotted in black colour. ", - "", - "PARAMETER", - " parameter STRING Comma-separated list of plot parameters", - nullptr -}; - -static const char *EcaCddHelp[] = { - "NAME", - " eca_cdd, etccdi_cdd - Consecutive dry days index per time period", - "", - "SYNOPSIS", - " <operator>[,R[,N[,params]]] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily precipitation amount RR, then the largest number ", - " of consecutive days where RR is less than R is counted. R is an optional parameter with ", - " default R = 1 mm. A further output variable is the number of dry periods of more than N days.", - " Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_cdd Consecutive dry days index per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_cdd Consecutive dry days index per time period", - " The default output frequency is yearly.", - " Periods within overlapping years are accounted for the first year.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", - " N INTEGER Minimum number of days exceeded (default: N = 5)", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaCfdHelp[] = { - "NAME", - " eca_cfd - Consecutive frost days index per time period", - "", - "SYNOPSIS", - " eca_cfd[,N] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily minimum temperature TN, then the largest number of", - " consecutive days where TN < 0 °C is counted. Note that TN have to be given in units of Kelvin.", - " A further output variable is the number of frost periods of more than N days.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", - "", - "PARAMETER", - " N INTEGER Minimum number of days exceeded (default: N = 5)", - nullptr -}; - -static const char *EcaCsuHelp[] = { - "NAME", - " eca_csu - Consecutive summer days index per time period", - "", - "SYNOPSIS", - " eca_csu[,T[,N]] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily maximum temperature TX, then the largest number of consecutive", - " days where TX > T is counted. The number T is an optional parameter with default T = 25°C.", - " Note that TN have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.", - " A further output variable is the number of summer periods of more than N days.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", - "", - "PARAMETER", - " T FLOAT Temperature threshold (unit: °C; default: T = 25°C)", - " N INTEGER Minimum number of days exceeded (default: N = 5)", - nullptr -}; - -static const char *EcaCwdHelp[] = { - "NAME", - " eca_cwd, etccdi_cwd - Consecutive wet days index per time period", - "", - "SYNOPSIS", - " eca_cwd[,R[,N[,params]]] infile outfile", - " etccdi_cwd infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily precipitation amount RR, then the largest number ", - " of consecutive days where RR is at least R is counted. R is an optional parameter with ", - " default R = 1 mm. A further output variable is the number of wet periods of more than N days.", - " Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_cwd Consecutive wet days index per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - "", - "PARAMETER", - " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", - " N INTEGER Minimum number of days exceeded (default: N = 5)", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaCwdiHelp[] = { - "NAME", - " eca_cwdi - Cold wave duration index wrt mean of reference period", - "", - "SYNOPSIS", - " eca_cwdi[,nday[,T]] infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily minimum temperature TN, and let infile2 be the mean ", - " TNnorm of daily minimum temperatures for any period used as reference. Then counted is the number of days", - " where, in intervals of at least nday consecutive days, TN < TNnorm - T.", - " The numbers nday and T are optional parameters with default nday = 6 and T = 5°C. ", - " A further output variable is the number of cold waves longer than or equal to nday days.", - " TNnorm is calculated as the mean of minimum temperatures of a five day window centred on each calendar day ", - " of a given climate reference period. Note that both TN and TNnorm have to be given in the same units.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - "", - "PARAMETER", - " nday INTEGER Number of consecutive days (default: nday = 6)", - " T FLOAT Temperature offset (unit: °C; default: T = 5°C)", - nullptr -}; - -static const char *EcaCwfiHelp[] = { - "NAME", - " eca_cwfi, etccdi_csdi - ", - " Cold-spell days index wrt 10th percentile of reference period", - "", - "SYNOPSIS", - " <operator>[,nday[,params]] infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily mean temperature TG, and infile2 be the 10th", - " percentile TGn10 of daily mean temperatures for any period used as reference. ", - " Then counted is the number of days where, in intervals of at least nday consecutive days,", - " TG < TGn10. The number nday is an optional parameter with default nday = 6.", - " A further output variable is the number of cold-spell periods longer than or equal to nday days.", - " TGn10 is calculated as the 10th percentile of daily mean temperatures of a five day window ", - " centred on each calendar day of a given climate reference period. Note that both TG and TGn10 ", - " have to be given in the same units.", - "", - "OPERATORS", - " eca_cwfi Cold-spell days index wrt 10th percentile of reference period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_csdi Cold-spell duration index", - " The default output frequency is yearly.", - " Periods within overlapping years are accounted for the first year.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " nday INTEGER Number of consecutive days (default: nday = 6)", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaEtrHelp[] = { - "NAME", - " eca_etr - Intra-period extreme temperature range", - "", - "SYNOPSIS", - " eca_etr infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 and infile2 be time series of thr maximum and minimum", - " temperature TX and TN, respectively. Then the extreme temperature", - " range is the difference of the maximum of TX and the minimum of TN.", - " Note that TX and TN have to be given in the same units.", - " The date information of a timestep in outfile is the date of", - " the last contributing timesteps in infile1 and infile2.", - nullptr -}; - -static const char *EcaFdHelp[] = { - "NAME", - " eca_fd, etccdi_fd - Frost days index per time period", - "", - "SYNOPSIS", - " <operator>[,parameter] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily minimum temperature TN,", - " then the number of days where TN < 0 °C is counted. Note", - " that TN have to be given in units of Kelvin. Parameter is a", - " comma-separated list of \"key=value\" pairs.", - "", - "OPERATORS", - " eca_fd Frost days index per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_fd Frost days index per time period", - " The default output frequency is yearly.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaGslHelp[] = { - "NAME", - " eca_gsl - Thermal Growing season length index", - "", - "SYNOPSIS", - " eca_gsl[,nday[,T[,fland]]] infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily mean temperature TG, and infile2 be a land-water mask.", - " Within a period of 12 months, the thermal growing season length is officially defined as the number of days between:", - " - first occurrence of at least nday consecutive days with TG > T", - " - first occurrence of at least nday consecutive days with TG < T within the last 6 months", - " On northern hemisphere, this period corresponds with the regular year, whereas on southern hemisphere, it starts ", - " at July 1st. Please note, that this definition may lead to weird results concerning values TG = T: ", - " In the first half of the period, these days do not contribute to the gsl, but they do within the second half.", - " Moreover this definition could lead to discontinuous values in equatorial regions.", - " ", - " The numbers nday and T are optional parameter with default nday = 6 and T = 5°C. ", - " The number fland is an optional parameter with default value fland = 0.5 and denotes the fraction of ", - " a grid point that have to be covered by land in order to be included in the calculation. A further output variable ", - " is the start day of year of the growing season. Note that TG have to be given in units of Kelvin, whereas T ", - " have to be given in degrees Celsius.", - " ", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", - "", - "PARAMETER", - " nday INTEGER Number of consecutive days (default: nday = 6)", - " T FLOAT Temperature threshold (unit: °C; default: T = 5°C)", - " fland FLOAT Land fraction threshold (default: fland = 0.5)", - nullptr -}; - -static const char *EcaHdHelp[] = { - "NAME", - " eca_hd - Heating degree days per time period", - "", - "SYNOPSIS", - " eca_hd[,T1[,T2]] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily mean temperature TG, then the heating degree days ", - " are defined as the sum of T1 - TG, where only values TG < T2 are considered. ", - " If T1 and T2 are omitted, a temperature of 17°C is used for both parameters. ", - " If only T1 is given, T2 is set to T1. Note that TG have to be given in units ", - " of kelvin, whereas T1 and T2 have to be given in degrees Celsius.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", - "", - "PARAMETER", - " T1 FLOAT Temperature limit (unit: °C; default: T1 = 17°C)", - " T2 FLOAT Temperature limit (unit: °C; default: T2 = T1)", - nullptr -}; - -static const char *EcaHwdiHelp[] = { - "NAME", - " eca_hwdi - Heat wave duration index wrt mean of reference period", - "", - "SYNOPSIS", - " eca_hwdi[,nday[,T]] infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily maximum temperature TX, and let infile2 be the mean ", - " TXnorm of daily maximum temperatures for any period used as reference. Then counted is the number of days", - " where, in intervals of at least nday consecutive days, TX > TXnorm + T.", - " The numbers nday and T are optional parameters with default nday = 6 and T = 5°C. ", - " A further output variable is the number of heat waves longer than or equal to nday days. ", - " TXnorm is calculated as the mean of maximum temperatures of a five day window centred on each calendar day", - " of a given climate reference period. Note that both TX and TXnorm have to be given in the same units.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - "", - "PARAMETER", - " nday INTEGER Number of consecutive days (default: nday = 6)", - " T FLOAT Temperature offset (unit: °C; default: T = 5°C)", - nullptr -}; - -static const char *EcaHwfiHelp[] = { - "NAME", - " eca_hwfi, etccdi_wsdi - ", - " Warm spell days index wrt 90th percentile of reference period", - "", - "SYNOPSIS", - " eca_hwfi[,nday[,params]] infile1 infile2 outfile", - " etccdi_wsdi infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily mean temperature TG, and ", - " infile2 be the 90th percentile TGn90 of daily mean temperatures", - " for any period used as reference. Then counted is the number of days", - " where, in intervals of at least nday consecutive days, TG > TGn90. The", - " number nday is an optional parameter with default nday = 6. A further", - " output variable is the number of warm-spell periods longer than or", - " equal to nday days. ", - " TGn90 is calculated as the 90th percentile of daily mean temperatures of a five ", - " day window centred on each calendar day of a given climate reference period.", - " Note that both TG and TGn90 have to be given in the same units.", - " Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_hwfi Warm spell days index wrt 90th percentile of reference period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - "", - "PARAMETER", - " nday INTEGER Number of consecutive days (default: nday = 6)", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaIdHelp[] = { - "NAME", - " eca_id, etccdi_id - Ice days index per time period", - "", - "SYNOPSIS", - " <operator>[,parameter] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily maximum temperature TX,", - " then the number of days where TX < 0 °C is counted. Note", - " that TX have to be given in units of Kelvin. Parameter is a", - " comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_id Ice days index per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_id Ice days index per time period", - " The default output frequency is yearly.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaR75pHelp[] = { - "NAME", - " eca_r75p - Moderate wet days wrt 75th percentile of reference period", - "", - "SYNOPSIS", - " eca_r75p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the percentage of wet days with RR > RRn75 is calculated. ", - " RRn75 is calculated as the 75th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,75.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaR75ptotHelp[] = { - "NAME", - " eca_r75ptot - Precipitation percent due to R75p days", - "", - "SYNOPSIS", - " eca_r75ptot infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn75 to the total ", - " precipitation sum is calculated. ", - " RRn75 is calculated as the 75th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,75.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaR90pHelp[] = { - "NAME", - " eca_r90p - Wet days wrt 90th percentile of reference period", - "", - "SYNOPSIS", - " eca_r90p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the percentage of wet days with RR > RRn90 is calculated. ", - " RRn90 is calculated as the 90th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,90.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaR90ptotHelp[] = { - "NAME", - " eca_r90ptot - Precipitation percent due to R90p days", - "", - "SYNOPSIS", - " eca_r90ptot infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn90 to the total ", - " precipitation sum is calculated. ", - " RRn90 is calculated as the 90th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,90.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaR95pHelp[] = { - "NAME", - " eca_r95p - Very wet days wrt 95th percentile of reference period", - "", - "SYNOPSIS", - " eca_r95p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the percentage of wet days with RR > RRn95 is calculated. ", - " RRn95 is calculated as the 95th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,95.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaR95ptotHelp[] = { - "NAME", - " eca_r95ptot - Precipitation percent due to R95p days", - "", - "SYNOPSIS", - " eca_r95ptot infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn95 to the total ", - " precipitation sum is calculated. ", - " RRn95 is calculated as the 95th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,95.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaR99pHelp[] = { - "NAME", - " eca_r99p - Extremely wet days wrt 99th percentile of reference period", - "", - "SYNOPSIS", - " eca_r99p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the percentage of wet days with RR > RRn99 is calculated. ", - " RRn99 is calculated as the 99th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,99.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaR99ptotHelp[] = { - "NAME", - " eca_r99ptot - Precipitation percent due to R99p days", - "", - "SYNOPSIS", - " eca_r99ptot infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)", - " and infile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ", - " used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn99 to the total ", - " precipitation sum is calculated. ", - " RRn99 is calculated as the 99th percentile of all wet days of a given climate reference period.", - " Usually infile2 is generated by the operator ydaypctl,99.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaPdHelp[] = { - "NAME", - " eca_pd, eca_r10mm, eca_r20mm, etccdi_r1mm - ", - " Precipitation days index per time period", - "", - "SYNOPSIS", - " eca_pd,x infile outfile", - " eca_r10mm infile outfile", - " eca_r20mm infile outfile", - " etccdi_r1mm[,parameter] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]),", - " then the number of days where RR is at least x mm is counted. ", - " eca_r10mm and eca_r20mm are specific ECA operators with a daily precipitation amount of 10 and 20 mm respectively.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile", - " except for the etccdi operator. Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_pd Precipitation days index per time period", - " Generic ECA operator with daily precipitation sum exceeding x mm.", - " eca_r10mm Heavy precipitation days index per time period", - " Specific ECA operator with daily precipitation sum exceeding 10 mm.", - " eca_r20mm Very heavy precipitation days index per time period", - " Specific ECA operator with daily precipitation sum exceeding 20 mm.", - " etccdi_r1mm Precipitation days index per time period", - " The default output frequency is yearly.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " x FLOAT Daily precipitation amount threshold in [mm]", - " freq STRING Output frequency (year, month)", - "", - "NOTE", - " Precipitation rates in [mm/s] have to be converted to precipitation amounts (multiply with 86400 s).", - " Apart from metadata information the result of eca_pd,1 and eca_rr1 is the same.", - nullptr -}; - -static const char *EcaRr1Help[] = { - "NAME", - " eca_rr1 - Wet days index per time period", - "", - "SYNOPSIS", - " eca_rr1[,R] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]), then", - " the number of days where RR is at least R is counted. R is an optional parameter with default R = 1 mm. ", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", - "", - "PARAMETER", - " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", - nullptr -}; - -static const char *EcaRx1dayHelp[] = { - "NAME", - " eca_rx1day, etccdi_rx1day - ", - " Highest one day precipitation amount per time period", - "", - "SYNOPSIS", - " <operator>[,parameter] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily precipitation amount RR,", - " then the maximum of RR is written to outfile. If the optional", - " parameter mode is set to 'm' the maximum daily precipitation", - " amounts are determined for each month. ", - " Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_rx1day Highest one day precipitation amount per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_rx1day Maximum 1-day Precipitation", - " The default output frequency is yearly.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaRx5dayHelp[] = { - "NAME", - " eca_rx5day, etccdi_rx5day - ", - " Highest five-day precipitation amount per time period", - "", - "SYNOPSIS", - " <operator>[,x[,params]] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of 5-day precipitation totals RR, then the maximum of RR is written to outfile. ", - " A further output variable is the number of 5 day period with precipitation totals greater than x mm, where x ", - " is an optional parameter with default x = 50 mm.", - " Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_rx5day Highest five-day precipitation amount per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_rx5day Highest five-day precipitation amount per time period", - " The default output frequency is yearly.", - " Periods within overlapping years are accounted for the first year.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " x FLOAT Precipitation threshold (unit: mm; default: x = 50 mm)", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaSdiiHelp[] = { - "NAME", - " eca_sdii - Simple daily intensity index per time period", - "", - "SYNOPSIS", - " eca_sdii[,R] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily precipitation amount RR, then the mean precipitation amount at ", - " wet days (RR >= R) is written to outfile. R is an optional parameter with default R = 1 mm.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile.", - "", - "PARAMETER", - " R FLOAT Precipitation threshold (unit: mm; default: R = 1 mm)", - nullptr -}; - -static const char *EcaSuHelp[] = { - "NAME", - " eca_su, etccdi_su - Summer days index per time period", - "", - "SYNOPSIS", - " <operator>[,T[,params]] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily maximum temperature TX, then the number of days where ", - " TX > T is counted. The number T is an optional parameter with default T = 25°C. ", - " Note that TX have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.", - " Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_su Summer days index per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_su Summer days index per time period", - " The default output frequency is yearly.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " T FLOAT Temperature threshold (unit: °C; default: T = 25°C)", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaTg10pHelp[] = { - "NAME", - " eca_tg10p - Cold days percent wrt 10th percentile of reference period", - "", - "SYNOPSIS", - " eca_tg10p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily mean temperature TG, and", - " infile2 be the 10th percentile TGn10 of daily mean temperatures", - " for any period used as reference. Then the percentage of time where ", - " TG < TGn10 is calculated.", - " TGn10 is calculated as the 10th percentile of daily mean temperatures of a five ", - " day window centred on each calendar day of a given climate reference period.", - " Note that both TG and TGn10 have to be given in the same units.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaTg90pHelp[] = { - "NAME", - " eca_tg90p - Warm days percent wrt 90th percentile of reference period", - "", - "SYNOPSIS", - " eca_tg90p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily mean temperature TG, and", - " infile2 be the 90th percentile TGn90 of daily mean temperatures", - " for any period used as reference. Then the percentage of time where TG > TGn90 ", - " is calculated. ", - " TGn90 is calculated as the 90th percentile of daily mean temperatures of a five ", - " day window centred on each calendar day of a given climate reference period.", - " Note that both TG and TGn90 have to be given in the same units.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaTn10pHelp[] = { - "NAME", - " eca_tn10p - Cold nights percent wrt 10th percentile of reference period", - "", - "SYNOPSIS", - " eca_tn10p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time serie of the daily minimum temperature TN, and", - " infile2 be the 10th percentile TNn10 of daily minimum temperatures", - " for any period used as reference. Then the percentage of time where TN < TNn10 ", - " is calculated.", - " TNn10 is calculated as the 10th percentile of daily minimum temperatures of a five ", - " day window centred on each calendar day of a given climate reference period.", - " Note that both TN and TNn10 have to be given in the same units.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaTn90pHelp[] = { - "NAME", - " eca_tn90p - Warm nights percent wrt 90th percentile of reference period", - "", - "SYNOPSIS", - " eca_tn90p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily minimum temperature TN, and infile2 be the ", - " 90th percentile TNn90 of daily minimum temperatures for any period used as reference. ", - " Then the percentage of time where TN > TNn90 is calculated. TNn90 is calculated as the 90th percentile", - " of daily minimum temperatures of a five day window centred on each calendar day of a given climate", - " reference period. Note that both TN and TNn90 have to be given in the same units.", - " The date information of a timestep in outfile is the date of the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaTrHelp[] = { - "NAME", - " eca_tr, etccdi_tr - Tropical nights index per time period", - "", - "SYNOPSIS", - " <operator>[,T[,params]] infile outfile", - "", - "DESCRIPTION", - " Let infile be a time series of the daily minimum temperature TN, then the number of days where ", - " TN > T is counted. The number T is an optional parameter with default T = 20°C. ", - " Note that TN have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.", - " Parameter is a comma-separated list of \"key=values\" pairs.", - "", - "OPERATORS", - " eca_tr Tropical nights index per time period", - " The operator counts over the entire time series.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile.", - " etccdi_tr Tropical nights index per time period", - " The default output frequency is yearly.", - " The date information of a timestep in outfile is the mid of", - " the frequency interval.", - "", - "PARAMETER", - " T FLOAT Temperature threshold (unit: °C; default: T = 20°C)", - " freq STRING Output frequency (year, month)", - nullptr -}; - -static const char *EcaTx10pHelp[] = { - "NAME", - " eca_tx10p - Very cold days percent wrt 10th percentile of reference period", - "", - "SYNOPSIS", - " eca_tx10p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily maximum temperature TX, and", - " infile2 be the 10th percentile TXn10 of daily maximum temperatures", - " for any period used as reference. Then the percentage of time where TX < TXn10.", - " is calculated.", - " TXn10 is calculated as the 10th percentile of daily maximum temperatures of a five ", - " day window centred on each calendar day of a given climate reference period.", - " Note that both TX and TXn10 have to be givenin the same units.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaTx90pHelp[] = { - "NAME", - " eca_tx90p - Very warm days percent wrt 90th percentile of reference period", - "", - "SYNOPSIS", - " eca_tx90p infile1 infile2 outfile", - "", - "DESCRIPTION", - " Let infile1 be a time series of the daily maximum temperature TX, and", - " infile2 be the 90th percentile TXn90 of daily maximum temperatures", - " for any period used as reference. Then the percentage of time where TX > TXn90.", - " is calculated.", - " TXn90 is calculated as the 90th percentile of daily maximum temperatures of a five ", - " day window centred on each calendar day of a given climate reference period.", - " Note that both TX and TXn90 have to be given in the same units.", - " The date information of a timestep in outfile is the date of", - " the last contributing timestep in infile1.", - nullptr -}; - -static const char *EcaEtccdiHelp[] = { - "NAME", - " etccdi_tx90p, etccdi_tx10p, etccdi_tn90p, etccdi_tn10p, etccdi_r95p, ", - " etccdi_r99p - ", - " ETCCDI conform index for a reference periode calculated with bootstrapping", - "", - "SYNOPSIS", - " <operator>,n,startboot,endboot[,m] infile1 infile2 infile3 outfile", - "", - "DESCRIPTION", - " This module enables to compute Climate Extremes Indices according to the method recommended", - " by the Expert Team on Climate Change Detection and Indices. It differs from the", - " corresponding eca_* indices by applying bootstrapping for a reference period", - " (see Zhang et al. 2005) given by startboot and endboot and using the R-type 8 method ", - " for percentile calculation.", - " A requirement for correct percentile calculation is that", - " CDO_PCTL_NBINS>=window*(endboot-startboot+1)*(sizeof(double)/sizeof(int))+2", - " This demands for high working storage since the entire data of the bootstrapping interval", - " need to be hold in storage. Otherwise, a histogram is used to calculate the percentile.", - " infile2 (infile3) contains the daily minimum (maximum) of the bootstrapping interval.", - " If m=m, the output variable will be saved monthly, otherwise with yearly frequency.", - "", - "OPERATORS", - " etccdi_tx90p Percentage of Days when Daily Maximum Temperature is Above the 90th Percentile", - " etccdi_tx10p Percentage of Days when Daily Maximum Temperature is Below the 10th Percentile", - " etccdi_tn90p Percentage of Days when Daily Minimum Temperature is Above the 90th Percentile", - " etccdi_tn10p Percentage of Days when Daily Minimum Temperature is Below the 10th Percentile", - " etccdi_r95p Annual Total Precipitation when Daily Precipitation Exceeds the 95th Percentile of Wet Day Precipitation", - " etccdi_r99p Annual Total Precipitation when Daily Precipitation Exceeds the 99th Percentile of Wet Day Precipitation", - "", - "PARAMETER", - " n INTEGER Window days, number of timesteps", - " startboot INTEGER First year of bootstrapping interval", - " endboot INTEGER Last year of bootstrapping interval", - " m CHARACTER Output frequency", - "", - "ENVIRONMENT", - " CDO_PCTL_NBINS", - " Sets the number of histogram bins. The default number is 101.", - nullptr -}; -// clang-format on +#include <vector> +#include <string_view> + +typedef std::vector<std::string_view> CdoHelp; + +extern const CdoHelp InfoHelp; +extern const CdoHelp SinfoHelp; +extern const CdoHelp XSinfoHelp; +extern const CdoHelp DiffHelp; +extern const CdoHelp NinfoHelp; +extern const CdoHelp ShowinfoHelp; +extern const CdoHelp ShowattributeHelp; +extern const CdoHelp FiledesHelp; +extern const CdoHelp ApplyHelp; +extern const CdoHelp CopyHelp; +extern const CdoHelp TeeHelp; +extern const CdoHelp PackHelp; +extern const CdoHelp UnpackHelp; +extern const CdoHelp BitroundingHelp; +extern const CdoHelp ReplaceHelp; +extern const CdoHelp DuplicateHelp; +extern const CdoHelp MergegridHelp; +extern const CdoHelp MergeHelp; +extern const CdoHelp SplitHelp; +extern const CdoHelp SplittimeHelp; +extern const CdoHelp SplitselHelp; +extern const CdoHelp SplitdateHelp; +extern const CdoHelp DistgridHelp; +extern const CdoHelp CollgridHelp; +extern const CdoHelp SelectHelp; +extern const CdoHelp SelmultiHelp; +extern const CdoHelp SelvarHelp; +extern const CdoHelp SeltimeHelp; +extern const CdoHelp SelboxHelp; +extern const CdoHelp SelregionHelp; +extern const CdoHelp SelgridcellHelp; +extern const CdoHelp SamplegridHelp; +extern const CdoHelp SelyearidxHelp; +extern const CdoHelp SelsurfaceHelp; +extern const CdoHelp CondHelp; +extern const CdoHelp Cond2Help; +extern const CdoHelp CondcHelp; +extern const CdoHelp MapReduceHelp; +extern const CdoHelp CompHelp; +extern const CdoHelp CompcHelp; +extern const CdoHelp YmoncompHelp; +extern const CdoHelp SetattributeHelp; +extern const CdoHelp SetpartabHelp; +extern const CdoHelp SetHelp; +extern const CdoHelp SettimeHelp; +extern const CdoHelp ChangeHelp; +extern const CdoHelp SetgridHelp; +extern const CdoHelp SetzaxisHelp; +extern const CdoHelp InvertHelp; +extern const CdoHelp InvertlevHelp; +extern const CdoHelp ShiftxyHelp; +extern const CdoHelp MaskregionHelp; +extern const CdoHelp MaskboxHelp; +extern const CdoHelp SetboxHelp; +extern const CdoHelp EnlargeHelp; +extern const CdoHelp SetmissHelp; +extern const CdoHelp VertfillmissHelp; +extern const CdoHelp TimfillmissHelp; +extern const CdoHelp SetgridcellHelp; +extern const CdoHelp ExprHelp; +extern const CdoHelp MathHelp; +extern const CdoHelp ArithcHelp; +extern const CdoHelp ArithHelp; +extern const CdoHelp DayarithHelp; +extern const CdoHelp MonarithHelp; +extern const CdoHelp YeararithHelp; +extern const CdoHelp YhourarithHelp; +extern const CdoHelp YdayarithHelp; +extern const CdoHelp YmonarithHelp; +extern const CdoHelp YseasarithHelp; +extern const CdoHelp ArithdaysHelp; +extern const CdoHelp ArithlatHelp; +extern const CdoHelp TimcumsumHelp; +extern const CdoHelp ConsecstatHelp; +extern const CdoHelp VarsstatHelp; +extern const CdoHelp EnsstatHelp; +extern const CdoHelp Ensstat2Help; +extern const CdoHelp EnsvalHelp; +extern const CdoHelp FldstatHelp; +extern const CdoHelp ZonstatHelp; +extern const CdoHelp MerstatHelp; +extern const CdoHelp GridboxstatHelp; +extern const CdoHelp RemapstatHelp; +extern const CdoHelp VertstatHelp; +extern const CdoHelp TimselstatHelp; +extern const CdoHelp TimselpctlHelp; +extern const CdoHelp RunstatHelp; +extern const CdoHelp RunpctlHelp; +extern const CdoHelp TimstatHelp; +extern const CdoHelp TimpctlHelp; +extern const CdoHelp HourstatHelp; +extern const CdoHelp HourpctlHelp; +extern const CdoHelp DaystatHelp; +extern const CdoHelp DaypctlHelp; +extern const CdoHelp MonstatHelp; +extern const CdoHelp MonpctlHelp; +extern const CdoHelp YearmonstatHelp; +extern const CdoHelp YearstatHelp; +extern const CdoHelp YearpctlHelp; +extern const CdoHelp SeasstatHelp; +extern const CdoHelp SeaspctlHelp; +extern const CdoHelp YhourstatHelp; +extern const CdoHelp DhourstatHelp; +extern const CdoHelp YdaystatHelp; +extern const CdoHelp YdaypctlHelp; +extern const CdoHelp YmonstatHelp; +extern const CdoHelp YmonpctlHelp; +extern const CdoHelp YseasstatHelp; +extern const CdoHelp YseaspctlHelp; +extern const CdoHelp YdrunstatHelp; +extern const CdoHelp YdrunpctlHelp; +extern const CdoHelp FldcorHelp; +extern const CdoHelp TimcorHelp; +extern const CdoHelp FldcovarHelp; +extern const CdoHelp TimcovarHelp; +extern const CdoHelp RegresHelp; +extern const CdoHelp DetrendHelp; +extern const CdoHelp TrendHelp; +extern const CdoHelp TrendarithHelp; +extern const CdoHelp EOFsHelp; +extern const CdoHelp EofcoeffHelp; +extern const CdoHelp RemapbilHelp; +extern const CdoHelp RemapbicHelp; +extern const CdoHelp RemapnnHelp; +extern const CdoHelp RemapdisHelp; +extern const CdoHelp RemapconHelp; +extern const CdoHelp RemaplafHelp; +extern const CdoHelp RemapHelp; +extern const CdoHelp RemapetaHelp; +extern const CdoHelp VertintmlHelp; +extern const CdoHelp VertintapHelp; +extern const CdoHelp VertintghHelp; +extern const CdoHelp IntlevelHelp; +extern const CdoHelp Intlevel3dHelp; +extern const CdoHelp InttimeHelp; +extern const CdoHelp IntyearHelp; +extern const CdoHelp SpectralHelp; +extern const CdoHelp SpecconvHelp; +extern const CdoHelp Wind2Help; +extern const CdoHelp WindHelp; +extern const CdoHelp FourierHelp; +extern const CdoHelp ImportbinaryHelp; +extern const CdoHelp ImportcmsafHelp; +extern const CdoHelp ImportamsrHelp; +extern const CdoHelp InputHelp; +extern const CdoHelp OutputHelp; +extern const CdoHelp OutputtabHelp; +extern const CdoHelp OutputgmtHelp; +extern const CdoHelp GradsdesHelp; +extern const CdoHelp AfterburnerHelp; +extern const CdoHelp FilterHelp; +extern const CdoHelp GridcellHelp; +extern const CdoHelp SmoothHelp; +extern const CdoHelp DeltatHelp; +extern const CdoHelp ReplacevaluesHelp; +extern const CdoHelp GetgridcellHelp; +extern const CdoHelp VargenHelp; +extern const CdoHelp TimsortHelp; +extern const CdoHelp WindTransHelp; +extern const CdoHelp RotuvbHelp; +extern const CdoHelp MrotuvbHelp; +extern const CdoHelp MastrfuHelp; +extern const CdoHelp PressureHelp; +extern const CdoHelp DeriveparHelp; +extern const CdoHelp AdisitHelp; +extern const CdoHelp RhopotHelp; +extern const CdoHelp HistogramHelp; +extern const CdoHelp SethaloHelp; +extern const CdoHelp WctHelp; +extern const CdoHelp FdnsHelp; +extern const CdoHelp StrwinHelp; +extern const CdoHelp StrbreHelp; +extern const CdoHelp StrgalHelp; +extern const CdoHelp HurrHelp; +extern const CdoHelp CMORliteHelp; +extern const CdoHelp VerifygridHelp; +extern const CdoHelp HealpixHelp; +extern const CdoHelp NCL_windHelp; +extern const CdoHelp CMORHelp; +extern const CdoHelp MagplotHelp; +extern const CdoHelp MagvectorHelp; +extern const CdoHelp MaggraphHelp; +extern const CdoHelp EcaCddHelp; +extern const CdoHelp EcaCfdHelp; +extern const CdoHelp EcaCsuHelp; +extern const CdoHelp EcaCwdHelp; +extern const CdoHelp EcaCwdiHelp; +extern const CdoHelp EcaCwfiHelp; +extern const CdoHelp EcaEtrHelp; +extern const CdoHelp EcaFdHelp; +extern const CdoHelp EcaGslHelp; +extern const CdoHelp EcaHdHelp; +extern const CdoHelp EcaHwdiHelp; +extern const CdoHelp EcaHwfiHelp; +extern const CdoHelp EcaIdHelp; +extern const CdoHelp EcaR75pHelp; +extern const CdoHelp EcaR75ptotHelp; +extern const CdoHelp EcaR90pHelp; +extern const CdoHelp EcaR90ptotHelp; +extern const CdoHelp EcaR95pHelp; +extern const CdoHelp EcaR95ptotHelp; +extern const CdoHelp EcaR99pHelp; +extern const CdoHelp EcaR99ptotHelp; +extern const CdoHelp EcaPdHelp; +extern const CdoHelp EcaRr1Help; +extern const CdoHelp EcaRx1dayHelp; +extern const CdoHelp EcaRx5dayHelp; +extern const CdoHelp EcaSdiiHelp; +extern const CdoHelp EcaSuHelp; +extern const CdoHelp EcaTg10pHelp; +extern const CdoHelp EcaTg90pHelp; +extern const CdoHelp EcaTn10pHelp; +extern const CdoHelp EcaTn90pHelp; +extern const CdoHelp EcaTrHelp; +extern const CdoHelp EcaTx10pHelp; +extern const CdoHelp EcaTx90pHelp; +extern const CdoHelp EcaEtccdiHelp; #endif diff --git a/src/par_io.cc b/src/par_io.cc index f6003ee252b41f24d6ed91ebbad6af8bd092e8a2..028a3456a750524430d6e5d06c1fcda4b84f4a44 100644 --- a/src/par_io.cc +++ b/src/par_io.cc @@ -23,19 +23,19 @@ read_record(void *arg) auto streamID = read_arg->streamID; auto p_varID = read_arg->varID; auto p_levelID = read_arg->levelID; - auto p_nmiss = read_arg->nmiss; + auto p_numMissVals = read_arg->numMissVals; auto p_array = read_arg->array; // fprintf(stderr, "read_record: streamID = %d\n", streamID); cdo_inq_record(streamID, p_varID, p_levelID); - cdo_read_record(streamID, p_array, p_nmiss); + cdo_read_record(streamID, p_array, p_numMissVals); // fprintf(stderr, "read_record: varID %d levelID %d\n", *p_varID, *p_levelID); return nullptr; } void -par_read_record(CdoStreamID streamID, int *varID, int *levelID, double *array, size_t *nmiss, par_io_t *parIO) +par_read_record(CdoStreamID streamID, int *varID, int *levelID, double *array, size_t *numMissVals, par_io_t *parIO) { bool lpario = false; int recID = 0, nrecs = 0; @@ -59,7 +59,7 @@ par_read_record(CdoStreamID streamID, int *varID, int *levelID, double *array, s read_arg.streamID = streamID; read_arg.varID = varID; read_arg.levelID = levelID; - read_arg.nmiss = nmiss; + read_arg.numMissVals = numMissVals; read_arg.array = array; read_record(&read_arg); @@ -73,7 +73,7 @@ par_read_record(CdoStreamID streamID, int *varID, int *levelID, double *array, s *varID = parIO->varID; *levelID = parIO->levelID; - *nmiss = parIO->nmiss; + *numMissVals = parIO->numMissVals; // fprintf(stderr, "parIO2: %ld streamID %d %d %d\n", (long)thrID, streamID, *varID, *levelID); array_copy(parIO->array_size, parIO->array, array); } @@ -92,7 +92,7 @@ par_read_record(CdoStreamID streamID, int *varID, int *levelID, double *array, s read_arg->streamID = streamID; read_arg->varID = &parIO->varID; read_arg->levelID = &parIO->levelID; - read_arg->nmiss = &parIO->nmiss; + read_arg->numMissVals = &parIO->numMissVals; read_arg->array = parIO->array; // fprintf(stderr, "pthread_create: streamID %d %d\n", read_arg->streamID,streamID); diff --git a/src/par_io.h b/src/par_io.h index 3bd32f83f17e5d4d31c73d28cb60247aa3124a51..8a51b80cc6b719b882e7d23c56d9970698f56eea 100644 --- a/src/par_io.h +++ b/src/par_io.h @@ -10,19 +10,20 @@ #endif #include <cstddef> +#include "cdoStream.h" struct read_arg_t { CdoStreamID streamID; int *varID, *levelID; - size_t *nmiss; + size_t *numMissVals; double *array; }; struct par_io_t { int varID, levelID; - size_t nmiss; + size_t numMissVals; double *array; int array_size; int recID, nrecs; @@ -33,6 +34,6 @@ struct par_io_t #endif }; -void par_read_record(CdoStreamID streamID, int *varID, int *levelID, double *array, size_t *nmiss, par_io_t *parIO); +void par_read_record(CdoStreamID streamID, int *varID, int *levelID, double *array, size_t *numMissVals, par_io_t *parIO); #endif /* PAR_IO_H */ diff --git a/src/param_conversion.cc b/src/param_conversion.cc index ec78adadd24bdca52369a966e896ce39931d58be..c648c90cf2ca832fb51a3633ea88b730c0e3741a 100644 --- a/src/param_conversion.cc +++ b/src/param_conversion.cc @@ -183,6 +183,25 @@ parameter_to_intlist(const std::string &string) return parameter_to_intlist(string.c_str()); } +double +radius_str_to_meter(const std::string &string) +{ + char *endptr = nullptr; + auto radius = strtod(string.c_str(), &endptr); + + if (*endptr != 0) + { + if (std::strncmp(endptr, "km", 2) == 0) + radius *= 1000; + else if (std::strncmp(endptr, "m", 1) == 0) + ; + else + cdo_abort("Float parameter >%s< contains invalid character at position %d!", string, (int) (endptr - string.c_str() + 1)); + } + + return radius; +} + double radius_str_to_deg(const std::string &string) { @@ -192,9 +211,9 @@ radius_str_to_deg(const std::string &string) if (*endptr != 0) { if (std::strncmp(endptr, "km", 2) == 0) - radius = 360 * ((radius * 1000) / (2 * PlanetRadius * M_PI)); + radius = 360 * ((radius * 1000) / (2.0 * PlanetRadiusDefault * M_PI)); else if (std::strncmp(endptr, "m", 1) == 0) - radius = 360 * ((radius) / (2 * PlanetRadius * M_PI)); + radius = 360 * ((radius) / (2.0 * PlanetRadiusDefault * M_PI)); else if (std::strncmp(endptr, "deg", 3) == 0) ; else if (std::strncmp(endptr, "rad", 3) == 0) @@ -223,22 +242,25 @@ string_to_param(const std::string ¶mstr) return string_to_param(paramstr.c_str()); } -void -param_to_string(int param, char *paramstr, int maxlen) +std::string +param_to_string(int param) { + char paramstr[CDI_MAX_NAME]; int dis, cat, num; cdiDecodeParam(param, &num, &cat, &dis); - size_t umaxlen = (maxlen >= 0) ? (unsigned) maxlen : 0U; + int maxlen = sizeof(paramstr); int len; if (dis == 255 && (cat == 255 || cat == 0)) - len = std::snprintf(paramstr, umaxlen, "%03d", num); + len = std::snprintf(paramstr, maxlen, "%03d", num); else if (dis == 255) - len = std::snprintf(paramstr, umaxlen, "%03d.%03d", num, cat); + len = std::snprintf(paramstr, maxlen, "%03d.%03d", num, cat); else - len = std::snprintf(paramstr, umaxlen, "%03d.%03d.%03d", num, cat, dis); + len = std::snprintf(paramstr, maxlen, "%03d.%03d.%03d", num, cat, dis); if (len >= maxlen || len < 0) cdo_abort("Internal problem (%s): size of input string is too small!", __func__); + + return std::string{paramstr}; } /* time/date/season converisons */ @@ -268,10 +290,7 @@ season_to_months(const char *season, int *imonths) size_t ke = ks + len; for (size_t k = ks; k < ke; ++k) imonths[imons[k]]++; } - else - { - cdo_abort("Season %s not available!", season); - } + else { cdo_abort("Season %s not available!", season); } } } diff --git a/src/param_conversion.h b/src/param_conversion.h index 662a0e528a8d5ef5ef9f2fb8a9b986597e130a8f..d4ff737678a93f15c5da1568ceb3e6c7f5eece8c 100644 --- a/src/param_conversion.h +++ b/src/param_conversion.h @@ -21,11 +21,11 @@ long parameter_to_long(const std::string &string); size_t parameter_to_size_t(const std::string &string); int parameter_to_intlist(const std::string &string); +double radius_str_to_meter(const std::string &string); double radius_str_to_deg(const std::string &string); int string_to_param(const std::string ¶mstr); -int string_to_param(const char *paramstr); -void param_to_string(int param, char *paramstr, int maxlen); +std::string param_to_string(int param); /* time/date/season converisons */ /* =================================================================================== */ diff --git a/src/parse_literals.cc b/src/parse_literals.cc index a489519eaa685489cda0f2276f7067bf6c5d800e..3621ec12195cf923391735792f8451f17723c31b 100644 --- a/src/parse_literals.cc +++ b/src/parse_literals.cc @@ -64,10 +64,7 @@ literals_find_datatype(int n, const std::vector<std::string> &literals) { dtype = (dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64) ? std::max(dtype, xtype) : xtype; } - else - { - dtype = (!(dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64)) ? std::max(dtype, xtype) : xtype; - } + else { dtype = (!(dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64)) ? std::max(dtype, xtype) : xtype; } } } } diff --git a/src/parser.cc b/src/parser.cc index 6d2732b1bcd9bd2c86ad6abe9491459381ac5c26..ed2eb17f247d8d9beaca00d2cbb6b1a2c72631d1 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -11,7 +11,7 @@ #include "parser.h" #include "cdo_syntax_error.h" #include "cdo_node_attach_exception.h" -#include "modules.h" +#include "factory.h" #include "cdo_output.h" namespace Parser @@ -28,6 +28,24 @@ static int staticParserCounter = 0; namespace Util { +void +extract_name_and_argument(const std::string &command, std::string &operatorName, std::string &operatorArgument) +{ + constexpr char delimiter = ','; + + const size_t start = (command[0] == '-') ? 1 : 0; + + size_t len = command.find(delimiter); + if (len == std::string::npos) + { + len = command.size(); + operatorArgument = ""; + } + else { operatorArgument = command.substr(len + 1, std::string::npos); } + + operatorName = command.substr(start, len - start); +} + std::string tab() { @@ -78,36 +96,79 @@ append(std::shared_ptr<T> &parent, std::shared_ptr<T> &child) } // namespace Util // Factory Funcs! + std::string -err_msg_oper_not_found(const std::string &name) +err_msg_oper_not_found(const std::string &operatorName) { - auto similarOperators = find_similar_operators(name); - if (similarOperators.size()) similarOperators = "\nSimilar operators: " + similarOperators; - return "Operator '" + name + "' not found" + similarOperators; + // Checking if the operatorname is an existing file name + auto fp = std::fopen(operatorName.c_str(), "r"); + +// Sicnce std::format is incomplete, we sadly cannot use it yet +// When the time comes: please remove the ifdef and keep the std::format variant +#ifdef FINALLY_STD_FORMAT + std::string err_msg; + + if (fp) + { + std::fclose(fp); + err_msg = std::format("Operator missing, {} is a file on disk!", operatorName); + } + else + { + // Operator is no filename + // Checking for similar operators + err_msg = std::format("Operator >{}< not found!\n" + "Similar operators are:\n{}", + operatorName.c_str(), Factory::find_similar_operators(operatorName)); + } + return err_msg; +#else + char err_msg[1024]{ 0 }; + if (fp) + { + std::fclose(fp); + std::snprintf(err_msg, sizeof(err_msg), "Operator missing, %s is a file on disk!", operatorName.c_str()); + } + else + { + // Operator is no filename + // Checking for similar operators + auto similar = Factory::find_similar_operators(operatorName); + std::snprintf(err_msg, sizeof(err_msg), "Operator >%s< not found!\nSimilar operators are:\n%s", operatorName.c_str(), + similar.c_str()); + } + return std::string(err_msg); +#endif } // Factory Funcs! static std::shared_ptr<Node> -create_operator_node(ARGV_ITERATOR &p_curentArgument) +create_operator_node(ARGV_ITERATOR &p_curentArgument, bool is_first = false) { debug_parser("Creating new operator node: %s", *p_curentArgument); std::string operatorName = ""; std::string operatorArguments = ""; - extract_name_and_argument(*p_curentArgument, operatorName, operatorArguments); + Util::extract_name_and_argument(*p_curentArgument, operatorName, operatorArguments); - auto moduleIterator = find_module(operatorName); + auto moduleIterator = Factory::find( + operatorName, [&]() { THROW(InternalCdoSyntaxError, p_curentArgument, err_msg_oper_not_found(operatorName)); }); - if (moduleIterator == get_modules().end()) + auto mod = Factory::get_module(moduleIterator); + if (!is_first && mod.constraints.pos_restriction == PositionRestrictions::OnlyFirst) { - THROW(InternalCdoSyntaxError, p_curentArgument, err_msg_oper_not_found(operatorName)); + THROW(InternalCdoSyntaxError, p_curentArgument, errmsg_not_in_first_position); } - - auto mod = moduleIterator->second; auto newNode = std::make_shared<Node>(p_curentArgument, operatorName, operatorArguments, mod.constraints); return newNode; } +static std::shared_ptr<Node> +create_first_operator_node(ARGV_ITERATOR &p_curentArgument) +{ + return create_operator_node(p_curentArgument, true); +} + static std::shared_ptr<Node> create_file_node(ARGV_ITERATOR &p_curentArgument) { @@ -164,10 +225,7 @@ public: { bool undecidable_from_here_on = !stack.empty() && (stack.back()->constraints.streamInCnt == -1) && (stack.back()->children.size() > 1); - if (cntVariableInputs > 1 && undecidable_from_here_on) - { - THROW(InternalCdoSyntaxError, node->iter, errmsg_multiple_variable); - } + if (cntVariableInputs > 1 && undecidable_from_here_on) { THROW(InternalCdoSyntaxError, node->iter, errmsg_multiple_variable); } if (node->constraints.streamInCnt == -1) { cntVariableInputs++; } debug_parser("pushing new node: %s", node->oper); stack.push_back(node); @@ -247,7 +305,7 @@ handle_node(Parser &parser, ARGV_ITERATOR &cur_arg) std::shared_ptr<Node> &parent = parser.top(); debug_parser("adding %s as leaf to %s", node->oper, parent->oper); Util::append(parent, node); - if(parent->is_done()) parser.pop(); + if (parent->is_done()) parser.pop(); } else { @@ -431,18 +489,16 @@ iterate(PARSER_STACK &parser_stack, ARGV_ITERATOR &cur_arg, const ARGV_ITERATOR std::vector<std::shared_ptr<Node>> run(std::vector<std::string> &p_argv) { - ARGV_ITERATOR cur_arg; - ARGV_ITERATOR end; std::shared_ptr<Node> first_operator; std::stack<Parser> parser_stack; - cur_arg = p_argv.begin(); - end = p_argv.end(); + ARGV_ITERATOR cur_arg = p_argv.begin(); + ARGV_ITERATOR end = p_argv.end(); std::string first_argv = *cur_arg; if (first_argv.find("-apply,") == 0) { THROW(InternalCdoSyntaxError, cur_arg, errmsg_apply_in_first_pos); } - first_operator = create_operator_node(cur_arg); + first_operator = create_first_operator_node(cur_arg); // TODO remove abs replace with numOut < 0 : 1 else numOut int numOut = first_operator->numOut(); @@ -455,6 +511,7 @@ run(std::vector<std::string> &p_argv) parser_stack.push({ first_operator, cur_arg }); + // MAIN LOOP iterate(parser_stack, cur_arg, without_out_files); if (parser_stack.size() > 1) { THROW(InternalCdoSyntaxError, parser_stack.top().start, errmsg_bracket_not_closed); } diff --git a/src/parser.h b/src/parser.h index 92bbe116f905dee93e19f4b8b79dbcc168ea3907..94e4d69f0e8813d89ecbb0ec385b87c18da47aaf 100644 --- a/src/parser.h +++ b/src/parser.h @@ -9,58 +9,60 @@ namespace Parser { -static std::string apply_help = - " This feature allows to prepend simple cdo chains to other chains\n" - " Apply syntax:\n" - " (1) [ chain : file1 file2 file ] (Recommended Syntax)\n" - " (2) -apply,<chain> [ file1 file2 file_n ] (Old Syntax) \n" - "\n" - " For example the call:\n" - " -merge [ -select,name=topo : *.grb ]\n" - " would merge all grib files in the folder after selecting the variable topo from them\n" - "\n" - " The example:\n" - " \"-merge [ -addc,1 -mulc,2 : -add file1 file2 -subc,1 file3 file4 ] out\"" - " would result in:\n" - " -merge -addc,1 -mulc,2 -add file1 file2 -addc,1 -mulc,2 -subc,3 file3 -addc,2 -mulc,23 file4 out\n" - "\n" - " In combination with the subgroup (see --argument_groups) feature this allows rather complex calls\n" - " -merge [ [ -addc,1 : *1991.grb ] -merge [ -mulc,23 : *1990.grb ] -add file3 file4 ] outfile \n"; - - -static std::string subgroup_help= - " This feature allow to use multiple operators with variable number of inputs\n" - " Notes:\n" - " When a bracket is closed it is no longer possible to add aditional inputs.\n" - " When a bracket is closed another variable input operator can be used without brackets\n" - "\n" - " Where it is normally not possible to chain multiple operators of that kind, with subgroups a arbitrary number can be chained\n" - " -merge -merge file1 operator file1 > error:\n" - " it cannot be decided which inputs belong to which operator\n" - " -merge [ -merge file1 operator ] file1 > success:\n" - "\n" - " With the brackets it is possible to have multiple variable inputs as inputs for another variable input\n" - " -merge [ -merge [ *.grb ] -merge [ *.nc ] ] out\n" - " In combination with the apply (see --apply) feature this allows rather complex calls\n" - " -merge [ [ -addc,1 : *1991.grb ] -merge [ -mulc,23 : *1990.grb ] -add file3 file4 ] outfile \n"; - - +static std::string apply_help + = " This feature allows to prepend simple cdo chains to other chains\n" + " Apply syntax:\n" + " (1) [ chain : file1 file2 file ] (Recommended Syntax)\n" + " (2) -apply,<chain> [ file1 file2 file_n ] (Old Syntax) \n" + "\n" + " For example the call:\n" + " -merge [ -select,name=topo : *.grb ]\n" + " would merge all grib files in the folder after selecting the variable topo from them\n" + "\n" + " The example:\n" + " \"-merge [ -addc,1 -mulc,2 : -add file1 file2 -subc,1 file3 file4 ] out\"" + " would result in:\n" + " -merge -addc,1 -mulc,2 -add file1 file2 -addc,1 -mulc,2 -subc,3 file3 -addc,2 -mulc,23 file4 out\n" + "\n" + " In combination with the subgroup (see --argument_groups) feature this allows rather complex calls\n" + " -merge [ [ -addc,1 : *1991.grb ] -merge [ -mulc,23 : *1990.grb ] -add file3 file4 ] outfile \n"; + +static std::string subgroup_help + = " This feature allow to use multiple operators with variable number of inputs\n" + " Notes:\n" + " When a bracket is closed it is no longer possible to add aditional inputs.\n" + " When a bracket is closed another variable input operator can be used without brackets\n" + "\n" + " Where it is normally not possible to chain multiple operators of that kind, with subgroups a arbitrary number can " + "be chained\n" + " -merge -merge file1 operator file1 > error:\n" + " it cannot be decided which inputs belong to which operator\n" + " -merge [ -merge file1 operator ] file1 > success:\n" + "\n" + " With the brackets it is possible to have multiple variable inputs as inputs for another variable input\n" + " -merge [ -merge [ *.grb ] -merge [ *.nc ] ] out\n" + " In combination with the apply (see --apply) feature this allows rather complex calls\n" + " -merge [ [ -addc,1 : *1991.grb ] -merge [ -mulc,23 : *1990.grb ] -add file3 file4 ] outfile \n"; //'Regular' parser messages -static std::string errmsg_multiple_variable = "Operator cannot be assigned.\n Reason:\n Multiple variable input operators used.\n Use subgroups via [ ] to clarify relations (help: --argument_groups).\n"; +static std::string errmsg_multiple_variable + = "Operator cannot be assigned.\n Reason:\n Multiple variable input operators used.\n Use subgroups via " + "[ ] to clarify relations (help: --argument_groups).\n"; static std::string errmsg_missing_outputs = "Missing outputs"; static std::string errmsg_missing_inputs = "Missing inputs"; -static std::string errmsg_unprocessed_inputs = "Operator cannot be assigned.\n Reason:\n No Operators with missing input left.\n"; +static std::string errmsg_unprocessed_inputs + = "Operator cannot be assigned.\n Reason:\n No Operators with missing input left.\n"; static std::string errmsg_keyword_output = "Keywords cannot be used as file names"; +static std::string errmsg_not_in_first_position = "This operator can't be combined with other operators!"; -//Subgroup errors +// Subgroup errors static std::string errmsg_mixed_input = "Mixing of normal inputs and subgroups is not allowed"; static std::string errmsg_missing_sub_group = "Closing bracket without open subgroup"; static std::string errmsg_empty_subgroup = "Empty Subgroup"; static std::string errmsg_bracket_not_closed = "Bracket not closed"; static std::string errmsg_malformed_subgroup = "Malformed Subgroup"; -//Apply error messages +// Apply error messages static std::string errmsg_only_1_to_1_operators = "Only operators with a single in and output allowed"; static std::string errmsg_apply_missing_argument = "Missing arguments"; static std::string errmsg_apply_multiple_roots = "Apply can only process chains with a single in and out put"; @@ -76,6 +78,7 @@ std::vector<std::shared_ptr<Node>> _parse(std::vector<std::string> p_argv); namespace Util { +void extract_name_and_argument(const std::string &command, std::string &operatorName, std::string &operatorArgument); std::string result_to_string(std::vector<std::shared_ptr<Node>> p_roots, std::string p_text = "returning: "); diff --git a/src/percentiles_hist.cc b/src/percentiles_hist.cc index 939e57f4b4b10e30f863ca10ab33e44a09204f85..37f2ec6b751ac1d83e0e9bb57e7cb0ed8961b803 100644 --- a/src/percentiles_hist.cc +++ b/src/percentiles_hist.cc @@ -40,7 +40,7 @@ hist_init_bins(int nbins, T *bins) } static void -histDefBounds(Histogram &hist, float a, float b) +histDefBounds(HistogramEntry &hist, float a, float b) { assert(hist.nbins > 0); @@ -63,7 +63,7 @@ calc_bin(int nbins, float histMin, float histStep, float value) template <typename T> static void -histBinAddValue(Histogram &hist, T *bins, float value) +histBinAddValue(HistogramEntry &hist, T *bins, float value) { auto bin = calc_bin(hist.nbins, hist.min, hist.step, value); if (bin >= 0 && bin < hist.nbins) bins[bin]++; @@ -71,14 +71,14 @@ histBinAddValue(Histogram &hist, T *bins, float value) template <typename T> static void -histBinSubValue(Histogram &hist, T *bins, float value) +histBinSubValue(HistogramEntry &hist, T *bins, float value) { auto bin = calc_bin(hist.nbins, hist.min, hist.step, value); if (bin >= 0 && bin < hist.nbins && bins[bin] > 0) bins[bin]--; } static void -histBin(Histogram &hist) +histBin(HistogramEntry &hist) { assert(hist.nsamp == hist.capacity); @@ -99,7 +99,7 @@ histBin(Histogram &hist) } /* unused static int -histReset(Histogram &hist) +histReset(HistogramEntry &hist) { assert(hist.nbins > 0); @@ -122,7 +122,7 @@ histReset(Histogram &hist) */ static void -histCheckValue(const Histogram &hist, float &value) +histCheckValue(const HistogramEntry &hist, float &value) { // 2011-08-01 Uwe Schulzweida: added check for rounding errors if (value < hist.min && (hist.min - value) < 1.e5f) value = hist.min; @@ -130,7 +130,7 @@ histCheckValue(const Histogram &hist, float &value) } static int -histAddValue(Histogram &hist, float value) +histAddValue(HistogramEntry &hist, float value) { assert(hist.nbins > 0); @@ -156,7 +156,7 @@ histAddValue(Histogram &hist, float value) } static void -histRemoveValue(Histogram &hist, float value) +histRemoveValue(HistogramEntry &hist, float value) { auto fltptr = FLT_PTR(hist.ptr); @@ -176,7 +176,7 @@ histRemoveValue(Histogram &hist, float value) } static int -histSubValue(Histogram &hist, float value) +histSubValue(HistogramEntry &hist, float value) { assert(hist.nbins > 0); @@ -220,7 +220,7 @@ histGetBin(int nbins, double s, const T *ptr) } static double -histGetPercentile(const Histogram &hist, double p) +histGetPercentile(const HistogramEntry &hist, double p) { assert(hist.nsamp > 0); assert(hist.nbins > 0); @@ -240,7 +240,7 @@ histGetPercentile(const Histogram &hist, double p) auto bin = hist.isUint32 ? histGetBin(hist.nbins, s, INT_PTR(hist.ptr)) : histGetBin(hist.nbins, s, SHR_PTR(hist.ptr)); - //assert(hist.step > 0.0f); + // assert(hist.step > 0.0f); return hist.min + bin * hist.step; } @@ -286,7 +286,7 @@ HistogramSet::createVarLevels(int varID, int nlevels, size_t nhists) template <typename T1, typename T2> static void -def_bounds(size_t nhists, std::vector<Histogram> &hists, const Varray<T1> &v1, const Varray<T2> &v2, float mv1, float mv2) +def_bounds(size_t nhists, std::vector<HistogramEntry> &hists, const Varray<T1> &v1, const Varray<T2> &v2, float mv1, float mv2) { assert(!v1.empty()); assert(!v2.empty()); @@ -333,12 +333,12 @@ HistogramSet::defVarLevelBounds(int varID, int levelID, const Field &field1, con template <typename T> static int -histAddVarLevelValues(size_t nhists, std::vector<Histogram> &hists, const Varray<T> &v, size_t nmiss, T mv) +histAddVarLevelValues(size_t nhists, std::vector<HistogramEntry> &hists, const Varray<T> &v, size_t numMissVals, T mv) { assert(!v.empty()); int nign = 0; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < nhists; ++i) if (!dbl_is_equal(v[i], mv)) nign += histAddValue(hists[i], v[i]); @@ -353,12 +353,12 @@ histAddVarLevelValues(size_t nhists, std::vector<Histogram> &hists, const Varray template <typename T> static int -histSubVarLevelValues(size_t nhists, std::vector<Histogram> &hists, const Varray<T> &v, size_t nmiss, T mv) +histSubVarLevelValues(size_t nhists, std::vector<HistogramEntry> &hists, const Varray<T> &v, size_t numMissVals, T mv) { assert(!v.empty()); int nign = 0; - if (nmiss) + if (numMissVals) { for (size_t i = 0; i < nhists; ++i) if (!dbl_is_equal(v[i], mv)) nign += histSubValue(hists[i], v[i]); @@ -387,9 +387,9 @@ HistogramSet::addVarLevelValues(int varID, int levelID, const Field &field) int nign = 0; if (field.memType == MemType::Float) - nign = histAddVarLevelValues(nhists, hists, field.vec_f, field.nmiss, (float) field.missval); + nign = histAddVarLevelValues(nhists, hists, field.vec_f, field.numMissVals, (float) field.missval); else - nign = histAddVarLevelValues(nhists, hists, field.vec_d, field.nmiss, field.missval); + nign = histAddVarLevelValues(nhists, hists, field.vec_d, field.numMissVals, field.missval); if (nign) { @@ -416,9 +416,9 @@ HistogramSet::subVarLevelValues(int varID, int levelID, const Field &field) int nign = 0; if (field.memType == MemType::Float) - nign = histSubVarLevelValues(nhists, hists, field.vec_f, field.nmiss, (float) field.missval); + nign = histSubVarLevelValues(nhists, hists, field.vec_f, field.numMissVals, (float) field.missval); else - nign = histSubVarLevelValues(nhists, hists, field.vec_d, field.nmiss, field.missval); + nign = histSubVarLevelValues(nhists, hists, field.vec_d, field.numMissVals, field.missval); if (nign) { @@ -451,26 +451,23 @@ HistogramSet::reset(int varID, int levelID) template <typename T> static size_t -calcPercentile(size_t nhists, const std::vector<Histogram> &hists, double p, Varray<T> &v, T mv) +calcPercentile(size_t nhists, const std::vector<HistogramEntry> &hists, double p, Varray<T> &v, T mv) { assert(!v.empty()); - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i = 0; i < nhists; ++i) { - if (hists[i].nsamp) - { - v[i] = histGetPercentile(hists[i], p); - } + if (hists[i].nsamp) { v[i] = histGetPercentile(hists[i], p); } else { v[i] = mv; - nmiss++; + numMissVals++; } } - return nmiss; + return numMissVals; } void @@ -487,7 +484,7 @@ HistogramSet::getVarLevelPercentiles(Field &field, int varID, int levelID, doubl const auto &hists = this->histograms[varID][levelID]; if (field.memType == MemType::Float) - field.nmiss = calcPercentile(nhists, hists, p, field.vec_f, (float) field.missval); + field.numMissVals = calcPercentile(nhists, hists, p, field.vec_f, (float) field.missval); else - field.nmiss = calcPercentile(nhists, hists, p, field.vec_d, field.missval); + field.numMissVals = calcPercentile(nhists, hists, p, field.vec_d, field.missval); } diff --git a/src/percentiles_hist.h b/src/percentiles_hist.h index e17eed84380f90e56f6996f4956730c83335a822..6c1027dce7235add59e97a3735e902d4909361a7 100644 --- a/src/percentiles_hist.h +++ b/src/percentiles_hist.h @@ -5,7 +5,7 @@ #include "field.h" -struct Histogram +struct HistogramEntry { void *ptr = nullptr; float min = 0.0f; @@ -30,7 +30,7 @@ private: int nsteps = 0; std::vector<int> var_nlevels; std::vector<size_t> var_nhists; - std::vector<std::vector<std::vector<Histogram>>> histograms; + std::vector<std::vector<std::vector<HistogramEntry>>> histograms; void init() diff --git a/src/pipe.cc b/src/pipe.cc index 67acd23a70111d18fbc8d8bbeb164bbab488db5c..ad78aa35fd950c099a75c233de0466e7439eb491 100644 --- a/src/pipe.cc +++ b/src/pipe.cc @@ -43,7 +43,7 @@ pipe_t::pipe_init() levelID = -1; nrecs = 0; - nmiss = 0; + numMissVals = 0; data_d = nullptr; data_f = nullptr; hasdata = false; @@ -71,7 +71,7 @@ pipe_t::pipe_inq_timestep(int p_tsID) { if (EOP) { - Debug(PIPE, "%s EOP",name.c_str()); + Debug(PIPE, "%s EOP", name.c_str()); break; } if (hasdata) @@ -83,7 +83,7 @@ pipe_t::pipe_inq_timestep(int p_tsID) data_is_float = false; read_cond.notify_all(); } - Debug(PIPE && !hasdata, "%s has no data", name); + Debug(PIPE && !hasdata, "%s has no data", name); recInq_cond.notify_all(); /* o.k. ??? */ @@ -125,7 +125,7 @@ pipe_t::pipe_inq_vlist(int &p_vlistID) while (p_vlistID == -1 && nwaitcycles < maxWaitCycles && !EOP) { time_to_wait += timeOut; - Debug(PIPE,"%s wait of vlistDef_cond", name.c_str()); + Debug(PIPE, "%s wait of vlistDef_cond", name.c_str()); vlistDef_cond.wait_for(lock, time_to_wait); nwaitcycles++; } @@ -182,7 +182,7 @@ pipe_t::pipe_inq_record(int *p_varID, int *p_levelID) { std::scoped_lock lock(m_mutex); - Debug(PIPE,"%s has no data %d %d ", name.c_str(), recIDr, " ", recIDw); + Debug(PIPE, "%s has no data %d %d ", name.c_str(), recIDr, " ", recIDw); if (hasdata || usedata) { hasdata = false; @@ -277,7 +277,7 @@ pipe_t::pipe_def_record(int p_varID, int p_levelID) * @param pipe pipe that has the wanted data */ size_t -pipe_t::pipe_read_pipe_record(double *const p_data, int vlistID, size_t *const p_nmiss) +pipe_t::pipe_read_pipe_record(double *const p_data, int vlistID, size_t *const p_numMissVals) { if (!p_data) cdo_abort("No data pointer for %s", name); @@ -290,12 +290,12 @@ pipe_t::pipe_read_pipe_record(double *const p_data, int vlistID, size_t *const p } else { memcpy(p_data, data_d, datasize * sizeof(double)); } - *p_nmiss = nmiss; + *p_numMissVals = numMissVals; return datasize; } size_t -pipe_t::pipe_read_pipe_record(float *const p_data, int vlistID, size_t *const p_nmiss) +pipe_t::pipe_read_pipe_record(float *const p_data, int vlistID, size_t *const p_numMissVals) { if (!p_data) cdo_abort("No data pointer for %s", name); @@ -308,28 +308,28 @@ pipe_t::pipe_read_pipe_record(float *const p_data, int vlistID, size_t *const p_ for (size_t i = 0; i < datasize; ++i) p_data[i] = (float) data_d[i]; } - *p_nmiss = nmiss; + *p_numMissVals = numMissVals; return datasize; } size_t -pipe_t::pipe_read_record(int p_vlistID, double *const p_data, size_t *const p_nmiss) +pipe_t::pipe_read_record(int p_vlistID, double *const p_data, size_t *const p_numMissVals) { - *p_nmiss = 0; + *p_numMissVals = 0; size_t nvals = 0; { std::unique_lock<std::mutex> lock(m_mutex); while (!hasdata) { - Debug(PIPE,"%s wait of write_cond", name.c_str()); + Debug(PIPE, "%s wait of write_cond", name.c_str()); write_cond.wait(lock); } - if (hasdata) { nvals = pipe_read_pipe_record(p_data, p_vlistID, p_nmiss); } + if (hasdata) { nvals = pipe_read_pipe_record(p_data, p_vlistID, p_numMissVals); } else { cdo_abort("data type %d not implemented", hasdata); } - Debug(PIPE, "%s read record %d",name.c_str(), recIDr); + Debug(PIPE, "%s read record %d", name.c_str(), recIDr); hasdata = false; data_d = nullptr; @@ -341,9 +341,9 @@ pipe_t::pipe_read_record(int p_vlistID, double *const p_data, size_t *const p_nm } size_t -pipe_t::pipe_read_record(int p_vlistID, float *const p_data, size_t *const p_nmiss) +pipe_t::pipe_read_record(int p_vlistID, float *const p_data, size_t *const p_numMissVals) { - *p_nmiss = 0; + *p_numMissVals = 0; size_t nvals = 0; { @@ -354,7 +354,7 @@ pipe_t::pipe_read_record(int p_vlistID, float *const p_data, size_t *const p_nmi write_cond.wait(lock); } - if (hasdata) { nvals = pipe_read_pipe_record(p_data, p_vlistID, p_nmiss); } + if (hasdata) { nvals = pipe_read_pipe_record(p_data, p_vlistID, p_numMissVals); } else { cdo_abort("data type %d not implemented", hasdata); } Debug(PIPE, "%s read record %d", name.c_str(), recIDr); @@ -369,9 +369,9 @@ pipe_t::pipe_read_record(int p_vlistID, float *const p_data, size_t *const p_nmi } size_t -pipe_t::pipe_read_record(int p_vlistID, Field *const p_field, size_t *const p_nmiss) +pipe_t::pipe_read_record(int p_vlistID, Field *const p_field, size_t *const p_numMissVals) { - return pipe_read_record(p_vlistID, p_field->vec_d.data(), p_nmiss); + return pipe_read_record(p_vlistID, p_field->vec_d.data(), p_numMissVals); } void @@ -398,37 +398,37 @@ pipe_t::wait_for_read() } void -pipe_t::pipe_write_record(const double *const p_data, size_t p_nmiss) +pipe_t::pipe_write_record(const double *const p_data, size_t p_numMissVals) { { std::scoped_lock lock(m_mutex); hasdata = true; // data pointer data_is_float = false; data_d = (double *) p_data; - nmiss = p_nmiss; + numMissVals = p_numMissVals; } wait_for_read(); } void -pipe_t::pipe_write_record(const float *const p_data, size_t p_nmiss) +pipe_t::pipe_write_record(const float *const p_data, size_t p_numMissVals) { { std::scoped_lock lock(m_mutex); hasdata = true; // data pointer data_is_float = true; data_f = (float *) p_data; - nmiss = p_nmiss; + numMissVals = p_numMissVals; } wait_for_read(); } void -pipe_t::pipe_write_record(const Field *const p_field, size_t p_nmiss) +pipe_t::pipe_write_record(const Field *const p_field, size_t p_numMissVals) { - pipe_write_record(p_field->vec_d.data(), p_nmiss); + pipe_write_record(p_field->vec_d.data(), p_numMissVals); } void diff --git a/src/pipe.h b/src/pipe.h index a9961760c8ca1a36aa43c50802d7ee17b9019a3d..d8b8a428e68f97f718a03c44ae874c5d47bcaa30 100644 --- a/src/pipe.h +++ b/src/pipe.h @@ -27,16 +27,16 @@ public: int pipe_inq_record(int *varID, int *levelID); void pipe_def_record(int p_varId, int p_levelID); - void pipe_write_record(const double *const p_data, size_t p_nmiss); - void pipe_write_record(const float *const p_data, size_t p_nmiss); - void pipe_write_record(const Field *const p_data, size_t p_nmiss); + void pipe_write_record(const double *const p_data, size_t p_numMissVals); + void pipe_write_record(const float *const p_data, size_t p_numMissVals); + void pipe_write_record(const Field *const p_data, size_t p_numMissVals); - size_t pipe_read_record(int p_vlistID, double *data, size_t *nmiss); - size_t pipe_read_record(int p_vlistID, float *data, size_t *nmiss); - size_t pipe_read_record(int p_vlistID, Field *data, size_t *nmiss); + size_t pipe_read_record(int p_vlistID, double *data, size_t *numMissVals); + size_t pipe_read_record(int p_vlistID, float *data, size_t *numMissVals); + size_t pipe_read_record(int p_vlistID, Field *data, size_t *numMissVals); - size_t pipe_read_pipe_record(double *data, int vlistID, size_t *p_nmiss); - size_t pipe_read_pipe_record(float *data, int vlistID, size_t *p_nmiss); + size_t pipe_read_pipe_record(double *data, int vlistID, size_t *p_numMissVals); + size_t pipe_read_pipe_record(float *data, int vlistID, size_t *p_numMissVals); void pipe_set_name(int processID, int inputIDX); void close(); @@ -48,7 +48,7 @@ public: int varID, levelID; int recIDr, recIDw, tsIDr, tsIDw; - size_t nmiss; + size_t numMissVals; int nrecs; bool data_is_float; diff --git a/src/pipeStream.cc b/src/pipeStream.cc index 320413eb7bdad15d34ea741b0444c88bc10c8fec..612c6dd13dd61729dc49a0f1967b958fdb447964 100644 --- a/src/pipeStream.cc +++ b/src/pipeStream.cc @@ -83,39 +83,39 @@ PipeStream::defRecord(int varID, int levelID) } void -PipeStream::read_record(float *p_data, size_t *p_nmiss) +PipeStream::read_record(float *p_data, size_t *p_numMissVals) { - m_nvals += m_pipe->pipe_read_record(m_vlistID, p_data, p_nmiss); + m_nvals += m_pipe->pipe_read_record(m_vlistID, p_data, p_numMissVals); } void -PipeStream::read_record(double *p_data, size_t *p_nmiss) +PipeStream::read_record(double *p_data, size_t *p_numMissVals) { - m_nvals += m_pipe->pipe_read_record(m_vlistID, p_data, p_nmiss); + m_nvals += m_pipe->pipe_read_record(m_vlistID, p_data, p_numMissVals); } void -PipeStream::read_record(Field *p_field, size_t *p_nmiss) +PipeStream::read_record(Field *p_field, size_t *p_numMissVals) { - m_nvals += m_pipe->pipe_read_record(m_vlistID, p_field, p_nmiss); + m_nvals += m_pipe->pipe_read_record(m_vlistID, p_field, p_numMissVals); } void -PipeStream::write_record(const float *p_data, size_t p_nmiss) +PipeStream::write_record(const float *p_data, size_t p_numMissVals) { - m_pipe->pipe_write_record(p_data, p_nmiss); + m_pipe->pipe_write_record(p_data, p_numMissVals); } void -PipeStream::write_record(const double *p_data, size_t p_nmiss) +PipeStream::write_record(const double *p_data, size_t p_numMissVals) { - m_pipe->pipe_write_record(p_data, p_nmiss); + m_pipe->pipe_write_record(p_data, p_numMissVals); } void -PipeStream::write_record(const Field *p_field, size_t p_nmiss) +PipeStream::write_record(const Field *p_field, size_t p_numMissVals) { - m_pipe->pipe_write_record(p_field, p_nmiss); + m_pipe->pipe_write_record(p_field, p_numMissVals); } void diff --git a/src/pipeStream.h b/src/pipeStream.h index 2f9fa85925e4385855afae01ace42dc4eba7d563..dc4d72ad9903b07179a7f4232bd98a69c510727e 100644 --- a/src/pipeStream.h +++ b/src/pipeStream.h @@ -33,13 +33,13 @@ public: void inq_record(int *varID, int *levelID) override; void defRecord(int varID, int levelID) override; - void read_record(float *const p_data, size_t *nmiss) override; - void read_record(double *const p_data, size_t *nmiss) override; - void read_record(Field *const p_field, size_t *nmiss) override; + void read_record(float *const p_data, size_t *numMissVals) override; + void read_record(double *const p_data, size_t *numMissVals) override; + void read_record(Field *const p_field, size_t *numMissVals) override; - void write_record(const float *const p_data, size_t nmiss) override; - void write_record(const double *const p_data, size_t nmiss) override; - void write_record(const Field *const p_field, size_t nmiss) override; + void write_record(const float *const p_data, size_t numMissVals) override; + void write_record(const double *const p_data, size_t numMissVals) override; + void write_record(const Field *const p_field, size_t numMissVals) override; void copyRecord(CdoStreamID p_fileStream) override; diff --git a/src/pmlist.cc b/src/pmlist.cc index 5b7bd2d00b034327cda35bfdbbb45055f364e336..b31dc5e1aba687506ac64580068db709e4928e16 100644 --- a/src/pmlist.cc +++ b/src/pmlist.cc @@ -13,6 +13,7 @@ #include "pmlist.h" #include "namelist.h" #include "cdo_output.h" +#include "util_string.h" static void keyValuesPrint(FILE *fp, const KeyValues &keyValues) @@ -29,42 +30,49 @@ KVList::print(FILE *fp) const } int -KVList::parse_arguments(int argc, const std::vector<std::string> &argv) +KVList::parse_arguments(const std::vector<std::string> &argv) { - // Assume key = value pairs. That is, if argv[i] contains no '=' then treat it as if it belongs to the values of argv[i-1]. - char key[256]; - int i = 0; - while (i < argc) + /* this function assumes input in the form of + * value_name1=10,2,3,4,value_name2=201,23 + **/ + + size_t equalPos = argv[0].find('='); + if (equalPos == std::string::npos) + { + fprintf(stderr, "missing '=' in key/value string: >%s<\n", argv[0].c_str()); + return -1; + } + + for (auto &it : argv) { - const char *currentArgv = argv[i].c_str(); - const char *end = strchr(currentArgv, '='); - if (end == nullptr) + equalPos = it.find('='); + if (equalPos != std::string::npos) { - fprintf(stderr, "Missing '=' in key/value string: >%s<\n", currentArgv); - return -1; + auto key = it.substr(0, equalPos); + + std::string value = Util::String::trim(it.substr(equalPos + 1)); + { // value vector gets moved at the end of scope + std::vector<std::string> value_vector; + + /* clang-format off */ + if (value.empty()) { value_vector = {}; } + else { value_vector = { value }; } + /* clang-format on */ + + push_back(KeyValues()); + KeyValues &newValue = back(); + newValue.nvalues = 0; + newValue.values = std::move(value_vector); + newValue.key = key; + } + back().nvalues = back().values.size(); + } + else + { + auto &last = back(); + last.values.push_back(it); + last.nvalues = last.values.size(); } - - std::snprintf(key, sizeof(key), "%.*s", (int) (end - currentArgv), currentArgv); - key[sizeof(key) - 1] = 0; - - int j = 1; - while (i + j < argc && strchr(argv[i + j].c_str(), '=') == nullptr) j++; - - int nvalues = j; - - KeyValues kv; - kv.values.resize(1); - kv.values[0] = end + 1; - if (kv.values[0][0] == 0) nvalues = 0; - - kv.key = key; - kv.nvalues = nvalues; - kv.values.resize(nvalues); - - for (j = 1; j < nvalues; ++j) kv.values[j] = argv[i + j]; - this->push_back(kv); - - i += j; } return 0; @@ -100,6 +108,22 @@ KVList::append(const char *key, const char *const *values, int nvalues) this->push_back(kv); } +void +KVList::append(std::string &key, std::vector<std::string> values) +{ + KeyValues kv; + kv.key = key; + kv.values = values; + kv.nvalues = kv.values.size(); + this->push_back(kv); +} + +void +KVList::append(std::string &key, std::string &values) +{ + append(key, std::vector<std::string>{ values }); +} + // Remove only one list item void KVList::remove(const std::string &inkey) diff --git a/src/pmlist.h b/src/pmlist.h index 5b4ee1b6ae64f837bb1bcef0bcf50deca78aa0ab..d834b1c8e098fe5723e03484a5528cf520bcdf5e 100644 --- a/src/pmlist.h +++ b/src/pmlist.h @@ -33,10 +33,12 @@ public: std::string name; void print(FILE *fp = stderr) const; - int parse_arguments(int argc, const std::vector<std::string> &argv); + int parse_arguments(const std::vector<std::string> &argv); const KeyValues *search(const std::string &key) const; void remove(const std::string &inkey); void append(const char *, const char *const *, int); + void append(std::string &key, std::vector<std::string> values); + void append(std::string &key, std::string &value); char *get_first_value(const char *key, const char *replacer); }; diff --git a/src/printinfo.cc b/src/printinfo.cc index be41e990a5c890011e56bf81f851231fd1991066..71267c7b3a4f37b9f80588a3810e74593150935f 100644 --- a/src/printinfo.cc +++ b/src/printinfo.cc @@ -635,7 +635,7 @@ print_zaxis_info(int vlistID) if (zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL)) printZaxisBoundsInfo(zaxisID, dig, levelsize, zinc, zunits); - if (zaxistype == ZAXIS_HYBRID) printZaxisHybridInfo(zaxisID); + if (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) printZaxisHybridInfo(zaxisID); if (zaxistype == ZAXIS_REFERENCE) printZaxisReferenceInfo(zaxisID); diff --git a/src/process.cc b/src/process.cc index fc1c4e679d747344b997a18b8e021ccb9d1e62aa..38eb6960c12db17168e27c0a4c6beece8a0cd47a 100644 --- a/src/process.cc +++ b/src/process.cc @@ -30,6 +30,9 @@ #include "fileStream.h" #include "pipeStream.h" +// temporary include for setting the local process +#include "process_int.h" + static int processNum = 0; int @@ -44,32 +47,25 @@ set_process_num(int p_num) processNum = p_num; } -Process::Process(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments) - : m_ID(p_ID), operatorName(p_operatorName) -{ - m_isActive = true; - init_process(p_operatorName, p_arguments); -} - -bool -Process::input_is_variable() +std::string +Process::replace_alias(const std::string &p_calledBy, const CdoModule &p_module) { - return (m_module.get_stream_in_cnt() == -1); + std::string originalName = p_calledBy; + int aliasID = p_module.is_alias(p_calledBy); + if (aliasID != -1) originalName = p_module.aliases[aliasID].original; + return originalName; } -void -Process::init_process(const std::string &p_operatorName, const std::vector<std::string> &p_arguments) +Process::Process(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments, + const CdoModule &p_module) + : m_ID(p_ID), m_module(p_module), m_oargv(p_arguments) { - startTime = cdo::get_wtime(); #ifdef HAVE_LIBPTHREAD threadID = pthread_self(); #endif - m_oargv = p_arguments; - operatorName = get_original(p_operatorName); - m_module = get_module(p_operatorName); - - def_prompt(); // has to be called after get operatorName + operatorName = replace_alias(p_operatorName, p_module); + def_prompt(operatorName); } int @@ -85,12 +81,12 @@ Process::get_stream_cnt_out() } void -Process::def_prompt() +Process::def_prompt(const std::string &name) { if (m_ID == 0) - std::snprintf(prompt, sizeof(prompt), "%s %s", cdo::progname, operatorName.c_str()); + std::snprintf(prompt, sizeof(prompt), "%s %s", cdo::progname, name.c_str()); else - std::snprintf(prompt, sizeof(prompt), "%s(%d) %s", cdo::progname, m_ID, operatorName.c_str()); + std::snprintf(prompt, sizeof(prompt), "%s(%d) %s", cdo::progname, m_ID, name.c_str()); } const char * @@ -99,149 +95,19 @@ Process::inq_prompt() const return prompt; } -void -Process::handle_process_err() -{ - switch (m_status) - { - case ProcessStatus::UnlimitedIOCounts: - { - cdo_abort("I/O stream counts unlimited no allowed!"); - break; - } - case ProcessStatus::MissInput: - { - cdo_abort("Input streams missing!"); - break; - } - case ProcessStatus::MissOutput: - { - cdo_abort("Output streams missing!"); - break; - } - case ProcessStatus::TooManyStreams: - case ProcessStatus::TooFewStreams: - { - auto inCnt = m_module.get_stream_in_cnt(); - auto outCnt = m_module.get_stream_out_cnt(); - bool lobase = (outCnt == -1); - if (lobase) outCnt = 1; - - std::string caseCount = (m_status == ProcessStatus::TooManyStreams) ? "many" : "few"; - std::string pluralIn = (inCnt > 1) ? "s" : ""; - std::string pluralOut = (outCnt > 1) ? "s" : ""; - - std::stringstream errMsg; - errMsg << "Too " << caseCount << " streams specified! Operator " << operatorName << " needs " << inCnt << " input stream" - << pluralIn << " and " << outCnt << " output " << (lobase ? "basename" : "stream") << pluralOut << "!"; - cdo_abort(errMsg.str()); - break; - } - case ProcessStatus::Ok: break; - } -} - -void -Process::validate() -{ - check_stream_cnt(); - if (m_status != ProcessStatus::Ok) handle_process_err(); -} - -void -Process::check_stream_cnt() -{ - int streamCnt = 0; - - int wantedStreamInCnt = m_module.get_stream_in_cnt(); - int wantedStreamOutCnt = m_module.get_stream_out_cnt(); - - int streamInCnt0 = wantedStreamInCnt; - - bool obase = false; - if (wantedStreamOutCnt == -1) - { - wantedStreamOutCnt = 1; - obase = true; - } - - if (wantedStreamInCnt == -1 && wantedStreamOutCnt == -1) { m_status = ProcessStatus::UnlimitedIOCounts; } - - // printf(" wantedStreamInCnt,wantedStreamOutCnt %d %d\n", - // wantedStreamInCnt,wantedStreamOutCnt); - else if (wantedStreamInCnt == -1) - { - wantedStreamInCnt = m_streamCnt - wantedStreamOutCnt; - if (wantedStreamInCnt < 1) m_status = ProcessStatus::MissInput; - } - - else if (wantedStreamOutCnt == -1) - { - wantedStreamOutCnt = m_streamCnt - wantedStreamInCnt; - if (wantedStreamOutCnt < 1) m_status = ProcessStatus::MissOutput; - } - else - { - // printf(" wantedStreamInCnt,wantedStreamOutCnt %d %d\n", - // wantedStreamInCnt,wantedStreamOutCnt); - - streamCnt = wantedStreamInCnt + wantedStreamOutCnt; - // printf(" streamCnt %d %d\n", m_streamCnt, streamCnt); - - if (m_streamCnt > streamCnt) - m_status = ProcessStatus::TooManyStreams; - else if (m_streamCnt < streamCnt && !obase) - m_status = ProcessStatus::TooFewStreams; - else if (wantedStreamInCnt > (int) inputStreams.size()) - m_status = ProcessStatus::TooFewStreams; - - else if (wantedStreamInCnt == 1 && streamInCnt0 == -1) - m_status = ProcessStatus::Ok; - } -} - -bool -Process::has_hall_inputs() -{ - if (m_module.get_stream_in_cnt() == -1) return false; - - return (m_module.get_stream_in_cnt() == static_cast<short>(inputStreams.size())); -} - -void -Process::set_inactive() -{ - m_isActive = false; -} - -int -Process::operator_add(const char *name, int f1, int f2, const char *enter) -{ - int operID = m_noper; - - if (operID >= MAX_OPERATOR) cdo_abort("Maximum number of %d operators reached!", MAX_OPERATOR); - - oper[m_noper] = { f1, f2, name, enter }; - - m_noper++; - - return operID; -} - int Process::get_operator_id() { - if (m_noper > 0) - { - for (int operID = 0; operID < m_noper; operID++) - { - if (operatorName == oper[operID].name) return operID; - } + if (m_module.operators.size() <= 0) { cdo_abort("Operator not initialized!"); } - cdo_abort("Operator not callable by this name! Name is: %s", operatorName); + Debug(PROCESS, "searching for %s", operatorName); + for (size_t operID = 0; operID < m_module.operators.size(); operID++) + { + Debug(PROCESS, "comparing %s and %s", operatorName, m_module.operators[operID].name); + if (operatorName == m_module.operators[operID].name) return operID; } - cdo_abort("Operator not initialized!"); + cdo_abort("Operator not callable by this name! Name is: %s", operatorName); return -1; } @@ -265,7 +131,6 @@ void Process::add_child(const std::shared_ptr<Process> &childProcess) { childProcesses.push_back(childProcess); - nchild = childProcesses.size(); add_pipe_in_stream(); } @@ -295,8 +160,25 @@ Process::add_pipe_out_stream() m_streamCnt++; } +void * +execute(void *process) +{ + + Process *p = (Process *) process; + + p->cdo_initialize(); + + p->init(); + p->run(); + p->close(); + + p->cdo_finish(); + + return nullptr; +} + pthread_t -Process::run() +Process::start_thread() { Debug(PROCESS, "starting new thread for process %d", m_ID); pthread_attr_t attr; @@ -329,80 +211,22 @@ Process::run() } pthread_t thrID; - auto rval = pthread_create(&thrID, &attr, m_module.func, this); + auto rval = pthread_create(&thrID, &attr, execute, this); if (rval != 0) { errno = rval; cdo_sys_error("pthread_create failed for '%s'", operatorName.c_str()); } - m_isActive = true; - return thrID; } // local helper function -extern "C" size_t getPeakRSS(); -static void -get_max_memstring(char *p_memstring, size_t memstringLen) -{ - auto memmax = getPeakRSS(); - if (memmax) - { - size_t muindex = 0; - const char *mu[] = { "B", "KB", "MB", "GB", "TB", "PB" }; - size_t nmu = sizeof(mu) / sizeof(char *); - while (memmax > 9999 && muindex < nmu - 1) - { - memmax /= 1024; - muindex++; - } - std::snprintf(p_memstring, memstringLen, " %zu%s", memmax, mu[muindex]); - } -} - -void -Process::print_benchmarks(double p_walltime, const char *p_memstring) -{ - auto numberOfUsedThreads = get_process_num(); - if (Options::test) - fprintf(stdout, " [%.2fs%s %dthread%s]", p_walltime, p_memstring, numberOfUsedThreads, ADD_PLURAL(numberOfUsedThreads)); - else - fprintf(stdout, " [%.2fs%s]", p_walltime, p_memstring); -} - -void -Process::print_processed_values() -{ - set_text_color(stdout, GREEN); - fprintf(stdout, "%s: ", prompt); - reset_text_color(stdout); - - auto nvals = inq_nvals(); - - if (nvals > 0) - { - fprintf(stdout, "Processed %zu value%s from %d variable%s", nvals, ADD_PLURAL(nvals), m_nvars, ADD_PLURAL(m_nvars)); - } - else if (m_nvars > 0) { fprintf(stdout, "Processed %d variable%s", m_nvars, ADD_PLURAL(m_nvars)); } - - if ((nvals || m_nvars) && ntimesteps > 0) fprintf(stdout, " over %d timestep%s", ntimesteps, ADD_PLURAL(ntimesteps)); - - if (m_ID == 0) - { - char memstring[32] = { "" }; - get_max_memstring(memstring, sizeof(memstring)); - print_benchmarks(cdo::get_wtime() - startTime, memstring); - } - - // if (m_nvars > 0 || nvals > 0 || ntimesteps > 0 || m_ID == 0) fprintf(stdout, "."); - fprintf(stdout, "\n"); -} bool Process::has_out_stream(CdoStreamID p_streamID) { - for (const CdoStreamID &streamID : outputStreams) + for (const auto &streamID : outputStreams) { if (streamID == p_streamID) return true; } @@ -412,7 +236,7 @@ Process::has_out_stream(CdoStreamID p_streamID) bool Process::has_in_stream(CdoStreamID p_streamID) { - for (const CdoStreamID &streamID : inputStreams) + for (const auto &streamID : inputStreams) { if (streamID == p_streamID) return true; } @@ -458,16 +282,23 @@ Process::get_argv(int p_idx) return m_oargv[p_idx]; } +void +Process::set_obase(const std::string &obase) +{ + m_obase = obase; +} // TODO into cc + const std::string Process::get_obase() { return m_obase; } + void Process::close_streams() { - for (auto s : inputStreams) { s->close(); } - for (auto s : outputStreams) { s->close(); } + for (auto &s : inputStreams) { s->close(); } + for (auto &s : outputStreams) { s->close(); } } int @@ -475,3 +306,28 @@ Process::get_id() { return m_ID; } +void +Process::cdo_initialize() +{ +#if defined(_OPENMP) + omp_set_num_threads(Threading::ompNumThreads); // Has to be called for every module (pthread)! +#endif +#ifdef HAVE_LIBPTHREAD + threadID = pthread_self(); +#endif + Debug(PROCESS_INT, "Initializing process: %s (id: %d)", operatorName, get_id()); + + set_local_process(this); +#ifdef HAVE_LIBPTHREAD + Debug(PROCESS_INT, "process %d thread %ld", m_ID, pthread_self()); +#endif +} +void +Process::cdo_finish(void) +{ + Debug(PROCESS_INT, "Finishing process: %d", get_id()); + +#ifdef HAVE_LIBPTHREAD + Debug(PROCESS_INT, "process %d thread %ld", m_ID, pthread_self()); +#endif +} diff --git a/src/process.h b/src/process.h index f5dc61254e8a85d75dc9df4bf1154f28d4b0d168..cd6d8fb24af71cad83d9b7b462edb1799cbfcb44 100644 --- a/src/process.h +++ b/src/process.h @@ -9,7 +9,8 @@ #define PROCESS_H #include "cdoStream.h" -#include "modules.h" +#include "cdo_module.h" +#include "cdo_timer.h" #include <vector> #include <iostream> @@ -28,59 +29,46 @@ enum class ProcessStatus TooManyStreams = -4, TooFewStreams = -5, }; - -class oper_t -{ -public: - int f1 = 0; - int f2 = 0; - std::string name; - const char *enter = nullptr; - - oper_t() {} - oper_t(int _f1, int _f2, const char *_name, const char *_enter) : f1(_f1), f2(_f2), name(_name), enter(_enter) {} - oper_t(const char *_name, int _f1, int _f2, const char *_enter) : f1(_f1), f2(_f2), name(_name), enter(_enter) {} - - oper_t(const char *_name) : f1(0), f2(0), name(_name), enter(nullptr) {} -}; +void *execute(void *process); class Process { + public: + /* Member Variables */ + int m_ID; + const CdoModule &m_module; int m_posInParent; -#ifdef HAVE_LIBPTHREAD - pthread_t threadID; -#endif - short nchild = 0; std::vector<std::shared_ptr<Process>> childProcesses; std::vector<std::shared_ptr<Process>> parentProcesses; std::vector<CdoStreamID> inputStreams; std::vector<CdoStreamID> outputStreams; - int nChildActive = 0; - - double startTime; int m_nvars = 0; - int ntimesteps = 0; int m_streamCnt = 0; + + char prompt[64]; + std::string m_operatorCommand = "UNINITALIZED"; std::string operatorName; std::string m_obase; - char prompt[64]; + std::vector<std::string> m_oargv; - short m_noper = 0; - bool m_isActive; +#ifdef HAVE_LIBPTHREAD + pthread_t threadID; +#endif - module_t m_module; - std::vector<std::string> m_oargv; - oper_t oper[MAX_OPERATOR]; + /* Member Functions */ - Process(int p_ID, const std::string &p_operatorNamme, const std::vector<std::string> &operatorArguments); + Process(int p_ID, const std::string &p_operatorName, const std::vector<std::string> &p_arguments, const CdoModule &p_module); + virtual ~Process() {} - pthread_t run(); - ProcessStatus m_status = ProcessStatus::Ok; + pthread_t start_thread(); + virtual void init() = 0; + virtual void run() = 0; + virtual void close() = 0; /** * returns the number of in streams this process currently has. @@ -99,12 +87,6 @@ public: * Adds a Process as parent and adds the parents input stream to out streams. */ void add_parent(const std::shared_ptr<Process> &parent_process); - /** - * Compares the wanted and current stream counts. - * @return if the wanted count is -1 this function always returns false. - * Are the current and wanted stream counts equal 1 and if they differ false. - */ - bool has_hall_inputs(); /** * Adds and creates a new file pstream to the in streams */ @@ -121,45 +103,35 @@ public: * Adds and creates a new file pstream to the out streams */ void add_pipe_out_stream(); - /** - * Adds an operator to the process - */ - int operator_add(const char *name, int f1, int f2, const char *enter); /** * returns the operatorID of the currently in use operator */ int get_operator_id(); - void set_inactive(); const char *inq_prompt() const; - void print_processed_values(); - void print_benchmarks(double p_walltime, const char *p_memstring); - void check_stream_cnt(); - void validate(); - void handle_process_err(); + const char *get_out_stream_name(); bool has_out_stream(CdoStreamID p_streamPtr); bool has_in_stream(CdoStreamID p_streamPtr); + bool has_no_pipes(); + size_t inq_nvals(); - const char *get_out_stream_name(); + size_t get_oper_argc(); std::string get_argv(int idx); + const std::string get_obase(); - void - set_obase(const std::string &obase) - { - m_obase = obase; - } // TODO into cc - bool input_is_variable(); + void set_obase(const std::string &obase); + int get_id(); - void init_process(const std::string &p_operatorName, const std::vector<std::string> &p_arguments); void close_streams(); - Process(){}; + std::string replace_alias(const std::string &p_calledBy, const CdoModule &p_module); + void def_prompt(const std::string &name); -private: - void def_prompt(); + void cdo_initialize(); + void cdo_finish(void); }; int get_process_num(); diff --git a/src/processManager.cc b/src/processManager.cc index 1ea3922f1f708396867942d7bbd2251d0a7b4e53..03ef9c14bc97f82e3987262b1ccd09f5a358492f 100644 --- a/src/processManager.cc +++ b/src/processManager.cc @@ -10,6 +10,8 @@ #include "cdo_output.h" #include "cdo_options.h" #include "fileStream.h" +#include "factory.h" +#include "util_string.h" #include <stack> #include <mutex> @@ -20,23 +22,82 @@ static std::string parse_err_msg = ""; static const int IS_OBASE = -1; +extern "C" size_t getPeakRSS(); +static void +get_max_memstring(char *p_memstring, size_t memstringLen) +{ + auto memmax = getPeakRSS(); + if (memmax) + { + size_t muindex = 0; + const char *mu[] = { "B", "KB", "MB", "GB", "TB", "PB" }; + size_t nmu = sizeof(mu) / sizeof(char *); + while (memmax > 9999 && muindex < nmu - 1) + { + memmax /= 1024; + muindex++; + } + std::snprintf(p_memstring, memstringLen, " %zu%s", memmax, mu[muindex]); + } +} + +void +print_benchmarks(double p_walltime, const char *p_memstring) +{ + auto numberOfUsedThreads = get_process_num(); + if (Options::test) + fprintf(stdout, " [%.2fs%s %dthread%s]", p_walltime, p_memstring, numberOfUsedThreads, ADD_PLURAL(numberOfUsedThreads)); + else + fprintf(stdout, " [%.2fs%s]", p_walltime, p_memstring); +} + +void +print_processed_values(Process *p_process, double p_time) +{ + set_text_color(stdout, GREEN); + fprintf(stdout, "%s: ", p_process->prompt); + reset_text_color(stdout); + + auto nvals = p_process->inq_nvals(); + + int nvars = p_process->m_nvars; + if (nvals > 0) + { + fprintf(stdout, "Processed %zu value%s from %d variable%s", nvals, ADD_PLURAL(nvals), nvars, ADD_PLURAL(nvars)); + } + else if (nvars > 0) { fprintf(stdout, "Processed %d variable%s", nvars, ADD_PLURAL(nvars)); } + + int ntimesteps = p_process->ntimesteps; + if ((nvals || nvars) && ntimesteps > 0) fprintf(stdout, " over %d timestep%s", ntimesteps, ADD_PLURAL(ntimesteps)); + + if (p_process->m_ID == 0) + { + char memstring[32] = { "" }; + get_max_memstring(memstring, sizeof(memstring)); + print_benchmarks(p_time, memstring); + } + + // if (m_nvars > 0 || nvals > 0 || ntimesteps > 0 || m_ID == 0) fprintf(stdout, "."); + fprintf(stdout, "\n"); +} + void ProcessManager::buildProcessTree(std::vector<std::shared_ptr<Node>> roots) { - Debug(PROCESS,"Building process Tree"); + Debug(PROCESS, "Building process Tree"); std::shared_ptr<Node> node = roots[0]->isFile ? roots[0]->children[0] : roots[0]; auto first_process = create_process(node->oper, split_args(node->arguments)); if (node->numOut() == IS_OBASE) { - Debug(PROCESS,"Setting obase for %s", node->oper); + Debug(PROCESS, "Setting obase for %s", node->oper); first_process->set_obase(roots[0]->oper); } else if (node->numOut() > 0) { for (const auto &n : roots) { - Debug(PROCESS,"adding out files to %s", node->oper); + Debug(PROCESS, "adding out files to %s", node->oper); first_process->add_file_out_stream(n->oper); } } @@ -45,7 +106,7 @@ ProcessManager::buildProcessTree(std::vector<std::shared_ptr<Node>> roots) { if (c->isFile) { - Debug(PROCESS,"Adding file in stream: %s", c->oper); + Debug(PROCESS, "Adding file in stream: %s", c->oper); first_process->add_file_in_stream(c->oper); } else @@ -63,18 +124,18 @@ ProcessManager::buildProcessTree(std::vector<std::shared_ptr<Node>> roots) std::shared_ptr<Process> ProcessManager::build_node(std::shared_ptr<Node> parent_node) { - Debug(PROCESS,"Building process for %s", parent_node->oper); + Debug(PROCESS, "Building process for %s", parent_node->oper); auto parent_process = create_process(parent_node->oper, split_args(parent_node->arguments)); for (auto child_node : parent_node->children) { if (child_node->isFile) { - Debug(PROCESS,"Adding file in stream: %s", child_node->oper); + Debug(PROCESS, "Adding file in stream: %s", child_node->oper); parent_process->add_file_in_stream(child_node->oper); } else { - Debug(PROCESS,"Building Process for %s", child_node->oper); + Debug(PROCESS, "Building Process for %s", child_node->oper); auto child_process = build_node(child_node); parent_process->add_child(child_process); child_process->add_parent(parent_process); @@ -99,12 +160,17 @@ ProcessManager::run_processes() reset_text_color(stdout); fprintf(stdout, "Process started\n"); } - m_threadIDs.push_back(idProcessPair.second->run()); + m_threadIDs.push_back(idProcessPair.second->start_thread()); } } m_threadIDs.push_back(pthread_self()); // MpMO::PrintCerr(Green("%s: ") + "xProcess started", get_process_from_id(0).inq_prompt()); - get_process_from_id(0)->m_module.func(get_process_from_id(0).get()); + Process *process_zero = get_process_from_id(0).get(); + + double start = cdo::get_wtime(); + execute(process_zero); + double end = cdo::get_wtime(); + if (!Options::silentMode && (cdo::stdoutIsTerminal || Options::cdoVerbose)) print_processed_values(process_zero, end - start); } void @@ -128,15 +194,22 @@ ProcessManager::clear_processes() m_numProcesses = 0; m_numProcessesActive = 0; } + const std::shared_ptr<Process> ProcessManager::create_process(const std::string &operatorName, const std::vector<std::string> &arguments) { + std::shared_ptr<Process> new_process; + if ((m_numProcesses + 1) >= MAX_PROCESS) { cdo_abort("Limit of %d processes reached!", MAX_PROCESS); } auto processID = m_numProcesses++; - if (processID >= MAX_PROCESS) cdo_abort("Limit of %d processes reached!", MAX_PROCESS); - auto success = m_processes.insert(std::make_pair(processID, std::make_shared<Process>(processID, operatorName, arguments))); - if (!success.second) cdo_abort("Process %d could not be created", processID); + + auto it = Factory::find(operatorName, [&processID]() { cdo_abort("Process %d could not be created", processID); }); + + auto constructor_function = Factory::get_constructor(it); + auto success = m_processes.insert(std::make_pair(processID, constructor_function(processID, operatorName, arguments))); + new_process = success.first->second; m_numProcessesActive++; - return success.first->second; + + return new_process; } int @@ -171,7 +244,7 @@ ProcessManager::get_operator_argv(std::string operatorArguments) while ((pos = operatorArguments.find(delimiter)) != std::string::npos) { argument_vector.push_back(operatorArguments.substr(0, pos)); - Debug(PROCESS,"added argument %s", argument_vector.back()); + Debug(PROCESS, "added argument %s", argument_vector.back()); operatorArguments.erase(0, pos + 1); } argument_vector.push_back(operatorArguments); @@ -190,10 +263,11 @@ ProcessManager::split_args(std::string operatorArguments) while ((pos = operatorArguments.find(delimiter)) != std::string::npos) { argument_vector.push_back(operatorArguments.substr(0, pos)); - Debug(PROCESS,"added argument %s", argument_vector.back()); + Debug(PROCESS, "added argument %s", argument_vector.back()); operatorArguments.erase(0, pos + 1); } argument_vector.push_back(operatorArguments); + Debug(PROCESS, "added argument %s", argument_vector.back()); return argument_vector; } diff --git a/src/processManager.h b/src/processManager.h index 237a8b89966c5e9d3fa126444f2abec2d71999c3..52638eb38eab017dfcbbd032e557e34c41847429 100644 --- a/src/processManager.h +++ b/src/processManager.h @@ -11,7 +11,6 @@ #include <pthread.h> #include "node.h" -#include "modules.h" // cdo includes diff --git a/src/process_int.cc b/src/process_int.cc index 3ac941302c746ee13b950d13a936c08d81d831c1..2b67fa3933fab39c50ffe70094103c9f48370c33 100644 --- a/src/process_int.cc +++ b/src/process_int.cc @@ -30,7 +30,12 @@ #include "factory.h" thread_local Process *localProcess; -static int NumProcessActive = 0; + +void +set_local_process(Process *p) +{ + localProcess = p; +} int cdo_filetype(void) @@ -44,12 +49,6 @@ cdo_filetype(void) return CdoDefault::FileType; } -Process & -process_self(void) -{ - return *localProcess; -} - void process_def_var_num(int nvars) { @@ -158,12 +157,6 @@ operator_input_arg(const char *enter) } } -int -cdo_operator_add(const char *name, int f1, int f2, const char *enter) -{ - return localProcess->operator_add(name, f1, f2, enter); -} - int cdo_operator_id(void) { @@ -173,37 +166,37 @@ cdo_operator_id(void) int cdo_operator_f1(int operID) { - return localProcess->oper[operID].f1; + return localProcess->m_module.operators[operID].f1; } int cdo_operator_f2(int operID) { - return localProcess->oper[operID].f2; + return localProcess->m_module.operators[operID].f2; } const char * cdo_operator_name(int operID) { - return localProcess->oper[operID].name.c_str(); + return localProcess->m_module.operators[operID].name.c_str(); } std::string cdo_module_name() { - return get_module_name_to(cdo_operator_name(cdo_operator_id())); + return localProcess->m_module.name; } const char * cdo_operator_enter(int operID) { - return localProcess->oper[operID].enter; + return localProcess->m_module.operators[operID].enter; } int cdo_stream_number() { - return operator_stream_number(localProcess->operatorName); + return localProcess->m_module.get_number(); } int @@ -346,23 +339,6 @@ cdo_get_obase() return localProcess->get_obase(); } -void -cdo_initialize(void *p_process) -{ -#if defined(_OPENMP) - omp_set_num_threads(Threading::ompNumThreads); // Has to be called for every module (pthread)! -#endif - localProcess = (Process *) p_process; -#ifdef HAVE_LIBPTHREAD - localProcess->threadID = pthread_self(); -#endif - Debug(PROCESS_INT, "Initializing process: %s (id: %d)", localProcess->operatorName, localProcess->get_id()); - -#ifdef HAVE_LIBPTHREAD - Debug(PROCESS_INT, "process %d thread %ld", localProcess->m_ID, pthread_self()); -#endif -} - const char * process_inq_prompt(void) { @@ -371,24 +347,6 @@ process_inq_prompt(void) extern "C" size_t getPeakRSS(); -void -cdo_finish(void) -{ - assert(((void) "Internal error: module not initialized!", (localProcess != nullptr))); - - Debug(PROCESS_INT, "Finishing process: %d", localProcess->m_ID); - -#ifdef HAVE_LIBPTHREAD - Debug(PROCESS_INT, "process %d thread %ld", localProcess->m_ID, pthread_self()); -#endif - - if (!Options::silentMode && (cdo::stdoutIsTerminal || Options::cdoVerbose)) localProcess->print_processed_values(); - - // localProcess->close_streams(); - localProcess->set_inactive(); - NumProcessActive--; -} - /* TODO move cdoClose internals into Pstream::close/ CdoStream::close */ void cdo_stream_close(CdoStreamID pstreamPtr) @@ -421,34 +379,34 @@ cdo_stream_inq_vlist(CdoStreamID p_pstreamPtr) // - - - - - - - void -cdo_write_record_f(CdoStreamID p_pstreamPtr, float *data, size_t nmiss) +cdo_write_record_f(CdoStreamID p_pstreamPtr, float *data, size_t numMissVals) { - p_pstreamPtr->write_record(data, nmiss); + p_pstreamPtr->write_record(data, numMissVals); } void -cdo_write_record(CdoStreamID p_pstreamPtr, double *data, size_t nmiss) +cdo_write_record(CdoStreamID p_pstreamPtr, double *data, size_t numMissVals) { - p_pstreamPtr->write_record(data, nmiss); + p_pstreamPtr->write_record(data, numMissVals); } void cdo_write_record(CdoStreamID p_pstreamPtr, Field &field) { if (field.memType == MemType::Float) - cdo_write_record_f(p_pstreamPtr, field.vec_f.data(), field.nmiss); + cdo_write_record_f(p_pstreamPtr, field.vec_f.data(), field.numMissVals); else - cdo_write_record(p_pstreamPtr, field.vec_d.data(), field.nmiss); + cdo_write_record(p_pstreamPtr, field.vec_d.data(), field.numMissVals); } void -cdo_write_record(CdoStreamID p_pstreamPtr, Field3D &field, int levelID, size_t nmiss) +cdo_write_record(CdoStreamID p_pstreamPtr, Field3D &field, int levelID, size_t numMissVals) { const auto offset = levelID * field.gridsize * field.nwpv; if (field.memType == MemType::Float) - cdo_write_record_f(p_pstreamPtr, field.vec_f.data() + offset, nmiss); + cdo_write_record_f(p_pstreamPtr, field.vec_f.data() + offset, numMissVals); else - cdo_write_record(p_pstreamPtr, field.vec_d.data() + offset, nmiss); + cdo_write_record(p_pstreamPtr, field.vec_d.data() + offset, numMissVals); } // - - - - - - - void @@ -485,36 +443,36 @@ cdo_inq_byteorder(CdoStreamID p_pstreamPtr) // - - - - - - - void -cdo_read_record_f(CdoStreamID p_pstreamPtr, float *data, size_t *nmiss) +cdo_read_record_f(CdoStreamID p_pstreamPtr, float *data, size_t *numMissVals) { if (data == nullptr) cdo_abort("Data pointer not allocated (cdo_read_record)!"); - p_pstreamPtr->read_record(data, nmiss); + p_pstreamPtr->read_record(data, numMissVals); } void -cdo_read_record(CdoStreamID p_pstreamPtr, double *data, size_t *nmiss) +cdo_read_record(CdoStreamID p_pstreamPtr, double *data, size_t *numMissVals) { if (data == nullptr) cdo_abort("Data pointer not allocated (cdo_read_record)!"); - p_pstreamPtr->read_record(data, nmiss); + p_pstreamPtr->read_record(data, numMissVals); } void cdo_read_record(CdoStreamID streamID, Field &field) { if (field.memType == MemType::Float) - cdo_read_record_f(streamID, field.vec_f.data(), &field.nmiss); + cdo_read_record_f(streamID, field.vec_f.data(), &field.numMissVals); else - cdo_read_record(streamID, field.vec_d.data(), &field.nmiss); + cdo_read_record(streamID, field.vec_d.data(), &field.numMissVals); } void -cdo_read_record(CdoStreamID streamID, Field3D &field, int levelID, size_t *nmiss) +cdo_read_record(CdoStreamID streamID, Field3D &field, int levelID, size_t *numMissVals) { const auto offset = levelID * field.gridsize * field.nwpv; if (field.memType == MemType::Float) - cdo_read_record_f(streamID, field.vec_f.data() + offset, nmiss); + cdo_read_record_f(streamID, field.vec_f.data() + offset, numMissVals); else - cdo_read_record(streamID, field.vec_d.data() + offset, nmiss); + cdo_read_record(streamID, field.vec_d.data() + offset, numMissVals); } // - - - - - - - diff --git a/src/process_int.h b/src/process_int.h index 7c01d5936ba5135af18f25d1287d7ee303a8d85e..ee4a7ada7649ddebffb4cd3f1cc48030de04500b 100644 --- a/src/process_int.h +++ b/src/process_int.h @@ -8,12 +8,11 @@ #ifndef PROCESS_INT_H #define PROCESS_INT_H -#include "processManager.h" #include "cdo_cdi_wrapper.h" #include "process.h" #include "factory.h" -Process &process_self(void); +void set_local_process(Process *p); bool cdo_assert_files_only(); bool cdo_stream_is_pipe(CdoStreamID streamID); bool data_is_unchanged(); @@ -43,15 +42,15 @@ void cdo_set_nan(double missval, size_t gridsize, double *array); void cdo_inq_record(CdoStreamID streamID, int *varID, int *levelID); void cdo_def_record(CdoStreamID streamID, int varID, int levelID); -void cdo_read_record_f(CdoStreamID streamID, float *data, size_t *nmiss); -void cdo_read_record(CdoStreamID streamID, double *data, size_t *nmiss); +void cdo_read_record_f(CdoStreamID streamID, float *data, size_t *numMissVals); +void cdo_read_record(CdoStreamID streamID, double *data, size_t *numMissVals); void cdo_read_record(CdoStreamID streamID, Field &field); -void cdo_read_record(CdoStreamID streamID, Field3D &field, int levelID, size_t *nmiss); +void cdo_read_record(CdoStreamID streamID, Field3D &field, int levelID, size_t *numMissVals); -void cdo_write_record_f(CdoStreamID streamID, float *data, size_t nmiss); -void cdo_write_record(CdoStreamID streamID, double *data, size_t nmiss); +void cdo_write_record_f(CdoStreamID streamID, float *data, size_t numMissVals); +void cdo_write_record(CdoStreamID streamID, double *data, size_t numMissVals); void cdo_write_record(CdoStreamID streamID, Field &data); -void cdo_write_record(CdoStreamID streamID, Field3D &data, int levelID, size_t nmiss); +void cdo_write_record(CdoStreamID streamID, Field3D &data, int levelID, size_t numMissVals); void cdo_copy_record(CdoStreamID streamIDdest, CdoStreamID streamIDsrc); @@ -70,11 +69,14 @@ CdoStreamID cdo_open_append(int outStreamIDX); CdoStreamID cdo_open_read(int inStreamIDX); CdoStreamID cdo_open_write(int outStreamIDX, int filetype = CDI_UNDEFID); CdoStreamID cdo_open_write(const std::string &p_filename, int filetype = CDI_UNDEFID); -int cdo_operator_add(const char *name, int f1, int f2, const char *enter); int cdo_operator_f1(int operID); int cdo_operator_f2(int operID); int cdo_operator_id(void); -void cdo_finish(); -void cdo_initialize(void *process); + +static inline bool +stream_is_pipe(int p_streamIndex) +{ + return (strncmp(cdo_get_stream_name(p_streamIndex), "(pipe", 5) == 0); +} #endif diff --git a/src/pthread_debug.h b/src/pthread_debug.h index b208f741083cafc40111dbabd06ed42ef5ab36a2..1990f46c261b229c8285e4095b0c0edafc822568 100644 --- a/src/pthread_debug.h +++ b/src/pthread_debug.h @@ -7,6 +7,8 @@ #ifndef PTHREAD_DEBUG_H #define PTHREAD_DEBUG_H +#include <pthread.h> + void print_pthread_attr(const char *caller, pthread_attr_t *attr); int Pthread_create(const char *caller, pthread_t *th, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); diff --git a/src/readline.cc b/src/readline.cc deleted file mode 100644 index bbc155a1cf53e629fc85fedc6bf44ada0e3edf46..0000000000000000000000000000000000000000 --- a/src/readline.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. - - Author: Uwe Schulzweida - -*/ - -#include "readline.h" - -namespace cdo -{ - -int -readline(FILE *fp, char *line, int len) -{ - int ichar, ipos = 0; - - while ((ichar = fgetc(fp)) != EOF) - { - if (ichar == '\r') - { - if ((ichar = fgetc(fp)) != EOF) - if (ichar != '\n') ungetc(ichar, fp); - break; - } - if (ichar == '\n') break; - line[ipos++] = ichar; - if (ipos >= len) - { - fprintf(stderr, "readline Warning: end of line not found (maxlen = %d)!\n", len); - break; - } - } - line[ipos] = 0; - - if (feof(fp) && ipos == 0) return 0; - - return 1; -} - -} // namespace cdo diff --git a/src/readline.h b/src/readline.h deleted file mode 100644 index 2c339e06519b2d5b5aa44af901bb9787e1e8f1fc..0000000000000000000000000000000000000000 --- a/src/readline.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. - - Author: Uwe Schulzweida - -*/ -#ifndef READLINE_H -#define READLINE_H - -#include <cstdio> - -namespace cdo -{ - -int readline(FILE *fp, char *line, int len); - -} - -#endif diff --git a/src/region.cc b/src/region.cc index 866fff393a762901eb9eef5b0dae9c3e2e60f168..ac5db65af588942dc13d2d0987750b277dfc3f89 100644 --- a/src/region.cc +++ b/src/region.cc @@ -5,23 +5,23 @@ */ +#include <fstream> + #include "cdo_options.h" #include "cdo_output.h" #include "util_string.h" #include "varray.h" -#include "readline.h" #include "dcw_reader.h" #include "region.h" static int -read_coords(size_t segmentNo, Varray<double> &xvals, Varray<double> &yvals, const char *polyfile, FILE *fp) +read_coords(size_t segmentNo, Varray<double> &xvals, Varray<double> &yvals, const std::string &polyfile, std::ifstream &file) { auto maxVals = xvals.size(); - constexpr size_t MAX_LINE = 256; - char line[MAX_LINE]; size_t number = 0, jumpedlines = 0; - while (cdo::readline(fp, line, MAX_LINE)) + std::string line; + while (std::getline(file, line)) { if (line[0] == '#' || line[0] == '\0') { @@ -35,7 +35,7 @@ read_coords(size_t segmentNo, Varray<double> &xvals, Varray<double> &yvals, cons auto lineNo = number + jumpedlines + 1; double xcoord, ycoord; - auto nread = std::sscanf(line, "%lf %lf", &xcoord, &ycoord); + auto nread = std::sscanf(line.c_str(), "%lf %lf", &xcoord, &ycoord); if (nread != 2) { if (Options::cdoVerbose) cdo_print("nread=%zu, xcoord=%g, ycoord=%g, line=%s\n", nread, xcoord, ycoord, line); @@ -62,10 +62,10 @@ read_coords(size_t segmentNo, Varray<double> &xvals, Varray<double> &yvals, cons } void -read_regions_from_file(const char *filename, Regions ®ions) +read_regions_from_file(const std::string &filename, Regions ®ions) { - auto fp = std::fopen(filename, "r"); - if (fp == nullptr) cdo_abort("Open failed on %s", filename); + std::ifstream file(filename); + if (!file.is_open()) cdo_abort("Open failed on: %s\n", filename); constexpr size_t maxVals = 1048576; Varray<double> xcoords(maxVals), ycoords(maxVals); @@ -74,7 +74,7 @@ read_regions_from_file(const char *filename, Regions ®ions) size_t n = 0; while (true) { - auto segmentSize = read_coords(segmentNo++, xcoords, ycoords, filename, fp); + auto segmentSize = read_coords(segmentNo++, xcoords, ycoords, filename, file); if (segmentSize == 0) break; if (segmentSize < 3) cdo_abort("Too few point for polygon in file %s (Min=3)!", filename); @@ -91,7 +91,7 @@ read_regions_from_file(const char *filename, Regions ®ions) for (int i = 0; i < segmentSize; ++i) y[offset + i] = ycoords[i]; } - std::fclose(fp); + file.close(); } void diff --git a/src/region.h b/src/region.h index b7743da839374b515bc668c33c4b19169114d2d7..5891fa6e6d76b528ef39e88fabc6deb3e4e62c39 100644 --- a/src/region.h +++ b/src/region.h @@ -7,6 +7,10 @@ #ifndef REGION_H #define REGION_H +#include <vector> +#include <cstddef> // size_t +#include <string> + struct Regions { std::vector<double> x, y; @@ -15,7 +19,7 @@ struct Regions size_t numSegments = 0; }; -void read_regions_from_file(const char *filename, Regions ®ions); +void read_regions_from_file(const std::string &filename, Regions ®ions); void read_regions_from_dcw(const char *codeNames, Regions ®ions); #endif // REGION_H diff --git a/src/remap.h b/src/remap.h index 86af5cb652c640532472a4b8905062fd82d78b13..4ca62eea9b3407eccf47646fcfc44273cda71048 100644 --- a/src/remap.h +++ b/src/remap.h @@ -136,7 +136,7 @@ RemapType int nused = 0; int gridID = -1; size_t gridsize = 0; - size_t nmiss = 0; + size_t numMissVals = 0; RemapGrid srcGrid; RemapGrid tgtGrid; RemapVars vars; @@ -185,8 +185,8 @@ void remap_gradients(RemapGrid &grid, const Field &field, RemapGradients &gradie void sort_add(size_t numLinks, size_t numWeights, size_t *add1, size_t *add2, double *weights); void sort_iter(size_t numLinks, size_t numWeights, size_t *add1, size_t *add2, double *weights, int parent); -void remap_write_data_scrip(const std::string &weightsfile, const RemapSwitches &remapSwitches, RemapGrid &srcGrid, RemapGrid &tgtGrid, - RemapVars &rv); +void remap_write_data_scrip(const std::string &weightsfile, const RemapSwitches &remapSwitches, RemapGrid &srcGrid, + RemapGrid &tgtGrid, RemapVars &rv); RemapSwitches remap_read_data_scrip(const std::string &weightsfile, int gridID1, int gridID2, RemapGrid &srcGrid, RemapGrid &tgtGrid, RemapVars &rv); @@ -217,11 +217,11 @@ void remap_check_area(size_t grid_size, const Varray<double> &cell_area, const c template <typename T> void -remap_set_mask(size_t gridsize, const Varray<T> &v, size_t nmiss, T missval, Varray<short> &mask) +remap_set_mask(size_t gridsize, const Varray<T> &v, size_t numMissVals, T missval, Varray<short> &mask) { mask.resize(gridsize); - if (nmiss) + if (numMissVals) { if (std::isnan(missval)) { @@ -245,12 +245,12 @@ remap_set_mask(size_t gridsize, const Varray<T> &v, size_t nmiss, T missval, Var } inline void -remap_set_mask(size_t gridsize, const Field &field1, size_t nmiss, double missval, Varray<short> &imask) +remap_set_mask(size_t gridsize, const Field &field1, size_t numMissVals, double missval, Varray<short> &imask) { if (field1.memType == MemType::Float) - remap_set_mask(gridsize, field1.vec_f, nmiss, (float) missval, imask); + remap_set_mask(gridsize, field1.vec_f, numMissVals, (float) missval, imask); else - remap_set_mask(gridsize, field1.vec_d, nmiss, missval, imask); + remap_set_mask(gridsize, field1.vec_d, numMissVals, missval, imask); } #endif /* REMAP_H */ diff --git a/src/remap_bicubic.cc b/src/remap_bicubic.cc index 8c1b8e6b4a0040cef6779ba82b5b23fbbb6f820d..bf8826af263a920de6c249abf4ca40c4db4c9778 100644 --- a/src/remap_bicubic.cc +++ b/src/remap_bicubic.cc @@ -6,7 +6,6 @@ */ #include <atomic> -#include <algorithm> // std::sort #include "process_int.h" #include "cdo_timer.h" @@ -82,8 +81,7 @@ bicubic_sort_weights(size_t (&indices)[4], double (&weights)[4][4]) for (int k = 0; k < 4; ++k) indexWeights[i].weight[k] = weights[i][k]; } - auto comp_index = [](const auto &a, const auto &b) noexcept { return a.index < b.index; }; - std::sort(indexWeights.begin(), indexWeights.end(), comp_index); + ranges::sort(indexWeights, {}, &IndexWeightX::index); for (size_t i = 0; i < numWeights; ++i) { @@ -228,7 +226,7 @@ bicubic_remap(const Varray<T> &srcArray, const double (&weights)[4][4], const si template <typename T> static void -remap_bicubic(RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t nmiss) +remap_bicubic(RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t numMissVals) { auto srcGrid = rsearch.srcGrid; auto tgtGrid = rsearch.tgtGrid; @@ -245,7 +243,7 @@ remap_bicubic(RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtArr auto srcGridSize = srcGrid->size; Varray<short> srcGridMask; - if (nmiss) remap_set_mask(srcGridSize, srcArray, nmiss, missval, srcGridMask); + if (numMissVals) remap_set_mask(srcGridSize, srcArray, numMissVals, missval, srcGridMask); // Compute mappings from source to target grid @@ -323,7 +321,7 @@ remap_bicubic(RemapSearch &rsearch, const Field &field1, Field &field2) if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); if (field1.memType == MemType::Float) - remap_bicubic(rsearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.nmiss); + remap_bicubic(rsearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.numMissVals); else - remap_bicubic(rsearch, field1.vec_d, field2.vec_d, field1.missval, field1.nmiss); + remap_bicubic(rsearch, field1.vec_d, field2.vec_d, field1.missval, field1.numMissVals); } diff --git a/src/remap_bilinear.cc b/src/remap_bilinear.cc index cb123f2bd07b49a3bd0f5ba236f0882f76629618..011ec125f2aab9dc65e8dfff8b65977baee2e0e8 100644 --- a/src/remap_bilinear.cc +++ b/src/remap_bilinear.cc @@ -6,7 +6,6 @@ */ #include <atomic> -#include <algorithm> // std::sort #include "process_int.h" #include "cdo_timer.h" @@ -142,8 +141,7 @@ bilinear_sort_weights(size_t (&indices)[4], double (&weights)[4]) indexWeights[i].weight = weights[i]; } - auto comp_index = [](const auto &a, const auto &b) noexcept { return a.index < b.index; }; - std::sort(indexWeights.begin(), indexWeights.end(), comp_index); + ranges::sort(indexWeights, {}, &IndexWeightX::index); for (size_t i = 0; i < numWeights; ++i) { @@ -379,7 +377,7 @@ remap_bilinear_healpix(const RemapSearch &rsearch, const Varray<T> &srcArray, co // This routine computes and apply the weights for a bilinear interpolation. template <typename T> static void -remap_bilinear(RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t nmiss) +remap_bilinear(RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t numMissVals) { const auto srcGrid = rsearch.srcGrid; auto tgtGrid = rsearch.tgtGrid; @@ -399,7 +397,7 @@ remap_bilinear(RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtAr auto srcGridSize = srcGrid->size; Varray<short> srcGridMask; - if (nmiss) remap_set_mask(srcGridSize, srcArray, nmiss, missval, srcGridMask); + if (numMissVals) remap_set_mask(srcGridSize, srcArray, numMissVals, missval, srcGridMask); // Compute mappings from source to target grid @@ -439,7 +437,7 @@ remap_bilinear(RemapSearch &rsearch, const Field &field1, Field &field2) if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); if (field1.memType == MemType::Float) - remap_bilinear(rsearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.nmiss); + remap_bilinear(rsearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.numMissVals); else - remap_bilinear(rsearch, field1.vec_d, field2.vec_d, field1.missval, field1.nmiss); + remap_bilinear(rsearch, field1.vec_d, field2.vec_d, field1.missval, field1.numMissVals); } diff --git a/src/remap_conserv.cc b/src/remap_conserv.cc index c7c903a6b6578881e14ca68f4bf3b81c311ad1cd..5c0c0bfc30a9193642ebe9b5a9517a2c74d83de3 100644 --- a/src/remap_conserv.cc +++ b/src/remap_conserv.cc @@ -6,7 +6,6 @@ */ #include <atomic> -#include <algorithm> // std::sort #include "process_int.h" #include "cdo_timer.h" @@ -147,7 +146,7 @@ static double get_edge_direction(const double *ref_corner, double *corner_a, double *corner_b) { double edge_norm[3]; - crossproduct_ld(corner_a, corner_b, edge_norm); + crossproduct_kahan(corner_a, corner_b, edge_norm); normalise_vector(edge_norm); // sine of the angle between the edge and the reference corner @@ -174,9 +173,7 @@ cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, con // the triangulation algorithm only works for cells that only have great circle edges enum yac_edge_type edgeTypes[3] = { GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE, GREAT_CIRCLE_EDGE }; double coordinates_xyz[3][3] = { { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 } }; - coordinates_xyz[0][0] = baseCorner[0]; - coordinates_xyz[0][1] = baseCorner[1]; - coordinates_xyz[0][2] = baseCorner[2]; + for (int k = 0; k < 3; ++k) coordinates_xyz[0][k] = baseCorner[k]; // data structure to hold the triangles of the target cell struct grid_cell partialCell; @@ -203,12 +200,8 @@ cdo_compute_concave_overlap_areas(size_t numSearchCells, CellSearch &search, con auto edgeDirection = get_edge_direction(baseCorner, cornerA, cornerB); - partialCell.coordinates_xyz[1][0] = cornerA[0]; - partialCell.coordinates_xyz[1][1] = cornerA[1]; - partialCell.coordinates_xyz[1][2] = cornerA[2]; - partialCell.coordinates_xyz[2][0] = cornerB[0]; - partialCell.coordinates_xyz[2][1] = cornerB[1]; - partialCell.coordinates_xyz[2][2] = cornerB[2]; + for (int k = 0; k < 3; ++k) partialCell.coordinates_xyz[1][k] = cornerA[k]; + for (int k = 0; k < 3; ++k) partialCell.coordinates_xyz[2][k] = cornerB[k]; // clip the current target cell triangle with all source cells yac_cell_clipping(numSearchCells, sourceCells.data(), partialCell, overlapCells.data()); @@ -410,9 +403,7 @@ normalize_weights(RemapGrid *tgtGrid, RemapVars &rv) rv.weights[i * numWeights] *= normFactor; } } - else if (rv.normOpt == NormOpt::NONE) - { - } + else if (rv.normOpt == NormOpt::NONE) {} } static void @@ -428,9 +419,7 @@ normalize_weights(NormOpt normOpt, double cellArea, double cellFrac, size_t numW auto normFactor = is_not_equal(cellFrac, 0.0) ? 1.0 / cellFrac : 0.0; for (size_t i = 0; i < numWeights; ++i) weights[i] *= normFactor; } - else if (normOpt == NormOpt::NONE) - { - } + else if (normOpt == NormOpt::NONE) {} } static void @@ -462,8 +451,7 @@ sort_weights(size_t numWeights, Varray<size_t> &indices, Varray<double> &weights indexWeights[i].weight = weights[i]; } - auto compareIndex = [](const auto &a, const auto &b) noexcept { return a.index < b.index; }; - std::sort(indexWeights.begin(), indexWeights.end(), compareIndex); + ranges::sort(indexWeights, {}, &IndexWeightX::index); for (size_t i = 0; i < numWeights; ++i) { @@ -649,7 +637,7 @@ remap_conserv_weights(RemapSearch &remapSearch, RemapVars &rv) if (!useCellsearch) for (int i = 0; i < Threading::ompNumThreads; ++i) indices2[i].resize(srcGridSize); - // Loop over target grid + // Loop over target grid #ifdef _OPENMP #pragma omp parallel for schedule(dynamic) default(shared) @@ -734,8 +722,10 @@ remap_conserv_weights(RemapSearch &remapSearch, RemapVars &rv) if (numWeights > 0) { - if (linksPerValue == -1) linksPerValue = numWeights; - else if (linksPerValue > 0 && linksPerValue != (long)numWeights) linksPerValue = 0; + if (linksPerValue == -1) + linksPerValue = numWeights; + else if (linksPerValue > 0 && linksPerValue != (long) numWeights) + linksPerValue = 0; } } @@ -790,7 +780,7 @@ conserv_remap(const Varray<T> &srcArray, size_t numWeights, const Varray<double> template <typename T> static void -remap_conserv(NormOpt normOpt, RemapSearch &remapSearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t nmiss) +remap_conserv(NormOpt normOpt, RemapSearch &remapSearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t numMissVals) { auto srcGrid = remapSearch.srcGrid; auto tgtGrid = remapSearch.tgtGrid; @@ -811,7 +801,7 @@ remap_conserv(NormOpt normOpt, RemapSearch &remapSearch, const Varray<T> &srcArr auto tgtGridSize = tgtGrid->size; Varray<short> srcGridMask; - if (nmiss) remap_set_mask(srcGridSize, srcArray, nmiss, missval, srcGridMask); + if (numMissVals) remap_set_mask(srcGridSize, srcArray, numMissVals, missval, srcGridMask); auto srcNumCorners = srcGrid->num_cell_corners; auto tgtNumCorners = tgtGrid->num_cell_corners; @@ -866,7 +856,7 @@ remap_conserv(NormOpt normOpt, RemapSearch &remapSearch, const Varray<T> &srcArr if (!useCellsearch) for (int i = 0; i < Threading::ompNumThreads; ++i) indices2[i].resize(srcGridSize); - // Loop over target grid + // Loop over target grid #ifdef _OPENMP #pragma omp parallel for schedule(dynamic) default(shared) @@ -981,9 +971,9 @@ remap_conserv(NormOpt normOpt, RemapSearch &remapSearch, const Field &field1, Fi if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); if (field1.memType == MemType::Float) - remap_conserv(normOpt, remapSearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.nmiss); + remap_conserv(normOpt, remapSearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.numMissVals); else - remap_conserv(normOpt, remapSearch, field1.vec_d, field2.vec_d, field1.missval, field1.nmiss); + remap_conserv(normOpt, remapSearch, field1.vec_d, field2.vec_d, field1.missval, field1.numMissVals); } template <typename T> @@ -1182,11 +1172,11 @@ remap_zonal_mean(const Varray2D<size_t> &remapIndices, const Varray2D<double> &r } } - size_t nmiss = 0; + size_t numMissVals = 0; for (size_t i2 = 0; i2 < ysize2; ++i2) - if (dbl_is_equal(tgtArray[i2], missval)) nmiss++; + if (dbl_is_equal(tgtArray[i2], missval)) numMissVals++; - return nmiss; + return numMissVals; } void @@ -1194,12 +1184,12 @@ remap_zonal_mean(const Varray2D<size_t> &remapIndices, const Varray2D<double> &r { // clang-format off if (field1.memType == MemType::Float && field2.memType == MemType::Float) - field2.nmiss = remap_zonal_mean(remapIndices, remapWeights, field1.vec_f, field2.vec_f, (float)field1.missval); + field2.numMissVals = remap_zonal_mean(remapIndices, remapWeights, field1.vec_f, field2.vec_f, (float)field1.missval); else if (field1.memType == MemType::Float && field2.memType == MemType::Double) - field2.nmiss = remap_zonal_mean(remapIndices, remapWeights, field1.vec_f, field2.vec_d, (float)field1.missval); + field2.numMissVals = remap_zonal_mean(remapIndices, remapWeights, field1.vec_f, field2.vec_d, (float)field1.missval); else if (field1.memType == MemType::Double && field2.memType == MemType::Float) - field2.nmiss = remap_zonal_mean(remapIndices, remapWeights, field1.vec_d, field2.vec_f, field1.missval); + field2.numMissVals = remap_zonal_mean(remapIndices, remapWeights, field1.vec_d, field2.vec_f, field1.missval); else - field2.nmiss = remap_zonal_mean(remapIndices, remapWeights, field1.vec_d, field2.vec_d, field1.missval); + field2.numMissVals = remap_zonal_mean(remapIndices, remapWeights, field1.vec_d, field2.vec_d, field1.missval); // clang-format on } diff --git a/src/remap_conserv_scrip.cc b/src/remap_conserv_scrip.cc index f903046bf422c90e367fb0ad3a2ae428cdfd9889..e1f04913b40b8d51dfe5b5d6c5b5e4d2db66fb44 100644 --- a/src/remap_conserv_scrip.cc +++ b/src/remap_conserv_scrip.cc @@ -1280,7 +1280,7 @@ remap_conserv_weights_scrip(RemapSearch &rsearch, RemapVars &rv) srch_corners = tgtNumCorners; #ifdef _OPENMP -#pragma omp parallel for default(none) shared(findex, rsearch, numWeights, src_centroid_lon, src_centroid_lat, grid_store, rv, \ +#pragma omp parallel for default(none) shared(findex, rsearch, numWeights, src_centroid_lon, src_centroid_lat, grid_store, rv, \ Options::cdoVerbose, max_subseg, srch_corner_lat, srch_corner_lon, maxSearchCells, \ srcNumCorners, srch_corners, srcGrid, tgtGrid, tgtGridSize, srcGridSize, srch_add) #endif @@ -1467,7 +1467,7 @@ remap_conserv_weights_scrip(RemapSearch &rsearch, RemapVars &rv) findex = 0; #ifdef _OPENMP -#pragma omp parallel for default(none) shared(findex, rsearch, numWeights, tgt_centroid_lon, tgt_centroid_lat, grid_store, rv, \ +#pragma omp parallel for default(none) shared(findex, rsearch, numWeights, tgt_centroid_lon, tgt_centroid_lat, grid_store, rv, \ Options::cdoVerbose, max_subseg, srch_corner_lat, srch_corner_lon, maxSearchCells, \ tgtNumCorners, srch_corners, srcGrid, tgtGrid, tgtGridSize, srcGridSize, srch_add) #endif diff --git a/src/remap_distwgt.cc b/src/remap_distwgt.cc index 7d96a85c4b9ffebc9135fe71aefd4f9b8818484e..c826fc6d9e1eec8d9e73d9ec33766ea978925e6c 100644 --- a/src/remap_distwgt.cc +++ b/src/remap_distwgt.cc @@ -77,8 +77,10 @@ remap_distwgt_weights(size_t numNeighbors, RemapSearch &rsearch, RemapVars &rv) if (numNeighbors > 1 && nadds > 0) { - if (linksPerValue == -1) linksPerValue = nadds; - else if (linksPerValue > 0 && linksPerValue != (long)nadds) linksPerValue = 0; + if (linksPerValue == -1) + linksPerValue = nadds; + else if (linksPerValue > 0 && linksPerValue != (long) nadds) + linksPerValue = 0; } } @@ -88,15 +90,17 @@ remap_distwgt_weights(size_t numNeighbors, RemapSearch &rsearch, RemapVars &rv) weight_links_to_remap_links(0, tgtGridSize, weightLinks, rv); - if (numNeighbors == 1) rv.linksPerValue = 1; - else if (linksPerValue > 0) rv.linksPerValue = linksPerValue; + if (numNeighbors == 1) + rv.linksPerValue = 1; + else if (linksPerValue > 0) + rv.linksPerValue = linksPerValue; if (Options::cdoVerbose) cdo_print("Point search nearest: %.2f seconds", timer.elapsed()); } // remap_distwgt_weights template <typename T> static void -remap_distwgt(size_t numNeighbors, RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t nmiss) +remap_distwgt(size_t numNeighbors, RemapSearch &rsearch, const Varray<T> &srcArray, Varray<T> &tgtArray, T missval, size_t numMissVals) { auto srcGrid = rsearch.srcGrid; auto tgtGrid = rsearch.tgtGrid; @@ -111,7 +115,7 @@ remap_distwgt(size_t numNeighbors, RemapSearch &rsearch, const Varray<T> &srcArr auto srcGridSize = srcGrid->size; Varray<short> srcGridMask; - if (nmiss) remap_set_mask(srcGridSize, srcArray, nmiss, missval, srcGridMask); + if (numMissVals) remap_set_mask(srcGridSize, srcArray, numMissVals, missval, srcGridMask); std::vector<knnWeightsType> knnWeights; knnWeights.reserve(Threading::ompNumThreads); @@ -145,8 +149,7 @@ remap_distwgt(size_t numNeighbors, RemapSearch &rsearch, const Varray<T> &srcArr remap_search_points(rsearch, llpoint, knnWgt); // Compute weights based on inverse distance if mask is false, eliminate those points - auto nadds - = (srcGridMask.size() > 0) ? knnWgt.computeWeights(srcGridMask) : knnWgt.computeWeights(); + auto nadds = (srcGridMask.size() > 0) ? knnWgt.computeWeights(srcGridMask) : knnWgt.computeWeights(); if (nadds) tgtValue = knnWgt.arrayWeightsSum(srcArray); } @@ -161,9 +164,9 @@ remap_distwgt(size_t numNeighbors, RemapSearch &rsearch, const Field &field1, Fi if (field1.memType != field2.memType) cdo_abort("Interal error, memType of field1 and field2 differ!"); if (field1.memType == MemType::Float) - remap_distwgt(numNeighbors, rsearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.nmiss); + remap_distwgt(numNeighbors, rsearch, field1.vec_f, field2.vec_f, (float) field1.missval, field1.numMissVals); else - remap_distwgt(numNeighbors, rsearch, field1.vec_d, field2.vec_d, field1.missval, field1.nmiss); + remap_distwgt(numNeighbors, rsearch, field1.vec_d, field2.vec_d, field1.missval, field1.numMissVals); } void @@ -193,7 +196,7 @@ intgriddis(const Field &field1, Field &field2, size_t numNeighbors) auto tgtGridSize = remap.tgtGrid.size; Varray<short> srcGridMask; - if (field1.nmiss) remap_set_mask(srcGridSize, srcArray, field1.nmiss, srcMissval, srcGridMask); + if (field1.numMissVals) remap_set_mask(srcGridSize, srcArray, field1.numMissVals, srcMissval, srcGridMask); std::vector<knnWeightsType> knnWeights; knnWeights.reserve(Threading::ompNumThreads); @@ -205,7 +208,7 @@ intgriddis(const Field &field1, Field &field2, size_t numNeighbors) // Loop over target grid - std::atomic<size_t> nmiss{ 0 }; + std::atomic<size_t> numMissVals{ 0 }; std::atomic<size_t> atomicCount{ 0 }; #ifdef _OPENMP @@ -230,17 +233,16 @@ intgriddis(const Field &field1, Field &field2, size_t numNeighbors) remap_search_points(remap.search, llpoint, knnWgt); // Compute weights based on inverse distance if mask is false, eliminate those points - auto nadds - = (srcGridMask.size() > 0) ? knnWgt.computeWeights(srcGridMask) : knnWgt.computeWeights(); + auto nadds = (srcGridMask.size() > 0) ? knnWgt.computeWeights(srcGridMask) : knnWgt.computeWeights(); if (nadds) tgtValue = knnWgt.arrayWeightsSum(srcArray); else - nmiss++; + numMissVals++; } progress::update(0, 1, 1); - field2.nmiss = nmiss; + field2.numMissVals = numMissVals; remap_grid_free(remap.srcGrid); remap_grid_free(remap.tgtGrid); diff --git a/src/remap_grid_cell_search.cc b/src/remap_grid_cell_search.cc index 9d6ba1ff2747f50c69ec0d43312bec2ae9cc2f27..48bd91e7acbad63f8dae7b06788982c0a5aa6c3a 100644 --- a/src/remap_grid_cell_search.cc +++ b/src/remap_grid_cell_search.cc @@ -5,7 +5,7 @@ */ -//#define WITH_XYZCOORDS 1 +// #define WITH_XYZCOORDS 1 #include "remap_grid_cell_search.h" #include "cdo_output.h" diff --git a/src/remap_point_search.cc b/src/remap_point_search.cc index 9e70c0dad6f9204f4a0618d79435e34176ab32c6..42365a4df48528969f6329b3d98efa7b249e8fe3 100644 --- a/src/remap_point_search.cc +++ b/src/remap_point_search.cc @@ -10,7 +10,7 @@ #include "cdo_math.h" #include "remap.h" #include <mpim_grid.h> -#include "cdo_output.h" +#include "cdo_output.h" static size_t fill_src_indices(bool isCyclic, long nx, long ny, long ii, long jj, long k, size_t *psrcIndices) @@ -44,7 +44,8 @@ fill_src_indices(bool isCyclic, long nx, long ny, long ii, long jj, long k, size } static void -store_distance_healpix(GridPointSearch &gps, double plon, double plat, knnWeightsType &knnWeights, size_t numIndices, size_t *indices, double *srcLons, double *srcLats) +store_distance_healpix(GridPointSearch &gps, double plon, double plat, knnWeightsType &knnWeights, size_t numIndices, + size_t *indices, double *srcLons, double *srcLats) { double xyz[3], query_pt[3]; gcLLtoXYZ(plon, plat, query_pt); @@ -137,9 +138,8 @@ gridSearchPointHealpix(GridPointSearch &gps, double plon, double plat, knnWeight if (neighbours[i] >= 0) indices[numWeights++] = neighbours[i]; double srcLons[9], srcLats[9]; - for (size_t i = 0; i < numWeights; ++i) - hp_index_to_lonlat(gps.order, gps.nside, indices[i], &srcLons[i], &srcLats[i]); - + for (size_t i = 0; i < numWeights; ++i) hp_index_to_lonlat(gps.order, gps.nside, indices[i], &srcLons[i], &srcLats[i]); + store_distance_healpix(gps, plon, plat, knnWeights, numWeights, indices, srcLons, srcLats); } @@ -210,7 +210,8 @@ gridSearchPointReg2d(GridPointSearch &gps, double plon, double plat, knnWeightsT size_t nbrIndices4[4]; double nbrDistance4[4]; for (size_t n = 0; n < numNeighbors; ++n) nbrIndices4[n] = SIZE_MAX; - searchResult = grid_search_square_reg_2d_NN(nx, ny, nbrIndices4, nbrDistance4, plat, plon, src_center_lat, src_center_lon); + searchResult + = grid_search_square_reg_2d_NN(nx, ny, nbrIndices4, nbrDistance4, plat, plon, src_center_lat, src_center_lon); if (searchResult < 0) { for (size_t n = 0; n < numNeighbors; ++n) nbrIndices[n] = nbrIndices4[n]; @@ -219,8 +220,8 @@ gridSearchPointReg2d(GridPointSearch &gps, double plon, double plat, knnWeightsT } else { - searchResult - = grid_search_square_reg_2d_NN(nx, ny, nbrIndices.data(), nbrDistance.data(), plat, plon, src_center_lat, src_center_lon); + searchResult = grid_search_square_reg_2d_NN(nx, ny, nbrIndices.data(), nbrDistance.data(), plat, plon, src_center_lat, + src_center_lon); } if (searchResult >= 0) @@ -408,5 +409,6 @@ remap_search_square(RemapSearch &rsearch, const LonLatPoint &llpoint, size_t (&s else if (rsearch.gps.in_use) return gridSearchSquareCurv2d(rsearch.gps, rsearch.srcGrid, srcIndices, srcLats, srcLons, llpoint.lat, llpoint.lon); else - return grid_search_square_curv_2d_scrip(rsearch.srcGrid, srcIndices, srcLats, srcLons, llpoint.lat, llpoint.lon, rsearch.srcBins); + return grid_search_square_curv_2d_scrip(rsearch.srcGrid, srcIndices, srcLats, srcLons, llpoint.lat, llpoint.lon, + rsearch.srcBins); } diff --git a/src/remap_scrip_io.cc b/src/remap_scrip_io.cc index 5a2d6d07cfa3379e85b40360699101bf20895442..4db2095ba183d687cdd2ca23f93d9a7b0e06e4ac 100644 --- a/src/remap_scrip_io.cc +++ b/src/remap_scrip_io.cc @@ -50,10 +50,7 @@ write_array_int64(int ncId, int ncVarId, nc_type xtype, size_t arraySize, size_t if (xtype == NC_NAT) {} #ifdef HAVE_NETCDF4 #ifdef NC_UINT64 - else if (xtype == NC_UINT64) - { - nce(nc_put_var_ulonglong(ncId, ncVarId, (unsigned long long *) array)); - } + else if (xtype == NC_UINT64) { nce(nc_put_var_ulonglong(ncId, ncVarId, (unsigned long long *) array)); } #endif #endif else @@ -73,10 +70,7 @@ read_array_int64(int ncId, int ncVarId, size_t arraySize, size_t *array) if (xtype == NC_NAT) {} #ifdef HAVE_NETCDF4 #ifdef NC_UINT64 - else if (xtype == NC_UINT64) - { - nce(nc_get_var_ulonglong(ncId, ncVarId, (unsigned long long *) array)); - } + else if (xtype == NC_UINT64) { nce(nc_get_var_ulonglong(ncId, ncVarId, (unsigned long long *) array)); } #endif #endif else @@ -270,7 +264,7 @@ remap_write_data_scrip(const std::string &weightsfile, const RemapSwitches &rema auto srcSizetype = (srcGrid.size > IndexLimit) ? largeSizetype : NC_INT; auto dstSizetype = (tgtGrid.size > IndexLimit) ? largeSizetype : NC_INT; - auto compress{Compress::NONE}; + auto compress{ Compress::NONE }; #ifdef HAVE_NETCDF4 if (CdoDefault::FileType == CDI_FILETYPE_NC4 || CdoDefault::FileType == CDI_FILETYPE_NC4C) { @@ -530,14 +524,8 @@ get_maptype(int ncId) int status = nc_get_att_int(ncId, NC_GLOBAL, "remap_order", &iatt); if (status == NC_NOERR) remapSwitches.remapOrder = iatt; } - else if (mapMethod.starts_with("Bilinear")) - { - remapSwitches.mapType = RemapMethod::BILINEAR; - } - else if (mapMethod.starts_with("Bicubic")) - { - remapSwitches.mapType = RemapMethod::BICUBIC; - } + else if (mapMethod.starts_with("Bilinear")) { remapSwitches.mapType = RemapMethod::BILINEAR; } + else if (mapMethod.starts_with("Bicubic")) { remapSwitches.mapType = RemapMethod::BICUBIC; } else if (mapMethod.starts_with("Distance")) { int numNeighbors = 4; diff --git a/src/remap_search_latbins.cc b/src/remap_search_latbins.cc index 9ffa4b42dfeb7e110c8759fdd018144badc46a07..af7cd615fbdf177482f231a807741b3bd2edceef 100644 --- a/src/remap_search_latbins.cc +++ b/src/remap_search_latbins.cc @@ -394,7 +394,7 @@ grid_search_square_curv_2d_scrip(RemapGrid *srcGrid, size_t (&srcIndices)[4], do printf("Using nearest-neighbor average for this point\n"); */ searchResult = gridSearchSquareCurv2dNNScrip(min_add, max_add, srcIndices, srcLats, plat, plon, srcGrid->cell_center_lat.data(), - srcGrid->cell_center_lon.data()); + srcGrid->cell_center_lon.data()); return searchResult; } diff --git a/src/remap_search_reg2d.cc b/src/remap_search_reg2d.cc index b5f6aa7322030731f1c83b889211689b7143fd1e..2f0856ff420d9a47798165125fa2b8669a6b7762 100644 --- a/src/remap_search_reg2d.cc +++ b/src/remap_search_reg2d.cc @@ -9,7 +9,7 @@ static void nbr_indices_and_distance(int &searchResult, size_t jj, size_t ii, size_t nx, double &dist_min, double distance, size_t *nbrIndices, - double *nbrDistance) + double *nbrDistance) { if (distance < dist_min) { diff --git a/src/remap_store_link.cc b/src/remap_store_link.cc index 664ead2ee87dc8d5fd675a4bd7d39d2f5597a490..e859a60be376510f86bda226951ffafe2f44cb86 100644 --- a/src/remap_store_link.cc +++ b/src/remap_store_link.cc @@ -141,10 +141,7 @@ weight_links_to_remap_links(int doAlloc, size_t gridSize, std::vector<WeightLink if (numLinks) delete[] weightLinks[i].indexWeights; } } - else - { - delete[] weightLinks[0].indexWeights; - } + else { delete[] weightLinks[0].indexWeights; } } } diff --git a/src/remap_store_link.h b/src/remap_store_link.h index 2821f1e8dc2f24b26250f1fe3ae821e29065ad26..6fee3a82d60ba2c65afc8f392efc1c648bfe7487 100644 --- a/src/remap_store_link.h +++ b/src/remap_store_link.h @@ -44,7 +44,8 @@ void weight_links_alloc(size_t numNeighbors, size_t gridSize, std::vector<Weight void weight_links_4_alloc(size_t gridSize, std::vector<WeightLinks4> &weightLinks); void store_weightlinks(int doAlloc, size_t numWeights, const size_t *indices, const double *weights, size_t cellIndex, std::vector<WeightLinks> &weightLinks); -void store_weightlinks_bicubic(const size_t *indices, double (&weights)[4][4], size_t cellIndex, std::vector<WeightLinks4> &weightLinks); +void store_weightlinks_bicubic(const size_t *indices, double (&weights)[4][4], size_t cellIndex, + std::vector<WeightLinks4> &weightLinks); void weight_links_to_remap_links(int doAlloc, size_t gridSize, std::vector<WeightLinks> &weightLinks, RemapVars &rv); void weight_links_4_to_remap_links(size_t gridSize, std::vector<WeightLinks4> &weightLinks, RemapVars &rv); diff --git a/src/remap_store_link_cnsrv.cc b/src/remap_store_link_cnsrv.cc index 82263f1804302579a6890d088f4bfa0da760a55f..59a6721dbd6e55fada4a08e48bf2d917809921e3 100644 --- a/src/remap_store_link_cnsrv.cc +++ b/src/remap_store_link_cnsrv.cc @@ -5,7 +5,8 @@ */ -#include "dmemory.h" +#include <stdlib.h> // malloc() + #include "process_int.h" #include "cdo_options.h" #include "remap.h" @@ -35,9 +36,9 @@ grid_store_init(GridStore &grid_store, long gridsize) fprintf(stdout, "blksize = %ld lastblksize = %ld max_size = %ld nblocks = %ld\n", grid_store.blk_size, grid_store.max_size % grid_store.blk_size, grid_store.max_size, grid_store.nblocks); - grid_store.blksize = (long *) Malloc(grid_store.nblocks * sizeof(long)); - grid_store.nlayers = (long *) Malloc(grid_store.nblocks * sizeof(long)); - grid_store.layers = (GridLayer **) Malloc(grid_store.nblocks * sizeof(GridLayer *)); + grid_store.blksize = (long *) malloc(grid_store.nblocks * sizeof(long)); + grid_store.nlayers = (long *) malloc(grid_store.nblocks * sizeof(long)); + grid_store.layers = (GridLayer **) malloc(grid_store.nblocks * sizeof(GridLayer *)); nblocks = grid_store.nblocks; for (iblk = 0; iblk < nblocks; ++iblk) @@ -71,9 +72,9 @@ grid_store_delete(GridStore &grid_store) } */ GridLayer *grid_layer_f = grid_layer; - Free(grid_layer->grid2_link); + free(grid_layer->grid2_link); grid_layer = grid_layer->next; - Free(grid_layer_f); + free(grid_layer_f); } /* if ( Options::cdoVerbose ) @@ -84,9 +85,9 @@ grid_store_delete(GridStore &grid_store) */ } - Free(grid_store.blksize); - Free(grid_store.layers); - Free(grid_store.nlayers); + free(grid_store.blksize); + free(grid_store.layers); + free(grid_store.nlayers); } /* @@ -153,9 +154,9 @@ store_link_cnsrv(RemapVars &rv, long add1, long add2, long numWeights, double *w if (ilayer < grid_store.nlayers[iblk]) { grid_layer->grid2_link[iadd2] = nlink; } else { - grid_layer = (GridLayer *) Malloc(sizeof(GridLayer)); + grid_layer = (GridLayer *) malloc(sizeof(GridLayer)); grid_layer->next = nullptr; - grid_layer->grid2_link = (long *) Malloc(grid_store.blksize[iblk] * sizeof(long)); + grid_layer->grid2_link = (long *) malloc(grid_store.blksize[iblk] * sizeof(long)); long blksize = grid_store.blksize[iblk]; for (long i = 0; i < blksize; ++i) grid_layer->grid2_link[i] = -1; diff --git a/src/remap_utils.cc b/src/remap_utils.cc index 617806ca3b81a325f108fde5802c14ee9aeaca09..186f426a87828b50a15b12ed7f9cf6d155ccaddf 100644 --- a/src/remap_utils.cc +++ b/src/remap_utils.cc @@ -14,7 +14,8 @@ void remap_sort_addr(RemapVars &rv); void -remap_print_info(int operfunc, bool remap_genweights, const RemapGrid &srcGrid, const RemapGrid &tgtGrid, size_t nmiss, int numNeighbors) +remap_print_info(int operfunc, bool remap_genweights, const RemapGrid &srcGrid, const RemapGrid &tgtGrid, size_t numMissVals, + int numNeighbors) { std::string outStr; // clang-format off @@ -43,13 +44,13 @@ remap_print_info(int operfunc, bool remap_genweights, const RemapGrid &srcGrid, if (tgtGrid.rank == 2) outStr += "x" + std::to_string(tgtGrid.dims[1]); outStr += ") grid"; - if (nmiss) outStr += ", with source mask (" + std::to_string(gridInqSize(srcGrid.gridID) - nmiss) + ")"; + if (numMissVals) outStr += ", with source mask (" + std::to_string(gridInqSize(srcGrid.gridID) - numMissVals) + ")"; cdo_print(outStr); } void -remap_print_warning(const std::string &remapWeightsFile, int operfunc, const RemapGrid &srcGrid, size_t nmiss) +remap_print_warning(const std::string &remapWeightsFile, int operfunc, const RemapGrid &srcGrid, size_t numMissVals) { (void) operfunc; @@ -61,7 +62,7 @@ remap_print_warning(const std::string &remapWeightsFile, int operfunc, const Rem if (srcGrid.rank == 2) outStr += "x" + std::to_string(srcGrid.dims[1]); outStr += ") grid"; - if (nmiss) outStr += " with mask (" + std::to_string(gridInqSize(srcGrid.gridID) - nmiss) + ")"; + if (numMissVals) outStr += " with mask (" + std::to_string(gridInqSize(srcGrid.gridID) - numMissVals) + ")"; outStr += " not found!"; @@ -410,5 +411,5 @@ remap_init(RemapType &remap) remap.nused = 0; remap.gridID = -1; remap.gridsize = 0; - remap.nmiss = 0; + remap.numMissVals = 0; } diff --git a/src/remap_utils.h b/src/remap_utils.h index d49bcd1f00d6117271b534402b200b36fb4a1478..24ad644663adc4073b9db919d077f6cb04128fc6 100644 --- a/src/remap_utils.h +++ b/src/remap_utils.h @@ -58,8 +58,9 @@ remap_func_is_dist(int operfunc) return (operfunc == REMAPDIS || operfunc == GENDIS || operfunc == REMAPNN || operfunc == GENNN); } -void remap_print_info(int operfunc, bool remap_genweights, const RemapGrid &srcGrid, const RemapGrid &tgtGrid, size_t nmiss, int numNeighbors); -void remap_print_warning(const std::string &remapWeightsFile, int operfunc, const RemapGrid &srcGrid, size_t nmiss); +void remap_print_info(int operfunc, bool remap_genweights, const RemapGrid &srcGrid, const RemapGrid &tgtGrid, size_t numMissVals, + int numNeighbors); +void remap_print_warning(const std::string &remapWeightsFile, int operfunc, const RemapGrid &srcGrid, size_t numMissVals); RemapParams remap_get_params(); void remap_set_params(const RemapParams &remapParams); diff --git a/src/remap_vars.cc b/src/remap_vars.cc index aa0cd6096a2da70ee366f4273eaf70660f56203a..52feb2a2acac9075b0f7b71c17cd124d30d33bc7 100644 --- a/src/remap_vars.cc +++ b/src/remap_vars.cc @@ -178,8 +178,8 @@ remap(Varray<T2> &tgtArray, T2 missval, size_t tgtSize, const RemapVars &rv, con tgtIndices target indices for each link srcIndices source indices for each link numWeights num of weights used in remapping - weights remapping weights for each link - srcArray array with source field to be remapped + weights remapping weights for each link + srcArray array with source field to be remapped Optional: @@ -189,7 +189,6 @@ remap(Varray<T2> &tgtArray, T2 missval, size_t tgtSize, const RemapVars &rv, con tgtArray array for remapped field on target grid */ - // if (Options::cdoVerbose) cdo_print("Remap links is sorted: %s", is_sorted_list() ? "true" : "false"); if (Options::cdoVerbose) cdo_print("Remap links per value: %ld", rv.linksPerValue); cdo::timer timer; @@ -288,7 +287,7 @@ remap_laf(Varray<T2> &tgtArray, T2 missval, size_t tgtSize, const RemapVars &rv, const auto &tgtIndices = rv.tgtCellIndices; // target indices for each link const auto &srcIndices = rv.srcCellIndices; // source indices for each link - varray_fill(tgtSize, tgtArray, missval); + ranges::fill(tgtArray, missval); if (numLinks == 0) return; @@ -316,8 +315,8 @@ remap_laf(Varray<T2> &tgtArray, T2 missval, size_t tgtSize, const RemapVars &rv, auto &src_cls = src_cls2[ompthID]; auto &src_weights = src_weights2[ompthID]; #endif - varray_fill(src_cls, static_cast<T1>(0.0)); - varray_fill(src_weights, 0.0); + ranges::fill(src_cls, static_cast<T1>(0.0)); + ranges::fill(src_weights, 0.0); // only for sorted tgtIndices! { diff --git a/src/remaplib.cc b/src/remaplib.cc index acbe5fdb8b0f899f565c56b429c1ca3b8e4659ea..c5753074aa6b393f07ea44957b618c0210c7dcaa 100644 --- a/src/remaplib.cc +++ b/src/remaplib.cc @@ -766,15 +766,15 @@ remap_init_grids(RemapMethod mapType, bool doExtrapolate, int gridID1, RemapGrid srcGrid.type = RemapGridType::HealPix; } - //#ifdef YAC_CELL_SEARCH - // if (is_reg2d_grid(gridID2) && mapType == RemapMethod::CONSERV) tgtGrid.type = RemapGridType::Reg2D; - //#else + // #ifdef YAC_CELL_SEARCH + // if (is_reg2d_grid(gridID2) && mapType == RemapMethod::CONSERV) tgtGrid.type = RemapGridType::Reg2D; + // #else if (srcGrid.type == RemapGridType::Reg2D) { if (is_reg2d_grid(gridID2) && mapType == RemapMethod::CONSERV) tgtGrid.type = RemapGridType::Reg2D; // else srcGrid.type = -1; } - //#endif + // #endif if (!remap_gen_weights && is_reg2d_grid(gridID2) && tgtGrid.type != RemapGridType::Reg2D) { @@ -885,7 +885,7 @@ remap_stat(int remapOrder, RemapGrid &srcGrid, RemapGrid &tgtGrid, RemapVars &rv std::vector<size_t> tgt_count(tgtGrid.size, 0); #ifdef HAVE_OPENMP4 - //#pragma omp simd -> wrong result with clang + // #pragma omp simd -> wrong result with clang #endif for (size_t i = 0; i < rv.numLinks; ++i) tgt_count[rv.tgtCellIndices[i]]++; diff --git a/src/remapsort.cc b/src/remapsort.cc index 3b7650d816df4971496eda4b1a1f3629530e5436..09374cc43b2208e5a328cf892773735583e5335b 100644 --- a/src/remapsort.cc +++ b/src/remapsort.cc @@ -219,7 +219,7 @@ sort_add(size_t numLinks, size_t numWeights, size_t *add1, size_t *add2, double */ /* MERGE SORT DEFINES */ -//#define MERGE_SORT_CHUNKS 64 +// #define MERGE_SORT_CHUNKS 64 #define MERGE_SORT_LIMIT_SIZE 4096 // numLinks/(MERGE_SORT_CHUNKS*omp_get_num_procs()) static void diff --git a/src/selboxinfo.h b/src/selboxinfo.h index 2d417f648d33087b192763b84fff29ad4d494862..629b17c5626998350518f61e4cb9610c281c7783 100644 --- a/src/selboxinfo.h +++ b/src/selboxinfo.h @@ -1,6 +1,8 @@ #ifndef SELBOXINFO_H #define SELBOXINFO_H +#include <vector> + struct SelboxInfo { std::vector<long> cellidx; diff --git a/src/sellist.cc b/src/sellist.cc index 5c7c844535260ff0d112b4de08aa9824d8b9df7b..e9f63b7d1dec4178741ef3c6d44559f3a09a723d 100644 --- a/src/sellist.cc +++ b/src/sellist.cc @@ -241,6 +241,36 @@ selinfo_check(SelectInfo &selInfo, int listIdx, void *par) return found; } +bool +selinfo_check_index(SelectInfo &selInfo, int listIdx, int ival, int maxValues) +{ + auto &selList = selInfo.selList; + auto found = false; + + if (!selInfo.isValidListIdx(listIdx)) return found; + + auto nvalues = selInfo.nvalues(listIdx); + if (nvalues) + { + auto &e = selList[listIdx]; + if (e.type == SelType::INT) + { + for (int i = 0; i < nvalues; ++i) + { + int eval = e.ivalues[i]; + if (eval < 0) eval = maxValues + eval + 1; + if (ival == eval) + { + found = true; + e.flag[i] = true; + } + } + } + } + + return found; +} + bool selinfo_check_date(SelectInfo &selInfo, int listIdx, const char *par) { diff --git a/src/sellist.h b/src/sellist.h index 8733d74f59652a77929e7037ddf69915c515b07f..7692b841b2a61e31e82821edf6db37d941299ed2 100644 --- a/src/sellist.h +++ b/src/sellist.h @@ -63,6 +63,7 @@ public: #define SELINFO_CHECK_FLAG(name) selinfo_check_flag(selInfo, listIdx_##name) #define SELINFO_CHECK_RANGE_FLAG(name) selinfo_check_range_flag(selInfo, listIdx_##name) #define SELINFO_CHECK(name) selinfo_check(selInfo, listIdx_##name, &name) +#define SELINFO_CHECK_INDEX(name, numValues) selinfo_check_index(selInfo, listIdx_##name, name, numValues) #define SELINFO_CHECK_DATE(name) selinfo_check_date(selInfo, listIdx_##name, name) #define SELINFO_CHECK_SEASON(name, month) selinfo_check_season(selInfo, listIdx_##name, month) #define SELINFO_CHECK_RANGE(name, value) selinfo_check_range(selInfo, listIdx_##name, value) @@ -74,6 +75,7 @@ int selinfo_add(SelectInfo &selInfo, const std::string &description, const std:: void selinfo_check_flag(const SelectInfo &selInfo, int listIdx); void selinfo_check_range_flag(const SelectInfo &selInfo, int listIdx); bool selinfo_check(SelectInfo &selInfo, int listIdx, void *par); +bool selinfo_check_index(SelectInfo &selInfo, int listIdx, int par, int maxValues); bool selinfo_check_date(SelectInfo &selInfo, int listIdx, const char *par); bool selinfo_check_season(SelectInfo &selInfo, int listIdx, int month); bool selinfo_check_range(SelectInfo &selInfo, int listIdx, double value); diff --git a/src/specspace.h b/src/specspace.h index 800c16ecd97465c33e3a8ec7c188df68c9367efa..87162d0b351411bcbbe8c52b13dce8e4fe10e2e5 100644 --- a/src/specspace.h +++ b/src/specspace.h @@ -12,6 +12,7 @@ #endif #include "cdo_options.h" +#include "cdo_output.h" #include "transform.h" #include "varray.h" @@ -72,7 +73,7 @@ public: if (use_fftw == false) { vtrig.resize(nlon); - const auto status = fft_set(vtrig.data(), ifax, nlon); + auto status = fft_set(vtrig.data(), ifax, nlon); if (status < 0) cdo_abort("FFT error!"); } } diff --git a/src/statistic.cc b/src/statistic.cc index 1106ba15e10ecea7bc0e834288e098eb887b8cb9..51c00d752d90a6d54c53e91bdb007e70cf77b992 100644 --- a/src/statistic.cc +++ b/src/statistic.cc @@ -40,7 +40,7 @@ gamma_help_1(double a, double x) double ap = a; double sum, del = sum = 1.0 / a; - for (int i = 1; i <= 100; ++i) // 100 iterations + for (int i = 1; i <= 100; ++i) // 100 iterations { ap++; del *= x / ap; @@ -66,7 +66,7 @@ gamma_help_2(double a, double x) double d = 1.0 / b; double h = d; - for (int i = 1; i <= 100; ++i) // 100 iterations + for (int i = 1; i <= 100; ++i) // 100 iterations { double an = -i * (i - a); b += 2.0; diff --git a/src/table.cc b/src/table.cc index 3ee6a416c9d3b2bc1f254e5c8de993b7cd8ebb5e..b5fd1fbf2c8362461f8300304fa882de6530b987 100644 --- a/src/table.cc +++ b/src/table.cc @@ -40,4 +40,4 @@ define_table(const std::string &tablearg) return tableID; } -} +} // namespace cdo diff --git a/src/util_date.h b/src/util_date.h index 72e552e8ffcb4b0b5720a0e884a28c3af9c2de13..5949763b248fd3825c224f73999fe4e4667fbfee 100644 --- a/src/util_date.h +++ b/src/util_date.h @@ -2,6 +2,9 @@ #define UTIL_DATE_H #include <cstring> +#include <cstdio> + +#include "cdi_datetime.h" enum { diff --git a/src/util_files.cc b/src/util_files.cc index 4327362e65231142470a4284e81f0a8d8f8d0d72..4790156226166facb864a24f85c18f64d7e99b7a 100644 --- a/src/util_files.cc +++ b/src/util_files.cc @@ -8,17 +8,34 @@ #include "util_files.h" #include "cdo_options.h" +// #include "cdo_output.h" #include "cdo_vlist.h" -#include "readline.h" #include "cdo_default_values.h" bool FileUtils::file_exists(const std::string &fileName) { - struct stat buf; - auto status = stat(fileName.c_str(), &buf); - return (status == 0) && (S_ISREG(buf.st_mode) && buf.st_size > 0); + /* + auto isZarr = (fileName.starts_with("file://") && fileName.find("zarr", 6) != std::string::npos); + if (isZarr) + { + cdo_abort("Enlargement of %s not possible!", fileName); + int start = 7; + auto pos = fileName.find("#mode", start); + if (pos == std::string::npos) return false; + auto zarrName = fileName.substr(start, pos - start); + struct stat buf; + auto status = stat(zarrName.c_str(), &buf); + return (status == 0) && (S_ISDIR(buf.st_mode) && buf.st_size > 0); + } + else + */ + { + struct stat buf; + auto status = stat(fileName.c_str(), &buf); + return (status == 0) && (S_ISREG(buf.st_mode) && buf.st_size > 0); + } } bool @@ -29,18 +46,16 @@ FileUtils::user_file_overwrite(const std::string &fileName) if (!Options::silentMode && cdo::stdinIsTerminal && cdo::stderrIsTerminal) { fprintf(stderr, "File %s already exists, overwrite? (yes/no): ", fileName.c_str()); - char line[1024]; - cdo::readline(stdin, line, 1024); - char *pline = line; - while (isspace((int) *pline)) pline++; - auto len = strlen(pline); - if (len == 3) + std::string line; + std::getline(std::cin, line); + while (std::isspace((int) line[0])) line.erase(0, 1); + if (line.size() == 3) { - if (std::strncmp(pline, "yes", 3) == 0 || std::strncmp(pline, "YES", 3) == 0) status = true; + if (line.starts_with("yes") || line.starts_with("YES")) status = true; } - else if (len == 1) + else if (line.size() == 1) { - if (pline[0] == 'y' || pline[0] == 'Y') status = true; + if (line[0] == 'y' || line[0] == 'Y') status = true; } } diff --git a/src/util_string.cc b/src/util_string.cc index 4adcac9c2767dd5b62feff8130cedaf5688e769c..1757748ccf42355e7b33d3e5c180a01a8e727af7 100644 --- a/src/util_string.cc +++ b/src/util_string.cc @@ -36,14 +36,14 @@ split_string(const std::string &str, const std::string &delimiter) std::string string_to_upper(std::string str) { - std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); }); + std::ranges::transform(str, str.begin(), ::toupper); return str; } std::string string_to_lower(std::string str) { - std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); }); + std::ranges::transform(str, str.begin(), ::tolower); return str; } @@ -142,7 +142,7 @@ split_with_seperator(const std::string &sourceString, const char seperator) bool string_is_float(const std::string &str) { - if (str.empty() || isspace(str[0])) return 0; + if (str.empty() || std::isspace(str[0])) return 0; char *ptr = nullptr; strtod(str.c_str(), &ptr); @@ -152,7 +152,7 @@ string_is_float(const std::string &str) bool string_is_int(const std::string &str) { - if (str.empty() || isspace(str[0])) return 0; + if (str.empty() || std::isspace(str[0])) return 0; char *ptr = nullptr; strtol(str.c_str(), &ptr, 10); @@ -171,7 +171,7 @@ tokenize_comma_seperated_int_list(const std::string &args) { auto tokens = split_with_seperator(args, ','); bool res = true; - for (auto t : tokens) + for (const auto &t : tokens) { if (!string_is_int(t)) { diff --git a/src/util_string.h b/src/util_string.h index b5fbb3b179de1394719192ba18e2bd0be1e09f52..5ad3ebafe62be7a3b5050f0e69c8918d435c0058 100644 --- a/src/util_string.h +++ b/src/util_string.h @@ -13,6 +13,7 @@ #include <vector> #include <memory> #include <stdexcept> +#include <algorithm> #define ADD_PLURAL(n) ((n) != 1 ? "s" : "") @@ -51,4 +52,32 @@ string_format(const std::string &format, Args... args) return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside } +namespace Util +{ +namespace String +{ +static inline std::string +ltrim(std::string s) +{ + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + return s; +} + +static inline std::string +rtrim(std::string s) +{ + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); + return s; +} + +static inline std::string +trim(std::string s) +{ + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); + return s; +} +} // namespace String +} // namespace Util + #endif diff --git a/src/varray.cc b/src/varray.cc index 3d718fb831768f877dcf2a72e37c83c84c94627a..651d3e722c5e54f4fa321bef325356c4064cf649 100644 --- a/src/varray.cc +++ b/src/varray.cc @@ -15,7 +15,6 @@ #include "cimdOmp.h" #include "arithmetic.h" - template <typename T> inline T min_value(T v1, T v2) @@ -72,7 +71,7 @@ template MinMax varray_min_max_mv(size_t len, const Varray<double> &v, double mi template <typename T> MinMaxSum -varray_min_max_sum(size_t len, const Varray<T> &v, MinMaxSum mms) +varray_min_max_sum(size_t len, const Varray<T> &v, const MinMaxSum &mms) { auto f_minmaxsum = [](auto val, auto &vmin, auto &vmax, auto &vsum) { vmin = min_value(vmin, val); @@ -107,12 +106,12 @@ varray_min_max_sum(size_t len, const Varray<T> &v, MinMaxSum mms) } // Explicit instantiation -template MinMaxSum varray_min_max_sum(size_t len, const Varray<float> &v, MinMaxSum mms); -template MinMaxSum varray_min_max_sum(size_t len, const Varray<double> &v, MinMaxSum mms); +template MinMaxSum varray_min_max_sum(size_t len, const Varray<float> &v, const MinMaxSum &mms); +template MinMaxSum varray_min_max_sum(size_t len, const Varray<double> &v, const MinMaxSum &mms); template <typename T> MinMaxSum -varray_min_max_sum_mv(size_t len, const Varray<T> &v, T missval, MinMaxSum mms) +varray_min_max_sum_mv(size_t len, const Varray<T> &v, T missval, const MinMaxSum &mms) { auto f_minmaxsum_mv = [](auto val, auto mv, auto &vmin, auto &vmax, auto &vsum, auto &nvals, auto is_EQ) { if (!is_EQ(val, mv)) @@ -133,7 +132,8 @@ varray_min_max_sum_mv(size_t len, const Varray<T> &v, T missval, MinMaxSum mms) { #ifndef __ICC // wrong result with icc19 #ifdef HAVE_OPENMP4 -#pragma omp parallel for simd if (len > cdoMinLoopSize) default(shared) schedule(static) reduction(min : vmin) reduction(max : vmax) reduction(+ : vsum,nvals) +#pragma omp parallel for simd if (len > cdoMinLoopSize) default(shared) schedule(static) reduction(min : vmin) \ + reduction(max : vmax) reduction(+ : vsum, nvals) #endif #endif for (size_t i = 0; i < len; ++i) f_minmaxsum_mv((double) v[i], missval, vmin, vmax, vsum, nvals, dbl_is_equal); @@ -142,7 +142,8 @@ varray_min_max_sum_mv(size_t len, const Varray<T> &v, T missval, MinMaxSum mms) { #ifndef __ICC // wrong result with icc19 #ifdef HAVE_OPENMP4 -#pragma omp parallel for simd if (len > cdoMinLoopSize) default(shared) schedule(static) reduction(min : vmin) reduction(max : vmax) reduction(+ : vsum,nvals) +#pragma omp parallel for simd if (len > cdoMinLoopSize) default(shared) schedule(static) reduction(min : vmin) \ + reduction(max : vmax) reduction(+ : vsum, nvals) #endif #endif for (size_t i = 0; i < len; ++i) f_minmaxsum_mv((double) v[i], missval, vmin, vmax, vsum, nvals, is_equal); @@ -155,8 +156,8 @@ varray_min_max_sum_mv(size_t len, const Varray<T> &v, T missval, MinMaxSum mms) } // Explicit instantiation -template MinMaxSum varray_min_max_sum_mv(size_t len, const Varray<float> &v, float missval, MinMaxSum mms); -template MinMaxSum varray_min_max_sum_mv(size_t len, const Varray<double> &v, double missval, MinMaxSum mms); +template MinMaxSum varray_min_max_sum_mv(size_t len, const Varray<float> &v, float missval, const MinMaxSum &mms); +template MinMaxSum varray_min_max_sum_mv(size_t len, const Varray<double> &v, double missval, const MinMaxSum &mms); template <typename T> MinMaxMean @@ -250,18 +251,18 @@ template <typename T> size_t array_num_mv(size_t len, const T *array, T missval) { - size_t nmiss = 0; + size_t numMissVals = 0; if (std::isnan(missval)) { - for (size_t i = 0; i < len; ++i) count_mv(array[i], missval, nmiss, dbl_is_equal); + for (size_t i = 0; i < len; ++i) count_mv(array[i], missval, numMissVals, dbl_is_equal); } else { - for (size_t i = 0; i < len; ++i) count_mv(array[i], missval, nmiss, is_equal); + for (size_t i = 0; i < len; ++i) count_mv(array[i], missval, numMissVals, is_equal); } - return nmiss; + return numMissVals; } // Explicit instantiation @@ -276,18 +277,18 @@ varray_num_mv(size_t len, const Varray<T> &v, T missval) assert(v.size() > 0); assert(len <= v.size()); - size_t nmiss = 0; + size_t numMissVals = 0; if (std::isnan(missval)) { - for (size_t i = 0; i < len; ++i) count_mv(v[i], missval, nmiss, dbl_is_equal); + for (size_t i = 0; i < len; ++i) count_mv(v[i], missval, numMissVals, dbl_is_equal); } else { - for (size_t i = 0; i < len; ++i) count_mv(v[i], missval, nmiss, is_equal); + for (size_t i = 0; i < len; ++i) count_mv(v[i], missval, numMissVals, is_equal); } - return nmiss; + return numMissVals; } // Explicit instantiation @@ -411,7 +412,6 @@ varray_max(size_t len, const Varray<T> &v) for (size_t i = 0; i < len; ++i) vmax = max_value(vmax, v[i]); } - return vmax; } @@ -439,7 +439,7 @@ varray_range(size_t len, const Varray<T> &v) vmin = min_value(vmin, v[i]); vmax = max_value(vmax, v[i]); } - } + } else { #ifdef HAVE_OPENMP4 @@ -1099,10 +1099,10 @@ varray_prevarsum_mv(size_t len, const Varray<T> &v, T missval, double &rsum, dou template <typename T> double -varray_var(size_t len, const Varray<T> &v, size_t nmiss, T missval) +varray_var(size_t len, const Varray<T> &v, size_t numMissVals, T missval) { double rsum = 0.0, rsumw = 0.0, rsumq = 0.0, rsumwq = 0.0; - if (nmiss > 0) + if (numMissVals > 0) varray_prevarsum_mv(len, v, missval, rsum, rsumw, rsumq, rsumwq); else varray_prevarsum(len, v, rsum, rsumw, rsumq, rsumwq); @@ -1114,15 +1114,15 @@ varray_var(size_t len, const Varray<T> &v, size_t nmiss, T missval) } // Explicit instantiation -template double varray_var(size_t len, const Varray<float> &v, size_t nmiss, float missval); -template double varray_var(size_t len, const Varray<double> &v, size_t nmiss, double missval); +template double varray_var(size_t len, const Varray<float> &v, size_t numMissVals, float missval); +template double varray_var(size_t len, const Varray<double> &v, size_t numMissVals, double missval); template <typename T> double -varray_var_1(size_t len, const Varray<T> &v, size_t nmiss, T missval) +varray_var_1(size_t len, const Varray<T> &v, size_t numMissVals, T missval) { double rsum = 0.0, rsumw = 0.0, rsumq = 0.0, rsumwq = 0.0; - if (nmiss > 0) + if (numMissVals > 0) varray_prevarsum_mv(len, v, missval, rsum, rsumw, rsumq, rsumwq); else varray_prevarsum(len, v, rsum, rsumw, rsumq, rsumwq); @@ -1134,8 +1134,8 @@ varray_var_1(size_t len, const Varray<T> &v, size_t nmiss, T missval) } // Explicit instantiation -template double varray_var_1(size_t len, const Varray<float> &v, size_t nmiss, float missval); -template double varray_var_1(size_t len, const Varray<double> &v, size_t nmiss, double missval); +template double varray_var_1(size_t len, const Varray<float> &v, size_t numMissVals, float missval); +template double varray_var_1(size_t len, const Varray<double> &v, size_t numMissVals, double missval); template <typename T> static void @@ -1210,10 +1210,10 @@ varray_weighted_prevarsum_mv(size_t len, const Varray<T> &v, const Varray<double template <typename T> double -varray_weighted_var(size_t len, const Varray<T> &v, const Varray<double> &w, size_t nmiss, T missval) +varray_weighted_var(size_t len, const Varray<T> &v, const Varray<double> &w, size_t numMissVals, T missval) { double rsum = 0.0, rsumw = 0.0, rsumq = 0.0, rsumwq = 0.0; - if (nmiss > 0) + if (numMissVals > 0) varray_weighted_prevarsum_mv(len, v, w, missval, rsum, rsumw, rsumq, rsumwq); else varray_weighted_prevarsum(len, v, w, rsum, rsumw, rsumq, rsumwq); @@ -1225,15 +1225,15 @@ varray_weighted_var(size_t len, const Varray<T> &v, const Varray<double> &w, siz } // Explicit instantiation -template double varray_weighted_var(size_t len, const Varray<float> &v, const Varray<double> &w, size_t nmiss, float missval); -template double varray_weighted_var(size_t len, const Varray<double> &v, const Varray<double> &w, size_t nmiss, double missval); +template double varray_weighted_var(size_t len, const Varray<float> &v, const Varray<double> &w, size_t numMissVals, float missval); +template double varray_weighted_var(size_t len, const Varray<double> &v, const Varray<double> &w, size_t numMissVals, double missval); template <typename T> double -varray_weighted_var_1(size_t len, const Varray<T> &v, const Varray<double> &w, size_t nmiss, T missval) +varray_weighted_var_1(size_t len, const Varray<T> &v, const Varray<double> &w, size_t numMissVals, T missval) { double rsum = 0.0, rsumw = 0.0, rsumq = 0.0, rsumwq = 0.0; - if (nmiss > 0) + if (numMissVals > 0) varray_weighted_prevarsum_mv(len, v, w, missval, rsum, rsumw, rsumq, rsumwq); else varray_weighted_prevarsum(len, v, w, rsum, rsumw, rsumq, rsumwq); @@ -1245,8 +1245,8 @@ varray_weighted_var_1(size_t len, const Varray<T> &v, const Varray<double> &w, s } // Explicit instantiation -template double varray_weighted_var_1(size_t len, const Varray<float> &v, const Varray<double> &w, size_t nmiss, float missval); -template double varray_weighted_var_1(size_t len, const Varray<double> &v, const Varray<double> &w, size_t nmiss, double missval); +template double varray_weighted_var_1(size_t len, const Varray<float> &v, const Varray<double> &w, size_t numMissVals, float missval); +template double varray_weighted_var_1(size_t len, const Varray<double> &v, const Varray<double> &w, size_t numMissVals, double missval); template <typename T> static void @@ -1319,13 +1319,13 @@ varray_prekurtsum_mv(size_t len, const Varray<T> &v, T missval, double mean, dou template <typename T> double -varray_kurt(size_t len, const Varray<T> &v, size_t nmiss, T missval) +varray_kurt(size_t len, const Varray<T> &v, size_t numMissVals, T missval) { double rsum3w; // 3rd moment variables double rsum2diff, rsum4diff; double rsum, rsumw; - if (nmiss > 0) + if (numMissVals > 0) { varray_prevarsum0_mv(len, v, missval, rsum, rsumw); varray_prekurtsum_mv(len, v, missval, (rsum / rsumw), rsum3w, rsum2diff, rsum4diff); @@ -1345,8 +1345,8 @@ varray_kurt(size_t len, const Varray<T> &v, size_t nmiss, T missval) } // Explicit instantiation -template double varray_kurt(size_t len, const Varray<float> &v, size_t nmiss, float missval); -template double varray_kurt(size_t len, const Varray<double> &v, size_t nmiss, double missval); +template double varray_kurt(size_t len, const Varray<float> &v, size_t numMissVals, float missval); +template double varray_kurt(size_t len, const Varray<double> &v, size_t numMissVals, double missval); template <typename T> static void @@ -1420,13 +1420,13 @@ varray_preskewsum_mv(size_t len, const Varray<T> &v, T missval, double mean, dou template <typename T> double -varray_skew(size_t len, const Varray<T> &v, size_t nmiss, T missval) +varray_skew(size_t len, const Varray<T> &v, size_t numMissVals, T missval) { double rsum3w; // 3rd moment variables double rsum3diff, rsum2diff; double rsum, rsumw; - if (nmiss > 0) + if (numMissVals > 0) { varray_prevarsum0_mv(len, v, missval, rsum, rsumw); varray_preskewsum_mv(len, v, missval, (rsum / rsumw), rsum3w, rsum3diff, rsum2diff); @@ -1446,8 +1446,8 @@ varray_skew(size_t len, const Varray<T> &v, size_t nmiss, T missval) } // Explicit instantiation -template double varray_skew(size_t len, const Varray<float> &v, size_t nmiss, float missval); -template double varray_skew(size_t len, const Varray<double> &v, size_t nmiss, double missval); +template double varray_skew(size_t len, const Varray<float> &v, size_t numMissVals, float missval); +template double varray_skew(size_t len, const Varray<double> &v, size_t numMissVals, double missval); #include <algorithm> @@ -1460,7 +1460,8 @@ get_nth_element(T *array, size_t length, size_t n) } template <typename T> -static double f_median(size_t len, Varray<T> &v) +static double +f_median(size_t len, Varray<T> &v) { if (len % 2 == 0) { @@ -1478,7 +1479,7 @@ static double f_median(size_t len, Varray<T> &v) template <typename T> double -varray_median(size_t len, const Varray<T> &v, size_t nmiss, T missval) +varray_median(size_t len, const Varray<T> &v, size_t numMissVals, T missval) { assert(len > 0); assert(v.size() > 0); @@ -1486,7 +1487,7 @@ varray_median(size_t len, const Varray<T> &v, size_t nmiss, T missval) double median = missval; - if (nmiss == 0) + if (numMissVals == 0) { Varray<T> v2 = v; median = f_median(len, v2); @@ -1495,7 +1496,8 @@ varray_median(size_t len, const Varray<T> &v, size_t nmiss, T missval) { Varray<T> v2(len); size_t count = 0; - for (size_t i = 0; i < len; ++i) if (!dbl_is_equal(v[i], missval)) v2[count++] = v[i]; + for (size_t i = 0; i < len; ++i) + if (!dbl_is_equal(v[i], missval)) v2[count++] = v[i]; if (count > 0 && count < len) median = f_median(count, v2); } @@ -1503,12 +1505,12 @@ varray_median(size_t len, const Varray<T> &v, size_t nmiss, T missval) } // Explicit instantiation -template double varray_median(size_t len, const Varray<float> &v, size_t nmiss, float missval); -template double varray_median(size_t len, const Varray<double> &v, size_t nmiss, double missval); +template double varray_median(size_t len, const Varray<float> &v, size_t numMissVals, float missval); +template double varray_median(size_t len, const Varray<double> &v, size_t numMissVals, double missval); template <typename T> double -varray_count(size_t len, const Varray<T> &v, size_t nmiss, T missval) +varray_count(size_t len, const Varray<T> &v, size_t numMissVals, T missval) { assert(len > 0); assert(v.size() > 0); @@ -1516,7 +1518,7 @@ varray_count(size_t len, const Varray<T> &v, size_t nmiss, T missval) size_t count = len; - if (nmiss > 0) + if (numMissVals > 0) { count = 0; for (size_t i = 0; i < len; ++i) @@ -1529,5 +1531,5 @@ varray_count(size_t len, const Varray<T> &v, size_t nmiss, T missval) } // Explicit instantiation -template double varray_count(size_t len, const Varray<float> &v, size_t nmiss, float missval); -template double varray_count(size_t len, const Varray<double> &v, size_t nmiss, double missval); +template double varray_count(size_t len, const Varray<float> &v, size_t numMissVals, float missval); +template double varray_count(size_t len, const Varray<double> &v, size_t numMissVals, double missval); diff --git a/src/varray.h b/src/varray.h index 92376451564b0f39f7d37ef162647609fba704fe..d3c7bf82a9e146b3a8b1eb21c2b106f66f7d8083 100644 --- a/src/varray.h +++ b/src/varray.h @@ -8,12 +8,14 @@ #define VARRAY_H #include <iostream> // cerr +#include <algorithm> #include <vector> #include <cstddef> #include <cfloat> #include <cassert> #include "compare.h" +namespace ranges = std::ranges; // unary operators // clang-format off @@ -53,7 +55,7 @@ const auto binary_op_MUL = [](double x, double y) noexcept { return x * y; }; const auto binary_op_DIV = [](double x, double y) noexcept { return x / y; }; // clang-format on -//#define CHECK_UNUSED_VECTOR 1 +// #define CHECK_UNUSED_VECTOR 1 #ifdef CHECK_UNUSED_VECTOR // clang-format off @@ -208,10 +210,10 @@ using Matrix = std::array<std::array<T, COL>, ROW>; */ template <typename T> -MinMaxSum varray_min_max_sum(size_t len, const Varray<T> &v, MinMaxSum mms); +MinMaxSum varray_min_max_sum(size_t len, const Varray<T> &v, const MinMaxSum &mms); template <typename T> -MinMaxSum varray_min_max_sum_mv(size_t len, const Varray<T> &v, T missval, MinMaxSum mms); +MinMaxSum varray_min_max_sum_mv(size_t len, const Varray<T> &v, T missval, const MinMaxSum &mms); template <typename T> MinMaxMean varray_min_max_mean(size_t len, const Varray<T> &v); @@ -225,28 +227,6 @@ MinMax array_min_max_mask(size_t len, const T *array, const Varray<int> &mask); void array_add_array(size_t len, double *array1, const double *array2); void array_add_array_mv(size_t len, double *array1, const double *array2, double missval); -template <typename T1, typename T2> -void -varray_fill(size_t len, T1 *v, T2 value) -{ - T1 c = value; - for (size_t i = 0; i < len; ++i) v[i] = c; -} - -template <typename T1, typename T2> -void -varray_fill(Varray<T1> &v, T2 value) -{ - varray_fill(v.size(), v.data(), value); -} - -template <typename T1, typename T2> -void -varray_fill(size_t len, Varray<T1> &v, T2 value) -{ - varray_fill(len, v.data(), value); -} - template <typename T1, typename T2> void array_copy(size_t len, const T1 *array1, T2 *array2) @@ -277,7 +257,7 @@ varray_transform(const Varray<T> &vIn, Varray<T> &vOut, UnaryOperation unary_op) assert(vOut.size() > 0); assert(vOut.size() <= vIn.size()); - const auto len = vIn.size(); + auto len = vIn.size(); for (size_t i = 0; i < len; ++i) vOut[i] = unary_op(vIn[i]); } @@ -347,27 +327,27 @@ template <typename T> double varray_weighted_avg_mv(size_t len, const Varray<T> &v, const Varray<double> &w, T missval); template <typename T> -double varray_var(size_t len, const Varray<T> &v, size_t nmiss, T missval); +double varray_var(size_t len, const Varray<T> &v, size_t numMissVals, T missval); template <typename T> -double varray_var_1(size_t len, const Varray<T> &v, size_t nmiss, T missval); +double varray_var_1(size_t len, const Varray<T> &v, size_t numMissVals, T missval); template <typename T> -double varray_weighted_var(size_t len, const Varray<T> &v, const Varray<double> &w, size_t nmiss, T missval); +double varray_weighted_var(size_t len, const Varray<T> &v, const Varray<double> &w, size_t numMissVals, T missval); template <typename T> -double varray_weighted_var_1(size_t len, const Varray<T> &v, const Varray<double> &w, size_t nmiss, T missval); +double varray_weighted_var_1(size_t len, const Varray<T> &v, const Varray<double> &w, size_t numMissVals, T missval); template <typename T> -double varray_skew(size_t len, const Varray<T> &v, size_t nmiss, T missval); +double varray_skew(size_t len, const Varray<T> &v, size_t numMissVals, T missval); template <typename T> -double varray_kurt(size_t len, const Varray<T> &v, size_t nmiss, T missval); +double varray_kurt(size_t len, const Varray<T> &v, size_t numMissVals, T missval); template <typename T> -double varray_median(size_t len, const Varray<T> &v, size_t nmiss, T missval); +double varray_median(size_t len, const Varray<T> &v, size_t numMissVals, T missval); template <typename T> -double varray_count(size_t len, const Varray<T> &v, size_t nmiss, T missval); +double varray_count(size_t len, const Varray<T> &v, size_t numMissVals, T missval); #endif // VARRAY_H diff --git a/src/verifygrid.h b/src/verifygrid.h index ec9338281478c781c371f2cbf954b861377ec5c5..ca363282d0285943c7936fb27125d1dec7e9b213 100644 --- a/src/verifygrid.h +++ b/src/verifygrid.h @@ -1,6 +1,8 @@ #ifndef VERIFYGRID_H #define VERIFYGRID_H +#include "varray.h" + struct Point { double x = 0.0, y = 0.0; diff --git a/src/vertical_interp.cc b/src/vertical_interp.cc index e862e81985c494b95bf2a2805754cc7a4580446a..c2c96de248e6cd530b463a425298ba83121b077b 100644 --- a/src/vertical_interp.cc +++ b/src/vertical_interp.cc @@ -285,8 +285,7 @@ template void vertical_interp_Z(const double *restrict geop, const double *restr template <typename T> static inline double -vertical_interp_X_kernel(const T *restrict arrayIn, const T *restrict levels3D, long nl, double level, long ngp, long nhlev, - double missval) +vertical_interp_X_kernel(const T *arrayIn, const T *levels3D, long nl, double level, long ngp, long nhlev, double missval) { auto nh = nl + ngp; return (nl < 0) ? missval @@ -297,38 +296,38 @@ vertical_interp_X_kernel(const T *restrict arrayIn, const T *restrict levels3D, template <typename T> void -vertical_interp_X(const T *restrict arrayIn3D, T *arrayOut3D, const T *levels3D, const int *vertIndex3D, - const double *restrict levels, long numLevels, long ngp, long nhlev, double missval) +vertical_interp_X(const T *restrict arrayIn3D, T *restrict arrayOut3D, const T *levels3D, const int *vertIndex3D, + const double *restrict levels, long numLevels, long numGP, long nhlev, double missval) { if (numLevels > 3) { #ifdef _OPENMP #pragma omp parallel for default(shared) #endif - for (long lp = 0; lp < numLevels; lp++) + for (long levIndex = 0; levIndex < numLevels; levIndex++) { - auto level = levels[lp]; - const int *restrict vertIndex = vertIndex3D + lp * ngp; - auto arrayOut = arrayOut3D + lp * ngp; - for (long i = 0; i < ngp; ++i) + auto level = levels[levIndex]; + const int *restrict vertIndex = vertIndex3D + levIndex * numGP; + auto *restrict arrayOut2D = arrayOut3D + levIndex * numGP; + for (long i = 0; i < numGP; ++i) { - arrayOut[i] = vertical_interp_X_kernel(arrayIn3D, levels3D, vertIndex[i] * ngp + i, level, ngp, nhlev, missval); + arrayOut2D[i] = vertical_interp_X_kernel(arrayIn3D, levels3D, vertIndex[i] * numGP + i, level, numGP, nhlev, missval); } } } else { - for (long lp = 0; lp < numLevels; lp++) + for (long levIndex = 0; levIndex < numLevels; levIndex++) { - auto level = levels[lp]; - const int *restrict vertIndex = vertIndex3D + lp * ngp; - auto *restrict arrayOut = arrayOut3D + lp * ngp; + auto level = levels[levIndex]; + const int *restrict vertIndex = vertIndex3D + levIndex * numGP; + auto *restrict arrayOut2D = arrayOut3D + levIndex * numGP; #ifdef _OPENMP #pragma omp parallel for default(shared) #endif - for (long i = 0; i < ngp; ++i) + for (long i = 0; i < numGP; ++i) { - arrayOut[i] = vertical_interp_X_kernel(arrayIn3D, levels3D, vertIndex[i] * ngp + i, level, ngp, nhlev, missval); + arrayOut2D[i] = vertical_interp_X_kernel(arrayIn3D, levels3D, vertIndex[i] * numGP + i, level, numGP, nhlev, missval); } } } @@ -336,16 +335,16 @@ vertical_interp_X(const T *restrict arrayIn3D, T *arrayOut3D, const T *levels3D, // Explicit instantiation template void vertical_interp_X(const float *restrict arrayIn3D, float *arrayOut3D, const float *levels3D, const int *vertIndex3D, - const double *levels, long numLevels, long ngp, long nhlev, double missval); + const double *levels, long numLevels, long numGP, long nhlev, double missval); template void vertical_interp_X(const double *restrict arrayIn3D, double *arrayOut3D, const double *levels3D, - const int *vertIndex3D, const double *levels, long numLevels, long ngp, long nhlev, double missval); + const int *vertIndex3D, const double *levels, long numLevels, long numGP, long nhlev, double missval); template <typename T> void gen_vert_index(int *vertIndex, const double *restrict plev, const T *restrict levels3D, long ngp, long nplev, long nhlev, bool lreverse) { - varray_fill(ngp * nplev, vertIndex, 0); + ranges::fill_n(vertIndex, ngp * nplev, 0); #ifdef _OPENMP #pragma omp parallel for default(shared) @@ -384,14 +383,14 @@ template void gen_vert_index(int *vertIndex, const double *plev, const double *l template <typename T> void gen_vert_index_mv(int *vertIndex, const double *restrict plev, long ngp, long nplev, const T *restrict psProg, - size_t *restrict pnmiss, bool lreverse) + size_t *restrict pnumMissVals, bool lreverse) { #ifdef _OPENMP #pragma omp parallel for default(shared) #endif for (long lp = 0; lp < nplev; lp++) { - pnmiss[lp] = 0; + pnumMissVals[lp] = 0; T pres = plev[lp]; auto *restrict vertIndexLev = vertIndex + lp * ngp; @@ -402,7 +401,7 @@ gen_vert_index_mv(int *vertIndex, const double *restrict plev, long ngp, long np if (pres < psProg[i]) { vertIndexLev[i] = -1; - pnmiss[lp]++; + pnumMissVals[lp]++; } } } @@ -413,7 +412,7 @@ gen_vert_index_mv(int *vertIndex, const double *restrict plev, long ngp, long np if (pres > psProg[i]) { vertIndexLev[i] = -1; - pnmiss[lp]++; + pnumMissVals[lp]++; } } } @@ -421,7 +420,7 @@ gen_vert_index_mv(int *vertIndex, const double *restrict plev, long ngp, long np } // Explicit instantiation -template void gen_vert_index_mv(int *vertIndex, const double *plev, long ngp, long nplev, const float *psProg, size_t *pnmiss, +template void gen_vert_index_mv(int *vertIndex, const double *plev, long ngp, long nplev, const float *psProg, size_t *pnumMissVals, bool lreverse); -template void gen_vert_index_mv(int *vertIndex, const double *plev, long ngp, long nplev, const double *psProg, size_t *pnmiss, +template void gen_vert_index_mv(int *vertIndex, const double *plev, long ngp, long nplev, const double *psProg, size_t *pnumMissVals, bool lreverse); diff --git a/src/vertical_interp.h b/src/vertical_interp.h index 64e1a70cb284dbc0bb918b26f82533e9643bf65e..7569a3e53e3038895785edf0371c1be984497b72 100644 --- a/src/vertical_interp.h +++ b/src/vertical_interp.h @@ -26,14 +26,14 @@ void vertical_interp_Z(const T *geop, const T *gz, T *pz, const T *fullPress, co template <typename T> void vertical_interp_X(const T *arrayIn3D, T *arrayOut3D, const T *levels3D, const int *vertIndex3D, const double *levels, - long numLevels, long ngp, long nhlev, double missval); + long numLevels, long numGP, long nhlev, double missval); template <typename T> void gen_vert_index(int *vertIndex, const double *plev, const T *fullPress, long ngp, long nplev, long nhlev, bool lreverse = false); template <typename T> -void gen_vert_index_mv(int *vertIndex, const double *plev, long ngp, long nplev, const T *psProg, size_t *pnmiss, +void gen_vert_index_mv(int *vertIndex, const double *plev, long ngp, long nplev, const T *psProg, size_t *pnumMissVals, bool lreverse = false); #endif /* VERTICAL_INTERP_H */ diff --git a/test/bandit_tests/Makefile.am b/test/bandit_tests/Makefile.am index fa64a462d29f7f63becac5e0d5f0b0e70227d093..88c43b4e6ffe19804be19cc2cb5d8ccd189848d9 100644 --- a/test/bandit_tests/Makefile.am +++ b/test/bandit_tests/Makefile.am @@ -1,4 +1,12 @@ -noinst_PROGRAMS = wildcards Seltime_test param_conversion_test module_definitions process_init module_interface parser string_util +noinst_PROGRAMS = wildcards\ + Seltime_test\ + param_conversion_test\ + module_definitions\ + process_init\ + module_interface\ + parser\ + string_util\ + pmlist tests_CPPFLAGS = -I$(top_srcdir)/test/bandit_tests -I$(top_srcdir)/test/bandit_tests/bandit -I$(top_srcdir)/libcdi/src -std=c++20 tests_LDADD = $(top_builddir)/src/libcdo.la $(top_builddir)/libcdi/src/libcdi.la @@ -8,6 +16,10 @@ parser_SOURCES = parser.cc parser_CPPFLAGS = $(tests_CPPFLAGS) parser_LDADD = $(tests_LDADD) +pmlist_SOURCES = pmlist.cc +pmlist_CPPFLAGS = $(tests_CPPFLAGS) +pmlist_LDADD = $(tests_LDADD) + param_conversion_test_SOURCES = param_conversion_test.cc param_conversion_test_CPPFLAGS = $(tests_CPPFLAGS) param_conversion_test_LDADD = $(tests_LDADD) @@ -37,4 +49,13 @@ string_util_CPPFLAGS = $(tests_CPPFLAGS) string_util_LDADD = $(tests_LDADD) LD_LIBRARY_PATH = $(tests_LDADD) -TESTS = ./parser ./wildcards ./Seltime_test ./param_conversion_test ./module_definitions ./process_init ./module_interface ./string_util +TESTS=./parser\ + ./wildcards\ + ./Seltime_test\ + ./param_conversion_test\ + ./module_definitions\ + ./process_init\ + ./module_interface\ + ./string_util\ + ./pmlist + diff --git a/test/bandit_tests/module_definitions.cc b/test/bandit_tests/module_definitions.cc index b08200da4c408e39281dd05bda9a9ad534928162..4f0aae3c1ad31331d9af9dee61d20a34ebbcc964 100644 --- a/test/bandit_tests/module_definitions.cc +++ b/test/bandit_tests/module_definitions.cc @@ -2,51 +2,33 @@ // BANDIT NEEDS TO BE INCLUDED FIRST!!! #include <iostream> -#include "../../src/modules.h" +#include <vector> -bool is_alias(const std::string &); +#include "../../src/modules.h" +#include "../../src/factory.h" +#include "../../src/cdo_module.h" -const std::string alias_name = "alias1-1"; -void * -testFunction(void *test) -{ - return test; -} -static const module_t module_with_alias = { "aliasModule", - testFunction, - {}, - { "oper1-1", "oper1-2" }, - 1, - 0, - 1, - 1, - NoRestriction, - { Alias(alias_name, "oper1-1") } }; +#include "test_module_list.h" using namespace snowhouse; go_bandit([]() { bandit::describe("Testing for registered module with alias", [&]() { - bandit::it("has registered the module", - [&]() { AssertThat(get_modules(), Is().OfLength(1)); }); - bandit::it( - "has added both operators to module map while not adding the alias", - [&]() { AssertThat(get_module_map(), Is().OfLength(2)); }); - bandit::it("has registered the alias", - [&]() { AssertThat(get_aliases(), Is().OfLength(1)); }); - bandit::it("has registered the correct original name", [&]() { - AssertThat(get_aliases()[alias_name], Is().EqualTo("oper1-1")); + bandit::it("has registered the module", [&]() { + AssertThat(Factory::get().size(), Is().EqualTo(13ul)); + }); + }); + bandit::describe("Testing if the help was added", [&]() { + bandit::it("and it can be retrieved", [&]() { + const CdoHelp expected_container = { "dummy_help" }; + AssertThat(Factory::get_help("oper1-1"), + EqualsContainer(expected_container)); }); }); bandit::describe("Testing the interface for alias and name retreval", [&]() { bandit::it("gets the right name for alias", [&]() { - AssertThat(get_original(alias_name.c_str()), Is().EqualTo("oper1-1")); - }); - bandit::it("extracts the operator name", [&]() { - AssertThat(get_original("oper1-1"), Is().EqualTo("oper1-1")); + AssertThat(Factory::get_original(alias_name), Is().EqualTo("oper1-1")); }); - bandit::it("recognizes an alias", - [&]() { AssertThat(is_alias(alias_name), IsTrue()); }); }); }); diff --git a/test/bandit_tests/module_interface.cc b/test/bandit_tests/module_interface.cc index 0c1348dd6c5233c05ffc291a0d1c43cdd1f2f3c2..856e69c02222977b08da689a3dfd2f3ba88b6bd1 100644 --- a/test/bandit_tests/module_interface.cc +++ b/test/bandit_tests/module_interface.cc @@ -4,41 +4,11 @@ #include <iostream> #include "../../src/modules.h" +#include "../../src/parser.h" using namespace snowhouse; go_bandit([]() { - bandit::describe( - "Testing operator name extraction from command string", [&]() { - bandit::it("returns the commandString if it and has no '-' and has no " - "arguments", - [&]() { - AssertThat(extract_operator_name("test"), - Is().EqualTo("test")); - }); - - bandit::it("returns the commandString without the '-' while it has no " - "arguments", - [&]() { - AssertThat(extract_operator_name("-test"), - Is().EqualTo("test")); - }); - - bandit::it( - "returns the commandString without the '-' while it has arguments", - [&]() { - AssertThat(extract_operator_name("-test,arg"), - Is().EqualTo("test")); - }); - - bandit::it( - "returns the commandString while it has arguments and has no '-'", - [&]() { - AssertThat(extract_operator_name("test,arg"), - Is().EqualTo("test")); - }); - }); - bandit::describe( "Testing operator name and argument extraction from command string", [&]() { @@ -47,7 +17,7 @@ go_bandit([]() { [&]() { std::string operName; std::string operArgument; - extract_name_and_argument("-test,arg", operName, + Parser::Util::extract_name_and_argument("-test,arg", operName, operArgument); AssertThat(operName, Is().EqualTo("test")); AssertThat(operArgument, Is().EqualTo("arg")); @@ -55,7 +25,7 @@ go_bandit([]() { bandit::it("does not cut off multiple arguments with no '-'", [&]() { std::string operName; std::string operArgument; - extract_name_and_argument("test,arg,arg2,arg3", operName, + Parser::Util::extract_name_and_argument("test,arg,arg2,arg3", operName, operArgument); AssertThat(operName, Is().EqualTo("test")); AssertThat(operArgument, Is().EqualTo("arg,arg2,arg3")); @@ -66,7 +36,7 @@ go_bandit([]() { [&]() { std::string operName; std::string operArgument; - extract_name_and_argument("test", operName, operArgument); + Parser::Util::extract_name_and_argument("test", operName, operArgument); AssertThat(operName, Is().EqualTo("test")); AssertThat(operArgument, Is().EqualTo("")); }); @@ -75,7 +45,7 @@ go_bandit([]() { [&]() { std::string operName; std::string operArgument; - extract_name_and_argument("-test", operName, operArgument); + Parser::Util::extract_name_and_argument("-test", operName, operArgument); AssertThat(operName, Is().EqualTo("test")); AssertThat(operArgument, Is().EqualTo("")); }); diff --git a/test/bandit_tests/parser.cc b/test/bandit_tests/parser.cc index b1e6adc10ba2cb0cdb61c26d337329814276d141..031cca553f63193e8ebb60d6033d492aa6e9074e 100644 --- a/test/bandit_tests/parser.cc +++ b/test/bandit_tests/parser.cc @@ -12,10 +12,11 @@ #include "../../src/modules.h" #include "../../src/process_int.h" #include "../../src/cdo_options.h" -#include "test_module_list.h" #include "../../src/cdo_node_attach_exception.h" #include "../../src/cdo_exception.h" +#include "test_module_list.h" + // Util stuff tests start at marker: TESTS using namespace snowhouse; @@ -25,7 +26,7 @@ cdoExit() { } const char * -process_inq_prompt(void) +test_process_inq_prompt(void) { static const char *context = "cdo_test"; return context; @@ -72,7 +73,7 @@ check(std::string description, std::vector<std::string> in, std::string out) unsigned numChildrenExpected = -1337; try { - auto res = Parser::parse(in, process_inq_prompt); + auto res = Parser::parse(in, test_process_inq_prompt); AssertThat(res, Is().OfLength(1)); node_structure = res[0]->to_string(); numChildrenExpected = getNumChildren(res[0]); @@ -108,7 +109,7 @@ checkApply(std::string description, std::vector<std::string> in, unsigned numChildrenExpected; try { - auto res = Parser::parse(in, process_inq_prompt); + auto res = Parser::parse(in, test_process_inq_prompt); if (res.size() > 0) { node_structure = res[0]->to_string(); @@ -136,7 +137,7 @@ go_bandit([]() { //============================================================================== cdo::progname = "cdo_bandit_test"; cdo::set_exit_function(cdoExit); - cdo::set_context_function(process_inq_prompt); + cdo::set_context_function(test_process_inq_prompt); // cdo::set_debug(1024); //-----------------------------Test_01------------------------------------------ @@ -377,6 +378,9 @@ go_bandit([]() { checkNegative("Missing inputs are detected in top most parser", { "-in1_out1", "-in1_out1", "out" }, Parser::errmsg_missing_inputs); + checkNegative("OnlyFirst operators are detected in other positions", + { "-in1_out1","-only_first_oper", "-in0_out1", "out" }, + Parser::errmsg_not_in_first_position); }); bandit::describe("Apply Errors:", [&]() { checkNegative("detects arguments with multiple inputs ", diff --git a/test/bandit_tests/pmlist.cc b/test/bandit_tests/pmlist.cc new file mode 100644 index 0000000000000000000000000000000000000000..9f89cee4855dd8fb40ed4953df4abc7d7e3c968f --- /dev/null +++ b/test/bandit_tests/pmlist.cc @@ -0,0 +1,194 @@ +// bandit needs to be included!!! + +#include "bandit/bandit/bandit.h" + +#include <string> +#include <vector> +#include <map> + +#include <stdlib.h> +#include "../../src/pmlist.h" + +class KVTest +{ +public: + std::string msg = "UNINITALIZED"; + std::vector<std::string> input = {}; + int retval = -2; + size_t num_keys = 0; + std::vector<size_t> num_vars = {}; + std::map<std::string, std::vector<std::string>> expected = {}; +}; + +void +check_key_and_values( + const std::pair<const std::string, std::vector<std::string>> &expected, + KVList &KV) +{ + bandit::it(KV.name + " has the right values in the right keys", [&] { + const KeyValues *ptr = KV.search(expected.first); + + AssertThat(ptr, snowhouse::Is().Not().Null()); + AssertThat(expected.second.size(), + snowhouse::Is().EqualTo(ptr->values.size())); + + for (size_t i = 0; i < ptr->values.size(); i++) + { + AssertThat(ptr->values[i], snowhouse::Is().EqualTo(expected.second[i])); + } + }); +} + +void +main_check(const KVTest &curTest, KVList &test_obj) +{ + + bandit::describe(test_obj.name, [&] { + int retVal = -2; + bandit::describe("runs and (" + std::to_string(curTest.retval) + ")", [&] { + retVal = test_obj.parse_arguments(curTest.input); + bandit::it("returns the right exit code", [&] { + AssertThat(retVal, snowhouse::Is().EqualTo(curTest.retval)); + }); + bandit::it("has the right number of keys", [&] { + AssertThat(test_obj.size(), snowhouse::Is().EqualTo(curTest.num_keys)); + }); + }); + + for (auto &expected : curTest.expected) + { + check_key_and_values(expected, test_obj); + } + }); +} + +// TESTS +go_bandit([]() { + std::vector<KVTest> tests + = { { .msg = "handles mutliple keys with multiple values", + .input = { "key1=1.0", "2.0", "key2=2.0", "2.2" }, + .retval = 0, + .num_keys = 2, + .num_vars = { 2, 2 }, + .expected + = { { "key1", { "1.0", "2.0" } }, { "key2", { "2.0", "2.2" } } } }, + + { .msg = "handles missing value after '='", + .input = { "key1=" }, + .retval = 0, + .num_keys = 1, + .expected = {} }, + + { .msg = "handles missing value after '=' in the second argument", + .input = { "key1=1.0", "key2=" }, + .retval = 0, + .num_keys = 2, + .expected = { { "key1", { "1.0" } }, { "key2", {} } } }, + + { .msg = "handles missing '='", + .input = { "key12.0" }, + .retval = -1, + .num_keys = 0, + .expected = {} }, + + { .msg = "handles missing '=' in the second value", + .input = { "key=12.0", "key2" }, + .retval = 0, + .num_keys = 1, + .expected = { { "key", { "12.0", "key2" } } } } }; + + bandit::describe("KvList parse_arguments", [&]() { + for (auto &curTest : tests) + { + bandit::describe(curTest.msg, [&] { + KVList kv; + kv.name = "parse_arguments test"; + main_check(curTest, kv); + }); + } + }); + + bandit::describe("KvList search", [&]() { + KVList kvlist; + auto test = tests[0]; + auto retVal = kvlist.parse_arguments(test.input); + if (retVal != 0) + { + AssertThat(retVal, snowhouse::Is().EqualTo(0)); + } + bandit::describe("KvList search returns correct result", [&]() { + auto resKey1 = kvlist.search("key1"); + bandit::describe("finds both keys and the correct values", [&]() { + bandit::it("finds the first keys", [&]() { + AssertThat(resKey1->key, snowhouse::Is().EqualTo("key1")); + }); + bandit::it("contains the right values", [&]() { + AssertThat(resKey1->values, + snowhouse::EqualsContainer(test.expected["key1"])); + }); + auto resKey2 = kvlist.search("key2"); + bandit::it("finds the second keys", [&]() { + AssertThat(resKey2->key, snowhouse::Is().EqualTo("key2")); + }); + bandit::it("contains the right values", [&]() { + AssertThat(resKey2->values, + snowhouse::EqualsContainer(test.expected["key2"])); + }); + }); + }); + }); + + bandit::describe("KvList append", [&]() { + KVList kvlist; + std::vector<std::string> to_be_inserted = { "1", "2" }; + std::vector<std::string> to_be_appended = { "3", "4" }; + std::string key = "key1"; + bandit::it("adds the values to a new key when no key was found", + [&]() { kvlist.append(key, to_be_inserted); }); + bandit::it("adds the values to the right key", + [&]() { kvlist.append(key, to_be_appended); }); + }); + + bandit::describe("KvList append", [&]() { + KVList kvlist; + std::string key = "key1"; + std::string false_key = "does_not_exist"; + + auto retVal = kvlist.parse_arguments(tests[0].input); + (void) retVal; + bandit::describe("removes given key", [&]() { + bandit::it("has size 2 before remove", [&]() { + AssertThat(kvlist.size(), snowhouse::Is().EqualTo(tests[0].num_keys)); + }); + kvlist.remove(key); + bandit::it("does no longer contain the key:" + key, [&]() { + AssertThat(kvlist.search(key), snowhouse::Is().Null()); + }); + bandit::it("has size 1 after remove", [&]() { + AssertThat(kvlist.size(), snowhouse::Is().EqualTo(1ul)); + }); + }); + bandit::describe("can handle removing a non existing key", [&]() { + auto before = kvlist.size(); + kvlist.remove(false_key); + auto after = kvlist.size(); + bandit::it("did not insert another key on accident", [&]() { + AssertThat(kvlist.search(false_key), snowhouse::Is().Null()); + }); + bandit::it("has not removed anything (size is the same)", + [&]() { AssertThat(before, snowhouse::Is().EqualTo(after)); }); + }); + }); +}); +#define EXCEPTION_EXTRA_INFO = 1; + +int +main(int argc, char **argv) +{ + std::vector<char *> argv_v(argv, argv + argc); + std::string reporter = "--reporter=spec"; + argv_v.push_back(&reporter[0]); + int result = bandit::run(argc + 1, argv_v.data()); + + return result; +} diff --git a/test/bandit_tests/process_init.cc b/test/bandit_tests/process_init.cc index 0f08579af7f68bb3f2cd986c96ff033c6750ec22..6b2c89ef531109ba49672f9ecf0ccf48cd7554b6 100644 --- a/test/bandit_tests/process_init.cc +++ b/test/bandit_tests/process_init.cc @@ -4,43 +4,48 @@ #include <iostream> #include <memory> +#include <vector> +#include <string> +#include <iostream> -#include "../../src/modules.h" +#include "../../src/cdo_module.h" #include "../../src/process.h" -const std::string alias_name = "alias1-1"; -void * -testFunction(void *test) -{ - return test; -} - -static const module_t module_with_alias = { "aliasModule", - testFunction, - {}, - { "oper1-1", "oper1-2" }, - 1, - 0, - 1, - 1, - NoRestriction, - { Alias(alias_name, "oper1-1") } }; +#include "../../src/factory.h" +#include "test_module_list.h" using namespace snowhouse; go_bandit([]() { cdo::progname = "process_init_test"; - std::vector<std::string> arguements; - auto shared_process = std::make_shared<Process>(0, alias_name, arguements); - - bandit::it( - "assignes the origial of the alias as operatorName in init of process", - [&]() { - AssertThat(shared_process->operatorName, Is().EqualTo("oper1-1")); - }); - - bandit::it("creates the right prompt, discarding the alias in favor of the original name", [&]() { - AssertThat(shared_process->prompt, - Is().EqualTo(std::string(cdo::progname) + " " + shared_process->operatorName)); + std::vector<std::string> arguments = {}; + auto constructor_wrapper = Factory::find(alias_name); + + bandit::it("factory contains operators", [&]() { + AssertThat(Factory::get().size(), Is().GreaterThan(0ul)); + bandit::it("found the alias", [&]() { + auto &factory = Factory::get(); + AssertThat(constructor_wrapper != factory.end(), + Is().EqualTo(true)); + + auto shared_process + = constructor_wrapper->second.constructor(0, alias_name, arguments); + + bandit::it("assignes the origial of the alias as operatorName in init of " + "process", + [&]() { + AssertThat(shared_process->operatorName, + Is().EqualTo("oper1-1")); + }); + + bandit::it( + "creates the right prompt, discarding the alias in favor of the " + "original name", + [&]() { + AssertThat(shared_process->prompt, + Is().EqualTo(std::string(cdo::progname) + " " + + shared_process->operatorName)); + }); + }); }); }); diff --git a/test/bandit_tests/test_module_list.h b/test/bandit_tests/test_module_list.h index 9b6675f41c28cc56a5ca08c29e6713d12a3b9423..30cb82c99f20c6d44238bbc4a10a761adeb94a99 100644 --- a/test/bandit_tests/test_module_list.h +++ b/test/bandit_tests/test_module_list.h @@ -1,24 +1,183 @@ #ifndef TEST_MODULE_LIST_H #define TEST_MODULE_LIST_H #include "../../src/modules.h" +#include "../../src/process.h" +#include "../../src/cdo_module.h" + +const CdoHelp dummy_help = { "dummy_help" }; + +class DummyProcess : public Process +{ +public: + using Process::Process; + void init(){}; + void run(){}; + void close(){}; +}; + +const std::string alias_name = "alias1-1"; + +class TestModule : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module = { + .name = "TestModule", + .operators = { { "oper1-1", 0, 1, "constantvalue", dummy_help }, + { "oper1-2", 0, 1, "constantvalue", dummy_help } }, + .aliases = { Alias("alias1-1", "oper1-1") }, + .mode = 0, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, NoRestriction }, + }; + inline static RegisterEntry<TestModule> registration + = RegisterEntry<TestModule>(module); +}; + +class OnlyFirstModule : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module = { + .name = "TestModule", + .operators = { { "only_first_oper", 0, 1, "constantvalue", dummy_help } }, + .aliases = {}, + .mode = 0, // Module mode: 0:intern 1:extern + .number = CDI_BOTH, // Allowed number type + .constraints = { 1, 1, OnlyFirst }, + }; + inline static RegisterEntry<OnlyFirstModule> registration + = RegisterEntry<OnlyFirstModule>(module); +}; + +class Module_in0_out1 : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "in0_out1", + .operators = { { "in0_out1", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { 0, 1, NoRestriction } }; + + inline static RegisterEntry<Module_in0_out1> registration + = RegisterEntry<Module_in0_out1>(module); +}; +class Module_in1_out0 : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "in1_out0", + .operators = { { "in1_out0", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { 1, 0, NoRestriction } }; + + inline static RegisterEntry<Module_in1_out0> registration + = RegisterEntry<Module_in1_out0>(module); +}; +class Module_in1_out1 : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "in1_out1", + .operators = { { "in1_out1", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { 1, 1, NoRestriction } }; + + inline static RegisterEntry<Module_in1_out1> registration + = RegisterEntry<Module_in1_out1>(module); +}; +class Module_in2_out1 : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "in2_out1", + .operators = { { "in2_out1", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { 2, 1, NoRestriction } }; + inline static RegisterEntry<Module_in2_out1> registration + = RegisterEntry<Module_in2_out1>(module); +}; +class Module_in2_outObase : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "in2_outObase", + .operators = { { "in2_outObase", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { 2, -1, NoRestriction } }; + inline static RegisterEntry<Module_in2_outObase> registration + = RegisterEntry<Module_in2_outObase>(module); +}; +class Module_in2_out0 : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "in2_out0", + .operators = { { "in2_out0", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { 2, 0, NoRestriction } }; + inline static RegisterEntry<Module_in2_out0> registration + = RegisterEntry<Module_in2_out0>(module); +}; +class Module_inVariable_out0 : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "inVariable_out0", + .operators = { { "inVariable_out0", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { -1, 0, NoRestriction } }; + inline static RegisterEntry<Module_inVariable_out0> registration + = RegisterEntry<Module_inVariable_out0>(module); +}; +class Module_inVariable_out1 : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "inVariable_out1", + .operators = { { "inVariable_out1", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { -1, 1, NoRestriction } }; + inline static RegisterEntry<Module_inVariable_out1> registration + = RegisterEntry<Module_inVariable_out1>(module); +}; +class Module_files_only : public DummyProcess +{ +public: + using DummyProcess::DummyProcess; + inline static CdoModule module + = { .name = "files_only", + .operators = { { "files_only", 0, 0, nullptr, dummy_help } }, + .aliases = {}, + .mode = 1, + .number = 0, + .constraints = { 1, 1, FilesOnly } }; + inline static RegisterEntry<Module_files_only> registration + = RegisterEntry<Module_files_only>(module); +}; -void *in0_out1(void *test) { return test; } -void *in1_out0(void *test) { return test; } -void *in1_out1(void *test) { return test; } -void *in2_out1(void *test) { return test; } -void *in2_out0(void *test) { return test; } -void *in2_outObase(void *test) { return test; } -void *inVariable_out0(void *test) { return test; } -void *inVariable_out1(void *test) { return test; } -void *file_only(void *test) { return test; } - -static const module_t module_in0_out1 = {"in0_out1",in0_out1, {}, { "in0_out1" }, 1, 0, 0, 1, NoRestriction }; -static const module_t module_in1_out0 = {"in1_out0",in0_out1, {}, { "in1_out0" }, 1, 0, 1, 0, NoRestriction }; -static const module_t module_in1_out1 = {"in1_out1",in1_out1, {}, { "in1_out1" }, 1, 0, 1, 1, NoRestriction }; -static const module_t module_in2_out1 = {"in2_out1",in2_out1, {}, { "in2_out1" }, 1, 0, 2, 1, NoRestriction }; -static const module_t module_in2_outObase = {"in2_outObase",in2_outObase, {}, { "in2_outObase" }, 1, 0, 2, -1, NoRestriction }; -static const module_t module_in2_out0 = {"in2_out0",in2_out0, {}, { "in2_out0" }, 1, 0, 2, 0, NoRestriction }; -static const module_t module_inVariable_out0 = {"inVariable_out0", inVariable_out0, {}, { "inVariable_out0" }, 1, 0, -1, 0, NoRestriction }; -static const module_t module_inVariable_out1 = {"inVariable_out1",inVariable_out1, {}, { "inVariable_out1" }, 1, 0, -1, 1, NoRestriction }; -static const module_t module_files_only = {"files_only",file_only, {}, { "files_only" }, 1, 0, 1, 1, FilesOnly }; #endif diff --git a/test/bandit_tests/util_string.cc b/test/bandit_tests/util_string.cc index 3cf02fd17cc3c8fbb12afd209b20c89a919de602..bf424731df15a04ec066ced2e94cbea298e082f4 100644 --- a/test/bandit_tests/util_string.cc +++ b/test/bandit_tests/util_string.cc @@ -73,6 +73,32 @@ go_bandit([]() { EqualsContainer(expected_tokens)); }); }); + bandit::describe("Testing trim functions", []() { + bandit::describe("Testing ltrim function", []() { + std::string to_be_trimmed = " spaces in front "; + std::string expected = "spaces in front "; + bandit::it("returns the right trim", [&]() { + std::string result = Util::String::ltrim(to_be_trimmed); + AssertThat(result, Equals(expected)); + }); + }); + bandit::describe("Testing rtrim function", []() { + std::string to_be_trimmed = " spaces in back "; + std::string expected = " spaces in back"; + bandit::it("returns the right trim", [&]() { + std::string result = Util::String::rtrim(to_be_trimmed); + AssertThat(result, Equals(expected)); + }); + }); + bandit::describe("Testing trim function", []() { + std::string to_be_trimmed = " no spaces "; + std::string expected = "no spaces"; + bandit::it("returns the right trim", [&]() { + std::string result = Util::String::trim(to_be_trimmed); + AssertThat(result, Equals(expected)); + }); + }); + }); }); bandit::describe("Testing function 'tokenize_comma_seperated_int_list'", diff --git a/test/bm_Remapcon.sh b/test/bm_Remapcon.sh index ac142a1d2a56293f94646128ce124ee1aadd197f..ee5f1f8ffee5d7d8797950ddb65be22193f88ef0 100755 --- a/test/bm_Remapcon.sh +++ b/test/bm_Remapcon.sh @@ -11,7 +11,7 @@ for N in 3 4 5 6 7 8 9; do $CDO -f nc4 topo,icor2b$N $IFILE OFILE=${IFILE}ycon echo "process $IFILE" - time $CDO -P 4 remapcon,global_0.2 $IFILE ${OFILE} + time $CDO -P 1 remapcon,global_0.2 $IFILE ${OFILE} done #1 levante: gcc 11.2.0 avx2 (interactiv) cdo-2.0.5 @@ -74,6 +74,20 @@ done #01 7 7 8 10 14 24 59 #04 2 2 3 3 5 8 21 +# CDO 2.4.0 (YAC3.0.1) +# +#1 hama: clang 16.0.6 avx2 +# 3 4 5 6 7 8 9 10 +#01 10 11 12 15 23 43 125 +#04 3 4 4 5 7 15 44 + +# CDO 2.4.0 (YAC3.1) +# +#1 hama: clang 16.0.6 avx2 +# 3 4 5 6 7 8 9 10 +#01 9 10 12 14 21 40 100 +#04 3 3 4 5 7 13 38 + #1 mistral: intel 18.0.1 avx2 (interactiv on mg208 node) # CDO version 1.9.8 -P 16 # ncells remapcon remapnn diff --git a/test/data/expr1_ref b/test/data/expr1_ref index 64f37005a2b2e49f97c65f872845a0800d6908dc..c19fb7bd7bf46c978f2d099386400ab52c781b8d 100644 Binary files a/test/data/expr1_ref and b/test/data/expr1_ref differ diff --git a/test/data/gen_refdata.sh b/test/data/gen_refdata.sh index 8ca9ccd58397edde383bf996980f83a1bbaea219..e6cc93c47c47b1ffff27e6a44f810679229c6fca 100755 --- a/test/data/gen_refdata.sh +++ b/test/data/gen_refdata.sh @@ -552,12 +552,12 @@ exit # TYPE=20 CODE=129,130,152,156,157 #EOF # -IFILE=afterdata +IFILE=afterdata.grb OFILE=hl_l19.grb $CDO fldmean $IFILE $OFILE IFILE=$OFILE -OFILE=ml2pl_ref -$CDO $FORMAT ml2pl,92500,85000,50000,20000 $IFILE $OFILE +OFILE=ml2plx_ref +$CDO $FORMAT ml2plx,100000,92500,85000,50000,20000 $IFILE $OFILE exit ######################################################################## # diff --git a/test/data/hl_l19.grb b/test/data/hl_l19.grb index 93e0185a387b8f852bbfd9c797e38ecd4c658d48..fa82feb557053d9955ee77476041a70b05d20bab 100644 Binary files a/test/data/hl_l19.grb and b/test/data/hl_l19.grb differ diff --git a/test/data/ml2plx_ref b/test/data/ml2plx_ref index 5fe010526b1079ec209f7ad54ce2a4ed520c09d7..00387c84af3e8f50b08f5e4b8cb9e56b784ddd3e 100644 Binary files a/test/data/ml2plx_ref and b/test/data/ml2plx_ref differ diff --git a/test/data/timcor_ref b/test/data/timcor_ref index bb874802f645e356fe6b8a4cc7c115960f413ee0..d9ebcc2a2f24ef21a6ab61ac05f4cdd82dc2b30e 100644 Binary files a/test/data/timcor_ref and b/test/data/timcor_ref differ diff --git a/test/pytest/Afterburner.py.test.in b/test/pytest/Afterburner.py.test.in index 6557590917cd2982ed8d424a59869db399a38b85..78e5704cb09f981db2a3aaf4139ae778f727b45d 100644 --- a/test/pytest/Afterburner.py.test.in +++ b/test/pytest/Afterburner.py.test.in @@ -35,7 +35,7 @@ if (not HAS_CGRIBEX): elif (not os.path.isdir(XTESTDIR)): test_module.add_skip("test not enabled") else: - SELECT="bot" + SELECT="bot_mean" SELFILE="select_" + SELECT with open(SELFILE, 'w') as f: @@ -66,13 +66,12 @@ if (not HAS_CGRIBEX): elif (not os.path.isdir(XTESTDIR)): test_module.add_skip("test not enabled") else: - SELECT="atm" + SELECT="atm_mean" SELFILE="select_" + SELECT with open(SELFILE, 'w') as f: f.write('CODE=130,131,132,133,135,153,154,156,157,223') - f.write('LEVEL=100000,92500,85000,77500,70000,60000,50000,40000,30000,25000,') - f.write(' 20000,15000,10000,7000,5000,3000,2000,1000,700,500,300,200,100,50,20,10') + f.write('LEVEL=100000,92500,85000,77500,70000,60000,50000,40000,30000,25000,20000,15000,10000,7000,5000,3000,2000,1000,700,500,300,200,100,50,20,10') f.write('TYPE=30') f.write('FORMAT=1') f.write('MEAN=1') @@ -87,4 +86,70 @@ else: t.clean(OFILE, SELFILE) test_module.add(t) +# Test 4 + +if (not HAS_CGRIBEX): + test_module.add_skip("CGRIBEX not enabled") +elif (not os.path.isdir(XTESTDIR)): + test_module.add_skip("test not enabled") +else: + SELECT="atm2_mean" + SELFILE="select_" + SELECT + + with open(SELFILE, 'w') as f: + f.write('CODE=138,148,149,155') + f.write('LEVEL=100000,92500,85000,77500,70000,60000,50000,40000,30000,25000,20000,15000,10000,7000,5000,3000,2000,1000,700,500,300,200,100,50,20,10') + f.write('TYPE=70') + f.write('FORMAT=1') + f.write('MEAN=1') + + IFILE=f'{XTESTDIR}/{AFTERTESTFILE}' + RFILE=f'{XTESTDIR}/after_{SELECT}_ref' + OFILE=f'after_{SELECT}_res' + + t=TAPTest(SELECT) + t.add(f'{CDO} {OPERATOR} {IFILE} {OFILE} < {SELFILE}') + t.add(f'{CDO} diff,abslim={ABSLIMMAX} {OFILE} {RFILE}') + t.clean(OFILE, SELFILE) + test_module.add(t) + +# Test 5 + +if (not HAS_CGRIBEX): + test_module.add_skip("CGRIBEX not enabled") +elif (not os.path.isdir(XTESTDIR)): + test_module.add_skip("test not enabled") +else: + SELECT="atm_mean" + + IFILE=f'{XTESTDIR}/{AFTERTESTFILE}' + RFILE=f'{XTESTDIR}/after_{SELECT}_ref' + OFILE=f'after_{SELECT}_res' + + t=TAPTest(f'{SELECT}:timmean/ml2pl/sp2gp/gheight_half') + t.add(f'{CDO} timmean -ml2plx,100000,92500,85000,77500,70000,60000,50000,40000,30000,25000,20000,15000,10000,7000,5000,3000,2000,1000,700,500,300,200,100,50,20,10 -sp2gp -merge {IFILE} -gheight_half -sp2gp {IFILE} {OFILE}') + t.add(f'{CDO} diff,abslim={ABSLIMMAX},names=intersect {OFILE} {RFILE}') + t.clean(OFILE, SELFILE) + test_module.add(t) + +# Test 6 + +if (not HAS_CGRIBEX): + test_module.add_skip("CGRIBEX not enabled") +elif (not os.path.isdir(XTESTDIR)): + test_module.add_skip("test not enabled") +else: + OPERATORS=["pressure", "pressure_half", "gheight", "gheight_half"] + + IFILE=f'{XTESTDIR}/{AFTERTESTFILE}' + for OPERATOR in OPERATORS: + RFILE=f'{XTESTDIR}/{OPERATOR}_ref' + OFILE=f'{OPERATOR}_res' + + t=TAPTest(f'{OPERATOR}') + t.add(f'{CDO} timmean -{OPERATOR} -sp2gp {IFILE} {OFILE}') + t.add(f'{CDO} diff,abslim={ABSLIMMAX},names=intersect {OFILE} {RFILE}') + t.clean(OFILE) + test_module.add(t) + test_module.run() diff --git a/test/pytest/Expr.py.test.in b/test/pytest/Expr.py.test.in index 27cec5012e50abbb1f3c62a8aa42fbf5f5c6ab4e..4dbf9ef65ccbf01f3fbc30099bc99bba7e0d1437 100644 --- a/test/pytest/Expr.py.test.in +++ b/test/pytest/Expr.py.test.in @@ -10,7 +10,7 @@ ABSLIMMAX="0.001" IFILE=f'{DATAPATH}pl_data' INSTR_LIST=[ -"C1=0.287;_clev=clev(var130);pottemp=var130*((100000/_clev)^C1);", +"var152;C1=0.287;_clev=clev(var130);pottemp=var130*((100000/_clev)^C1);", "C1=0;C2=273.15;C3=1;var1=var129>C1?var130-C2:C3*var152;", "C1=3+4;C2=C1-7;r1=C2+fldmean(var130);r2=vertmean(var130)+C2;" ] diff --git a/test/pytest/Maggraph.py.test.in b/test/pytest/Maggraph.py.test.in index 0715a5c779213bff47b124f7bac4c4112bdda83c..c77793793be5f591ee2f97bfbefb76de7acd14c0 100644 --- a/test/pytest/Maggraph.py.test.in +++ b/test/pytest/Maggraph.py.test.in @@ -28,7 +28,8 @@ for OPER in OPERATORS: t=TAPTest(f'{OPER},device={DEVICE},stat=TRUE') t.add(f'{CDO} {OPER},device={DEVICE},stat=TRUE {IFILES} {OBASE}') - t.add(f'cmp {RFILE} {OFILE}') +# t.add(f'cmp {RFILE} {OFILE}') + t.clean(OFILE) test_module.add(t) test_module.run() diff --git a/test/pytest/Magplot.py.test.in b/test/pytest/Magplot.py.test.in index 1bfb1aa6bb491a04bfbdd9f9d1886a5e4e43bb8d..ef1b08e38444911edf4dac5fca085f1dbdb896b4 100644 --- a/test/pytest/Magplot.py.test.in +++ b/test/pytest/Magplot.py.test.in @@ -26,9 +26,9 @@ for OPER in OPERATORS: OFILE=f'{OBASE}_tsurf.png' RFILE=f'{XTESTDIR}/ref_mag_{OPER}_tsurf.png' - t=TAPTest() - t.add(f'{CDO} {OPER},device={DEVICE},list=200;240;250;260;270;280;290;300;340 {IFILE} {OBASE}') - t.add(f'cmp {RFILE} {OFILE}') + t=TAPTest(f'{OPER},device={DEVICE}') + t.add(f'{CDO} {OPER},"device={DEVICE},list=200;240;250;260;270;280;290;300;340" {IFILE} {OBASE}') +# t.add(f'cmp {RFILE} {OFILE}') t.clean(OFILE) test_module.add(t) diff --git a/test/pytest/Magvector.py.test.in b/test/pytest/Magvector.py.test.in index c5573225e742381ba4bc5122792dc6c8182cee31..b058be4a76ed0e8058a9b33e4275f8ec35ca5496 100644 --- a/test/pytest/Magvector.py.test.in +++ b/test/pytest/Magvector.py.test.in @@ -26,9 +26,9 @@ for OPER in OPERATORS: OFILE=f'{OBASE}.1.png' RFILE=f'{XTESTDIR}/ref_mag_{OPER}.1.png' - t=CdoTesT(f'{OPER},device={DEVICE}') + t=TAPTest(f'{OPER},device={DEVICE}') t.add(f'{CDO} {OPER},device={DEVICE} -chname,u10,u,v10,v {IFILE} {OBASE}') - t.add(f'cmp {RFILE} {OFILE}') +# t.add(f'cmp {RFILE} {OFILE}') t.clean(OFILE) test_module.add(t) diff --git a/test/pytest/Remap4.py.test.in b/test/pytest/Remap4.py.test.in index 604f95e8f3e93fa37b72aacc07be7e21550d00ec..e8518239733e6f15024f68b0681abce9bbfee606 100644 --- a/test/pytest/Remap4.py.test.in +++ b/test/pytest/Remap4.py.test.in @@ -10,7 +10,7 @@ HAS_THREADS=cdo_check_req("has-threads") # remapdis depends on extrapolation for curvilinear grids OPERATORS=["remapnn","remapbil","remapbic","remapcon"] -ABSLIMS=defaultdict(lambda : 0.0002, {"remapdis" : 0.001}) +ABSLIMS=defaultdict(lambda : 0.001, {"remapdis" : 0.001}) GRID="global.grid" TGTGRID="rotated.grid" diff --git a/test/pytest/Timstat3.py.test.in b/test/pytest/Timstat3.py.test.in index 6b4c17ab0c0f073456a1e85eaa66368836e1f6c2..ee21aed7ab874befaa13d2789050698976189e6f 100644 --- a/test/pytest/Timstat3.py.test.in +++ b/test/pytest/Timstat3.py.test.in @@ -3,7 +3,6 @@ from cdoTest import * OPERATORS=["meandiff2test","varquot2test"] -FMS=["srv","grb"] test_module = TestModule() @@ -18,11 +17,10 @@ for OPERATOR in OPERATORS: RFILE=f'{DATAPATH}/{OPERATOR}_ref' OFILE=f'{OPERATOR}_res' - t=TAPTest(f'(srv/grb) {OPERATOR}') - for FM in FMS: - t.add(f'{CDO} -f {FM} {OPERATOR},3,0.05 {IFILE1} {IFILE2} {OFILE}') - t.add(f'{CDO} diff,abslim=0.004 {OFILE} {RFILE}') - t.clean(OFILE) + t=TAPTest(f'{OPERATOR}') + t.add(f'{CDO} {OPERATOR},3,0.05 {IFILE1} {IFILE2} {OFILE}') + t.add(f'{CDO} diff,abslim=0.004 {OFILE} {RFILE}') + t.clean(OFILE) test_module.add(t) test_module.clean(IFILE1,IFILE2) diff --git a/test/pytest/Vertint.py.test.in b/test/pytest/Vertint.py.test.in index 46a8152d331f36d7d9c8182a4974a530c66594f8..7a4b4789152821c24ec2abd432f8a8b48a7985ad 100644 --- a/test/pytest/Vertint.py.test.in +++ b/test/pytest/Vertint.py.test.in @@ -15,7 +15,7 @@ RFILE=f'{DATAPATH}/{OPERATOR}_ref' OFILE=f'{OPERATOR}_res' t=TAPTest(f'{OPERATOR} parameter set 1') t.add(f'{CDO} {FORMAT} {OPERATOR},90000,80000,70000,30000 {IFILE} {OFILE}') -t.add(f'{CDO} diff,abslim=0.001 {OFILE} {RFILE}') +t.add(f'{CDO} diff,abslim=0.002 {OFILE} {RFILE}') t.clean(OFILE) test_module.add(t) @@ -66,7 +66,7 @@ RFILE=f'{DATAPATH}/{OPERATOR}_ref' OFILE=f'{OPERATOR}_res' t=TAPTest(OPERATOR) t.add(f'{CDO} {FORMAT} {OPERATOR},100000,92500,85000,50000,20000 {IFILE} {OFILE}') -t.add(f'{CDO} diff,abslim=0.001 {OFILE} {RFILE}') +t.add(f'{CDO} diff,abslim=0.003 {OFILE} {RFILE}') t.clean(OFILE) test_module.add(t) diff --git a/test/pytest/cdoTest.py.in b/test/pytest/cdoTest.py.in index c671c94ea99250d7f6af9d4e3bf5ad57c64daaae..5c82c018d2c886c19f4cb7b8ea4996df21a918a3 100644 --- a/test/pytest/cdoTest.py.in +++ b/test/pytest/cdoTest.py.in @@ -197,7 +197,7 @@ class TestModule: self.cleanFiles.append(a) def __prepare_data(self,c): - print_flush("Preparing data:") + print_flush("Preparing data:",c) status = run_command(c) if(status != 0): print_flush("ERROR: Fail in test preperation")