![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /*
00002 * NCWriteMPAS.cpp
00003 *
00004 * Created on: April 9, 2014
00005 */
00006
00007 #include "NCWriteMPAS.hpp"
00008 #include "MBTagConventions.hpp"
00009
00010 namespace moab
00011 {
00012
00013 NCWriteMPAS::~NCWriteMPAS()
00014 {
00015 // TODO Auto-generated destructor stub
00016 }
00017
00018 ErrorCode NCWriteMPAS::collect_mesh_info()
00019 {
00020 Interface*& mbImpl = _writeNC->mbImpl;
00021 std::vector< std::string >& dimNames = _writeNC->dimNames;
00022 std::vector< int >& dimLens = _writeNC->dimLens;
00023 Tag& mGlobalIdTag = _writeNC->mGlobalIdTag;
00024
00025 ErrorCode rval;
00026
00027 // Look for time dimension
00028 std::vector< std::string >::iterator vecIt;
00029 if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "Time" ) ) != dimNames.end() )
00030 tDim = vecIt - dimNames.begin();
00031 else if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "time" ) ) != dimNames.end() )
00032 tDim = vecIt - dimNames.begin();
00033 else
00034 {
00035 MB_SET_ERR( MB_FAILURE, "Couldn't find 'Time' or 'time' dimension" );
00036 }
00037 nTimeSteps = dimLens[tDim];
00038
00039 // Get number of levels
00040 if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nVertLevels" ) ) != dimNames.end() )
00041 levDim = vecIt - dimNames.begin();
00042 else
00043 {
00044 MB_SET_ERR( MB_FAILURE, "Couldn't find 'nVertLevels' dimension" );
00045 }
00046 nLevels = dimLens[levDim];
00047
00048 // Get local vertices
00049 rval = mbImpl->get_entities_by_dimension( _fileSet, 0, localVertsOwned );MB_CHK_SET_ERR( rval, "Trouble getting local vertices in current file set" );
00050 assert( !localVertsOwned.empty() );
00051
00052 // Get local edges
00053 rval = mbImpl->get_entities_by_dimension( _fileSet, 1, localEdgesOwned );MB_CHK_SET_ERR( rval, "Trouble getting local edges in current file set" );
00054 // There are no edges if NO_EDGES read option is set
00055
00056 // Get local cells
00057 rval = mbImpl->get_entities_by_dimension( _fileSet, 2, localCellsOwned );MB_CHK_SET_ERR( rval, "Trouble getting local cells in current file set" );
00058 assert( !localCellsOwned.empty() );
00059
00060 #ifdef MOAB_HAVE_MPI
00061 bool& isParallel = _writeNC->isParallel;
00062 if( isParallel )
00063 {
00064 ParallelComm*& myPcomm = _writeNC->myPcomm;
00065 int rank = myPcomm->proc_config().proc_rank();
00066 int procs = myPcomm->proc_config().proc_size();
00067 if( procs > 1 )
00068 {
00069 #ifndef NDEBUG
00070 unsigned int num_local_verts = localVertsOwned.size();
00071 #endif
00072 rval = myPcomm->filter_pstatus( localVertsOwned, PSTATUS_NOT_OWNED, PSTATUS_NOT );MB_CHK_SET_ERR( rval, "Trouble getting owned vertices in current file set" );
00073
00074 // Assume that PARALLEL_RESOLVE_SHARED_ENTS option is set
00075 // Verify that not all local vertices are owned by the last processor
00076 if( procs - 1 == rank )
00077 assert( "PARALLEL_RESOLVE_SHARED_ENTS option is set" && localVertsOwned.size() < num_local_verts );
00078
00079 if( !localEdgesOwned.empty() )
00080 {
00081 rval = myPcomm->filter_pstatus( localEdgesOwned, PSTATUS_NOT_OWNED, PSTATUS_NOT );MB_CHK_SET_ERR( rval, "Trouble getting owned edges in current file set" );
00082 }
00083
00084 rval = myPcomm->filter_pstatus( localCellsOwned, PSTATUS_NOT_OWNED, PSTATUS_NOT );MB_CHK_SET_ERR( rval, "Trouble getting owned cells in current file set" );
00085 }
00086 }
00087 #endif
00088
00089 std::vector< int > gids( localVertsOwned.size() );
00090 rval = mbImpl->tag_get_data( mGlobalIdTag, localVertsOwned, &gids[0] );MB_CHK_SET_ERR( rval, "Trouble getting global IDs on local vertices" );
00091
00092 // Get localGidVertsOwned
00093 std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidVertsOwned ) );
00094
00095 if( !localEdgesOwned.empty() )
00096 {
00097 gids.resize( localEdgesOwned.size() );
00098 rval = mbImpl->tag_get_data( mGlobalIdTag, localEdgesOwned, &gids[0] );MB_CHK_SET_ERR( rval, "Trouble getting global IDs on local edges" );
00099
00100 // Get localGidEdgesOwned
00101 std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidEdgesOwned ) );
00102 }
00103
00104 gids.resize( localCellsOwned.size() );
00105 rval = mbImpl->tag_get_data( mGlobalIdTag, localCellsOwned, &gids[0] );MB_CHK_SET_ERR( rval, "Trouble getting global IDs on local cells" );
00106
00107 // Get localGidCellsOwned
00108 std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidCellsOwned ) );
00109
00110 return MB_SUCCESS;
00111 }
00112
00113 ErrorCode NCWriteMPAS::collect_variable_data( std::vector< std::string >& var_names, std::vector< int >& tstep_nums )
00114 {
00115 NCWriteHelper::collect_variable_data( var_names, tstep_nums );
00116
00117 std::vector< std::string >& dimNames = _writeNC->dimNames;
00118 std::vector< int >& dimLens = _writeNC->dimLens;
00119
00120 // Dimension indices for other optional levels
00121 std::vector< unsigned int > opt_lev_dims;
00122
00123 unsigned int lev_idx;
00124 std::vector< std::string >::iterator vecIt;
00125
00126 // Get index of vertex levels P1
00127 if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nVertLevelsP1" ) ) != dimNames.end() )
00128 {
00129 lev_idx = vecIt - dimNames.begin();
00130 opt_lev_dims.push_back( lev_idx );
00131 }
00132
00133 // Get index of vertex levels P2
00134 if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nVertLevelsP2" ) ) != dimNames.end() )
00135 {
00136 lev_idx = vecIt - dimNames.begin();
00137 opt_lev_dims.push_back( lev_idx );
00138 }
00139
00140 // Get index of soil levels
00141 if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nSoilLevels" ) ) != dimNames.end() )
00142 {
00143 lev_idx = vecIt - dimNames.begin();
00144 opt_lev_dims.push_back( lev_idx );
00145 }
00146
00147 std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
00148
00149 for( size_t i = 0; i < var_names.size(); i++ )
00150 {
00151 std::string varname = var_names[i];
00152 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname );
00153 if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname );
00154
00155 WriteNC::VarData& currentVarData = vit->second;
00156 std::vector< int >& varDims = currentVarData.varDims;
00157
00158 // Skip edge variables, if there are no edges
00159 if( localEdgesOwned.empty() && currentVarData.entLoc == WriteNC::ENTLOCEDGE ) continue;
00160
00161 // If nVertLevels dimension is not found, try other optional levels such as nVertLevelsP1
00162 if( std::find( varDims.begin(), varDims.end(), levDim ) == varDims.end() )
00163 {
00164 for( unsigned int j = 0; j < opt_lev_dims.size(); j++ )
00165 {
00166 if( std::find( varDims.begin(), varDims.end(), opt_lev_dims[j] ) != varDims.end() )
00167 {
00168 currentVarData.numLev = dimLens[opt_lev_dims[j]];
00169 break;
00170 }
00171 }
00172 }
00173
00174 // Skip set variables, which were already processed in
00175 // NCWriteHelper::collect_variable_data()
00176 if( WriteNC::ENTLOCSET == currentVarData.entLoc ) continue;
00177
00178 // Set up writeStarts and writeCounts (maximum number of dimensions is 3)
00179 currentVarData.writeStarts.resize( 3 );
00180 currentVarData.writeCounts.resize( 3 );
00181 unsigned int dim_idx = 0;
00182
00183 // First: Time
00184 if( currentVarData.has_tsteps )
00185 {
00186 // Non-set variables with timesteps
00187 // 3 dimensions like (Time, nCells, nVertLevels)
00188 // 2 dimensions like (Time, nCells)
00189 assert( 3 == varDims.size() || 2 == varDims.size() );
00190
00191 // Time should be the first dimension
00192 assert( tDim == varDims[0] );
00193
00194 currentVarData.writeStarts[dim_idx] = 0; // This value is timestep dependent, will be set later
00195 currentVarData.writeCounts[dim_idx] = 1;
00196 dim_idx++;
00197 }
00198 else
00199 {
00200 // Non-set variables without timesteps
00201 // 2 dimensions like (nCells, nVertLevels)
00202 // 1 dimension like (nCells)
00203 assert( 2 == varDims.size() || 1 == varDims.size() );
00204 }
00205
00206 // Next: nVertices / nCells / nEdges
00207 switch( currentVarData.entLoc )
00208 {
00209 case WriteNC::ENTLOCVERT:
00210 // Vertices
00211 // Start from the first localGidVerts
00212 // Actually, this will be reset later for writing
00213 currentVarData.writeStarts[dim_idx] = localGidVertsOwned[0] - 1;
00214 currentVarData.writeCounts[dim_idx] = localGidVertsOwned.size();
00215 break;
00216 case WriteNC::ENTLOCFACE:
00217 // Faces
00218 // Start from the first localGidCells
00219 // Actually, this will be reset later for writing
00220 currentVarData.writeStarts[dim_idx] = localGidCellsOwned[0] - 1;
00221 currentVarData.writeCounts[dim_idx] = localGidCellsOwned.size();
00222 break;
00223 case WriteNC::ENTLOCEDGE:
00224 // Edges
00225 // Start from the first localGidEdges
00226 // Actually, this will be reset later for writing
00227 currentVarData.writeStarts[dim_idx] = localGidEdgesOwned[0] - 1;
00228 currentVarData.writeCounts[dim_idx] = localGidEdgesOwned.size();
00229 break;
00230 default:
00231 MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << varname );
00232 }
00233 dim_idx++;
00234
00235 // Finally: nVertLevels or other optional levels, it is possible that there is no
00236 // level dimension (numLev is 0) for this non-set variable, e.g. (Time, nCells)
00237 if( currentVarData.numLev > 0 )
00238 {
00239 // Non-set variables with levels
00240 // 3 dimensions like (Time, nCells, nVertLevels)
00241 // 2 dimensions like (nCells, nVertLevels)
00242 assert( 3 == varDims.size() || 2 == varDims.size() );
00243
00244 currentVarData.writeStarts[dim_idx] = 0;
00245 currentVarData.writeCounts[dim_idx] = currentVarData.numLev;
00246 dim_idx++;
00247 }
00248 else
00249 {
00250 // Non-set variables without levels
00251 // 2 dimensions like (Time, nCells)
00252 // 1 dimension like (nCells)
00253 assert( 2 == varDims.size() || 1 == varDims.size() );
00254 }
00255
00256 // Get variable size
00257 currentVarData.sz = 1;
00258 for( std::size_t idx = 0; idx < dim_idx; idx++ )
00259 currentVarData.sz *= currentVarData.writeCounts[idx];
00260 }
00261
00262 return MB_SUCCESS;
00263 }
00264
00265 ErrorCode NCWriteMPAS::write_nonset_variables( std::vector< WriteNC::VarData >& vdatas, std::vector< int >& tstep_nums )
00266 {
00267 Interface*& mbImpl = _writeNC->mbImpl;
00268
00269 int success;
00270
00271 // For each variable tag in the indexed lists, write a time step data
00272 for( unsigned int i = 0; i < vdatas.size(); i++ )
00273 {
00274 WriteNC::VarData& variableData = vdatas[i];
00275
00276 // Skip edge variables, if there are no edges
00277 if( localEdgesOwned.empty() && variableData.entLoc == WriteNC::ENTLOCEDGE ) continue;
00278
00279 // Get local owned entities of this variable
00280 Range* pLocalEntsOwned = NULL;
00281 Range* pLocalGidEntsOwned = NULL;
00282 switch( variableData.entLoc )
00283 {
00284 case WriteNC::ENTLOCVERT:
00285 // Vertices
00286 pLocalEntsOwned = &localVertsOwned;
00287 pLocalGidEntsOwned = &localGidVertsOwned;
00288 break;
00289 case WriteNC::ENTLOCEDGE:
00290 // Edges
00291 pLocalEntsOwned = &localEdgesOwned;
00292 pLocalGidEntsOwned = &localGidEdgesOwned;
00293 break;
00294 case WriteNC::ENTLOCFACE:
00295 // Cells
00296 pLocalEntsOwned = &localCellsOwned;
00297 pLocalGidEntsOwned = &localGidCellsOwned;
00298 break;
00299 default:
00300 MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << variableData.varName );
00301 }
00302
00303 unsigned int num_timesteps;
00304 unsigned int ents_idx = 0;
00305 if( variableData.has_tsteps )
00306 {
00307 // Non-set variables with timesteps
00308 // 3 dimensions like (Time, nCells, nVertLevels)
00309 // 2 dimensions like (Time, nCells)
00310 num_timesteps = tstep_nums.size();
00311 ents_idx++;
00312 }
00313 else
00314 {
00315 // Non-set variables without timesteps
00316 // 2 dimensions like (nCells, nVertLevels)
00317 // 1 dimension like (nCells)
00318 num_timesteps = 1;
00319 }
00320
00321 unsigned int num_lev;
00322 if( variableData.numLev > 0 )
00323 {
00324 // Non-set variables with levels
00325 // 3 dimensions like (Time, nCells, nVertLevels)
00326 // 2 dimensions like (nCells, nVertLevels)
00327 num_lev = variableData.numLev;
00328 }
00329 else
00330 {
00331 // Non-set variables without levels
00332 // 2 dimensions like (Time, nCells)
00333 // 1 dimension like (nCells)
00334 num_lev = 1;
00335 }
00336
00337 for( unsigned int t = 0; t < num_timesteps; t++ )
00338 {
00339 // We will write one time step, and count will be one; start will be different
00340 // Use tag_get_data instead of tag_iterate to copy tag data, as localEntsOwned
00341 // might not be contiguous.
00342 if( tDim == variableData.varDims[0] ) variableData.writeStarts[0] = t; // This is start for time
00343 std::vector< double > tag_data( pLocalEntsOwned->size() * num_lev );
00344 ErrorCode rval = mbImpl->tag_get_data( variableData.varTags[t], *pLocalEntsOwned, &tag_data[0] );MB_CHK_SET_ERR( rval, "Trouble getting tag data on owned entities" );
00345
00346 #ifdef MOAB_HAVE_PNETCDF
00347 size_t nb_writes = pLocalGidEntsOwned->psize();
00348 std::vector< int > requests( nb_writes ), statuss( nb_writes );
00349 size_t idxReq = 0;
00350 #endif
00351
00352 // Now write copied tag data
00353 // Use nonblocking put (request aggregation)
00354 switch( variableData.varDataType )
00355 {
00356 case NC_DOUBLE: {
00357 size_t indexInDoubleArray = 0;
00358 size_t ic = 0;
00359 for( Range::pair_iterator pair_iter = pLocalGidEntsOwned->pair_begin();
00360 pair_iter != pLocalGidEntsOwned->pair_end(); ++pair_iter, ic++ )
00361 {
00362 EntityHandle starth = pair_iter->first;
00363 EntityHandle endh = pair_iter->second;
00364 variableData.writeStarts[ents_idx] = (NCDF_SIZE)( starth - 1 );
00365 variableData.writeCounts[ents_idx] = (NCDF_SIZE)( endh - starth + 1 );
00366
00367 // Do a partial write, in each subrange
00368 #ifdef MOAB_HAVE_PNETCDF
00369 // Wait outside this loop
00370 success =
00371 NCFUNCREQP( _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
00372 &( variableData.writeCounts[0] ),
00373 &( tag_data[indexInDoubleArray] ), &requests[idxReq++] );
00374 #else
00375 success = NCFUNCAP(
00376 _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
00377 &( variableData.writeCounts[0] ), &( tag_data[indexInDoubleArray] ) );
00378 #endif
00379 if( success )
00380 MB_SET_ERR( MB_FAILURE,
00381 "Failed to write double data in a loop for variable " << variableData.varName );
00382 // We need to increment the index in double array for the
00383 // next subrange
00384 indexInDoubleArray += ( endh - starth + 1 ) * num_lev;
00385 }
00386 assert( ic == pLocalGidEntsOwned->psize() );
00387 #ifdef MOAB_HAVE_PNETCDF
00388 success = ncmpi_wait_all( _fileId, requests.size(), &requests[0], &statuss[0] );
00389 if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
00390 #endif
00391 break;
00392 }
00393 default:
00394 MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double data is not implemented yet" );
00395 }
00396 }
00397 }
00398
00399 return MB_SUCCESS;
00400 }
00401
00402 } /* namespace moab */