![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
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 ___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