diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 61f2c43840..88332b4da0 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -148,7 +148,7 @@ jobs: matrix: tests: - 'ascii2nc_indy pb2nc_indy tc_dland tc_pairs tc_stat plot_tc tc_rmw rmw_analysis tc_gen' - - 'met_test_scripts mode_graphics mtd regrid airnow gsi_tools netcdf modis series_analysis gen_ens_prod wwmca_regrid gen_vx_mask grid_weight interp_shape grid_diag grib_tables lidar2nc shift_data_plane trmm2nc aeronet wwmca_plot ioda2nc gaussian' + - 'met_test_scripts mode_multivar mode_graphics mtd regrid airnow gsi_tools netcdf modis series_analysis gen_ens_prod wwmca_regrid gen_vx_mask grid_weight interp_shape grid_diag grib_tables lidar2nc shift_data_plane trmm2nc aeronet wwmca_plot ioda2nc gaussian' fail-fast: false steps: - uses: actions/checkout@v2 diff --git a/met/Make-include b/met/Make-include index 42f1d5f3b3..784b2dcdd8 100644 --- a/met/Make-include +++ b/met/Make-include @@ -34,6 +34,7 @@ MET_CPPFLAGS = -I${top_builddir}/src/basic/vx_cal \ -I${top_builddir}/src/libcode/vx_solar \ -I${top_builddir}/src/libcode/vx_statistics \ -I${top_builddir}/src/libcode/vx_stat_out \ + -I${top_builddir}/src/libcode/vx_bool_calc \ -I${top_builddir}/src/libcode/vx_summary \ -I${top_builddir}/src/libcode/vx_time_series \ -I${top_builddir}/src/libcode/vx_series_data \ @@ -73,6 +74,7 @@ MET_LDFLAGS = -L${top_builddir}/src/basic/vx_cal \ -L${top_builddir}/src/libcode/vx_pxm \ -L${top_builddir}/src/libcode/vx_render \ -L${top_builddir}/src/libcode/vx_regrid \ + -L${top_builddir}/src/libcode/vx_bool_calc \ -L${top_builddir}/src/libcode/vx_shapedata \ -L${top_builddir}/src/libcode/vx_solar \ -L${top_builddir}/src/libcode/vx_statistics \ diff --git a/met/configure.ac b/met/configure.ac index df6a93a428..341c2f4592 100644 --- a/met/configure.ac +++ b/met/configure.ac @@ -1240,6 +1240,7 @@ AC_CONFIG_FILES([Makefile src/libcode/vx_summary/Makefile src/libcode/vx_python3_utils/Makefile src/libcode/vx_data2d_python/Makefile + src/libcode/vx_bool_calc/Makefile src/libcode/vx_pointdata_python/Makefile src/tools/Makefile src/tools/core/Makefile diff --git a/met/data/config/MODEConfig_default b/met/data/config/MODEConfig_default index 0b38827ef3..35090f770a 100644 --- a/met/data/config/MODEConfig_default +++ b/met/data/config/MODEConfig_default @@ -25,7 +25,6 @@ obtype = "ANALYS"; // // Verification grid -// May be set separately in each "field" entry // regrid = { to_grid = NONE; diff --git a/met/data/config/MODEMultivarConfig_default b/met/data/config/MODEMultivarConfig_default new file mode 100644 index 0000000000..dde6e5ca3b --- /dev/null +++ b/met/data/config/MODEMultivarConfig_default @@ -0,0 +1,259 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// MODE configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "WRF"; + +// +// Output description to be written +// +desc = "NA"; + +// +// Output observation type to be written +// +obtype = "ANALYS"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Approximate grid resolution (km) +// +grid_res = 20; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Run all permutations of radius and threshold +// +quilt = FALSE; + +// +// MODE Multivar boolean combination logic +// +multivar_logic = "#1 && #2 && #3"; + +// +// Forecast and observation fields to be verified +// +fcst = { + + field = [ + + { + name = "ALPHA"; + level = "(*,*)"; + }, + + { + name = "BETA"; + level = "(*,*)"; + }, + + { + name = "GAMMA"; + level = "(*,*)"; + } + + ]; + + conv_radius = 2; // in grid squares + conv_thresh = >=5.0; + vld_thresh = 0.5; + filter_attr_name = []; + filter_attr_thresh = []; + merge_thresh = >=3.5; + merge_flag = NONE; +} +obs = fcst; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Handle missing data +// +mask_missing_flag = NONE; + +// +// Match objects between the forecast and observation fields +// +match_flag = NONE; + +// +// Maximum centroid distance for objects to be compared +// +max_centroid_dist = 800.0/grid_res; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification masking regions +// +mask = { + grid = ""; + grid_flag = NONE; // Apply to NONE, FCST, OBS, or BOTH + poly = ""; + poly_flag = NONE; // Apply to NONE, FCST, OBS, or BOTH +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Fuzzy engine weights +// +weight = { + centroid_dist = 2.0; + boundary_dist = 4.0; + convex_hull_dist = 0.0; + angle_diff = 1.0; + aspect_diff = 0.0; + area_ratio = 1.0; + int_area_ratio = 2.0; + curvature_ratio = 0.0; + complexity_ratio = 0.0; + inten_perc_ratio = 0.0; + inten_perc_value = 50; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Fuzzy engine interest functions +// +interest_function = { + + centroid_dist = ( + ( 0.0, 1.0 ) + ( 60.0/grid_res, 1.0 ) + ( 600.0/grid_res, 0.0 ) + ); + + boundary_dist = ( + ( 0.0, 1.0 ) + ( 400.0/grid_res, 0.0 ) + ); + + convex_hull_dist = ( + ( 0.0, 1.0 ) + ( 400.0/grid_res, 0.0 ) + ); + + angle_diff = ( + ( 0.0, 1.0 ) + ( 30.0, 1.0 ) + ( 90.0, 0.0 ) + ); + + aspect_diff = ( + ( 0.00, 1.0 ) + ( 0.10, 1.0 ) + ( 0.75, 0.0 ) + ); + + corner = 0.8; + ratio_if = ( + ( 0.0, 0.0 ) + ( corner, 1.0 ) + ( 1.0, 1.0 ) + ); + + area_ratio = ratio_if; + + int_area_ratio = ( + ( 0.00, 0.00 ) + ( 0.10, 0.50 ) + ( 0.25, 1.00 ) + ( 1.00, 1.00 ) + ); + + curvature_ratio = ratio_if; + + complexity_ratio = ratio_if; + + inten_perc_ratio = ratio_if; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Total interest threshold for determining matches +// +total_interest_thresh = 0.7; + +// +// Interest threshold for printing output pair information +// +print_interest_thresh = 0.0; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Plotting information +// +met_data_dir = "MET_BASE"; + +fcst_raw_plot = { + color_table = "MET_BASE/colortables/met_default.ctable"; + plot_min = 0.0; + plot_max = 0.0; +} + +obs_raw_plot = { + color_table = "MET_BASE/colortables/met_default.ctable"; + plot_min = 0.0; + plot_max = 0.0; +} + +object_plot = { + color_table = "MET_BASE/colortables/mode_obj.ctable"; +} + +// +// Boolean for plotting on the region of valid data within the domain +// +plot_valid_flag = FALSE; + +// +// Plot polyline edges using great circle arcs instead of straight lines +// +plot_gcarc_flag = FALSE; + +//////////////////////////////////////////////////////////////////////////////// + +// +// NetCDF matched pairs, PostScript, and contingency table output files +// +ps_plot_flag = TRUE; +nc_pairs_flag = TRUE; +ct_stats_flag = TRUE; + +//////////////////////////////////////////////////////////////////////////////// + +shift_right = 0; // grid squares + +//////////////////////////////////////////////////////////////////////////////// + +output_prefix = ""; +version = "V10.1.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/met/data/config/Makefile.am b/met/data/config/Makefile.am index 5ab35344a9..6766b264dc 100644 --- a/met/data/config/Makefile.am +++ b/met/data/config/Makefile.am @@ -30,6 +30,7 @@ config_DATA = \ Madis2NcConfig_default \ MODEAnalysisConfig_default \ MODEConfig_default \ + MODEMultivarConfig_default \ MTDConfig_default \ PB2NCConfig_default \ PointStatConfig_default \ diff --git a/met/docs/Users_Guide/mode.rst b/met/docs/Users_Guide/mode.rst index a0df6932da..5413546077 100644 --- a/met/docs/Users_Guide/mode.rst +++ b/met/docs/Users_Guide/mode.rst @@ -103,10 +103,21 @@ Summary statistics Once MODE has been run, summary statistics are written to an output file. These files contain information about all single and cluster objects and their attributes. Total interest for object pairs is also output, as are percentiles of intensity inside the objects. The output file is in a simple flat ASCII tabular format (with one header line) and thus should be easily readable by just about any programming language, scripting language, or statistics package. Refer to :numref:`MODE-output` for lists of the statistics included in the MODE output files. Example scripts will be posted on the MET website in the future. +.. _MODE-multivar: + +Multi-Variate MODE +------------------ + +Traditionally, MODE defines objects by smoothing and thresholding data from a single input field. MET version 10.1.0 extends MODE by adding the option to define objects using multiple input fields. + +As described in :numref:`MODE-configuration-file`, the **field** entry in the forecast and observation dictionaries define the input data to be processed. If **field** is defined as a dictionary, the traditional method for running MODE is invoked, where objects are defined using a single input field. If **field** is defined as an array of dictionaries, each specifying a different input field, then the multi-variate MODE logic is invoked and requires the **multivar_logic** configuration entry to be set. Traditional MODE is run once for each input field to define objects for that field. Note that the object definition criteria can be defined separately for each field array entry. The objects from each input field are combined into a *super* object for both the forecast and observation data. + +The **multivar_logic** configuration entry, described in :numref:`MODE-configuration-file`, defines the boolean logic for combining objects from multiple fields into a *super* object. If this configuration option is set, there must be an equal or greater number of fields defined in an array of dictionaries for it define a *super* object of more than one field. Note that the multi-variate MODE forecast and observation input fields and combination logic do not need to match. The resulting forecast and observation *super* objects are written to NetCDF output files. Users can then configure and run traditional MODE to compare the forecast super object to the observed super object. + Practical information ===================== -This section contains a description of how MODE can be configured and run. The MODE tool is used to perform a features-based verification of gridded model data using gridded observations. The input gridded model and observation datasets must be in one of the MET supported gridded file formats. The requirement of having all gridded fields using the same grid specification has been removed with METv5.1. The Grid-Stat tool performs no interpolation when the input model, observation, and climatology datasets must be on a common grid. MET will interpolate these files to a common grid if one is specified. There is a regrid option in the configuration file that allows the user to define the grid upon which the scores will be computed. The gridded analysis data may be based on observations, such as Stage II or Stage IV data for verifying accumulated precipitation, or a model analysis field may be used. However, users are cautioned that it is generally unwise to verify model output using an analysis field produced by the same model. +This section contains a description of how MODE can be configured and run. The MODE tool is used to perform a features-based verification of gridded model data using gridded observations. The input gridded model and observation datasets must be in one of the MET supported gridded file formats. If the input datasets are not already on a common grid, MODE can interpolate them to a common grid. The regrid option in the configuration file enables the user to specify the grid upon which the scores will be computed. The gridded analysis data may be based on observations, such as Stage II or Stage IV data for verifying accumulated precipitation, or a model analysis field may be used. However, users are cautioned that it is generally unwise to verify model output using an analysis field produced by the same model. MODE provides the capability to select a single model variable/level from which to derive objects to be analyzed. MODE was developed and tested using accumulated precipitation. However, the code has been generalized to allow the use of any gridded model and observation field. Based on the options specified in the configuration file, MODE will define a set of simple objects in the model and observation fields. It will then compute an interest value for each pair of objects across the fields using a fuzzy engine approach. Those interest values are thresholded, and any pairs of objects above the threshold will be matched/merged. Through the configuration file, MODE offers a wide range of flexibility in how the objects are defined, processed, matched, and merged. @@ -198,7 +209,6 @@ _____________________ The configuration options listed above are common to many MET tools and are described in :numref:`config_options`. - _____________________ .. code-block:: none @@ -221,6 +231,16 @@ The **quilt** entry indicates whether all permutations of convolution radii and _____________________ +.. code-block:: none + + multivar_logic = "#1 && #2 && #3"; + +The **multivar_logic** entry appears only in the **MODEMultivarConfig_default** file. This option applies to running multi-variate MODE by setting **field** to an array of dictionaries to define multiple input fields. Objects are defined separately for each input field based on the configuration settings specified for each field array entry. The **multivar_logic** entry is a string which defines how objects for each field are combined into a final *super* object. The objects for each field are referred to as '#N' where N is the N-th field array entry. The '&&' and '||' strings define intersection and union logic, respectively. For example, "#1 && #2" is the intersection of the objects from the first and second fields. "(#1 && #2) || #3" is the union of that intersection with the objects from the third field. + +The **multivar_logic** entry is parsed separately from the **fcst** and **obs** dictionaries and can be defined differently in each. + +_____________________ + .. code-block:: none fcst = { @@ -242,6 +262,8 @@ _____________________ The **field** entries in the forecast and observation dictionaries specify the model and observation variables and level to be compared. See a more complete description of them in :numref:`config_options`. In the above example, the forecast settings are copied into the observation dictionary using **obs = fcst;.** +When **field** is set to an array of dictionaries rather than a single one, the multi-variate MODE logic is invoked. Please see :numref:`MODE-multivar` for a description of that logic. + The **censor_thresh** and **censor_val** entries are used to censor the raw data as described in :numref:`config_options`. Their functionality replaces the **raw_thresh** entry, which is deprecated in met-6.1. Prior to defining objects, it is recommended that the raw fields should be made to look similar to each other. For example, if the model only predicts values for a variable above some threshold, the observations should be thresholded at that same level. The censor thresholds can be specified using symbols. By default, no censor thresholding is applied. The **conv_radius** entry defines the radius of the circular convolution applied to smooth the raw fields. The radii are specified in terms of grid units. The default convolution radii are defined in terms of the previously defined **grid_res** entry. Multiple convolution radii may be specified as an array (e.g. **conv_radius = [ 5, 10, 15 ];**). diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index 24d9517542..f95e9b0e44 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -657,6 +657,12 @@ static const char conf_key_is_wind_speed[] = "is_wind_speed"; static const char conf_key_is_wind_direction[] = "is_wind_direction"; static const char conf_key_is_prob[] = "is_prob"; +// +// for use with mode multivar +// + +static const char conf_key_multivar_logic [] = "multivar_logic"; + // // Climatology parameter key names // diff --git a/met/src/basic/vx_config/dictionary.h b/met/src/basic/vx_config/dictionary.h index 08f84191c3..6319e8d78c 100644 --- a/met/src/basic/vx_config/dictionary.h +++ b/met/src/basic/vx_config/dictionary.h @@ -127,6 +127,8 @@ class DictionaryEntry { const ConcatString string_value () const; + Dictionary * dict () const; // doesn't check for dict vs array + Dictionary * dict_value () const; Dictionary * array_value () const; @@ -165,6 +167,8 @@ inline int DictionaryEntry::n_args() const { return ( Nargs ); } inline const IcodeVector * DictionaryEntry::icv() const { return ( v ); } +inline Dictionary * DictionaryEntry::dict() const { return ( Dict ); } + //////////////////////////////////////////////////////////////////////// diff --git a/met/src/basic/vx_util/command_line.cc b/met/src/basic/vx_util/command_line.cc index d1c1cefcfb..366123c78c 100644 --- a/met/src/basic/vx_util/command_line.cc +++ b/met/src/basic/vx_util/command_line.cc @@ -652,6 +652,52 @@ return; //////////////////////////////////////////////////////////////////////// +void CommandLine::set(const StringArray & a) + +{ + +clear(); + +int j; +ConcatString s; + + +ProgramName = get_short_name(a[0].c_str()); + +for (j=1; j<(a.n()); ++j) { // j starts at one here, not zero + + s = a[j]; + + args.add(s); + +} + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void CommandLine::set(const StringArray & a, UsageFunction uf) + +{ + +set(a); + +set_usage(uf); + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + void CommandLine::shift_down(int pos, int k) { diff --git a/met/src/basic/vx_util/command_line.h b/met/src/basic/vx_util/command_line.h index d992ed81ca..9acbc3fa9b 100644 --- a/met/src/basic/vx_util/command_line.h +++ b/met/src/basic/vx_util/command_line.h @@ -176,7 +176,10 @@ class CommandLine { // set stuff // - void set(int argc, char ** argv); // includes argv[0] + void set(int argc, char ** argv); // includes argv[0] + + void set(const StringArray &); // includes argv[0] + void set(const StringArray &, UsageFunction); // includes argv[0] void set_usage(UsageFunction); diff --git a/met/src/basic/vx_util/file_exists.cc b/met/src/basic/vx_util/file_exists.cc index 92473fe46d..a09f5cb715 100644 --- a/met/src/basic/vx_util/file_exists.cc +++ b/met/src/basic/vx_util/file_exists.cc @@ -20,8 +20,13 @@ using namespace std; #include #include #include +#include +#include +#include +#include #include "file_exists.h" +#include "empty_string.h" //////////////////////////////////////////////////////////////////////// @@ -45,3 +50,38 @@ return ( false ); //////////////////////////////////////////////////////////////////////// +bool directory_exists(const char * path) + +{ + +if ( empty(path) ) { + + cerr << "\n\n directory_exists(const char *) -> empty path!\n\n"; + + exit ( 1 ); + +} + +if ( ! file_exists(path) ) return ( false ); + +struct stat s; + +if ( stat(path, &s) < 0 ) { + + cerr << "\n\n directory_exists(const char *) -> unable to stat path \"" + << path << "\" ... " << strerror(errno) << "\n\n"; + + exit ( 1 ); + +} + +if ( S_ISDIR(s.st_mode) ) return ( true ); + +return ( false ); + +} + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/basic/vx_util/file_exists.h b/met/src/basic/vx_util/file_exists.h index 75bcf2879b..ed3d7db2ec 100644 --- a/met/src/basic/vx_util/file_exists.h +++ b/met/src/basic/vx_util/file_exists.h @@ -23,6 +23,8 @@ extern bool file_exists(const char * path); +extern bool directory_exists(const char * path); + //////////////////////////////////////////////////////////////////////// diff --git a/met/src/basic/vx_util/two_d_array.h b/met/src/basic/vx_util/two_d_array.h index 8b1aba2203..ca683e13e8 100644 --- a/met/src/basic/vx_util/two_d_array.h +++ b/met/src/basic/vx_util/two_d_array.h @@ -95,6 +95,8 @@ class TwoD_Array { void put(const T &, int _x, int _y); + T get(int _x, int _y) const; // there are times when operator[] or operator() are inconvenient + bool s_is_on(int _x, int _y) const; bool f_is_on(int _x, int _y) const; @@ -279,6 +281,20 @@ return ( E[two_to_one(_x, _y)] ); //////////////////////////////////////////////////////////////////////// +template + +T TwoD_Array::get(int _x, int _y) const + +{ + +return ( E[two_to_one(_x, _y)] ); + +} + + +//////////////////////////////////////////////////////////////////////// + + template bool TwoD_Array::s_is_on(int _x, int _y) const @@ -379,6 +395,12 @@ return ( -1 ); //////////////////////////////////////////////////////////////////////// +typedef TwoD_Array BoolPlane; + + +//////////////////////////////////////////////////////////////////////// + + #endif /* __MET_TWO_D_ARRAY_H__ */ diff --git a/met/src/libcode/Makefile.am b/met/src/libcode/Makefile.am index 8ed5d82c73..7d6f82fb1e 100644 --- a/met/src/libcode/Makefile.am +++ b/met/src/libcode/Makefile.am @@ -59,6 +59,7 @@ SUBDIRS += vx_data2d_factory \ vx_series_data \ vx_regrid \ vx_nc_obs \ - vx_solar + vx_solar \ + vx_bool_calc MAINTAINERCLEANFILES = Makefile.in diff --git a/met/src/libcode/vx_bool_calc/.gitignore b/met/src/libcode/vx_bool_calc/.gitignore new file mode 100644 index 0000000000..92b269f31e --- /dev/null +++ b/met/src/libcode/vx_bool_calc/.gitignore @@ -0,0 +1,7 @@ +*_to_string.h +*_to_string.cc +*.o +*.a +.deps +Makefile +Makefile.in diff --git a/met/src/libcode/vx_bool_calc/Makefile.am b/met/src/libcode/vx_bool_calc/Makefile.am new file mode 100644 index 0000000000..0625684670 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/Makefile.am @@ -0,0 +1,31 @@ +## @start 1 +## Makefile.am -- Process this file with automake to produce Makefile.in +## @end 1 + +MAINTAINERCLEANFILES = Makefile.in + +# Include the project definitions + +include ${top_srcdir}/Make-include + +# The library + +noinst_LIBRARIES = libvx_bool_calc.a +libvx_bool_calc_a_SOURCES = \ + tokentype_to_string.cc tokentype_to_string.h \ + make_program.cc make_program.h \ + bool_calc.cc bool_calc.h \ + token.cc token.h \ + tokenizer.cc tokenizer.h \ + token_stack.cc token_stack.h +libvx_bool_calc_a_CPPFLAGS = ${MET_CPPFLAGS} + +if ENABLE_DEVELOPMENT +tokentype_to_string.cc tokentype_to_string.h: token.h + ${ENUM_TO_STRING} -concat_string -reverse token.h + +clean-local: + -rm -f tokentype_to_string.cc + -rm -f tokentype_to_string.h +endif + diff --git a/met/src/libcode/vx_bool_calc/bool_calc.cc b/met/src/libcode/vx_bool_calc/bool_calc.cc new file mode 100644 index 0000000000..bdd05c2c0a --- /dev/null +++ b/met/src/libcode/vx_bool_calc/bool_calc.cc @@ -0,0 +1,219 @@ + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include +#include +#include +#include + +#include "bool_calc.h" +#include "make_program.h" + +#include "vx_log.h" + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for class BoolCalc + // + + +//////////////////////////////////////////////////////////////////////// + + +BoolCalc::BoolCalc() + +{ + +init_from_scratch(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +BoolCalc::~BoolCalc() { + +clear(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void BoolCalc::init_from_scratch() + +{ + +s = 0; + +program = 0; + +clear(); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void BoolCalc::clear() + +{ + +if ( s ) { delete s; s = 0; } + +if ( program ) { delete program; program = 0; } + +Max_depth = Max_local = 0; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void BoolCalc::set(const char * algebraic) + +{ + +program = new Program; + +make_program(algebraic, *program); + +s = new stack; + +Max_depth = max_depth(*program); + +Max_local = max_local(*program); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void BoolCalc::dump_program(ostream & out) const + +{ + +int j; +const Program P = *program; + +for (j=0; j<(int) (program->size()); ++j) { + + out << "\nElement # " << j << " ... \n"; + + P[j].dump(out, 1); + +} // for j + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool BoolCalc::run(const vector arg) + +{ + +int j; +Token tok; +bool tf = false; +bool tf2 = false; +bool result = false; +Program & P = *program; + + +for (j=0; j<((int) P.size()); ++j) { + + tok = P[j]; + + switch ( tok.type ) { + + + case tok_local_var: + tf = arg[tok.number_1b - 1]; // don't forget the -1 + s->push(tf); + break; + + + case tok_negation: + tf = s->top(); + s->pop(); + s->push(!tf); + break; + + + case tok_union: + tf2 = s->top(); + s->pop(); + tf = s->top(); + s->pop(); + s->push(tf || tf2); + break; + + + case tok_intersection: + tf2 = s->top(); + s->pop(); + tf = s->top(); + s->pop(); + s->push(tf && tf2); + break; + + + default: + mlog << Error << "\nBoolCalc::run(const vector) -> " + << "bad token in program ... \n\n"; + tok.dump(cerr, 1); + exit ( 1 ); + break; + + } // switch + +} // for j + + +if ( s->size() != 1 ) { + + mlog << Error << "\nBoolCalc::run(const vector) -> " + << "too many elements left on stack! (" + << (s->size()) << ")\n\n"; + + exit ( 1 ); + +} + +result = s->top(); + +s->pop(); + +return ( result ); + +} + + +//////////////////////////////////////////////////////////////////////// + + + + diff --git a/met/src/libcode/vx_bool_calc/bool_calc.h b/met/src/libcode/vx_bool_calc/bool_calc.h new file mode 100644 index 0000000000..e55b746208 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/bool_calc.h @@ -0,0 +1,68 @@ + + +//////////////////////////////////////////////////////////////////////// + + +#ifndef __BOOL_CALC_H__ +#define __BOOL_CALC_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include +#include + +#include "token.h" + + +//////////////////////////////////////////////////////////////////////// + + +class BoolCalc { + + private: + + void init_from_scratch(); + + + stack * s; // allocated + + Program * program; // allocated + + + + public: + + BoolCalc(); + ~BoolCalc(); + + void clear(); + + void dump_program(ostream &) const; + + + + int Max_depth; // maximum stack depth needed to run the program + + int Max_local; // largest local variable number in program + + + + void set(const char *); // algebraic boolean expression + + bool run(const vector); + + +}; + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __BOOL_CALC_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/libcode/vx_bool_calc/make_program.cc b/met/src/libcode/vx_bool_calc/make_program.cc new file mode 100644 index 0000000000..0072a3f658 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/make_program.cc @@ -0,0 +1,307 @@ + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include +#include +#include +#include +#include +#include + +#include "vx_util.h" + +#include "tokenizer.h" +#include "token_stack.h" +#include "make_program.h" + +#include "vx_log.h" + + +//////////////////////////////////////////////////////////////////////// + + +static bool balanced(const char *); // check balanced parentheses + +static void process(const Token &, TokenStack &, Program &); + + +//////////////////////////////////////////////////////////////////////// + + +void make_program(const char * input, Program & program) + +{ + +Tokenizer tiz; +Token tok; +TokenStack op; // operator + + +if ( ! balanced(input) ) { + + mlog << Error << "\nmake_program() -> " + << "unbalanced parentheses!\n\n"; + + exit ( 1 ); + +} + +program.clear(); + + +tiz.set(input); + + + //////////////// + +while ( 1 ) { + + tok = tiz.next_token(); + + if ( tok.is_eof() ) break; + + process(tok, op, program); + + // op.dump(cout); + +} // while + + + // + // there should be no marks left on the stack + // + +while ( op.nonempty() ) { + + tok = op.pop(); + + if ( tok.is_mark() ) { + + mlog << Error << "\nmake_program() -> " + << "extra paranthesis?\n\n"; + + exit ( 1 ); + + } + + program.push_back(tok); + +} + + +// cout << "\n\n"; +// +// cout << "Input \"" << input.text() << "\"\n\n"; +// +// cout << "Result \"" << result.text() << "\"\n\n"; + + // + // done + // + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool balanced(const char * text) + +{ + +int j = 0; +char c; +int count = 0; + +while ( (c = text[j++]) != 0 ) { + + if ( c == '(' ) ++count; + if ( c == ')' ) --count; + +} + + +return ( count == 0 ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void process(const Token & t, TokenStack & op, Program & program) + +{ + +Token tt; + + ////////////////////////////////////// + + +if ( t.is_mark() ) { op.push(t); return; } + + + ////////////////////////////////////// + + +if ( t.is_operand() ) { program.push_back(t); return; } + + + ////////////////////////////////////// + + +if ( t.is_operator() ) { + + + if ( op.empty() ) { op.push(t); } + else if ( t.prec() >= op.top_prec() ) { op.push(t); } + else if ( t.prec() < op.top_prec() ) { + + while ( op.nonempty() && (t.prec() <= op.top_prec()) ) { + // while ( op.nonempty() && (t.prec() < op.top_prec()) ) { + + if ( op.top_is_mark() ) break; + + tt = op.pop(); + + program.push_back(tt); + + } // while + + op.push(t); + + } else { + + cout << "\n\n this shouldn't happen!\n\n" << flush; + + exit ( 1 ); + + } + + // last_was_operator = true; + + return; + +} // if t.is_operator + + + ////////////////////////////////////// + + +bool mark_found = false; + + +if ( t.is_unmark() ) { + + while ( op.nonempty() ) { + + tt = op.pop(); + + if ( tt.is_mark() ) { mark_found = true; break; } + else program.push_back(tt); + + } + +} + +if ( ! mark_found ) { + + cout << "\n\n process() -> mark not found! ... unbalanced parentheses?\n\n"; + + exit ( 1 ); + +} + + + // + // done + // + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +int max_local(const Program & program) // largest local variable number in program + +{ + +int j, k, n; + +n = 0; + +for (j=0; j<(int) program.size(); ++j) { + + if ( program[j].type != tok_local_var ) continue; + + k = program[j].number_1b; + + if ( k > n ) n = k; + +} // for j + + +return ( n ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +int max_depth(const Program & program) // maximum stack depth needed to run the program + +{ + +int j, n, d; +Token tok; + + +n = d = 0; + + +for (j=0; j<(int) program.size(); ++j) { + + tok = program[j]; + + switch ( tok.type ) { + + case tok_local_var: d += 1; break; + + case tok_union: d -= 1; break; + case tok_intersection: d -= 1; break; + + + default: + d = 0; + break; + + } // switch + + if ( d > n ) n = d; + +} // for j + + + + + +return ( n ); + +} + + +//////////////////////////////////////////////////////////////////////// + + + + diff --git a/met/src/libcode/vx_bool_calc/make_program.h b/met/src/libcode/vx_bool_calc/make_program.h new file mode 100644 index 0000000000..de2e039d94 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/make_program.h @@ -0,0 +1,45 @@ + + +//////////////////////////////////////////////////////////////////////// + + +#ifndef __MAKE_BOOL_PROGRAM_H__ +#define __MAKE_BOOL_PROGRAM_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include + +#include "token.h" + + +//////////////////////////////////////////////////////////////////////// + + +extern void make_program(const char * input, Program &); + + +//////////////////////////////////////////////////////////////////////// + + + // maximum stack depth needed to run the program + +extern int max_depth(const Program &); + + + // largest local variable number in program + +extern int max_local(const Program &); + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __MAKE_BOOL_PROGRAM_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/libcode/vx_bool_calc/token.cc b/met/src/libcode/vx_bool_calc/token.cc new file mode 100644 index 0000000000..d2bff4c067 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/token.cc @@ -0,0 +1,390 @@ + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// + + +#include "indent.h" + +#include "token.h" +#include "tokentype_to_string.h" + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for class Token + // + + +//////////////////////////////////////////////////////////////////////// + + +Token::Token() + +{ + +init_from_scratch(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Token::~Token() + +{ + +// set_eof(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Token::Token(const Token & t) + +{ + +init_from_scratch(); + +assign(t); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Token & Token::operator=(const Token & t) + +{ + +if ( this == &t ) return ( * this ); + +assign(t); + +return ( * this ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::assign(const Token & t) + +{ + +clear(); + +type = t.type; + +text = t.text; + + in_prec = t.in_prec; +out_prec = t.out_prec; + +pos = t.pos; + +number_1b = t.number_1b; + +delta = t.delta; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::init_from_scratch() + +{ + +clear(); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::clear() + +{ + +set_eof(); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::dump(ostream & out, int depth) const + +{ + +Indent prefix(depth); + + +out << '\n'; + +out << prefix << "type = " << tokentype_to_string(type) << '\n'; + + +out << prefix << "text = "; + +if ( text.nonempty() ) out << '\"' << text << '\"'; + +out << '\n'; + +// out << prefix << "prec = (" << in_prec << ' ' << out_prec << ")\n"; + +// out << prefix << "pos = " << pos << '\n'; + +out << prefix << "number_1b = " << number_1b << '\n'; + +// out << prefix << "delta = " << delta << '\n'; + + + // + // done + // + +out.flush(); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::set_eof() + +{ + +text.clear(); + +delta = 0; + +in_prec = out_prec = 0; + +pos = -1; + +number_1b = 0; + +type = tok_eof; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::set_union(int _pos) + +{ + +pos = _pos; + +type = tok_union; + +text = union_char; + + in_prec = union_in_prec; +out_prec = union_out_prec; + +number_1b = 0; + +delta = union_delta; + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::set_intersection(int _pos) + +{ + +pos = _pos; + +type = tok_intersection; + +text = intersection_char; + + in_prec = intersection_in_prec; +out_prec = intersection_out_prec; + +number_1b = 0; + +delta = intersection_delta; + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::set_mark(int _pos) + +{ + +type = tok_mark; + +text = mark_char; + +in_prec = out_prec = 100; + +pos = _pos; + +delta = 0; + +number_1b = 0; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::set_unmark(int _pos) + +{ + +type = tok_unmark; + +text = unmark_char; + +in_prec = out_prec = 100; + +pos = _pos; + +delta = 0; + +number_1b = 0; + +return; + +} + +//////////////////////////////////////////////////////////////////////// + + +void Token::set_local_var(int _number_1b, int _pos) + +{ + +type = tok_local_var; + +number_1b = _number_1b; + +text.erase(); + +in_prec = out_prec = 0; + +pos = _pos; + +delta = 1; + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Token::set_negation(int _pos) + +{ + +text = negation_char; + +type = tok_negation; + + in_prec = negation_in_prec; +out_prec = negation_out_prec; + +pos = _pos; + +delta = negation_delta; + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Token::is_operator() const + +{ + +const bool tf = (type == tok_union) + || (type == tok_intersection) + || (type == tok_negation); + + +return ( tf ); + +} + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for misc functions + // + + +//////////////////////////////////////////////////////////////////////// + + +ostream & operator<<(ostream & out, const Token & t) + +{ + +t.dump(out); + +return ( out ); + +} + +//////////////////////////////////////////////////////////////////////// + + + + diff --git a/met/src/libcode/vx_bool_calc/token.h b/met/src/libcode/vx_bool_calc/token.h new file mode 100644 index 0000000000..1ef22450b9 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/token.h @@ -0,0 +1,192 @@ + + +//////////////////////////////////////////////////////////////////////// + + +#ifndef __MY_BOOL_TOKEN_H__ +#define __MY_BOOL_TOKEN_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include +#include + +#include "concat_string.h" + + +//////////////////////////////////////////////////////////////////////// + + +static const char union_char[] = "||"; +static const char intersection_char[] = "&&"; +static const char negation_char = '!'; + +static const char mark_char = '('; +static const char unmark_char = ')'; + +static const char local_var_char = '#'; + + +//////////////////////////////////////////////////////////////////////// + + + // delta = net pushes minus pops + +static const int union_delta = -1; +static const int intersection_delta = -1; +static const int negation_delta = 0; +static const int local_var_delta = 1; + + // + +static const int union_in_prec = 2; +static const int union_out_prec = 1; + +static const int intersection_in_prec = 4; +static const int intersection_out_prec = 3; + +static const int negation_in_prec = 10; +static const int negation_out_prec = 10; + + +//////////////////////////////////////////////////////////////////////// + + +enum TokenType { + + tok_union, + tok_intersection, + tok_negation, + + tok_local_var, + + tok_mark, + tok_unmark, + + tok_eof, + + no_token_type, + +}; + + +//////////////////////////////////////////////////////////////////////// + + +class Token { + + void init_from_scratch(); + + void assign(const Token &); + + public: + + Token(); // defaults to eof + ~Token(); + Token(const Token &); + Token & operator=(const Token &); + + void clear(); + + void dump(ostream &, int = 0) const; + + + TokenType type; + + ConcatString text; + + int in_prec; + int out_prec; + + int pos; // 0-based + + int number_1b; // for local variables, 1-based + + int delta; // net pushes minus pops + + + + bool is_operand () const; // ie, a local variable + bool is_operator () const; + + bool is_mark () const; + bool is_unmark () const; + + bool is_eof () const; + + // + + void set_eof(); + + void set_mark (int = -1); + void set_unmark (int = -1); + + void set_local_var(int _number_1b, int _pos = -1); // local variable + + void set_negation(int _pos = -1); // negation (ie, logical not) + + void set_union(int _pos = -1); + void set_intersection(int _pos = -1); + + + + // void print() const; + + int prec() const; // the "out" prec + +}; + + +//////////////////////////////////////////////////////////////////////// + + +extern ostream & operator<<(ostream &, const Token &); + + +//////////////////////////////////////////////////////////////////////// + + +// inline void Token::print() const { +// +// if ( result.nonempty() ) result << ','; +// +// if ( type == tok_local_var ) result << local_var_char << number; +// else result << value; +// +// cout << value << '\n' << flush; +// +// return; +// +// } + + +//////////////////////////////////////////////////////////////////////// + + +inline int Token::prec () const { return ( out_prec ); } + +inline bool Token::is_mark () const { return ( type == tok_mark ); } +inline bool Token::is_unmark () const { return ( type == tok_unmark ); } + +inline bool Token::is_eof () const { return ( type == tok_eof ); } + +inline bool Token::is_operand () const { return ( type == tok_local_var ); } + + +//////////////////////////////////////////////////////////////////////// + + +typedef vector Program; + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __MY_BOOL_TOKEN_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/libcode/vx_bool_calc/token_stack.cc b/met/src/libcode/vx_bool_calc/token_stack.cc new file mode 100644 index 0000000000..cdcdb2f039 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/token_stack.cc @@ -0,0 +1,415 @@ + + +//////////////////////////////////////////////////////////////////////// + + + // + // Warning: This file is machine generated + // + // Do not edit by hand + // + // + // Created by stackgen on August 20, 2019 3:12 pm MDT + // + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + + +#include +#include +#include +#include +#include + +#include "vx_util.h" + +#include "token_stack.h" + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for class TokenStack + // + + +//////////////////////////////////////////////////////////////////////// + + +TokenStack::TokenStack() + +{ + +init_from_scratch(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +TokenStack::~TokenStack() + +{ + +clear(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +TokenStack::TokenStack(const TokenStack & a) + +{ + +init_from_scratch(); + +assign(a); + +} + + +//////////////////////////////////////////////////////////////////////// + + +TokenStack & TokenStack::operator=(const TokenStack & a) + +{ + +if ( this == &a ) return ( * this ); + +assign(a); + +return ( * this ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void TokenStack::init_from_scratch() + +{ + +e = (Token *) 0; + +AllocInc = 50; // default value + +clear(); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void TokenStack::clear() + +{ + +if ( e ) { delete [] e; e = (Token *) 0; } + + + +Nelements = 0; + +Nalloc = 0; + +// AllocInc = 50; // don't reset AllocInc + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void TokenStack::assign(const TokenStack & _a) + +{ + +clear(); + +if ( _a.depth() == 0 ) return; + +extend(_a.depth()); + +int j; + +for (j=0; j<(_a.depth()); ++j) { + + e[j] = _a.e[j]; + +} + +Nelements = _a.Nelements; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void TokenStack::extend(int n) + +{ + +if ( n <= Nalloc ) return; + +n = AllocInc*( (n + AllocInc - 1)/AllocInc ); + +int j; +Token * u = new Token [n]; + +if ( !u ) { + + cout << "TokenStack::extend(int) -> memory allocation error\n\n"; + + exit ( 1 ); + +} + +for(j=0; j bad value ... " << n << "\n\n"; + + exit ( 1 ); + +} + +if ( n == 0 ) AllocInc = 50; // default value +else AllocInc = n; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void TokenStack::push(const Token & a) + +{ + +extend(Nelements + 1); + +e[Nelements++] = a; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +Token TokenStack::pop() + +{ + +if ( Nelements <= 0 ) { + + cout << "TokenStack::pop() -> stack empty!\n\n"; + + exit ( 1 ); + +} + +Token _t = e[Nelements - 1]; + +--Nelements; + +return ( _t ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Token TokenStack::peek() const + +{ + +if ( Nelements <= 0 ) { + + cout << "TokenStack::pop() -> stack empty!\n\n"; + + exit ( 1 ); + +} + +Token _t = e[Nelements - 1]; + +return ( _t ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +int TokenStack::top_prec() const // the "in" prec + +{ + +if ( Nelements <= 0 ) { + + cout << "TokenStack::top_prec() -> stack empty!\n\n"; + + exit ( 1 ); + +} + +int k = e[Nelements - 1].in_prec; + +return ( k ); + +} + + +//////////////////////////////////////////////////////////////////////// + +/* +char TokenStack::top_value() const + +{ + +if ( Nelements <= 0 ) { + + cout << "TokenStack::top_value() -> stack empty!\n\n"; + + exit ( 1 ); + +} + +char c = e[Nelements - 1].value; + +return ( c ); + +} +*/ + + +//////////////////////////////////////////////////////////////////////// + + +bool TokenStack::top_is_mark() const + +{ + +if ( Nelements <= 0 ) { + + cout << "TokenStack::top_is_mark() -> stack empty!\n\n"; + + exit ( 1 ); + +} + +bool tf = e[Nelements - 1].is_mark(); + +return ( tf ); + +} + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for misc functions + // + + +//////////////////////////////////////////////////////////////////////// + + +ostream & operator<<(ostream & out, const TokenStack & ts) + +{ + +ts.dump(out); + +return ( out ); + +} + + +//////////////////////////////////////////////////////////////////////// + + + + diff --git a/met/src/libcode/vx_bool_calc/token_stack.h b/met/src/libcode/vx_bool_calc/token_stack.h new file mode 100644 index 0000000000..d1afbe1d18 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/token_stack.h @@ -0,0 +1,98 @@ + + +//////////////////////////////////////////////////////////////////////// + + +#ifndef __OPERAND_STACK_H__ +#define __OPERAND_STACK_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include + +#include "token.h" + + +//////////////////////////////////////////////////////////////////////// + + +class TokenStack { + + private: + + void init_from_scratch(); + + void assign(const TokenStack &); + + void extend(int); + + + int Nelements; + + int Nalloc; + + int AllocInc; + + Token * e; + + + public: + + TokenStack(); + ~TokenStack(); + TokenStack(const TokenStack &); + TokenStack & operator=(const TokenStack &); + + void clear(); + + void dump(ostream &, int = 0) const; + + void set_alloc_inc(int = 0); // 0 means default value (50) + + int depth() const; + + bool empty() const; + bool nonempty() const; + + void push(const Token &); + + Token pop(); + + Token peek() const; + + int top_prec() const; // the "in" prec + + // char top_value() const; + + bool top_is_mark() const; + +}; + + +//////////////////////////////////////////////////////////////////////// + + +inline int TokenStack::depth() const { return ( Nelements ); } + +inline bool TokenStack::empty() const { return ( Nelements == 0 ); } + +inline bool TokenStack::nonempty() const { return ( Nelements > 0 ); } + + +//////////////////////////////////////////////////////////////////////// + + +extern ostream & operator<<(ostream &, const TokenStack &); + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __OPERAND_STACK_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/libcode/vx_bool_calc/tokenizer.cc b/met/src/libcode/vx_bool_calc/tokenizer.cc new file mode 100644 index 0000000000..7b676f452e --- /dev/null +++ b/met/src/libcode/vx_bool_calc/tokenizer.cc @@ -0,0 +1,244 @@ + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include +#include +#include +#include +#include +#include + +#include "empty_string.h" +#include "tokenizer.h" + +#include "vx_log.h" + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for class Tokenizer + // + + +//////////////////////////////////////////////////////////////////////// + + +Tokenizer::Tokenizer() + +{ + +init_from_scratch(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Tokenizer::~Tokenizer() + +{ + +clear(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Tokenizer::init_from_scratch() + +{ + +source = 0; + +clear(); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Tokenizer::clear() + +{ + +if ( source ) { delete [] source; source = 0; } + +pos = -1; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Tokenizer::set(const char * input) + +{ + +if ( empty(input) ) { + + mlog << Error << "\nTokenizer::set() -> " + << "empty input string!\n\n"; + + exit ( 1 ); + +} + +const int N = strlen(input); + +char * c = new char [N + 1]; + +memcpy(c, input, N); + +c[N] = (char) 0; + +source = c; + +pos = 0; + + + // + // done + // + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +int Tokenizer::get_number() + +{ + +int value = 0; +char c; + +// ++pos; + +while ( (c = source[pos]) != 0 ) { + + if ( isdigit(c) ) { value = 10*value + (c - '0'); ++pos; } + else break; + +} + +return ( value ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Token Tokenizer::next_token() + +{ + +int k, old_pos; +Token tok; +char c, c2; + + + // + // skip whitespace + // + +while ( 1 ) { + + c = source[pos]; + + if ( c == 0 ) { + + tok.set_eof(); + + return ( tok ); + + } + + if ( !isspace(c) ) break; + + ++pos; + +} // while + + +old_pos = pos; + +c = source[pos++]; + +if ( c == mark_char ) { + + tok.set_mark(old_pos); + +} +else if ( c == unmark_char ) { + + tok.set_unmark(old_pos); + +} +else if ( c == union_char[0] ) { + + c2 = source[pos++]; + if ( c2 == union_char[1]) tok.set_union(old_pos); + else { + mlog << Error << "\nTokenizer::next_token() -> " + << "unrecognized token: " << c << c2 << "\n\n"; + exit ( 1 ); + } + +} +else if ( c == intersection_char[0] ) { + + tok.set_intersection(old_pos); + c2 = source[pos++]; + if ( c2 == intersection_char[1]) tok.set_intersection(old_pos); + else { + mlog << Error << "\nTokenizer::next_token() -> " + << "unrecognized token: " << c << c2 << "\n\n"; + exit ( 1 ); + } + +} +else if ( c == negation_char ) { + + tok.set_negation(old_pos); + +} +else if ( c = local_var_char ) { + + k = get_number(); + tok.set_local_var(k, old_pos); + +} +else { + + mlog << Error << "\nTokenizer::next_token() -> " + << "unrecognized character: " << c << "\n\n"; + exit ( 1 ); + +} + + +return ( tok ); + +} + + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_bool_calc/tokenizer.h b/met/src/libcode/vx_bool_calc/tokenizer.h new file mode 100644 index 0000000000..dd3189b518 --- /dev/null +++ b/met/src/libcode/vx_bool_calc/tokenizer.h @@ -0,0 +1,53 @@ + + +//////////////////////////////////////////////////////////////////////// + + +#ifndef __TOKENIZER_H__ +#define __TOKENIZER_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include "token.h" + + +//////////////////////////////////////////////////////////////////////// + + +class Tokenizer { + + private: + + void init_from_scratch(); + + int get_number(); + + const char * source; // allocated, nul-terminated + + int pos; // next unread character + + public: + + Tokenizer(); + ~Tokenizer(); + + void clear(); + + void set(const char * input); + + Token next_token(); + +}; + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __TOKENIZER_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/libcode/vx_shapedata/Makefile.am b/met/src/libcode/vx_shapedata/Makefile.am index 234cba342a..f54e937535 100644 --- a/met/src/libcode/vx_shapedata/Makefile.am +++ b/met/src/libcode/vx_shapedata/Makefile.am @@ -19,6 +19,7 @@ libvx_shapedata_a_SOURCES = \ set.cc set.h \ interest.cc interest.h \ mode_columns.h \ + mode_field_info.cc mode_field_info.h \ mode_conf_info.cc mode_conf_info.h \ engine.cc engine.h \ ihull.cc ihull.h \ diff --git a/met/src/libcode/vx_shapedata/engine.cc b/met/src/libcode/vx_shapedata/engine.cc index a1ca40798e..e01de1d981 100644 --- a/met/src/libcode/vx_shapedata/engine.cc +++ b/met/src/libcode/vx_shapedata/engine.cc @@ -403,7 +403,7 @@ void ModeFuzzyEngine::do_fcst_convolution() { if(!need_fcst_conv) return; - r = conf_info.fcst_conv_radius; + r = conf_info.Fcst->conv_radius; *fcst_conv = *fcst_raw; @@ -413,7 +413,7 @@ void ModeFuzzyEngine::do_fcst_convolution() { // // Apply a circular convolution to the raw field // - if(r > 0) fcst_conv->conv_filter_circ(2*r + 1, conf_info.fcst_vld_thresh); + if(r > 0) fcst_conv->conv_filter_circ(2*r + 1, conf_info.Fcst->vld_thresh); need_fcst_conv = false; need_fcst_thresh = true; @@ -435,7 +435,7 @@ void ModeFuzzyEngine::do_obs_convolution() { if(!need_obs_conv) return; - r = conf_info.obs_conv_radius; + r = conf_info.Obs->conv_radius; *obs_conv = *obs_raw; @@ -445,7 +445,7 @@ void ModeFuzzyEngine::do_obs_convolution() { // // Apply a circular convolution to the raw field // - if(r > 0) obs_conv->conv_filter_circ(2*r + 1, conf_info.obs_vld_thresh); + if(r > 0) obs_conv->conv_filter_circ(2*r + 1, conf_info.Obs->vld_thresh); need_obs_conv = false; need_obs_thresh = true; @@ -469,15 +469,15 @@ void ModeFuzzyEngine::do_fcst_thresholding() { *fcst_mask = *fcst_conv; *fcst_thresh = *fcst_raw; - fcst_thresh->threshold(conf_info.fcst_conv_thresh); + fcst_thresh->threshold(conf_info.Fcst->conv_thresh); // // Threshold the convolved field // - fcst_mask->threshold(conf_info.fcst_conv_thresh); + fcst_mask->threshold(conf_info.Fcst->conv_thresh); mlog << Debug(3) << "Applying convolution threshold " - << conf_info.fcst_conv_thresh.get_str() + << conf_info.Fcst->conv_thresh.get_str() << " resulted in " << fcst_mask->n_objects() << " simple forecast objects.\n"; @@ -502,15 +502,15 @@ void ModeFuzzyEngine::do_obs_thresholding() { *obs_mask = *obs_conv; *obs_thresh = *obs_raw; - obs_thresh->threshold(conf_info.obs_conv_thresh); + obs_thresh->threshold(conf_info.Obs->conv_thresh); // // Threshold the convolved field // - obs_mask->threshold(conf_info.obs_conv_thresh); + obs_mask->threshold(conf_info.Obs->conv_thresh); mlog << Debug(3) << "Applying convolution threshold " - << conf_info.obs_conv_thresh.get_str() + << conf_info.Obs->conv_thresh.get_str() << " resulted in " << obs_mask->n_objects() << " simple observation objects.\n"; @@ -536,11 +536,11 @@ void ModeFuzzyEngine::do_fcst_filtering() { // // Apply object attribute filtering logic // - if(conf_info.fcst_filter_attr_map.size() > 0) { + if(conf_info.Fcst->filter_attr_map.size() > 0) { - fcst_mask->threshold_attr(conf_info.fcst_filter_attr_map, - fcst_raw, conf_info.fcst_conv_thresh, grid, - conf_info.fcst_info->is_precipitation()); + fcst_mask->threshold_attr(conf_info.Fcst->filter_attr_map, + fcst_raw, conf_info.Fcst->conv_thresh, grid, + conf_info.Fcst->var_info->is_precipitation()); mlog << Debug(3) << "Applying object attribute filtering" << " resulted in " << fcst_mask->n_objects() @@ -571,11 +571,11 @@ void ModeFuzzyEngine::do_obs_filtering() { // // Apply object attribute filtering logic // - if(conf_info.obs_filter_attr_map.size() > 0) { + if(conf_info.Obs->filter_attr_map.size() > 0) { - obs_mask->threshold_attr(conf_info.obs_filter_attr_map, - obs_raw, conf_info.obs_conv_thresh, grid, - conf_info.obs_info->is_precipitation()); + obs_mask->threshold_attr(conf_info.Obs->filter_attr_map, + obs_raw, conf_info.Obs->conv_thresh, grid, + conf_info.Obs->var_info->is_precipitation()); mlog << Debug(3) << "Applying object attribute filtering" << " resulted in " << obs_mask->n_objects() @@ -658,12 +658,12 @@ void ModeFuzzyEngine::do_fcst_merging(const char *default_config, if(!need_fcst_merge) return; - if(conf_info.fcst_merge_flag == MergeType_Both || - conf_info.fcst_merge_flag == MergeType_Thresh) + if(conf_info.Fcst->merge_flag == MergeType_Both || + conf_info.Fcst->merge_flag == MergeType_Thresh) do_fcst_merge_thresh(); - if(conf_info.fcst_merge_flag == MergeType_Both || - conf_info.fcst_merge_flag == MergeType_Engine) + if(conf_info.Fcst->merge_flag == MergeType_Both || + conf_info.Fcst->merge_flag == MergeType_Engine) do_fcst_merge_engine(default_config, merge_config); // @@ -686,12 +686,12 @@ void ModeFuzzyEngine::do_obs_merging(const char *default_config, if(!need_obs_merge) return; - if(conf_info.obs_merge_flag == MergeType_Both || - conf_info.obs_merge_flag == MergeType_Thresh) + if(conf_info.Obs->merge_flag == MergeType_Both || + conf_info.Obs->merge_flag == MergeType_Thresh) do_obs_merge_thresh(); - if(conf_info.obs_merge_flag == MergeType_Both || - conf_info.obs_merge_flag == MergeType_Engine) + if(conf_info.Obs->merge_flag == MergeType_Both || + conf_info.Obs->merge_flag == MergeType_Engine) do_obs_merge_engine(default_config, merge_config); // @@ -792,7 +792,7 @@ void ModeFuzzyEngine::do_no_match() { fcst_shape[j] = select(*fcst_split, j+1); fcst_single[j].set(*fcst_raw, *fcst_thresh, fcst_shape[j], conf_info.inten_perc_value, - conf_info.fcst_info->is_precipitation()); + conf_info.Fcst->var_info->is_precipitation()); fcst_single[j].object_number = j+1; } @@ -802,7 +802,7 @@ void ModeFuzzyEngine::do_no_match() { obs_shape[j] = select(*obs_split, j+1); obs_single[j].set(*obs_raw, *obs_thresh, obs_shape[j], conf_info.inten_perc_value, - conf_info.obs_info->is_precipitation()); + conf_info.Obs->var_info->is_precipitation()); obs_single[j].object_number = j+1; } @@ -882,7 +882,7 @@ void ModeFuzzyEngine::do_match_merge() { fcst_shape[j] = select(*fcst_split, j+1); fcst_single[j].set(*fcst_raw, *fcst_thresh, fcst_shape[j], conf_info.inten_perc_value, - conf_info.fcst_info->is_precipitation()); + conf_info.Fcst->var_info->is_precipitation()); fcst_single[j].object_number = j+1; } @@ -892,7 +892,7 @@ void ModeFuzzyEngine::do_match_merge() { obs_shape[j] = select(*obs_split, j+1); obs_single[j].set(*obs_raw, *obs_thresh, obs_shape[j], conf_info.inten_perc_value, - conf_info.obs_info->is_precipitation()); + conf_info.Obs->var_info->is_precipitation()); obs_single[j].object_number = j+1; } @@ -1042,7 +1042,7 @@ void ModeFuzzyEngine::do_fcst_merge_thresh() { // // Threshold the forecast merge field // - fcst_merge_mask.threshold(conf_info.fcst_merge_thresh); + fcst_merge_mask.threshold(conf_info.Fcst->merge_thresh); // // Split up the forecast merge field @@ -1165,7 +1165,7 @@ void ModeFuzzyEngine::do_obs_merge_thresh() { // // Threshold the forecast merge field // - obs_merge_mask.threshold(conf_info.obs_merge_thresh); + obs_merge_mask.threshold(conf_info.Obs->merge_thresh); // // Split up the forecast merge field @@ -1300,8 +1300,8 @@ void ModeFuzzyEngine::do_fcst_merge_engine(const char *default_config, fcst_engine->ctable = ctable; if(default_config && merge_config) { fcst_engine->conf_info.read_config(default_config, merge_config); - fcst_engine->conf_info.process_config(conf_info.fcst_info->file_type(), - conf_info.obs_info->file_type()); + fcst_engine->conf_info.process_config(conf_info.Fcst->var_info->file_type(), + conf_info.Obs->var_info->file_type()); path = replace_path(fcst_engine->conf_info.object_pi.color_table.c_str()); fcst_engine->ctable.read(path.c_str()); } @@ -1309,20 +1309,20 @@ void ModeFuzzyEngine::do_fcst_merge_engine(const char *default_config, // // Copy over fcst_info and obs_info // - *(fcst_engine->conf_info.fcst_info) = *(conf_info.fcst_info); - *(fcst_engine->conf_info.obs_info) = *(conf_info.fcst_info); + *(fcst_engine->conf_info.Fcst->var_info) = *(conf_info.Fcst->var_info); + *(fcst_engine->conf_info.Obs->var_info) = *(conf_info.Fcst->var_info); // // Copy over the forecast threshold values // - fcst_engine->conf_info.fcst_conv_thresh = conf_info.fcst_conv_thresh; - fcst_engine->conf_info.obs_conv_thresh = conf_info.fcst_conv_thresh; + fcst_engine->conf_info.Fcst->conv_thresh = conf_info.Fcst->conv_thresh; + fcst_engine->conf_info.Obs->conv_thresh = conf_info.Fcst->conv_thresh; - fcst_engine->conf_info.fcst_filter_attr_map = conf_info.fcst_filter_attr_map; - fcst_engine->conf_info.obs_filter_attr_map = conf_info.fcst_filter_attr_map; + fcst_engine->conf_info.Fcst->filter_attr_map = conf_info.Fcst->filter_attr_map; + fcst_engine->conf_info.Obs->filter_attr_map = conf_info.Fcst->filter_attr_map; - fcst_engine->conf_info.fcst_merge_thresh = conf_info.fcst_merge_thresh; - fcst_engine->conf_info.obs_merge_thresh = conf_info.fcst_merge_thresh; + fcst_engine->conf_info.Fcst->merge_thresh = conf_info.Fcst->merge_thresh; + fcst_engine->conf_info.Obs->merge_thresh = conf_info.Fcst->merge_thresh; // // Copy the previously defined fuzzy engine fields @@ -1467,8 +1467,8 @@ void ModeFuzzyEngine::do_obs_merge_engine(const char *default_config, obs_engine->ctable = ctable; if(default_config && merge_config) { obs_engine->conf_info.read_config(default_config, merge_config); - obs_engine->conf_info.process_config(conf_info.fcst_info->file_type(), - conf_info.obs_info->file_type()); + obs_engine->conf_info.process_config(conf_info.Fcst->var_info->file_type(), + conf_info.Obs->var_info->file_type()); path = replace_path(obs_engine->conf_info.object_pi.color_table.c_str()); obs_engine->ctable.read(path.c_str()); } @@ -1476,20 +1476,20 @@ void ModeFuzzyEngine::do_obs_merge_engine(const char *default_config, // // Copy over fcst_info and obs_info // - *(obs_engine->conf_info.fcst_info) = *(conf_info.obs_info); - *(obs_engine->conf_info.obs_info) = *(conf_info.obs_info); + *(obs_engine->conf_info.Fcst->var_info) = *(conf_info.Obs->var_info); + *(obs_engine->conf_info.Obs->var_info) = *(conf_info.Obs->var_info); // // Copy over the observation threshold values // - obs_engine->conf_info.fcst_conv_thresh = conf_info.obs_conv_thresh; - obs_engine->conf_info.obs_conv_thresh = conf_info.obs_conv_thresh; + obs_engine->conf_info.Fcst->conv_thresh = conf_info.Obs->conv_thresh; + obs_engine->conf_info.Obs->conv_thresh = conf_info.Obs->conv_thresh; - obs_engine->conf_info.fcst_filter_attr_map = conf_info.obs_filter_attr_map; - obs_engine->conf_info.obs_filter_attr_map = conf_info.obs_filter_attr_map; + obs_engine->conf_info.Fcst->filter_attr_map = conf_info.Obs->filter_attr_map; + obs_engine->conf_info.Obs->filter_attr_map = conf_info.Obs->filter_attr_map; - obs_engine->conf_info.fcst_merge_thresh = conf_info.obs_merge_thresh; - obs_engine->conf_info.obs_merge_thresh = conf_info.obs_merge_thresh; + obs_engine->conf_info.Fcst->merge_thresh = conf_info.Obs->merge_thresh; + obs_engine->conf_info.Obs->merge_thresh = conf_info.Obs->merge_thresh; // // Copy the previously defined fuzzy engine fields @@ -1634,7 +1634,7 @@ void ModeFuzzyEngine::do_match_fcst_merge() { fcst_shape[j] = select(*fcst_split, j+1); fcst_single[j].set(*fcst_raw, *fcst_thresh, fcst_shape[j], conf_info.inten_perc_value, - conf_info.fcst_info->is_precipitation()); + conf_info.Fcst->var_info->is_precipitation()); fcst_single[j].object_number = j+1; } @@ -1644,7 +1644,7 @@ void ModeFuzzyEngine::do_match_fcst_merge() { obs_shape[j] = select(*obs_split, j+1); obs_single[j].set(*obs_raw, *obs_thresh, obs_shape[j], conf_info.inten_perc_value, - conf_info.obs_info->is_precipitation()); + conf_info.Obs->var_info->is_precipitation()); obs_single[j].object_number = j+1; } @@ -1811,7 +1811,7 @@ void ModeFuzzyEngine::do_match_only() { fcst_shape[j] = select(*fcst_split, j+1); fcst_single[j].set(*fcst_raw, *fcst_thresh, fcst_shape[j], conf_info.inten_perc_value, - conf_info.fcst_info->is_precipitation()); + conf_info.Fcst->var_info->is_precipitation()); fcst_single[j].object_number = j+1; } @@ -1821,7 +1821,7 @@ void ModeFuzzyEngine::do_match_only() { obs_shape[j] = select(*obs_split, j+1); obs_single[j].set(*obs_raw, *obs_thresh, obs_shape[j], conf_info.inten_perc_value, - conf_info.obs_info->is_precipitation()); + conf_info.Obs->var_info->is_precipitation()); obs_single[j].object_number = j+1; } @@ -2062,13 +2062,13 @@ void ModeFuzzyEngine::do_cluster_features() { fcst_clus_shape[j] = select(*fcst_clus_split, j+1); fcst_cluster[j].set(*fcst_raw, *fcst_thresh, fcst_clus_shape[j], conf_info.inten_perc_value, - conf_info.fcst_info->is_precipitation()); + conf_info.Fcst->var_info->is_precipitation()); fcst_cluster[j].object_number = j+1; obs_clus_shape[j] = select(*obs_clus_split, j+1); obs_cluster[j].set(*obs_raw, *obs_thresh, obs_clus_shape[j], conf_info.inten_perc_value, - conf_info.obs_info->is_precipitation()); + conf_info.Obs->var_info->is_precipitation()); obs_cluster[j].object_number = j+1; } @@ -2817,48 +2817,48 @@ void write_header_columns(ModeFuzzyEngine & eng, const Grid & grid, AsciiTable & // Forecast convolution radius at.set_entry(row, c++, - eng.conf_info.fcst_conv_radius); + eng.conf_info.Fcst->conv_radius); // Forecast convolution threshold at.set_entry(row, c++, - eng.conf_info.fcst_conv_thresh.get_str()); + eng.conf_info.Fcst->conv_thresh.get_str()); // Observation convolution radius at.set_entry(row, c++, - eng.conf_info.obs_conv_radius); + eng.conf_info.Obs->conv_radius); // Observation convolution threshold at.set_entry(row, c++, - eng.conf_info.obs_conv_thresh.get_str()); + eng.conf_info.Obs->conv_thresh.get_str()); // Forecast Variable Name s = check_hdr_str(conf_key_fcst_var, - eng.conf_info.fcst_info->name_attr()); + eng.conf_info.Fcst->var_info->name_attr()); at.set_entry(row, c++, s.text()); // Forecast Variable Units s = check_hdr_str(conf_key_fcst_units, - eng.conf_info.fcst_info->units_attr(), true); + eng.conf_info.Fcst->var_info->units_attr(), true); at.set_entry(row, c++, s.text()); // Forecast Variable Level s = check_hdr_str(conf_key_fcst_lev, - eng.conf_info.fcst_info->level_attr(), true); + eng.conf_info.Fcst->var_info->level_attr(), true); at.set_entry(row, c++, s.text()); // Observation Variable Name s = check_hdr_str(conf_key_obs_var, - eng.conf_info.obs_info->name_attr()); + eng.conf_info.Obs->var_info->name_attr()); at.set_entry(row, c++, s.text()); // Observation Variable Units s = check_hdr_str(conf_key_obs_units, - eng.conf_info.obs_info->units_attr(), true); + eng.conf_info.Obs->var_info->units_attr(), true); at.set_entry(row, c++, s.text()); // Observation Variable Level s = check_hdr_str(conf_key_obs_lev, - eng.conf_info.obs_info->level_attr(), true); + eng.conf_info.Obs->var_info->level_attr(), true); at.set_entry(row, c++, s.text()); // Observation type diff --git a/met/src/libcode/vx_shapedata/mode_conf_info.cc b/met/src/libcode/vx_shapedata/mode_conf_info.cc index a145f9f6c4..9bae581a01 100644 --- a/met/src/libcode/vx_shapedata/mode_conf_info.cc +++ b/met/src/libcode/vx_shapedata/mode_conf_info.cc @@ -54,8 +54,18 @@ void ModeConfInfo::init_from_scratch() { // Initialize pointers - fcst_info = (VarInfo *) 0; - obs_info = (VarInfo *) 0; + // fcst_info = (VarInfo *) 0; + // obs_info = (VarInfo *) 0; + + N_fields = 0; + + Field_Index = 0; + + fcst_array = 0; + obs_array = 0; + + fcst_array = 0; + obs_array = 0; clear(); @@ -80,29 +90,34 @@ void ModeConfInfo::clear() grid_res = bad_data_double; - fcst_conv_radius_array.clear(); - obs_conv_radius_array.clear(); + Field_Index = 0; - fcst_conv_radius = bad_data_int; - obs_conv_radius = bad_data_int; + fcst_multivar_logic.clear(); + obs_multivar_logic.clear(); - fcst_conv_thresh_array.clear(); - obs_conv_thresh_array.clear(); + // fcst_conv_radius_array.clear(); + // obs_conv_radius_array.clear(); - fcst_merge_thresh_array.clear(); - obs_merge_thresh_array.clear(); + // fcst_conv_radius = bad_data_int; + // obs_conv_radius = bad_data_int; - fcst_conv_thresh.clear(); - obs_conv_thresh.clear(); + // fcst_conv_thresh_array.clear(); + // obs_conv_thresh_array.clear(); - fcst_vld_thresh = bad_data_double; - obs_vld_thresh = bad_data_double; + // fcst_merge_thresh_array.clear(); + // obs_merge_thresh_array.clear(); - fcst_filter_attr_map.clear(); - obs_filter_attr_map.clear(); + // fcst_conv_thresh.clear(); + // obs_conv_thresh.clear(); - fcst_merge_flag = MergeType_None; - obs_merge_flag = MergeType_None; + // fcst_vld_thresh = bad_data_double; + // obs_vld_thresh = bad_data_double; + + // fcst_filter_attr_map.clear(); + // obs_filter_attr_map.clear(); + + // fcst_merge_flag = MergeType_None; + // obs_merge_flag = MergeType_None; match_flag = MatchType_None; @@ -161,9 +176,18 @@ void ModeConfInfo::clear() quilt = false; + // Deallocate memory - if(fcst_info) { delete fcst_info; fcst_info = (VarInfo *) 0; } - if(obs_info) { delete obs_info; obs_info = (VarInfo *) 0; } + // if(fcst_info) { delete fcst_info; fcst_info = (VarInfo *) 0; } + // if(obs_info) { delete obs_info; obs_info = (VarInfo *) 0; } + + if ( fcst_array ) { delete [] fcst_array; fcst_array = 0; } + if ( obs_array ) { delete [] obs_array; obs_array = 0; } + + Fcst = 0; + Obs = 0; + + N_fields = 0; return; @@ -171,7 +195,7 @@ void ModeConfInfo::clear() //////////////////////////////////////////////////////////////////////// -void ModeConfInfo::read_config(const char *default_file_name, const char *user_file_name) +void ModeConfInfo::read_config(const char * default_file_name, const char * user_file_name) { @@ -185,6 +209,8 @@ void ModeConfInfo::read_config(const char *default_file_name, const char *user_f // Read the user-specified config file conf.read(user_file_name); + get_multivar_programs(); + nc_info.set_compress_level(conf.nc_compression()); return; @@ -198,11 +224,11 @@ void ModeConfInfo::process_config(GrdFileType ftype, GrdFileType otype) { -int j, n; -VarInfoFactory info_factory; -Dictionary *fcst_dict = (Dictionary *) 0; -Dictionary *obs_dict = (Dictionary *) 0; -Dictionary *dict = (Dictionary *) 0; +int j, k, n; +// VarInfoFactory info_factory; +Dictionary * fcst_dict = (Dictionary *) 0; +Dictionary * obs_dict = (Dictionary *) 0; +Dictionary * dict = (Dictionary *) 0; PlotInfo plot_info; // Dump the contents of the config file @@ -242,142 +268,184 @@ PlotInfo plot_info; fcst_dict = conf.lookup_dictionary(conf_key_fcst); obs_dict = conf.lookup_dictionary(conf_key_obs); + +// X + read_fields (fcst_array, fcst_dict, ftype, 'F'); // the order is important here + read_fields ( obs_array, obs_dict, otype, 'O'); // the order is important here + + Fcst = fcst_array; // + 0 + Obs = obs_array; // + 0 + // Allocate new VarInfo objects - fcst_info = info_factory.new_var_info(ftype); - obs_info = info_factory.new_var_info(otype); +// *X fcst_info = info_factory.new_var_info(ftype); +// *X obs_info = info_factory.new_var_info(otype); // Set the dictionaries - fcst_info->set_dict(*(fcst_dict->lookup_dictionary(conf_key_field))); - obs_info->set_dict(*(obs_dict->lookup_dictionary(conf_key_field))); +// *X fcst_info->set_dict(*(fcst_dict->lookup_dictionary(conf_key_field))); +// *X 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); + for (j=0; jdump(cout); + mlog << Debug(5) + << "Parsed observation field:\n"; + obs_array[j].var_info->dump(cout); + } // for j } // No support for wind direction - if(fcst_info->is_wind_direction() || obs_info->is_wind_direction()) { - mlog << Error << "\nModeConfInfo::process_config() -> " - << "the wind direction field may not be verified " - << "using MODE.\n\n"; - exit(1); + for (j=0; jis_wind_direction() || obs_array[j].var_info->is_wind_direction()) { + mlog << Error << "\nModeConfInfo::process_config() -> " + << "the wind direction field may not be verified " + << "using MODE.\n\n"; + exit(1); + } } // Conf: fcst.raw_thresh and obs.raw_thresh are deprecated - if ( fcst_dict->lookup(conf_key_raw_thresh) || - obs_dict->lookup(conf_key_raw_thresh) ) { - mlog << Error << "\nModeConfInfo::process_config() -> " - << "the \"" << conf_key_raw_thresh << "\" entry is deprecated in MET " - << met_version << "! Use \"" << conf_key_censor_thresh << "\" and \"" - << conf_key_censor_val << "\" instead.\n\n"; - exit(1); - } +// *X if ( fcst_dict->lookup(conf_key_raw_thresh) || +// *X obs_dict->lookup(conf_key_raw_thresh) ) { +// *X mlog << Error << "\nModeConfInfo::process_config() -> " +// *X << "the \"" << conf_key_raw_thresh << "\" entry is deprecated in MET " +// *X << met_version << "! Use \"" << conf_key_censor_thresh << "\" and \"" +// *X << conf_key_censor_val << "\" instead.\n\n"; +// *X exit(1); +// *X } // Conf: fcst.conv_radius and obs.conv_radius - fcst_conv_radius_array = fcst_dict->lookup_int_array(conf_key_conv_radius); - obs_conv_radius_array = obs_dict->lookup_int_array(conf_key_conv_radius); +// *X fcst_conv_radius_array = fcst_dict->lookup_int_array(conf_key_conv_radius); +// *X obs_conv_radius_array = obs_dict->lookup_int_array(conf_key_conv_radius); - if ( fcst_conv_radius_array.n_elements() != obs_conv_radius_array.n_elements() ) { + for (j=0; j " - << "fcst and obs convolution radius arrays need to be the same size\n\n"; + if ( fcst_array[j].conv_radius_array.n_elements() != obs_array[j].conv_radius_array.n_elements() ) { - exit ( 1 ); + mlog << Error << "\nModeConfInfo::process_config() -> " + << "fcst and obs convolution radius arrays need to be the same size\n\n"; + + exit ( 1 ); + + } } // Check that fcst_conv_radius and obs_conv_radius are non-negative - n = fcst_conv_radius_array.n_elements(); // same as obs_conv_radius_array.n_elements() + for (j=0; j " - << "fcst_conv_radius (" << fcst_conv_radius_array[j] - << ") and obs_conv_radius (" << obs_conv_radius_array[j] - << ") must be non-negative\n\n"; + if(fcst_array[j].conv_radius_array[k] < 0 || obs_array[j].conv_radius_array[k] < 0) { - exit(1); + mlog << Error << "\nModeConfInfo::process_config() -> " + << "fcst_conv_radius (" << fcst_array[j].conv_radius_array[k] + << ") and obs_conv_radius (" << obs_array[j].conv_radius_array[k] + << ") must be non-negative\n\n"; - } + exit(1); - } + } - if ( fcst_conv_radius_array.n_elements() == 1 ) fcst_conv_radius = fcst_conv_radius_array[0]; - if ( obs_conv_radius_array.n_elements() == 1 ) obs_conv_radius = obs_conv_radius_array[0]; + } // for k + + } // for j + + + for (j=0; jlookup_thresh_array(conf_key_conv_thresh); - obs_conv_thresh_array = obs_dict->lookup_thresh_array(conf_key_conv_thresh); +// *X fcst_conv_thresh_array = fcst_dict->lookup_thresh_array(conf_key_conv_thresh); +// *X obs_conv_thresh_array = obs_dict->lookup_thresh_array(conf_key_conv_thresh); - if ( fcst_conv_thresh_array.n_elements() != obs_conv_thresh_array.n_elements() ) { + for (j=0; j " - << "fcst and obs convolution threshold arrays need to be the same size\n\n"; + if ( fcst_array[j].conv_thresh_array.n_elements() != obs_array[j].conv_thresh_array.n_elements() ) { - exit ( 1 ); + mlog << Error << "\nModeConfInfo::process_config() -> " + << "fcst and obs convolution threshold arrays need to be the same size\n\n"; + + exit ( 1 ); + + } } - if ( fcst_conv_thresh_array.n_elements() == 1 ) fcst_conv_thresh = fcst_conv_thresh_array[0]; - if ( obs_conv_thresh_array.n_elements() == 1 ) obs_conv_thresh = obs_conv_thresh_array[0]; + + for (j=0; jlookup_double(conf_key_vld_thresh); - obs_vld_thresh = obs_dict->lookup_double(conf_key_vld_thresh); +// *X fcst_vld_thresh = fcst_dict->lookup_double(conf_key_vld_thresh); +// *X obs_vld_thresh = obs_dict->lookup_double(conf_key_vld_thresh); // Conf: fcst.filter_attr_name and fcst.filter_attr_thresh // obs.filter_attr_name and obs.filter_attr_thresh - fcst_filter_attr_map = parse_conf_filter_attr_map(fcst_dict); - obs_filter_attr_map = parse_conf_filter_attr_map(obs_dict); +// *X fcst_filter_attr_map = parse_conf_filter_attr_map(fcst_dict); +// *X obs_filter_attr_map = parse_conf_filter_attr_map(obs_dict); // 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)); +// *X fcst_merge_flag = int_to_mergetype(fcst_dict->lookup_int(conf_key_merge_flag)); +// *X obs_merge_flag = int_to_mergetype(obs_dict->lookup_int(conf_key_merge_flag)); // Conf: fcst.merge_thresh and obs.merge_thresh - fcst_merge_thresh_array = fcst_dict->lookup_thresh_array(conf_key_merge_thresh); - obs_merge_thresh_array = obs_dict->lookup_thresh_array(conf_key_merge_thresh); +// *X fcst_merge_thresh_array = fcst_dict->lookup_thresh_array(conf_key_merge_thresh); +// *X obs_merge_thresh_array = obs_dict->lookup_thresh_array(conf_key_merge_thresh); - if ( need_fcst_merge_thresh() && (fcst_merge_thresh_array.n_elements() != fcst_conv_thresh_array.n_elements()) ) { + for (j=0; j " - << "fcst conv thresh and fcst merge thresh arrays need to be the same size\n\n"; + if ( fcst_array[j].need_merge_thresh() && (fcst_array[j].merge_thresh_array.n_elements() != fcst_array[j].conv_thresh_array.n_elements()) ) { - exit ( 1 ); + mlog << Error << "\nModeConfInfo::process_config() -> " + << "fcst conv thresh and fcst merge thresh arrays need to be the same size\n\n"; - } + exit ( 1 ); + } - if ( need_obs_merge_thresh() && (obs_merge_thresh_array.n_elements() != obs_conv_thresh_array.n_elements()) ) { - mlog << Error << "\nModeConfInfo::process_config() -> " - << "obs conv thresh and obs merge thresh arrays need to be the same size\n\n"; + if ( obs_array[j].need_merge_thresh() && (obs_array[j].merge_thresh_array.n_elements() != obs_array[j].conv_thresh_array.n_elements()) ) { - exit ( 1 ); + mlog << Error << "\nModeConfInfo::process_config() -> " + << "obs conv thresh and obs merge thresh arrays need to be the same size\n\n"; - } + exit ( 1 ); - if ( fcst_merge_thresh_array.n_elements() == 1 ) fcst_merge_thresh = fcst_merge_thresh_array[0]; - if ( obs_merge_thresh_array.n_elements() == 1 ) obs_merge_thresh = obs_merge_thresh_array[0]; + } + + } // for j + + for (j=0; j " - << "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"; + for (j=0; j " + << "When matching is disabled (match_flag = " + << matchtype_to_string(match_flag) + << ") but merging is requested (fcst_merge_flag = " + << mergetype_to_string(fcst_array[j].merge_flag) + << ", obs_merge_flag = " + << mergetype_to_string(obs_array[j].merge_flag) + << ") any merging information will be discarded.\n\n"; + } + } // Conf: max_centroid_dist @@ -525,11 +598,14 @@ PlotInfo plot_info; // Conf: fcst_raw_plot - fcst_raw_pi = parse_conf_plot_info(conf.lookup_dictionary(conf_key_fcst_raw_plot)); +// *X + fcst_array->raw_pi = parse_conf_plot_info(conf.lookup_dictionary(conf_key_fcst_raw_plot)); // Conf: obs_raw_plot - obs_raw_pi = parse_conf_plot_info(conf.lookup_dictionary(conf_key_obs_raw_plot)); +// *X + + obs_array->raw_pi = parse_conf_plot_info(conf.lookup_dictionary(conf_key_obs_raw_plot)); // Conf: object_plot @@ -561,7 +637,8 @@ PlotInfo plot_info; // Conf: shift_right - shift_right = fcst_dict->lookup_int(conf_key_shift_right); +// *X + shift_right = fcst_dict->lookup_int(conf_key_shift_right); return; @@ -571,18 +648,132 @@ PlotInfo plot_info; //////////////////////////////////////////////////////////////////////// +void ModeConfInfo::read_fields (Mode_Field_Info * & info_array, Dictionary * dict, GrdFileType type, char _fo) + +{ + +const DictionaryEntry * ee = dict->lookup(conf_key_field); + +if ( !ee ) { + + mlog << "\n\n ModeConfInfo::read_fields () -> \"field\" entry not found in dictionary!\n\n"; + + exit ( 1 ); + +} + +const Dictionary * field = ee->dict(); + +const int N = ( (field->is_array()) ? (field->n_entries()) : 1 ); + +info_array = new Mode_Field_Info [N]; + +N_fields = N; + + +if ( field->is_array() ) { + + int j, k; + const DictionaryEntry * e = 0; + const Dictionary & D = *field; + + if ( (N_fields > 0) && (N != N_fields) ) { + + mlog << Error + << "\n\n ModeConfInfo::read_field_dict() -> fcst and obs dictionaries have different number of entries\n\n"; + + exit ( 1 ); + + } + + for (j=0; jtype() != DictionaryType) && (e->type() != ArrayType) ) { + + mlog << Error + << "\n\n ModeConfInfo::read_field_dict() -> field entry # " << (j + 1) << " is not a dictionary!\n\n"; + + exit ( 1 ); + + } + + info_array[j].set(true, j, e->dict_value(), &conf, type, _fo, false); + + if ( j == 0 ) { + + for (k=1; k= N_fields) ) { + + mlog << Error + << "\n\n ModeConfInfo::set_field_index(int) -> range check error\n\n"; + + exit ( 1 ); + +} + +Field_Index = k; + +Fcst = fcst_array + k; + Obs = obs_array + k; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + void ModeConfInfo::set_perc_thresh(const DataPlane &f_dp, const DataPlane &o_dp) + { // // Compute percentiles for forecast and observation thresholds. // - if( !fcst_conv_thresh_array.need_perc() && - !obs_conv_thresh_array.need_perc() && - !fcst_merge_thresh_array.need_perc() && - !obs_merge_thresh_array.need_perc() ) return; + if( !(Fcst->conv_thresh_array.need_perc() ) && + !(Obs->conv_thresh_array.need_perc() ) && + !(Fcst->merge_thresh_array.need_perc() ) && + !(Obs->merge_thresh_array.need_perc() ) ) return; // // Sort the input arrays @@ -604,18 +795,21 @@ void ModeConfInfo::set_perc_thresh(const DataPlane &f_dp, // // Compute percentiles // - fcst_conv_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, - &fcst_conv_thresh_array, - &obs_conv_thresh_array); - obs_conv_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, - &fcst_conv_thresh_array, - &obs_conv_thresh_array); - fcst_merge_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, - &fcst_merge_thresh_array, - &obs_merge_thresh_array); - obs_merge_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, - &fcst_merge_thresh_array, - &obs_merge_thresh_array); + Fcst->conv_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, + &(Fcst->conv_thresh_array), + &(Obs->conv_thresh_array)); + + Obs->conv_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, + &(Fcst->conv_thresh_array), + &(Obs->conv_thresh_array)); + + Fcst->merge_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, + &(Fcst->merge_thresh_array), + &(Obs->merge_thresh_array)); + + Obs->merge_thresh_array.set_perc(&fsort, &osort, (NumArray *) 0, + &(Fcst->merge_thresh_array), + &(Obs->merge_thresh_array)); return; @@ -703,17 +897,18 @@ void ModeConfInfo::set_conv_radius_by_index(int k) // the same number of elements // -if ( (k < 0) || (k >= fcst_conv_radius_array.n_elements()) ) { +if ( (k < 0) || (k >= Fcst->conv_radius_array.n_elements()) ) { - mlog << Error << "\nModeConfInfo::set_conv_radius_by_index(int) -> " + mlog << Error + << "\nModeConfInfo::set_conv_radius_by_index(int) -> " << "range check error\n\n"; exit ( 1 ); } -fcst_conv_radius = fcst_conv_radius_array[k]; - obs_conv_radius = obs_conv_radius_array[k]; +Fcst->conv_radius = Fcst->conv_radius_array[k]; + Obs->conv_radius = Obs->conv_radius_array[k]; return; @@ -732,17 +927,18 @@ void ModeConfInfo::set_conv_thresh_by_index(int k) // the same number of elements // -if ( (k < 0) || (k >= fcst_conv_thresh_array.n_elements()) ) { +if ( (k < 0) || (k >= Fcst->conv_thresh_array.n_elements()) ) { - mlog << Error << "\nModeConfInfo::set_conv_thresh_by_index(int) -> " + mlog << Error + << "\nModeConfInfo::set_conv_thresh_by_index(int) -> " << "range check error\n\n"; exit ( 1 ); } -fcst_conv_thresh = fcst_conv_thresh_array[k]; - obs_conv_thresh = obs_conv_thresh_array[k]; +Fcst->conv_thresh = Fcst->conv_thresh_array[k]; + Obs->conv_thresh = Obs->conv_thresh_array[k]; return; @@ -756,16 +952,21 @@ void ModeConfInfo::set_fcst_merge_thresh_by_index(int k) { -if ( (k < 0) || (k >= fcst_merge_thresh_array.n_elements()) ) { +Fcst->set_merge_thresh_by_index(k); - mlog << Error << "\nModeConfInfo::set_fcst_merge_thresh_by_index(int) -> " - << "range check error\n\n"; - - exit ( 1 ); +return; } -fcst_merge_thresh = fcst_merge_thresh_array[k]; + +//////////////////////////////////////////////////////////////////////// + + +void ModeConfInfo::set_obs_merge_thresh_by_index(int k) + +{ + +Obs->set_merge_thresh_by_index(k); return; @@ -775,22 +976,55 @@ return; //////////////////////////////////////////////////////////////////////// -void ModeConfInfo::set_obs_merge_thresh_by_index(int k) +int ModeConfInfo::n_runs() const { -if ( (k < 0) || (k >= obs_merge_thresh_array.n_elements()) ) { +const int nr = n_conv_radii(); +const int nt = n_conv_threshs(); - mlog << Error << "\nModeConfInfo::set_obs_merge_thresh_by_index(int) -> " - << "range check error\n\n"; +return ( nr*nt ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool ModeConfInfo::is_multivar() + +{ + +const DictionaryEntry * e = conf.lookup("fcst"); + +if ( e->type() != DictionaryType ) { + + mlog << Error + << "\n\n ModeConfInfo::is_multivar() const -> bad object type for entry \"fcst\"\n\n"; exit ( 1 ); } - obs_merge_thresh = obs_merge_thresh_array[k]; -return; +const DictionaryEntry * e2 = e->dict()->lookup("field"); +bool status = false; + +switch ( e2->type() ) { + + case ArrayType: status = true; break; + case DictionaryType: status = false; break; + + default: + mlog << Error + << "\n\n ModeConfInfo::is_multivar() const -> bad object type for entry \"fcst.field\"\n\n"; + exit ( 1 ); + break; + +} + + +return ( status ); } @@ -798,14 +1032,27 @@ return; //////////////////////////////////////////////////////////////////////// -int ModeConfInfo::n_runs() const +void ModeConfInfo::get_multivar_programs() { -const int nr = n_conv_radii(); -const int nt = n_conv_threshs(); +Dictionary * dict = (Dictionary *) 0; -return ( nr*nt ); +fcst_multivar_logic.clear(); + obs_multivar_logic.clear(); + + +dict = conf.lookup_dictionary(conf_key_fcst); + +if ( dict->lookup(conf_key_multivar_logic) ) fcst_multivar_logic = dict->lookup_string(conf_key_multivar_logic); + +dict = conf.lookup_dictionary(conf_key_obs); + +if ( dict->lookup(conf_key_multivar_logic) ) obs_multivar_logic = dict->lookup_string(conf_key_multivar_logic); + + + +return; } diff --git a/met/src/libcode/vx_shapedata/mode_conf_info.h b/met/src/libcode/vx_shapedata/mode_conf_info.h index 8e71a4f3c3..5e6c436f62 100644 --- a/met/src/libcode/vx_shapedata/mode_conf_info.h +++ b/met/src/libcode/vx_shapedata/mode_conf_info.h @@ -22,6 +22,8 @@ #include "vx_cal.h" #include "vx_math.h" +#include "mode_field_info.h" + //////////////////////////////////////////////////////////////////////// @@ -65,103 +67,75 @@ class ModeConfInfo { void init_from_scratch(); + int Field_Index; + + int N_fields; // = 1 for traditional MODE + // > 1 for multivar MODE + // should always be at least 1 + public: + ModeConfInfo(); ~ModeConfInfo(); void clear(); - void read_config (const char * default_filename, const char * user_filename); + void set_field_index(int); - void process_config (GrdFileType ftype, GrdFileType otype); + int field_index() const; - void set_perc_thresh(const DataPlane &, const DataPlane &); + bool is_multivar(); - void parse_nc_info (); + ConcatString fcst_multivar_logic; + ConcatString obs_multivar_logic; - void set_conv_radius_by_index (int); - void set_conv_thresh_by_index (int); + void get_multivar_programs(); - void set_fcst_merge_thresh_by_index (int); - void set_obs_merge_thresh_by_index (int); - int n_conv_threshs () const; - int n_conv_radii () const; + ///////////////////////////////////////////////////////////////////// - int n_fcst_merge_threshs () const; - int n_obs_merge_threshs () const; - int n_runs() const; // # threshs times # radii + Mode_Field_Info * fcst_array; // allocated + Mode_Field_Info * obs_array; // allocated - int get_compression_level(); - - // Store data parsed from the MODE configuration object + Mode_Field_Info * Fcst; // points to current field, not allocated + Mode_Field_Info * Obs; // points to current field, not allocated - MetConfig conf; // MODE configuration object - ConcatString model; // Model name - ConcatString desc; // Description - ConcatString obtype; // Observation type - - double grid_res; - - VarInfo * fcst_info; // allocated - VarInfo * obs_info; // allocated - - bool quilt; // default: false + ///////////////////////////////////////////////////////////////////// - IntArray fcst_conv_radius_array; // List of convolution radii in grid squares - IntArray obs_conv_radius_array; - int fcst_conv_radius; // Convolution radius in grid squares - int obs_conv_radius; + // + // configuration file + // - ThreshArray fcst_conv_thresh_array; // List of conv thresholds to use - ThreshArray obs_conv_thresh_array; - - SingleThresh fcst_conv_thresh; // Convolution threshold to define objects - SingleThresh obs_conv_thresh; - - double fcst_vld_thresh; // Minimum ratio of valid data points in the convolution area - double obs_vld_thresh; - - map fcst_filter_attr_map; // Discard objects that don't meet these attribute thresholds - map obs_filter_attr_map; - - ThreshArray fcst_merge_thresh_array; // Lower convolution threshold used for double merging method - ThreshArray obs_merge_thresh_array; - - SingleThresh fcst_merge_thresh; // Lower convolution threshold used for double merging method - SingleThresh obs_merge_thresh; - - MergeType fcst_merge_flag; // Define which merging methods should be employed - MergeType obs_merge_flag; - - FieldType mask_missing_flag; // Mask missing data between fcst and obs + MetConfig conf; // MODE configuration object - MatchType match_flag; // Define which matching methods should be employed + void read_config (const char * default_filename, const char * user_filename); + void process_config (GrdFileType ftype, GrdFileType otype); - double max_centroid_dist; // Only compare objects whose centroids are close enough (in grid squares) + void read_fields (Mode_Field_Info * &, Dictionary * dict, GrdFileType, char _fo); - ConcatString mask_grid_name; // Path for masking grid area - FieldType mask_grid_flag; // Define which fields should be masked out + // + // weights + // - ConcatString mask_poly_name; // Path for masking poly area - FieldType mask_poly_flag; // Define which fields should be masked out + double centroid_dist_wt; // Weights used as input to the fuzzy engine + double boundary_dist_wt; + double convex_hull_dist_wt; + double angle_diff_wt; + double aspect_diff_wt; + double area_ratio_wt; + double int_area_ratio_wt; + double curvature_ratio_wt; + double complexity_ratio_wt; + double inten_perc_ratio_wt; - double centroid_dist_wt; // Weights used as input to the fuzzy engine - double boundary_dist_wt; - double convex_hull_dist_wt; - double angle_diff_wt; - double aspect_diff_wt; - double area_ratio_wt; - double int_area_ratio_wt; - double curvature_ratio_wt; - double complexity_ratio_wt; - double inten_perc_ratio_wt; - int inten_perc_value; // Intensity percentile used for the intensity percentile ratio + // + // interest maps + // PiecewiseLinear * centroid_dist_if; // Interest functions used as input to the fuzzy engine PiecewiseLinear * boundary_dist_if; // not allocated @@ -174,30 +148,82 @@ class ModeConfInfo { PiecewiseLinear * complexity_ratio_if; PiecewiseLinear * inten_perc_ratio_if; - double total_interest_thresh; // Total interest threshold defining significance + // + // interest thresholds + // + double total_interest_thresh; // Total interest threshold defining significance double print_interest_thresh; // Only write output for pairs with this interest - ConcatString met_data_dir; // MET data directory + // + // limits + // - PlotInfo fcst_raw_pi; // Raw forecast plotting info - PlotInfo obs_raw_pi; // Raw observation plotting info - PlotInfo object_pi; // Object plotting info + double max_centroid_dist; // Only compare objects whose centroids are close enough (in grid squares) + + + // + // flags + // + bool quilt; // default: false bool plot_valid_flag; // Zoom up plot to the sub-region of valid data bool plot_gcarc_flag; // Plot lines as great-circle arcs bool ps_plot_flag; // Flag for the output PostScript image file // bool nc_pairs_flag; // output NetCDF file - ModeNcOutInfo nc_info; bool ct_stats_flag; // Flag for the output contingency table statistics file + FieldType mask_missing_flag; // Mask missing data between fcst and obs + MatchType match_flag; // Define which matching methods should be employed + FieldType mask_grid_flag; // Define which fields should be masked out + FieldType mask_poly_flag; // Define which fields should be masked out + + + // + // misc member data + // + + int inten_perc_value; // Intensity percentile used for the intensity percentile ratio + double grid_res; + + ConcatString model; // Model name + ConcatString desc; // Description + ConcatString obtype; // Observation type + + ConcatString mask_grid_name; // Path for masking grid area + ConcatString mask_poly_name; // Path for masking poly area + + ConcatString met_data_dir; // MET data directory + + PlotInfo object_pi; // Object plotting info + + ModeNcOutInfo nc_info; + int shift_right; // shift amount for global grids ConcatString output_prefix; // String to customize output file name ConcatString version; // Config file version - bool need_fcst_merge_thresh () const; // mergetype is both or thresh - bool need_obs_merge_thresh () const; // mergetype is both or thresh + // + // misc member functions + // + + void set_perc_thresh(const DataPlane &, const DataPlane &); + + void parse_nc_info (); + + void set_conv_radius_by_index (int); + void set_conv_thresh_by_index (int); + + int n_conv_threshs () const; + int n_conv_radii () const; + + int n_runs() const; // # threshs times # radii + + int get_compression_level(); + + void set_fcst_merge_thresh_by_index (int); + void set_obs_merge_thresh_by_index (int); }; @@ -205,23 +231,26 @@ class ModeConfInfo { //////////////////////////////////////////////////////////////////////// -inline int ModeConfInfo::n_conv_radii() const { return ( fcst_conv_radius_array.n_elements() ); } // should be the same as - // obs_conv_radius_array.n_elements() +inline int ModeConfInfo::n_conv_radii() const { return ( Fcst->conv_radius_array.n_elements() ); } // should be the same as + // obs_conv_radius_array.n_elements() -inline int ModeConfInfo::n_conv_threshs() const { return ( fcst_conv_thresh_array.n_elements() ); } // should be the same as - // obs_conv_thresh_array.n_elements() +inline int ModeConfInfo::n_conv_threshs() const { return ( Fcst->conv_thresh_array.n_elements() ); } // should be the same as + // obs_conv_thresh_array.n_elements() -inline int ModeConfInfo::n_fcst_merge_threshs () const { return ( fcst_merge_thresh_array.n_elements() ); } -inline int ModeConfInfo::n_obs_merge_threshs () const { return ( obs_merge_thresh_array.n_elements() ); } +// inline int ModeConfInfo::n_fcst_merge_threshs () const { return ( fcst->merge_thresh_array.n_elements() ); } +// inline int ModeConfInfo::n_obs_merge_threshs () const { return ( obs->merge_thresh_array.n_elements() ); } -inline bool ModeConfInfo::need_fcst_merge_thresh () const { return ( (fcst_merge_flag == MergeType_Both) || (fcst_merge_flag == MergeType_Thresh) ); } -inline bool ModeConfInfo::need_obs_merge_thresh () const { return ( ( obs_merge_flag == MergeType_Both) || ( obs_merge_flag == MergeType_Thresh) ); } +// inline bool ModeConfInfo::need_fcst_merge_thresh () const { return ( (fcst->merge_flag == MergeType_Both) || (fcst->merge_flag == MergeType_Thresh) ); } +// inline bool ModeConfInfo::need_obs_merge_thresh () const { return ( ( obs->merge_flag == MergeType_Both) || ( obs->merge_flag == MergeType_Thresh) ); } inline int ModeConfInfo::get_compression_level() { return conf.nc_compression(); } +inline int ModeConfInfo::field_index() const { return Field_Index; } + + //////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_shapedata/mode_data_field.h b/met/src/libcode/vx_shapedata/mode_data_field.h new file mode 100644 index 0000000000..7b5d7359a1 --- /dev/null +++ b/met/src/libcode/vx_shapedata/mode_data_field.h @@ -0,0 +1,64 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2019 +// ** 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 __MODE_DATA_FIELD_H__ +#define __MODE_DATA_FIELD_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include + + +//////////////////////////////////////////////////////////////////////// + + +class ModeDataField { + + private: + + void init_from_scratch(); + + void assign(const ModeDataField &); + + public: + + ModeDataField(); + ~ModeDataField(); + ModeDataField(const ModeDataField &); + ModeDataField & operator=(const ModeDataField &); + + void clear(); + + void dump(ostream &, int depth = 0) const; + + + + + + + + + +}; + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __MODE_DATA_FIELD_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/libcode/vx_shapedata/mode_field_info.cc b/met/src/libcode/vx_shapedata/mode_field_info.cc new file mode 100644 index 0000000000..bd3a55fc65 --- /dev/null +++ b/met/src/libcode/vx_shapedata/mode_field_info.cc @@ -0,0 +1,301 @@ + + +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2019 +// ** 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 "vx_config.h" +#include "vx_data2d.h" +#include "vx_grid.h" +#include "vx_util.h" +#include "vx_cal.h" +#include "vx_math.h" +#include "vx_data2d_factory.h" + +#include "mode_field_info.h" + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for class Mode_Field_Info + // + + +//////////////////////////////////////////////////////////////////////// + + +Mode_Field_Info::Mode_Field_Info() + +{ + +init_from_scratch(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Mode_Field_Info::~Mode_Field_Info() + +{ + +clear(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Mode_Field_Info::Mode_Field_Info(const Mode_Field_Info & i) + +{ + +init_from_scratch(); + +assign(i); + +} + + +//////////////////////////////////////////////////////////////////////// + + +Mode_Field_Info & Mode_Field_Info::operator=(const Mode_Field_Info & i) + +{ + +if ( this == &i ) return ( * this ); + +assign(i); + +return ( * this ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Mode_Field_Info::init_from_scratch() + +{ + +dict = 0; + +conf = 0; + +var_info = 0; + +clear(); + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Mode_Field_Info::clear() + +{ + +index = -1; + +dict = 0; // not allocated, so don't delete + +conf = 0; // not allocated, so don't delete + +gft = FileType_None; + +Multivar = false; + +FO = (char) 0; + +conv_radius = 0; + +vld_thresh = 0.0; + +if ( var_info ) { delete var_info; var_info = 0; } + +conv_radius_array.clear(); + +conv_thresh_array.clear(); + +merge_thresh_array.clear(); + +conv_thresh.clear(); + +merge_thresh.clear(); + +merge_flag = MergeType_Engine; + +// raw_pi.clear(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Mode_Field_Info::assign(const Mode_Field_Info & i) + +{ + +set(i.Multivar, i.index, i.dict, i.conf, i.gft, i.FO, true); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Mode_Field_Info::set (const bool _multivar, int _index, Dictionary * _dict, MetConfig * _conf, GrdFileType type, char _fo, bool do_clear) + +{ + +VarInfoFactory info_factory; + +if ( do_clear ) clear(); + +Multivar = _multivar; + +index = _index; + +dict = _dict; + +conf = _conf; + +var_info = info_factory.new_var_info(type); + +if ( _multivar ) { + + var_info->set_dict(*dict); + +} else { + + var_info->set_dict(*(dict->lookup_dictionary(conf_key_field))); + +} + +FO = _fo; + +gft = type; + +if ( dict->lookup(conf_key_raw_thresh) ) { + + mlog << Error + << "\nMode_Field_Info::process_config() -> " + << "the \"" << conf_key_raw_thresh << "\" entry is deprecated in MET " + << met_version << "! Use \"" << conf_key_censor_thresh << "\" and \"" + << conf_key_censor_val << "\" instead.\n\n"; + + exit(1); + +} + +if ( dict->lookup(conf_key_conv_radius) ) { + + conv_radius_array = dict->lookup_int_array(conf_key_conv_radius); + +} + +if ( dict->lookup(conf_key_conv_thresh) ) { + + conv_thresh_array = dict->lookup_thresh_array(conf_key_conv_thresh); + +} + +if ( dict->lookup(conf_key_merge_thresh) ) { + + merge_thresh_array = dict->lookup_thresh_array(conf_key_merge_thresh); + +} + +if ( dict->lookup(conf_key_vld_thresh) ) { + + vld_thresh = dict->lookup_double(conf_key_vld_thresh); + +} + +if ( dict->lookup(conf_key_merge_flag) ) { + + merge_flag = int_to_mergetype(dict->lookup_int(conf_key_merge_flag)); + +} + + +filter_attr_map = parse_conf_filter_attr_map(dict); + +if ( FO == 'F' ) raw_pi = parse_conf_plot_info(conf->lookup_dictionary(conf_key_fcst_raw_plot)); +else raw_pi = parse_conf_plot_info(conf->lookup_dictionary(conf_key_obs_raw_plot)); + + + + + // + // done + // + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Mode_Field_Info::set_merge_thresh_by_index (int k) + +{ + +if ( (k < 0) || (k >= merge_thresh_array.n_elements()) ) { + + mlog << Error << "\nMode_Field_Info::set_fcst_merge_thresh_by_index(int) -> " + << "range check error\n\n"; + + exit ( 1 ); + +} + +merge_thresh = merge_thresh_array[k]; + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Mode_Field_Info::need_merge_thresh () const + +{ + +bool status = (merge_flag == MergeType_Both) || (merge_flag == MergeType_Thresh); + +return ( status ); + +} + + +//////////////////////////////////////////////////////////////////////// + + + diff --git a/met/src/libcode/vx_shapedata/mode_field_info.h b/met/src/libcode/vx_shapedata/mode_field_info.h new file mode 100644 index 0000000000..800c396f13 --- /dev/null +++ b/met/src/libcode/vx_shapedata/mode_field_info.h @@ -0,0 +1,110 @@ + + +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2019 +// ** 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 __MODE_FIELD_INFO_H__ +#define __MODE_FIELD_INFO_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include "vx_config.h" +#include "vx_data2d.h" +#include "vx_grid.h" +#include "vx_util.h" +#include "vx_cal.h" +#include "vx_math.h" + + +//////////////////////////////////////////////////////////////////////// + + +typedef map AttrFilterMap; + + +//////////////////////////////////////////////////////////////////////// + + +class Mode_Field_Info { + + protected: + + void init_from_scratch(); + + void assign(const Mode_Field_Info &); + + + Dictionary * dict; // not allocated + + MetConfig * conf; // not allocated + + GrdFileType gft; + + char FO; // 'F' or 'O', for fcst or obs + + bool Multivar; + + public: + + Mode_Field_Info(); + ~Mode_Field_Info(); + Mode_Field_Info(const Mode_Field_Info &); + Mode_Field_Info & operator=(const Mode_Field_Info &); + + void clear(); + + void set (const bool _multivar, int _index, Dictionary *, MetConfig *, GrdFileType, char _fo, bool do_clear = false); + + int index; + + // + // member data + // + + int conv_radius; // Convolution radius in grid squares + double vld_thresh; // Minimum ratio of valid data points in the convolution area + + VarInfo * var_info; // allocated + IntArray conv_radius_array; // List of convolution radii in grid squares + + ThreshArray conv_thresh_array; // List of conv thresholds to use + ThreshArray merge_thresh_array; // Lower convolution threshold used for double merging method + SingleThresh conv_thresh; // Convolution threshold to define objects + SingleThresh merge_thresh; // Lower convolution threshold used for double merging method + + MergeType merge_flag; // Define which merging methods should be employed + + PlotInfo raw_pi; // Raw forecast plotting info + + // + // member functions + // + + void set_merge_thresh_by_index (int); + int n_merge_threshs () const; + bool need_merge_thresh () const; // mergetype is both or thresh + AttrFilterMap filter_attr_map; // Discard objects that don't meet these attribute thresholds + +}; + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __MODE_FIELD_INFO_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/tools/core/mode/Makefile.am b/met/src/tools/core/mode/Makefile.am index 662dee58ef..14df6b0ca8 100644 --- a/met/src/tools/core/mode/Makefile.am +++ b/met/src/tools/core/mode/Makefile.am @@ -11,7 +11,12 @@ include ${top_srcdir}/Make-include # The program bin_PROGRAMS = mode -mode_SOURCES = mode.cc \ +mode_SOURCES = mode_usage.cc \ + mode_frontend.cc \ + multivar_frontend.cc \ + mode.cc \ + combine_boolplanes.cc \ + objects_from_netcdf.cc \ mode_ps_file.cc \ plot_engine.cc \ page_1.cc \ @@ -45,6 +50,7 @@ mode_LDADD = -lvx_pxm \ -lvx_regrid \ -lvx_grid \ -lvx_config \ + -lvx_bool_calc \ -lvx_cal \ -lvx_util \ -lvx_math \ diff --git a/met/src/tools/core/mode/combine_boolplanes.cc b/met/src/tools/core/mode/combine_boolplanes.cc new file mode 100644 index 0000000000..3b9db02d39 --- /dev/null +++ b/met/src/tools/core/mode/combine_boolplanes.cc @@ -0,0 +1,111 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2022 +// ** 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 +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include + +#include "combine_boolplanes.h" + + +//////////////////////////////////////////////////////////////////////// + + // + // assumes all the input BoolPlanes (and the output BoolPlane) are the same size + // + +void combine_boolplanes(const BoolPlane * bpa, const int n_planes, + BoolCalc & calc, + BoolPlane & bp_out) + + +{ + +int j, x, y; +const int nx = bp_out.nx(); +const int ny = bp_out.ny(); +vector v(n_planes); +bool tf = false; + + +for (x=0; x @@ -71,7 +73,9 @@ using namespace std; #include #include -#include "mode_exec.h" +#include "string_array.h" +#include "mode_usage.h" +#include "mode_conf_info.h" #ifdef WITH_PYTHON #include "global_python.h" @@ -90,156 +94,65 @@ using namespace std; /////////////////////////////////////////////////////////////////////// -static const char program_name [] = "mode"; - -static ModeExecutive mode_exec; // gotta make this global ... not sure why - - -/////////////////////////////////////////////////////////////////////// - - -// static const char * default_out_dir = "MET_BASE/out/mode"; -static const char * default_out_dir = "."; +extern int mode_frontend(const StringArray &); +extern int multivar_frontend(const StringArray &); -static int compress_level = -1; +extern const char * const program_name; /////////////////////////////////////////////////////////////////////// -static void do_quilt (); -static void do_straight (); - -static void process_command_line(int, char **); - -static void usage(); - -static void set_config_merge_file (const StringArray &); -static void set_outdir (const StringArray &); -static void set_compress (const StringArray &); - - -/////////////////////////////////////////////////////////////////////// - - -int main(int argc, char * argv []) - -{ - - // - // Set handler to be called for memory allocation error - // - -set_new_handler(oom); - // - // Process the command line arguments + // these need external linkage // -process_command_line(argc, argv); - - // - // Process the forecast and observation files - // - -ModeConfInfo & conf = mode_exec.engine.conf_info; - -mode_exec.setup_fcst_obs_data(); +const char * const program_name = "mode"; -if (compress_level >= 0) conf.nc_info.set_compress_level(compress_level); +/////////////////////////////////////////////////////////////////////// -if ( conf.quilt ) { - - do_quilt(); - -} else { - - do_straight(); - -} - -mode_exec.clear(); - - // - // done - // - -#ifdef WITH_PYTHON - GP.finalize(); -#endif -return ( 0 ); - -} +static const char default_config_filename [] = "MET_BASE/config/MODEConfig_default"; /////////////////////////////////////////////////////////////////////// -void do_straight() +int main(int argc, char * argv []) { -const ModeConfInfo & conf = mode_exec.engine.conf_info; - -const int NCT = conf.n_conv_threshs(); -const int NCR = conf.n_conv_radii(); - -if ( NCT != NCR ) { - - mlog << Error - << "\n\n " - << program_name - << ": all convolution radius and threshold arrays must have the same number of elements!\n\n"; - - exit ( 1 ); - -} - -int index; +if ( argc == 1 ) both_usage(); -for (index=0; index #include #include @@ -223,29 +218,29 @@ void ModeExecutive::setup_fcst_obs_data() // Read the gridded data from the input forecast file - if ( !(fcst_mtddf->data_plane(*(engine.conf_info.fcst_info), Fcst_sd.data)) ) { + if ( !(fcst_mtddf->data_plane(*(engine.conf_info.Fcst->var_info), Fcst_sd.data)) ) { mlog << Error << "\nsetup_fcst_obs_data() -> " << "can't get forecast data \"" - << engine.conf_info.fcst_info->magic_str() + << engine.conf_info.Fcst->var_info->magic_str() << "\" from file \"" << fcst_file << "\"\n\n"; exit(1); } // Read the gridded data from the input observation file - if ( !(obs_mtddf->data_plane(*(engine.conf_info.obs_info), Obs_sd.data)) ) { + if ( !(obs_mtddf->data_plane(*(engine.conf_info.Obs->var_info), Obs_sd.data)) ) { mlog << Error << "\nsetup_fcst_obs_data() -> " << "can't get observation data \"" - << engine.conf_info.obs_info->magic_str() + << engine.conf_info.Obs->var_info->magic_str() << "\" from file \"" << obs_file << "\"\n\n"; exit(1); } // Determine the verification grid - grid = parse_vx_grid(engine.conf_info.fcst_info->regrid(), + grid = parse_vx_grid(engine.conf_info.Fcst->var_info->regrid(), &(fcst_mtddf->grid()), &(obs_mtddf->grid())); // Store the grid @@ -256,29 +251,29 @@ void ModeExecutive::setup_fcst_obs_data() if ( !(fcst_mtddf->grid() == grid) ) { mlog << Debug(1) - << "Regridding forecast " << engine.conf_info.fcst_info->magic_str() + << "Regridding forecast " << engine.conf_info.Fcst->var_info->magic_str() << " to the verification grid.\n"; Fcst_sd.data = met_regrid(Fcst_sd.data, fcst_mtddf->grid(), grid, - engine.conf_info.fcst_info->regrid()); + engine.conf_info.Fcst->var_info->regrid()); } // Regrid, if necessary if ( !(obs_mtddf->grid() == grid) ) { mlog << Debug(1) - << "Regridding observation " << engine.conf_info.obs_info->magic_str() + << "Regridding observation " << engine.conf_info.Obs->var_info->magic_str() << " to the verification grid.\n"; Obs_sd.data = met_regrid(Obs_sd.data, obs_mtddf->grid(), grid, - engine.conf_info.obs_info->regrid()); + engine.conf_info.Obs->var_info->regrid()); } // Rescale probabilites from [0, 100] to [0, 1] - if ( engine.conf_info.fcst_info->p_flag() ) rescale_probability(Fcst_sd.data); + if ( engine.conf_info.Fcst->var_info->p_flag() ) rescale_probability(Fcst_sd.data); // Rescale probabilites from [0, 100] to [0, 1] - if ( engine.conf_info.obs_info->p_flag() ) rescale_probability(Obs_sd.data); + if ( engine.conf_info.Obs->var_info->p_flag() ) rescale_probability(Obs_sd.data); // Print a warning if the valid times do not match @@ -288,32 +283,32 @@ void ModeExecutive::setup_fcst_obs_data() << "Forecast and observation valid times do not match " << unix_to_yyyymmdd_hhmmss(Fcst_sd.data.valid()) << " != " << unix_to_yyyymmdd_hhmmss(Obs_sd.data.valid()) << " for " - << engine.conf_info.fcst_info->magic_str() << " versus " - << engine.conf_info.obs_info->magic_str() << ".\n\n"; + << engine.conf_info.Fcst->var_info->magic_str() << " versus " + << engine.conf_info.Obs->var_info->magic_str() << ".\n\n"; } // Print a warning if the accumulation intervals do not match - if(engine.conf_info.fcst_info->level().type() == LevelType_Accum && - engine.conf_info.obs_info->level().type() == LevelType_Accum && + if(engine.conf_info.Fcst->var_info->level().type() == LevelType_Accum && + engine.conf_info.Obs->var_info->level().type() == LevelType_Accum && Fcst_sd.data.accum() != Obs_sd.data.accum()) { mlog << Warning << "\nsetup_fcst_obs_data() -> " << "Forecast and observation accumulation times do not match " << sec_to_hhmmss(Fcst_sd.data.valid()) << " != " << sec_to_hhmmss(Obs_sd.data.valid()) << " for " - << engine.conf_info.fcst_info->magic_str() << " versus " - << engine.conf_info.obs_info->magic_str() << ".\n\n"; + << engine.conf_info.Fcst->var_info->magic_str() << " versus " + << engine.conf_info.Obs->var_info->magic_str() << ".\n\n"; } mlog << Debug(1) << "Forecast Field: " - << engine.conf_info.fcst_info->name_attr() << " at " - << engine.conf_info.fcst_info->level_attr() + << engine.conf_info.Fcst->var_info->name_attr() << " at " + << engine.conf_info.Fcst->var_info->level_attr() << "\n" << "Observation Field: " - << engine.conf_info.obs_info->name_attr() << " at " - << engine.conf_info.obs_info->level_attr() + << engine.conf_info.Obs->var_info->name_attr() << " at " + << engine.conf_info.Obs->var_info->level_attr() << "\n"; // Mask out the missing data between fields @@ -374,8 +369,8 @@ T_index = t_index; conf.set_conv_radius_by_index (R_index); conf.set_conv_thresh_by_index (T_index); -if ( conf.need_fcst_merge_thresh () ) conf.set_fcst_merge_thresh_by_index (T_index); -if ( conf.need_obs_merge_thresh () ) conf.set_obs_merge_thresh_by_index (T_index); +if ( conf.Fcst->need_merge_thresh () ) conf.set_fcst_merge_thresh_by_index (T_index); +if ( conf.Obs->need_merge_thresh () ) conf.set_obs_merge_thresh_by_index (T_index); // // Set up the engine with these raw fields @@ -425,7 +420,7 @@ void ModeExecutive::do_match_merge() mlog << Debug(2) << "Performing merging (" - << mergetype_to_string(engine.conf_info.fcst_merge_flag) + << mergetype_to_string(engine.conf_info.Fcst->merge_flag) << ") in the forecast field.\n"; // Do the forecast merging @@ -434,7 +429,7 @@ void ModeExecutive::do_match_merge() mlog << Debug(2) << "Performing merging (" - << mergetype_to_string(engine.conf_info.obs_merge_flag) + << mergetype_to_string(engine.conf_info.Obs->merge_flag) << ") in the observation field.\n"; // Do the observation merging @@ -558,8 +553,8 @@ void ModeExecutive::compute_ct_stats() obs_mask = *engine.obs_raw; // Apply the thresholds specified in the config file - fcst_mask.threshold(engine.conf_info.fcst_conv_thresh); - obs_mask.threshold(engine.conf_info.obs_conv_thresh); + fcst_mask.threshold(engine.conf_info.Fcst->conv_thresh); + obs_mask.threshold(engine.conf_info.Obs->conv_thresh); } // Object fields else if(i == 1) { @@ -749,8 +744,8 @@ void ModeExecutive::write_obj_stats() out.close(); - if(engine.conf_info.fcst_merge_flag == MergeType_Both || - engine.conf_info.fcst_merge_flag == MergeType_Engine) { + if(engine.conf_info.Fcst->merge_flag == MergeType_Both || + engine.conf_info.Fcst->merge_flag == MergeType_Engine) { // // Create output stats file for forecast merging @@ -781,8 +776,8 @@ void ModeExecutive::write_obj_stats() out.close(); } - if(engine.conf_info.obs_merge_flag == MergeType_Both || - engine.conf_info.obs_merge_flag == MergeType_Engine) { + if(engine.conf_info.Obs->merge_flag == MergeType_Both || + engine.conf_info.Obs->merge_flag == MergeType_Engine) { // // Create output stats file for observation merging @@ -829,8 +824,8 @@ if ( info.all_false() ) return; int n, x, y; ConcatString out_file; ConcatString s; - const ConcatString fcst_thresh = engine.conf_info.fcst_conv_thresh.get_str(5); - const ConcatString obs_thresh = engine.conf_info.obs_conv_thresh.get_str(5); + const ConcatString fcst_thresh = engine.conf_info.Fcst->conv_thresh.get_str(5); + const ConcatString obs_thresh = engine.conf_info.Obs->conv_thresh.get_str(5); float *fcst_raw_data = (float *) 0; float *fcst_obj_raw_data = (float *) 0; @@ -963,8 +958,8 @@ if ( info.all_false() ) return; // write the radius and threshold values // - if ( !put_nc_data(&fcst_radius_var, &engine.conf_info.fcst_conv_radius) - || !put_nc_data(&obs_radius_var, &engine.conf_info.obs_conv_radius) ) { + if ( !put_nc_data(&fcst_radius_var, &engine.conf_info.Fcst->conv_radius) + || !put_nc_data(&obs_radius_var, &engine.conf_info.Obs->conv_radius) ) { mlog << Error << "write_obj_netcdf() -> " @@ -989,15 +984,14 @@ if ( info.all_false() ) return; // fcst and obs values for variable, level and units // - nc_add_string(f_out, engine.conf_info.fcst_info->name_attr().c_str(), "fcst_variable", "fcst_variable_length"); - nc_add_string(f_out, engine.conf_info.obs_info->name_attr().c_str(), "obs_variable", "obs_variable_length"); - - nc_add_string(f_out, engine.conf_info.fcst_info->level_attr().c_str(), "fcst_level", "fcst_level_length"); - nc_add_string(f_out, engine.conf_info.obs_info->level_attr().c_str(), "obs_level", "obs_level_length"); + nc_add_string(f_out, engine.conf_info.Fcst->var_info->name_attr().c_str(), "fcst_variable", "fcst_variable_length"); + nc_add_string(f_out, engine.conf_info.Obs->var_info->name_attr().c_str(), "obs_variable", "obs_variable_length"); - nc_add_string(f_out, engine.conf_info.fcst_info->units_attr().c_str(), "fcst_units", "fcst_units_length"); - nc_add_string(f_out, engine.conf_info.obs_info->units_attr().c_str(), "obs_units", "obs_units_length"); + nc_add_string(f_out, engine.conf_info.Fcst->var_info->level_attr().c_str(), "fcst_level", "fcst_level_length"); + nc_add_string(f_out, engine.conf_info.Obs->var_info->level_attr().c_str(), "obs_level", "obs_level_length"); + nc_add_string(f_out, engine.conf_info.Fcst->var_info->units_attr().c_str(), "fcst_units", "fcst_units_length"); + nc_add_string(f_out, engine.conf_info.Obs->var_info->units_attr().c_str(), "obs_units", "obs_units_length"); // Add forecast variable attributes diff --git a/met/src/tools/core/mode/mode_exec.h b/met/src/tools/core/mode/mode_exec.h index ee20a83795..934f674a30 100644 --- a/met/src/tools/core/mode/mode_exec.h +++ b/met/src/tools/core/mode/mode_exec.h @@ -1,8 +1,3 @@ - - -//////////////////////////////////////////////////////////////////////// - - // ** Copyright UCAR (c) 1992 - 2022 // ** University Corporation for Atmospheric Research (UCAR) // ** National Center for Atmospheric Research (NCAR) @@ -10,6 +5,7 @@ // ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + //////////////////////////////////////////////////////////////////////// @@ -45,6 +41,7 @@ using namespace netCDF; #include "mode_ps_file.h" + //////////////////////////////////////////////////////////////////////// @@ -158,4 +155,3 @@ inline int ModeExecutive::n_runs () const { return ( engine.conf_info.n_runs () ///////////////////////////////////////////////////////////////////////// - diff --git a/met/src/tools/core/mode/mode_frontend.cc b/met/src/tools/core/mode/mode_frontend.cc new file mode 100644 index 0000000000..1b8ce2937d --- /dev/null +++ b/met/src/tools/core/mode/mode_frontend.cc @@ -0,0 +1,345 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2019 +// ** 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 +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +/////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "string_array.h" + +#include "mode_usage.h" +#include "mode_exec.h" + +#ifdef WITH_PYTHON +#include "global_python.h" +#endif + + +/////////////////////////////////////////////////////////////////////// +// +// Create output files using the following naming convention: +// +// mode_YYYYMMDDI_FHH_HHA.ps/.txt +// +// Where I indicates initilization time, L indicates lead time, +// and A indicates accumulation time. +// +/////////////////////////////////////////////////////////////////////// + + +extern const char * const program_name; + +static ModeExecutive * mode_exec = 0; + + +/////////////////////////////////////////////////////////////////////// + + +static const char * default_out_dir = "."; + +static int compress_level = -1; + +static int field_index = -1; + + +/////////////////////////////////////////////////////////////////////// + + +static void do_quilt (); +static void do_straight (); + +static void process_command_line(const StringArray &); + + +static void set_config_merge_file (const StringArray &); +static void set_outdir (const StringArray &); +static void set_logfile (const StringArray &); +static void set_verbosity (const StringArray &); +static void set_compress (const StringArray &); + +static void set_field_index (const StringArray &); // undocumented + + +/////////////////////////////////////////////////////////////////////// + + +int mode_frontend(const StringArray & Argv) + +{ + + // + // Set handler to be called for memory allocation error + // + +set_new_handler(oom); + + // + // Process the command line arguments + // + +mode_exec = new ModeExecutive; + +process_command_line(Argv); + + + + // + // Process the forecast and observation files + // + +ModeConfInfo & conf = mode_exec->engine.conf_info; + +if ( field_index >= 0 ) conf.set_field_index(field_index); + +mode_exec->setup_fcst_obs_data(); + +if (compress_level >= 0) conf.nc_info.set_compress_level(compress_level); + + +if ( conf.quilt ) { + + do_quilt(); + +} else { + + do_straight(); + +} + +// mode_exec.clear(); + + // + // done + // + +#ifdef WITH_PYTHON + GP.finalize(); +#endif + +if ( mode_exec ) { delete mode_exec; mode_exec = 0; } + +return ( 0 ); + +} + + +/////////////////////////////////////////////////////////////////////// + + +void do_straight() + +{ + +const ModeConfInfo & conf = mode_exec->engine.conf_info; + +const int NCT = conf.n_conv_threshs(); +const int NCR = conf.n_conv_radii(); + +if ( NCT != NCR ) { + + mlog << Error + << "\n\n " + << program_name + << ": all convolution radius and threshold arrays must have the same number of elements!\n\n"; + + exit ( 1 ); + +} + +int index; + +for (index=0; indexdo_conv_thresh(index, index); + + mode_exec->do_match_merge(); + + mode_exec->process_output(); + +} + + + // + // done + // + +return; + +} + + +/////////////////////////////////////////////////////////////////////// + + +void do_quilt() + +{ + +int t_index, r_index; // indices into the convolution threshold and radius arrays + + +for (r_index=0; r_index<(mode_exec->n_conv_radii()); ++r_index) { + + for (t_index=0; t_index<(mode_exec->n_conv_threshs()); ++t_index) { + + mode_exec->do_conv_thresh(r_index, t_index); + + mode_exec->do_match_merge(); + + mode_exec->process_output(); + + } + +} + + // + // done + // + +return; + +} + + +/////////////////////////////////////////////////////////////////////// + + +void process_command_line(const StringArray & argv) + +{ + + CommandLine cline; + ConcatString s; + const int argc = argv.n(); + + + // Set the default output directory + mode_exec->out_dir = replace_path(default_out_dir); + + // Check for zero arguments + if(argc == 1) singlevar_usage(); + + // Parse the command line into tokens + cline.set(argv); + + // Set the usage function + cline.set_usage(singlevar_usage); + + // Add the options function calls + cline.add(set_config_merge_file, "-config_merge", 1); + cline.add(set_outdir, "-outdir", 1); + cline.add(set_logfile, "-log", 1); + cline.add(set_verbosity, "-v", 1); + cline.add(set_compress, "-compress", 1); + + // + // add for mode multivar ... undocumented + // + + cline.add(set_field_index, "-field_index", 1); + + // Parse the command line + cline.parse(); + + // Check for error. There should be three arguments left: + // forecast, observation, and config filenames + if(cline.n() != 3) singlevar_usage(); + + // Store the input forecast and observation file names + mode_exec->fcst_file = cline[0]; + mode_exec->obs_file = cline[1]; + mode_exec->match_config_file = cline[2]; + + mode_exec->init(); + + return; + +} + +/////////////////////////////////////////////////////////////////////// + +void set_config_merge_file(const StringArray & a) +{ + mode_exec->merge_config_file = a[0]; +} + +//////////////////////////////////////////////////////////////////////// + +void set_outdir(const StringArray & a) +{ + mode_exec->out_dir = a[0]; +} + +//////////////////////////////////////////////////////////////////////// + +void set_logfile(const StringArray & a) +{ + ConcatString filename; + + filename = a[0]; + + mlog.open_log_file(filename); +} + +//////////////////////////////////////////////////////////////////////// + +void set_verbosity(const StringArray & a) +{ + mlog.set_verbosity_level(atoi(a[0].c_str())); +} + +//////////////////////////////////////////////////////////////////////// + +void set_compress(const StringArray & a) { + compress_level = atoi(a[0].c_str()); +} + +//////////////////////////////////////////////////////////////////////// + + +void set_field_index(const StringArray & a) + +{ + +field_index = atoi(a[0].c_str()); + +if ( field_index < 0 ) { + + mlog << Error + << program_name << ": bad index value ... " + << field_index << "\n\n"; + + exit ( 1 ); + +} + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + + diff --git a/met/src/tools/core/mode/mode_multivar.cc b/met/src/tools/core/mode/mode_multivar.cc new file mode 100644 index 0000000000..aa4174c6e7 --- /dev/null +++ b/met/src/tools/core/mode/mode_multivar.cc @@ -0,0 +1,335 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2019 +// ** 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 +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +/////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mode_usage.h" +#include "mode_exec.h" + +#ifdef WITH_PYTHON +#include "global_python.h" +#endif + + +/////////////////////////////////////////////////////////////////////// +// +// Create output files using the following naming convention: +// +// mode_YYYYMMDDI_FHH_HHA.ps/.txt +// +// Where I indicates initilization time, L indicates lead time, +// and A indicates accumulation time. +// +/////////////////////////////////////////////////////////////////////// + + +extern const char * const program_name; + +static ModeExecutive mode_exec; // gotta make this global ... not sure why + + +/////////////////////////////////////////////////////////////////////// + + +static const char * default_out_dir = "."; + +static int compress_level = -1; + +static int field_index = -1; + + +/////////////////////////////////////////////////////////////////////// + + +static void do_quilt (); +static void do_straight (); + +static void process_command_line(int, char **); + +static void set_config_merge_file (const StringArray &); +static void set_outdir (const StringArray &); +static void set_logfile (const StringArray &); +static void set_verbosity (const StringArray &); +static void set_compress (const StringArray &); + +static void set_field_index (const StringArray &); // undocumented + + +/////////////////////////////////////////////////////////////////////// + + +int main_multivar(int argc, char * argv []) + +{ + + // + // Set handler to be called for memory allocation error + // + +set_new_handler(oom); + + // + // Process the command line arguments + // + +process_command_line(argc, argv); + + // + // Process the forecast and observation files + // + +ModeConfInfo & conf = mode_exec.engine.conf_info; + +if ( field_index >= 0 ) conf.set_field_index(field_index); + +mode_exec.setup_fcst_obs_data(); + +if (compress_level >= 0) conf.nc_info.set_compress_level(compress_level); + + +if ( conf.quilt ) { + + do_quilt(); + +} else { + + do_straight(); + +} + +mode_exec.clear(); + + // + // done + // + +#ifdef WITH_PYTHON + GP.finalize(); +#endif + +return ( 0 ); + +} + + +/////////////////////////////////////////////////////////////////////// + + +void do_straight() + +{ + +const ModeConfInfo & conf = mode_exec.engine.conf_info; + +const int NCT = conf.n_conv_threshs(); +const int NCR = conf.n_conv_radii(); + +if ( NCT != NCR ) { + + mlog << Error + << "\n\n " + << program_name + << ": all convolution radius and threshold arrays must have the same number of elements!\n\n"; + + exit ( 1 ); + +} + +int index; + +for (index=0; indexmet_data_dir; ConcatString s; - s = replace_path(ConfInfo->fcst_raw_pi.color_table.c_str()); + s = replace_path(ConfInfo->Fcst->raw_pi.color_table.c_str()); mlog << Debug(1) << "Loading forecast raw color table: " << s << "\n"; FcstRawCtable.read(s.c_str()); - s = replace_path(ConfInfo->obs_raw_pi.color_table.c_str()); + s = replace_path(ConfInfo->Obs->raw_pi.color_table.c_str()); mlog << Debug(1) << "Loading observation raw color table: " << s << "\n"; @@ -208,7 +209,7 @@ mlog << Debug(1) << "Loading observation raw color table: " << s << "\n"; // data_min and data_max values // -if ( (ConfInfo->fcst_info->name_attr() == ConfInfo->obs_info->name_attr()) && +if ( (ConfInfo->Fcst->var_info->name_attr() == ConfInfo->Obs->var_info->name_attr()) && is_eq( FcstRawCtable.data_min (bad_data_double), 0.0) && is_eq( FcstRawCtable.data_max (bad_data_double), 1.0) && is_eq( ObsRawCtable.data_min (bad_data_double), 0.0) && @@ -249,11 +250,11 @@ if ( (ConfInfo->fcst_info->name_attr() == ConfInfo->obs_info->name_attr()) && // config file, rescale the forecast colortable to the requested range // -if ( !is_eq(ConfInfo->fcst_raw_pi.plot_min, 0.0) || - !is_eq(ConfInfo->fcst_raw_pi.plot_max, 0.0) ) { +if ( !is_eq(ConfInfo->Fcst->raw_pi.plot_min, 0.0) || + !is_eq(ConfInfo->Fcst->raw_pi.plot_max, 0.0) ) { - FcstRawCtable.rescale(ConfInfo->fcst_raw_pi.plot_min, - ConfInfo->fcst_raw_pi.plot_max, + FcstRawCtable.rescale(ConfInfo->Fcst->raw_pi.plot_min, + ConfInfo->Fcst->raw_pi.plot_max, bad_data_double); } @@ -263,11 +264,11 @@ if ( !is_eq(ConfInfo->fcst_raw_pi.plot_min, 0.0) || // config file, rescale the observation colortable to the requested range // -if ( !is_eq(ConfInfo->obs_raw_pi.plot_min, 0.0) || - !is_eq(ConfInfo->obs_raw_pi.plot_max, 0.0) ) { +if ( !is_eq(ConfInfo->Obs->raw_pi.plot_min, 0.0) || + !is_eq(ConfInfo->Obs->raw_pi.plot_max, 0.0) ) { - ObsRawCtable.rescale(ConfInfo->obs_raw_pi.plot_min, - ConfInfo->obs_raw_pi.plot_max, + ObsRawCtable.rescale(ConfInfo->Obs->raw_pi.plot_min, + ConfInfo->Obs->raw_pi.plot_max, bad_data_double); } @@ -541,15 +542,15 @@ void ModePsFile::make_plot() { -const MergeType fcst_merge_flag = ConfInfo->fcst_merge_flag; -const MergeType obs_merge_flag = ConfInfo->obs_merge_flag; +const MergeType fcst_merge_flag = ConfInfo->Fcst->merge_flag; +const MergeType obs_merge_flag = ConfInfo->Obs->merge_flag; ConcatString s; s << cs_erase - << "MODE: " << ConfInfo->fcst_info->name_attr() << " at " - << ConfInfo->fcst_info->level_attr() << " vs " - << ConfInfo->obs_info->name_attr() << " at " - << ConfInfo->obs_info->level_attr(); + << "MODE: " << ConfInfo->Fcst->var_info->name_attr() << " at " + << ConfInfo->Fcst->var_info->level_attr() << " vs " + << ConfInfo->Obs->var_info->name_attr() << " at " + << ConfInfo->Obs->var_info->level_attr(); plot_engine(*Engine, FOEng, s.c_str()); @@ -602,12 +603,12 @@ const double h_tab_cen = PageWidth/2.0; if ( fcst ) { merge_mask = *(eng.fcst_conv); - merge_mask.threshold(eng.conf_info.fcst_merge_thresh); + merge_mask.threshold(eng.conf_info.Fcst->merge_thresh); } else { merge_mask = *(eng.obs_conv); - merge_mask.threshold(eng.conf_info.obs_merge_thresh); + merge_mask.threshold(eng.conf_info.Obs->merge_thresh); } diff --git a/met/src/tools/core/mode/mode_ps_file.h b/met/src/tools/core/mode/mode_ps_file.h index 92749b9b46..4bcb213365 100644 --- a/met/src/tools/core/mode/mode_ps_file.h +++ b/met/src/tools/core/mode/mode_ps_file.h @@ -202,5 +202,3 @@ inline void ModePsFile::nextline() { text_y -= TextSep; return; } //////////////////////////////////////////////////////////////////////// - - diff --git a/met/src/tools/core/mode/mode_ps_table_defs.h b/met/src/tools/core/mode/mode_ps_table_defs.h index e60f90d764..35ebecf99b 100644 --- a/met/src/tools/core/mode/mode_ps_table_defs.h +++ b/met/src/tools/core/mode/mode_ps_table_defs.h @@ -1,8 +1,4 @@ - - -//////////////////////////////////////////////////////////////////////// - - +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // ** Copyright UCAR (c) 1992 - 2022 // ** University Corporation for Atmospheric Research (UCAR) // ** National Center for Atmospheric Research (NCAR) @@ -49,5 +45,3 @@ static Color dark_gray = blend_colors(white, black, 0.50); //////////////////////////////////////////////////////////////////////// - - diff --git a/met/src/tools/core/mode/mode_singlevar.cc b/met/src/tools/core/mode/mode_singlevar.cc new file mode 100644 index 0000000000..fc747ba499 --- /dev/null +++ b/met/src/tools/core/mode/mode_singlevar.cc @@ -0,0 +1,335 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2019 +// ** 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 +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mode_usage.h" +#include "mode_exec.h" + +#ifdef WITH_PYTHON +#include "global_python.h" +#endif + + +/////////////////////////////////////////////////////////////////////// +// +// Create output files using the following naming convention: +// +// mode_YYYYMMDDI_FHH_HHA.ps/.txt +// +// Where I indicates initilization time, L indicates lead time, +// and A indicates accumulation time. +// +/////////////////////////////////////////////////////////////////////// + + +extern const char * const program_name; + +static ModeExecutive mode_exec; // gotta make this global ... not sure why + + +/////////////////////////////////////////////////////////////////////// + + +static const char * default_out_dir = "."; + +static int compress_level = -1; + +static int field_index = -1; + + +/////////////////////////////////////////////////////////////////////// + + +static void do_quilt (); +static void do_straight (); + +static void process_command_line(int, char **); + +static void set_config_merge_file (const StringArray &); +static void set_outdir (const StringArray &); +static void set_logfile (const StringArray &); +static void set_verbosity (const StringArray &); +static void set_compress (const StringArray &); + +static void set_field_index (const StringArray &); // undocumented + + +/////////////////////////////////////////////////////////////////////// + + +int main_singlevar(int argc, char * argv []) + +{ + + // + // Set handler to be called for memory allocation error + // + +set_new_handler(oom); + + // + // Process the command line arguments + // + +process_command_line(argc, argv); + + // + // Process the forecast and observation files + // + +ModeConfInfo & conf = mode_exec.engine.conf_info; + +if ( field_index >= 0 ) conf.set_field_index(field_index); + +mode_exec.setup_fcst_obs_data(); + +if (compress_level >= 0) conf.nc_info.set_compress_level(compress_level); + + +if ( conf.quilt ) { + + do_quilt(); + +} else { + + do_straight(); + +} + +mode_exec.clear(); + + // + // done + // + +#ifdef WITH_PYTHON + GP.finalize(); +#endif + +return ( 0 ); + +} + + +/////////////////////////////////////////////////////////////////////// + + +void do_straight() + +{ + +const ModeConfInfo & conf = mode_exec.engine.conf_info; + +const int NCT = conf.n_conv_threshs(); +const int NCR = conf.n_conv_radii(); + +if ( NCT != NCR ) { + + mlog << Error + << "\n\n " + << program_name + << ": all convolution radius and threshold arrays must have the same number of elements!\n\n"; + + exit ( 1 ); + +} + +int index; + +for (index=0; index + +#include "mode_usage.h" +#include "mode_exec.h" + +#include "util_constants.h" +#include "logger.h" + + +//////////////////////////////////////////////////////////////////////// + + +extern const char * const program_name; + +extern ModeExecutive mode_exec; + + +//////////////////////////////////////////////////////////////////////// + + +void both_usage() + +{ + + +cout << "\n*** Model Evaluation Tools (MET" << met_version << ") ***\n\n"; + +cout << "Single Variable MODE:\n" + "=====================\n"; + +singlevar_usage(); + +cout << "Multi Variable MODE:\n" + << "====================\n"; + +multivar_usage(); + +exit ( 1 ); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void singlevar_usage() + +{ + +cout << "\n\n" + << "Usage: " << program_name << "\n" + << "\tfcst_file\n" + << "\tobs_file\n" + << "\tconfig_file\n" + << "\t[-config_merge merge_config_file]\n" + << "\t[-outdir path]\n" + << "\t[-log file]\n" + << "\t[-v level]\n" + << "\t[-compress level]\n\n" + + << "\twhere\n" + + << "\t\t\"fcst_file\" is a gridded forecast file " + << "containing the field to be verified (required).\n" + + << "\t\t\"obs_file\" is a gridded observation file " + << "containing the verifying field (required).\n" + + << "\t\t\"config_file\" is a MODEConfig file " + << "containing the desired configuration settings (required).\n" + + << "\t\t\"-config_merge merge_config_file\" overrides the default " + << "fuzzy engine settings for merging within the fcst/obs fields " + << "(optional).\n" + + << "\t\t\"-outdir path\" overrides the default output directory " + << "(./) (optional).\n" + + << "\t\t\"-log file\" outputs log messages to the specified " + << "file (optional).\n" + + << "\t\t\"-v level\" overrides the default level of logging (" + << mlog.verbosity_level() << ") (optional).\n" + + << "\t\t\"-compress level\" overrides the compression level of " + << "NetCDF variable (optional).\n\n" + + << flush; + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void multivar_usage() + +{ + +cout << "\n\n" + << "\tUsage: " << program_name << "\n" + << "\tfcst_file_list\n" + << "\tobs_file_list\n" + << "\tconfig_file\n" + << "\t[-outdir path]\n" + << "\t[-log file]\n" + << "\t[-v level]\n" + + << "\twhere\n" + + << "\t\t\"fcst_file_list\" is an ASCII file containing a list of " + << "forecast files to be used (required).\n" + + << "\t\t\"obs_file_list\" is an ASCII file containing a list of " + << "observation files to be used (required).\n" + + << "\t\t\"config\" is a MODEConfig file containing the desired " + << "configuration settings (required).\n" + + << "\t\t\"-outdir path\" overrides the default output directory " + << "(./) (optional).\n" + + << "\t\t\"-log file\" outputs log messages to the specified file " + << "(optional).\n" + + << "\t\t\"-v level\" overrides the default level of logging (" + << mlog.verbosity_level() << ") (optional).\n\n" + + << flush; + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/core/mode/mode_usage.h b/met/src/tools/core/mode/mode_usage.h new file mode 100644 index 0000000000..441c924a80 --- /dev/null +++ b/met/src/tools/core/mode/mode_usage.h @@ -0,0 +1,33 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2022 +// ** 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 __MODE_USAGE_H__ +#define __MODE_USAGE_H__ + + +//////////////////////////////////////////////////////////////////////// + + +extern void both_usage(); + +extern void singlevar_usage(); + +extern void multivar_usage(); + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __MODE_USAGE_H__ */ + + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/core/mode/multivar_frontend.cc b/met/src/tools/core/mode/multivar_frontend.cc new file mode 100644 index 0000000000..5d4e9b4bfc --- /dev/null +++ b/met/src/tools/core/mode/multivar_frontend.cc @@ -0,0 +1,568 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2022 +// ** 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 +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +//////////////////////////////////////////////////////////////////////// + + +static const char fcst_super_nc_filename [] = "f_super.nc"; +static const char obs_super_nc_filename [] = "o_super.nc"; + +static const char mode_default_config [] = "MET_BASE/config/MODEConfig_default"; + +static const char super_object_var_name [] = "super"; + +static const int dir_creation_mode = 0755; + +static const float on_value = (float) 100.0; +static const float off_value = (float) 0.0; + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "vx_util.h" +#include "file_exists.h" +#include "two_d_array.h" +#include "get_filenames.h" +#include "mode_conf_info.h" +#include "shapedata.h" +#include "interest.h" +#include "met_file.h" +#include "mode_usage.h" +#include "mode_exec.h" + +#include "combine_boolplanes.h" +#include "objects_from_netcdf.h" +#include "parse_file_list.h" + + +using namespace netCDF; + + +//////////////////////////////////////////////////////////////////////// + + +extern int mode_frontend(const StringArray &); + + +//////////////////////////////////////////////////////////////////////// + + +extern const char * const program_name; + + +static const char sep [] = "===================================================="; + +static const char tab [] = " "; + +static const bool do_clusters = false; + +static ModeConfInfo config; + +static string mode_path; +static string fcst_fof; +static string obs_fof; +static string config_file; +static string outdir; + + +//////////////////////////////////////////////////////////////////////// + + +static void set_outdir (const StringArray &); +static void set_logfile (const StringArray &); +static void set_verbosity (const StringArray &); + + +static void read_config(const string & filename); + +static void run_command(const ConcatString & command); + +static void process_command_line(const StringArray &); + +static void write_output_nc_file(const char * path, const MetNcFile &, const BoolPlane &); + + +//////////////////////////////////////////////////////////////////////// + + +int multivar_frontend(const StringArray & Argv) + +{ + +const int Argc = Argv.n(); + +if ( Argc < 4 ) multivar_usage(); + +int j; +StringArray fcst_filenames; +StringArray obs_filenames; +ConcatString dir; + + +process_command_line(Argv); + + +read_config(config_file); + +if ( config.fcst_multivar_logic.empty() ) { + + mlog << Error << "\n" << program_name + << ": fcst multivar logic not specified!\n\n"; + + exit ( 1 ); + +} + + +if ( config.obs_multivar_logic.empty() ) { + + mlog << Error << "\n" << program_name + << ": obs multivar logic not specified!\n\n"; + + exit ( 1 ); + +} + + // + // make sure the multivar logic programs are in the config file + // + +fcst_filenames = parse_ascii_file_list(fcst_fof.c_str()); + obs_filenames = parse_ascii_file_list(obs_fof.c_str()); + +if ( fcst_filenames.n() != obs_filenames.n() ) { + + mlog << Error << "\n" << program_name + << ": number of fcst and obs files should be the same!\n\n"; + + exit ( 1 ); + +} + +const int n_files = fcst_filenames.n(); +ConcatString mode_args; +ConcatString command; +StringArray a, nc_files, mode_argv; +int status; +char junk [256]; + +mlog << Debug(2) << "\n" << sep << "\n"; + + // + // check for no inputs + // + +if ( n_files == 0 ) { + + mlog << Error << "\n" << program_name + << ": no input forecast files to process!\n\n"; + + exit ( 1 ); + +} + + // + // do the individual mode runs + // + +for (j=0; j 0 ) dir << outdir << '/'; + + snprintf(junk, sizeof(junk), "%02d", j); + + dir << junk; + + if ( ! directory_exists(dir.c_str()) ) { + + mlog << Debug(2) + << program_name << ": creating output directory \"" + << dir << "\"\n\n"; + + status = mkdir(dir.c_str(), dir_creation_mode); + + if ( status < 0 ) { + + mlog << Error << "\n" << program_name + << ": unable to create output directory \"" + << dir << "\"\n\n"; + + exit ( 1 ); + + } + + } + + // + // build the command for running mode + // + + mode_argv.clear(); + + mode_argv.add(mode_path); + mode_argv.add(fcst_filenames[j]); + mode_argv.add(obs_filenames[j]); + mode_argv.add(config_file); + + command << cs_erase + << mode_path << ' ' + << fcst_filenames[j] << ' ' + << obs_filenames[j] << ' ' + << config_file; + + mode_argv.add("-v"); + snprintf(junk, sizeof(junk), "%d", mlog.verbosity_level()); + mode_argv.add(junk); + + mode_argv.add("-outdir"); + mode_argv.add(dir); + + command << " -v " << mlog.verbosity_level(); + + command << " -outdir " << dir; + + mode_argv.add("-field_index"); + snprintf(junk, sizeof(junk), "%d", j); + mode_argv.add(junk); + + command << " -field_index " << j; + + // + // run mode + // + + mlog << Debug(1) << "Running mode command: \"" << command << "\"\n\n"; + + run_command(command); + + // [TODO] MET #1238: run MODE in memory instead of via system calls. + // (void) mode_frontend(mode_argv); + + mlog << Debug(2) << "\n finished mode run " << (j + 1) << " of " << n_files + << "\n" << sep << "\n"; + + a = get_filenames_from_dir(dir.text(), "mode_", ".nc"); + + nc_files.add(a); + +} // for j + +mlog << Debug(2) << "\n finished with individual mode runs " + << "\n" << sep << "\n"; + +BoolPlane * f_plane = new BoolPlane [n_files]; +BoolPlane * o_plane = new BoolPlane [n_files]; +BoolPlane f_result, o_result; +Pgm image; + + // + // load the objects from the mode output files + // + +for (j=0; j vdim(2); + + +for (x=0; x + +#include "objects_from_netcdf.h" + + +//////////////////////////////////////////////////////////////////////// + + +using namespace netCDF; + + +//////////////////////////////////////////////////////////////////////// + + + // + // these don't seem to be collected in any header file + // + // that I could find + // + + +static const string lat_dim_name = "lat"; +static const string lon_dim_name = "lon"; + +static const string fcst_simple_id_var_name = "fcst_obj_id"; +static const string obs_simple_id_var_name = "obs_obj_id"; + +static const string fcst_cluster_id_var_name = "fcst_clus_id"; +static const string obs_cluster_id_var_name = "obs_clus_id"; + + +//////////////////////////////////////////////////////////////////////// + + +static void populate_bool_plane(const int * buf, const int nx, const int ny, BoolPlane & bp_out); + + +//////////////////////////////////////////////////////////////////////// + + +void objects_from_netcdf(const char * netcdf_filename, + bool do_clusters, // do we look at cluster objects or simple objects? + BoolPlane & fcst_out, + BoolPlane & obs_out) + +{ + +int * buf = 0; +const string * fcst_var_name = 0; +const string * obs_var_name = 0; + +if ( do_clusters ) { + + fcst_var_name = &fcst_cluster_id_var_name; + obs_var_name = &obs_cluster_id_var_name; + +} else { + + fcst_var_name = &fcst_simple_id_var_name; + obs_var_name = &obs_simple_id_var_name; + +} + + + // + // open the netcdf file + // + +NcFile nc((std::string) netcdf_filename, NcFile::read); + + // + // grab the lat/lon dimensions + // + +NcDim lat_dim, lon_dim; + +lat_dim = nc.getDim(lat_dim_name); +lon_dim = nc.getDim(lon_dim_name); + + // + // use the lat/lon dimensions to set the size of the bool planes + // + +const int n_lat = (int) lat_dim.getSize(); +const int n_lon = (int) lon_dim.getSize(); +const int nx = n_lon; +const int ny = n_lat; + +buf = new int [nx*ny]; + + // + // grab the netcdf variables + // + +NcVar f_var, o_var; + +f_var = nc.getVar(*fcst_var_name); +o_var = nc.getVar( *obs_var_name); + + // + // populate the bool planes + // + +f_var.getVar(buf); + +populate_bool_plane(buf, nx, ny, fcst_out); + +o_var.getVar(buf); + +populate_bool_plane(buf, nx, ny, obs_out); + + // + // done + // + +if ( buf ) { delete [] buf; buf = 0; } + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void populate_bool_plane(const int * buf, const int nx, const int ny, BoolPlane & bp_out) + +{ + +int x, y, n, k; +bool tf; + +bp_out.set_size(nx, ny); + +for (x=0; x 0 ); + + bp_out.put(tf, x, y); + + } // for y + +} // for x + + + + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + + diff --git a/met/src/tools/core/mode/objects_from_netcdf.h b/met/src/tools/core/mode/objects_from_netcdf.h new file mode 100644 index 0000000000..aa6e8e1fb1 --- /dev/null +++ b/met/src/tools/core/mode/objects_from_netcdf.h @@ -0,0 +1,49 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2022 +// ** 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 __MODE_OBJECTS_FROM_NETCDF_H__ +#define __MODE_OBJECTS_FROM_NETCDF_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include "two_d_array.h" + + +//////////////////////////////////////////////////////////////////////// + + + // + // grabs the objects from a MODE output netcdf file + // + + +//////////////////////////////////////////////////////////////////////// + + +extern void objects_from_netcdf(const char * netcdf_filename, + bool do_clusters, // do we look at cluster objects or simple objects? + BoolPlane & fcst_out, + BoolPlane & obs_out); + + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __MODE_OBJECTS_FROM_NETCDF_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + diff --git a/met/src/tools/core/mode/page_1.cc b/met/src/tools/core/mode/page_1.cc index 4d1d23e636..a72442dc99 100644 --- a/met/src/tools/core/mode/page_1.cc +++ b/met/src/tools/core/mode/page_1.cc @@ -332,8 +332,8 @@ t1.write_xy1_to_cell(1, 2, 0.0, dy, 0.5, 0.0, eng.conf_info.model.c_str()); nextline(); -t1.write_xy1_to_cell(2, 1, dx, dy, 0.0, 0.0, eng.conf_info.fcst_info->name_attr().c_str()); -t1.write_xy1_to_cell(2, 2, dx, dy, 0.0, 0.0, eng.conf_info.obs_info->name_attr().c_str()); +t1.write_xy1_to_cell(2, 1, dx, dy, 0.0, 0.0, eng.conf_info.Fcst->var_info->name_attr().c_str()); +t1.write_xy1_to_cell(2, 2, dx, dy, 0.0, 0.0, eng.conf_info.Obs->var_info->name_attr().c_str()); // // Level Name @@ -341,8 +341,8 @@ t1.write_xy1_to_cell(2, 2, dx, dy, 0.0, 0.0, eng.conf_info.obs_info->name_attr() nextline(); -t1.write_xy1_to_cell(3, 1, dx, dy, 0.0, 0.0, eng.conf_info.fcst_info->level_attr().c_str()); -t1.write_xy1_to_cell(3, 2, dx, dy, 0.0, 0.0, eng.conf_info.obs_info->level_attr().c_str()); +t1.write_xy1_to_cell(3, 1, dx, dy, 0.0, 0.0, eng.conf_info.Fcst->var_info->level_attr().c_str()); +t1.write_xy1_to_cell(3, 2, dx, dy, 0.0, 0.0, eng.conf_info.Obs->var_info->level_attr().c_str()); // // Units @@ -350,8 +350,8 @@ t1.write_xy1_to_cell(3, 2, dx, dy, 0.0, 0.0, eng.conf_info.obs_info->level_attr( nextline(); -t1.write_xy1_to_cell(4, 1, dx, dy, 0.0, 0.0, eng.conf_info.fcst_info->units_attr().c_str()); -t1.write_xy1_to_cell(4, 2, dx, dy, 0.0, 0.0, eng.conf_info.obs_info->units_attr().c_str()); +t1.write_xy1_to_cell(4, 1, dx, dy, 0.0, 0.0, eng.conf_info.Fcst->var_info->units_attr().c_str()); +t1.write_xy1_to_cell(4, 2, dx, dy, 0.0, 0.0, eng.conf_info.Obs->var_info->units_attr().c_str()); // // Initialization Time @@ -720,10 +720,10 @@ roman(); // // Convolution Radius // - snprintf(junk, sizeof(junk), "%d", eng.conf_info.fcst_conv_radius); + snprintf(junk, sizeof(junk), "%d", eng.conf_info.Fcst->conv_radius); t.write_xy1_to_cell(r, 1, dx, dy, 0.0, 0.0, junk); - snprintf(junk, sizeof(junk), "%d", eng.conf_info.obs_conv_radius); + snprintf(junk, sizeof(junk), "%d", eng.conf_info.Obs->conv_radius); t.write_xy1_to_cell(r, 2, dx, dy, 0.0, 0.0, junk); ++r; @@ -732,10 +732,10 @@ roman(); // // Convolution Threshold // - thresh_str = eng.conf_info.fcst_conv_thresh.get_str(2); + thresh_str = eng.conf_info.Fcst->conv_thresh.get_str(2); t.write_xy1_to_cell(r, 1, dx, dy, 0.0, 0.0, thresh_str.c_str()); - thresh_str = eng.conf_info.obs_conv_thresh.get_str(2); + thresh_str = eng.conf_info.Obs->conv_thresh.get_str(2); t.write_xy1_to_cell(r, 2, dx, dy, 0.0, 0.0, thresh_str.c_str()); ++r; @@ -745,10 +745,10 @@ roman(); // Object Filters // - snprintf(junk, sizeof(junk), "%i", (int) eng.conf_info.fcst_filter_attr_map.size()); + snprintf(junk, sizeof(junk), "%i", (int) eng.conf_info.Fcst->filter_attr_map.size()); t.write_xy1_to_cell(r, 1, dx, dy, 0.0, 0.0, junk); - snprintf(junk, sizeof(junk), "%i", (int) eng.conf_info.obs_filter_attr_map.size()); + snprintf(junk, sizeof(junk), "%i", (int) eng.conf_info.Obs->filter_attr_map.size()); t.write_xy1_to_cell(r, 2, dx, dy, 0.0, 0.0, junk); ++r; @@ -773,10 +773,10 @@ roman(); // Merge Threshold // - thresh_str = eng.conf_info.fcst_merge_thresh.get_str(2); + thresh_str = eng.conf_info.Fcst->merge_thresh.get_str(2); t.write_xy1_to_cell(r, 1, dx, dy, 0.0, 0.0, thresh_str.c_str()); - thresh_str = eng.conf_info.obs_merge_thresh.get_str(2); + thresh_str = eng.conf_info.Obs->merge_thresh.get_str(2); t.write_xy1_to_cell(r, 2, dx, dy, 0.0, 0.0, thresh_str.c_str()); ++r; @@ -792,15 +792,15 @@ roman(); // Merging flag // - if(eng.conf_info.fcst_merge_flag == MergeType_Thresh) label = "thresh"; - else if(eng.conf_info.fcst_merge_flag == MergeType_Engine) label = "engine"; - else if(eng.conf_info.fcst_merge_flag == MergeType_Both) label = "thresh/engine"; + if(eng.conf_info.Fcst->merge_flag == MergeType_Thresh) label = "thresh"; + else if(eng.conf_info.Fcst->merge_flag == MergeType_Engine) label = "engine"; + else if(eng.conf_info.Fcst->merge_flag == MergeType_Both) label = "thresh/engine"; else label = "none"; t.write_xy1_to_cell(r, 1, dx, dy, 0.0, 0.0, label.c_str()); - if(eng.conf_info.obs_merge_flag == MergeType_Thresh) label = "thresh"; - else if(eng.conf_info.obs_merge_flag == MergeType_Engine) label = "engine"; - else if(eng.conf_info.obs_merge_flag == MergeType_Both) label = "thresh/engine"; + if(eng.conf_info.Obs->merge_flag == MergeType_Thresh) label = "thresh"; + else if(eng.conf_info.Obs->merge_flag == MergeType_Engine) label = "engine"; + else if(eng.conf_info.Obs->merge_flag == MergeType_Both) label = "thresh/engine"; else label = "none"; t.write_xy1_to_cell(r, 2, dx, dy, 0.0, 0.0, label.c_str()); diff --git a/test/bin/unit_test.sh b/test/bin/unit_test.sh index 0c95bba7ac..eff6bc65da 100755 --- a/test/bin/unit_test.sh +++ b/test/bin/unit_test.sh @@ -55,6 +55,7 @@ UNIT_XML="unit_ascii2nc.xml \ unit_ensemble_stat.xml \ unit_stat_analysis_es.xml \ unit_mode.xml \ + unit_mode_multivar.xml \ unit_mode_analysis.xml \ unit_plot_point_obs.xml \ unit_plot_data_plane.xml \ diff --git a/test/config/MODEConfig_multivar_fake_data b/test/config/MODEConfig_multivar_fake_data new file mode 100644 index 0000000000..282d7e7ec7 --- /dev/null +++ b/test/config/MODEConfig_multivar_fake_data @@ -0,0 +1,259 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// MODE configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "WRF"; + +// +// Output description to be written +// +desc = "NA"; + +// +// Output observation type to be written +// +obtype = "PRECIP"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Approximate grid resolution (km) +// +grid_res = 20; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Run all permutations of radius and threshold +// +quilt = FALSE; + +// +// MODE Multivar boolean combination logic +// +multivar_logic = "#1 && #2 && #3"; + +// +// Forecast and observation fields to be verified +// +fcst = { + + field = [ + + { + name = "ALPHA"; + level = "(*,*)"; + }, + + { + name = "BETA"; + level = "(*,*)"; + }, + + { + name = "GAMMA"; + level = "(*,*)"; + } + + ]; + + conv_radius = 2; // in grid squares + conv_thresh = >=5.0; + vld_thresh = 0.5; + filter_attr_name = []; + filter_attr_thresh = []; + merge_thresh = >=3.5; + merge_flag = NONE; +} +obs = fcst; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Handle missing data +// +mask_missing_flag = NONE; + +// +// Match objects between the forecast and observation fields +// +match_flag = NONE; + +// +// Maximum centroid distance for objects to be compared +// +max_centroid_dist = 800.0/grid_res; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification masking regions +// +mask = { + grid = ""; + grid_flag = NONE; // Apply to NONE, FCST, OBS, or BOTH + poly = ""; + poly_flag = NONE; // Apply to NONE, FCST, OBS, or BOTH +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Fuzzy engine weights +// +weight = { + centroid_dist = 2.0; + boundary_dist = 4.0; + convex_hull_dist = 0.0; + angle_diff = 1.0; + aspect_diff = 0.0; + area_ratio = 1.0; + int_area_ratio = 2.0; + curvature_ratio = 0.0; + complexity_ratio = 0.0; + inten_perc_ratio = 0.0; + inten_perc_value = 50; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Fuzzy engine interest functions +// +interest_function = { + + centroid_dist = ( + ( 0.0, 1.0 ) + ( 60.0/grid_res, 1.0 ) + ( 600.0/grid_res, 0.0 ) + ); + + boundary_dist = ( + ( 0.0, 1.0 ) + ( 400.0/grid_res, 0.0 ) + ); + + convex_hull_dist = ( + ( 0.0, 1.0 ) + ( 400.0/grid_res, 0.0 ) + ); + + angle_diff = ( + ( 0.0, 1.0 ) + ( 30.0, 1.0 ) + ( 90.0, 0.0 ) + ); + + aspect_diff = ( + ( 0.00, 1.0 ) + ( 0.10, 1.0 ) + ( 0.75, 0.0 ) + ); + + corner = 0.8; + ratio_if = ( + ( 0.0, 0.0 ) + ( corner, 1.0 ) + ( 1.0, 1.0 ) + ); + + area_ratio = ratio_if; + + int_area_ratio = ( + ( 0.00, 0.00 ) + ( 0.10, 0.50 ) + ( 0.25, 1.00 ) + ( 1.00, 1.00 ) + ); + + curvature_ratio = ratio_if; + + complexity_ratio = ratio_if; + + inten_perc_ratio = ratio_if; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Total interest threshold for determining matches +// +total_interest_thresh = 0.7; + +// +// Interest threshold for printing output pair information +// +print_interest_thresh = 0.0; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Plotting information +// +met_data_dir = "MET_BASE"; + +fcst_raw_plot = { + color_table = "MET_BASE/colortables/met_default.ctable"; + plot_min = 0.0; + plot_max = 25.4; +} + +obs_raw_plot = { + color_table = "MET_BASE/colortables/met_default.ctable"; + plot_min = 0.0; + plot_max = 25.4; +} + +object_plot = { + color_table = "MET_BASE/colortables/mode_obj.ctable"; +} + +// +// Boolean for plotting on the region of valid data within the domain +// +plot_valid_flag = FALSE; + +// +// Plot polyline edges using great circle arcs instead of straight lines +// +plot_gcarc_flag = FALSE; + +//////////////////////////////////////////////////////////////////////////////// + +// +// NetCDF matched pairs, PostScript, and contingency table output files +// +ps_plot_flag = TRUE; +nc_pairs_flag = TRUE; +ct_stats_flag = TRUE; + +//////////////////////////////////////////////////////////////////////////////// + +shift_right = 0; // grid squares + +//////////////////////////////////////////////////////////////////////////////// + +output_prefix = ""; +version = "V10.1.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/xml/unit_mode_multivar.xml b/test/xml/unit_mode_multivar.xml new file mode 100644 index 0000000000..ebfcf179cb --- /dev/null +++ b/test/xml/unit_mode_multivar.xml @@ -0,0 +1,42 @@ + + + + + + + + + + +]> + + + + &TEST_DIR; + true + + + echo "&DATA_DIR_MODEL;/mode_multivar/alpha_fcst.nc \ + &DATA_DIR_MODEL;/mode_multivar/beta_fcst.nc \ + &DATA_DIR_MODEL;/mode_multivar/gamma_fcst.nc" \ + > &OUTPUT_DIR;/mode_multivar/input_fcst_file_list; \ + echo "&DATA_DIR_MODEL;/mode_multivar/alpha_obs.nc \ + &DATA_DIR_MODEL;/mode_multivar/beta_obs.nc \ + &DATA_DIR_MODEL;/mode_multivar/gamma_obs.nc" \ + > &OUTPUT_DIR;/mode_multivar/input_obs_file_list; \ + &MET_BIN;/mode + \ + &OUTPUT_DIR;/mode_multivar/input_fcst_file_list \ + &OUTPUT_DIR;/mode_multivar/input_obs_file_list \ + &CONFIG_DIR;/MODEConfig_multivar_fake_data \ + -outdir &OUTPUT_DIR;/mode_multivar \ + -v 2 + + + &OUTPUT_DIR;/mode_multivar/f_super.nc + &OUTPUT_DIR;/mode_multivar/o_super.nc + + + +