![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "NCHelperHOMME.hpp"
00002 #include "moab/ReadUtilIface.hpp"
00003 #include "moab/FileOptions.hpp"
00004 #include "moab/SpectralMeshTool.hpp"
00005
00006 #include
00007
00008 namespace moab
00009 {
00010
00011 NCHelperHOMME::NCHelperHOMME( ReadNC* readNC, int fileId, const FileOptions& opts, EntityHandle fileSet )
00012 : UcdNCHelper( readNC, fileId, opts, fileSet ), _spectralOrder( -1 ), connectId( -1 ), isConnFile( false )
00013 {
00014 // Calculate spectral order
00015 std::map< std::string, ReadNC::AttData >::iterator attIt = readNC->globalAtts.find( "np" );
00016 if( attIt != readNC->globalAtts.end() )
00017 {
00018 int success = NCFUNC( get_att_int )( readNC->fileId, attIt->second.attVarId, attIt->second.attName.c_str(),
00019 &_spectralOrder );
00020 if( 0 == success ) _spectralOrder--; // Spectral order is one less than np
00021 }
00022 else
00023 {
00024 // As can_read_file() returns true and there is no global attribute "np", it should be a
00025 // connectivity file
00026 isConnFile = true;
00027 _spectralOrder = 3; // Assume np is 4
00028 }
00029 }
00030
00031 bool NCHelperHOMME::can_read_file( ReadNC* readNC, int fileId )
00032 {
00033 // If global attribute "np" exists then it should be the HOMME grid
00034 if( readNC->globalAtts.find( "np" ) != readNC->globalAtts.end() )
00035 {
00036 // Make sure it is CAM grid
00037 std::map< std::string, ReadNC::AttData >::iterator attIt = readNC->globalAtts.find( "source" );
00038 if( attIt == readNC->globalAtts.end() ) return false;
00039 unsigned int sz = attIt->second.attLen;
00040 std::string att_data;
00041 att_data.resize( sz + 1 );
00042 att_data[sz] = '\000';
00043 int success =
00044 NCFUNC( get_att_text )( fileId, attIt->second.attVarId, attIt->second.attName.c_str(), &att_data[0] );
00045 if( success ) return false;
00046 if( att_data.find( "CAM" ) == std::string::npos ) return false;
00047
00048 return true;
00049 }
00050 else
00051 {
00052 // If dimension names "ncol" AND "ncorners" AND "ncells" exist, then it should be the HOMME
00053 // connectivity file In this case, the mesh can still be created
00054 std::vector< std::string >& dimNames = readNC->dimNames;
00055 if( ( std::find( dimNames.begin(), dimNames.end(), std::string( "ncol" ) ) != dimNames.end() ) &&
00056 ( std::find( dimNames.begin(), dimNames.end(), std::string( "ncorners" ) ) != dimNames.end() ) &&
00057 ( std::find( dimNames.begin(), dimNames.end(), std::string( "ncells" ) ) != dimNames.end() ) )
00058 return true;
00059 }
00060
00061 return false;
00062 }
00063
00064 ErrorCode NCHelperHOMME::init_mesh_vals()
00065 {
00066 std::vector< std::string >& dimNames = _readNC->dimNames;
00067 std::vector< int >& dimLens = _readNC->dimLens;
00068 std::map< std::string, ReadNC::VarData >& varInfo = _readNC->varInfo;
00069
00070 ErrorCode rval;
00071 unsigned int idx;
00072 std::vector< std::string >::iterator vit;
00073
00074 // Look for time dimension
00075 if( isConnFile )
00076 {
00077 // Connectivity file might not have time dimension
00078 }
00079 else
00080 {
00081 if( ( vit = std::find( dimNames.begin(), dimNames.end(), "time" ) ) != dimNames.end() )
00082 idx = vit - dimNames.begin();
00083 else if( ( vit = std::find( dimNames.begin(), dimNames.end(), "t" ) ) != dimNames.end() )
00084 idx = vit - dimNames.begin();
00085 else
00086 {
00087 MB_SET_ERR( MB_FAILURE, "Couldn't find 'time' or 't' dimension" );
00088 }
00089 tDim = idx;
00090 nTimeSteps = dimLens[idx];
00091 }
00092
00093 // Get number of vertices (labeled as number of columns)
00094 if( ( vit = std::find( dimNames.begin(), dimNames.end(), "ncol" ) ) != dimNames.end() )
00095 idx = vit - dimNames.begin();
00096 else
00097 {
00098 MB_SET_ERR( MB_FAILURE, "Couldn't find 'ncol' dimension" );
00099 }
00100 vDim = idx;
00101 nVertices = dimLens[idx];
00102
00103 // Set number of cells
00104 nCells = nVertices - 2;
00105
00106 // Get number of levels
00107 if( isConnFile )
00108 {
00109 // Connectivity file might not have level dimension
00110 }
00111 else
00112 {
00113 if( ( vit = std::find( dimNames.begin(), dimNames.end(), "lev" ) ) != dimNames.end() )
00114 idx = vit - dimNames.begin();
00115 else if( ( vit = std::find( dimNames.begin(), dimNames.end(), "ilev" ) ) != dimNames.end() )
00116 idx = vit - dimNames.begin();
00117 else
00118 {
00119 MB_SET_ERR( MB_FAILURE, "Couldn't find 'lev' or 'ilev' dimension" );
00120 }
00121 levDim = idx;
00122 nLevels = dimLens[idx];
00123 }
00124
00125 // Store lon values in xVertVals
00126 std::map< std::string, ReadNC::VarData >::iterator vmit;
00127 if( ( vmit = varInfo.find( "lon" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
00128 {
00129 rval = read_coordinate( "lon", 0, nVertices - 1, xVertVals );MB_CHK_SET_ERR( rval, "Trouble reading 'lon' variable" );
00130 }
00131 else
00132 {
00133 MB_SET_ERR( MB_FAILURE, "Couldn't find 'lon' variable" );
00134 }
00135
00136 // Store lat values in yVertVals
00137 if( ( vmit = varInfo.find( "lat" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
00138 {
00139 rval = read_coordinate( "lat", 0, nVertices - 1, yVertVals );MB_CHK_SET_ERR( rval, "Trouble reading 'lat' variable" );
00140 }
00141 else
00142 {
00143 MB_SET_ERR( MB_FAILURE, "Couldn't find 'lat' variable" );
00144 }
00145
00146 // Store lev values in levVals
00147 if( isConnFile )
00148 {
00149 // Connectivity file might not have level variable
00150 }
00151 else
00152 {
00153 if( ( vmit = varInfo.find( "lev" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
00154 {
00155 rval = read_coordinate( "lev", 0, nLevels - 1, levVals );MB_CHK_SET_ERR( rval, "Trouble reading 'lev' variable" );
00156
00157 // Decide whether down is positive
00158 char posval[10] = { 0 };
00159 int success = NCFUNC( get_att_text )( _fileId, ( *vmit ).second.varId, "positive", posval );
00160 if( 0 == success && !strcmp( posval, "down" ) )
00161 {
00162 for( std::vector< double >::iterator dvit = levVals.begin(); dvit != levVals.end(); ++dvit )
00163 ( *dvit ) *= -1.0;
00164 }
00165 }
00166 else
00167 {
00168 MB_SET_ERR( MB_FAILURE, "Couldn't find 'lev' variable" );
00169 }
00170 }
00171
00172 // Store time coordinate values in tVals
00173 if( isConnFile )
00174 {
00175 // Connectivity file might not have time variable
00176 }
00177 else
00178 {
00179 if( ( vmit = varInfo.find( "time" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
00180 {
00181 rval = read_coordinate( "time", 0, nTimeSteps - 1, tVals );MB_CHK_SET_ERR( rval, "Trouble reading 'time' variable" );
00182 }
00183 else if( ( vmit = varInfo.find( "t" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
00184 {
00185 rval = read_coordinate( "t", 0, nTimeSteps - 1, tVals );MB_CHK_SET_ERR( rval, "Trouble reading 't' variable" );
00186 }
00187 else
00188 {
00189 // If expected time variable does not exist, set dummy values to tVals
00190 for( int t = 0; t < nTimeSteps; t++ )
00191 tVals.push_back( (double)t );
00192 }
00193 }
00194
00195 // For each variable, determine the entity location type and number of levels
00196 std::map< std::string, ReadNC::VarData >::iterator mit;
00197 for( mit = varInfo.begin(); mit != varInfo.end(); ++mit )
00198 {
00199 ReadNC::VarData& vd = ( *mit ).second;
00200
00201 // Default entLoc is ENTLOCSET
00202 if( std::find( vd.varDims.begin(), vd.varDims.end(), tDim ) != vd.varDims.end() )
00203 {
00204 if( std::find( vd.varDims.begin(), vd.varDims.end(), vDim ) != vd.varDims.end() )
00205 vd.entLoc = ReadNC::ENTLOCVERT;
00206 }
00207
00208 // Default numLev is 0
00209 if( std::find( vd.varDims.begin(), vd.varDims.end(), levDim ) != vd.varDims.end() ) vd.numLev = nLevels;
00210 }
00211
00212 // Hack: create dummy variables for dimensions (like ncol) with no corresponding coordinate
00213 // variables
00214 rval = create_dummy_variables();MB_CHK_SET_ERR( rval, "Failed to create dummy variables" );
00215
00216 return MB_SUCCESS;
00217 }
00218
00219 // When noMesh option is used on this read, the old ReadNC class instance for last read can get out
00220 // of scope (and deleted). The old instance initialized localGidVerts properly when the mesh was
00221 // created, but it is now lost. The new instance (will not create the mesh with noMesh option) has
00222 // to restore it based on the existing mesh from last read
00223 ErrorCode NCHelperHOMME::check_existing_mesh()
00224 {
00225 Interface*& mbImpl = _readNC->mbImpl;
00226 Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
00227 bool& noMesh = _readNC->noMesh;
00228
00229 if( noMesh && localGidVerts.empty() )
00230 {
00231 // We need to populate localGidVerts range with the gids of vertices from current file set
00232 // localGidVerts is important in reading the variable data into the nodes
00233 // Also, for our purposes, localGidVerts is truly the GLOBAL_ID tag data, not other
00234 // file_id tags that could get passed around in other scenarios for parallel reading
00235
00236 // Get all vertices from current file set (it is the input set in no_mesh scenario)
00237 Range local_verts;
00238 ErrorCode rval = mbImpl->get_entities_by_dimension( _fileSet, 0, local_verts );MB_CHK_SET_ERR( rval, "Trouble getting local vertices in current file set" );
00239
00240 if( !local_verts.empty() )
00241 {
00242 std::vector< int > gids( local_verts.size() );
00243
00244 // !IMPORTANT : this has to be the GLOBAL_ID tag
00245 rval = mbImpl->tag_get_data( mGlobalIdTag, local_verts, &gids[0] );MB_CHK_SET_ERR( rval, "Trouble getting local gid values of vertices" );
00246
00247 // Restore localGidVerts
00248 std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidVerts ) );
00249 nLocalVertices = localGidVerts.size();
00250 }
00251 }
00252
00253 return MB_SUCCESS;
00254 }
00255
00256 ErrorCode NCHelperHOMME::create_mesh( Range& faces )
00257 {
00258 Interface*& mbImpl = _readNC->mbImpl;
00259 std::string& fileName = _readNC->fileName;
00260 Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
00261 const Tag*& mpFileIdTag = _readNC->mpFileIdTag;
00262 DebugOutput& dbgOut = _readNC->dbgOut;
00263 bool& spectralMesh = _readNC->spectralMesh;
00264 int& gatherSetRank = _readNC->gatherSetRank;
00265 int& trivialPartitionShift = _readNC->trivialPartitionShift;
00266
00267 int rank = 0;
00268 int procs = 1;
00269 #ifdef MOAB_HAVE_MPI
00270 bool& isParallel = _readNC->isParallel;
00271 if( isParallel )
00272 {
00273 ParallelComm*& myPcomm = _readNC->myPcomm;
00274 rank = myPcomm->proc_config().proc_rank();
00275 procs = myPcomm->proc_config().proc_size();
00276 }
00277 #endif
00278
00279 ErrorCode rval;
00280 int success = 0;
00281
00282 // Need to get/read connectivity data before creating elements
00283 std::string conn_fname;
00284
00285 if( isConnFile )
00286 {
00287 // Connectivity file has already been read
00288 connectId = _readNC->fileId;
00289 }
00290 else
00291 {
00292 // Try to open the connectivity file through CONN option, if used
00293 rval = _opts.get_str_option( "CONN", conn_fname );
00294 if( MB_SUCCESS != rval )
00295 {
00296 // Default convention for reading HOMME is a file HommeMapping.nc in same dir as data
00297 // file
00298 conn_fname = std::string( fileName );
00299 size_t idx = conn_fname.find_last_of( "/" );
00300 if( idx != std::string::npos )
00301 conn_fname = conn_fname.substr( 0, idx ).append( "/HommeMapping.nc" );
00302 else
00303 conn_fname = "HommeMapping.nc";
00304 }
00305 #ifdef MOAB_HAVE_PNETCDF
00306 #ifdef MOAB_HAVE_MPI
00307 if( isParallel )
00308 {
00309 ParallelComm*& myPcomm = _readNC->myPcomm;
00310 success =
00311 NCFUNC( open )( myPcomm->proc_config().proc_comm(), conn_fname.c_str(), 0, MPI_INFO_NULL, &connectId );
00312 }
00313 else
00314 success = NCFUNC( open )( MPI_COMM_SELF, conn_fname.c_str(), 0, MPI_INFO_NULL, &connectId );
00315 #endif
00316 #else
00317 success = NCFUNC( open )( conn_fname.c_str(), 0, &connectId );
00318 #endif
00319 if( success ) MB_SET_ERR( MB_FAILURE, "Failed on open" );
00320 }
00321
00322 std::vector< std::string > conn_names;
00323 std::vector< int > conn_vals;
00324 rval = _readNC->get_dimensions( connectId, conn_names, conn_vals );MB_CHK_SET_ERR( rval, "Failed to get dimensions for connectivity" );
00325
00326 // Read connectivity into temporary variable
00327 int num_fine_quads = 0;
00328 int num_coarse_quads = 0;
00329 int start_idx = 0;
00330 std::vector< std::string >::iterator vit;
00331 int idx = 0;
00332 if( ( vit = std::find( conn_names.begin(), conn_names.end(), "ncells" ) ) != conn_names.end() )
00333 idx = vit - conn_names.begin();
00334 else if( ( vit = std::find( conn_names.begin(), conn_names.end(), "ncenters" ) ) != conn_names.end() )
00335 idx = vit - conn_names.begin();
00336 else
00337 {
00338 MB_SET_ERR( MB_FAILURE, "Failed to get number of quads" );
00339 }
00340 int num_quads = conn_vals[idx];
00341 if( !isConnFile && num_quads != nCells )
00342 {
00343 dbgOut.tprintf( 1,
00344 "Warning: number of quads from %s and cells from %s are inconsistent; "
00345 "num_quads = %d, nCells = %d.\n",
00346 conn_fname.c_str(), fileName.c_str(), num_quads, nCells );
00347 }
00348
00349 // Get the connectivity into tmp_conn2 and permute into tmp_conn
00350 int cornerVarId;
00351 success = NCFUNC( inq_varid )( connectId, "element_corners", &cornerVarId );
00352 if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of 'element_corners'" );
00353 NCDF_SIZE tmp_starts[2] = { 0, 0 };
00354 NCDF_SIZE tmp_counts[2] = { 4, static_cast< NCDF_SIZE >( num_quads ) };
00355 std::vector< int > tmp_conn( 4 * num_quads ), tmp_conn2( 4 * num_quads );
00356 success = NCFUNCAG( _vara_int )( connectId, cornerVarId, tmp_starts, tmp_counts, &tmp_conn2[0] );
00357 if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get temporary connectivity" );
00358 if( isConnFile )
00359 {
00360 // This data/connectivity file will be closed later in ReadNC::load_file()
00361 }
00362 else
00363 {
00364 success = NCFUNC( close )( connectId );
00365 if( success ) MB_SET_ERR( MB_FAILURE, "Failed on close" );
00366 }
00367 // Permute the connectivity
00368 for( int i = 0; i < num_quads; i++ )
00369 {
00370 tmp_conn[4 * i] = tmp_conn2[i];
00371 tmp_conn[4 * i + 1] = tmp_conn2[i + 1 * num_quads];
00372 tmp_conn[4 * i + 2] = tmp_conn2[i + 2 * num_quads];
00373 tmp_conn[4 * i + 3] = tmp_conn2[i + 3 * num_quads];
00374 }
00375
00376 // Need to know whether we'll be creating gather mesh later, to make sure
00377 // we allocate enough space in one shot
00378 bool create_gathers = false;
00379 if( rank == gatherSetRank ) create_gathers = true;
00380
00381 // Shift rank to obtain a rotated trivial partition
00382 int shifted_rank = rank;
00383 if( procs >= 2 && trivialPartitionShift > 0 ) shifted_rank = ( rank + trivialPartitionShift ) % procs;
00384
00385 // Compute the number of local quads, accounting for coarse or fine representation
00386 // spectral_unit is the # fine quads per coarse quad, or spectralOrder^2
00387 int spectral_unit = ( spectralMesh ? _spectralOrder * _spectralOrder : 1 );
00388 // num_coarse_quads is the number of quads instantiated in MOAB; if !spectralMesh,
00389 // num_coarse_quads = num_fine_quads
00390 num_coarse_quads = int( std::floor( 1.0 * num_quads / ( spectral_unit * procs ) ) );
00391 // start_idx is the starting index in the HommeMapping connectivity list for this proc, before
00392 // converting to coarse quad representation
00393 start_idx = 4 * shifted_rank * num_coarse_quads * spectral_unit;
00394 // iextra = # coarse quads extra after equal split over procs
00395 int iextra = num_quads % ( procs * spectral_unit );
00396 if( shifted_rank < iextra ) num_coarse_quads++;
00397 start_idx += 4 * spectral_unit * std::min( shifted_rank, iextra );
00398 // num_fine_quads is the number of quads in the connectivity list in HommeMapping file assigned
00399 // to this proc
00400 num_fine_quads = spectral_unit * num_coarse_quads;
00401
00402 // Now create num_coarse_quads
00403 EntityHandle* conn_arr;
00404 EntityHandle start_vertex;
00405 Range tmp_range;
00406
00407 // Read connectivity into that space
00408 EntityHandle* sv_ptr = NULL;
00409 EntityHandle start_quad;
00410 SpectralMeshTool smt( mbImpl, _spectralOrder );
00411 if( !spectralMesh )
00412 {
00413 rval = _readNC->readMeshIface->get_element_connect( num_coarse_quads, 4, MBQUAD, 0, start_quad, conn_arr,
00414 // Might have to create gather mesh later
00415 ( create_gathers ? num_coarse_quads + num_quads
00416 : num_coarse_quads ) );MB_CHK_SET_ERR( rval, "Failed to create local quads" );
00417 tmp_range.insert( start_quad, start_quad + num_coarse_quads - 1 );
00418 int* tmp_conn_end = ( &tmp_conn[start_idx + 4 * num_fine_quads - 1] ) + 1;
00419 std::copy( &tmp_conn[start_idx], tmp_conn_end, conn_arr );
00420 std::copy( conn_arr, conn_arr + 4 * num_fine_quads, range_inserter( localGidVerts ) );
00421 }
00422 else
00423 {
00424 rval = smt.create_spectral_elems( &tmp_conn[0], num_fine_quads, 2, tmp_range, start_idx, &localGidVerts );MB_CHK_SET_ERR( rval, "Failed to create spectral elements" );
00425 int count, v_per_e;
00426 rval = mbImpl->connect_iterate( tmp_range.begin(), tmp_range.end(), conn_arr, v_per_e, count );MB_CHK_SET_ERR( rval, "Failed to get connectivity of spectral elements" );
00427 rval = mbImpl->tag_iterate( smt.spectral_vertices_tag( true ), tmp_range.begin(), tmp_range.end(), count,
00428 (void*&)sv_ptr );MB_CHK_SET_ERR( rval, "Failed to get fine connectivity of spectral elements" );
00429 }
00430
00431 // Create vertices
00432 nLocalVertices = localGidVerts.size();
00433 std::vector< double* > arrays;
00434 rval = _readNC->readMeshIface->get_node_coords( 3, nLocalVertices, 0, start_vertex, arrays,
00435 // Might have to create gather mesh later
00436 ( create_gathers ? nLocalVertices + nVertices : nLocalVertices ) );MB_CHK_SET_ERR( rval, "Failed to create local vertices" );
00437
00438 // Set vertex coordinates
00439 Range::iterator rit;
00440 double* xptr = arrays[0];
00441 double* yptr = arrays[1];
00442 double* zptr = arrays[2];
00443 int i;
00444 for( i = 0, rit = localGidVerts.begin(); i < nLocalVertices; i++, ++rit )
00445 {
00446 assert( *rit < xVertVals.size() + 1 );
00447 xptr[i] = xVertVals[( *rit ) - 1]; // lon
00448 yptr[i] = yVertVals[( *rit ) - 1]; // lat
00449 }
00450
00451 // Convert lon/lat/rad to x/y/z
00452 const double pideg = acos( -1.0 ) / 180.0;
00453 double rad = ( isConnFile ) ? 8000.0 : 8000.0 + levVals[0];
00454 for( i = 0; i < nLocalVertices; i++ )
00455 {
00456 double cosphi = cos( pideg * yptr[i] );
00457 double zmult = sin( pideg * yptr[i] );
00458 double xmult = cosphi * cos( xptr[i] * pideg );
00459 double ymult = cosphi * sin( xptr[i] * pideg );
00460 xptr[i] = rad * xmult;
00461 yptr[i] = rad * ymult;
00462 zptr[i] = rad * zmult;
00463 }
00464
00465 // Get ptr to gid memory for vertices
00466 Range vert_range( start_vertex, start_vertex + nLocalVertices - 1 );
00467 void* data;
00468 int count;
00469 rval = mbImpl->tag_iterate( mGlobalIdTag, vert_range.begin(), vert_range.end(), count, data );MB_CHK_SET_ERR( rval, "Failed to iterate global id tag on local vertices" );
00470 assert( count == nLocalVertices );
00471 int* gid_data = (int*)data;
00472 std::copy( localGidVerts.begin(), localGidVerts.end(), gid_data );
00473
00474 // Duplicate global id data, which will be used to resolve sharing
00475 if( mpFileIdTag )
00476 {
00477 rval = mbImpl->tag_iterate( *mpFileIdTag, vert_range.begin(), vert_range.end(), count, data );MB_CHK_SET_ERR( rval, "Failed to iterate file id tag on local vertices" );
00478 assert( count == nLocalVertices );
00479 int bytes_per_tag = 4;
00480 rval = mbImpl->tag_get_bytes( *mpFileIdTag, bytes_per_tag );MB_CHK_SET_ERR( rval, "Can't get number of bytes for file id tag" );
00481 if( 4 == bytes_per_tag )
00482 {
00483 gid_data = (int*)data;
00484 std::copy( localGidVerts.begin(), localGidVerts.end(), gid_data );
00485 }
00486 else if( 8 == bytes_per_tag )
00487 { // Should be a handle tag on 64 bit machine?
00488 long* handle_tag_data = (long*)data;
00489 std::copy( localGidVerts.begin(), localGidVerts.end(), handle_tag_data );
00490 }
00491 }
00492
00493 // Create map from file ids to vertex handles, used later to set connectivity
00494 std::map< EntityHandle, EntityHandle > vert_handles;
00495 for( rit = localGidVerts.begin(), i = 0; rit != localGidVerts.end(); ++rit, i++ )
00496 vert_handles[*rit] = start_vertex + i;
00497
00498 // Compute proper handles in connectivity using offset
00499 for( int q = 0; q < 4 * num_coarse_quads; q++ )
00500 {
00501 conn_arr[q] = vert_handles[conn_arr[q]];
00502 assert( conn_arr[q] );
00503 }
00504 if( spectralMesh )
00505 {
00506 int verts_per_quad = ( _spectralOrder + 1 ) * ( _spectralOrder + 1 );
00507 for( int q = 0; q < verts_per_quad * num_coarse_quads; q++ )
00508 {
00509 sv_ptr[q] = vert_handles[sv_ptr[q]];
00510 assert( sv_ptr[q] );
00511 }
00512 }
00513
00514 // Add new vertices and quads to current file set
00515 faces.merge( tmp_range );
00516 tmp_range.insert( start_vertex, start_vertex + nLocalVertices - 1 );
00517 rval = mbImpl->add_entities( _fileSet, tmp_range );MB_CHK_SET_ERR( rval, "Failed to add new vertices and quads to current file set" );
00518
00519 // Mark the set with the spectral order
00520 Tag sporder;
00521 rval = mbImpl->tag_get_handle( "SPECTRAL_ORDER", 1, MB_TYPE_INTEGER, sporder, MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_SET_ERR( rval, "Trouble creating SPECTRAL_ORDER tag" );
00522 rval = mbImpl->tag_set_data( sporder, &_fileSet, 1, &_spectralOrder );MB_CHK_SET_ERR( rval, "Trouble setting data to SPECTRAL_ORDER tag" );
00523
00524 if( create_gathers )
00525 {
00526 EntityHandle gather_set;
00527 rval = _readNC->readMeshIface->create_gather_set( gather_set );MB_CHK_SET_ERR( rval, "Failed to create gather set" );
00528
00529 // Create vertices
00530 arrays.clear();
00531 // Don't need to specify allocation number here, because we know enough verts were created
00532 // before
00533 rval = _readNC->readMeshIface->get_node_coords( 3, nVertices, 0, start_vertex, arrays );MB_CHK_SET_ERR( rval, "Failed to create gather set vertices" );
00534
00535 xptr = arrays[0];
00536 yptr = arrays[1];
00537 zptr = arrays[2];
00538 for( i = 0; i < nVertices; i++ )
00539 {
00540 double cosphi = cos( pideg * yVertVals[i] );
00541 double zmult = sin( pideg * yVertVals[i] );
00542 double xmult = cosphi * cos( xVertVals[i] * pideg );
00543 double ymult = cosphi * sin( xVertVals[i] * pideg );
00544 xptr[i] = rad * xmult;
00545 yptr[i] = rad * ymult;
00546 zptr[i] = rad * zmult;
00547 }
00548
00549 // Get ptr to gid memory for vertices
00550 Range gather_set_verts_range( start_vertex, start_vertex + nVertices - 1 );
00551 rval = mbImpl->tag_iterate( mGlobalIdTag, gather_set_verts_range.begin(), gather_set_verts_range.end(), count,
00552 data );MB_CHK_SET_ERR( rval, "Failed to iterate global id tag on gather set vertices" );
00553 assert( count == nVertices );
00554 gid_data = (int*)data;
00555 for( int j = 1; j <= nVertices; j++ )
00556 gid_data[j - 1] = j;
00557 // Set the file id tag too, it should be bigger something not interfering with global id
00558 if( mpFileIdTag )
00559 {
00560 rval = mbImpl->tag_iterate( *mpFileIdTag, gather_set_verts_range.begin(), gather_set_verts_range.end(),
00561 count, data );MB_CHK_SET_ERR( rval, "Failed to iterate file id tag on gather set vertices" );
00562 assert( count == nVertices );
00563 int bytes_per_tag = 4;
00564 rval = mbImpl->tag_get_bytes( *mpFileIdTag, bytes_per_tag );MB_CHK_SET_ERR( rval, "Can't get number of bytes for file id tag" );
00565 if( 4 == bytes_per_tag )
00566 {
00567 gid_data = (int*)data;
00568 for( int j = 1; j <= nVertices; j++ )
00569 gid_data[j - 1] = nVertices + j; // Bigger than global id tag
00570 }
00571 else if( 8 == bytes_per_tag )
00572 { // Should be a handle tag on 64 bit machine?
00573 long* handle_tag_data = (long*)data;
00574 for( int j = 1; j <= nVertices; j++ )
00575 handle_tag_data[j - 1] = nVertices + j; // Bigger than global id tag
00576 }
00577 }
00578
00579 rval = mbImpl->add_entities( gather_set, gather_set_verts_range );MB_CHK_SET_ERR( rval, "Failed to add vertices to the gather set" );
00580
00581 // Create quads
00582 Range gather_set_quads_range;
00583 // Don't need to specify allocation number here, because we know enough quads were created
00584 // before
00585 rval = _readNC->readMeshIface->get_element_connect( num_quads, 4, MBQUAD, 0, start_quad, conn_arr );MB_CHK_SET_ERR( rval, "Failed to create gather set quads" );
00586 gather_set_quads_range.insert( start_quad, start_quad + num_quads - 1 );
00587 int* tmp_conn_end = ( &tmp_conn[4 * num_quads - 1] ) + 1;
00588 std::copy( &tmp_conn[0], tmp_conn_end, conn_arr );
00589 for( i = 0; i != 4 * num_quads; i++ )
00590 conn_arr[i] += start_vertex - 1; // Connectivity array is shifted by where the gather verts start
00591 rval = mbImpl->add_entities( gather_set, gather_set_quads_range );MB_CHK_SET_ERR( rval, "Failed to add quads to the gather set" );
00592 }
00593
00594 return MB_SUCCESS;
00595 }
00596
00597 ErrorCode NCHelperHOMME::read_ucd_variables_to_nonset_allocate( std::vector< ReadNC::VarData >& vdatas,
00598 std::vector< int >& tstep_nums )
00599 {
00600 Interface*& mbImpl = _readNC->mbImpl;
00601 std::vector< int >& dimLens = _readNC->dimLens;
00602 DebugOutput& dbgOut = _readNC->dbgOut;
00603
00604 Range* range = NULL;
00605
00606 // Get vertices
00607 Range verts;
00608 ErrorCode rval = mbImpl->get_entities_by_dimension( _fileSet, 0, verts );MB_CHK_SET_ERR( rval, "Trouble getting vertices in current file set" );
00609 assert( "Should only have a single vertex subrange, since they were read in one shot" && verts.psize() == 1 );
00610
00611 for( unsigned int i = 0; i < vdatas.size(); i++ )
00612 {
00613 // Support non-set variables with 3 dimensions like (time, lev, ncol)
00614 assert( 3 == vdatas[i].varDims.size() );
00615
00616 // For a non-set variable, time should be the first dimension
00617 assert( tDim == vdatas[i].varDims[0] );
00618
00619 // Set up readStarts and readCounts
00620 vdatas[i].readStarts.resize( 3 );
00621 vdatas[i].readCounts.resize( 3 );
00622
00623 // First: time
00624 vdatas[i].readStarts[0] = 0; // This value is timestep dependent, will be set later
00625 vdatas[i].readCounts[0] = 1;
00626
00627 // Next: lev
00628 vdatas[i].readStarts[1] = 0;
00629 vdatas[i].readCounts[1] = vdatas[i].numLev;
00630
00631 // Finally: ncol
00632 switch( vdatas[i].entLoc )
00633 {
00634 case ReadNC::ENTLOCVERT:
00635 // Vertices
00636 // Start from the first localGidVerts
00637 // Actually, this will be reset later on in a loop
00638 vdatas[i].readStarts[2] = localGidVerts[0] - 1;
00639 vdatas[i].readCounts[2] = nLocalVertices;
00640 range = &verts;
00641 break;
00642 default:
00643 MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << vdatas[i].varName );
00644 }
00645
00646 // Get variable size
00647 vdatas[i].sz = 1;
00648 for( std::size_t idx = 0; idx != 3; idx++ )
00649 vdatas[i].sz *= vdatas[i].readCounts[idx];
00650
00651 for( unsigned int t = 0; t < tstep_nums.size(); t++ )
00652 {
00653 dbgOut.tprintf( 2, "Reading variable %s, time step %d\n", vdatas[i].varName.c_str(), tstep_nums[t] );
00654
00655 if( tstep_nums[t] >= dimLens[tDim] )
00656 {
00657 MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number " << tstep_nums[t] );
00658 }
00659
00660 // Get the tag to read into
00661 if( !vdatas[i].varTags[t] )
00662 {
00663 rval = get_tag_to_nonset( vdatas[i], tstep_nums[t], vdatas[i].varTags[t], vdatas[i].numLev );MB_CHK_SET_ERR( rval, "Trouble getting tag for variable " << vdatas[i].varName );
00664 }
00665
00666 // Get ptr to tag space
00667 void* data;
00668 int count;
00669 rval = mbImpl->tag_iterate( vdatas[i].varTags[t], range->begin(), range->end(), count, data );MB_CHK_SET_ERR( rval, "Failed to iterate tag for variable " << vdatas[i].varName );
00670 assert( (unsigned)count == range->size() );
00671 vdatas[i].varDatas[t] = data;
00672 }
00673 }
00674
00675 return rval;
00676 }
00677
00678 #ifdef MOAB_HAVE_PNETCDF
00679 ErrorCode NCHelperHOMME::read_ucd_variables_to_nonset_async( std::vector< ReadNC::VarData >& vdatas,
00680 std::vector< int >& tstep_nums )
00681 {
00682 DebugOutput& dbgOut = _readNC->dbgOut;
00683
00684 ErrorCode rval = read_ucd_variables_to_nonset_allocate( vdatas, tstep_nums );MB_CHK_SET_ERR( rval, "Trouble allocating space to read non-set variables" );
00685
00686 // Finally, read into that space
00687 int success;
00688
00689 for( unsigned int i = 0; i < vdatas.size(); i++ )
00690 {
00691 std::size_t sz = vdatas[i].sz;
00692
00693 // A typical supported variable: float T(time, lev, ncol)
00694 // For tag values, need transpose (lev, ncol) to (ncol, lev)
00695 size_t ni = vdatas[i].readCounts[2]; // ncol
00696 size_t nj = 1; // Here we should just set nj to 1
00697 size_t nk = vdatas[i].readCounts[1]; // lev
00698
00699 for( unsigned int t = 0; t < tstep_nums.size(); t++ )
00700 {
00701 // We will synchronize all these reads with the other processors,
00702 // so the wait will be inside this double loop; is it too much?
00703 size_t nb_reads = localGidVerts.psize();
00704 std::vector< int > requests( nb_reads ), statuss( nb_reads );
00705 size_t idxReq = 0;
00706
00707 // Tag data for this timestep
00708 void* data = vdatas[i].varDatas[t];
00709
00710 // Set readStart for each timestep along time dimension
00711 vdatas[i].readStarts[0] = tstep_nums[t];
00712
00713 switch( vdatas[i].varDataType )
00714 {
00715 case NC_FLOAT:
00716 case NC_DOUBLE: {
00717 // Read float as double
00718 std::vector< double > tmpdoubledata( sz );
00719
00720 // In the case of ucd mesh, and on multiple proc,
00721 // we need to read as many times as subranges we have in the
00722 // localGidVerts range;
00723 // basically, we have to give a different point
00724 // for data to start, for every subrange :(
00725 size_t indexInDoubleArray = 0;
00726 size_t ic = 0;
00727 for( Range::pair_iterator pair_iter = localGidVerts.pair_begin();
00728 pair_iter != localGidVerts.pair_end(); ++pair_iter, ic++ )
00729 {
00730 EntityHandle starth = pair_iter->first;
00731 EntityHandle endh = pair_iter->second; // Inclusive
00732 vdatas[i].readStarts[2] = (NCDF_SIZE)( starth - 1 );
00733 vdatas[i].readCounts[2] = (NCDF_SIZE)( endh - starth + 1 );
00734
00735 // Do a partial read, in each subrange
00736 // Wait outside this loop
00737 success =
00738 NCFUNCREQG( _vara_double )( _fileId, vdatas[i].varId, &( vdatas[i].readStarts[0] ),
00739 &( vdatas[i].readCounts[0] ),
00740 &( tmpdoubledata[indexInDoubleArray] ), &requests[idxReq++] );
00741 if( success )
00742 MB_SET_ERR( MB_FAILURE,
00743 "Failed to read double data in a loop for variable " << vdatas[i].varName );
00744 // We need to increment the index in double array for the
00745 // next subrange
00746 indexInDoubleArray += ( endh - starth + 1 ) * 1 * vdatas[i].numLev;
00747 }
00748 assert( ic == localGidVerts.psize() );
00749
00750 success = ncmpi_wait_all( _fileId, requests.size(), &requests[0], &statuss[0] );
00751 if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
00752
00753 if( vdatas[i].numLev > 1 )
00754 // Transpose (lev, ncol) to (ncol, lev)
00755 kji_to_jik_stride( ni, nj, nk, data, &tmpdoubledata[0], localGidVerts );
00756 else
00757 {
00758 for( std::size_t idx = 0; idx != tmpdoubledata.size(); idx++ )
00759 ( (double*)data )[idx] = tmpdoubledata[idx];
00760 }
00761
00762 break;
00763 }
00764 default:
00765 MB_SET_ERR( MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName );
00766 }
00767 }
00768 }
00769
00770 // Debug output, if requested
00771 if( 1 == dbgOut.get_verbosity() )
00772 {
00773 dbgOut.printf( 1, "Read variables: %s", vdatas.begin()->varName.c_str() );
00774 for( unsigned int i = 1; i < vdatas.size(); i++ )
00775 dbgOut.printf( 1, ", %s ", vdatas[i].varName.c_str() );
00776 dbgOut.tprintf( 1, "\n" );
00777 }
00778
00779 return rval;
00780 }
00781 #else
00782 ErrorCode NCHelperHOMME::read_ucd_variables_to_nonset( std::vector< ReadNC::VarData >& vdatas,
00783 std::vector< int >& tstep_nums )
00784 {
00785 DebugOutput& dbgOut = _readNC->dbgOut;
00786
00787 ErrorCode rval = read_ucd_variables_to_nonset_allocate( vdatas, tstep_nums );MB_CHK_SET_ERR( rval, "Trouble allocating space to read non-set variables" );
00788
00789 // Finally, read into that space
00790 int success;
00791 for( unsigned int i = 0; i < vdatas.size(); i++ )
00792 {
00793 std::size_t sz = vdatas[i].sz;
00794
00795 // A typical supported variable: float T(time, lev, ncol)
00796 // For tag values, need transpose (lev, ncol) to (ncol, lev)
00797 size_t ni = vdatas[i].readCounts[2]; // ncol
00798 size_t nj = 1; // Here we should just set nj to 1
00799 size_t nk = vdatas[i].readCounts[1]; // lev
00800
00801 for( unsigned int t = 0; t < tstep_nums.size(); t++ )
00802 {
00803 // Tag data for this timestep
00804 void* data = vdatas[i].varDatas[t];
00805
00806 // Set readStart for each timestep along time dimension
00807 vdatas[i].readStarts[0] = tstep_nums[t];
00808
00809 switch( vdatas[i].varDataType )
00810 {
00811 case NC_FLOAT:
00812 case NC_DOUBLE: {
00813 // Read float as double
00814 std::vector< double > tmpdoubledata( sz );
00815
00816 // In the case of ucd mesh, and on multiple proc,
00817 // we need to read as many times as subranges we have in the
00818 // localGidVerts range;
00819 // basically, we have to give a different point
00820 // for data to start, for every subrange :(
00821 size_t indexInDoubleArray = 0;
00822 size_t ic = 0;
00823 for( Range::pair_iterator pair_iter = localGidVerts.pair_begin();
00824 pair_iter != localGidVerts.pair_end(); ++pair_iter, ic++ )
00825 {
00826 EntityHandle starth = pair_iter->first;
00827 EntityHandle endh = pair_iter->second; // Inclusive
00828 vdatas[i].readStarts[2] = (NCDF_SIZE)( starth - 1 );
00829 vdatas[i].readCounts[2] = (NCDF_SIZE)( endh - starth + 1 );
00830
00831 success = NCFUNCAG( _vara_double )( _fileId, vdatas[i].varId, &( vdatas[i].readStarts[0] ),
00832 &( vdatas[i].readCounts[0] ),
00833 &( tmpdoubledata[indexInDoubleArray] ) );
00834 if( success )
00835 MB_SET_ERR( MB_FAILURE,
00836 "Failed to read double data in a loop for variable " << vdatas[i].varName );
00837 // We need to increment the index in double array for the
00838 // next subrange
00839 indexInDoubleArray += ( endh - starth + 1 ) * 1 * vdatas[i].numLev;
00840 }
00841 assert( ic == localGidVerts.psize() );
00842
00843 if( vdatas[i].numLev > 1 )
00844 // Transpose (lev, ncol) to (ncol, lev)
00845 kji_to_jik_stride( ni, nj, nk, data, &tmpdoubledata[0], localGidVerts );
00846 else
00847 {
00848 for( std::size_t idx = 0; idx != tmpdoubledata.size(); idx++ )
00849 ( (double*)data )[idx] = tmpdoubledata[idx];
00850 }
00851
00852 break;
00853 }
00854 default:
00855 MB_SET_ERR( MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName );
00856 }
00857 }
00858 }
00859
00860 // Debug output, if requested
00861 if( 1 == dbgOut.get_verbosity() )
00862 {
00863 dbgOut.printf( 1, "Read variables: %s", vdatas.begin()->varName.c_str() );
00864 for( unsigned int i = 1; i < vdatas.size(); i++ )
00865 dbgOut.printf( 1, ", %s ", vdatas[i].varName.c_str() );
00866 dbgOut.tprintf( 1, "\n" );
00867 }
00868
00869 return rval;
00870 }
00871 #endif
00872
00873 } // namespace moab