MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 #include "ReadNC.hpp" 00002 #include "NCHelper.hpp" 00003 00004 #include "moab/ReadUtilIface.hpp" 00005 #include "MBTagConventions.hpp" 00006 #include "moab/FileOptions.hpp" 00007 00008 namespace moab 00009 { 00010 00011 ReaderIface* ReadNC::factory( Interface* iface ) 00012 { 00013 return new ReadNC( iface ); 00014 } 00015 00016 ReadNC::ReadNC( Interface* impl ) 00017 : mbImpl( impl ), fileId( -1 ), mGlobalIdTag( 0 ), mpFileIdTag( NULL ), dbgOut( stderr ), isParallel( false ), 00018 partMethod( ScdParData::ALLJORKORI ), scdi( NULL ), 00019 #ifdef MOAB_HAVE_MPI 00020 myPcomm( NULL ), 00021 #endif 00022 noMesh( false ), noVars( false ), spectralMesh( false ), noMixedElements( false ), noEdges( false ), 00023 gatherSetRank( -1 ), tStepBase( -1 ), trivialPartitionShift( 0 ), myHelper( NULL ) 00024 { 00025 assert( impl != NULL ); 00026 impl->query_interface( readMeshIface ); 00027 } 00028 00029 ReadNC::~ReadNC() 00030 { 00031 mbImpl->release_interface( readMeshIface ); 00032 if( myHelper != NULL ) delete myHelper; 00033 } 00034 00035 ErrorCode ReadNC::load_file( const char* file_name, 00036 const EntityHandle* file_set, 00037 const FileOptions& opts, 00038 const ReaderIface::SubsetList* /*subset_list*/, 00039 const Tag* file_id_tag ) 00040 { 00041 // See if opts has variable(s) specified 00042 std::vector< std::string > var_names; 00043 std::vector< int > tstep_nums; 00044 std::vector< double > tstep_vals; 00045 00046 // Get and cache predefined tag handles 00047 mGlobalIdTag = mbImpl->globalId_tag(); 00048 // Store the pointer to the tag; if not null, set when global id tag 00049 // is set too, with the same data, duplicated 00050 mpFileIdTag = file_id_tag; 00051 00052 ErrorCode rval = parse_options( opts, var_names, tstep_nums, tstep_vals );MB_CHK_SET_ERR( rval, "Trouble parsing option string" ); 00053 00054 // Open the file 00055 dbgOut.tprintf( 1, "Opening file %s\n", file_name ); 00056 fileName = std::string( file_name ); 00057 int success; 00058 00059 #ifdef MOAB_HAVE_PNETCDF 00060 if( isParallel ) 00061 success = NCFUNC( open )( myPcomm->proc_config().proc_comm(), file_name, 0, MPI_INFO_NULL, &fileId ); 00062 else 00063 success = NCFUNC( open )( MPI_COMM_SELF, file_name, 0, MPI_INFO_NULL, &fileId ); 00064 #else 00065 success = NCFUNC( open )( file_name, 0, &fileId ); 00066 #endif 00067 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble opening file " << file_name ); 00068 00069 // Read the header (num dimensions, dimensions, num variables, global attribs) 00070 rval = read_header();MB_CHK_SET_ERR( rval, "Trouble reading file header" ); 00071 00072 // Make sure there's a file set to put things in 00073 EntityHandle tmp_set; 00074 if( noMesh && !file_set ) 00075 { 00076 MB_SET_ERR( MB_FAILURE, "NOMESH option requires non-NULL file set on input" ); 00077 } 00078 else if( !file_set || ( file_set && *file_set == 0 ) ) 00079 { 00080 rval = mbImpl->create_meshset( MESHSET_SET, tmp_set );MB_CHK_SET_ERR( rval, "Trouble creating file set" ); 00081 } 00082 else 00083 tmp_set = *file_set; 00084 00085 // Get the scd interface 00086 scdi = NULL; 00087 rval = mbImpl->query_interface( scdi ); 00088 if( NULL == scdi ) return MB_FAILURE; 00089 00090 if( NULL != myHelper ) delete myHelper; 00091 00092 // Get appropriate NC helper instance based on information read from the header 00093 myHelper = NCHelper::get_nc_helper( this, fileId, opts, tmp_set ); 00094 if( NULL == myHelper ) 00095 { 00096 MB_SET_ERR( MB_FAILURE, "Failed to get NCHelper class instance" ); 00097 } 00098 00099 // Initialize mesh values 00100 rval = myHelper->init_mesh_vals();MB_CHK_SET_ERR( rval, "Trouble initializing mesh values" ); 00101 00102 // Check existing mesh from last read 00103 if( noMesh && !noVars ) 00104 { 00105 rval = myHelper->check_existing_mesh();MB_CHK_SET_ERR( rval, "Trouble checking mesh from last read" ); 00106 } 00107 00108 // Create some conventional tags, e.g. __NUM_DIMS 00109 // For multiple reads to a specified file set, we assume a single file, or a series of 00110 // files with separated timesteps. Keep a flag on the file set to prevent conventional 00111 // tags from being created again on a second read 00112 Tag convTagsCreated = 0; 00113 int def_val = 0; 00114 rval = mbImpl->tag_get_handle( "__CONV_TAGS_CREATED", 1, MB_TYPE_INTEGER, convTagsCreated, 00115 MB_TAG_SPARSE | MB_TAG_CREAT, &def_val );MB_CHK_SET_ERR( rval, "Trouble getting _CONV_TAGS_CREATED tag" ); 00116 int create_conv_tags_flag = 0; 00117 rval = mbImpl->tag_get_data( convTagsCreated, &tmp_set, 1, &create_conv_tags_flag ); 00118 // The first read to the file set 00119 if( 0 == create_conv_tags_flag ) 00120 { 00121 // Read dimensions (coordinate variables) by default to create tags like __<var_name>_DIMS 00122 // This is done only once (assume that all files read to the file set have the same 00123 // dimensions) 00124 rval = myHelper->read_variables( dimNames, tstep_nums );MB_CHK_SET_ERR( rval, "Trouble reading dimensions" ); 00125 00126 rval = myHelper->create_conventional_tags( tstep_nums );MB_CHK_SET_ERR( rval, "Trouble creating NC conventional tags" ); 00127 00128 create_conv_tags_flag = 1; 00129 rval = mbImpl->tag_set_data( convTagsCreated, &tmp_set, 1, &create_conv_tags_flag );MB_CHK_SET_ERR( rval, "Trouble setting data to _CONV_TAGS_CREATED tag" ); 00130 } 00131 // Another read to the file set 00132 else 00133 { 00134 if( tStepBase > -1 ) 00135 { 00136 // If timesteps spread across files, merge time values read 00137 // from current file to existing time tag 00138 rval = myHelper->update_time_tag_vals();MB_CHK_SET_ERR( rval, "Trouble updating time tag values" ); 00139 } 00140 } 00141 00142 // Create mesh vertex/edge/face sequences 00143 Range faces; 00144 if( !noMesh ) 00145 { 00146 rval = myHelper->create_mesh( faces );MB_CHK_SET_ERR( rval, "Trouble creating mesh" ); 00147 } 00148 00149 // Read specified variables onto grid 00150 if( !noVars ) 00151 { 00152 if( var_names.empty() ) 00153 { 00154 // If VARIABLE option is missing, read all variables 00155 rval = myHelper->read_variables( var_names, tstep_nums );MB_CHK_SET_ERR( rval, "Trouble reading all variables" ); 00156 } 00157 else 00158 { 00159 // Exclude dimensions that are read to the file set by default 00160 std::vector< std::string > non_dim_var_names; 00161 for( unsigned int i = 0; i < var_names.size(); i++ ) 00162 { 00163 if( std::find( dimNames.begin(), dimNames.end(), var_names[i] ) == dimNames.end() ) 00164 non_dim_var_names.push_back( var_names[i] ); 00165 } 00166 00167 if( !non_dim_var_names.empty() ) 00168 { 00169 rval = myHelper->read_variables( non_dim_var_names, tstep_nums );MB_CHK_SET_ERR( rval, "Trouble reading specified variables" ); 00170 } 00171 } 00172 } 00173 00174 #ifdef MOAB_HAVE_MPI 00175 // Create partition set, and populate with elements 00176 if( isParallel ) 00177 { 00178 // Write partition tag name on partition set 00179 Tag part_tag = myPcomm->partition_tag(); 00180 int dum_rank = myPcomm->proc_config().proc_rank(); 00181 // the tmp_set is the file_set 00182 rval = mbImpl->tag_set_data( part_tag, &tmp_set, 1, &dum_rank );MB_CHK_SET_ERR( rval, "Trouble writing partition tag name on partition set" ); 00183 } 00184 #endif 00185 00186 mbImpl->release_interface( scdi ); 00187 scdi = NULL; 00188 00189 // Close the file 00190 success = NCFUNC( close )( fileId ); 00191 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble closing file" ); 00192 00193 return MB_SUCCESS; 00194 } 00195 00196 ErrorCode ReadNC::parse_options( const FileOptions& opts, 00197 std::vector< std::string >& var_names, 00198 std::vector< int >& tstep_nums, 00199 std::vector< double >& tstep_vals ) 00200 { 00201 int tmpval; 00202 if( MB_SUCCESS == opts.get_int_option( "DEBUG_IO", 1, tmpval ) ) 00203 { 00204 dbgOut.set_verbosity( tmpval ); 00205 dbgOut.set_prefix( "NC " ); 00206 } 00207 00208 ErrorCode rval = opts.get_strs_option( "VARIABLE", var_names ); 00209 if( MB_TYPE_OUT_OF_RANGE == rval ) 00210 noVars = true; 00211 else 00212 noVars = false; 00213 00214 opts.get_ints_option( "TIMESTEP", tstep_nums ); 00215 opts.get_reals_option( "TIMEVAL", tstep_vals ); 00216 00217 rval = opts.get_null_option( "NOMESH" ); 00218 if( MB_SUCCESS == rval ) noMesh = true; 00219 00220 rval = opts.get_null_option( "SPECTRAL_MESH" ); 00221 if( MB_SUCCESS == rval ) spectralMesh = true; 00222 00223 rval = opts.get_null_option( "NO_MIXED_ELEMENTS" ); 00224 if( MB_SUCCESS == rval ) noMixedElements = true; 00225 00226 rval = opts.get_null_option( "NO_EDGES" ); 00227 if( MB_SUCCESS == rval ) noEdges = true; 00228 00229 if( 2 <= dbgOut.get_verbosity() ) 00230 { 00231 if( !var_names.empty() ) 00232 { 00233 std::cerr << "Variables requested: "; 00234 for( unsigned int i = 0; i < var_names.size(); i++ ) 00235 std::cerr << var_names[i]; 00236 std::cerr << std::endl; 00237 } 00238 00239 if( !tstep_nums.empty() ) 00240 { 00241 std::cerr << "Timesteps requested: "; 00242 for( unsigned int i = 0; i < tstep_nums.size(); i++ ) 00243 std::cerr << tstep_nums[i]; 00244 std::cerr << std::endl; 00245 } 00246 00247 if( !tstep_vals.empty() ) 00248 { 00249 std::cerr << "Time vals requested: "; 00250 for( unsigned int i = 0; i < tstep_vals.size(); i++ ) 00251 std::cerr << tstep_vals[i]; 00252 std::cerr << std::endl; 00253 } 00254 } 00255 00256 rval = opts.get_int_option( "GATHER_SET", 0, gatherSetRank ); 00257 if( MB_TYPE_OUT_OF_RANGE == rval ) 00258 { 00259 MB_SET_ERR( rval, "Invalid value for GATHER_SET option" ); 00260 } 00261 00262 rval = opts.get_int_option( "TIMESTEPBASE", 0, tStepBase ); 00263 if( MB_TYPE_OUT_OF_RANGE == rval ) 00264 { 00265 MB_SET_ERR( rval, "Invalid value for TIMESTEPBASE option" ); 00266 } 00267 00268 rval = opts.get_int_option( "TRIVIAL_PARTITION_SHIFT", 1, trivialPartitionShift ); 00269 if( MB_TYPE_OUT_OF_RANGE == rval ) 00270 { 00271 MB_SET_ERR( rval, "Invalid value for TRIVIAL_PARTITION_SHIFT option" ); 00272 } 00273 00274 #ifdef MOAB_HAVE_MPI 00275 isParallel = ( opts.match_option( "PARALLEL", "READ_PART" ) != MB_ENTITY_NOT_FOUND ); 00276 00277 if( !isParallel ) 00278 // Return success here, since rval still has _NOT_FOUND from not finding option 00279 // in this case, myPcomm will be NULL, so it can never be used; always check for isParallel 00280 // before any use for myPcomm 00281 return MB_SUCCESS; 00282 00283 int pcomm_no = 0; 00284 rval = opts.get_int_option( "PARALLEL_COMM", pcomm_no ); 00285 if( MB_TYPE_OUT_OF_RANGE == rval ) 00286 { 00287 MB_SET_ERR( rval, "Invalid value for PARALLEL_COMM option" ); 00288 } 00289 myPcomm = ParallelComm::get_pcomm( mbImpl, pcomm_no ); 00290 if( 0 == myPcomm ) 00291 { 00292 myPcomm = new ParallelComm( mbImpl, MPI_COMM_WORLD ); 00293 } 00294 const int rank = myPcomm->proc_config().proc_rank(); 00295 dbgOut.set_rank( rank ); 00296 00297 int dum; 00298 rval = opts.match_option( "PARTITION_METHOD", ScdParData::PartitionMethodNames, dum ); 00299 if( MB_FAILURE == rval ) 00300 { 00301 MB_SET_ERR( rval, "Unknown partition method specified" ); 00302 } 00303 else if( MB_ENTITY_NOT_FOUND == rval ) 00304 partMethod = ScdParData::ALLJORKORI; 00305 else 00306 partMethod = dum; 00307 #endif 00308 00309 return MB_SUCCESS; 00310 } 00311 00312 ErrorCode ReadNC::read_header() 00313 { 00314 dbgOut.tprint( 1, "Reading header...\n" ); 00315 00316 // Get the global attributes 00317 int numgatts; 00318 int success; 00319 success = NCFUNC( inq_natts )( fileId, &numgatts ); 00320 if( success ) MB_SET_ERR( MB_FAILURE, "Couldn't get number of global attributes" ); 00321 00322 // Read attributes into globalAtts 00323 ErrorCode result = get_attributes( NC_GLOBAL, numgatts, globalAtts );MB_CHK_SET_ERR( result, "Trouble getting global attributes" ); 00324 dbgOut.tprintf( 1, "Read %u attributes\n", (unsigned int)globalAtts.size() ); 00325 00326 // Read in dimensions into dimNames and dimLens 00327 result = get_dimensions( fileId, dimNames, dimLens );MB_CHK_SET_ERR( result, "Trouble getting dimensions" ); 00328 dbgOut.tprintf( 1, "Read %u dimensions\n", (unsigned int)dimNames.size() ); 00329 00330 // Read in variables into varInfo 00331 result = get_variables();MB_CHK_SET_ERR( result, "Trouble getting variables" ); 00332 dbgOut.tprintf( 1, "Read %u variables\n", (unsigned int)varInfo.size() ); 00333 00334 return MB_SUCCESS; 00335 } 00336 00337 ErrorCode ReadNC::get_attributes( int var_id, int num_atts, std::map< std::string, AttData >& atts, const char* prefix ) 00338 { 00339 char dum_name[120]; 00340 00341 for( int i = 0; i < num_atts; i++ ) 00342 { 00343 // Get the name 00344 int success = NCFUNC( inq_attname )( fileId, var_id, i, dum_name ); 00345 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting attribute name" ); 00346 00347 AttData& data = atts[std::string( dum_name )]; 00348 data.attName = std::string( dum_name ); 00349 success = NCFUNC( inq_att )( fileId, var_id, dum_name, &data.attDataType, &data.attLen ); 00350 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting info for attribute " << data.attName ); 00351 data.attVarId = var_id; 00352 00353 dbgOut.tprintf( 2, "%sAttribute %s: length=%u, varId=%d, type=%d\n", ( prefix ? prefix : "" ), 00354 data.attName.c_str(), (unsigned int)data.attLen, data.attVarId, data.attDataType ); 00355 } 00356 00357 return MB_SUCCESS; 00358 } 00359 00360 ErrorCode ReadNC::get_dimensions( int file_id, std::vector< std::string >& dim_names, std::vector< int >& dim_lens ) 00361 { 00362 // Get the number of dimensions 00363 int num_dims; 00364 int success = NCFUNC( inq_ndims )( file_id, &num_dims ); 00365 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting number of dimensions" ); 00366 00367 if( num_dims > NC_MAX_DIMS ) 00368 { 00369 MB_SET_ERR( MB_FAILURE, 00370 "ReadNC: File contains " << num_dims << " dims but NetCDF library supports only " << NC_MAX_DIMS ); 00371 } 00372 00373 char dim_name[NC_MAX_NAME + 1]; 00374 NCDF_SIZE dim_len; 00375 dim_names.resize( num_dims ); 00376 dim_lens.resize( num_dims ); 00377 00378 for( int i = 0; i < num_dims; i++ ) 00379 { 00380 success = NCFUNC( inq_dim )( file_id, i, dim_name, &dim_len ); 00381 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting dimension info" ); 00382 00383 dim_names[i] = std::string( dim_name ); 00384 dim_lens[i] = dim_len; 00385 00386 dbgOut.tprintf( 2, "Dimension %s, length=%u\n", dim_name, (unsigned int)dim_len ); 00387 } 00388 00389 return MB_SUCCESS; 00390 } 00391 00392 ErrorCode ReadNC::get_variables() 00393 { 00394 // First cache the number of time steps 00395 std::vector< std::string >::iterator vit = std::find( dimNames.begin(), dimNames.end(), "time" ); 00396 if( vit == dimNames.end() ) vit = std::find( dimNames.begin(), dimNames.end(), "t" ); 00397 00398 int ntimes = 0; 00399 if( vit != dimNames.end() ) ntimes = dimLens[vit - dimNames.begin()]; 00400 if( !ntimes ) ntimes = 1; 00401 00402 // Get the number of variables 00403 int num_vars; 00404 int success = NCFUNC( inq_nvars )( fileId, &num_vars ); 00405 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting number of variables" ); 00406 00407 if( num_vars > NC_MAX_VARS ) 00408 { 00409 MB_SET_ERR( MB_FAILURE, 00410 "ReadNC: File contains " << num_vars << " vars but NetCDF library supports only " << NC_MAX_VARS ); 00411 } 00412 00413 char var_name[NC_MAX_NAME + 1]; 00414 int var_ndims; 00415 00416 for( int i = 0; i < num_vars; i++ ) 00417 { 00418 // Get the name first, so we can allocate a map iterate for this var 00419 success = NCFUNC( inq_varname )( fileId, i, var_name ); 00420 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting variable name" ); 00421 VarData& data = varInfo[std::string( var_name )]; 00422 data.varName = std::string( var_name ); 00423 data.varId = i; 00424 data.varTags.resize( ntimes, 0 ); 00425 00426 // Get the data type 00427 success = NCFUNC( inq_vartype )( fileId, i, &data.varDataType ); 00428 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting data type for variable " << data.varName ); 00429 00430 // Get the number of dimensions, then the dimensions 00431 success = NCFUNC( inq_varndims )( fileId, i, &var_ndims ); 00432 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting number of dims for variable " << data.varName ); 00433 data.varDims.resize( var_ndims ); 00434 00435 success = NCFUNC( inq_vardimid )( fileId, i, &data.varDims[0] ); 00436 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting dimensions for variable " << data.varName ); 00437 00438 // Finally, get the number of attributes, then the attributes 00439 success = NCFUNC( inq_varnatts )( fileId, i, &data.numAtts ); 00440 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble getting number of dims for variable " << data.varName ); 00441 00442 // Print debug info here so attribute info comes afterwards 00443 dbgOut.tprintf( 2, "Variable %s: Id=%d, numAtts=%d, datatype=%d, num_dims=%u\n", data.varName.c_str(), 00444 data.varId, data.numAtts, data.varDataType, (unsigned int)data.varDims.size() ); 00445 00446 ErrorCode rval = get_attributes( i, data.numAtts, data.varAtts, " " );MB_CHK_SET_ERR( rval, "Trouble getting attributes for variable " << data.varName ); 00447 } 00448 00449 return MB_SUCCESS; 00450 } 00451 00452 ErrorCode ReadNC::read_tag_values( const char*, 00453 const char*, 00454 const FileOptions&, 00455 std::vector< int >&, 00456 const SubsetList* ) 00457 { 00458 return MB_FAILURE; 00459 } 00460 00461 } // namespace moab