MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /* 00002 * compareMaps.cpp 00003 * this tool will take 2 existing map files in nc format, and compare their sparse matrices 00004 * we can compare xc, yc, areas, fractions with ncdiff from nco 00005 * maybe there is another utility in nco, need to ask Charlie Zender 00006 * 00007 * example of usage: 00008 * ./mbcmpmaps -i map1.nc -j map2.nc 00009 * will look for row, col, S entries, and use eigen3 sparse matrix constructor 00010 * 00011 * can be built only if netcdf and eigen3 are available 00012 * 00013 * 00014 */ 00015 #include "moab/MOABConfig.h" 00016 00017 #ifndef MOAB_HAVE_EIGEN3 00018 #error compareMaps tool requires eigen3 configuration 00019 #endif 00020 00021 #include "moab/ProgOptions.hpp" 00022 00023 #include "netcdf.h" 00024 #include <cmath> 00025 #include <iomanip> 00026 #include <Eigen/Sparse> 00027 #define ERR_NC( e ) \ 00028 { \ 00029 printf( "Error: %s\n", nc_strerror( e ) ); \ 00030 exit( 2 ); \ 00031 } 00032 00033 // copy from ReadNCDF.cpp some useful macros for reading from a netcdf file (exodus?) 00034 // ncFile is an integer initialized when opening the nc file in read mode 00035 00036 int ncFile1; 00037 00038 #define INS_ID( stringvar, prefix, id ) sprintf( stringvar, prefix, id ) 00039 00040 #define GET_DIM1( ncdim, name, val ) \ 00041 { \ 00042 int gdfail = nc_inq_dimid( ncFile1, name, &( ncdim ) ); \ 00043 if( NC_NOERR == gdfail ) \ 00044 { \ 00045 size_t tmp_val; \ 00046 gdfail = nc_inq_dimlen( ncFile1, ncdim, &tmp_val ); \ 00047 if( NC_NOERR != gdfail ) \ 00048 { \ 00049 ERR_NC( gdfail ) \ 00050 } \ 00051 else \ 00052 ( val ) = tmp_val; \ 00053 } \ 00054 else \ 00055 ( val ) = 0; \ 00056 } 00057 00058 #define GET_DIMB1( ncdim, name, varname, id, val ) \ 00059 INS_ID( name, varname, id ); \ 00060 GET_DIM1( ncdim, name, val ); 00061 00062 #define GET_VAR1( name, id, dims ) \ 00063 { \ 00064 ( id ) = -1; \ 00065 int gvfail = nc_inq_varid( ncFile1, name, &( id ) ); \ 00066 if( NC_NOERR == gvfail ) \ 00067 { \ 00068 int ndims; \ 00069 gvfail = nc_inq_varndims( ncFile1, id, &ndims ); \ 00070 if( NC_NOERR == gvfail ) \ 00071 { \ 00072 ( dims ).resize( ndims ); \ 00073 gvfail = nc_inq_vardimid( ncFile1, id, &( dims )[0] ); \ 00074 if( NC_NOERR != gvfail ) \ 00075 { \ 00076 ERR_NC( gvfail ) \ 00077 } \ 00078 } \ 00079 } \ 00080 } 00081 00082 #define GET_1D_INT_VAR1( name, id, vals ) \ 00083 { \ 00084 GET_VAR1( name, id, vals ); \ 00085 if( -1 != ( id ) ) \ 00086 { \ 00087 size_t ntmp; \ 00088 int ivfail = nc_inq_dimlen( ncFile1, ( vals )[0], &ntmp ); \ 00089 if( NC_NOERR != ivfail ) \ 00090 { \ 00091 ERR_NC( ivfail ) \ 00092 } \ 00093 ( vals ).resize( ntmp ); \ 00094 size_t ntmp1 = 0; \ 00095 ivfail = nc_get_vara_int( ncFile1, id, &ntmp1, &ntmp, &( vals )[0] ); \ 00096 if( NC_NOERR != ivfail ) \ 00097 { \ 00098 ERR_NC( ivfail ) \ 00099 } \ 00100 } \ 00101 } 00102 00103 #define GET_1D_DBL_VAR1( name, id, vals ) \ 00104 { \ 00105 std::vector< int > dum_dims; \ 00106 GET_VAR1( name, id, dum_dims ); \ 00107 if( -1 != ( id ) ) \ 00108 { \ 00109 size_t ntmp; \ 00110 int dvfail = nc_inq_dimlen( ncFile1, dum_dims[0], &ntmp ); \ 00111 if( NC_NOERR != dvfail ) \ 00112 { \ 00113 ERR_NC( dvfail ) \ 00114 } \ 00115 ( vals ).resize( ntmp ); \ 00116 size_t ntmp1 = 0; \ 00117 dvfail = nc_get_vara_double( ncFile1, id, &ntmp1, &ntmp, &( vals )[0] ); \ 00118 if( NC_NOERR != dvfail ) \ 00119 { \ 00120 ERR_NC( dvfail ) \ 00121 } \ 00122 } \ 00123 } 00124 00125 int ncFile2; 00126 00127 #define GET_DIM2( ncdim, name, val ) \ 00128 { \ 00129 int gdfail = nc_inq_dimid( ncFile2, name, &( ncdim ) ); \ 00130 if( NC_NOERR == gdfail ) \ 00131 { \ 00132 size_t tmp_val; \ 00133 gdfail = nc_inq_dimlen( ncFile2, ncdim, &tmp_val ); \ 00134 if( NC_NOERR != gdfail ) \ 00135 { \ 00136 ERR_NC( gdfail ) \ 00137 } \ 00138 else \ 00139 ( val ) = tmp_val; \ 00140 } \ 00141 else \ 00142 ( val ) = 0; \ 00143 } 00144 00145 #define GET_DIMB2( ncdim, name, varname, id, val ) \ 00146 INS_ID( name, varname, id ); \ 00147 GET_DIM2( ncdim, name, val ); 00148 00149 #define GET_VAR2( name, id, dims ) \ 00150 { \ 00151 ( id ) = -1; \ 00152 int gvfail = nc_inq_varid( ncFile2, name, &( id ) ); \ 00153 if( NC_NOERR == gvfail ) \ 00154 { \ 00155 int ndims; \ 00156 gvfail = nc_inq_varndims( ncFile2, id, &ndims ); \ 00157 if( NC_NOERR == gvfail ) \ 00158 { \ 00159 ( dims ).resize( ndims ); \ 00160 gvfail = nc_inq_vardimid( ncFile2, id, &( dims )[0] ); \ 00161 if( NC_NOERR != gvfail ) \ 00162 { \ 00163 ERR_NC( gvfail ) \ 00164 } \ 00165 } \ 00166 } \ 00167 } 00168 00169 #define GET_1D_INT_VAR2( name, id, vals ) \ 00170 { \ 00171 GET_VAR2( name, id, vals ); \ 00172 if( -1 != ( id ) ) \ 00173 { \ 00174 size_t ntmp; \ 00175 int ivfail = nc_inq_dimlen( ncFile2, ( vals )[0], &ntmp ); \ 00176 if( NC_NOERR != ivfail ) \ 00177 { \ 00178 ERR_NC( ivfail ) \ 00179 } \ 00180 ( vals ).resize( ntmp ); \ 00181 size_t ntmp1 = 0; \ 00182 ivfail = nc_get_vara_int( ncFile2, id, &ntmp1, &ntmp, &( vals )[0] ); \ 00183 if( NC_NOERR != ivfail ) \ 00184 { \ 00185 ERR_NC( ivfail ) \ 00186 } \ 00187 } \ 00188 } 00189 00190 #define GET_1D_DBL_VAR2( name, id, vals ) \ 00191 { \ 00192 std::vector< int > dum_dims; \ 00193 GET_VAR2( name, id, dum_dims ); \ 00194 if( -1 != ( id ) ) \ 00195 { \ 00196 size_t ntmp; \ 00197 int dvfail = nc_inq_dimlen( ncFile2, dum_dims[0], &ntmp ); \ 00198 if( NC_NOERR != dvfail ) \ 00199 { \ 00200 ERR_NC( dvfail ) \ 00201 } \ 00202 ( vals ).resize( ntmp ); \ 00203 size_t ntmp1 = 0; \ 00204 dvfail = nc_get_vara_double( ncFile2, id, &ntmp1, &ntmp, &( vals )[0] ); \ 00205 if( NC_NOERR != dvfail ) \ 00206 { \ 00207 ERR_NC( dvfail ) \ 00208 } \ 00209 } \ 00210 } 00211 00212 #define GET_2D_DBL_VAR1( name, id, vals ) \ 00213 { \ 00214 std::vector< int > dum_dims; \ 00215 GET_VAR1( name, id, dum_dims ); \ 00216 if( -1 != ( id ) ) \ 00217 { \ 00218 size_t ntmp[2]; \ 00219 int dvfail = nc_inq_dimlen( ncFile1, dum_dims[0], &ntmp[0] ); \ 00220 if( NC_NOERR != dvfail ) \ 00221 { \ 00222 ERR_NC( dvfail ) \ 00223 } \ 00224 dvfail = nc_inq_dimlen( ncFile1, dum_dims[1], &ntmp[1] ); \ 00225 if( NC_NOERR != dvfail ) \ 00226 { \ 00227 ERR_NC( dvfail ) \ 00228 } \ 00229 ( vals ).resize( ntmp[0] * ntmp[1] ); \ 00230 size_t ntmp1[2] = { 0, 0 }; \ 00231 dvfail = nc_get_vara_double( ncFile1, id, ntmp1, ntmp, &( vals )[0] ); \ 00232 if( NC_NOERR != dvfail ) \ 00233 { \ 00234 ERR_NC( dvfail ) \ 00235 } \ 00236 } \ 00237 } 00238 00239 #define GET_2D_DBL_VAR2( name, id, vals ) \ 00240 { \ 00241 std::vector< int > dum_dims; \ 00242 GET_VAR2( name, id, dum_dims ); \ 00243 if( -1 != ( id ) ) \ 00244 { \ 00245 size_t ntmp[2]; \ 00246 int dvfail = nc_inq_dimlen( ncFile2, dum_dims[0], &ntmp[0] ); \ 00247 if( NC_NOERR != dvfail ) \ 00248 { \ 00249 ERR_NC( dvfail ) \ 00250 } \ 00251 dvfail = nc_inq_dimlen( ncFile2, dum_dims[1], &ntmp[1] ); \ 00252 if( NC_NOERR != dvfail ) \ 00253 { \ 00254 ERR_NC( dvfail ) \ 00255 } \ 00256 ( vals ).resize( ntmp[0] * ntmp[1] ); \ 00257 size_t ntmp1[2] = { 0, 0 }; \ 00258 dvfail = nc_get_vara_double( ncFile2, id, ntmp1, ntmp, &( vals )[0] ); \ 00259 if( NC_NOERR != dvfail ) \ 00260 { \ 00261 ERR_NC( dvfail ) \ 00262 } \ 00263 } \ 00264 } 00265 00266 typedef Eigen::Map< Eigen::VectorXd > EigenV; 00267 00268 void diff_vect( const char* var_name, int n ) 00269 { 00270 // compare frac_a between maps 00271 std::vector< double > fraca1( n ), fraca2( n ); 00272 int idfa1, idfa2; 00273 GET_1D_DBL_VAR1( var_name, idfa1, fraca1 ); 00274 EigenV fa1( fraca1.data(), n ); 00275 GET_1D_DBL_VAR2( var_name, idfa2, fraca2 ); 00276 EigenV fa2( fraca2.data(), n ); 00277 00278 EigenV diff( fraca2.data(), n ); 00279 diff = fa1 - fa2; 00280 00281 int imin, imax; 00282 double minV = diff.minCoeff( &imin ); 00283 double maxV = diff.maxCoeff( &imax ); 00284 std::cout << var_name << " diff norm: " << diff.norm() << " min at " << imin << " : " << minV << " max at " << imax 00285 << " : " << maxV << "\n"; 00286 return; 00287 } 00288 00289 void diff_2d_vect( const char* var_name, int n ) 00290 { 00291 // compare frac_a between maps 00292 std::vector< double > fraca1( n ), fraca2( n ); 00293 int idfa1, idfa2; 00294 GET_2D_DBL_VAR1( var_name, idfa1, fraca1 ); 00295 EigenV fa1( fraca1.data(), n ); 00296 GET_2D_DBL_VAR2( var_name, idfa2, fraca2 ); 00297 EigenV fa2( fraca2.data(), n ); 00298 std::cout << var_name << " diff norm: " << ( fa1 - fa2 ).norm() << "\n"; 00299 return; 00300 } 00301 int main( int argc, char* argv[] ) 00302 { 00303 00304 ProgOptions opts; 00305 00306 std::string inputfile1, inputfile2; 00307 opts.addOpt< std::string >( "firstMap,i", "input filename 1", &inputfile1 ); 00308 opts.addOpt< std::string >( "secondMap,j", "input second map", &inputfile2 ); 00309 int print_diff = 20; 00310 opts.addOpt< int >( "print_differences,p", "print differences ", &print_diff ); 00311 double fraction = 0.9; 00312 opts.addOpt< double >( "fraction_diff,f", "fraction threshold", &fraction ); 00313 00314 opts.parseCommandLine( argc, argv ); 00315 00316 // Open netcdf/exodus file 00317 int fail = nc_open( inputfile1.c_str(), 0, &ncFile1 ); 00318 if( NC_NOWRITE != fail ) 00319 { 00320 ERR_NC( fail ) 00321 } 00322 00323 std::cout << " opened " << inputfile1 << " for map 1 \n"; 00324 00325 fail = nc_open( inputfile2.c_str(), 0, &ncFile2 ); 00326 if( NC_NOWRITE != fail ) 00327 { 00328 ERR_NC( fail ) 00329 } 00330 00331 std::cout << " opened " << inputfile2 << " for map 2 \n"; 00332 int temp_dim; 00333 int na1, nb1, ns1, na2, nb2, ns2, nv_a, nv_b, nv_a2, nv_b2; 00334 GET_DIM1( temp_dim, "n_a", na1 ); 00335 GET_DIM2( temp_dim, "n_a", na2 ); 00336 GET_DIM1( temp_dim, "n_b", nb1 ); 00337 GET_DIM2( temp_dim, "n_b", nb2 ); 00338 GET_DIM1( temp_dim, "n_s", ns1 ); 00339 GET_DIM2( temp_dim, "n_s", ns2 ); 00340 GET_DIM1( temp_dim, "nv_a", nv_a ); 00341 GET_DIM2( temp_dim, "nv_a", nv_a2 ); 00342 GET_DIM1( temp_dim, "nv_b", nv_b ); 00343 GET_DIM2( temp_dim, "nv_b", nv_b2 ); 00344 if( nv_a != nv_a2 || nv_b != nv_b2 ) 00345 { 00346 std::cout << " different nv dimensions:" << nv_a << " == " << nv_a2 << " or " << nv_b << " == " << nv_b2 00347 << " bail out \n"; 00348 return 1; 00349 } 00350 std::cout << " n_a, n_b, n_s : " << na1 << ", " << nb1 << ", " << ns1 << " for map 1 \n"; 00351 00352 std::cout << " n_a, n_b, n_s : " << na2 << ", " << nb2 << ", " << ns2 << " for map 2 \n"; 00353 if( na1 != na2 || nb1 != nb2 ) 00354 { 00355 std::cout << " different dimensions bail out \n"; 00356 return 1; 00357 } 00358 std::vector< int > col1( ns1 ), row1( ns1 ); 00359 std::vector< int > col2( ns2 ), row2( ns2 ); 00360 00361 std::vector< double > val1( ns1 ), val2( ns2 ); 00362 00363 int idrow1, idcol1, idrow2, idcol2, ids1, ids2; 00364 GET_1D_INT_VAR1( "row", idrow1, row1 ); 00365 GET_1D_INT_VAR1( "col", idcol1, col1 ); 00366 GET_1D_DBL_VAR1( "S", ids1, val1 ); 00367 GET_1D_INT_VAR2( "row", idrow2, row2 ); 00368 GET_1D_INT_VAR2( "col", idcol2, col2 ); 00369 GET_1D_DBL_VAR2( "S", ids2, val2 ); 00370 00371 // first matrix 00372 typedef Eigen::Triplet< double > Triplet; 00373 std::vector< Triplet > tripletList; 00374 tripletList.reserve( ns1 ); 00375 for( int iv = 0; iv < ns1; iv++ ) 00376 { 00377 tripletList.push_back( Triplet( row1[iv] - 1, col1[iv] - 1, val1[iv] ) ); 00378 } 00379 Eigen::SparseMatrix< double > weight1( nb1, na1 ); 00380 00381 weight1.setFromTriplets( tripletList.begin(), tripletList.end() ); 00382 weight1.makeCompressed(); 00383 00384 if( ns1 != ns2 ) tripletList.resize( ns2 ); 00385 for( int iv = 0; iv < ns2; iv++ ) 00386 { 00387 tripletList[iv] = Triplet( row2[iv] - 1, col2[iv] - 1, val2[iv] ); 00388 } 00389 Eigen::SparseMatrix< double > weight2( nb2, na2 ); 00390 00391 weight2.setFromTriplets( tripletList.begin(), tripletList.end() ); 00392 weight2.makeCompressed(); 00393 00394 // default storage type is column major 00395 Eigen::SparseMatrix< double > diff = weight1 - weight2; 00396 diff.makeCompressed(); // is it needed or not ? 00397 auto coeffs = diff.coeffs(); 00398 double maxv = coeffs.maxCoeff(); 00399 double minv = coeffs.minCoeff(); 00400 std::cout << " euclidian norm for difference: " << diff.norm() 00401 << " \n squared norm for difference: " << diff.squaredNorm() << "\n" 00402 << " minv: " << minv << " maxv: " << maxv << "\n"; 00403 // print out the first 10 positions for which the value is outside 90% of min/max values 00404 double min_threshold = fraction * minv; 00405 double max_threshold = fraction * maxv; 00406 int counter = 0; 00407 std::cout << std::setprecision( 9 ); 00408 for( int k = 0; ( k < diff.outerSize() ); ++k ) // this is by column 00409 { 00410 for( Eigen::SparseMatrix< double >::InnerIterator it( diff, k ); ( it ) && ( counter < print_diff ); ++it ) 00411 { 00412 double val = it.value(); 00413 if( val <= min_threshold || val >= max_threshold ) 00414 { 00415 int row = it.row(); 00416 int col = it.col(); 00417 std::cout << " counter:" << counter << "\t col: " << col + 1 << "\t row: " << row + 1 00418 << "\t diff: " << val; 00419 std::cout << "\t map1: " << weight1.coeffRef( row, col ) << "\t map2: " << weight2.coeffRef( row, col ) 00420 << "\n"; // row index 00421 counter++; 00422 } 00423 } 00424 } 00425 00426 // compare frac_a between maps 00427 diff_vect( "frac_a", na1 ); 00428 diff_vect( "frac_b", nb1 ); 00429 diff_vect( "area_a", na1 ); 00430 diff_vect( "area_b", nb1 ); 00431 diff_vect( "yc_a", na1 ); 00432 diff_vect( "yc_b", nb1 ); 00433 diff_vect( "xc_a", na1 ); 00434 diff_vect( "xc_b", nb1 ); 00435 diff_2d_vect( "xv_a", na1 * nv_a ); 00436 diff_2d_vect( "yv_a", na1 * nv_a ); 00437 diff_2d_vect( "xv_b", nb1 * nv_b ); 00438 diff_2d_vect( "yv_b", nb1 * nv_b ); 00439 00440 return 0; 00441 }