From 70912105bcbfc9121379058e5e46fbc10e14c188 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:38:35 -0600 Subject: [PATCH] Update develop-ref after dtcenter/MET#2981 (#2983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 2673 Moved dvariable declaration after include * #2673 Move down namespace below include * Feature #2395 wdir (#2820) * Per #2395, add new columns to VL1L2, VAL1L2, and VCNT line types for wind direction statistics. Work still in progress. * Per #2395, write the new VCNT columns to the output and document the additions to the VL1L2, VAL1L2, and VCNT columns. * Per #2395, add the definition of new statistics to Appendix G. * Per #2395, update file version history. * Per #2395, tweak warning message about zero wind vectors and update grid-stat and point-stat to log calls to the do_vl1l2() function. * Per #2395, refine the weights for wind direction stats, ignoring the undefined directions. * Update src/tools/core/stat_analysis/aggr_stat_line.cc * Update src/tools/core/stat_analysis/parse_stat_line.cc * Update src/tools/core/stat_analysis/aggr_stat_line.cc * Recent changes to branch protection rules for the develop branch have broken the logic of the update_truth.yml GHA workflow. Instead of submitting a PR to merge develop into develop-ref directly, use an intermediate update_truth_for_develop branch. * Feature #2280 ens_prob (#2823) * Per #2280, update to support probability threshold strings like ==8, where 8 is the number of ensemble members, to create probability bins centered on the n/8 for n = 0 ... 8. * Per #2280, update docs about probability threshold settings. * Per #2280, use a loose tolerance when checking for consistent bin widths. * Per #2280, add a new unit test for grid_stat to demonstrate processing the output from gen_ens_prod. * Per #2280, when verifying NMEP probability forecasts, smooth the obs data first. * Per #2280, only request STAT output for the PCT line type to match unit_grid_stat.xml and minimize the new output files. * Per #2280, update config option docs. * Per #2280, update config option docs. * #2673 Change 0 to nullptr * #2673 Change 0 to nullptr * #2673 Change 0 to nullptr * #2673 Change 0 to nullptr * #2673 Change 0 to nullptr * #2673 Removed the redundant parentheses with return * #2673 Removed the redundant parentheses with return * #2673 Removed the redundant parentheses with return * #2673 Removed the redundant parentheses with return * #2673 Removed the redundant parentheses with return * #2673 restored return statement * #2673 Added std namespace * #2673 Moved down 'using namespace' statement. Removed trailing spaces * #2673 Moved down 'using namespace' statement. * #2673 Moved down 'using namespace' statement. * #2673 Moved down 'using namespace' statement. * #2673 Moved down 'using namespace' statement. * #2673 Added std namespace * #2673 Added std namespace * #2673 Added std namespace * #2673 Changed literal 1 to boolean value, true * Feature #2673 enum_to_string (#2835) * Feature #2583 ecnt (#2825) * Unrelated to #2583, fix typo in code comments. * Per #2583, add hooks write 3 new ECNT columns for observation error data. * Per #2583, make error messages about mis-matched array lengths more informative. * Per #2583, switch to more concise variable naming conventions of ign_oerr_cnv, ign_oerr_cor, and dawid_seb. * Per #2583, fix typo to enable compilation * Per #2583, define the 5 new ECNT column names. * Per #2583, add 5 new columns to the ECNT table in the Ensemble-Stat chapter * Per #2583, update stat_columns.cc to write these 5 new ECNT columns * Per #2583, update ECNTInfo class to compute the 5 new ECNT statistics. * Per #2583, update stat-analysis to parse the 5 new ECNT columns. * Per #2583, update aggregate_stat logic for 5 new ECNT columns. * Per #2583, update PairDataEnsemble logic for 5 new ECNT columns * Per #2583, update vx_statistics library with obs_error handling logic for the 5 new ECNT columns * Per #2583, changes to make it compile * Per #2583, changes to make it compile * Per #2583, switch to a consistent ECNT column naming convention with OERR at the end. Using IGN_CONV_OERR and IGN_CORR_OERR. * Per #2583, define ObsErrorEntry::variance() with a call to the dist_var() utility function. * Per #2583, update PairDataEnsemble::compute_pair_vals() to compute the 5 new stats with the correct inputs. * Per #2583, add DEBUG(10) log messages about computing these new stats. * Per #2583, update Stat-Analysis to compute these 5 new stats from the ORANK line type. * Per #2583, whitespace and comments. * Per #2583, update the User's Guide. * Per #2583, remove the DS_ADD_OERR and DS_MULT_OERR ECNT columns and rename DS_OERR as DSS, since observation error is not actually involved in its computation. * Per #2583, minor update to Appendix C * Per #2583, rename ECNT line type statistic DSS to IDSS. * Per #2583, fix a couple of typos * Per #2583, more error checking. * Per #2583, remove the ECNT IDSS column since its just 2*pi*IGN, the existing ignorance score, and only provides meaningful information when combined with the other Dawid-Sebastiani statistics that have already been removed. * Per #2583, add Eric's documentation of these new stats to Appendix C. Along the way, update the DOI links in the references based on this APA style guide: https://apastyle.apa.org/style-grammar-guidelines/references/dois-urls#:~:text=Include%20a%20DOI%20for%20all,URL%2C%20include%20only%20the%20DOI. * Per #2583, fix new equations with embedded underscores for PDF by defining both html and pdf formatting options. * Per #2583, update the ign_conv_oerr equation to include a 2 *pi multiplier for consistency with the existing ignorance score. Also, fix the documented equations. * Per #2583, remove log file that was inadvertently added on this branch. * Per #2583, simplify ObsErrorEntry::variance() implementation. For the distribution type of NONE, return a variance of 0.0 rather than bad data, as discussed with @michelleharrold and @JeffBeck-NOAA on 3/8/2024. --------- Co-authored-by: MET Tools Test Account * Revert #2825 since more documentation and testing is needed (#2837) This reverts commit 108a8958b206d6712197823a083666ab039bf818. * Feature #2583 ecnt fix IGN_OERR_CORR (#2838) * Unrelated to #2583, fix typo in code comments. * Per #2583, add hooks write 3 new ECNT columns for observation error data. * Per #2583, make error messages about mis-matched array lengths more informative. * Per #2583, switch to more concise variable naming conventions of ign_oerr_cnv, ign_oerr_cor, and dawid_seb. * Per #2583, fix typo to enable compilation * Per #2583, define the 5 new ECNT column names. * Per #2583, add 5 new columns to the ECNT table in the Ensemble-Stat chapter * Per #2583, update stat_columns.cc to write these 5 new ECNT columns * Per #2583, update ECNTInfo class to compute the 5 new ECNT statistics. * Per #2583, update stat-analysis to parse the 5 new ECNT columns. * Per #2583, update aggregate_stat logic for 5 new ECNT columns. * Per #2583, update PairDataEnsemble logic for 5 new ECNT columns * Per #2583, update vx_statistics library with obs_error handling logic for the 5 new ECNT columns * Per #2583, changes to make it compile * Per #2583, changes to make it compile * Per #2583, switch to a consistent ECNT column naming convention with OERR at the end. Using IGN_CONV_OERR and IGN_CORR_OERR. * Per #2583, define ObsErrorEntry::variance() with a call to the dist_var() utility function. * Per #2583, update PairDataEnsemble::compute_pair_vals() to compute the 5 new stats with the correct inputs. * Per #2583, add DEBUG(10) log messages about computing these new stats. * Per #2583, update Stat-Analysis to compute these 5 new stats from the ORANK line type. * Per #2583, whitespace and comments. * Per #2583, update the User's Guide. * Per #2583, remove the DS_ADD_OERR and DS_MULT_OERR ECNT columns and rename DS_OERR as DSS, since observation error is not actually involved in its computation. * Per #2583, minor update to Appendix C * Per #2583, rename ECNT line type statistic DSS to IDSS. * Per #2583, fix a couple of typos * Per #2583, more error checking. * Per #2583, remove the ECNT IDSS column since its just 2*pi*IGN, the existing ignorance score, and only provides meaningful information when combined with the other Dawid-Sebastiani statistics that have already been removed. * Per #2583, add Eric's documentation of these new stats to Appendix C. Along the way, update the DOI links in the references based on this APA style guide: https://apastyle.apa.org/style-grammar-guidelines/references/dois-urls#:~:text=Include%20a%20DOI%20for%20all,URL%2C%20include%20only%20the%20DOI. * Per #2583, fix new equations with embedded underscores for PDF by defining both html and pdf formatting options. * Per #2583, update the ign_conv_oerr equation to include a 2 *pi multiplier for consistency with the existing ignorance score. Also, fix the documented equations. * Per #2583, remove log file that was inadvertently added on this branch. * Per #2583, simplify ObsErrorEntry::variance() implementation. For the distribution type of NONE, return a variance of 0.0 rather than bad data, as discussed with @michelleharrold and @JeffBeck-NOAA on 3/8/2024. * Per #2583, updates to ensemble-stat.rst recommended by @michelleharrold and @JeffBeck-NOAA. * Per #2583, implement changes to the IGN_CORR_OERR corrected as directed by @ericgilleland. --------- Co-authored-by: MET Tools Test Account * Update the pull request template to include a question about expected impacts to existing METplus Use Cases. * #2830 Changed enum Builtin to enum class * #2830 Converted enum to enum class at config_constants.h * Feature #2830 bootstrap enum (#2843) * Bugfix #2833 develop azimuth (#2840) * Per #2833, fix n-1 bug when defining the azimuth delta for range/azimuth grids. * Per #2833, when definng TcrmwData:range_max_km, divide by n_range - 1 since the range values start at 0. * Per #2833, remove max_range_km from the TC-RMW config file. Set the default rmw_scale to NA so that its not used by default. And update the documentation. Still actually need to make the logic of the code work as it should. * Per #2833, update tc_rmw to define the range as either a function of rmw or using explicit spacing in km. * Per #2833, update the TCRMW Config files to remove the max_range_km entry, and update the unit test for one call to use RMW ranges and the other to use ranges defined in kilometers. * Per #2833, just correct code comments. * Per #2833, divide by n - 1 when computing the range delta, rather than n. * Per #2833, correct the handling of the maximum range in the tc-rmw tool. For fixed delta km, need to define the max range when setting up the grid at the beginning. --------- Co-authored-by: MET Tools Test Account * #2830 Changed enum PadSize to enum class * #2830 Removed redundant parantheses * #2830 Removed commenyted out code * #2830 Use auto * #2830 Changed enum to enum class for DistType, InterpMthd, GridTemplates, and NormalizeType * #2830 Moved enum_class_as_integer from header file to cc files * #2830 Added enum_as_int.hpp * #2830 Added enum_as_int.hpp * Deleted enum_class_as_integer and renamed it to enum_class_as_int * Removed redundant paranthese * #2830 Changed enum to enumclass * #2830 Changed enum_class_as_integer to enum_class_as_int * Feature #2379 sonarqube gha (#2847) * Per #2379, testing initial GHA SonarQube setup. * Per #2379, switch to only analyzing the src directory. * Per #2379, move more config logic from sonar-project.properties into the workflow. #ci-skip-all * Per #2379, try removing + symbols * Per #2379, move projectKey into xml workflow and remove sonar-project.properties. * Per #2379, try following the instructions at https://github.com/sonarsource-cfamily-examples/linux-autotools-gh-actions-sq/blob/main/.github/workflows/build.yml ci-skip-all * Per #2379, see details of progress described in this issue comment: https://github.com/dtcenter/MET/issues/2379#issuecomment-2000242425 * Unrelated to #2379, just removing spurious space that gets flagged as a diff when re-running enum_to_string on seneca. * Per #2379, try running SonarQube through GitHub. * Per #2379, remove empty env section and also disable the testing workflow temporarily during sonarqube development. * Per #2379, fix docker image name. * Per #2379, delete unneeded script. * Per #2379, update GHA to scan Python code and push to the correct SonarQube projects. * Per #2379, update GHA SonarQube project names * Per #2379, update the build job name * Per #2379, update the comile step name * Per #2379, switch to consistent SONAR variable names. * Per #2379, fix type in sed expressions. * Per #2379, just rename the log artifact * Per #2379, use time_command wrapper instead of run_command. * Per #2379, fix bad env var name * Per #2379, switch from egrep to grep. * Per #2379, just try cat-ting the logfile * Per #2379, test whether cat-ting the log file actually works. * Per #2379, revert back * Per #2379, mention SonarQube in the PR template. Make workflow name more succinct. * Per #2379, add SONAR_REFERENCE_BRANCH setting to define the sonar.newCode.referenceBranch property. The goal is to define the comparison reference branch for each SonarQube scan. * Per #2379, have the sonarqube.yml job print the reference branch it's using * Per #2379, intentionally introduce a new code smell to see if SonarQube correctly flag it as appearing in new code. * Per #2379, trying adding the SonarQube quality gate check. * Per #2379, add logic for using the report-task.txt output files to check the quality gate status for both the python and cxx scans. * Per #2379 must use unique GHA id's * Per #2379, working on syntax for quality gate checks * Per #2379, try again. * Per #2379, try again * Per #2379, try again * Per #2379, try again * Per #2379, try again * Per #2379, try again * Per #2379, try yet again * Per #2379 * Per #2379, add more debug * Per #2379, remove -it option from docker run commands * Per #2379, again * Per #2379, now that the scan works as expected, remove the intentional SonarQube code smell as well as debug logging. * Hotfix related to #2379. The sonar.newCode.referenceBranch and sonar.branch.name cannot be set to the same string! Only add the newCode definition when they differ. * #2830 Changed enum STATJobType to enum class * #2830 Changed STATLineType to enum class * #2830 Changed Action to enum class * #2830 Changed ModeDataType to enum class * #2830 Changed StepCase to enum class * #2830 Changed enum to enum class * #2830 Changed GenesisPairCategory to enum class * #2830 Removed rediundabt parenrthese * #2830 Reduced same if checking * #2830 Cleanup * #2830 USe empty() instead of lebgth checking * #2830 Adjusted indentations * Feature #2379 develop sonarqube updates (#2850) * Per #2379, move rgb2ctable.py into the python utility scripts directory for better organization and to enable convenient SonarQube scanning. * Per #2379, remove point.py from the vx_python3_utils directory which cleary was inadvertenlty added during development 4 years ago. As far as I can tell it isn't being called by any other code and doesn't belong in the repository. Note that scripts/python/met/point.py has the same name but is entirely different. * Per #2379, update the GHA SonarQube scan to do a single one with Python and C++ combined. The nightly build script is still doing 2 separate scans for now. If this all works well, they could also be combined into a single one. * Per #2379, eliminate MET_CONFIG_OPTIONS from the SonarQube workflow since it doesn't need to be and probably shouldn't be configurable. * Per #2379, trying to copy report-task.txt out of the image * Per #2379, update build_met_sonarqube.sh to check the scan return status * Per #2379, fix bash assignment syntax * Per #2379, remove unused SCRIPT_DIR envvar * Per #2379, switch to a single SonarQube scan for MET's nightly build as well * Feature 2654 ascii2nc polar buoy support (#2846) * Added iabp data type, and modified file_handler to filter based on time range, which was added as a command line option * handle time using input year, hour, min, and doy * cleanup and switch to position day of year for time computations * Added an ascii2nc unit test for iabp data * Added utility scripts to pull iabp data from the web and find files in a time range * Modified iabp_handler to always output a placeholder 'location' observation with value 1 * added description of IABP data python utility scripts * Fixed syntax error * Fixed Another syntax error. * Slight reformat of documentation * Per #2654, update the Makefiles in scripts/python/utility to include all the python scripts that should be installed. * Per #2654, remove unused code from get_iabp_from_web.py that is getting flagged as a bug by SonarQube. * Per #2654, fix typo in docs --------- Co-authored-by: John Halley Gotway Co-authored-by: MET Tools Test Account * Feature #2786 rpss_from_prob (#2861) * Per #2786, small change to a an error message unrelated to this development. * Per #2786, add RPSInfo::set_climo_prob() function to derive the RPS line type from climatology probability bins. And update Ensemble-Stat to call it. * Per #2786, minor change to clarify error log message. * Per #2786, for is_prob = TRUE input, the RPS line type is the only output option. Still need to update docs! * Per #2786, add new call to Ensemble-Stat to test computing RPS from climo probabilities * Per #2786, use name rps_climo_bin_prob to be very explicit. * Per #2786, redefine logic of RPSInfo::set_climo_bin_prob() to match the CPC definition. Note that reliability, resolution, uncertainty, and RPSS based on the sample climatology are all set to bad data. Need to investigate whether they can be computed using these inputs. * Per #2786, remove the requirement that any fcst.prob_cat_thresh thresholds must be defined. If they are defined, pass them through to the FCST_THRESH output column. If not, write NA. Add check to make sure the event occurs in exactly 1 category. * Per #2786, don't enforce fcst.prob_cat_thresh == obs.prob_cat_thresh for probabilistic inputs. And add more is_prob checks so that only the RPS line type can be written when given probabilistic inputs. * updated documentation * Per #2786, call rescale_probability() function to convert from 0-100 probs to 0-1 probs. --------- Co-authored-by: j-opatz * Feature #2862 v12.0.0-beta4 (#2864) * Feature #2379 develop single_sq_project (#2865) * Hotfix to the documentation in the develop branch. Issue #2858 was closed as a duplicate of #2857. I had included it in the MET-12.0.0-beta4 release notes, but the work is not yet actually complete. * Feature 2842 ugrid config (#2852) * #2842 Removed UGrid related setting * #2842 Corrected vertical level for data_plane_array * #2842 Do not allow the time range * #2842 The UGridConfig file can be passed as ugrid_dataset * #2842 Changed -config option to -ugrid_config * #2842 Deleted UGrid configurations * 2842 Fix a compile error when UGrid is disabled * #2842 Cleanup * #2842 Added an unittest point_stat_ugrid_mpas_config * #2842 Added a PointStatConfig without UGrid dataset. * #2842 Corrected ty[po at the variable name * Switched from time_centered to time_instant. I think time_centered is the center of the forecast lead window and time_instant is the time the forecast is valid (end of forecast window). * #2842 Removed ugrid_max_distance_km and unused metadata names * #2842 Restored time variable time_instant for LFric * #2842 Adjust lon between -180 and 180 * #2842 Adjust lon between -180 and 180 * #2842 Adjust lon between -180 and 180 * #2842 Adjusted lon to between -180 to 180 * #2842 Changed variable names * Per #2842, switch from degrees east to west right when the longitudes are read. * #2842, switch from degrees east to west right when the longitudes are read * #2842 Cleanup debug messages --------- Co-authored-by: Howard Soh Co-authored-by: Daniel Adriaansen Co-authored-by: John Halley Gotway * Feature 2753 comp script config (#2868) * set dynamic library file extension to .dylib if running on MacOS and .so otherwise * Added disabling of jasper documentation for compiliation on Hera * Updated * remove extra export of compiler env vars * include full path to log file so it is easier to file the log file to examine when a command fails * send cmake output to a log file * remove redundant semi-colon * use full path to log file so it is easier to examine on failure * use run_cmd to catch if rm command fails * Modifications for compilation on hera, gaea, and orion * Updating * fixed variable name * clean up if/else statements * set TIFF_LIBRARY_RELEASE argument to use full path to dynamic library file to prevent failure installing proj library * set LDFLAGS so that LDFLAGS value set in the user's environment will also be used * Updated based on gaea, orion, and hera installs * Updated * change extension of dynamic library files only if architecture is arm64 because older Macs still use .so * added netcdf library to args to prevent error installing NetCDF-CXX when PROJ has been installed in the same run of the script -- PATH is set in the COMPILE_PROJ if block that causes this flag from being added automatically * clean up how rpath and -L are added to LDFLAGS so that each entry is separate -- prevents errors installing on Mac arm64 because multiple rpath values aren't read using :. Also use MET_PROJLIB * Updated * removed -ltiff from MET libs * only add path to rpath and -L arguments if they are not already included in LDFLAGS * changed from using LIB_TIFF (full path to tiff lib file) to use TIFF_LIB_DIR (dir containing tiff lib file). Added TIFF_INCLUDE_DIR to proj compilation and -DJAS_ENABLE_DOC to jasper compliation taken from @jprestop branch * update comments * ensure all MET_* and MET_*LIB variables are added to the rpath for consistency * remove unnecessary if block and only export LDFLAGS at the end of setting locally * Updated * Added section for adding /lib64 and rearranged placement of ADDTL_DIR * Commenting out the running of the Jasper lib tests * Updating and/or removing files * Updating and/or removing files * Latest udpates which include the addition of the tiff library for proj * Remove commented out line. Co-authored-by: John Halley Gotway * Make indentation consistent. Co-authored-by: John Halley Gotway * Make indentation consistent. Co-authored-by: John Halley Gotway * Make indentation consistent. Co-authored-by: John Halley Gotway * Per 2753, added -lm to configure_lib_args for NetCDF-CXX * Per #2753 updating acorn files * Per #2753, update wcoss2 files * Per #2753, updating acorn file to include MET_PYTHON_EXE * Per #2753, updated files for 12.0.0 for derecho * Per #2753, updated derecho file adding MET_PYTHON_EXE and made corrections * Updating config files * Updating orion files * Updates for gaea's files * Updating gaea modulefile * Removing modulefile for cheyenne * Added MET_PYTHON_EXE * Added MET_PYTHON_EXE to hera too * Adding file for hercules * Removing equals sign from setenv * Adding file for hercules * Updated script to add libjpeg installation for grib2c * Per #2753, Adding file for casper --------- Co-authored-by: George McCabe <23407799+georgemccabe@users.noreply.github.com> Co-authored-by: John Halley Gotway * Feature #2795 level_mismatch_warning (#2873) * Per #2795, move the warning message about level mismatch from the config validation step to when the forecast files are being processed. Only check this when the number of forecast fields is greater than 1, but no longer limit the check to pressure levels only. * Per #2795, add comments * Whitespace * Per #2795, port level mismatch fix over to Ensemble-Stat. Check it for each verification task, but only print it once for each task, rather than once for each task * ensemble member. * Feature #2870 removing_MISSING_warning (#2872) * Per #2870, define utility functions for parsing the file type from a file list and for logging missing files, checking for the MISSING keyword. Also, update Ensemble-Stat and Gen-Ens-Prod to call these functions. * Per #2870, update the gen_ens_prod tests to demonstrate the use of the MISSING keyword for missing files. METplus uses this keyword for Ensemble-Stat and Gen-Ens-Prod. * Feature 2842 ugrid config (#2875) * #2842 Removed UGrid related setting * #2842 Corrected vertical level for data_plane_array * #2842 Do not allow the time range * #2842 The UGridConfig file can be passed as ugrid_dataset * #2842 Changed -config option to -ugrid_config * #2842 Deleted UGrid configurations * 2842 Fix a compile error when UGrid is disabled * #2842 Cleanup * #2842 Added an unittest point_stat_ugrid_mpas_config * #2842 Added a PointStatConfig without UGrid dataset. * #2842 Corrected ty[po at the variable name * Switched from time_centered to time_instant. I think time_centered is the center of the forecast lead window and time_instant is the time the forecast is valid (end of forecast window). * #2842 Removed ugrid_max_distance_km and unused metadata names * #2842 Restored time variable time_instant for LFric * #2842 Adjust lon between -180 and 180 * #2842 Adjust lon between -180 and 180 * #2842 Adjust lon between -180 and 180 * #2842 Adjusted lon to between -180 to 180 * #2842 Changed variable names * Per #2842, switch from degrees east to west right when the longitudes are read. * #2842, switch from degrees east to west right when the longitudes are read * #2842 Cleanup debug messages * #2842 Disabled output types except STAT for sl1l2 * #2842 Disabled output types except STAT for sl1l2 and MPR * #2842 Reduced output files for UGrid --------- Co-authored-by: Howard Soh Co-authored-by: Daniel Adriaansen Co-authored-by: John Halley Gotway * Hotfix to develop branch to remove duplicate test named 'point_stat_ugrid_mpas_config'. That was causing unit_ugrid.xml to fail because it was still looking for .txt output files that are no longer being generated. * Feature 2748 document ugrid (#2869) * Initial documentation of the UGRID capability. * Fixes error in references, adds appendix to index, and adds sub-section for configuration entries and a table for metadata map items. * Corrects LFRic, rewords section on UGRID conventions, updates description of using GridStat, and removes mention of nodes. * Forgot one more mention of UGRID conventions. * Incorporates more suggestions from @willmayfield. * Switches to numerical table reference. * Feature #2781 Convert MET NetCDF point obs to Pandas DataFrame (#2877) * Per #2781, added function to convert MET NetCDF point observation data to pandas so it can be read and modified in a python embedding script. Added example python embedding script * ignore python cache files * fixed function call * reduce cognitive complexity to satisfy SonarQube and add boolean return value to catch if function fails to read data * clean up script and add comments * replace call to object function that doesn't exist, handle exception when file passed to script cannot be read by the NetCDF library * rename example script * add new example script to makefiles * fix logic to build pandas DataFrame to properly get header information from observation header IDs * Per #2781, add unit test to demonstrate python embedding script that reads MET NetCDF point observation file and converts it to a pandas DataFrame * Per #2781, added init function for nc_point_obs to take an input filename. Also raise TypeError exception from nc_point_obs.read_data() if input file cannot be read * call parent class init function to properly initialize nc_point_obs * Feature #2833 pcp_combine_missing (#2886) * Per #2883, add -input_thresh command line option to configure allowable missing input files. * Per #2883, update pcp_combine usage statement. * Per #2883, update existing pcp_combine -derive unit test example by adding 3 new missing file inputs at the beginning, middle, and end of the file list. The first two are ignored since they include the MISSING keyword, but the third without that keyword triggers a warning message as desired. The -input_thresh option is added to only require 70% of the input files be present. This should produce the exact same output data. * Per #2883, update the pcp_combine logic for the sum command to allow missing data files based on the -input_thresh threshold. Add a test in unit_pcp_combine.xml to demonstrate. * Update docs/Users_Guide/reformat_grid.rst Co-authored-by: George McCabe <23407799+georgemccabe@users.noreply.github.com> * Per #2883, update pcp_combine usage statement in the code to be more simliar to the User's Guide. * Per #2883, switch to using derive_file_list_missing as the one containing missing files and recreate derive_file_list as it had existed for the test named pcp_combine_derive_VLD_THRESH. * Per #2883, move initialization inside the same loop to resolve SonarQube issues. * Per #2883, update sum_data_files() to switch from allocating memory to using STL vectors to satisfy SonarQube. * Per #2883, changes to declarations of variables to satisfy SonarQube. * Per #2883, address more SonarQube issues * Per #2883, backing out an unintended change I made to tcrmw_grid.cc. This change belongs on a different branch. * Per #2883, update logic of parse_file_list_type() function to handle python input strings. Also update pcp_combine to parse the type of input files being read and log non-missing python input files expected. --------- Co-authored-by: George McCabe <23407799+georgemccabe@users.noreply.github.com> * Per #2888, update STATAnalysisJob::dump_stat_line() to support dumping stat line types VCNT, RPS, DMAP, and SSIDX. (#2891) * Per #2659, making updates as proposed at the 20240516 MET Eng. Mtg. (#2895) * Feature #2395 TOTAL_DIR (#2892) * Per #2395, remove the n_dir_undef and n_dira_undef variables that are superceded by the new dcount and dacount VL1L2Info members to keep track of the number of valid wind direction vectors. * Per #2395, add TOTAL_DIR columns to the VL1L2, VAL1L2, and VCNT line types and update the header column tables. * Per #2395, update the User's Guide to list the new TOTAL_DIR columns in the VL1L2, VAL1L2, and VCNT line types. * Per #2395, update stat_analysis to parse the new TOTAL_DIR columns and use the values to aggregate results when needed. * Per #2395, for SonarQube change 'const char *' to 'const char * const' to satisfy the finding that 'Global variables should be const.' Should probably switch from 'char char *' to strings eventually. But for now, I'm just making up for some SonarQube technical debt. * Per #2395, fix typo in placement of the DIR_ME column name in the met_header_columns_V12.0.txt file * Per #2395, add 2 new Stat-Analysis jobs to demonstrate the processing of VL1L2 lines. * Per #2395, update logic of is_vector_dir_stat(). Instead of just checking 'DIR_', check 'DIR_ME', 'DIR_MAE', and 'DIR_MSE' to avoid an false positive match for the 'DIR_ERR' column which is computed from the vector partial sums rather than the individual direction differences. * Bugfix #2897 develop python_valid_time (#2899) * Per #2897, fix typos in 2 log messages. Also fix the bug in storing the valid time strings. The time string in vld_array should exactly correspond to the numeric unixtime values in vld_num_array. Therefore they need to be updated inside the same if block. The bug is that we were storing only the unique unixtime values but storing ALL of the valid time string, not just the unique ones. * Per #2897, minor change to formatting of log message * MET #2897, don’t waste time searching, just set the index to n - 1 * Per #2897, remove unused add_prec_point_obs(...) function * Per #2897, update add_point_obs(...) logic for DEBUG(9) to print very detailed log messages about what obs are being rejected and which are being used for each verification task. * Per #2897, refine the 'using' log message to make the wording consistent with the summary rejection reason counts log message * Per #2897, update the User's Guide about -v 9 for Point-Stat --------- Co-authored-by: j-opatz Co-authored-by: MET Tools Test Account * Bugfix 2867 point2grid qc flag (#2890) * #2867 Added compute_adp_qc_flag and adjusted ADP QC flags * #2867 Added point2grid_GOES_16_ADP_Enterprise_high. Changed AOD QC flags to 0,1,2 (was 1,2,3) * #2867 Added get_nc_att_values_ * #2867 Added get_nc_att_values. Added the argument allow_conversion to get_nc_data(netCDF::NcVar *, uchar *data) * #2867 Read the ADP QC flag values and meanings attributes from DQF variable and set the QC high, meduium, low values to support Enterprise algorithm. Adjusted the ADP QC values by using AOD qc values * #2867 Cleanup * #2867 Corrected indent * #2867 Changed log message * #2867 Removed unused argument * #2867 Removed unused argument * Cleanup * #2867 Fix SonarQube findings * #2867 Deleted protected section with no members * #2867 Cleanup * #2867 FIxed SonarQube findings; unused local variables, decalare as const, etc * #2867 MOved include directives to top * #2867 Changed some argumenmt with references to avoid copying objects * #2867 Do not filter by QC flag if -qc is not given * #2867 Use enumj class for GOES QC: HIGH, MEDIUM, and LOW * #2867 Added log message back which were deleted accidently * #2867 Chaned statci const to constexpr * #2867 Initial release. Separated from nc_utils.h * @2867 Added nc_utils_core.h * #2867 Moved some blocks to nc_utils_core.h * #2867 Include nc_utils_core.h * #2867 Added const references * Per #2867, fixing typo in comments. --------- Co-authored-by: Howard Soh Co-authored-by: j-opatz * Hotfix to develop to fix the update_truth.yml workflow logic. This testing workflow run failed (https://github.com/dtcenter/MET/actions/runs/9209471209). Here we switch to a unique update truth branch name to avoid conflicts. * Avoid pushing directly to the develop or main_vX.Y branches since that is not necessary for the automation logic in MET. * #2904 Changed R path to R-4.4.0 (#2905) Co-authored-by: Howard Soh * Feature #2912 pb2nc error (#2914) * Feature 2717 convert unit.pl to unit.py (#2871) * created unit.py module in new internal/test_unit/python directory * added xml parsing to unit.py * added repl_env function * added reading of the remaining xml tags in build_tests function * progress on main function (putting together test commands) * a few more lines in the main function * minor updates * fixed how the test command was being run * added if name/main and command line parsing * fixed handling of no 'env' in cmd_only mode * handle params from xml that have \ after filename without space in between * added logging * added some more pieces to unit * more updates to unit.py, including running checks on output files * bug fixes, improved handling of output file names, improved handling of env vars, improved logging output * fixed how shell commands are run, and other minor fixes * added last bits from the perl script, fixed some bugs * created unit.py module in new internal/test_unit/python directory * added xml parsing to unit.py * added repl_env function * added reading of the remaining xml tags in build_tests function * progress on main function (putting together test commands) * a few more lines in the main function * minor updates * update scripts to call python unit test script instead of the old perl script * fix she-bang line to allow script to be run without python3 before it * add missing test_dir and exit_on_fail tags that are found in the rest of the unit test xml files * fix call to logger.warning * change tags named 'exists' to 'exist' to match the rest of the xml files * added logger to function * removed tab at end of line that was causing output file path to be excluded from the command * fix broken checks for output files * incorporated george's recommended changes * changed default to overwrite logs; allow for more than one xml file to be passed in command --------- Co-authored-by: Natalie babij Co-authored-by: Natalie babij Co-authored-by: Natalie babij Co-authored-by: Natalie Babij Co-authored-by: John Halley Gotway Co-authored-by: George McCabe <23407799+georgemccabe@users.noreply.github.com> Co-authored-by: j-opatz * Bugfix 2867 point2grid qc unittest (#2913) * #2867 Added compute_adp_qc_flag and adjusted ADP QC flags * #2867 Added point2grid_GOES_16_ADP_Enterprise_high. Changed AOD QC flags to 0,1,2 (was 1,2,3) * #2867 Added get_nc_att_values_ * #2867 Added get_nc_att_values. Added the argument allow_conversion to get_nc_data(netCDF::NcVar *, uchar *data) * #2867 Read the ADP QC flag values and meanings attributes from DQF variable and set the QC high, meduium, low values to support Enterprise algorithm. Adjusted the ADP QC values by using AOD qc values * #2867 Cleanup * #2867 Corrected indent * #2867 Changed log message * #2867 Removed unused argument * #2867 Removed unused argument * Cleanup * #2867 Fix SonarQube findings * #2867 Deleted protected section with no members * #2867 Cleanup * #2867 FIxed SonarQube findings; unused local variables, decalare as const, etc * #2867 MOved include directives to top * #2867 Changed some argumenmt with references to avoid copying objects * #2867 Do not filter by QC flag if -qc is not given * #2867 Use enumj class for GOES QC: HIGH, MEDIUM, and LOW * #2867 Added log message back which were deleted accidently * #2867 Chaned statci const to constexpr * #2867 Initial release. Separated from nc_utils.h * @2867 Added nc_utils_core.h * #2867 Moved some blocks to nc_utils_core.h * #2867 Include nc_utils_core.h * #2867 Added const references * #2867 Some 'static const' were chnaged to constexpr * #2867 Changed -qc options (1,2,3 to 0,1 - high & medium) for AOD * #2867 Merged develop branch * #2867 Corrected the unit test name --------- Co-authored-by: Howard Soh * Feature #2911 tc_stat_set_hdr (#2916) * Per #2911, no real changes for Stat-Analysis. Just changing order of variables for consistency. * Per #2911, add StatHdrColumns::apply_set_hdr_opts(...) function to be used by TC-Stat. * Per #2911, move ByColumn to the TCStatJob base class and add HdrName and HdrValue to support the -set_hdr job command. * Per #2911, update GSI tools to call the newly added StatHdrColumns::apply_set_hdr_opts(...) function. * Per #2911, update logic of Stat-Analysis for consistency to make use of common apply_set_hdr_opts() function. * Per #2911, add DataLine::set_item() function to support -set_hdr options. * Per #2911, just update contents of error message * Per #2911, add TCStatLine member functions for has() and get_offset(). * Per #2911, update tc_stat to support applying -set_hdr to TC-Stat filter jobs. * Per #2911, revise TC-Stat config files to exercise the -set_hdr job command option * Per #2911, update TC-Stat documentation to mention the -set_hdr job command option * Per #2911, add note * Per #2911, as recommended by SonarQube, make some of these member functions const. * Bugfix #2856 develop ens_climo (#2918) * Per #2856, port over fixes from main_v11.1 to develop. * Per #2856, correct conditionals in set_job_controls.sh and tweak existing Ensemble-Stat configuration file to exercise the logic that's being impacted here. * Bugfix #2841 develop tang_rad_winds (#2921) * Per #2841, port over fixes from bugfix_2841_main_v11.1_tang_rad_winds for the develop branch * Per #2841, clarify in the docs that azimuths are defined in degrees counter-clockwise from due east. * Per #2841, just updating with output from enum_to_string. * Per #2841, tweak the documentation. * Per #2841, correct the location of using namespace lines. * Per #2841, update compute_tc_diag.py to no longer skip writing the radial and tangential wind diagnostics. * Per #2841, update compute_tc_diag.py to no longer skip writing radial and tangential wind diagnostics. * Revert "Per #2841, update compute_tc_diag.py to no longer skip writing radial and tangential wind diagnostics." This reverts commit f097345bedcfcca663e8fb4322eed5b5e00e19fd. * Revert "Per #2841, update compute_tc_diag.py to no longer skip writing the radial and tangential wind diagnostics." This reverts commit c0402151b038c59efab99c060cc5c390edf002f6. * Per #2841, update comp_dir.sh logic to include .dat in the files that are diffed * Replace tab with spaces * Per #2841, correct the units for the azimuth netcdf output variable * Per #2841, reverse the x dimension of the rotated latlon grid to effectively switch from counterclockwise rotation to clockwise. --------- Co-authored-by: MET Tools Test Account * Feature #2601 seeps climo config (#2927) * #2601 Added seeps_grid_climo_name and seeps_point_climo_name * #2601 Added seeps_grid_climo_name * #2601 Removed SEEPS settings * #2601 Initial release * #2601 Changed to set the SEEPS climo by using the configuration * #2601 Removed SEESP settings at PointStatConfig_APCP and use PointStatConfig_SEEPS for SEEPSm testing * #2601 Updated descryption for seeps_grid_climo_name * #2601 Added a argument for the SEEPS clomo file * #2601 Added conf_key_seeps_grid_climo_name and conf_key_seeps_point_climo_name * #2601 Support the climo filename from the configuration * #2601 Corrected key for climo name * Removing duplicate word --------- Co-authored-by: Howard Soh Co-authored-by: Julie Prestopnik * Feature 2673 sonarqube beta5 redundant parentheses (#2930) * #2673 Removed redundant_parentheses * #2673 Removed redundant_parentheses * #2673 Removed redundant parentheses * #2673 Removed redundant parentheses --------- Co-authored-by: Howard Soh * Fix release checksum action (#2929) * Feature 2857 tripolar coordinates (#2928) * #2857 Added MetNcCFDataFile::build_grid_from_lat_lon_vars * #2857 Added NcCfFile::build_grid_from_lat_lon_vars * #2857 Check the coordinates attribute to find latitude, longitude, and time variables * #2857 Get the lat/lon variables from coordinates attribute if exists * #2857 Added two constants * #2857 Deleted debug messages * #2857 Added lat_vname and lon_vname for var_name_map * #2857 Added two unit tests: point2grid_sea_ice_tripolar and point2grid_sea_ice_tripolar_config * #2857 Initial release * #2857 Correct dictinary to get file_type * #2857 DO not check the time variable for point2grid * #2857 Added point2grid_tripolar_rtofs --------- Co-authored-by: Howard Soh * Feature 2932 v12.0.0-beta5 (#2933) * Per #2932, updating version and release notes * Per #2932, updating date on release notes * Per #2932, fixed formatting and links * Update release-notes.rst * Update release-notes.rst Removing inline backticks since they do not format the way I expected, especially when put inside bolded release notes. --------- Co-authored-by: John Halley Gotway * Feature fix release notes (#2934) * Fixing up release notes * Update release-notes.rst --------- Co-authored-by: John Halley Gotway * Per dtcenter/METplus#2643 discussion, add more detail about the budget interpolation method. * Feature #2924 fcst climo, PR 1 of 2 (#2939) * Per #2924, Update the MPR and ORANK output line types to just write duplicate existing climo values, update the header tables and MPR/ORANK documentation tables. * Per #2924, update get_n_orank_columns() logic * Per #2924, update the Stat-Analysis parsing logic to parse the new MPR and ORANK climatology columns. * Per #2924, making some changes to the vx_statistics library to store climo data... but more work to come. Committing this first set of changes that are incomplete but do compile. * Per #2924, this big set of changes does compile but make test produces a segfault for ensemble-stat * Per #2924, fix return value for is_keeper_obs() * Per #2924, move fcst_info/obs_info into the VxPairBase pointer. * Per #2924, update Ensemble-Stat to set the VxPairBase::fcst_info pointer * Per #2924 udpate handling of fcst_info and obs_info pointers in Ensemble-Stat * Per #2924, update the GSI tools to handle the new fcst climo columns. * Per #2924, add backward compatibility logic so that when old climo column names are requested, the new ones are used. * Per #2924, print a DEBUG(2) log message if old column names are used. * Per #2924, switch the unit tests to reference the updated MPR column names rather than the old ones. * Per #2924, working progress. Not fully compiling yet * Per #2924, another round of changes. Removing MPR:FCST_CLIMO_CDF output column. This compiles but not sure if it actually runs yet * Per #2924, work in progress * Per #2924, work in progress. Almost compiling again. * Per #2924, get it compiling * Per #2924, add back in support for SCP and CDP which are interpreted as SOCP and OCDP, resp * Per #2924, update docs about SCP and CDP threshold types * Per #2924, minor whitespace changes * Per #2924, fix an uninitialized pointer bug by defining/calling SeepsClimoGrid::init_from_scratch() member function. The constructor had been calling clear() to delete pointers that weren't properly initialized to nullptr. Also, simplify some map processing logic. * Per #2924, rename SeepsAggScore from seeps to seeps_agg for clarity and to avoid conflicts in member function implementations. * Per #2924, fix seeps compilation error in Point-Stat * Per #2924, fix bug in the boolean logic for handling the do_climo_cdp NetCDF output option. * Per #2924, add missing exit statement. * Per #2924, tweak threshold.h * Per #2924, define one perc_thresh_info entry for each enumerated PercThreshType value * Per #2924, simplify the logic for handling percentile threshold types and print a log message once when the old versions are still used. * Per #2924, update the string comparison return value logic * Per #2924, fix the perc thresh string parsing logic by calling ConcatString::startswith() * Per #2924, switch all instances of CDP to OCDP. Gen-Ens-Prod was writing NetCDF files with OCDP in the output variable names, but Grid-Stat was requesting that the wrong variable name be read. So the unit tests failed. * Per #2924, add more doc details * Per #2924, update default config file to indicate when climo_mean and climo_stdev can be set seperately in the fcst and obs dictionaries. * Per #2924, update the MET tools to parse climo_mean and climo_stdev separately from the fcst and obs dictionaries. * Per #2924, backing out new/modified columns to minimize reg test diffs * Per #2924, one more section to be commented out later. * Per #2924, replace several calls to strncmp() with ConcatString::startswith() to simplify the code * Per #2924, strip out some more references to OBS_CLIMO_... in the unit tests. * Per #2924, delete accidental file * Per #2924 fix broken XML comments * Per #2924, fix comments * Per #2924, address SonarQube findings * Per #2924, tweak a Point-Stat and Grid-Stat unit test config file to make the output more comparable to develop. * Per #2924, fix bug in the logic of PairDataPoint and PairDataEnsemble, when looping over the 3-dim array do not return when checking the climo and fcst values. Instead we need to continue to the next loop iteration. * Per #2924, address more SonarQube code smells to reduce the overall number in MET for this PR. * Per #2924, correct the logic for parsing climo data from MPR lines. * Per #2924, cleanup grid_stat.cc source code by making calls to DataPlane::is_empty() and Grid::nxy(). * Per #2924, remove unneeded ==0 * Hotfix to the develop branch for a copy/paste bug introduced by PR #2939 * Feature #2924 sal1l2_mae, PR 3 of 3 (#2943) * Per #2924, track SL1L2 and SAL1L2 MAE scores with separate variables since they are no longer the same value. I renamed the existing 'mae' as 'smae' and added a new 'samae' variable. Renaming the existing lets me use the compiler help find all references to it throughout the code. * Per #2924, update the User's Guide climatology details and equations. * Per #2924, some changes to aggr_stat_line.cc and series_analysis.cc to satisfy some SonarQube code smells. * Update develop to clarify masking poly options based on METplus Discussion dtcenter/METplus#2650 * Remove two semi-colons that are not actually necessary to avoid confusion. * Per dtcenter/METplus#2653 discussion, update the MTD usage statement to clarify that data specified in the fcst dictionary is read from the -single input files. * Feature #2924 fcst climo, PR 2 of 3 (#2942) * Per #2924, Update the MPR and ORANK output line types to just write duplicate existing climo values, update the header tables and MPR/ORANK documentation tables. * Per #2924, update get_n_orank_columns() logic * Per #2924, update the Stat-Analysis parsing logic to parse the new MPR and ORANK climatology columns. * Per #2924, making some changes to the vx_statistics library to store climo data... but more work to come. Committing this first set of changes that are incomplete but do compile. * Per #2924, this big set of changes does compile but make test produces a segfault for ensemble-stat * Per #2924, fix return value for is_keeper_obs() * Per #2924, move fcst_info/obs_info into the VxPairBase pointer. * Per #2924, update Ensemble-Stat to set the VxPairBase::fcst_info pointer * Per #2924 udpate handling of fcst_info and obs_info pointers in Ensemble-Stat * Per #2924, update the GSI tools to handle the new fcst climo columns. * Per #2924, add backward compatibility logic so that when old climo column names are requested, the new ones are used. * Per #2924, print a DEBUG(2) log message if old column names are used. * Per #2924, switch the unit tests to reference the updated MPR column names rather than the old ones. * Per #2924, working progress. Not fully compiling yet * Per #2924, another round of changes. Removing MPR:FCST_CLIMO_CDF output column. This compiles but not sure if it actually runs yet * Per #2924, work in progress * Per #2924, work in progress. Almost compiling again. * Per #2924, get it compiling * Per #2924, add back in support for SCP and CDP which are interpreted as SOCP and OCDP, resp * Per #2924, update docs about SCP and CDP threshold types * Per #2924, minor whitespace changes * Per #2924, fix an uninitialized pointer bug by defining/calling SeepsClimoGrid::init_from_scratch() member function. The constructor had been calling clear() to delete pointers that weren't properly initialized to nullptr. Also, simplify some map processing logic. * Per #2924, rename SeepsAggScore from seeps to seeps_agg for clarity and to avoid conflicts in member function implementations. * Per #2924, fix seeps compilation error in Point-Stat * Per #2924, fix bug in the boolean logic for handling the do_climo_cdp NetCDF output option. * Per #2924, add missing exit statement. * Per #2924, tweak threshold.h * Per #2924, define one perc_thresh_info entry for each enumerated PercThreshType value * Per #2924, simplify the logic for handling percentile threshold types and print a log message once when the old versions are still used. * Per #2924, update the string comparison return value logic * Per #2924, fix the perc thresh string parsing logic by calling ConcatString::startswith() * Per #2924, switch all instances of CDP to OCDP. Gen-Ens-Prod was writing NetCDF files with OCDP in the output variable names, but Grid-Stat was requesting that the wrong variable name be read. So the unit tests failed. * Per #2924, add more doc details * Per #2924, update default config file to indicate when climo_mean and climo_stdev can be set seperately in the fcst and obs dictionaries. * Per #2924, update the MET tools to parse climo_mean and climo_stdev separately from the fcst and obs dictionaries. * Per #2924, backing out new/modified columns to minimize reg test diffs * Per #2924, one more section to be commented out later. * Per #2924, replace several calls to strncmp() with ConcatString::startswith() to simplify the code * Per #2924, strip out some more references to OBS_CLIMO_... in the unit tests. * Per #2924, delete accidental file * Per #2924 fix broken XML comments * Per #2924, fix comments * Per #2924, address SonarQube findings * Per #2924, tweak a Point-Stat and Grid-Stat unit test config file to make the output more comparable to develop. * Per #2924, fix bug in the logic of PairDataPoint and PairDataEnsemble, when looping over the 3-dim array do not return when checking the climo and fcst values. Instead we need to continue to the next loop iteration. * Per #2924, address more SonarQube code smells to reduce the overall number in MET for this PR. * Per #2924, correct the logic for parsing climo data from MPR lines. * Per #2924, update MPR and ORANK line types to update/add FCST/OBS_CLIMO_MEAN/STDEV/CDF columns. * Per #2924, cleanup grid_stat.cc source code by making calls to DataPlane::is_empty() and Grid::nxy(). * Per #2924, remove unneeded ==0 * Per #2924, working on PR2. * Per #2924, update User's Guide with notional example of specifying climo_mean and climo_stdev separately in the fcst and obs dicts. * Per #2924, adding a new unit test. It does NOT yet run as expected. Will debug on seneca * Per #2924, pass the description string to the read_climo_data_plane*() function to provide better log messages * Per #2924, more work on consistent log messages * Per #2924, tweak the configuration to define both field, climo_mean, and climo_stdev in both the fcst and obs dictionaries * Per #2924, tweak the unit_climatology_mixed.xml test * Per #2924, only whitespace changes. * Per #2924, missed swapping MET #2924 changes in 3 test files * Per #2924, delete accidentally committed file * Per #2924, delete accidentally committed files * Per #2924, add support for GRIB1 time range indicator value of 123 used for the corresponding METplus Use Case. Note that there are 22 other TRI values not currently supported. * Adds caveat regarding longitudes appearing in DEBUG statements with a… (#2947) * Adds caveat regarding longitudes appearing in DEBUG statements with a different sign to the FAQ. * Update appendixA.rst Missing paren * Create install_met_env.cactus * Adding special script for installing beta5 on wcoss2 * Modifying script, including updates to eckit and atlas * Corrected version of bufr being used * Feature #2938 pb2nc_center_time (#2954) * Per #2938, define CRC_Array::add_uniq(...) member function which is now used in PB2NC * Per #2938, replace n_elements() with n() to make the code more concise. Refine log/warning message when multiple message center times are encountered. * Feature #1371 series_analysis (#2951) * Per #1371, add -input command line argument and add support for ALL for the CTC, MCTC, SL1L2, and PCT line types. * Per #1371, rename the -input command line option as -aggregate instead * Per #1371, work in progress * Per #1371, just comments * Per #1371, working on aggregating CTC counts * Per #1371, work in progress * Per #1371, update timing info using time stamps in the aggr file * Per #1371, close the aggregate data file * Per #1371, define set_event() and set_nonevent() member functions * Per #1371, add logic to aggregate MCTC and PCT counts * Merging changes from develop * Per #1371, work in progress aggregating all the line statistics types. Still have several issues to address * Per #1371, switch to using get_stat() functions * Per #1371, work in progress. More consolidation * Per #1371, correct expected output file name * Per #1371, consistent regridding log messages and fix the Series-Analysis PairDataPoint object handling logic. * Per #1371, check the return status when opening the aggregate file. * Per #1371, fix prc/pjc typo * Per #1371, fix the series_analysis PCT aggregation logic and add a test to unit_series_analysis.xml to demonstrate. * Per #1371, resolve a few SonarQube findings * Per #1371, make use of range-based for loop, as recommeded by SonarQube * Per #1371, update series-analysis to apply the valid data threshold properly using the old aggregate data and the new pair data. * Per #1371, update series_analysis to buffer data and write it all at once instead of storing data value by value for each point. * Per #1371, add useful error message when required aggregation variables are not present in the input -aggr file. * Per #1371, print a Debug(2) message listing the aggregation fields being read. * Per #1371, correct operator+= logic in met_stats.cc for SL1L2Info, VL1L2Info, and NBRCNTInfo. The metadata settings, like fthresh and othresh, were not being passed to the output. * Per #1371, the DataPlane for the computed statistics should be initialized to a field of bad data values rather than the default value of 0. Otherwise, 0's are reported for stats a grid points with no data when they should really be reported as bad data! * Per #1371, update logic of the compute_cntinfo() function so that CNT statistics can be derived from a single SL1L2Info object containing both scalar and scalar anomaly partial sums. These changes enable CNT:ANOM_CORR to be aggregated in the Series-Analysis tool. * Per #1371, fix logic of climo log message. * Per #1371, this is actually related to MET #2924. In compute_pctinfo() used obs climo data first, if provided. And if not, use fcst climo data. * Per #1371, fix indexing bug (+i instead of +1) when check the valid data count. Also update the logic of read_aggr_total() to return a count of 0 for bad data. * Per #1371, add logic to aggregate the PSTD BRIERCL and BSS statistics in the do_climo_brier() function. Tested manually to confirm that it works. * Per #1371, switch to using string literals to satisfy SonarQube * Per #1371, update series_analysis tests in unit_climatology_1.0deg.xml to demonstrate aggregating climo-based stats. * Per #1371, remove extra comment * Per #1371, skip writing the PCT THRESH_i columns to the Series-Analysis output since they are not used * Per #1371, fix the R string literals to remove \t and \n escape sequences. * Per #1371, update the read_aggr_data_plane() suggestion strings. * Per #1371, ignore unneeded PCT 'THRESH_' variables both when reading and writing ALL PCT columns. * Per #1371, update the test named series_analysis_AGGR_CMD_LINE to include data for the F42 lead time that had previously been included for the same run in the develop branch. Note however that the timestamps in the output file for the develop branch (2012040900_to_2012041100) were wrong and have been corrected here (2012040900_to_2012041018) to match the actual data. * Per #1371, update the -aggr note to warn users about slow runtimes * Feature 2948 cxx17 (#2953) * Per #2948, updating versions of ecbuild, eckit, and atlas * Per #2948, Adding MET_CXX_STANDARD * Per #2948, updated wording for MET_CXX_STANDARD description * Per #2948, updating script to work with two versions of ecbuild, eckit, and atlas * Per #2948, without this change, there are compilation problems if the user wants to compile wihtout python * Per #2948, fixing logic for MET_CXX_STANDARD * Per #2928, adding missing end bracket * Per #2948, fixed the logic for compiling versions of ecbuild, eckit, and atlas * Per 948, fixed syntax for setting CXXFLAGS * Per #2948, adding new Makefile.in files and configure and changing METbaseimage 3.2 to 3.3. * Per #2948, updating version of met base tag from 3.2 to 3.3 * Per #2948, adding --enable-all MET_CXX_STANDARD=11 job * Update compilation_options.yml * Per #2948, added a job10 for MET_CXX_STANDARD=14 * Per #2948, added brief documentation for the MET_CXX_STANDARD option --------- Co-authored-by: Julie Prestopnik Co-authored-by: John Halley Gotway * Feature 1729 set attr grid (#2955) * #1729 Allow to change to differnt grid size if the raw size is 0 * Added build_grid_by_grid_string and build_grid_by_grid_string * #1729 Calls build_grid_by_grid_string * #1729 Added set_attr_grid at the -field option * #1729 Set obs_type to TYPE_NCCF if the file_type is given at the config file * #1729 Support set_sttr_grid and changed Error messages to Warning * #1729 FIxed SonmarQube findings * #1729 Initial release for unit test * #1729 Added update_missing_values * #1729 Deleted a shadowed local variable * #2673 Added more is_eq * #2673 Added get_exe_duration * 2673 Reducded nested statements * 2673 Fixed SonarGube findings * 2673 Fixed SonarQube findings * 2673 Fixed SonarQube findings * #1729 Added aan unittest plot_data_plane_set_attr_grid * #1729 Added aan unittest point2grid_cice_set_attr_grid * #1729 Added changed back the verbose level * #1729 Corrected typo --------- Co-authored-by: Howard Soh * Bugfix #2958 develop BAGSS SEDI CI (#2959) * Bugfix 2936 point2grid gfs (#2964) * #2936 Support 1D lat/lon values * #2936 Initial release * #2936 Cast the data type to avoid a compile warning * #2936 Added an unittest point2grid_gfs_1D_lat_lon --------- Co-authored-by: Howard Soh * Bugfix 2968 point2grid set attr grid (#2969) * #2968 Corrected set_attr_grid for point2grid_cice_set_attr_grid * #2968 Compare the DataPlane size and the variable data size * #2968 nx and ny are not ignored with set_attr_grid * #2968 Compare the DataPlane size and the variable data size --------- Co-authored-by: Howard Soh * Feature 2937 update unit (#2944) * added single quotes around env var/val pairs in export statements in cmd only mode * updated logic in unit() to check exec return value against expected return value; created TEST xml file to test this feature * deleted TEST_ xml, added test with retval 1 to unit_ascii2nc --------- Co-authored-by: Natalie Babij * Feature #2887 categorical weights PR 1 of 2 (#2967) * Per #2887, update NumArray::vals() to return a reference to the vector rather a pointer to doubles. * Per #2887, switch over the whole ContingencyTable class heirarchy from storing integer counts to storing double-precision weights. * Add ContingencyTable::is_integer() member function to check whether the table contains all integers * Per #2887, update parse_stat_line.cc to get it to compile after changing PCT to store thresholds in a std::vector. * Per #2887, update PCTInfo::clear() logic. * Per #2887, update ctc_by_row() logic to create reproducible results with the develop branch. * Per #2887, update logic of define_prob_bins() to add a final >=1.0 threshold if needed. While ==0.1 works fine, I found that ==0.05 did not because the last >=1.0 threshold was missing likely do to floating point precision issues. This change should fix that problem. * Per #2887, update roc_auc() function to match the develop branch * Per #2887, fix bug if computation of far() * Per #2887, replaced all ==0 integer equality checks with calls to is_eq() instead and fix a couple of equations to snuff out diffs in some CTS statistics. * Per #2887, address some of the 34 SonarQube code smells flagged for this PR. Note that the compute_ci.h/.cc changes are necessary and good since we should be computing CI's using doubles instead of integer counts. * Per #2887, update run_sonarqube.sh to specify the target CXX standard as 11. The hope is that that will limit the findings to only those features available in the C++11 standard. * Per #2887, update to SonarQube version 6.1.0.4477 released on 6/27/2024. * Per #2887, updating build_met_sonarqube.sh to specify --std=c++11 since c++17 is used by default * Hotfix to develop to fix a bug introduced for MET #2887. Refine the define_prob_bins() utility function so that ==n probability thresholds result in the correct number of probability thresholds. We were adding an unncessary 10-th bin (from 1.07143 to 1.0) for the ==7 probability threshold type. * Fix typo in tc-pairs.rst * Update build_docker_and_trigger_metplus.yml The docs directory was moved up to the top-level of the repository but this workflow was not updated. Changing the ignore setting so that doc-only updates do not trigger the full METplus testing workflow. * Feature 2023 remove double quotes around keywords (#2974) * testing AREA and AUTO changes * Keywords B thru L * thru R * adding quotes back in for lower case items * S thru the end of the document * Removing double quotes around 3 key words * Per #2023, adding a label name for the Attributes section * Per #2023, adding an internal link for the MODE tool Attributes section. * Adding quotes around Valid basins entries * more double quote updates * more complex updates with Julie P help * removing double quotes * fixing typos * removing double quotes * unbolding SURFACE and putting it in double quotes * fixing grammar * grammar * fixing typo * fixing typo --------- Co-authored-by: Julie Prestopnik * Feature #2924 parse_config (#2963) * Per #2924, remove GenEnsProd config file comment about parsing desc separately from each obs.field entry because the obs dictionary does not exist in the GenEnsProd config file. * Per #2924, update list of needed config entry names * Per #2924, remove const from the parent() member function so that we can perform lookups for the parent. * Per #2924, update the signature for and logic of the utility functions that retrieve the climatology data. Rather than requiring all the climo_mean and climo_stdev dictionary entries to be defined at the same config file context level, parse each one individually. This enables the METplus wrappers to only partially override this dictionary and still rely on the default values provided in MET's default configuration files. * Per #2924, update all calls to the climatology utility functions based on the new function signature. Also update the tools to check the number of climo fields separately for the forecast and observation climos. * Per #2924, update the parsing logic for the climatology regrid dictionary. Use config.fcst.climo_mean.regrid first, config.fcst.regrid second, and config.climo_mean.regrid third. Notably, DO NOT use config.regrid. This is definitely the problem with having regrid specified at mutliple config file context levels. It makes the logic for which to use when very messy. * Per #2924, forgot to add an else to print an error * Per #2924, remove extraneous semicolon * Per #2924, move 'fcst.regrid' into 'fcst.climo_mean.regrid'. Defining the climatology regridding logic inside fcst is problematic because it applies to the forecast data as well and you end up with the verification grid being undefined. So the climo regridding logic must be defined in 'climo_mean.regrid' either within the 'fcst' and 'obs' dictionaries or at the top-level config context. * Per #2924, based on PR feedback from @georgemccabe, add the Upper_Left, Upper_Right, Lower_Right, and Lower_Left interpolation methods to the list of valid options for regridding, as already indicated in the MET User's Guide. * Per #2924, update the logic of parse_conf_regrid() to (hopefully) make it work the way @georgemccabe expects it to. It now uses pointers to both the primary and default dictionaries and parses each entry individually. * Per #2924, need to check for non-null pointer before using it * Per #2924, revise the climo_name dictionary lookup logic when parsing the regrid dictionary. * Per #2924, update logic for handling RegridInfo * Per #2924, remove the default regridding information from the 'Searching' log message to avoid confusion. --------- Co-authored-by: MET Tools Test Account * Feature #2924 parse_config PR 2 (#2975) * Per #2924, remove GenEnsProd config file comment about parsing desc separately from each obs.field entry because the obs dictionary does not exist in the GenEnsProd config file. * Per #2924, update list of needed config entry names * Per #2924, remove const from the parent() member function so that we can perform lookups for the parent. * Per #2924, update the signature for and logic of the utility functions that retrieve the climatology data. Rather than requiring all the climo_mean and climo_stdev dictionary entries to be defined at the same config file context level, parse each one individually. This enables the METplus wrappers to only partially override this dictionary and still rely on the default values provided in MET's default configuration files. * Per #2924, update all calls to the climatology utility functions based on the new function signature. Also update the tools to check the number of climo fields separately for the forecast and observation climos. * Per #2924, update the parsing logic for the climatology regrid dictionary. Use config.fcst.climo_mean.regrid first, config.fcst.regrid second, and config.climo_mean.regrid third. Notably, DO NOT use config.regrid. This is definitely the problem with having regrid specified at mutliple config file context levels. It makes the logic for which to use when very messy. * Per #2924, forgot to add an else to print an error * Per #2924, remove extraneous semicolon * Per #2924, move 'fcst.regrid' into 'fcst.climo_mean.regrid'. Defining the climatology regridding logic inside fcst is problematic because it applies to the forecast data as well and you end up with the verification grid being undefined. So the climo regridding logic must be defined in 'climo_mean.regrid' either within the 'fcst' and 'obs' dictionaries or at the top-level config context. * Per #2924, based on PR feedback from @georgemccabe, add the Upper_Left, Upper_Right, Lower_Right, and Lower_Left interpolation methods to the list of valid options for regridding, as already indicated in the MET User's Guide. * Per #2924, update the logic of parse_conf_regrid() to (hopefully) make it work the way @georgemccabe expects it to. It now uses pointers to both the primary and default dictionaries and parses each entry individually. * Per #2924, need to check for non-null pointer before using it * Per #2924, revise the climo_name dictionary lookup logic when parsing the regrid dictionary. * Per #2924, update logic for handling RegridInfo * Per #2924, remove the default regridding information from the 'Searching' log message to avoid confusion. * Per #2924, escape sequences, like \n, cannot be used inside R-string literals. * Per #2924, update the logic of check_climo_n_vx() * Per #2924, revise logic in read_climo_data_plane_array(). Check the number of climo fields provided. If there's 0, just return since no data has been requested. If there's 1, use it regardless of the number of input fields. If there's more than 1, just use the requested i_vx index value. * Per #2924, update Series-Analysis to set both i_fcst and i_obs when looping over the series entries. * Per #2924, no real change. Just whitespace. * Unrelated to #2924, superficial changes to formatting of method_name strings for consistency. * Per #2924, add a new series_analysis test that ERRORS OUT prior to this PR but works after the changes in this PR. --------- Co-authored-by: MET Tools Test Account * Feature 2949 cxx11 doc (#2973) * Per #2949, updating installation instructions * Per #2949, adding missing colon from note directive * Per #2949, third attempt to get the new note to show up * Per #2949, modifying text and format * Per #2949, removing images in favor of code blocks for easier modification * Per #2949, modified wording for clarity * Per #2929, corrected typo * Update installation.rst No changes to content, only whitespace for consistency, mostly removing tabs. * Update docs/Users_Guide/installation.rst Co-authored-by: John Halley Gotway * Per #2949, testing variable replacement, expect failures * Per #2949, reverting to orignal state after testing --------- Co-authored-by: John Halley Gotway * Bugfix #2979 develop MTD Grid (#2981) * Per #2979, remove nc_grid.h/.cc and replace it with calls to the read_netcdf_grid(...) and write_netcdf_proj(...) library utility functions. Note that these changes do compile but I haven't tested whether they actually fix the underlying problem. Also note that nc_utils_local.h/.cc can also likely be replaced with calls to common library functions. * Per #2979, remove references to nc_grid.o from the MTD test code. * Per #2979, insert a newline in unit.py output between the env vars and the command. * Per #2979, insert a newline in unit.py output between the env vars and the command. * Per #2979, the write_netcdf_proj(...) utility function adds the lat and lon dimensions. Update mtd to NOT define those dimensions prior to calling write_netcdf_proj(...). * Per #2979, minor changes to is_eq() calls to fix compiler warning messages * Per #2979, for the develop branch, also replace nc_utils_local.h/.cc with calls to common library code. Also remove commented out code. * Per #2979, delete commented out code and make error/warning message formatting consistent. * Fixes for SonarQube --------- Co-authored-by: MET Tools Test Account --------- Co-authored-by: Howard Soh Co-authored-by: John Halley Gotway Co-authored-by: Howard Soh Co-authored-by: MET Tools Test Account Co-authored-by: davidalbo Co-authored-by: j-opatz Co-authored-by: Daniel Adriaansen Co-authored-by: Julie Prestopnik Co-authored-by: George McCabe <23407799+georgemccabe@users.noreply.github.com> Co-authored-by: natalieb-noaa <146213121+natalieb-noaa@users.noreply.github.com> Co-authored-by: Natalie babij Co-authored-by: Natalie babij Co-authored-by: Natalie babij Co-authored-by: Natalie Babij Co-authored-by: Julie Prestopnik Co-authored-by: lisagoodrich <33230218+lisagoodrich@users.noreply.github.com> Co-authored-by: metplus-bot <97135045+metplus-bot@users.noreply.github.com> --- docs/Users_Guide/figure/installation_dir.png | Bin 90216 -> 0 bytes .../figure/installation_dir_after.png | Bin 27860 -> 0 bytes docs/Users_Guide/installation.rst | 73 +- internal/test_unit/python/unit.py | 2 +- .../tools/other/mode_time_domain/Makefile.am | 2 - .../tools/other/mode_time_domain/Makefile.in | 4 - src/basic/vx_math/is_bad_data.h | 8 + src/libcode/vx_statistics/compute_stats.cc | 2 +- src/tools/other/mode_time_domain/2d_att.cc | 17 +- .../other/mode_time_domain/2d_att_array.cc | 40 +- .../other/mode_time_domain/2d_moments.cc | 12 +- src/tools/other/mode_time_domain/2d_moments.h | 4 - src/tools/other/mode_time_domain/3d_att.cc | 221 +----- src/tools/other/mode_time_domain/3d_att.h | 6 - .../mode_time_domain/3d_att_pair_array.cc | 30 +- .../mode_time_domain/3d_att_pair_array.h | 1 - .../mode_time_domain/3d_att_single_array.cc | 14 +- src/tools/other/mode_time_domain/3d_conv.cc | 52 +- .../other/mode_time_domain/3d_moments.cc | 13 +- src/tools/other/mode_time_domain/3d_moments.h | 3 - src/tools/other/mode_time_domain/Makefile.am | 2 - src/tools/other/mode_time_domain/Makefile.in | 40 +- src/tools/other/mode_time_domain/fo_graph.cc | 33 +- src/tools/other/mode_time_domain/fo_graph.h | 7 - src/tools/other/mode_time_domain/fo_node.cc | 2 - .../other/mode_time_domain/fo_node_array.cc | 13 +- .../other/mode_time_domain/interest_calc.cc | 4 - .../other/mode_time_domain/interest_calc.h | 1 - src/tools/other/mode_time_domain/mm_engine.cc | 5 - src/tools/other/mode_time_domain/mtd.cc | 39 - .../other/mode_time_domain/mtd_config_info.cc | 174 +---- .../other/mode_time_domain/mtd_file_base.cc | 66 +- .../other/mode_time_domain/mtd_file_float.cc | 118 +--- .../other/mode_time_domain/mtd_file_int.cc | 195 ++--- .../other/mode_time_domain/mtd_nc_defs.h | 73 +- .../other/mode_time_domain/mtd_nc_output.cc | 32 +- .../other/mode_time_domain/mtd_nc_output.h | 2 - .../other/mode_time_domain/mtd_partition.cc | 64 +- .../other/mode_time_domain/mtd_read_data.cc | 25 +- .../other/mode_time_domain/mtd_txt_output.cc | 30 +- .../mode_time_domain/mtdfiletype_to_string.cc | 1 + src/tools/other/mode_time_domain/nc_grid.cc | 665 ------------------ src/tools/other/mode_time_domain/nc_grid.h | 41 -- .../other/mode_time_domain/nc_utils_local.cc | 191 ----- .../other/mode_time_domain/nc_utils_local.h | 50 -- 45 files changed, 353 insertions(+), 2024 deletions(-) delete mode 100644 docs/Users_Guide/figure/installation_dir.png delete mode 100644 docs/Users_Guide/figure/installation_dir_after.png delete mode 100644 src/tools/other/mode_time_domain/nc_grid.cc delete mode 100644 src/tools/other/mode_time_domain/nc_grid.h delete mode 100644 src/tools/other/mode_time_domain/nc_utils_local.cc delete mode 100644 src/tools/other/mode_time_domain/nc_utils_local.h diff --git a/docs/Users_Guide/figure/installation_dir.png b/docs/Users_Guide/figure/installation_dir.png deleted file mode 100644 index 40f1b48231ef9e749bf5217b31a8640c783768be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90216 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 YEV2Dr%FZI;iTmJKa^@>J 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 diff --git a/docs/Users_Guide/installation.rst b/docs/Users_Guide/installation.rst index 2494abe520..5e5d1469db 100644 --- a/docs/Users_Guide/installation.rst +++ b/docs/Users_Guide/installation.rst @@ -162,18 +162,34 @@ Environment Variables to Run Script Before running the compilation script, there are five environment variables that are required: **TEST_BASE**, **COMPILER**, **MET_SUBDIR**, **MET_TARBALL**, and **USE_MODULES**. + If compiling support for Python embedding, the script will need the following additional environment variables: **MET_PYTHON**, **MET_PYTHON_CC**, and -**MET_PYTHON_LD**. All of these environment variables are discussed -in further detail in the Environment Variable Descriptions section below. -An easy way to set these environment variables is in an environment -configuration file (for example, **install_met_env.**). An -example environment configuration file to start from (**install_met_env.generic_gnu**), -as well as environment configuration files used on HPCs at NCAR and NOAA, +**MET_PYTHON_LD**. + +All of these environment variables are discussed in further detail in the +Environment Variable Descriptions section below. An easy way to set these +environment variables is in an environment configuration file +(for example, **install_met_env.**). An example environment +configuration file to start with (**install_met_env.generic_gnu**), +as well as the environment configuration files used on HPCs at NCAR and NOAA, can be found in the `MET GitHub repository `_ in the `scripts/installation/config `_ directory. +.. note:: Starting with MET-12.0.0, C++17 is the default C++ standard for MET due to the requirements of its dependent libraries. However, MET itself only makes use of C++11 features. + + The ATLAS library (conditionally required for MET, if support for + unstructured grids is desired) + `versions 0.33.0 `_ + and later requires compiler support for the C++17 standard. + + At this time, users with systems that do not yet support the C++17 + standard, can still compile MET with an older C++ standard, using an + older version of ATLAS, by adding the MET_CXX_STANDARD variable to + the environment configuration file as described in the **OPTIONAL** + section below. + Environment Variable Descriptions --------------------------------- @@ -198,7 +214,7 @@ Environment Variable Descriptions subdirectory will be installed and is often set equivalent to **TEST_BASE** (e.g. ${TEST_BASE}). - **MET_TARBALL** – Format is *v12.0.0tar.gz*. This is the name of the downloaded MET tarball. + **MET_TARBALL** – Format is *v12.0.0.tar.gz*. This is the name of the downloaded MET tarball. **USE_MODULES** – Format is *TRUE* or *FALSE*. Set to FALSE if using a machine that does not use modulefiles; set to TRUE if using a machine that does use modulefiles. For more information on @@ -218,6 +234,7 @@ Environment Variable Descriptions following environment variables if using the Intel compilers: | For non-oneAPI Intel compilers: + | | export FC=ifort | export F77=ifort | export F90=ifort @@ -226,6 +243,7 @@ Environment Variable Descriptions | For oneAPI Intel compilers: + | | export FC=ifx | export F77=ifx | export F90=ifx @@ -239,7 +257,6 @@ Environment Variable Descriptions configuration file, and users with a oneAPI Intel compiler should use the install_met_env.generic_intel_oneapi configuration file. - .. dropdown:: REQUIRED, IF COMPILING PYTHON EMBEDDING **MET_PYTHON** – Format is */usr/local/python3*. @@ -289,13 +306,13 @@ Environment Variable Descriptions **export MET_CXX_STANDARD** - Specify the version of the supported C++ standard. Values may be 11, 14, or 17. The default value is 17. - (e.g. export MET_CXX_STANDARD=11). + (e.g. export MET_CXX_STANDARD=11) External Library Handling in compile_MET_all.sh ----------------------------------------------- -.. dropdown:: IF THE USER WANTS TO HAVE THE COMPILATION SCRIPT DOWNLOAD THE LIBRARY DEPENDENCIES +.. dropdown:: IF THE USER WANTS TO HAVE THE COMPILATION SCRIPT COMPILE THE LIBRARY DEPENDENCIES The **compile_MET_all.sh** script will compile and install MET and its :ref:`required_external_libraries_to_build_MET`, if needed. @@ -399,7 +416,21 @@ particular system’s needs, MET is ready for installation. The screenshot below contents of the installation directory followed by the tar_files subdirectory at this step on the machine ‘hera’. -.. image:: figure/installation_dir.png +.. code-block:: ini + + /contrib/met/12.0.0$ ls + compile_MET_all.sh install_met_env.hera tar_files + + /contrib/met/12.0.0$ ls tar_files + HDF-EOS2.16v1.00.tar.Z eckit-1.24.4.tar.gz netcdf-4.7.4.tar.gz + HDF4.2r3.tar.gz freetype-2.11.0.tar.gz netcdf-cxx4-4.3.1.tar.gz + atlas-0.30.0.tar.gz g2clib-1.6.4.tar.gz pixman-0.40.0.tar.gz + atlas-0.35.0.tar.gz gsl-1.11.tar.gz proj-7.1.0.tar.gz + bufr_v11.6.0.tar.gz gsl-2.7.1.tar.gz sqlite-autoconf-3430100.tar.gz + cairo-1.16.0.tar.xz hdf5-1.12.2.tar.gz tiff-4.6.0.tar.gz + ecbuild-3.5.0.tar.gz jasper-2.0.25.tar.gz zlib-1.2.11.tar.gz + ecbuild-3.7.0.tar.gz jpegsrc.v9e.tar.gz + eckit-1.20.2.tar.gz libpng-1.6.37.tar.gz Simply enter the following into the terminal to execute the script: @@ -409,14 +440,17 @@ Simply enter the following into the terminal to execute the script: The screenshot below shows the contents of the installation directory after installation: -.. image:: figure/installation_dir_after.png +.. code-block:: ini + + /contrib/met/12.0.0$ ls + MET-12.0.0 bin compile_MET_all.sh external_libs install_met_env.hera share tar_files To confirm that MET was installed successfully, run the following command from the installation directory to check for errors in the test file: .. code-block:: ini - - grep -i error MET12.0.0/met.make_test.log - + + grep -i error MET-12.0.0/met.make_test.log + If no errors are returned, the installation was successful. Due to the highly variable nature of hardware systems, users may encounter issues during the installation process that result in MET not being installed. If this occurs please @@ -463,7 +497,6 @@ version. If a different version is required, select the correct version from the dropdown option. Follow Docker’s instructions for a successful installation. - Loading the Latest Docker Image of MET -------------------------------------- @@ -481,7 +514,6 @@ version number will result in an error due to Docker’s behavior of attempting to retrieve an image with the “latest” tag, which MET no longer uses. - Running the Docker version of MET --------------------------------- @@ -502,7 +534,7 @@ the same way the latest image of MET was pulled: .. code-block:: ini docker run -it --rm dtcenter/met:12.0.0 /bin/bash - + If the usage MET via Docker images was successful, it is highly recommended to move on to using the METplus wrappers of the tools, which have their own @@ -552,7 +584,6 @@ to make the container: singularity build met-12.0.0.sif docker://dtcenter/met:12.0.0 - Running the MET Container ------------------------- @@ -573,7 +604,7 @@ be used otherwise the instance will continue to run in the background: .. code-block:: ini - singularity instance stop /path/to/container/met-12.0.0.sif met-12.0.0 + singularity instance stop /path/to/container/met-12.0.0.sif met-12.0.0 Now that MET is successfully installed, it is highly recommended to next install the METplus wrappers to take full advantage of @@ -583,5 +614,3 @@ Users can also proceed to the and run through the examples that only utilize the MET processes (METplus wrapper applications and commands will not work unless METplus wrappers are also installed). - - diff --git a/internal/test_unit/python/unit.py b/internal/test_unit/python/unit.py index 3bc2b222a9..1fc3bf681a 100755 --- a/internal/test_unit/python/unit.py +++ b/internal/test_unit/python/unit.py @@ -234,7 +234,7 @@ def unit(test_xml, file_log=None, cmd_only=False, noexit=False, memchk=False, ca # # on failure, print the problematic test and exit, if requested if not (ret_ok and out_ok): - logger.info("\n".join(set_envs) + cmd + cmd_outs + "\n".join(unset_envs) + "\n") + logger.info("\n".join(set_envs) + "\n" + cmd + "\n" + cmd_outs + "\n".join(unset_envs) + "\n") if not noexit: sys.exit(1) diff --git a/internal/test_util/tools/other/mode_time_domain/Makefile.am b/internal/test_util/tools/other/mode_time_domain/Makefile.am index 5bbe02612e..1f9be23d82 100644 --- a/internal/test_util/tools/other/mode_time_domain/Makefile.am +++ b/internal/test_util/tools/other/mode_time_domain/Makefile.am @@ -38,8 +38,6 @@ test_velocity_LDADD = \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_partition.o \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_read_data.o \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_txt_output.o \ - ${top_builddir}/src/tools/other/mode_time_domain/mtd-nc_grid.o \ - ${top_builddir}/src/tools/other/mode_time_domain/mtd-nc_utils_local.o \ -lvx_pxm \ -lvx_plot_util \ -lvx_nav \ diff --git a/internal/test_util/tools/other/mode_time_domain/Makefile.in b/internal/test_util/tools/other/mode_time_domain/Makefile.in index c87b755d7d..b1b08361df 100644 --- a/internal/test_util/tools/other/mode_time_domain/Makefile.in +++ b/internal/test_util/tools/other/mode_time_domain/Makefile.in @@ -125,8 +125,6 @@ test_velocity_DEPENDENCIES = ${top_builddir}/src/tools/other/mode_time_domain/mt ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_partition.o \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_read_data.o \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_txt_output.o \ - ${top_builddir}/src/tools/other/mode_time_domain/mtd-nc_grid.o \ - ${top_builddir}/src/tools/other/mode_time_domain/mtd-nc_utils_local.o \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) @@ -378,8 +376,6 @@ test_velocity_LDADD = \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_partition.o \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_read_data.o \ ${top_builddir}/src/tools/other/mode_time_domain/mtd-mtd_txt_output.o \ - ${top_builddir}/src/tools/other/mode_time_domain/mtd-nc_grid.o \ - ${top_builddir}/src/tools/other/mode_time_domain/mtd-nc_utils_local.o \ -lvx_pxm \ -lvx_plot_util \ -lvx_nav \ diff --git a/src/basic/vx_math/is_bad_data.h b/src/basic/vx_math/is_bad_data.h index 80af0916ef..cb1c4afa8c 100644 --- a/src/basic/vx_math/is_bad_data.h +++ b/src/basic/vx_math/is_bad_data.h @@ -80,6 +80,14 @@ inline int is_eq(float a, float b) { return is_eq((double)a, (double)b); } +inline int is_eq(double a, float b) { + return is_eq(a, (double)b); +} + +inline int is_eq(float a, double b) { + return is_eq((double)a, b); +} + template inline int is_eq(T a, T b) { return (a == b); diff --git a/src/libcode/vx_statistics/compute_stats.cc b/src/libcode/vx_statistics/compute_stats.cc index c0d988efd3..4dc90e4aeb 100644 --- a/src/libcode/vx_statistics/compute_stats.cc +++ b/src/libcode/vx_statistics/compute_stats.cc @@ -1593,7 +1593,7 @@ void compute_aggregated_seeps_grid(const DataPlane &fcst_dp, const DataPlane &ob float obs_value = obs_dp.get(ix, iy); fcst_cat = obs_cat = bad_data_int; seeps_score = bad_data_double; - if (!is_eq(fcst_value, -9999.0) && !is_eq(obs_value, -9999.0)) { + if (!is_bad_data(fcst_value) && !is_bad_data(obs_value)) { SeepsScore *seeps_mpr = seeps_climo->get_record(ix, iy, fcst_value, obs_value); if (seeps_mpr != nullptr) { fcst_cat = seeps_mpr->fcst_cat; diff --git a/src/tools/other/mode_time_domain/2d_att.cc b/src/tools/other/mode_time_domain/2d_att.cc index 2ea1ff0844..f65ed2ae7f 100644 --- a/src/tools/other/mode_time_domain/2d_att.cc +++ b/src/tools/other/mode_time_domain/2d_att.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -399,15 +398,7 @@ a.ObjectNumber = obj_number; moments = mask_2d.calc_2d_moments(); -if ( moments.N == 0 ) { - - // mlog << Error << "\n\n calc_2d_single_atts() -> empty object!\n\n"; - - // exit ( 1 ); - - return a; - -} +if ( moments.N == 0 ) return a; a.Xbar = (moments.Sx)/(moments.N); a.Ybar = (moments.Sy)/(moments.N); @@ -430,7 +421,8 @@ values = new float [a.Area]; if ( !values ) { - mlog << Error << "\n\n calc_2d_single_atts() -> memory allocation error\n\n"; + mlog << Error << "\ncalc_2d_single_atts() -> " + << "memory allocation error\n\n"; exit ( 1 ); @@ -626,6 +618,3 @@ return; //////////////////////////////////////////////////////////////////////// - - - diff --git a/src/tools/other/mode_time_domain/2d_att_array.cc b/src/tools/other/mode_time_domain/2d_att_array.cc index 86a3f99081..b805304c0f 100644 --- a/src/tools/other/mode_time_domain/2d_att_array.cc +++ b/src/tools/other/mode_time_domain/2d_att_array.cc @@ -7,20 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - -//////////////////////////////////////////////////////////////////////// - - - // - // Warning: This file is machine generated - // - // Do not edit by hand - // - // - // Created by arraygen on September 17, 2015 10:11 am MDT - // - - //////////////////////////////////////////////////////////////////////// @@ -127,13 +113,10 @@ void SingleAtt2DArray::clear() if ( e ) { delete [] e; e = (SingleAtt2D *) nullptr; } - Nelements = 0; Nalloc = 0; -// AllocInc = 50; // don't reset AllocInc - return; @@ -174,7 +157,8 @@ SingleAtt2D * u = new SingleAtt2D [N]; if ( !u ) { - mlog << Error << "SingleAtt2DArray::extend(int) -> memory allocation error\n\n"; + mlog << Error << "\nSingleAtt2DArray::extend(int) -> " + << "memory allocation error\n\n"; exit ( 1 ); @@ -238,7 +222,8 @@ void SingleAtt2DArray::set_alloc_inc(int N) if ( N < 0 ) { - mlog << Error << "SingleAtt2DArray::set_alloc_int(int) -> bad value ... " << N << "\n\n"; + mlog << Error << "\nSingleAtt2DArray::set_alloc_int(int) -> " + << "bad value ... " << N << "\n\n"; exit ( 1 ); @@ -299,7 +284,8 @@ SingleAtt2D & SingleAtt2DArray::operator[](int N) const if ( (N < 0) || (N >= Nelements) ) { - mlog << Error << "\n\n SingleAtt2DArray::operator[](int) -> range check error ... " << N << "\n\n"; + mlog << Error << "\nSingleAtt2DArray::operator[](int) -> " + << "range check error ... " << N << "\n\n"; exit ( 1 ); } @@ -344,8 +330,8 @@ unixtime SingleAtt2DArray::valid_time(int index) const if ( (index < 0) || (index >= Nelements) ) { - mlog << Error - << "SingleAtt2DArray::valid_time(int) const -> range check error\n\n"; + mlog << Error << "\nSingleAtt2DArray::valid_time(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -365,8 +351,8 @@ int SingleAtt2DArray::lead_time(int index) const if ( (index < 0) || (index >= Nelements) ) { - mlog << Error - << "SingleAtt2DArray::lead_time(int) const -> range check error\n\n"; + mlog << Error << "\nSingleAtt2DArray::lead_time(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -386,8 +372,8 @@ int SingleAtt2DArray::time_index(int index) const if ( (index < 0) || (index >= Nelements) ) { - mlog << Error - << "SingleAtt2DArray::time_index(int) const -> range check error\n\n"; + mlog << Error << "\nSingleAtt2DArray::time_index(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -401,5 +387,3 @@ return e[index].time_index(); //////////////////////////////////////////////////////////////////////// - - diff --git a/src/tools/other/mode_time_domain/2d_moments.cc b/src/tools/other/mode_time_domain/2d_moments.cc index ed1053d819..fc3cad6289 100644 --- a/src/tools/other/mode_time_domain/2d_moments.cc +++ b/src/tools/other/mode_time_domain/2d_moments.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -25,12 +24,10 @@ using namespace std; //////////////////////////////////////////////////////////////////////// - // // Code for class Mtd_2D_Moments // - //////////////////////////////////////////////////////////////////////// @@ -177,7 +174,8 @@ void Mtd_2D_Moments::centralize() if ( N == 0 ) { - mlog << Error << "\n\n Mtd_2D_Moments::centralize() -> no data!\n\n"; + mlog << Error << "\nMtd_2D_Moments::centralize() -> " + << "no data!\n\n"; exit ( 1 ); @@ -220,7 +218,8 @@ double Mtd_2D_Moments::calc_2D_axis_plane_angle() const if ( ! IsCentralized ) { - mlog << Error << "\n\n Mtd_2D_Moments::calc_2D_axis_plane_angle() const -> moments must be centralized first!\n\n"; + mlog << Error << "\nMtd_2D_Moments::calc_2D_axis_plane_angle() const -> " + << "moments must be centralized first!\n\n"; exit ( 1 ); @@ -242,6 +241,3 @@ return angle; //////////////////////////////////////////////////////////////////////// - - - diff --git a/src/tools/other/mode_time_domain/2d_moments.h b/src/tools/other/mode_time_domain/2d_moments.h index 2052561687..3dcf4c995c 100644 --- a/src/tools/other/mode_time_domain/2d_moments.h +++ b/src/tools/other/mode_time_domain/2d_moments.h @@ -57,7 +57,6 @@ class Mtd_2D_Moments { int area() const; - // // do stuff // @@ -66,11 +65,8 @@ class Mtd_2D_Moments { void centralize(); - double calc_2D_axis_plane_angle() const; - - }; diff --git a/src/tools/other/mode_time_domain/3d_att.cc b/src/tools/other/mode_time_domain/3d_att.cc index 3f30a12786..a347be824e 100644 --- a/src/tools/other/mode_time_domain/3d_att.cc +++ b/src/tools/other/mode_time_domain/3d_att.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -779,8 +778,6 @@ IntersectionVol = 0; IsSimple = true; -// UnionVol = 0; - TimeCentroidDelta = 0.0; SpaceCentroidDist = 0.0; @@ -830,9 +827,6 @@ ObsClusterNumber = a.ObsClusterNumber; IntersectionVol = a.IntersectionVol; -// UnionVol = a.UnionVol; - - TimeCentroidDelta = a.TimeCentroidDelta; SpaceCentroidDist = a.SpaceCentroidDist; @@ -954,20 +948,6 @@ return; } -//////////////////////////////////////////////////////////////////////// - -/* -void PairAtt3D::set_union_volume(int k) - -{ - -UnionVol = k; - -return; - -} -*/ - //////////////////////////////////////////////////////////////////////// @@ -1261,7 +1241,7 @@ moments = mask.calc_3d_moments(); if ( moments.N == 0 ) { - mlog << Error << "\n\ncalc_3d_single_atts() -> " + mlog << Error << "\ncalc_3d_single_atts() -> " << "empty object!\n\n"; exit ( 1 ); @@ -1354,7 +1334,7 @@ values = new float [Vol]; if ( !values ) { - mlog << Error << "\n\ncalc_3d_single_atts() -> " + mlog << Error << "\ncalc_3d_single_atts() -> " << "memory allocation error\n\n"; exit ( 1 ); @@ -1453,7 +1433,6 @@ for (x=0; x<(fcst_obj.nx()); ++x) { } p.set_intersection_volume (IV); -// p.set_union_volume (UV); // // centroid distances @@ -1546,188 +1525,6 @@ return p; } -//////////////////////////////////////////////////////////////////////// - -/* -double calc_total_interest(const PairAtt3D & p, const MtdConfigInfo & conf) - -{ - -double t = 0.0; -double num, den; // numerator and denominator in the expression for total interest -double I, w; -PiecewiseLinear * f = 0; - -num = 0.0; -den = 0.0; - - // - // We don't need to use "is_eq" to check whether each weight is - // nonzero, because the MtdConfigInfo::read_config() function has - // already done that. That same function has already tested that - // the weights are not all zero. - // - - // - // space centroid dist - // - -w = conf.space_centroid_dist_wt; - -if ( w != 0.0 ) { - - f = conf.space_centroid_dist_if; - - I = (*f)(p.space_centroid_dist()); - - num += w*I; - - den += w; - -} - - // - // time centroid delta - // - -w = conf.time_centroid_delta_wt; - -if ( w != 0.0 ) { - - f = conf.time_centroid_delta_if; - - I = (*f)(p.time_centroid_delta()); - - num += w*I; - - den += w; - -} - - // - // speed delta - // - -w = conf.speed_delta_wt; - -if ( w != 0.0 ) { - - f = conf.speed_delta_if; - - I = (*f)(p.speed_delta()); - - num += w*I; - - den += w; - -} - - // - // direction difference - // - -w = conf.direction_diff_wt; - -if ( w != 0.0 ) { - - f = conf.direction_diff_if; - - I = (*f)(p.direction_difference()); - - num += w*I; - - den += w; - -} - - // - // volume ratio - // - -w = conf.volume_ratio_wt; - -if ( w != 0.0 ) { - - f = conf.volume_ratio_if; - - I = (*f)(p.volume_ratio()); - - num += w*I; - - den += w; - -} - - // - // axis angle difference - // - -w = conf.axis_angle_diff_wt; - -if ( w != 0.0 ) { - - f = conf.axis_angle_diff_if; - - I = (*f)(p.axis_angle_diff()); - - num += w*I; - - den += w; - -} - - // - // start time delta - // - -w = conf.start_time_delta_wt; - -if ( w != 0.0 ) { - - f = conf.start_time_delta_if; - - I = (*f)(p.start_time_delta()); - - num += w*I; - - den += w; - -} - - // - // end time delta - // - -w = conf.end_time_delta_wt; - -if ( w != 0.0 ) { - - f = conf.end_time_delta_if; - - I = (*f)(p.end_time_delta()); - - num += w*I; - - den += w; - -} - - // - // The denominator is just the sum of the weights, - // which, as stated above, we already know is nonzero. - // - -t = num/den; - - // - // done - // - -return t; - -} -*/ - //////////////////////////////////////////////////////////////////////// @@ -1738,15 +1535,6 @@ double calc_2d_dist(const double x1_grid, const double y1_grid, double dist; - // - // distance in grid units - // - -// const double dx = x1_grid - x2_grid; -// const double dy = y1_grid - y2_grid; -// -// dist = sqrt ( dx*dx + dy*dy ); - // // great circle distance // @@ -1771,8 +1559,3 @@ return dist; //////////////////////////////////////////////////////////////////////// - - - - - diff --git a/src/tools/other/mode_time_domain/3d_att.h b/src/tools/other/mode_time_domain/3d_att.h index 91ad4901c3..d0b6084316 100644 --- a/src/tools/other/mode_time_domain/3d_att.h +++ b/src/tools/other/mode_time_domain/3d_att.h @@ -308,9 +308,6 @@ class PairAtt3D { void dump(std::ostream &, int depth = 0) const; - // SingleAtt3D Fcst; - // SingleAtt3D Obs; - // // set stuff // @@ -395,7 +392,6 @@ inline int PairAtt3D::fcst_cluster_number() const { return FcstClusterNumber; } inline int PairAtt3D::obs_cluster_number() const { return ObsClusterNumber; } inline int PairAtt3D::intersection_vol () const { return IntersectionVol; } -// inline int PairAtt3D::union_vol () const { return UnionVol; } inline double PairAtt3D::time_centroid_delta () const { return TimeCentroidDelta; } inline double PairAtt3D::space_centroid_dist () const { return SpaceCentroidDist; } @@ -430,8 +426,6 @@ extern PairAtt3D calc_3d_pair_atts(const Object & _fcst_obj, const SingleAtt3D & _fa, const SingleAtt3D & _oa); -// extern double calc_total_interest(const PairAtt3D &, const MtdConfigInfo &); - //////////////////////////////////////////////////////////////////////// diff --git a/src/tools/other/mode_time_domain/3d_att_pair_array.cc b/src/tools/other/mode_time_domain/3d_att_pair_array.cc index cd5bcd1ad6..8ff840be1c 100644 --- a/src/tools/other/mode_time_domain/3d_att_pair_array.cc +++ b/src/tools/other/mode_time_domain/3d_att_pair_array.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -113,15 +112,10 @@ void PairAtt3DArray::clear() if ( e ) { delete [] e; e = (PairAtt3D *) nullptr; } - - Nelements = 0; Nalloc = 0; -// AllocInc = 100; // don't reset AllocInc - - return; } @@ -161,7 +155,8 @@ PairAtt3D * u = new PairAtt3D [N]; if ( !u ) { - mlog << Error << "PairAtt3DArray::extend(int) -> memory allocation error\n\n"; + mlog << Error << "\nPairAtt3DArray::extend(int) -> " + << "memory allocation error\n\n"; exit ( 1 ); @@ -225,7 +220,8 @@ void PairAtt3DArray::set_alloc_inc(int N) if ( N < 0 ) { - mlog << Error << "PairAtt3DArray::set_alloc_int(int) -> bad value ... " << N << "\n\n"; + mlog << Error << "\nPairAtt3DArray::set_alloc_int(int) -> " + << "bad value ... " << N << "\n\n"; exit ( 1 ); @@ -286,7 +282,8 @@ PairAtt3D & PairAtt3DArray::operator[](int N) const if ( (N < 0) || (N >= Nelements) ) { - mlog << Error << "\n\n PairAtt3DArray::operator[](int) -> range check error ... " << N << "\n\n"; + mlog << Error << "\nPairAtt3DArray::operator[](int) -> " + << "range check error ... " << N << "\n\n"; exit ( 1 ); } @@ -305,7 +302,8 @@ int PairAtt3DArray::fcst_obj_number(int k) const if ( (k < 0) || (k >= Nelements) ) { - mlog << Error << "\n\n PairAtt3DArray::fcst_obj_number(int) -> range check error\n\n"; + mlog << Error << "\nPairAtt3DArray::fcst_obj_number(int) -> " + << "range check error\n\n"; exit ( 1 ); @@ -325,7 +323,8 @@ int PairAtt3DArray::obs_obj_number(int k) const if ( (k < 0) || (k >= Nelements) ) { - mlog << Error << "\n\n PairAtt3DArray::obs_obj_number(int) -> range check error\n\n"; + mlog << Error << "\nPairAtt3DArray::obs_obj_number(int) -> " + << "range check error\n\n"; exit ( 1 ); @@ -345,7 +344,8 @@ int PairAtt3DArray::fcst_cluster_number(int k) const if ( (k < 0) || (k >= Nelements) ) { - mlog << Error << "\n\n PairAtt3DArray::fcst_cluster_number(int) -> range check error\n\n"; + mlog << Error << "\nPairAtt3DArray::fcst_cluster_number(int) -> " + << "range check error\n\n"; exit ( 1 ); @@ -365,7 +365,8 @@ int PairAtt3DArray::obs_cluster_number(int k) const if ( (k < 0) || (k >= Nelements) ) { - mlog << Error << "\n\n PairAtt3DArray::obs_cluster_number(int) -> range check error\n\n"; + mlog << Error << "\nPairAtt3DArray::obs_cluster_number(int) -> " + << "range check error\n\n"; exit ( 1 ); @@ -385,7 +386,8 @@ double PairAtt3DArray::total_interest(int k) const if ( (k < 0) || (k >= Nelements) ) { - mlog << Error << "\n\n PairAtt3DArray::total_interest(int) -> range check error\n\n"; + mlog << Error << "\nPairAtt3DArray::total_interest(int) -> " + << "range check error\n\n"; exit ( 1 ); diff --git a/src/tools/other/mode_time_domain/3d_att_pair_array.h b/src/tools/other/mode_time_domain/3d_att_pair_array.h index f3cdf13674..470324e562 100644 --- a/src/tools/other/mode_time_domain/3d_att_pair_array.h +++ b/src/tools/other/mode_time_domain/3d_att_pair_array.h @@ -92,7 +92,6 @@ class PairAtt3DArray { void patch_cluster_numbers(const MM_Engine &); - }; diff --git a/src/tools/other/mode_time_domain/3d_att_single_array.cc b/src/tools/other/mode_time_domain/3d_att_single_array.cc index d8fdba1252..dabf30bdeb 100644 --- a/src/tools/other/mode_time_domain/3d_att_single_array.cc +++ b/src/tools/other/mode_time_domain/3d_att_single_array.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -113,14 +112,10 @@ void SingleAtt3DArray::clear() if ( e ) { delete [] e; e = (SingleAtt3D *) nullptr; } - - Nelements = 0; Nalloc = 0; -// AllocInc = 100; // don't reset AllocInc - return; @@ -161,7 +156,8 @@ SingleAtt3D * u = new SingleAtt3D [N]; if ( !u ) { - mlog << Error << "SingleAtt3DArray::extend(int) -> memory allocation error\n\n"; + mlog << Error << "\nSingleAtt3DArray::extend(int) -> " + << "memory allocation error\n\n"; exit ( 1 ); @@ -225,7 +221,8 @@ void SingleAtt3DArray::set_alloc_inc(int N) if ( N < 0 ) { - mlog << Error << "SingleAtt3DArray::set_alloc_int(int) -> bad value ... " << N << "\n\n"; + mlog << Error << "\nSingleAtt3DArray::set_alloc_int(int) -> " + << "bad value ... " << N << "\n\n"; exit ( 1 ); @@ -286,7 +283,8 @@ SingleAtt3D & SingleAtt3DArray::operator[](int N) const if ( (N < 0) || (N >= Nelements) ) { - mlog << Error << "\n\n SingleAtt3DArray::operator[](int) -> range check error ... " << N << "\n\n"; + mlog << Error << "\nSingleAtt3DArray::operator[](int) -> " + << "range check error ... " << N << "\n\n"; exit ( 1 ); } diff --git a/src/tools/other/mode_time_domain/3d_conv.cc b/src/tools/other/mode_time_domain/3d_conv.cc index 1ecbe0b68a..b095989391 100644 --- a/src/tools/other/mode_time_domain/3d_conv.cc +++ b/src/tools/other/mode_time_domain/3d_conv.cc @@ -244,12 +244,6 @@ file_id = 1; // This is declared static in the netCDF library header file ncG spatial_conv_radius = spatial_R; - -// mlog << Error << "\n\n" -// << " MtdFloatFile::convolve(const int) const -> still doesn't allow for bad data!\n\n" -// << "\n\n"; - - const int Nxy = Nx*Ny; const int Nxyz = Nx*Ny*Nt; @@ -263,7 +257,8 @@ for (int k=0; k memory allocation error\n\n"; + mlog << Error << "\nMtdFloatFile::convolve(const int, const int, const int) const: process() -> " + << "memory allocation error\n\n"; exit ( 1 ); @@ -278,8 +273,6 @@ max_conv_value = -1.0e100; unixtime time_start = time(nullptr); -// cout << "\n\n n = " << mtd_three_to_one(Nx, Ny, Nt, 88, 397, 0) << "\n\n"; - for (int t=0; t bad size\n\n"; + mlog << Error << "\nDataHandle::set_size() -> " + << "bad size\n\n"; exit ( 1 ); @@ -532,9 +517,6 @@ bool status = false; const int nx = mtd.nx(); const int ny = mtd.ny(); - -// mlog << Debug(5) << "In get_data_plane\n"; - for (y=0; y " + << "unable to write image file: " << filename << "\n\n"; exit ( 1 ); @@ -1038,11 +1009,10 @@ for (int x=0; x " + << "unable to write image file: " << filename << "\n\n"; exit ( 1 ); @@ -1056,7 +1026,3 @@ return; //////////////////////////////////////////////////////////////////////// - - - - diff --git a/src/tools/other/mode_time_domain/3d_moments.cc b/src/tools/other/mode_time_domain/3d_moments.cc index 7c2b4362d4..53e1b8b547 100644 --- a/src/tools/other/mode_time_domain/3d_moments.cc +++ b/src/tools/other/mode_time_domain/3d_moments.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -187,7 +186,8 @@ void Mtd_3D_Moments::centralize() if ( N == 0 ) { - mlog << Error << "\n\n Mtd_3D_Moments::centralize() -> no data!\n\n"; + mlog << Error << "\nMtd_3D_Moments::centralize() -> " + << "no data!\n\n"; exit ( 1 ); @@ -242,7 +242,8 @@ void Mtd_3D_Moments::calc_3d_velocity(double & vx, double & vy) const if ( ! IsCentralized ) { - mlog << Error << "\n\n Mtd_3D_Moments::calc_3d_velocity(double &, double &) const -> moments must be centralized first!\n\n"; + mlog << Error << "\nMtd_3D_Moments::calc_3d_velocity(double &, double &) const -> " + << "moments must be centralized first!\n\n"; exit ( 1 ); @@ -266,7 +267,8 @@ double Mtd_3D_Moments::calc_3d_axis_plane_angle() const if ( ! IsCentralized ) { - mlog << Error << "\n\n Mtd_3D_Moments::calc_3d_axis_plane_angle() const -> moments must be centralized first!\n\n"; + mlog << Error << "\nMtd_3D_Moments::calc_3d_axis_plane_angle() const -> " + << "moments must be centralized first!\n\n"; exit ( 1 ); @@ -288,6 +290,3 @@ return angle; //////////////////////////////////////////////////////////////////////// - - - diff --git a/src/tools/other/mode_time_domain/3d_moments.h b/src/tools/other/mode_time_domain/3d_moments.h index 933fa4e7ad..7f5f8bb02f 100644 --- a/src/tools/other/mode_time_domain/3d_moments.h +++ b/src/tools/other/mode_time_domain/3d_moments.h @@ -70,13 +70,10 @@ class Mtd_3D_Moments { void centralize(); - void calc_3d_velocity(double & vx, double & vy) const; double calc_3d_axis_plane_angle() const; - - }; diff --git a/src/tools/other/mode_time_domain/Makefile.am b/src/tools/other/mode_time_domain/Makefile.am index 34ad4461ee..b75702d973 100644 --- a/src/tools/other/mode_time_domain/Makefile.am +++ b/src/tools/other/mode_time_domain/Makefile.am @@ -12,8 +12,6 @@ include ${top_srcdir}/Make-include bin_PROGRAMS = mtd mtd_SOURCES = mtd.cc \ mtdfiletype_to_string.cc mtdfiletype_to_string.h \ - nc_utils_local.cc nc_utils_local.h \ - nc_grid.cc nc_grid.h \ 3d_moments.cc 3d_moments.h \ 2d_moments.cc 2d_moments.h \ fo_node.cc fo_node.h \ diff --git a/src/tools/other/mode_time_domain/Makefile.in b/src/tools/other/mode_time_domain/Makefile.in index a0f69996a1..532000c57e 100644 --- a/src/tools/other/mode_time_domain/Makefile.in +++ b/src/tools/other/mode_time_domain/Makefile.in @@ -102,7 +102,6 @@ CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_mtd_OBJECTS = mtd-mtd.$(OBJEXT) mtd-mtdfiletype_to_string.$(OBJEXT) \ - mtd-nc_utils_local.$(OBJEXT) mtd-nc_grid.$(OBJEXT) \ mtd-3d_moments.$(OBJEXT) mtd-2d_moments.$(OBJEXT) \ mtd-fo_node.$(OBJEXT) mtd-fo_node_array.$(OBJEXT) \ mtd-fo_graph.$(OBJEXT) mtd-mtd_config_info.$(OBJEXT) \ @@ -152,8 +151,7 @@ am__depfiles_remade = ./$(DEPDIR)/mtd-2d_att.Po \ ./$(DEPDIR)/mtd-mtd_partition.Po \ ./$(DEPDIR)/mtd-mtd_read_data.Po \ ./$(DEPDIR)/mtd-mtd_txt_output.Po \ - ./$(DEPDIR)/mtd-mtdfiletype_to_string.Po \ - ./$(DEPDIR)/mtd-nc_grid.Po ./$(DEPDIR)/mtd-nc_utils_local.Po + ./$(DEPDIR)/mtd-mtdfiletype_to_string.Po am__mv = mv -f AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -372,8 +370,6 @@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in mtd_SOURCES = mtd.cc \ mtdfiletype_to_string.cc mtdfiletype_to_string.h \ - nc_utils_local.cc nc_utils_local.h \ - nc_grid.cc nc_grid.h \ 3d_moments.cc 3d_moments.h \ 2d_moments.cc 2d_moments.h \ fo_node.cc fo_node.h \ @@ -544,8 +540,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mtd-mtd_read_data.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mtd-mtd_txt_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mtd-mtdfiletype_to_string.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mtd-nc_grid.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mtd-nc_utils_local.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @@ -595,34 +589,6 @@ mtd-mtdfiletype_to_string.obj: mtdfiletype_to_string.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mtd-mtdfiletype_to_string.obj `if test -f 'mtdfiletype_to_string.cc'; then $(CYGPATH_W) 'mtdfiletype_to_string.cc'; else $(CYGPATH_W) '$(srcdir)/mtdfiletype_to_string.cc'; fi` -mtd-nc_utils_local.o: nc_utils_local.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mtd-nc_utils_local.o -MD -MP -MF $(DEPDIR)/mtd-nc_utils_local.Tpo -c -o mtd-nc_utils_local.o `test -f 'nc_utils_local.cc' || echo '$(srcdir)/'`nc_utils_local.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mtd-nc_utils_local.Tpo $(DEPDIR)/mtd-nc_utils_local.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nc_utils_local.cc' object='mtd-nc_utils_local.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mtd-nc_utils_local.o `test -f 'nc_utils_local.cc' || echo '$(srcdir)/'`nc_utils_local.cc - -mtd-nc_utils_local.obj: nc_utils_local.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mtd-nc_utils_local.obj -MD -MP -MF $(DEPDIR)/mtd-nc_utils_local.Tpo -c -o mtd-nc_utils_local.obj `if test -f 'nc_utils_local.cc'; then $(CYGPATH_W) 'nc_utils_local.cc'; else $(CYGPATH_W) '$(srcdir)/nc_utils_local.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mtd-nc_utils_local.Tpo $(DEPDIR)/mtd-nc_utils_local.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nc_utils_local.cc' object='mtd-nc_utils_local.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mtd-nc_utils_local.obj `if test -f 'nc_utils_local.cc'; then $(CYGPATH_W) 'nc_utils_local.cc'; else $(CYGPATH_W) '$(srcdir)/nc_utils_local.cc'; fi` - -mtd-nc_grid.o: nc_grid.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mtd-nc_grid.o -MD -MP -MF $(DEPDIR)/mtd-nc_grid.Tpo -c -o mtd-nc_grid.o `test -f 'nc_grid.cc' || echo '$(srcdir)/'`nc_grid.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mtd-nc_grid.Tpo $(DEPDIR)/mtd-nc_grid.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nc_grid.cc' object='mtd-nc_grid.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mtd-nc_grid.o `test -f 'nc_grid.cc' || echo '$(srcdir)/'`nc_grid.cc - -mtd-nc_grid.obj: nc_grid.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mtd-nc_grid.obj -MD -MP -MF $(DEPDIR)/mtd-nc_grid.Tpo -c -o mtd-nc_grid.obj `if test -f 'nc_grid.cc'; then $(CYGPATH_W) 'nc_grid.cc'; else $(CYGPATH_W) '$(srcdir)/nc_grid.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mtd-nc_grid.Tpo $(DEPDIR)/mtd-nc_grid.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nc_grid.cc' object='mtd-nc_grid.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mtd-nc_grid.obj `if test -f 'nc_grid.cc'; then $(CYGPATH_W) 'nc_grid.cc'; else $(CYGPATH_W) '$(srcdir)/nc_grid.cc'; fi` - mtd-3d_moments.o: 3d_moments.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtd_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mtd-3d_moments.o -MD -MP -MF $(DEPDIR)/mtd-3d_moments.Tpo -c -o mtd-3d_moments.o `test -f '3d_moments.cc' || echo '$(srcdir)/'`3d_moments.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mtd-3d_moments.Tpo $(DEPDIR)/mtd-3d_moments.Po @@ -1067,8 +1033,6 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/mtd-mtd_read_data.Po -rm -f ./$(DEPDIR)/mtd-mtd_txt_output.Po -rm -f ./$(DEPDIR)/mtd-mtdfiletype_to_string.Po - -rm -f ./$(DEPDIR)/mtd-nc_grid.Po - -rm -f ./$(DEPDIR)/mtd-nc_utils_local.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -1137,8 +1101,6 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/mtd-mtd_read_data.Po -rm -f ./$(DEPDIR)/mtd-mtd_txt_output.Po -rm -f ./$(DEPDIR)/mtd-mtdfiletype_to_string.Po - -rm -f ./$(DEPDIR)/mtd-nc_grid.Po - -rm -f ./$(DEPDIR)/mtd-nc_utils_local.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/tools/other/mode_time_domain/fo_graph.cc b/src/tools/other/mode_time_domain/fo_graph.cc index 48b031813a..2ecdf62c25 100644 --- a/src/tools/other/mode_time_domain/fo_graph.cc +++ b/src/tools/other/mode_time_domain/fo_graph.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -168,7 +167,8 @@ int FO_Graph::f_index(int f_num) const if ( (f_num < 0) || (f_num >= N_fcst) ) { - mlog << Error << "\n\n FO_Graph::f_index(int f_num) const -> range check error!\n\n"; + mlog << Error << "\nFO_Graph::f_index(int f_num) const -> " + << "range check error!\n\n"; exit ( 1 ); @@ -188,7 +188,8 @@ int FO_Graph::o_index(int o_num) const if ( (o_num < 0) || (o_num >= N_obs) ) { - mlog << Error << "\n\n FO_Graph::o_index(int o_num) const -> range check error!\n\n"; + mlog << Error << "\nFO_Graph::o_index(int o_num) const -> " + << "range check error!\n\n"; exit ( 1 ); @@ -214,7 +215,8 @@ if ( (n_f == 0) && (n_o == 0) ) trouble = true; if ( trouble ) { - mlog << Error << "\n\n FO_Graph::set_size(int n_f, int n_o) -> bad n_f or n_o value(s)\n\n"; + mlog << Error << "\nFO_Graph::set_size(int n_f, int n_o) -> " + << "bad n_f or n_o value(s)\n\n"; exit ( 1 ); @@ -229,9 +231,6 @@ N_total = N_fcst + N_obs; TheGraph = new FO_Node [N_total*N_total]; - - - // // done // @@ -365,7 +364,8 @@ void FO_Graph::erase_edges() if ( ! TheGraph ) { - mlog << Error << "\n\n FO_Graph::erase_edges() -> empty graph!\n\n"; + mlog << Error << "\nFO_Graph::erase_edges() -> " + << "empty graph!\n\n"; exit ( 1 ); @@ -394,7 +394,8 @@ void FO_Graph::do_dump_table(AsciiTable & table) const if ( ! TheGraph ) { - mlog << Error << "\n\n FO_Graph::dump_as_table() -> empty graph!\n\n"; + mlog << Error << "\nO_Graph::dump_as_table() -> " + << "empty graph!\n\n"; exit ( 1 ); @@ -410,16 +411,6 @@ const int obs_stop = obs_start + N_obs - 1; table.set_size(N_total + 2, N_total + 2); -// for (r=0; r<(table.nrows()); ++r) { -// -// for (c=0; c<(table.ncols()); ++c) { -// -// table.set_entry(r, c, '.'); -// -// } -// -// } - c = fcst_stop + 1; for (r=1; r<(table.nrows()); ++r) { @@ -499,7 +490,6 @@ for (j=0; j memory allocation error\n\n"; + mlog << Error << "\nFO_Node_Array::extend(int) -> " + << "memory allocation error\n\n"; exit ( 1 ); @@ -225,7 +222,8 @@ void FO_Node_Array::set_alloc_inc(int N) if ( N < 0 ) { - mlog << Error << "FO_Node_Array::set_alloc_int(int) -> bad value ... " << N << "\n\n"; + mlog << Error << "\nFO_Node_Array::set_alloc_int(int) -> " + << "bad value ... " << N << "\n\n"; exit ( 1 ); @@ -286,7 +284,8 @@ FO_Node & FO_Node_Array::operator[](int N) const if ( (N < 0) || (N >= Nelements) ) { - mlog << Error << "\n\n FO_Node_Array::operator[](int) -> range check error ... " << N << "\n\n"; + mlog << Error << "\nFO_Node_Array::operator[](int) -> " + << "range check error ... " << N << "\n\n"; exit ( 1 ); } diff --git a/src/tools/other/mode_time_domain/interest_calc.cc b/src/tools/other/mode_time_domain/interest_calc.cc index f3e98e21c6..630fb92855 100644 --- a/src/tools/other/mode_time_domain/interest_calc.cc +++ b/src/tools/other/mode_time_domain/interest_calc.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -361,6 +360,3 @@ return sum; //////////////////////////////////////////////////////////////////////// - - - diff --git a/src/tools/other/mode_time_domain/interest_calc.h b/src/tools/other/mode_time_domain/interest_calc.h index 120a53137b..7cf4d1362d 100644 --- a/src/tools/other/mode_time_domain/interest_calc.h +++ b/src/tools/other/mode_time_domain/interest_calc.h @@ -84,7 +84,6 @@ class InterestCalculator { double operator()(const PairAtt3D &); - }; diff --git a/src/tools/other/mode_time_domain/mm_engine.cc b/src/tools/other/mode_time_domain/mm_engine.cc index a170f64b64..1928c97594 100644 --- a/src/tools/other/mode_time_domain/mm_engine.cc +++ b/src/tools/other/mode_time_domain/mm_engine.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -208,12 +207,8 @@ for (j=0; j<(graph.n_fcst()); ++j) { if ( ! graph.has_fo_edge(j, k) ) continue; - // mlog << Debug(5) << "\n Merging fcst " << j << ", obs " << k << '\n' << flush; - part.merge_values(f_i, o_i); - // specialzed_dump(graph.n_fcst(), graph.n_obs(), p); - } // for k } // for j diff --git a/src/tools/other/mode_time_domain/mtd.cc b/src/tools/other/mode_time_domain/mtd.cc index 14cd5a18bb..aaad44203d 100644 --- a/src/tools/other/mode_time_domain/mtd.cc +++ b/src/tools/other/mode_time_domain/mtd.cc @@ -151,7 +151,6 @@ default_config_filename = replace_path(default_config_path); config.read_config(default_config_filename.c_str(), local_config_filename.c_str()); - // // determine the input file types // - check the config file for the file_type @@ -263,8 +262,6 @@ fcst_raw.regrid(to_grid, config.fcst_info->regrid()); // ConcatString prefix; -// int year, month, day, hour, minute, second; -// char junk[256]; prefix = make_output_prefix(config, obs_raw.start_valid_time()); @@ -394,10 +391,6 @@ MtdIntFile fo, oo; if ( have_pairs ) { - // mlog << Debug(5) << "\n Calculating pair attributes ... (Nf = " - // << (fcst_obj.n_objects()) << ", No = " - // << (obs_obj.n_objects()) << ")\n\n"; - for (j=0; j<(fcst_obj.n_objects()); ++j) { fo = fcst_obj.select(j + 1); @@ -412,9 +405,6 @@ if ( have_pairs ) { p.set_simple(); - // mlog << Debug(5) << " (F_" << j << ", O_" << k << ") " - // << p.total_interest() << '\n'; - pa_simple.add(p); } @@ -424,7 +414,6 @@ if ( have_pairs ) { } // if have_pairs - // // calculate 2d simple attributes // @@ -520,9 +509,6 @@ for (j=0; j<(obs_obj.n_objects()); ++j) { } // for j - - - // // create graph // @@ -554,26 +540,14 @@ if ( have_pairs ) { for (j=0; j 5 ) fcst_cluster_att.dump(cout); - mlog << Debug(2) << "Calculating 3D obs cluster attributes\n"; @@ -622,8 +594,6 @@ if ( have_pairs ) { att_3 = calc_3d_single_atts(mask, obs_raw, config.model.c_str(), config.inten_perc_value); - // if ( att.Xvelocity > 20.0 ) mask.write("w.nc"); - att_3.set_object_number(j + 1); // 1-based att_3.set_obs(); @@ -634,8 +604,6 @@ if ( have_pairs ) { } - // obs_cluster_att.dump(cout); - } // if have_pairs // @@ -670,12 +638,8 @@ if ( have_pairs ) { p.set_cluster(); - // p.set_total_interest(e.calc(p)); p.set_total_interest(-1.0); - // mlog << Debug(5) << " (F_" << j << ", O_" << k << ") " - // << p.total_interest() << '\n'; - pa_cluster.add(p); } @@ -787,9 +751,6 @@ if ( have_pairs ) { } // for j - - - } // if have pairs // diff --git a/src/tools/other/mode_time_domain/mtd_config_info.cc b/src/tools/other/mode_time_domain/mtd_config_info.cc index 97b9d90e29..c23af5a638 100644 --- a/src/tools/other/mode_time_domain/mtd_config_info.cc +++ b/src/tools/other/mode_time_domain/mtd_config_info.cc @@ -191,51 +191,6 @@ conf.read(default_file_name); if ( user_file_name ) conf.read(user_file_name); - // check the fuzzy-engine weights - // calculation of total interest assumes these tests - - // - // Update: these tests are not really needed since the InterestCalculator - // class checks this - // - -/* -bool all_zero = true; - -if ( is_eq(space_centroid_dist_wt, 0.0) ) space_centroid_dist_wt = 0.0; -else all_zero = false; - -if ( is_eq(time_centroid_delta_wt, 0.0) ) time_centroid_delta_wt = 0.0; -else all_zero = false; - -if ( is_eq(speed_delta_wt, 0.0) ) speed_delta_wt = 0.0; -else all_zero = false; - -if ( is_eq(direction_diff_wt, 0.0) ) direction_diff_wt = 0.0; -else all_zero = false; - -if ( is_eq(volume_ratio_wt, 0.0) ) volume_ratio_wt = 0.0; -else all_zero = false; - -if ( is_eq(axis_angle_diff_wt, 0.0) ) axis_angle_diff_wt = 0.0; -else all_zero = false; - -if ( is_eq(start_time_delta_wt, 0.0) ) start_time_delta_wt = 0.0; -else all_zero = false; - -if ( is_eq(end_time_delta_wt, 0.0) ) end_time_delta_wt = 0.0; -else all_zero = false; - - -if ( all_zero ) { - - mlog << Error << "\n\n MtdConfigInfo::read_config() -> all the fuzzy engine weights are zero!\n\n"; - - exit ( 1 ); - -} -*/ - // // done // @@ -259,10 +214,6 @@ void MtdConfigInfo::process_config(GrdFileType ftype, GrdFileType otype) bool status = false; double sum; - // Dump the contents of the config file - - // if(mlog.verbosity_level() >= 5) conf.dump(cout); - // Initialize clear(); @@ -298,19 +249,6 @@ void MtdConfigInfo::process_config(GrdFileType ftype, GrdFileType otype) fcst_info->set_dict(*(fcst_dict->lookup_dictionary(conf_key_field))); obs_info->set_dict(*(obs_dict->lookup_dictionary(conf_key_field))); - // Dump the contents of the VarInfo objects -// -// if(mlog.verbosity_level() >= 5) { -// mlog << Debug(5) -// << "Parsed forecast field:\n"; -// fcst_info->dump(cout); -// mlog << Debug(5) -// << "Parsed observation field:\n"; -// obs_info->dump(cout); -// } -// - - // No support for wind direction if(fcst_info->is_wind_direction() || obs_info->is_wind_direction()) { @@ -350,68 +288,6 @@ void MtdConfigInfo::process_config(GrdFileType ftype, GrdFileType otype) fcst_conv_thresh = fcst_dict->lookup_thresh(conf_key_conv_thresh); obs_conv_thresh = obs_dict->lookup_thresh(conf_key_conv_thresh); - // Conf: fcst.vld_thresh and obs.vld_thresh - - // fcst_vld_thresh = fcst_dict->lookup_double(conf_key_vld_thresh); - // obs_vld_thresh = obs_dict->lookup_double(conf_key_vld_thresh); - - // Conf: fcst.merge_thresh and obs.merge_thresh - - // fcst_merge_thresh = fcst_dict->lookup_thresh(conf_key_merge_thresh); - // obs_merge_thresh = obs_dict->lookup_thresh(conf_key_merge_thresh); - - // Conf: fcst.merge_flag and obs.merge_flag - - // fcst_merge_flag = int_to_mergetype(fcst_dict->lookup_int(conf_key_merge_flag)); - // obs_merge_flag = int_to_mergetype(obs_dict->lookup_int(conf_key_merge_flag)); - - // Conf: mask_missing_flag - - // mask_missing_flag = int_to_fieldtype(conf.lookup_int(conf_key_mask_missing_flag)); - - // Conf: match_flag - - // match_flag = int_to_matchtype(conf.lookup_int(conf_key_match_flag)); - - // Check that match_flag is set between 0 and 3 -/* - if(match_flag == MatchType::None && - (fcst_merge_flag != MergeType::None || obs_merge_flag != MergeType::None) ) { - mlog << Warning << "\nMtdConfigInfo::process_config() -> " - << "When matching is disabled (match_flag = " - << matchtype_to_string(match_flag) - << ") but merging is requested (fcst_merge_flag = " - << mergetype_to_string(fcst_merge_flag) - << ", obs_merge_flag = " - << mergetype_to_string(obs_merge_flag) - << ") any merging information will be discarded.\n\n"; - } -*/ - // Conf: max_centroid_dist - - // max_centroid_dist = conf.lookup_double(conf_key_max_centroid_dist); - - // Check that max_centroid_dist is > 0 -/* - if(max_centroid_dist <= 0) { - mlog << Warning << "\nMtdConfigInfo::process_config() -> " - << "max_centroid_dist (" << max_centroid_dist - << ") should be set > 0\n\n"; - } - -*/ - // Conf: mask.grid - -/* - mask_grid_name = conf.lookup_string(conf_key_mask_grid); - mask_grid_flag = int_to_fieldtype(conf.lookup_int(conf_key_mask_grid_flag)); - - // Conf: mask.poly - - mask_poly_name = conf.lookup_string(conf_key_mask_poly); - mask_poly_flag = int_to_fieldtype(conf.lookup_int(conf_key_mask_poly_flag)); -*/ - // Conf: weight dict = conf.lookup_dictionary(conf_key_weight); @@ -494,20 +370,6 @@ void MtdConfigInfo::process_config(GrdFileType ftype, GrdFileType otype) exit(1); } - // Conf: print_interest_thresh - - // print_interest_thresh = conf.lookup_double(conf_key_print_interest_thresh); - - // Check that print_interest_thresh is between 0 and 1. -/* - if(print_interest_thresh < 0 || print_interest_thresh > 1) { - mlog << Error << "\nMtdConfigInfo::process_config() -> " - << "print_interest_thresh (" << print_interest_thresh - << ") must be set between 0 and 1.\n\n"; - exit(1); - } -*/ - // Conf: nc_pairs_flag parse_nc_info(); @@ -516,10 +378,6 @@ void MtdConfigInfo::process_config(GrdFileType ftype, GrdFileType otype) parse_txt_info(); - // Conf: ct_stats_flag - - // ct_stats_flag = conf.lookup_bool(conf_key_ct_stats_flag); - // Conf: output_prefix output_prefix = conf.lookup_string(conf_key_output_prefix); @@ -564,8 +422,8 @@ e = conf.lookup(conf_key_nc_output); if ( !e ) { - mlog << Error - << "\n\n MtdConfigInfo::parse_nc_info() -> lookup failed for key \"" + mlog << Error << "\nMtdConfigInfo::parse_nc_info() -> " + << "lookup failed for key \"" << conf_key_nc_output << "\"\n\n"; exit ( 1 ); @@ -590,11 +448,9 @@ if ( type == BooleanType ) { if ( type != DictionaryType ) { - mlog << Error - << "\n\n MtdConfigInfo::parse_nc_info() -> bad type (" - << configobjecttype_to_string(type) - << ") for key \"" - << conf_key_nc_pairs_flag << "\"\n\n"; + mlog << Error << "\nMtdConfigInfo::parse_nc_info() -> " + << "bad type (" << configobjecttype_to_string(type) + << ") for key \"" << conf_key_nc_pairs_flag << "\"\n\n"; exit ( 1 ); @@ -608,10 +464,8 @@ Dictionary * d = e->dict_value(); nc_info.do_latlon = d->lookup_bool(conf_key_latlon_flag); nc_info.do_raw = d->lookup_bool(conf_key_raw_flag); -// nc_info.do_object_raw = d->lookup_bool(conf_key_object_raw_flag); nc_info.do_object_id = d->lookup_bool(conf_key_object_id_flag); nc_info.do_cluster_id = d->lookup_bool(conf_key_cluster_id_flag); -// nc_info.do_polylines = d->lookup_bool(conf_key_do_polylines_flag); // // done @@ -638,9 +492,8 @@ e = conf.lookup(key); if ( !e ) { - mlog << Error - << "\n\n MtdConfigInfo::parse_txt_info() -> lookup failed for key \"" - << key << "\"\n\n"; + mlog << Error << "\nMtdConfigInfo::parse_txt_info() -> " + << "lookup failed for key \"" << key << "\"\n\n"; exit ( 1 ); @@ -654,11 +507,9 @@ const ConfigObjectType type = e->type(); if ( type != DictionaryType ) { - mlog << Error - << "\n\n MtdConfigInfo::parse_txt_info() -> bad type (" - << configobjecttype_to_string(type) - << ") for key \"" - << key << "\"\n\n"; + mlog << Error << "\nMtdConfigInfo::parse_txt_info() -> " + << "bad type (" << configobjecttype_to_string(type) + << ") for key \"" << key << "\"\n\n"; exit ( 1 ); @@ -851,7 +702,6 @@ bool MtdNcOutInfo::all_false() const { -// bool status = do_latlon || do_raw || do_object_raw || do_object_id || do_cluster_id || do_polylines; bool status = do_latlon || do_raw || do_object_id || do_cluster_id; return !status; @@ -868,10 +718,8 @@ void MtdNcOutInfo::set_all_false() do_latlon = false; do_raw = false; -// do_object_raw = false; do_object_id = false; do_cluster_id = false; -// do_polylines = false; return; @@ -887,10 +735,8 @@ void MtdNcOutInfo::set_all_true() do_latlon = true; do_raw = true; -// do_object_raw = true; do_object_id = true; do_cluster_id = true; -// do_polylines = true; return; diff --git a/src/tools/other/mode_time_domain/mtd_file_base.cc b/src/tools/other/mode_time_domain/mtd_file_base.cc index 8bb5abd972..f46a43392b 100644 --- a/src/tools/other/mode_time_domain/mtd_file_base.cc +++ b/src/tools/other/mode_time_domain/mtd_file_base.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -23,11 +22,11 @@ #include "mtd_file.h" #include "mtd_partition.h" #include "mtd_nc_defs.h" -#include "nc_grid.h" -#include "nc_utils_local.h" #include "mtdfiletype_to_string.h" +#include "get_met_grid.h" #include "vx_math.h" +#include "vx_nc_util.h" using namespace std; using namespace netCDF; @@ -179,8 +178,6 @@ if ( G ) { G->dump(out, depth + 1); - // out << prefix << (G->xml_serialize()) << '\n'; - } else { out << prefix << "Grid = 0\n"; @@ -238,7 +235,8 @@ Grid MtdFileBase::grid() const if ( !G ) { - mlog << Error << "\n\n MtdFileBase::grid() const -> no grid!\n\n"; + mlog << Error << "\nMtdFileBase::grid() const -> " + << "no grid!\n\n"; exit ( 1 ); @@ -271,7 +269,8 @@ void MtdFileBase::latlon_to_xy(double lat, double lon, double & x, double & y) c if ( !G ) { - mlog << Error << "\n\n MtdFileBase::latlon_to_xy() -> no grid!\n\n"; + mlog << Error << "\nMtdFileBase::latlon_to_xy() -> " + << "no grid!\n\n"; exit ( 1 ); @@ -333,7 +332,8 @@ void MtdFileBase::xy_to_latlon(double x, double y, double & lat, double & lon) c if ( !G ) { - mlog << Error << "\n\n MtdFileBase::xy_to_latlon() -> no grid!\n\n"; + mlog << Error << "\nMtdFileBase::xy_to_latlon() -> " + << "no grid!\n\n"; exit ( 1 ); @@ -355,7 +355,8 @@ unixtime MtdFileBase::valid_time(int t) const if ( (t < 0) || ( t >= Nt) ) { - mlog << Error << "\n\n MtdFileBase::valid_time(int t) -> range check error\n\n"; + mlog << Error << "\nMtdFileBase::valid_time(int t) -> " + << "range check error\n\n"; exit ( 1 ); @@ -375,7 +376,8 @@ unixtime MtdFileBase::actual_valid_time(int t) const if ( (t < 0) || ( t >= (int)ActualValidTimes.size()) ) { - mlog << Error << "\n\n MtdFileBase::valid_time(int t) -> range check error\n\n"; + mlog << Error << "\nMtdFileBase::valid_time(int t) -> " + << "range check error\n\n"; exit ( 1 ); @@ -395,7 +397,8 @@ int MtdFileBase::lead_time(int index) const if ( (index < 0) || ( index >= Nt) ) { - mlog << Error << "\n\n MtdFileBase::lead_time(int t) -> range check error\n\n"; + mlog << Error << "\nMtdFileBase::lead_time(int t) -> " + << "range check error\n\n"; exit ( 1 ); @@ -413,7 +416,6 @@ void MtdFileBase::read(NcFile & f) { -//NcDim * dim = 0; NcDim dim; // Nx, Ny, Nt @@ -427,40 +429,40 @@ Ny = GET_NC_SIZE(dim); dim = get_nc_dim(&f, nt_dim_name); Nt = GET_NC_SIZE(dim); -//dim = 0; - // Grid G = new Grid; -read_nc_grid(f, *G); +read_netcdf_grid(&f, *G); // timestamp info -StartValidTime = parse_start_time(string_att(f, start_time_att_name)); +ConcatString s; + +get_att_value_string(&f, start_time_att_name, s); + +StartValidTime = timestring_to_unix(s.text()); -DeltaT = string_att_as_int (f, delta_t_att_name); +DeltaT = get_att_value_int(&f, delta_t_att_name); // FileType -// ConcatString s = (string)string_att(f, filetype_att_name); -ConcatString s; bool status = false; -s.add(string_att(f, filetype_att_name)); +get_att_value_string(&f, filetype_att_name, s); status = string_to_mtdfiletype(s.text(), FileType); if ( ! status ) { - mlog << Error << "\n\n MtdFileBase::read(NcFile &) -> unable to parse filetype string \"" + mlog << Error << "\nMtdFileBase::read(NcFile &) -> " + << "unable to parse filetype string \"" << s << "\"\n\n"; exit ( 1 ); } - // // done // @@ -480,19 +482,20 @@ void MtdFileBase::write(NcFile & f) const char junk[256]; ConcatString s; - // Nx, Ny, Nt + // Add the time dimension -add_dim(&f, nx_dim_name, Nx); -add_dim(&f, ny_dim_name, Ny); add_dim(&f, nt_dim_name, Nt); // Grid -write_nc_grid(f, *G); +NcDim ny_dim; +NcDim nx_dim; + +write_netcdf_proj(&f, *G, ny_dim, nx_dim); // timestamp info -s = start_time_string(StartValidTime); +s = unix_to_yyyymmdd_hhmmss(StartValidTime); add_att(&f, start_time_att_name, s.text()); @@ -508,7 +511,6 @@ s = mtdfiletype_to_string(FileType); add_att(&f, filetype_att_name, s.text()); - // // done // @@ -527,8 +529,8 @@ void MtdFileBase::set_lead_time(int index, int value) if ( (index < 0) || (index >= Nt) ) { - mlog << Error - << "MtdFileBase::set_lead_time(int index, int value) -> range check error on index ... " + mlog << Error << "MtdFileBase::set_lead_time(int index, int value) -> " + << "range check error on index ... " << index << "\n\n"; exit ( 1 ); @@ -553,7 +555,3 @@ return; //////////////////////////////////////////////////////////////////////// - - - - diff --git a/src/tools/other/mode_time_domain/mtd_file_float.cc b/src/tools/other/mode_time_domain/mtd_file_float.cc index f76f349aa0..bdfacb4e46 100644 --- a/src/tools/other/mode_time_domain/mtd_file_float.cc +++ b/src/tools/other/mode_time_domain/mtd_file_float.cc @@ -24,9 +24,9 @@ #include "mtd_file.h" #include "mtd_partition.h" #include "mtd_nc_defs.h" -#include "nc_utils_local.h" #include "vx_math.h" +#include "vx_nc_util.h" using namespace std; using namespace netCDF; @@ -168,7 +168,6 @@ if ( f.Data ) { } - // // done // @@ -255,7 +254,8 @@ void MtdFloatFile::set_spatial_radius(int spatial_r) if ( spatial_r < 0 ) { - mlog << Error << "\n\n MtdFloatFile::set_spatial_radius(int) -> bad value ... " << spatial_r << "\n\n"; + mlog << Error << "\nMtdFloatFile::set_spatial_radius(int) -> " + << "bad value ... " << spatial_r << "\n\n"; exit ( 1 ); @@ -277,7 +277,8 @@ void MtdFloatFile::set_time_window(int beg, int end) if ( end < beg ) { - mlog << Error << "\n\n MtdFloatFile::set_time_window(int) -> bad values ... " << beg << " and " << end << "\n\n"; + mlog << Error << "\nMtdFloatFile::set_time_window(int) -> " + << "bad values ... " << beg << " and " << end << "\n\n"; exit ( 1 ); @@ -317,7 +318,8 @@ void MtdFloatFile::put(const DataPlane & plane, const int t) if ( (plane.nx() != Nx) || (plane.ny() != Ny) ) { - mlog << Error << "\n\n MtdFloatFile::put(const DataPlane &, const int) -> plane wrong size!\n\n"; + mlog << Error << "\nMtdFloatFile::put(const DataPlane &, const int) -> " + << "plane wrong size!\n\n"; exit ( 1 ); @@ -325,7 +327,8 @@ if ( (plane.nx() != Nx) || (plane.ny() != Ny) ) { if ( (t < 0) || (t >= Nt) ) { - mlog << Error << "\n\n MtdFloatFile::put(const DataPlane &, const int) -> bad time\n\n"; + mlog << Error << "\nMtdFloatFile::put(const DataPlane &, const int) -> " + << "bad time\n\n"; exit ( 1 ); @@ -359,8 +362,6 @@ for (x=0; x no data!\n\n"; + mlog << Error << "\nMtdFloatFile::threshold(double, MtdIntFile &) const -> " + << "no data!\n\n"; exit ( 1 ); @@ -542,7 +544,8 @@ void MtdFloatFile::threshold(const SingleThresh & t, MtdIntFile & out) const if ( !Data ) { - mlog << Error << "\n\n MtdFloatFile::threshold(double, MtdIntFile &) const -> no data!\n\n"; + mlog << Error << "\nMtdFloatFile::threshold(double, MtdIntFile &) const -> " + << "no data!\n\n"; exit ( 1 ); @@ -592,7 +595,6 @@ out.set_threshold(-9999.0); out.set_filetype(mtd_file_mask); - // // done // @@ -629,11 +631,9 @@ void MtdFloatFile::read(NcFile & f) { -//NcVar * var = 0; NcVar var; - // // read the base class stuff // @@ -642,8 +642,8 @@ MtdFileBase::read(f); // DataMin, DataMax -DataMin = string_att_as_double (f, min_value_att_name); -DataMax = string_att_as_double (f, max_value_att_name); +DataMin = (float) get_att_value_double(&f, min_value_att_name); +DataMax = (float) get_att_value_double(&f, max_value_att_name); // Data @@ -651,24 +651,6 @@ set_size(Nx, Ny, Nt); var = get_nc_var(&f, data_field_name); -//if ( !(var->set_cur(0, 0, 0)) ) { -// -// mlog << Error << "\n\n MtdFloatFile::read() -> trouble setting corner\n\n"; -// -// exit ( 1 ); -// -//} -// -//// const time_t t_start = time(0); // for timing the data read operation -// -//if ( ! (var->get(Data, Nt, Ny, Nx)) ) { -// -// mlog << Error << "\n\n MtdFloatFile::read(const char *) -> trouble getting data\n\n"; -// -// exit ( 1 ); -// -//} - LongArray offsets; // {0,0,0}; LongArray lengths; // {Nt, Ny, Nx}; @@ -679,19 +661,15 @@ lengths.add(Nt); lengths.add(Ny); lengths.add(Nx); -//if ( ! get_nc_data(&var, Data, (long *){Nt, Ny, Nx}, (long *){0,0,0}) ) { if ( ! get_nc_data(&var, Data, lengths, offsets) ) { - mlog << Error << "\n\n MtdFloatFile::read(const char *) -> trouble getting data\n\n"; + mlog << Error << "\nMtdFloatFile::read(const char *) -> " + << "trouble getting data\n\n"; exit ( 1 ); } -// const time_t t_stop = time(0); // for timing the data read operation - -// mlog << Debug(5) << "\n\n MtdFloatFile::read(): Time to read data = " << (t_stop - t_start) << " seconds\n\n" << flush; - // // done // @@ -708,13 +686,9 @@ void MtdFloatFile::write(NcFile & f) const { -//NcDim * nx_dim = 0; -//NcDim * ny_dim = 0; -//NcDim * nt_dim = 0; NcDim nx_dim; NcDim ny_dim; NcDim nt_dim; -//NcVar * data_var = 0; NcVar data_var ; const char format [] = "%.3f"; char junk[256]; @@ -764,24 +738,6 @@ add_var(&f, data_field_name, ncFloat, nt_dim, ny_dim, nx_dim); data_var = get_nc_var(&f, data_field_name); -//if ( !(data_var->set_cur(0, 0, 0)) ) { -// -// mlog << Error << "\n\n MtdFloatFile::write() -> trouble setting corner on data field\n\n"; -// -// exit ( 1 ); -// -//} -// -//// const time_t t_start = time(0); // for timing the data write operation -// -//if ( !(data_var->put(Data, Nt, Ny, Nx)) ) { -// -// mlog << Error << "\n\n MtdFloatFile::write() -> trouble with put in data field\n\n"; -// -// exit ( 1 ); -// -//} - LongArray offsets; // {0,0,0}; LongArray lengths; // {Nt, Ny, Nx}; @@ -792,19 +748,15 @@ lengths.add(Nt); lengths.add(Ny); lengths.add(Nx); -//if ( ! get_nc_data(&data_var, Data, (long *){Nt, Ny, Nx}, (long *){0,0,0}) ) { if ( ! get_nc_data(&data_var, Data, lengths, offsets) ) { - mlog << Error << "\n\n MtdFloatFile::read(const char *) -> trouble getting data\n\n"; + mlog << Error << "\nMtdFloatFile::read(const char *) -> " + << "trouble getting data\n\n"; exit ( 1 ); } -// const time_t t_stop = time(0); // for timing the data write operation - -// mlog << Debug(5) << "\n\n MtdFloatFile::write(): Time to write data = " << (t_stop - t_start) << " seconds\n\n" << flush; - // // done // @@ -825,11 +777,10 @@ NcFile f(_filename, NcFile::replace); if ( IS_INVALID_NC(f) ) { - mlog << Error << "\n\n MtdFloatFile::write(const char *) -> unable to open netcdf output file \"" << _filename << "\"\n\n"; + mlog << Error << "\nMtdFloatFile::write(const char *) -> " + << "unable to open netcdf output file: " << _filename << "\n\n"; - // exit ( 1 ); - - return; + exit ( 1 ); } @@ -853,7 +804,8 @@ MtdFloatFile MtdFloatFile::const_t_slice(int t) const if ( (t < 0) || (t >= Nt) ) { - mlog << Error << "\n\n MtdFloatFile MtdFloatFile::const_t_slice(int) const -> range check error\n\n"; + mlog << Error << "\nMtdFloatFile MtdFloatFile::const_t_slice(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -921,7 +873,8 @@ void MtdFloatFile::get_data_plane(const int t, DataPlane & out) if ( (t < 0) || (t >= Nt) ) { - mlog << Error << "\n\n MtdFloatFile::get_data_plane() -> range check error on t\n\n"; + mlog << Error << "\nMtdFloatFile::get_data_plane() -> " + << "range check error on t\n\n"; exit ( 1 ); @@ -956,9 +909,6 @@ for (x=0; x= Nt) ) { - mlog << Error << "\n\n " << method_name << "range check error on t\n\n"; + mlog << Error << "\n" << method_name + << "range check error on t\n\n"; exit ( 1 ); @@ -985,7 +937,8 @@ if ( (t < 0) || (t >= Nt) ) { if ( (d.nx() != Nx) || (d.ny() != Ny) ) { - mlog << Error << "\n\n " << method_name << "data plane is wrong size!\n\n"; + mlog << Error << "\n" << method_name + << "data plane is wrong size!\n\n"; exit ( 1 ); @@ -1002,8 +955,9 @@ for (x=0; x=data_cnt) { - mlog << Debug(4) << method_name << "offset " << n - << " is out of range (" << " from " << x << ", " << y <<", " << t <<")\n"; + mlog << Debug(4) << method_name + << "offset " << n << " is out of range (from " + << x << ", " << y <<", " << t <<")\n"; continue; } @@ -1085,7 +1039,3 @@ return; //////////////////////////////////////////////////////////////////////// - - - - diff --git a/src/tools/other/mode_time_domain/mtd_file_int.cc b/src/tools/other/mode_time_domain/mtd_file_int.cc index 92f6e214a6..2cbe00e400 100644 --- a/src/tools/other/mode_time_domain/mtd_file_int.cc +++ b/src/tools/other/mode_time_domain/mtd_file_int.cc @@ -24,9 +24,9 @@ #include "mtd_file.h" #include "mtd_partition.h" #include "mtd_nc_defs.h" -#include "nc_utils_local.h" #include "vx_math.h" +#include "vx_nc_util.h" using namespace std; using namespace netCDF; @@ -302,7 +302,8 @@ void MtdIntFile::set_radius(int r) if ( r < 0 ) { - mlog << Error << "\n MtdIntFile::set_radius(int) -> bad value ... " << r << "\n\n"; + mlog << Error << "\nMtdIntFile::set_radius(int) -> " + << "bad value ... " << r << "\n\n"; exit ( 1 ); @@ -325,7 +326,8 @@ void MtdIntFile::set_time_window(int beg, int end) if ( end < beg ) { - mlog << Error << "\n MtdIntFile::set_time_window(int) -> bad values ... " << beg << " and " << end << "\n\n"; + mlog << Error << "\nMtdIntFile::set_time_window(int) -> " + << "bad values ... " << beg << " and " << end << "\n\n"; exit ( 1 ); @@ -347,14 +349,6 @@ void MtdIntFile::set_threshold(double t) { -// if ( t < 0.0 ) { -// -// mlog << Error << "\n MtdIntFile::set_threshold(double) -> bad value ... " << t << "\n\n"; -// -// exit ( 1 ); -// -// } - Threshold = t; return; @@ -421,11 +415,8 @@ void MtdIntFile::read(NcFile & f) { -//NcVar * var = 0; NcVar var ; - - // // read the base class stuff // @@ -434,8 +425,8 @@ MtdFileBase::read(f); // DataMin, DataMax -DataMin = string_att_as_double (f, min_value_att_name); -DataMax = string_att_as_double (f, max_value_att_name); +DataMin = get_att_value_int(&f, min_value_att_name); +DataMax = get_att_value_int(&f, max_value_att_name); // Data @@ -443,24 +434,6 @@ set_size(Nx, Ny, Nt); var = get_nc_var(&f, data_field_name); -//if ( !(var->set_cur(0, 0, 0)) ) { -// -// mlog << Error << "\n MtdIntFile::read() -> trouble setting corner\n\n"; -// -// exit ( 1 ); -// -//} -// -//// const time_t t_start = time(0); // for timing the data read operation -// -//if ( ! (var->get(Data, Nt, Ny, Nx)) ) { -// -// mlog << Error << "\n MtdIntFile::read(const char *) -> trouble getting data\n\n"; -// -// exit ( 1 ); -// -//} - LongArray offsets; // {0,0,0}; LongArray lengths; // {Nt, Ny, Nx}; @@ -471,19 +444,15 @@ lengths.add(Nt); lengths.add(Ny); lengths.add(Nx); -//if ( ! get_nc_data(&var, Data, (long *){Nt, Ny, Nx}, (long *){0,0,0}) ) { if ( ! get_nc_data(&var, Data, lengths, offsets) ) { - mlog << Error << "\n MtdIntFile::read(const char *) -> trouble getting data\n\n"; + mlog << Error << "\nMtdIntFile::read(const char *) -> " + << "trouble getting data\n\n"; exit ( 1 ); } -// const time_t t_stop = time(0); // for timing the data read operation - -// mlog << Debug(5) << "\n MtdIntFile::read(): Time to read data = " << (t_stop - t_start) << " seconds\n\n" << flush; - // // done // @@ -500,23 +469,16 @@ void MtdIntFile::write(NcFile & f) const { -//NcDim * nx_dim = 0; -//NcDim * ny_dim = 0; -//NcDim * nt_dim = 0; -//NcDim * n_obj_dim = 0; -NcDim nx_dim ; -NcDim ny_dim ; -NcDim nt_dim ; +NcDim nx_dim; +NcDim ny_dim; +NcDim nt_dim; NcDim n_obj_dim; -//NcVar * data_var = 0; -//NcVar * volumes_var = 0; -NcVar data_var ; -NcVar volumes_var ; +NcVar data_var; +NcVar volumes_var; const char format [] = "%d"; char junk[256]; const bool is_split = (ObjVolume != 0); - // // write stuff from parent class // @@ -571,8 +533,6 @@ add_att(&f, threshold_att_name, Threshold); data_var = add_var(&f, data_field_name, ncInt, nt_dim, ny_dim, nx_dim); -//data_var = get_nc_var(&f, data_field_name); - LongArray offsets; // {0,0,0}; LongArray lengths; // {Nt, Ny, Nx}; @@ -585,30 +545,13 @@ lengths.add(Nx); if ( ! put_nc_data(&data_var, Data, lengths, offsets) ) { - mlog << Error << "\n MtdIntFile::write(const char *) -> trouble getting data\n\n"; + mlog << Error << "\nMtdIntFile::write(const char *) -> " + << "trouble getting data\n\n"; exit ( 1 ); } -//if ( !(data_var->set_cur(0, 0, 0)) ) { -// -// mlog << Error << "\n MtdIntFile::write() -> trouble setting corner on data field\n\n"; -// -// exit ( 1 ); -// -//} -// -//// const time_t t_start = time(0); // for timing the data write operation -// -//if ( !(data_var->put(Data, Nt, Ny, Nx)) ) { -// -// mlog << Error << "\n MtdIntFile::write() -> trouble writing data field\n\n"; -// -// exit ( 1 ); -// -//} - // // volumes, if needed // @@ -617,11 +560,10 @@ if ( is_split ) { volumes_var = add_var(&f, volumes_name, ncInt, n_obj_dim); - //volumes_var = get_nc_var(&f, volumes_name); - if ( !(put_nc_data(&volumes_var, ObjVolume, Nobjects, 0)) ) { - mlog << Error << "\n MtdIntFile::write() -> trouble writing object volumes\n\n"; + mlog << Error << "\nMtdIntFile::write() -> " + << "trouble writing object volumes\n\n"; exit ( 1 ); @@ -629,10 +571,6 @@ if ( is_split ) { } // if is_split -// const time_t t_stop = time(0); // for timing the data write operation - -// mlog << Debug(5) << "\n MtdIntFile::write(): Time to write data = " << (t_stop - t_start) << " seconds\n\n" << flush; - // // done // @@ -653,7 +591,8 @@ NcFile f(_filename, NcFile::replace); if ( IS_INVALID_NC(f) ) { - mlog << Error << "\n MtdIntFile::write(const char *) -> unable to open netcdf output file \"" << _filename << "\"\n\n"; + mlog << Error << "\nMtdIntFile::write(const char *) -> " + << "unable to open netcdf output file: " << _filename << "\n\n"; // exit ( 1 ); @@ -681,7 +620,8 @@ MtdIntFile MtdIntFile::const_t_slice(const int t) const if ( (t < 0) || (t >= Nt) ) { - mlog << Error << "\n MtdIntFile MtdIntFile::const_t_slice(int) const -> range check error\n\n"; + mlog << Error << "\nMtdIntFile MtdIntFile::const_t_slice(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -750,7 +690,8 @@ MtdIntFile MtdIntFile::const_t_mask(const int t, const int obj_num) const // if ( (t < 0) || (t >= Nt) ) { - mlog << Error << "\n MtdIntFile MtdIntFile::const_t_mask(int) const -> range check error\n\n"; + mlog << Error << "\nMtdIntFile MtdIntFile::const_t_mask(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -938,7 +879,8 @@ void MtdIntFile::zero_border(int n) if ( !Data ) { - mlog << Error << "\n MtdIntFile::zero_border(int) -> no data field!\n\n"; + mlog << Error << "\nMtdIntFile::zero_border(int) -> " + << "no data field!\n\n"; exit ( 1 ); @@ -946,7 +888,8 @@ if ( !Data ) { if ( 2*n >= min(Nx, Ny) ) { - mlog << Error << "\n MtdIntFile::zero_border(int) -> border size too large!\n\n"; + mlog << Error << "\nMtdIntFile::zero_border(int) -> " + << "border size too large!\n\n"; exit ( 1 ); @@ -999,7 +942,8 @@ void MtdIntFile::set_to_zeroes() if ( !Data ) { - mlog << Error << "\n MtdIntFile::set_to_zeroes() -> no data!\n\n"; + mlog << Error << "\nMtdIntFile::set_to_zeroes() -> " + << "no data!\n\n"; exit ( 1 ); @@ -1025,7 +969,8 @@ MtdIntFile MtdIntFile::split_const_t(int & n_shapes) const if ( Nt != 1 ) { - mlog << Error << "\n split_const_t(int &) -> not const-time slice!\n\n"; + mlog << Error << "\nsplit_const_t(int &) -> " + << "not const-time slice!\n\n"; exit ( 1 ); @@ -1041,7 +986,6 @@ Mtd_Partition p; const MtdIntFile & id = *this; - d.set_size(Nx, Ny, 1); d.set_grid(*G); @@ -1261,7 +1205,8 @@ int MtdIntFile::volume(int k) const if ( !ObjVolume ) { - mlog << Error << "\n MtdIntFile::volume(int) -> field not split!\n\n"; + mlog << Error << "\nMtdIntFile::volume(int) -> " + << "field not split!\n\n"; exit ( 1 ); @@ -1269,7 +1214,8 @@ if ( !ObjVolume ) { if ( (k < 0) || (k >= Nobjects) ) { - mlog << Error << "\n MtdIntFile::volume(int) -> range check error!\n\n"; + mlog << Error << "\nMtdIntFile::volume(int) -> " + << "range check error!\n\n"; exit ( 1 ); @@ -1290,7 +1236,8 @@ int MtdIntFile::total_volume() const if ( !ObjVolume ) { - mlog << Error << "\n MtdIntFile::total_volume() -> field not split!\n\n"; + mlog << Error << "\nMtdIntFile::total_volume() -> " + << "field not split!\n\n"; exit ( 1 ); @@ -1354,21 +1301,8 @@ int j, k; const int n3 = Nx*Ny*Nt; int * old_to_new = (int *) nullptr; int * new_volumes = (int *) nullptr; -// double * new_intensities = (double *) nullptr; int * d = Data; - -// if ( n_new == 0 ) { -// -// mlog << Error << "\n MtdIntFile::sift_objects() -> no objects left!\n\n"; -// -// exit ( 1 ); -// -// } - - - - if ( n_new > 0 ) { old_to_new = new int [Nobjects]; @@ -1381,17 +1315,12 @@ if ( n_new > 0 ) { new_volumes[j] = ObjVolume[new_to_old[j]]; - // new_intensities[j] = MaxConvIntensity[new_to_old[j]]; - } for (j=0; j 0 ) { } -// mlog << Debug(5) << "replace count = " << replace_count << '\n' << flush; -// mlog << Debug(5) << "zero count = " << zero_count << '\n' << flush; - // // rewire // @@ -1539,7 +1465,8 @@ for (x=0; x empty object!\n\n"; + mlog << Error << "\nMtdIntFile::calc_3d_centroid() const -> " + << "empty object!\n\n"; exit ( 1 ); @@ -1587,15 +1514,7 @@ for (x=0; x empty object!\n\n"; - - // exit ( 1 ); - - return; - -} +if ( count == 0 ) return; xbar /= count; ybar /= count; @@ -1641,7 +1560,8 @@ MtdIntFile MtdIntFile::select(int n) const // 1-based if ( (n < 1) || (n > Nobjects) ) { - mlog << Error << "\n MtdIntFile::select(int) -> range check error on n ... " + mlog << Error << "\nMtdIntFile::select(int) -> " + << "range check error on n ... " << "NObjects = " << Nobjects << " ... " << "n = " << n << "\n\n"; @@ -1693,7 +1613,8 @@ MtdIntFile MtdIntFile::select_cluster(const IntArray & a) const // 1-based if ( (a.min() < 0) || (a.max() > Nobjects) ) { - mlog << Error << "\n MtdIntFile::select_cluster(const IntArray &) -> range check error\n\n"; + mlog << Error << "\nMtdIntFile::select_cluster(const IntArray &) -> " + << "range check error\n\n"; exit ( 1 ); @@ -1757,7 +1678,8 @@ int MtdIntFile::x_left(const int y) const if ( (y < 0) || (y >= Ny) ) { - mlog << Error << "\n MtdIntFile::x_left(int) -> range check error\n\n"; + mlog << Error << "\nMtdIntFile::x_left(int) -> " + << "range check error\n\n"; exit ( 1 ); @@ -1786,7 +1708,8 @@ int MtdIntFile::x_right(const int y) const if ( (y < 0) || (y >= Ny) ) { - mlog << Error << "\n MtdIntFile::x_right(int) -> range check error\n\n"; + mlog << Error << "\nMtdIntFile::x_right(int) -> " + << "range check error\n\n"; exit ( 1 ); @@ -1875,7 +1798,8 @@ Mtd_2D_Moments MtdIntFile::calc_2d_moments() const if ( Nt != 1 ) { - mlog << Error << "\n MtdIntFile::calc_2d_moments() const -> not a 2D object!\n\n"; + mlog << Error << "\nMtdIntFile::calc_2d_moments() const -> " + << "not a 2D object!\n\n"; exit ( 1 ); @@ -1936,9 +1860,6 @@ MtdIntFile after; MtdIntFile rv; Mtd_Partition p; const int zero_border_size = 2; -// int imin, imax; - - // // find the partition @@ -1979,8 +1900,6 @@ for (j=1; j<(mask.nt()); ++j) { } -// p.dump(cout); - n_shapes = p.n_elements(); // @@ -2017,7 +1936,8 @@ for (t=0; t<(mask.nt()); ++t) { if ( nc < 0 ) { - mlog << Error << "\n split(const MtdIntFile &, int &) -> can't find cell!\n\n"; + mlog << Error << "\nsplit(const MtdIntFile &, int &) -> " + << "can't find cell!\n\n"; exit ( 1 ); @@ -2051,7 +1971,8 @@ void adjust_obj_numbers(MtdIntFile & s, int delta) if ( s.nt() != 1 ) { - mlog << Error << "\n adjust_obj_numbers() -> not const-time slice!\n\n"; + mlog << Error << "\nadjust_obj_numbers() -> " + << "not const-time slice!\n\n"; exit ( 1 ); @@ -2106,8 +2027,6 @@ for (x=0; x trouble opening output file \"" - << output_filename << "\"\n\n"; + mlog << Error << "\ndo_mtd_nc_output() -> " + << "trouble opening output file: " + << output_filename << "\n\n"; exit ( 1 ); @@ -68,11 +69,9 @@ const bool have_pairs = (fcst_obj.n_objects() != 0) && ( obs_obj.n_objects() != 0); // - // dimensions + // add time dimension // -nx_dim = add_dim(&out, nx_dim_name, fcst_raw.nx()); -ny_dim = add_dim(&out, ny_dim_name, fcst_raw.ny()); nt_dim = add_dim(&out, nt_dim_name, fcst_raw.nt()); // @@ -82,7 +81,7 @@ nt_dim = add_dim(&out, nt_dim_name, fcst_raw.nt()); write_netcdf_global(&out, output_filename, "MTD", config.model.c_str(), config.obtype.c_str(), config.desc.c_str()); -write_nc_grid(out, fcst_raw.grid()); +write_netcdf_proj(&out, fcst_raw.grid(), ny_dim, nx_dim); // // variables @@ -142,19 +141,18 @@ NcFile out(output_filename, NcFile::replace); if ( IS_INVALID_NC(out) ) { - mlog << Error << "\n\n do_mtd_nc_output[single]() -> trouble opening output file \"" - << output_filename << "\"\n\n"; + mlog << Error << "\ndo_mtd_nc_output[single]() -> " + << "trouble opening output file: " + << output_filename << "\n\n"; exit ( 1 ); } // - // dimensions + // add time dimension // -nx_dim = add_dim(&out, nx_dim_name, raw.nx()); -ny_dim = add_dim(&out, ny_dim_name, raw.ny()); nt_dim = add_dim(&out, nt_dim_name, raw.nt()); // @@ -164,7 +162,7 @@ nt_dim = add_dim(&out, nt_dim_name, raw.nt()); write_netcdf_global(&out, output_filename, "MTD", config.model.c_str(), config.obtype.c_str(), config.desc.c_str()); -write_nc_grid(out, raw.grid()); +write_netcdf_proj(&out, raw.grid(), ny_dim, nx_dim); // // variables @@ -220,7 +218,6 @@ add_att(&lon_var, "long_name", "Longitude"); float * lat_data = new float [nx*ny]; float * lon_data = new float [nx*ny]; - Lat = lat_data; Lon = lon_data; @@ -268,7 +265,7 @@ const int ny = raw.ny(); const int nt = raw.nt(); ConcatString s; -const char * const name = ( is_fcst ? fcst_raw_name : obs_raw_name ); +const string name = ( is_fcst ? fcst_raw_name : obs_raw_name ); NcVar var = add_var(&out, name, ncFloat, nt_dim, ny_dim, nx_dim); @@ -304,7 +301,7 @@ const int ny = id.ny(); const int nt = id.nt(); ConcatString s; -const char * const name = ( is_fcst ? fcst_obj_id_name : obs_obj_id_name ); +const string name = ( is_fcst ? fcst_obj_id_name : obs_obj_id_name ); NcVar var = add_var(&out, name, ncInt, nt_dim, ny_dim, nx_dim); @@ -319,7 +316,6 @@ long offsets[3] = {0,0,0}; long lengths[3] = {nt,ny, nx}; put_nc_data(&var, id.data(), lengths, offsets); - // // done // @@ -350,7 +346,7 @@ const int n3 = nx*ny*nt; out_data = new int [n3]; -const char * const name = ( is_fcst ? fcst_clus_id_name : obs_clus_id_name ); +const string name = ( is_fcst ? fcst_clus_id_name : obs_clus_id_name ); NcVar var = add_var(&out, name, ncInt, nt_dim, ny_dim, nx_dim); diff --git a/src/tools/other/mode_time_domain/mtd_nc_output.h b/src/tools/other/mode_time_domain/mtd_nc_output.h index c0aa4a5aa0..c0d8471b4f 100644 --- a/src/tools/other/mode_time_domain/mtd_nc_output.h +++ b/src/tools/other/mode_time_domain/mtd_nc_output.h @@ -19,8 +19,6 @@ #include "mtd_nc_defs.h" -#include "nc_grid.h" -#include "nc_utils_local.h" #include "mtd_file_float.h" #include "mtd_file_int.h" diff --git a/src/tools/other/mode_time_domain/mtd_partition.cc b/src/tools/other/mode_time_domain/mtd_partition.cc index 22bf007ef7..192ed95de9 100644 --- a/src/tools/other/mode_time_domain/mtd_partition.cc +++ b/src/tools/other/mode_time_domain/mtd_partition.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -199,28 +198,6 @@ return; } -//////////////////////////////////////////////////////////////////////// - -/* -bool EquivalenceClass::has(int k) const - -{ - -int j; -int * e = E; - -for (j=0; j= Nelements) ) { - mlog << Error << "\n\n EquivalenceClass::element(int) const -> range check error\n\n"; + mlog << Error << "\nEquivalenceClass::element(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -529,28 +507,6 @@ return; } -//////////////////////////////////////////////////////////////////////// - -/* -bool Mtd_Partition::has(int k) const - -{ - -int j; -EquivalenceClass ** c = C; - -for (j=0; jhas(k) ) return true; - -} - - -return false; - -} -*/ - //////////////////////////////////////////////////////////////////////// @@ -560,7 +516,8 @@ bool Mtd_Partition::has(int index, int k) const if ( (index < 0) || (index >= Nelements) ) { - mlog << Error << "\n\n Mtd_Partition::has(int index, int k) const -> range check error on index\n\n"; + mlog << Error << "\nMtd_Partition::has(int index, int k) const -> " + << "range check error on index\n\n"; exit ( 1 ); @@ -602,7 +559,8 @@ void Mtd_Partition::merge_classes(int nclass_1, int nclass_2) if ( (nclass_1 < 0) || (nclass_1 >= Nelements) || (nclass_2 < 0) || (nclass_2 >= Nelements) ) { - mlog << Error << "\n\n Mtd_Partition::merge_classes() -> range check error\n\n"; + mlog << Error << "\nMtd_Partition::merge_classes() -> " + << "range check error\n\n"; exit ( 1 ); @@ -662,7 +620,8 @@ nclass_2 = which_class(value_2); if ( (nclass_1 < 0) || (nclass_2 < 0) ) { - mlog << Error << "\n\n Mtd_Partition::merge_values() -> bad values ... " + mlog << Error << "\nMtd_Partition::merge_values() -> " + << "bad values ... " << "(value_1, value_2) = " << value_1 << ", " << value_2 << " ... " << "(nclass_1, nclass_2) = " << nclass_1 << ", " << nclass_2 << "\n\n"; @@ -711,7 +670,8 @@ const EquivalenceClass * Mtd_Partition::operator()(int k) const if ( (k < 0) || (k >= Nelements) ) { - mlog << Error << "\n\n Mtd_Partition::operator()(int) const -> range check error\n\n"; + mlog << Error << "\nMtd_Partition::operator()(int) const -> " + << "range check error\n\n"; exit ( 1 ); @@ -778,8 +738,6 @@ for (j=0; j mtd_read_data(MtdConfigInfo & config, VarInfo & varinfo, { +static const char *method_name = "mtd_read_data() -> "; + if ( filenames.n() < 2 ) { - mlog << Error << "\n\n mtd_read_data() -> need at least 2 data files!\n\n"; + mlog << Error << "\n" << method_name + << "need at least 2 data files!\n\n"; exit ( 1 ); @@ -52,14 +55,15 @@ vector valid_times; for (j=0; j<(filenames.n()); ++j) { - mlog << Debug(2) - << "mtd_read_data() -> processing file \"" << filenames[j] << "\"\n"; + mlog << Debug(2) << method_name + << "processing file: " << filenames[j] << "\n"; data_2d_file = factory.new_met_2d_data_file(filenames[j].c_str(), varinfo.file_type()); if ( ! data_2d_file->data_plane(varinfo, plane) ) { - mlog << Error << "\n\n mtd_read_data() -> unable to get data plane at time " << j << "\n\n"; + mlog << Error << "\n" << method_name + << "unable to get data plane at time " << j << "\n\n"; exit ( 1 ); @@ -67,7 +71,8 @@ for (j=0; j<(filenames.n()); ++j) { if ( ! data_2d_file->data_plane(varinfo, plane) ) { - mlog << Error << "\n\n mtd_read_data() -> unable to get data plane at time " << j << "\n\n"; + mlog << Error << "\n" << method_name + << "unable to get data plane at time " << j << "\n\n"; exit ( 1 ); @@ -157,9 +162,13 @@ if (variableTimeIncs) { unixtime umean = (unixtime)mean; unixtime uvar = (unixtime)var; unixtime suvar = (unixtime)svar; - mlog << Warning << "\n\n mtd_read_data() -> File time increments are not constant, could be problematic\n"; - mlog << Warning << " mtd_read_data() -> Using MODE of the increments, mode=" << dt_start << "\n"; - mlog << Warning << " mtd_read_data() -> Time increment properties: mean=" << umean << " variance=" << uvar << " sqrt(var)=" << suvar << "\n\n"; + mlog << Warning << "\n" << method_name + << "file time increments are not constant, could be problematic\n\n"; + mlog << Warning << "\n" << method_name + << "using MODE of the increments, mode=" << dt_start << "\n\n"; + mlog << Warning << "\n" << method_name + << "Time increment properties: mean=" << umean << " variance=" << uvar + << " sqrt(var)=" << suvar << "\n\n"; } } diff --git a/src/tools/other/mode_time_domain/mtd_txt_output.cc b/src/tools/other/mode_time_domain/mtd_txt_output.cc index f1ee61aa5d..b3f9ea14b4 100644 --- a/src/tools/other/mode_time_domain/mtd_txt_output.cc +++ b/src/tools/other/mode_time_domain/mtd_txt_output.cc @@ -7,7 +7,6 @@ // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// @@ -56,13 +55,13 @@ ofstream out; AsciiTable table; const int Nobj = fcst_att.n() + obs_att.n(); - out.open(output_filename); if ( ! out ) { - mlog << Error << "\n\n do_3d_single_txt_output() -> unable to open output filename \"" - << output_filename << "\'\n\n"; + mlog << Error << "\ndo_3d_single_txt_output() -> " + << "unable to open output filename: " + << output_filename << "\n\n"; exit ( 1 ); @@ -172,13 +171,13 @@ ofstream out; AsciiTable table; const int Nobj = att.n(); - out.open(output_filename); if ( ! out ) { - mlog << Error << "\n\n do_3d_single_txt_output[single]() -> unable to open output filename \"" - << output_filename << "\'\n\n"; + mlog << Error << "\ndo_3d_single_txt_output[single]() -> " + << "unable to open output filename: " + << output_filename << "\n\n"; exit ( 1 ); @@ -322,8 +321,9 @@ out.open(output_filename); if ( ! out ) { - mlog << Error << "\n\n do_3d_pair_txt_output() -> unable to open output filename \"" - << output_filename << "\'\n\n"; + mlog << Error << "\ndo_3d_pair_txt_output() -> " + << "unable to open output filename: " + << output_filename << "\n\n"; exit ( 1 ); @@ -415,13 +415,13 @@ ofstream out; AsciiTable table; const int n_total = fcst_simple_att.n() + obs_simple_att.n() + fcst_cluster_att.n() + obs_cluster_att.n(); - out.open(output_filename); if ( ! out ) { - mlog << Error << "\n\n do_2d_txt_output() -> unable to open output filename \"" - << output_filename << "\'\n\n"; + mlog << Error << "\ndo_2d_txt_output() -> " + << "unable to open output filename: " + << output_filename << "\n\n"; exit ( 1 ); @@ -613,13 +613,13 @@ ofstream out; AsciiTable table; const int n_total = att.n(); - out.open(output_filename); if ( ! out ) { - mlog << Error << "\n\n do_2d_txt_output[single]() -> unable to open output filename \"" - << output_filename << "\'\n\n"; + mlog << Error << "\ndo_2d_txt_output[single]() -> " + << "unable to open output filename: " + << output_filename << "\n\n"; exit ( 1 ); diff --git a/src/tools/other/mode_time_domain/mtdfiletype_to_string.cc b/src/tools/other/mode_time_domain/mtdfiletype_to_string.cc index e7a2ff1a4e..0208bf537e 100644 --- a/src/tools/other/mode_time_domain/mtdfiletype_to_string.cc +++ b/src/tools/other/mode_time_domain/mtdfiletype_to_string.cc @@ -73,6 +73,7 @@ else if ( strcmp(text, "mtd_file_conv" ) == 0 ) { t = mtd_file_conv; re else if ( strcmp(text, "mtd_file_mask" ) == 0 ) { t = mtd_file_mask; return true; } else if ( strcmp(text, "mtd_file_object" ) == 0 ) { t = mtd_file_object; return true; } else if ( strcmp(text, "no_mtd_file_type") == 0 ) { t = no_mtd_file_type; return true; } + // // nope // diff --git a/src/tools/other/mode_time_domain/nc_grid.cc b/src/tools/other/mode_time_domain/nc_grid.cc deleted file mode 100644 index e5865a1c4a..0000000000 --- a/src/tools/other/mode_time_domain/nc_grid.cc +++ /dev/null @@ -1,665 +0,0 @@ -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* -// ** Copyright UCAR (c) 1992 - 2024 -// ** University Corporation for Atmospheric Research (UCAR) -// ** National Center for Atmospheric Research (NCAR) -// ** Research Applications Lab (RAL) -// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - - - -//////////////////////////////////////////////////////////////////////// - - -#include -#include -#include -#include -#include -#include - -#include - -#include "nc_utils_local.h" -#include "nc_grid.h" - -using namespace std; -using namespace netCDF; - - -//////////////////////////////////////////////////////////////////////// - - -static bool read_nc_st_grid (NcFile &, Grid &); -static bool read_nc_lc_grid (NcFile &, Grid &); -static bool read_nc_latlon_grid (NcFile &, Grid &); - -static void write_nc_st_grid (NcFile &, const StereographicData &); -static void write_nc_lc_grid (NcFile &, const LambertData &); -static void write_nc_latlon_grid (NcFile &, const LatLonData &); - - -//////////////////////////////////////////////////////////////////////// - - -bool read_nc_grid(NcFile & f, Grid & g) - -{ - - bool status = false; - ConcatString proj; - //const ConcatString proj = string_att(f, "Projection"); - get_att_value_string(&f, (string)"Projection", proj); - - - g.clear(); - - - if ( proj == "Polar Stereographic" ) { - - status = read_nc_st_grid(f, g); - - } else if ( proj == "Lambert Conformal" ) { - - status = read_nc_lc_grid(f, g); - - } else if ( proj == "LatLon" ) { - - status = read_nc_latlon_grid(f, g); - - } else { - - mlog << Error << "\n\n read_nc_grid() -> haven't written code to parse \"" << proj << "\" grids yet!\n\n"; - - return false; - - } - - - // - // done - // - -return status; - -} - - -//////////////////////////////////////////////////////////////////////// - - -bool write_nc_grid(NcFile & f, const Grid & g) - -{ - -GridInfo info = g.info(); - -if ( !(info.ok()) ) { - - mlog << Error << "\n\n write_nc_grid(NcFile &, const Grid &) -> can't get information from grid!\n\n"; - - exit ( 1 ); - -} - - if ( info.st ) write_nc_st_grid (f, *(info.st)); -else if ( info.lc ) write_nc_lc_grid (f, *(info.lc)); -else if ( info.ll ) write_nc_latlon_grid (f, *(info.ll)); -else { - - mlog << Error << "\n\n bool write_nc_grid(NcFile &, const Grid &) -> unsupported projection type\n\n"; - - exit ( 1 ); - -} - - // - // done - // - -return false; - -} - - -//////////////////////////////////////////////////////////////////////// - - -bool read_nc_st_grid(NcFile & f, Grid & g) - -{ - - StereographicData data; - ConcatString c; - - // - // name - // - - data.name = "Unknown stereographic"; - - // - // hemisphere - // - - //c = string_att(f, "hemisphere"); - get_att_value_string(&f, (string)"hemisphere", c); - -data.hemisphere = c[0]; - - // - // scale latitude - // - -data.scale_lat = string_att_as_double(f, "scale_lat"); - - // - // lat/lon pin - // - -data.lat_pin = string_att_as_double(f, "lat_pin"); -data.lon_pin = string_att_as_double(f, "lon_pin"); - -data.lon_pin *= -1.0; - - // - // x/y pin - // - -data.x_pin = string_att_as_double(f, "x_pin"); -data.y_pin = string_att_as_double(f, "y_pin"); - - // - // orientation longitude - // - -data.lon_orient = string_att_as_double(f, "lon_orient"); - -data.lon_orient *= -1.0; - - // - // D, R - // - -data.d_km = string_att_as_double(f, "d_km"); -data.r_km = string_att_as_double(f, "r_km"); - - // - // Nx, Ny - // - -data.nx = string_att_as_int(f, "nx"); -data.ny = string_att_as_int(f, "ny"); - -data.eccentricity = 0.; -data.false_east = 0.; -data.false_north = 0.; -data.scale_factor = 1.0; -data.dy_km = data.d_km; - - // - // done - // - -g.set(data); - -return true; - -} - - -//////////////////////////////////////////////////////////////////////// - - -bool read_nc_lc_grid(NcFile & f, Grid & g) - -{ - -LambertData data; -g.clear(); - - // - // name - // - -data.name = "Unknown lambert"; - - // - // scale latitudes - // - -data.scale_lat_1 = string_att_as_double(f, "scale_lat_1"); -data.scale_lat_2 = string_att_as_double(f, "scale_lat_2"); - - // - // lat/lon pin - // - -data.lat_pin = string_att_as_double(f, "lat_pin"); -data.lon_pin = string_att_as_double(f, "lon_pin"); - -data.lon_pin *= -1.0; - - // - // x/y pin - // - -data.x_pin = string_att_as_double(f, "x_pin"); -data.y_pin = string_att_as_double(f, "y_pin"); - - // - // orientation longitude - // - -data.lon_orient = string_att_as_double(f, "lon_orient"); - -data.lon_orient *= -1.0; - - // - // D, R - // - -data.d_km = string_att_as_double(f, "d_km"); -data.r_km = string_att_as_double(f, "r_km"); - - // - // Nx, Ny - // - -data.nx = string_att_as_int(f, "nx"); -data.ny = string_att_as_int(f, "ny"); - - // - // Rotation angle - // - -data.so2_angle = 0.0; - - // - // done - // - -g.set(data); - -return true; - -} - - -//////////////////////////////////////////////////////////////////////// - - -bool read_nc_latlon_grid(NcFile & f, Grid & g) - -{ - -LatLonData data; - -g.clear(); - - // - // name - // - -data.name = "Unknown latlon"; - - // - // lower-left lat/lon - // - -data.lat_ll = string_att_as_double(f, "lat_ll"); -data.lon_ll = string_att_as_double(f, "lon_ll"); - -data.lon_ll = -(data.lon_ll); - - // - // lat/lon deltas - // - -data.delta_lat = string_att_as_double(f, "delta_lat"); -data.delta_lon = string_att_as_double(f, "delta_lon"); - - // - // grid size - // - -data.Nlat = string_att_as_int(f, "Nlat"); -data.Nlon = string_att_as_int(f, "Nlon"); - - - // - // done - // - -g.set(data); - -return true; - -} - - -//////////////////////////////////////////////////////////////////////// - - -void write_nc_st_grid(NcFile & f, const StereographicData & data) - -{ - -ConcatString junk; -ConcatString j2; - - // - // name - // - -add_att(&f, "Projection", "Polar Stereographic"); - - // - // hemisphere - // - -junk = data.hemisphere; - -add_att(&f, "hemisphere", junk); - - // - // scale latitude - // - - j2.format("%.5f", data.scale_lat); - -fix_float(j2); - - junk.format("%s degrees_north", j2.c_str()); - -add_att(&f, "scale_lat", junk); - - // - // lat/lon pin point - // - -junk.format("%.5f", data.lat_pin); - -fix_float(junk); - -add_att(&f, "lat_pin", junk); - - - junk.format("%.5f", -(data.lon_pin)); - -fix_float(junk); - -add_att(&f, "lon_pin", junk); - - // - // x/y pin point - // - - junk.format("%.5f", data.x_pin); - -fix_float(junk); - -add_att(&f, "x_pin", junk); - - - junk.format("%.5f", data.y_pin); - -fix_float(junk); - -add_att(&f, "y_pin", junk); - - // - // orientation longitude - // - - junk.format("%.5f", -(data.lon_orient)); - -fix_float(junk); - -add_att(&f, "lon_orient", junk); - - // - // D and R - // - - j2.format("%.5f", data.d_km); - -fix_float(j2); - - junk.format("%s km", j2.c_str()); - -add_att(&f, "d_km", junk); - - - j2.format("%.5f", data.r_km); - -fix_float(j2); - - junk.format("%s km", j2.c_str()); - -add_att(&f, "r_km", junk); - - // - // nx and ny - // - - junk.format("%d", data.nx); - -add_att(&f, "nx", junk); - - - junk.format("%d", data.ny); - -add_att(&f, "ny", junk); - - - // - // done - // - -return; - -} - - -//////////////////////////////////////////////////////////////////////// - - -void write_nc_lc_grid(NcFile & f, const LambertData & data) - -{ - -ConcatString junk; -ConcatString j2; - - // - // name - // - -add_att(&f, "Projection", "Lambert Conformal"); - - // - // scale latitudes - // - - junk.format("%.5f", data.scale_lat_1); - -fix_float(junk); - -add_att(&f, "scale_lat_1", junk); - - - junk.format("%.5f", data.scale_lat_2); - -fix_float(junk); - -add_att(&f, "scale_lat_2", junk); - - // - // lat/lon pin point - // - - junk.format("%.5f", data.lat_pin); - -fix_float(junk); - -add_att(&f, "lat_pin", junk); - - - junk.format("%.5f", -(data.lon_pin)); - -fix_float(junk); - -add_att(&f, "lon_pin", junk); - - // - // x/y pin point - // - - junk.format("%.5f", data.x_pin); - -fix_float(junk); - -add_att(&f, "x_pin", junk); - - - junk.format("%.5f", data.y_pin); - -fix_float(junk); - -add_att(&f, "y_pin", junk); - - // - // orientation longitude - // - - junk.format("%.5f", -(data.lon_orient)); - -fix_float(junk); - -add_att(&f, "lon_orient", junk); - - // - // D and R - // - - j2.format("%.5f", data.d_km); - -fix_float(j2); - - junk.format("%s km", j2.c_str()); - -add_att(&f, "d_km", junk); - - - j2.format("%.5f", data.r_km); - -fix_float(j2); - - junk.format("%s km", j2.c_str()); - -add_att(&f, "r_km", junk); - - // - // nx and ny - // - - junk.format("%d", data.nx); - -add_att(&f, "nx", junk); - - - junk.format("%d", data.ny); - -add_att(&f, "ny", junk); - - - // - // done - // - -return; - -} - - -//////////////////////////////////////////////////////////////////////// - - -void write_nc_latlon_grid (NcFile & f, const LatLonData & data) - -{ - -ConcatString junk; - - - // - // name - // - -add_att(&f, "Projection", "LatLon"); - - // - // lower left point - // - - junk.format("%.5f", data.lat_ll); - -fix_float(junk); - -add_att(&f, "lat_ll", junk); - - - junk.format("%.5f", -(data.lon_ll)); - -fix_float(junk); - -add_att(&f, "lon_ll", junk); - - // - // lat/lon deltas - // - - junk.format("%.5f", data.delta_lat); - -fix_float(junk); - -add_att(&f, "delta_lat", junk); - - - junk.format("%.5f", data.delta_lon); - -fix_float(junk); - -add_att(&f, "delta_lon", junk); - - // - // grid size - // - - junk.format("%d", data.Nlat); - -fix_float(junk); - -add_att(&f, "Nlat", junk); - - - junk.format("%d", data.Nlon); - -fix_float(junk); - -add_att(&f, "Nlon", junk); - - - // - // done - // - -return; - -} - - -//////////////////////////////////////////////////////////////////////// - - diff --git a/src/tools/other/mode_time_domain/nc_grid.h b/src/tools/other/mode_time_domain/nc_grid.h deleted file mode 100644 index c130990c8c..0000000000 --- a/src/tools/other/mode_time_domain/nc_grid.h +++ /dev/null @@ -1,41 +0,0 @@ -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* -// ** Copyright UCAR (c) 1992 - 2024 -// ** University Corporation for Atmospheric Research (UCAR) -// ** National Center for Atmospheric Research (NCAR) -// ** Research Applications Lab (RAL) -// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - - - -//////////////////////////////////////////////////////////////////////// - - -#ifndef __NETCDF_GRIDS_H__ -#define __NETCDF_GRIDS_H__ - - -//////////////////////////////////////////////////////////////////////// - - -#include "nc_utils.h" -#include "vx_grid.h" - - -//////////////////////////////////////////////////////////////////////// - - -extern bool read_nc_grid(netCDF::NcFile &, Grid &); - -extern bool write_nc_grid(netCDF::NcFile &, const Grid &); - - -//////////////////////////////////////////////////////////////////////// - - -#endif /* __NETCDF_GRIDS_H__ */ - - -//////////////////////////////////////////////////////////////////////// - - diff --git a/src/tools/other/mode_time_domain/nc_utils_local.cc b/src/tools/other/mode_time_domain/nc_utils_local.cc deleted file mode 100644 index 00761859cb..0000000000 --- a/src/tools/other/mode_time_domain/nc_utils_local.cc +++ /dev/null @@ -1,191 +0,0 @@ -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* -// ** Copyright UCAR (c) 1992 - 2024 -// ** University Corporation for Atmospheric Research (UCAR) -// ** National Center for Atmospheric Research (NCAR) -// ** Research Applications Lab (RAL) -// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - - - -//////////////////////////////////////////////////////////////////////// - - -#include -#include -#include -#include -#include -#include - -#include - -#include "nc_utils.h" -#include "nc_utils_local.h" -#include "vx_log.h" - -using namespace std; -using namespace netCDF; - - -//////////////////////////////////////////////////////////////////////// - - -static const int cbuf_size = 8096; - -static char cbuf [cbuf_size]; - - -//////////////////////////////////////////////////////////////////////// - - -const char * string_att(const NcFile & Nc, const char * name) - -{ - -const char *method_name = "string_att() -> "; -NcGroupAtt *att = get_nc_att(&Nc, (string)name); - -if ( GET_NC_TYPE_ID_P(att) != NcType::nc_CHAR ) { - - mlog << Error << "\n" << method_name << "attribute \"" << name - << "\" is not a character string!\n\n"; - - exit ( 1 ); - -} - -ConcatString value; -get_att_value_chars(att, value); -m_strncpy(cbuf, value.c_str(), cbuf_size - 1, method_name); - -cbuf[cbuf_size - 1] = (char) 0; - -if (att) { delete att; att = nullptr; } - - // - // done - // - -return cbuf; - -} - - -//////////////////////////////////////////////////////////////////////// - - -double string_att_as_double (const NcFile & Nc, const char * name) - -{ - -const char * c = string_att(Nc, name); - -double value = atof(c); - -return value; - -} - - -//////////////////////////////////////////////////////////////////////// - - -int string_att_as_int (const NcFile & Nc, const char * name) - -{ - -const char * c = string_att(Nc, name); - -int k = atoi(c); - -return k; - -} - - -//////////////////////////////////////////////////////////////////////// - - -long long string_att_as_ll (const NcFile & Nc, const char * name) - -{ - -const char * c = string_att(Nc, name); - -long long k = atoll(c); - -return k; - -} - - -//////////////////////////////////////////////////////////////////////// - - // - // example: 20100517_010000 - // - -unixtime parse_start_time(const char * text) - -{ - -int k; -int month, day, year, hour, minute, second; -unixtime t; -const int n = m_strlen(text); - -if ( n != 15 ) { - - mlog << Error << "\n\n parse_start_time() -> bad string ... \"" << text << "\"\n\n"; - - exit ( 1 ); - -} - -k = atoi(text); - -year = k/10000; -month = (k%10000)/100; -day = k%100; - -k = atoi(text + 9); - -hour = k/10000; -minute = (k%10000)/100; -second = k%100; - -t = mdyhms_to_unix(month, day, year, hour, minute, second); - - - // - // done - // - -return t; - -} - - -//////////////////////////////////////////////////////////////////////// - - -ConcatString start_time_string(const unixtime t) - -{ - -int month, day, year, hour, minute, second; -char junk[256]; - -unix_to_mdyhms(t, month, day, year, hour, minute, second); - -snprintf(junk, sizeof(junk), "%04d%02d%02d_%02d%02d%02d", year, month, day, hour, minute, second); - -return ConcatString(junk); - -} - - -//////////////////////////////////////////////////////////////////////// - - diff --git a/src/tools/other/mode_time_domain/nc_utils_local.h b/src/tools/other/mode_time_domain/nc_utils_local.h deleted file mode 100644 index 2f1f1df055..0000000000 --- a/src/tools/other/mode_time_domain/nc_utils_local.h +++ /dev/null @@ -1,50 +0,0 @@ -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* -// ** Copyright UCAR (c) 1992 - 2024 -// ** University Corporation for Atmospheric Research (UCAR) -// ** National Center for Atmospheric Research (NCAR) -// ** Research Applications Lab (RAL) -// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA -// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - - - -//////////////////////////////////////////////////////////////////////// - - -#ifndef __MTD_NETCDF_UTILS_H__ -#define __MTD_NETCDF_UTILS_H__ - - -//////////////////////////////////////////////////////////////////////// - - -#include "concat_string.h" -#include "vx_cal.h" -#include "nc_utils.h" - -//////////////////////////////////////////////////////////////////////// - - -extern const char * string_att (const netCDF::NcFile &, const char * name); -extern int string_att_as_int (const netCDF::NcFile &, const char * name); -extern long long string_att_as_ll (const netCDF::NcFile &, const char * name); -extern double string_att_as_double (const netCDF::NcFile &, const char * name); - - -//////////////////////////////////////////////////////////////////////// - - -extern unixtime parse_start_time(const char *); - -extern ConcatString start_time_string(const unixtime); - - -//////////////////////////////////////////////////////////////////////// - - -#endif /* __MTD_NETCDF_UTILS_H__ */ - - -//////////////////////////////////////////////////////////////////////// - -