diff --git a/grid_gen/mesh_conversion_tools/README b/grid_gen/mesh_conversion_tools/README index 6120688d7..85e4fcd09 100644 --- a/grid_gen/mesh_conversion_tools/README +++ b/grid_gen/mesh_conversion_tools/README @@ -21,7 +21,7 @@ Purpose: at: https://github.com/MPAS-Dev/geometric_features Masks have a value of 0 or 1, and are integers. - + Requirements: mpas_mesh_converter.cpp requires the c++ netcdf libraries to be able to read/write NetCDF files. It also requires the tr1 headers for c++, specifically unordered_set. @@ -34,9 +34,9 @@ Requirements: It has been tested using g++ version 4.8.1 Usage of mpas_mesh_converter.cpp: - ./MpasMeshConverter.x [input_name] [output_name] + ./MpasMeshConverter.x [-i input_name] [-o output_name] [-h] - input_name: + -i input_name: The input_name should be the name of a NetCDF file containing the following information. Dimensions: nCells - The number of cells described in the file. @@ -58,61 +58,88 @@ Usage of mpas_mesh_converter.cpp: history -- (Optional) Should be defined to a string describing how the input file was generated. mesh_id -- (Optional) Should be a 40 character string (Alpha-Numeric) that can be used to identify the mesh. If ommitted, a random string will be placed in the output file. - output_name: + -o output_name: The output_name should be the name of the NetCDF file that will be generated. It will be a valid MPAS mesh. No initial conditions are placed in this file. If input_name is specified, output_name defaults to mesh.nc. + -h: + This flag prints the program usage statement. + Usage of mpas_cell_culler.cpp: - ./MpasCellCuller.x [input_name] [output_name] [[-m/-i] mask_file] + ./MpasCellCuller.x [-i input_name] [-o output_name] [[-m/-v/-p] masks_name] [-n index_mapping_output_name] [-h] - input_name: + -i input_name: The input name should be the name of a NetCDF file that is a fully valid MPAS file. It is required to have all of the fields an output file from MpasMeshConverter.x contains. There is one additional field: cullCell -- (Optional) Should be dimensioned nCells. Should contain a 1 for all cells that should be removed and a 0 for all cells that should be kept. - output_name: + -o output_name: The output_name should be the name of the NetCDF file that will be generated. It will be the same as the input file, with cells, edges, and vertices removed where appropriate. Also, the cullCell field will be removed. If input_name is specified, outputname defaults to culled_mesh.nc. - - -m/-i: + + -m/-v/-p mask_name: These flags allow the addition of a masks file to be used to define cells that should be culled. If the -m flag is used, the masks file is used to cull the mesh. Meaning, where any mask in the masks file is 1, the mesh will be culled. - If the -i flag is used, the inverse of the masks file is used to cull + If the -v flag is used, the inverse of the masks file is used to cull the mesh. Meaning where all masks in the masks file are 0, the mesh will be culled. - - mask_file: - The mask_file argument should be the name of a NetCDF file containing + If the -p flag is used, any marked cells will not be culled. + + The mask_name argument should be the name of a NetCDF file containing the regionCellMasks field, which defines masks for culling cells. + -n index_mapping_output_name: + This flag allows the cellMap variable, which stores a mapping from the unculled to culled cell IDs, + to be written out to a text file called index_mapping_output_name. + + -h: + This flag prints the program usage statement. + Usage of mpas_mask_creator.cpp: - ./MpasMaskCreator.x [input_mesh] [output_masks] [feature_group1] [feature_group2] ... [feature_groupN] + ./MpasMaskCreator.x [-i input_mesh] [-o output_masks] [ [-f/-s] file.geojson ] [-p] [-h] - input_name: + -i input_name: The input name should be the path to a NetCDF file that is a fully valid MPAS file. - output_masks: + -o output_masks: The output masks should be the path to a NetCDF file that will be generated. It will contain all of the mask information after applying the region specifications to the input name mesh file. - - feature_groupN: - After the output masks argument, the mask creator can take an arbitrary - number of feature files. The mask creator assumes each file is a group - of features (regions, transects, point data, etc.). Each file must be - formatted as geojson, and the name of each group should be contained - within the file. - - The mask creator assumes the latitude and longitude contained within - each geojson file are given in degrees, and that the latitude ranges - from -90 to 90, while the longitude ranges from -180 to 180. + + -s file.geojson: + This argument pair defines a set of points (from the geojson point definition) + that will be used as seed points in a flood fill algorithim. + This is useful when trying to remove isolated cells from a mesh. + + -f file.geojson: + This argument pair defines a set of geojson features (regions, transects, or points) + that will be converted into masks / lists. + + -p: + This argument causes the longitude range to be 0-360 degrees with the prime meridian at 0 degrees. + If this flag is not set, the longitude range is -180-180 with 0 degrees being the prime meridian. + Whether this flag is passed in or not, any longitudes written are in the 0-360 range. + + -h: + This flag prints the program usage statement. + + The mask creator can take an arbitrary number of feature files with the + -f/-s option. The mask creator assumes each file is a group + of features (regions, transects, point data, etc.). Each file must be + formatted as geojson, and the name of each group should be contained + within the file. + + The mask creator assumes the latitude and longitude contained within + each geojson file are given in degrees, and that the latitude ranges + from -90 to 90, while the longitude ranges from -180 to 180. + Notes for mpas_mesh_converter.cpp: - The output mesh should have an attribute "mesh_spec" which defined which @@ -121,7 +148,7 @@ Notes for mpas_mesh_converter.cpp: given a negative area. - Negative area cells can be removed at a later state to remove non-complete cells. - + Notes for mpas_cell_culler.cpp: - Cells that contain negative area will be removed in addition to all cells that have diff --git a/grid_gen/mesh_conversion_tools/mpas_cell_culler.cpp b/grid_gen/mesh_conversion_tools/mpas_cell_culler.cpp index 291973ac6..16725e2fd 100644 --- a/grid_gen/mesh_conversion_tools/mpas_cell_culler.cpp +++ b/grid_gen/mesh_conversion_tools/mpas_cell_culler.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "netcdf_utils.h" @@ -55,25 +56,30 @@ int mapAndOutputGridCoordinates(const string inputFilename, const string outputF int mapAndOutputCellFields(const string inputFilename, const string outputFilename); int mapAndOutputEdgeFields(const string inputFilename, const string outputFilename); int mapAndOutputVertexFields(const string inputFilename, const string outputFilename); +int outputCellMap(const string mapFilename); /*}}}*/ void print_usage(){/*{{{*/ cout << endl << endl; cout << "Usage:" << endl; - cout << "\tMpasCellCuller.x [input_name] [output_name] [[-m/-i/-p] masks_name]" << endl; + cout << "\tMpasCellCuller.x [-i input_name] [-o output_name] [[-m/-v/-p] masks_name] [-n index_mapping_output_name] [-h]" << endl; cout << endl; - cout << "\t\tinput_name:" << endl; + cout << "\t\t-i input_name:" << endl; cout << "\t\t\tThis argument specifies the input MPAS mesh." << endl; - cout << "\t\toutput_name:" << endl; + cout << "\t\t\tIf not specified it defaults to grid.nc." << endl << endl; + cout << "\t\t-o output_name:" << endl; cout << "\t\t\tThis argument specifies the output culled MPAS mesh." << endl; - cout << "\t\t\tIf not specified, it defaults to culled_mesh.nc, but" << endl; - cout << "\t\t\tit is required if additional arguments are specified." << endl; - cout << "\t\t-m/-i:" << endl; - cout << "\t\t\tThis argument controls how a set of masks is used when culling a mesh." << endl; + cout << "\t\t\tIf not specified, it defaults to culled_mesh.nc." << endl << endl; + cout << "\t\t-m/-v/-p masks_name:" << endl; + cout << "\t\t\tThese arguments control how a set of masks is used when culling a mesh." << endl; cout << "\t\t\tThe -m argument applies a mask to cull based on (i.e. where the mask is 1, the mesh will be culled)." << endl; - cout << "\t\t\tThe -i argument applies the inverse mask to cull based on (i.e. where the mask is 0, the mesh will be culled)." << endl; + cout << "\t\t\tThe -v argument applies the inverse mask to cull based on (i.e. where the mask is 0, the mesh will be culled)." << endl; cout << "\t\t\tThe -p argument forces any marked cells to not be culled." << endl; - cout << "\t\t\tIf this argument is specified, the masks_name argument is required" << endl; + cout << "\t\t\tIf any of these arguments are specified, the masks_name argument is required" << endl << endl; + cout << "\t\t-n index_mapping_output_name:" << endl; + cout << "\t\t\tOutput the cellMap variable to a text file called index_mapping_output_name." << endl << endl; + cout << "\t\t-h:" << endl; + cout << "\t\t\tOutput this usage description and exit." << endl << endl; }/*}}}*/ string gen_random(const int len); @@ -81,9 +87,11 @@ string gen_random(const int len); int main ( int argc, char *argv[] ) { int error; string out_name = "culled_mesh.nc"; - string in_name = "mesh.nc"; + string in_name = "grid.nc"; vector mask_names; vector mask_ops; + string map_name = ""; + int c; cout << endl << endl; cout << "************************************************************" << endl; @@ -97,63 +105,50 @@ int main ( int argc, char *argv[] ) { // // If the input file was not specified, get it now. // - if ( argc <= 1 ) - { - cout << "\n"; - cout << "MPAS_CELL_CULLER:\n"; - cout << " Please enter the NetCDF input filename.\n"; - - cin >> in_name; - - cout << "\n"; - cout << "MPAS_CELL_CULLER:\n"; - cout << " Please enter the output NetCDF MPAS Mesh filename.\n"; - - cin >> out_name; - } - else if (argc == 2) - { - in_name = argv[1]; - - cout << "\n"; - cout << "MPAS_CELL_CULLER:\n"; - cout << " Output name not specified. Using default of culled_mesh.nc\n"; - } - else if (argc == 3) - { - in_name = argv[1]; - out_name = argv[2]; - } - else if ( argc >= 4 && argc % 2 == 0 ) - { - cout << "\n"; - cout << " ERROR: Incorrect number of arguments specified. See usage statement" << endl; - print_usage(); - exit(1); - } - else - { - cullMasks = true; - in_name = argv[1]; - out_name = argv[2]; - - for ( int i = 3; i < argc; i+=2 ) { - if (strcmp(argv[i], "-m") == 0 ) { - mask_ops.push_back(merge); - } else if ( strcmp(argv[i], "-i") == 0 ){ - mask_ops.push_back(invert); - } else if ( strcmp(argv[i], "-p") == 0 ){ - mask_ops.push_back(preserve); - } else { - cout << " ERROR: Invalid option passed on the command line " << argv[i] << ". Exiting..." << endl; - exit(1); - } - mask_names.push_back( argv[i+1] ); + while ( (c = getopt(argc, argv, "i:o:m:v:p:n:h")) != -1) { + switch (c) { + case 'i': + // input grid filename + in_name = optarg; + break; + case 'o': + // output grid filename + out_name = optarg; + break; + case 'm': + // merge mask + cullMasks = true; + mask_ops.push_back(merge); + mask_names.push_back(optarg); + break; + case 'v': + // invert mask + cullMasks = true; + mask_ops.push_back(invert); + mask_names.push_back(optarg); + break; + case 'p': + // marked cells not culled + cullMasks = true; + mask_ops.push_back(preserve); + mask_names.push_back(optarg); + break; + case 'n': + // index mapping output text filename + map_name = optarg; + break; + case 'h': + // print the usage statement + print_usage(); + exit(1); + default: + printf ("ERROR: Invalid option passed on the command line 0%o. Exiting...\n", c); + print_usage(); + exit(1); } } - if(out_name == in_name){ cout << " ERROR: Input and Output names are the same." << endl; return 1; @@ -221,6 +216,15 @@ int main ( int argc, char *argv[] ) { exit(error); } + if (map_name != "") + { + cout << "Output cellMap" << endl; + if(error = outputCellMap(map_name)){ + cout << "Error - " << error << endl; + exit(error); + } + } + return 0; } @@ -533,21 +537,21 @@ int outputGridDimensions( const string outputFilename ){/*{{{*/ int nCellsNew, nEdgesNew, nVerticesNew; // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Replace, NULL, 0, NcFile::Offset64Bits); /* for(vec_int_itr = edgesOnCell.begin(); vec_int_itr != edgesOnCell.end(); ++vec_int_itr){ - maxEdges = std::max(maxEdges, (int)(*vec_int_itr).size()); + maxEdges = std::max(maxEdges, (int)(*vec_int_itr).size()); }*/ - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // define dimensions NcDim *nCellsDim; NcDim *nEdgesDim; @@ -571,7 +575,7 @@ int outputGridDimensions( const string outputFilename ){/*{{{*/ for(int iEdge = 0; iEdge < nEdges; iEdge++){ nEdgesNew += (edgeMap.at(iEdge) != -1); } - + // write dimensions if (!(nCellsDim = grid.add_dim( "nCells", nCellsNew) )) return NC_ERR; if (!(nEdgesDim = grid.add_dim( "nEdges", nEdgesNew) )) return NC_ERR; @@ -581,7 +585,7 @@ int outputGridDimensions( const string outputFilename ){/*{{{*/ if (!(timeDim = grid.add_dim( "Time") )) return NC_ERR; grid.close(); - + // file closed when file obj goes out of scope return 0; }/*}}}*/ @@ -594,10 +598,10 @@ int outputGridAttributes( const string inputFilename, const string outputFilenam * **********************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); @@ -608,7 +612,7 @@ int outputGridAttributes( const string inputFilename, const string outputFilenam string history_str = ""; string id_str = ""; string parent_str = ""; - + // write attributes if(!spherical){ if (!(sphereAtt = grid.add_att( "on_a_sphere", "NO\0"))) return NC_ERR; @@ -653,7 +657,7 @@ int outputGridAttributes( const string inputFilename, const string outputFilenam if (!(id = grid.add_att( "file_id", id_str.c_str() ))) return NC_ERR; grid.close(); - + // file closed when file obj goes out of scope return 0; }/*}}}*/ @@ -668,16 +672,16 @@ int mapAndOutputGridCoordinates( const string inputFilename, const string output * **********************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nCellsDim = grid.get_dim( "nCells" ); NcDim *nEdgesDim = grid.get_dim( "nEdges" ); @@ -693,7 +697,7 @@ int mapAndOutputGridCoordinates( const string inputFilename, const string output NcVar *idx2cellVar, *idx2edgeVar, *idx2vertexVar; int i, idx_map; - + double *xOld, *yOld, *zOld, *latOld, *lonOld; double *xNew, *yNew, *zNew, *latNew, *lonNew; int *idxToNew; @@ -752,7 +756,7 @@ int mapAndOutputGridCoordinates( const string inputFilename, const string output delete[] latNew; delete[] lonNew; delete[] idxToNew; - + //Build and write edge coordinate arrays xOld = new double[nEdges]; yOld = new double[nEdges]; @@ -883,16 +887,16 @@ int mapAndOutputCellFields( const string inputFilename, const string outputFilen * ***************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nCellsDim = grid.get_dim( "nCells" ); NcDim *nEdgesDim = grid.get_dim( "nEdges" ); @@ -912,7 +916,7 @@ int mapAndOutputCellFields( const string inputFilename, const string outputFilen double *areaCellNew; int *tmp_arr_old, *nEdgesOnCellOld, *nEdgesOnCellNew; int *tmp_arr_new; - + tmp_arr_old = new int[nCells*maxEdges]; nEdgesOnCellOld = new int[nCells]; nEdgesOnCellNew = new int[nCellsNew]; @@ -1025,7 +1029,7 @@ int mapAndOutputCellFields( const string inputFilename, const string outputFilen delete[] tmp_arr_new; // Map areaCell - areaCellNew = new double[nCellsNew]; + areaCellNew = new double[nCellsNew]; for(int iCell = 0; iCell < nCells; iCell++){ if(cellMap.at(iCell) != -1){ @@ -1073,16 +1077,16 @@ int mapAndOutputEdgeFields( const string inputFilename, const string outputFilen * ***************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nEdgesDim = grid.get_dim( "nEdges" ); NcDim *maxEdges2Dim = grid.get_dim( "maxEdges2" ); @@ -1184,7 +1188,7 @@ int mapAndOutputEdgeFields( const string inputFilename, const string outputFilen #endif } } - + if (!(voeVar = grid.add_var("verticesOnEdge", ncInt, nEdgesDim, twoDim))) return NC_ERR; if (!voeVar->put(verticesOnEdgeNew,nEdgesNew,2)) return NC_ERR; if (!(coeVar = grid.add_var("cellsOnEdge", ncInt, nEdgesDim, twoDim))) return NC_ERR; @@ -1313,16 +1317,16 @@ int mapAndOutputVertexFields( const string inputFilename, const string outputFil * ***************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nVerticesDim = grid.get_dim( "nVertices" ); NcDim *vertexDegreeDim = grid.get_dim( "vertexDegree" ); @@ -1417,7 +1421,25 @@ int mapAndOutputVertexFields( const string inputFilename, const string outputFil return 0; }/*}}}*/ /*}}}*/ +int outputCellMap(const string mapFilename){/*{{{*/ + /***************************************************************** + * + * This function outputs the cellMap variable used in the culling + * to a text file named mapFilename. + * + * ***************************************************************/ + ofstream outputfile; + outputfile.open(mapFilename); + + for (int iCell=0 ; iCell < nCells ; iCell++) { + outputfile << cellMap.at(iCell) << endl; + } + + outputfile.close(); + + return 0; +}/*}}}*/ string gen_random(const int len) {/*{{{*/ static const char alphanum[] = "0123456789" @@ -1432,4 +1454,3 @@ string gen_random(const int len) {/*{{{*/ return rand_str; }/*}}}*/ - diff --git a/grid_gen/mesh_conversion_tools/mpas_mask_creator.cpp b/grid_gen/mesh_conversion_tools/mpas_mask_creator.cpp index 288416752..533448b60 100644 --- a/grid_gen/mesh_conversion_tools/mpas_mask_creator.cpp +++ b/grid_gen/mesh_conversion_tools/mpas_mask_creator.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "netcdf_utils.h" #include "pnt.h" @@ -140,16 +141,26 @@ int outputMaskFields( const string outputFilename); void print_usage() {/*{{{*/ cout << endl << endl; cout << " USAGE:" << endl; - cout << "\tMpasMaskCreator.x in_file out_file [ [-f/-s] file.geojson ] [--positive_lon]" << endl; - cout << "\t\tin_file: This argument defines the input file that masks will be created for." << endl; - cout << "\t\tout_file: This argument defines the file that masks will be written to." << endl; - cout << "\t\t-s file.geojson: This argument pair defines a set of points (from the geojson point definition)" << endl; - cout << "\t\t\tthat will be used as seed points in a flood fill algorithim. This is useful when trying to remove isolated cells from a mesh." << endl; - cout << "\t\t-f file.geojson: This argument pair defines a set of geojson features (regions, transects, or points)" << endl; - cout << "\t\t\tthat will be converted into masks / lists." << endl; - cout << "\t\t--positive_lon: This argument causes the logitude range to be 0-360 degrees with the prime meridian at 0 degrees." << endl; - cout << "\t\t\tIf this flag is not set, the logitude range is -180-180 with 0 degrees being the prime meridian." << endl; - cout << "\t\t\tWhether this flag is passed in or not, any longitudes written are in the 0-360 range." << endl; + cout << "\tMpasMaskCreator.x [-i in_file] [-o out_file] [ [-f/-s] file.geojson ] [-p] [-h]" << endl << endl; + cout << "\t\t-i in_file:" << endl; + cout << "\t\t\tThis argument defines the input file that masks will be created for." << endl; + cout << "\t\t\tIf not specified it defaults to masks.nc." << endl << endl; + cout << "\t\t-o out_file:" << endl; + cout << "\t\t\tThis argument defines the file that masks will be written to." << endl; + cout << "\t\t\tIf not specified it defaults to grid.nc." << endl << endl; + cout << "\t\t-s file.geojson:" << endl; + cout << "\t\t\tThis argument pair defines a set of points (from the geojson point definition)" << endl; + cout << "\t\t\tthat will be used as seed points in a flood fill algorithim." << endl; + cout << "\t\t\tThis is useful when trying to remove isolated cells from a mesh." << endl << endl; + cout << "\t\t-f file.geojson:" << endl; + cout << "\t\t\tThis argument pair defines a set of geojson features (regions, transects, or points)" << endl; + cout << "\t\t\tthat will be converted into masks / lists." << endl << endl; + cout << "\t\t-p:" << endl; + cout << "\t\t\tThis argument causes the longitude range to be 0-360 degrees with the prime meridian at 0 degrees." << endl; + cout << "\t\t\tIf this flag is not set, the longitude range is -180-180 with 0 degrees being the prime meridian." << endl; + cout << "\t\t\tWhether this flag is passed in or not, any longitudes written are in the 0-360 range." << endl << endl; + cout << "\t\t-h:" << endl; + cout << "\t\t\tOutput this usage description and exit." << endl << endl; }/*}}}*/ string gen_random(const int len); @@ -160,6 +171,7 @@ int main ( int argc, char *argv[] ) { vector seed_files; string out_name = "masks.nc"; string in_name = "grid.nc"; + int c; cout << endl << endl; cout << "************************************************************" << endl; @@ -171,36 +183,32 @@ int main ( int argc, char *argv[] ) { cout << "************************************************************" << endl; cout << endl << endl; - if ( argc < 5 ) { - cout << " ERROR: Incorrect usage. See usage statement." << endl; - print_usage(); - exit(1); - } else { - string str_flag; - string str_file; - in_name = argv[1]; - out_name = argv[2]; - - int i = 3; - while ( i < argc ) { - str_flag = argv[i]; - - if ( str_flag == "-s" ) { - str_file = argv[i+1]; - seed_files.push_back(str_file); - i += 2; - } else if ( str_flag == "-f" ) { - str_file = argv[i+1]; - mask_files.push_back(str_file); - i += 2; - } else if ( str_flag == "--positive_lon" ) { - lonRangePositive = true; - i++; - } else { - cout << " ERROR: Invalid flag " << str_flag << " passed in. See usage statement." << endl; - print_usage(); - exit(1); - } + while ( (c = getopt(argc, argv, "i:o:f:s:ph")) != -1) { + switch (c) { + case 'i': + // input grid filename + in_name = optarg; + break; + case 'o': + // output grid filename + out_name = optarg; + break; + case 'f': + mask_files.push_back(optarg); + break; + case 's': + seed_files.push_back(optarg); + break; + case 'p': + lonRangePositive = true; + case 'h': + // print the usage statement + print_usage(); + exit(1); + default: + printf ("ERROR: Invalid option passed on the command line 0%o. Exiting...\n", c); + print_usage(); + exit(1); } } diff --git a/grid_gen/mesh_conversion_tools/mpas_mesh_converter.cpp b/grid_gen/mesh_conversion_tools/mpas_mesh_converter.cpp index fbcc2e34f..6fbd40879 100644 --- a/grid_gen/mesh_conversion_tools/mpas_mesh_converter.cpp +++ b/grid_gen/mesh_conversion_tools/mpas_mesh_converter.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "netcdf_utils.h" #include "pnt.h" @@ -115,10 +116,26 @@ int writeGraphFile(const string outputFilename); string gen_random(const int len); +void print_usage(){/*{{{*/ + cout << endl << endl; + cout << "Usage:" << endl; + cout << "\tMpasMeshConverter.x [-i input_name] [-o output_name] [-h]" << endl; + cout << endl; + cout << "\t\t-i input_name:" << endl; + cout << "\t\t\tThis argument specifies the input Netcdf file to be converted to an MPAS mesh." << endl; + cout << "\t\t\tIf not specified it defaults to mesh.nc." << endl << endl; + cout << "\t\t-o output_name:" << endl; + cout << "\t\t\tThis argument specifies the output MPAS mesh to be generated." << endl; + cout << "\t\t\tIf not specified, it defaults to grid.nc." << endl << endl; + cout << "\t\t-h:" << endl; + cout << "\t\t\tOutput this usage description and exit." << endl << endl; +}/*}}}*/ + int main ( int argc, char *argv[] ) { int error; string out_name = "mesh.nc"; string in_name = "grid.nc"; + int c; cout << endl << endl; cout << "************************************************************" << endl; @@ -133,32 +150,26 @@ int main ( int argc, char *argv[] ) { // // If the input file was not specified, get it now. // - if ( argc <= 1 ) - { - cout << "\n"; - cout << "MPAS_MESH_CONVERTER:\n"; - cout << " Please enter the NetCDF input filename.\n"; - - cin >> in_name; - - cout << "\n"; - cout << "MPAS_MESH_CONVERTER:\n"; - cout << " Please enter the output NetCDF MPAS Mesh filename.\n"; - cin >> out_name; - } - else if (argc == 2) - { - in_name = argv[1]; - - cout << "\n"; - cout << "MPAS_MESH_CONVERTER:\n"; - cout << " Output name not specified. Using default of mesh.nc\n"; - } - else if (argc == 3) - { - in_name = argv[1]; - out_name = argv[2]; + while ( (c = getopt(argc, argv, "i:o:h")) != -1) { + switch (c) { + case 'i': + // input grid filename + in_name = optarg; + break; + case 'o': + // output grid filename + out_name = optarg; + break; + case 'h': + // print the usage statement + print_usage(); + exit(1); + default: + printf ("ERROR: Invalid option passed on the command line 0%o. Exiting...\n", c); + print_usage(); + exit(1); + } } if(in_name == out_name){ @@ -264,7 +275,7 @@ int main ( int argc, char *argv[] ) { cout << "Error - " << error << endl; exit(error); } - + cout << "Reading and writing meshDensity" << endl; if(error = outputMeshDensity(out_name)){ cout << "Error - " << error << endl; @@ -506,14 +517,14 @@ int buildUnorderedCellConnectivity(){/*{{{*/ // It should compute the inverse of cellsOnVertex (verticesOnCell) unordered. // It will also compute an unordered cellsOnCell that can be considered invalid for actual use (e.g. quad grids). // This ordering should happen regardless of it the mesh is planar or spherical. - + int iVertex, iCell, newCell, j, k, l, m, matches; bool add; #ifdef _DEBUG cout << endl << endl << "Begin function: buildUnorderedCellConnectivity" << endl << endl; #endif - + verticesOnCell.clear(); verticesOnCell.resize(cells.size()); @@ -732,7 +743,7 @@ int firstOrderingVerticesOnCell(){/*{{{*/ }/*}}}*/ int buildCompleteCellMask(){/*{{{*/ /* - * The buildCompleteCellMask function parses an ordered + * The buildCompleteCellMask function parses an ordered * verticesOnCell field to determine if a cell is complete. It takes each * vertex-vertex pair (from verticesOnCell) and determines the angle * between them. If only one vertex is shared, the "edge" is skipped. @@ -939,8 +950,8 @@ int buildEdges(){/*{{{*/ if(completeCellMask.at(iCell) == 1) { // Build edges from every vertex/vertex pair around a cell if the cell is complete for(l = 0; l < verticesOnCell.at(iCell).size()-1; l++){ - vertex1 = verticesOnCell.at(iCell).at(l); - vertex2 = verticesOnCell.at(iCell).at(l+1); + vertex1 = verticesOnCell.at(iCell).at(l); + vertex2 = verticesOnCell.at(iCell).at(l+1); // Find cell shaerd by vertices, that's not iCell cell1 = iCell; @@ -1073,7 +1084,7 @@ int buildEdges(){/*{{{*/ for(k = 0; k < verticesOnCell.at(cell2).size(); k++){ if(verticesOnCell.at(cell1).at(j) == verticesOnCell.at(cell2).at(k)) { if(vertex1 == -1){ - vertex1 = verticesOnCell.at(cell1).at(j); + vertex1 = verticesOnCell.at(cell1).at(j); } else if(vertex2 == -1) { vertex2 = verticesOnCell.at(cell1).at(j); } else { @@ -1254,7 +1265,7 @@ int buildEdges(){/*{{{*/ #ifdef _DEBUG cout << "New Edge At: " << edge_loc << endl; cout << " c1: " << cells.at(cell1) << endl; - if(cell2 > -1) { + if(cell2 > -1) { cout << " c2: " << cells.at(cell2) << endl; cout << " mod? c2: " << cell_loc2 << endl; } else { @@ -1344,7 +1355,7 @@ int orderVertexArrays(){/*{{{*/ if(vertex1 != -1) { edgesOnVertex.at(vertex1).push_back(iEdge); - } + } if(vertex2 != -1){ edgesOnVertex.at(vertex2).push_back(iEdge); @@ -1457,7 +1468,7 @@ int orderCellArrays(){/*{{{*/ * orderCellArrays assumes verticesOnCell are ordered CCW already. * */ - int iCell, iVertex, iEdge, iEdge2, add_cell; + int iCell, iVertex, iEdge, iEdge2, add_cell; int cell1, cell2, vertex1, vertex2, prev_vertex; int edge_idx, loc_edge_idx; int i, j, k, swp_idx; @@ -1490,8 +1501,8 @@ int orderCellArrays(){/*{{{*/ // First, build full list of edges on cell. for(iEdge = 0; iEdge < edges.size(); iEdge++){ - cell1 = cellsOnEdge.at(iEdge).at(0); - cell2 = cellsOnEdge.at(iEdge).at(1); + cell1 = cellsOnEdge.at(iEdge).at(0); + cell2 = cellsOnEdge.at(iEdge).at(1); edgesOnCell.at(cell1).push_back(iEdge); if(cell2 != -1){ @@ -1521,7 +1532,7 @@ int orderCellArrays(){/*{{{*/ #endif // /* - // Determine starting edge. It should either be the first edge in the set, + // Determine starting edge. It should either be the first edge in the set, // or the only edge such that all other edges are CCW from it. edge_idx = edgesOnCell.at(iCell).at(0); loc_edge_idx = 0; @@ -1736,7 +1747,7 @@ int buildAreas(){/*{{{*/ for(iCell = 0; iCell < cells.size(); iCell++){ areaCell.at(iCell) = 0.0; - + if(completeCellMask.at(iCell) == 1){ for(j = 0; j < edgesOnCell.at(iCell).size(); j++){ iEdge = edgesOnCell.at(iCell).at(j); @@ -2108,7 +2119,7 @@ int buildAngleEdge(){/*{{{*/ * or * 2. The angles the positive normal direction (u) * makes with the local eastward direction. - * + * * In a plane, local eastward is defined as the x axis, and * nortward is defined as the y axis. */ @@ -2155,7 +2166,7 @@ int buildAngleEdge(){/*{{{*/ } if(!spherical){ - cell_loc2.fixPeriodicity(cell_loc1, xPeriodicFix, yPeriodicFix); + cell_loc2.fixPeriodicity(cell_loc1, xPeriodicFix, yPeriodicFix); normal = cell_loc2 - cell_loc1; angleEdge.at(iEdge) = acos( x_axis.dot(normal) / (x_axis.magnitude() * normal.magnitude())); @@ -2254,7 +2265,7 @@ int buildMeshQualities(){/*{{{*/ } else { cellQuality.at(iCell) = 0.0; } - gridSpacing.at(iCell) = spacing / edgesOnCell.at(iCell).size(); + gridSpacing.at(iCell) = spacing / edgesOnCell.at(iCell).size(); } #ifdef _DEBUG @@ -2344,10 +2355,10 @@ int outputGridDimensions( const string outputFilename ){/*{{{*/ * **********************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Replace, NULL, 0, NcFile::Offset64Bits); @@ -2357,12 +2368,12 @@ int outputGridDimensions( const string outputFilename ){/*{{{*/ /* for(vec_int_itr = edgesOnCell.begin(); vec_int_itr != edgesOnCell.end(); ++vec_int_itr){ - maxEdges = std::max(maxEdges, (int)(*vec_int_itr).size()); + maxEdges = std::max(maxEdges, (int)(*vec_int_itr).size()); }*/ - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // define dimensions NcDim *nCellsDim; NcDim *nEdgesDim; @@ -2373,7 +2384,7 @@ int outputGridDimensions( const string outputFilename ){/*{{{*/ NcDim *THREEDim; NcDim *vertexDegreeDim; NcDim *timeDim; - + // write dimensions if (!(nCellsDim = grid.add_dim( "nCells", cells.size()) )) return NC_ERR; if (!(nEdgesDim = grid.add_dim( "nEdges", edges.size()) )) return NC_ERR; @@ -2385,7 +2396,7 @@ int outputGridDimensions( const string outputFilename ){/*{{{*/ if (!(timeDim = grid.add_dim( "Time") )) return NC_ERR; grid.close(); - + // file closed when file obj goes out of scope return 0; }/*}}}*/ @@ -2399,10 +2410,10 @@ int outputGridAttributes( const string outputFilename, const string inputFilenam // Return this code to the OS in case of failure. static const int NC_ERR = 2; char mesh_spec_str[1024]; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); @@ -2413,7 +2424,7 @@ int outputGridAttributes( const string outputFilename, const string inputFilenam string history_str = ""; string id_str = ""; string parent_str =""; - + // write attributes if(!spherical){ if (!(sphereAtt = grid.add_att( "on_a_sphere", "NO\0"))) return NC_ERR; @@ -2459,7 +2470,7 @@ int outputGridAttributes( const string outputFilename, const string inputFilenam if (!(id = grid.add_att( "file_id", id_str.c_str() ))) return NC_ERR; grid.close(); - + // file closed when file obj goes out of scope return 0; }/*}}}*/ @@ -2474,16 +2485,16 @@ int outputGridCoordinates( const string outputFilename) {/*{{{*/ * **********************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nCellsDim = grid.get_dim( "nCells" ); NcDim *nEdgesDim = grid.get_dim( "nEdges" ); @@ -2499,7 +2510,7 @@ int outputGridCoordinates( const string outputFilename) {/*{{{*/ NcVar *idx2cellVar, *idx2edgeVar, *idx2vertexVar; int i; - + double *x, *y, *z, *lat, *lon; int *idxTo; @@ -2547,7 +2558,7 @@ int outputGridCoordinates( const string outputFilename) {/*{{{*/ delete[] lat; delete[] lon; delete[] idxTo; - + //Build and write edge coordinate arrays x = new double[nEdges]; y = new double[nEdges]; @@ -2656,16 +2667,16 @@ int outputCellConnectivity( const string outputFilename) {/*{{{*/ * ***************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nCellsDim = grid.get_dim( "nCells" ); NcDim *maxEdgesDim = grid.get_dim( "maxEdges" ); @@ -2678,7 +2689,7 @@ int outputCellConnectivity( const string outputFilename) {/*{{{*/ NcVar *cocVar, *nEocVar, *eocVar, *vocVar; int *tmp_arr; - + // Build and write COC array tmp_arr = new int[nCells*maxEdges]; @@ -2711,7 +2722,7 @@ int outputCellConnectivity( const string outputFilename) {/*{{{*/ for(vec_int_itr = edgesOnCell.begin(); vec_int_itr != edgesOnCell.end(); ++vec_int_itr){ j = 0; for(int_itr = (*vec_int_itr).begin(); int_itr != (*vec_int_itr).end(); ++int_itr){ - tmp_arr[i*maxEdges + j] = (*int_itr) + 1; + tmp_arr[i*maxEdges + j] = (*int_itr) + 1; j++; } @@ -2721,7 +2732,7 @@ int outputCellConnectivity( const string outputFilename) {/*{{{*/ if (!(eocVar = grid.add_var("edgesOnCell", ncInt, nCellsDim, maxEdgesDim))) return NC_ERR; if (!eocVar->put(tmp_arr,nCells,maxEdges)) return NC_ERR; - // Build and write VOC array + // Build and write VOC array for(i = 0; i < nCells; i++){ for(j = 0; j < maxEdges; j++){ tmp_arr[i*maxEdges + j] = 0; @@ -2732,7 +2743,7 @@ int outputCellConnectivity( const string outputFilename) {/*{{{*/ for(vec_int_itr = verticesOnCell.begin(); vec_int_itr != verticesOnCell.end(); ++vec_int_itr){ j = 0; for(int_itr = (*vec_int_itr).begin(); int_itr != (*vec_int_itr).end(); ++int_itr){ - tmp_arr[i*maxEdges + j] = (*int_itr) + 1; + tmp_arr[i*maxEdges + j] = (*int_itr) + 1; j++; } i++; @@ -2772,16 +2783,16 @@ int outputEdgeConnectivity( const string outputFilename) {/*{{{*/ * ***************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nEdgesDim = grid.get_dim( "nEdges" ); NcDim *maxEdges2Dim = grid.get_dim( "maxEdges2" ); @@ -2812,7 +2823,7 @@ int outputEdgeConnectivity( const string outputFilename) {/*{{{*/ for(vec_int_itr = edgesOnEdge.begin(); vec_int_itr != edgesOnEdge.end(); ++vec_int_itr){ j = 0; for(int_itr = (*vec_int_itr).begin(); int_itr != (*vec_int_itr).end(); ++int_itr){ - tmp_arr[i*maxEdges2 + j] = (*int_itr) + 1; + tmp_arr[i*maxEdges2 + j] = (*int_itr) + 1; j++; } @@ -2834,7 +2845,7 @@ int outputEdgeConnectivity( const string outputFilename) {/*{{{*/ for(vec_int_itr = cellsOnEdge.begin(); vec_int_itr != cellsOnEdge.end(); ++vec_int_itr){ j = 0; for(int_itr = (*vec_int_itr).begin(); int_itr != (*vec_int_itr).end(); ++int_itr){ - tmp_arr[i*two + j] = (*int_itr) + 1; + tmp_arr[i*two + j] = (*int_itr) + 1; j++; } @@ -2849,7 +2860,7 @@ int outputEdgeConnectivity( const string outputFilename) {/*{{{*/ for(vec_int_itr = verticesOnEdge.begin(); vec_int_itr != verticesOnEdge.end(); ++vec_int_itr){ j = 0; for(int_itr = (*vec_int_itr).begin(); int_itr != (*vec_int_itr).end(); ++int_itr){ - tmp_arr[i*two + j] = (*int_itr) + 1; + tmp_arr[i*two + j] = (*int_itr) + 1; j++; } @@ -2876,7 +2887,7 @@ int outputEdgeConnectivity( const string outputFilename) {/*{{{*/ cellsOnEdge.clear(); // verticesOnEdge.clear(); // Needed for Initial conditions. edgesOnEdge.clear(); - + return 0; }/*}}}*/ int outputVertexConnectivity( const string outputFilename) {/*{{{*/ @@ -2889,16 +2900,16 @@ int outputVertexConnectivity( const string outputFilename) {/*{{{*/ * ***************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nVerticesDim = grid.get_dim( "nVertices" ); NcDim *vertexDegreeDim = grid.get_dim( "vertexDegree" ); @@ -2914,7 +2925,7 @@ int outputVertexConnectivity( const string outputFilename) {/*{{{*/ // Build and write COV array tmp_arr = new int[nVertices*vertexDegree]; - + for(i = 0; i < nVertices; i++){ for(j = 0; j < vertexDegree; j++){ tmp_arr[i*vertexDegree + j] = 0; @@ -2925,7 +2936,7 @@ int outputVertexConnectivity( const string outputFilename) {/*{{{*/ for(vec_int_itr = cellsOnVertex.begin(); vec_int_itr != cellsOnVertex.end(); ++vec_int_itr){ j = 0; for(int_itr = (*vec_int_itr).begin(); int_itr != (*vec_int_itr).end(); ++int_itr){ - tmp_arr[i*vertexDegree + j] = (*int_itr) + 1; + tmp_arr[i*vertexDegree + j] = (*int_itr) + 1; j++; } i++; @@ -2944,7 +2955,7 @@ int outputVertexConnectivity( const string outputFilename) {/*{{{*/ for(vec_int_itr = edgesOnVertex.begin(); vec_int_itr != edgesOnVertex.end(); ++vec_int_itr){ j = 0; for(int_itr = (*vec_int_itr).begin(); int_itr != (*vec_int_itr).end(); ++int_itr){ - tmp_arr[i*vertexDegree + j] = (*int_itr) + 1; + tmp_arr[i*vertexDegree + j] = (*int_itr) + 1; j++; } @@ -2956,7 +2967,7 @@ int outputVertexConnectivity( const string outputFilename) {/*{{{*/ // Build and write bdryVert array tmp_arr = new int[nVertices]; - + i = 0; for(vec_int_itr = cellsOnVertex.begin(); vec_int_itr != cellsOnVertex.end(); ++vec_int_itr){ if((*vec_int_itr).size() == vertexDegree){ @@ -2986,16 +2997,16 @@ int outputCellParameters( const string outputFilename) {/*{{{*/ * *******************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nCellsDim = grid.get_dim( "nCells" ); @@ -3028,16 +3039,16 @@ int outputVertexParameters( const string outputFilename) {/*{{{*/ * *******************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nVerticesDim = grid.get_dim( "nVertices" ); NcDim *vertexDegreeDim = grid.get_dim( "vertexDegree" ); @@ -3103,16 +3114,16 @@ int outputEdgeParameters( const string outputFilename) {/*{{{*/ * *******************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; - + // fetch dimensions NcDim *nEdgesDim = grid.get_dim( "nEdges" ); NcDim *maxEdges2Dim = grid.get_dim( "maxEdges2" ); @@ -3184,13 +3195,13 @@ int outputMeshDensity( const string outputFilename) {/*{{{*/ * *************************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; @@ -3225,13 +3236,13 @@ int outputMeshQualities( const string outputFilename) {/*{{{*/ * *************************************************************************/ // Return this code to the OS in case of failure. static const int NC_ERR = 2; - + // set error behaviour (matches fortran behaviour) NcError err(NcError::verbose_nonfatal); - + // open the scvtmesh file NcFile grid(outputFilename.c_str(), NcFile::Write); - + // check to see if the file was opened if(!grid.is_valid()) return NC_ERR; @@ -3321,4 +3332,3 @@ string gen_random(const int len) {/*{{{*/ return rand_str; }/*}}}*/ -