MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /* 00002 * NCWriteHelper.cpp 00003 * 00004 * Created on: Mar 28, 2014 00005 * Author: iulian 00006 */ 00007 00008 #include "NCWriteHelper.hpp" 00009 #include "NCWriteEuler.hpp" 00010 #include "NCWriteFV.hpp" 00011 #include "NCWriteHOMME.hpp" 00012 #include "NCWriteMPAS.hpp" 00013 #include "NCWriteGCRM.hpp" 00014 00015 #include "moab/WriteUtilIface.hpp" 00016 #include "MBTagConventions.hpp" 00017 00018 #include <sstream> 00019 00020 #ifdef WIN32 00021 #ifdef size_t 00022 #undef size_t 00023 #endif 00024 #endif 00025 00026 namespace moab 00027 { 00028 00029 //! Get appropriate helper instance for WriteNC class; based on some info in the file set 00030 NCWriteHelper* NCWriteHelper::get_nc_helper( WriteNC* writeNC, 00031 int fileId, 00032 const FileOptions& opts, 00033 EntityHandle fileSet ) 00034 { 00035 std::string& grid_type = writeNC->grid_type; 00036 if( grid_type == "CAM_EUL" ) 00037 return new( std::nothrow ) NCWriteEuler( writeNC, fileId, opts, fileSet ); 00038 else if( grid_type == "CAM_FV" ) 00039 return new( std::nothrow ) NCWriteFV( writeNC, fileId, opts, fileSet ); 00040 else if( grid_type == "CAM_SE" ) 00041 return new( std::nothrow ) NCWriteHOMME( writeNC, fileId, opts, fileSet ); 00042 else if( grid_type == "MPAS" ) 00043 return new( std::nothrow ) NCWriteMPAS( writeNC, fileId, opts, fileSet ); 00044 else if( grid_type == "GCRM" ) 00045 return new( std::nothrow ) NCWriteGCRM( writeNC, fileId, opts, fileSet ); 00046 00047 // Unknown NetCDF grid 00048 return NULL; 00049 } 00050 00051 ErrorCode NCWriteHelper::collect_variable_data( std::vector< std::string >& var_names, std::vector< int >& tstep_nums ) 00052 { 00053 Interface*& mbImpl = _writeNC->mbImpl; 00054 std::vector< std::string >& dimNames = _writeNC->dimNames; 00055 std::vector< int >& dimLens = _writeNC->dimLens; 00056 std::set< std::string >& usedCoordinates = _writeNC->usedCoordinates; 00057 std::set< std::string >& dummyVarNames = _writeNC->dummyVarNames; 00058 std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo; 00059 DebugOutput& dbgOut = _writeNC->dbgOut; 00060 00061 ErrorCode rval; 00062 00063 usedCoordinates.clear(); 00064 00065 if( tstep_nums.empty() && nTimeSteps > 0 ) 00066 { 00067 // No timesteps input, get them all 00068 for( int i = 0; i < nTimeSteps; i++ ) 00069 tstep_nums.push_back( i ); 00070 } 00071 00072 for( size_t i = 0; i < var_names.size(); i++ ) 00073 { 00074 std::string varname = var_names[i]; 00075 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname ); 00076 if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname ); 00077 00078 WriteNC::VarData& currentVarData = vit->second; 00079 00080 dbgOut.tprintf( 2, " for variable %s varDims.size %d \n", varname.c_str(), 00081 (int)currentVarData.varDims.size() ); 00082 for( size_t j = 0; j < currentVarData.varDims.size(); j++ ) 00083 { 00084 std::string dimName = dimNames[currentVarData.varDims[j]]; 00085 vit = varInfo.find( dimName ); 00086 if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << dimName ); 00087 00088 usedCoordinates.insert( dimName ); // Collect those used, we will need to write them to the file 00089 dbgOut.tprintf( 2, " for variable %s need dimension %s with length %d\n", varname.c_str(), 00090 dimName.c_str(), dimLens[currentVarData.varDims[j]] ); 00091 } 00092 00093 // Process coordinate variables later 00094 if( usedCoordinates.find( varname ) != usedCoordinates.end() ) continue; 00095 00096 // Default has_tsteps is false 00097 if( std::find( currentVarData.varDims.begin(), currentVarData.varDims.end(), tDim ) != 00098 currentVarData.varDims.end() ) 00099 currentVarData.has_tsteps = true; 00100 00101 // Default numLev is 0 00102 if( ( std::find( currentVarData.varDims.begin(), currentVarData.varDims.end(), levDim ) != 00103 currentVarData.varDims.end() ) ) 00104 currentVarData.numLev = nLevels; 00105 00106 // Process set variables 00107 if( WriteNC::ENTLOCSET == currentVarData.entLoc ) 00108 { 00109 if( currentVarData.has_tsteps ) 00110 { 00111 // Set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen) 00112 // TBD 00113 MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing set variables with timesteps is not implemented yet" ); 00114 } 00115 else 00116 { 00117 // Get the tag with varname 00118 Tag tag = 0; 00119 rval = mbImpl->tag_get_handle( varname.c_str(), tag );MB_CHK_SET_ERR( rval, "Can't find tag " << varname ); 00120 currentVarData.varTags.push_back( tag ); // Really, only one for these 00121 const void* data; 00122 int size; 00123 rval = mbImpl->tag_get_by_ptr( tag, &_fileSet, 1, &data, &size );MB_CHK_SET_ERR( rval, "Can't get data of tag " << varname ); 00124 00125 // Find the type of tag, and use it 00126 DataType type; 00127 rval = mbImpl->tag_get_data_type( tag, type );MB_CHK_SET_ERR( rval, "Can't get data type of tag " << varname ); 00128 00129 currentVarData.varDataType = NC_DOUBLE; 00130 if( MB_TYPE_INTEGER == type ) currentVarData.varDataType = NC_INT; 00131 00132 assert( 0 == currentVarData.memoryHogs.size() ); // Nothing so far 00133 currentVarData.memoryHogs.push_back( (void*)data ); 00134 00135 if( currentVarData.varDims.empty() ) 00136 { 00137 // Scalar variable 00138 currentVarData.writeStarts.push_back( 0 ); 00139 currentVarData.writeCounts.push_back( 1 ); 00140 } 00141 else 00142 { 00143 for( size_t j = 0; j < currentVarData.varDims.size(); j++ ) 00144 { 00145 currentVarData.writeStarts.push_back( 0 ); 00146 currentVarData.writeCounts.push_back( dimLens[currentVarData.varDims[j]] ); 00147 } 00148 } 00149 00150 // Get variable size 00151 currentVarData.sz = 1; 00152 for( std::size_t idx = 0; idx != currentVarData.writeCounts.size(); idx++ ) 00153 currentVarData.sz *= currentVarData.writeCounts[idx]; 00154 } 00155 } // if (WriteNC::ENTLOCSET == currentVarData.entLoc) 00156 // Process non-set variables 00157 else 00158 { 00159 Tag indexedTag = 0; 00160 00161 if( currentVarData.has_tsteps ) 00162 { 00163 for( unsigned int t = 0; t < tstep_nums.size(); t++ ) 00164 { 00165 std::stringstream ssTagNameWithIndex; 00166 ssTagNameWithIndex << varname << tstep_nums[t]; 00167 rval = mbImpl->tag_get_handle( ssTagNameWithIndex.str().c_str(), indexedTag );MB_CHK_SET_ERR( rval, "Can't find tag " << ssTagNameWithIndex.str() ); 00168 dbgOut.tprintf( 2, " found indexed tag %d with name %s\n", tstep_nums[t], 00169 ssTagNameWithIndex.str().c_str() ); 00170 currentVarData.varTags.push_back( indexedTag ); 00171 } 00172 } 00173 else 00174 { 00175 // This should be a user-created non-set variable without timesteps 00176 // Treat it like having one, 0th, timestep 00177 std::stringstream ssTagNameWithIndex; 00178 ssTagNameWithIndex << varname << 0; 00179 rval = mbImpl->tag_get_handle( ssTagNameWithIndex.str().c_str(), indexedTag );MB_CHK_SET_ERR( rval, "Can't find tag " << ssTagNameWithIndex.str() << " for a user-created variable" ); 00180 dbgOut.tprintf( 2, " found indexed tag 0 with name %s\n", ssTagNameWithIndex.str().c_str() ); 00181 currentVarData.varTags.push_back( indexedTag ); 00182 } 00183 00184 // The type of the tag is fixed though 00185 DataType type; 00186 rval = mbImpl->tag_get_data_type( indexedTag, type );MB_CHK_SET_ERR( rval, "Can't get data type of tag " << varname ); 00187 00188 currentVarData.varDataType = NC_DOUBLE; 00189 if( MB_TYPE_INTEGER == type ) currentVarData.varDataType = NC_INT; 00190 } 00191 } // for (size_t i = 0; i < var_names.size(); i++) 00192 00193 // Process coordinate variables here 00194 // Check that for used coordinates we have found the tags 00195 for( std::set< std::string >::iterator setIt = usedCoordinates.begin(); setIt != usedCoordinates.end(); ++setIt ) 00196 { 00197 const std::string& coordName = *setIt; 00198 00199 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( coordName ); 00200 if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << coordName ); 00201 00202 WriteNC::VarData& varCoordData = vit->second; 00203 Tag coordTag = 0; 00204 rval = mbImpl->tag_get_handle( coordName.c_str(), coordTag );MB_CHK_SET_ERR( rval, "Can't find tag " << coordName ); 00205 varCoordData.varTags.push_back( coordTag ); // Really, only one for these 00206 00207 const void* data; 00208 int sizeCoordinate; 00209 rval = mbImpl->tag_get_by_ptr( coordTag, &_fileSet, 1, &data, &sizeCoordinate );MB_CHK_SET_ERR( rval, "Can't get coordinate values of " << coordName ); 00210 dbgOut.tprintf( 2, " found coordinate tag with name %s and length %d\n", coordName.c_str(), sizeCoordinate ); 00211 00212 // Find the type of tag, and use it 00213 DataType type; 00214 rval = mbImpl->tag_get_data_type( coordTag, type );MB_CHK_SET_ERR( rval, "Can't get data type of tag " << coordName ); 00215 varCoordData.varDataType = NC_DOUBLE; 00216 if( MB_TYPE_INTEGER == type ) varCoordData.varDataType = NC_INT; 00217 00218 // Get dimension length (the only dimension of this coordinate variable, with the same name) 00219 assert( 1 == varCoordData.varDims.size() ); 00220 int coordDimLen = dimLens[varCoordData.varDims[0]]; 00221 00222 if( dummyVarNames.find( coordName ) != dummyVarNames.end() ) 00223 { 00224 // For a dummy coordinate variable, the tag size is always 1 00225 // The number of coordinates should be set to dimension length, instead of 1 00226 assert( 1 == sizeCoordinate ); 00227 sizeCoordinate = coordDimLen; 00228 00229 // No variable data to write 00230 data = NULL; 00231 } 00232 else 00233 { 00234 // The number of coordinates should be exactly the same as dimension length 00235 // However, if timesteps spread across files and time tag has been updated, 00236 // sizeCoordinate will be larger 00237 if( varCoordData.varDims[0] != tDim ) assert( sizeCoordinate == coordDimLen ); 00238 } 00239 00240 // For time, the actual output size and values are determined by tstep_nums 00241 if( varCoordData.varDims[0] == tDim ) 00242 { 00243 // Does not apply to dummy time tag (e.g. 'Time' tag of MPAS), when timesteps 00244 // spread across files 00245 if( NULL != data ) assert( tstep_nums.size() > 0 && tstep_nums.size() <= (size_t)sizeCoordinate ); 00246 00247 sizeCoordinate = tstep_nums.size(); 00248 00249 if( NULL != data ) 00250 { 00251 assert( NC_DOUBLE == varCoordData.varDataType ); 00252 timeStepVals.resize( sizeCoordinate ); 00253 for( unsigned int t = 0; t < tstep_nums.size(); t++ ) 00254 timeStepVals[t] = ( (double*)data )[tstep_nums[t]]; 00255 00256 data = &timeStepVals[0]; 00257 } 00258 } 00259 00260 // This is the length 00261 varCoordData.sz = sizeCoordinate; 00262 varCoordData.writeStarts.resize( 1 ); 00263 varCoordData.writeStarts[0] = 0; 00264 varCoordData.writeCounts.resize( 1 ); 00265 varCoordData.writeCounts[0] = sizeCoordinate; 00266 00267 assert( 0 == varCoordData.memoryHogs.size() ); // Nothing so far 00268 varCoordData.memoryHogs.push_back( (void*)data ); 00269 } // for (std::set<std::string>::iterator setIt ... 00270 00271 return MB_SUCCESS; 00272 } 00273 00274 ErrorCode NCWriteHelper::init_file( std::vector< std::string >& var_names, 00275 std::vector< std::string >& desired_names, 00276 bool append ) 00277 { 00278 std::vector< std::string >& dimNames = _writeNC->dimNames; 00279 std::set< std::string >& usedCoordinates = _writeNC->usedCoordinates; 00280 std::set< std::string >& dummyVarNames = _writeNC->dummyVarNames; 00281 std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo; 00282 std::map< std::string, WriteNC::AttData >& globalAtts = _writeNC->globalAtts; 00283 DebugOutput& dbgOut = _writeNC->dbgOut; 00284 00285 int tDim_in_dimNames = tDim; 00286 int levDim_in_dimNames = levDim; 00287 00288 // If append mode, make sure we are in define mode; a simple open will not allow creation of new 00289 // variables 00290 if( append ) 00291 { 00292 int errcode = NCFUNC( redef )( _fileId ); 00293 if( errcode != NC_NOERR ) MB_SET_ERR( MB_FAILURE, "Can't open file in redefine mode" ); 00294 } 00295 00296 // First initialize all coordinates, then fill VarData for actual variables (and dimensions) 00297 // Check that for used coordinates we have found the tags 00298 for( std::set< std::string >::iterator setIt = usedCoordinates.begin(); setIt != usedCoordinates.end(); ++setIt ) 00299 { 00300 const std::string& coordName = *setIt; 00301 00302 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( coordName ); 00303 if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << coordName ); 00304 00305 WriteNC::VarData& varCoordData = vit->second; 00306 varCoordData.varDims.resize( 1 ); 00307 00308 // If not append, create it for sure 00309 // If append, we might already have it, including the tag / variable with the same name 00310 /* 00311 * int ncmpi_inq_dimid(int ncid, const char *name, int *idp); 00312 */ 00313 if( append ) 00314 { 00315 int dimId; 00316 if( NCFUNC( inq_dimid )( _fileId, coordName.c_str(), &dimId ) == NC_NOERR ) 00317 { // If not found, create it later 00318 varCoordData.varDims[0] = dimId; 00319 dbgOut.tprintf( 2, " file already has coordName %s dim id is %d \n", coordName.c_str(), 00320 (int)varCoordData.varDims[0] ); 00321 00322 // Update tDim and levDim to actual dimension id 00323 if( coordName == dimNames[tDim_in_dimNames] ) 00324 tDim = varCoordData.varDims[0]; 00325 else if( coordName == dimNames[levDim_in_dimNames] ) 00326 levDim = varCoordData.varDims[0]; 00327 00328 // Skip dummy coordinate variables (e.g. ncol) 00329 if( dummyVarNames.find( coordName ) != dummyVarNames.end() ) continue; 00330 00331 // Check that the coordinate is a variable too 00332 // Inquire for a variable with the same name 00333 int varId; 00334 if( NCFUNC( inq_varid )( _fileId, coordName.c_str(), &varId ) != NC_NOERR ) 00335 MB_SET_ERR( MB_FAILURE, "We do not have a variable with the same name " << coordName ); 00336 // We should also check that this variable has one dimension, and it is dimId 00337 varCoordData.varId = varId; 00338 dbgOut.tprintf( 2, " file already has coordinate %s and varId is %d \n", coordName.c_str(), varId ); 00339 00340 continue; // Maybe more checks are needed here 00341 } 00342 } 00343 00344 /* int nc_def_dim (int ncid, const char *name, size_t len, int *dimidp); 00345 * example: status = nc_def_dim(fileId, "lat", 18L, &latid); 00346 */ 00347 00348 // Actually define a dimension 00349 if( NCFUNC( def_dim )( _fileId, coordName.c_str(), (size_t)varCoordData.sz, &varCoordData.varDims[0] ) != 00350 NC_NOERR ) 00351 MB_SET_ERR( MB_FAILURE, "Failed to generate dimension " << coordName ); 00352 dbgOut.tprintf( 2, " for coordName %s dim id is %d \n", coordName.c_str(), (int)varCoordData.varDims[0] ); 00353 00354 // Update tDim and levDim to actual dimension id 00355 if( coordName == dimNames[tDim_in_dimNames] ) 00356 tDim = varCoordData.varDims[0]; 00357 else if( coordName == dimNames[levDim_in_dimNames] ) 00358 levDim = varCoordData.varDims[0]; 00359 00360 // Create a variable with the same name, and its only dimension the one we just defined 00361 /* 00362 * int nc_def_var (int ncid, const char *name, nc_type xtype, 00363 int ndims, const int dimids[], int *varidp); 00364 example: 00365 http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c/nc_005fdef_005fvar.html#nc_005fdef_005fvar 00366 */ 00367 00368 // Skip dummy coordinate variables (e.g. ncol) 00369 if( dummyVarNames.find( coordName ) != dummyVarNames.end() ) continue; 00370 00371 // Define a coordinate variable 00372 if( NCFUNC( def_var )( _fileId, coordName.c_str(), varCoordData.varDataType, 1, &( varCoordData.varDims[0] ), 00373 &varCoordData.varId ) != NC_NOERR ) 00374 MB_SET_ERR( MB_FAILURE, "Failed to create coordinate variable " << coordName ); 00375 00376 dbgOut.tprintf( 2, " for coordName %s variable id is %d \n", coordName.c_str(), varCoordData.varId ); 00377 } 00378 00379 // Now look at requested variables, and update from the index in dimNames to the actual 00380 // dimension id 00381 for( size_t i = 0; i < var_names.size(); i++ ) 00382 { 00383 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( var_names[i] ); 00384 if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find requested variable " << var_names[i] ); 00385 00386 // Skip coordinate variables 00387 if( usedCoordinates.find( var_names[i] ) != usedCoordinates.end() ) continue; 00388 00389 WriteNC::VarData& variableData = vit->second; 00390 00391 // The index is for dimNames; we need to find out the actual dimension id (from above) 00392 int numDims = (int)variableData.varDims.size(); 00393 for( int j = 0; j < numDims; j++ ) 00394 { 00395 std::string dimName = dimNames[variableData.varDims[j]]; 00396 std::map< std::string, WriteNC::VarData >::iterator vit2 = varInfo.find( dimName ); 00397 if( vit2 == varInfo.end() ) 00398 MB_SET_ERR( MB_FAILURE, "Can't find requested coordinate variable " << dimName ); 00399 00400 WriteNC::VarData& coordData = vit2->second; 00401 // Index in dimNames to actual dimension id 00402 variableData.varDims[j] = coordData.varDims[0]; // This one, being a coordinate, is the only one 00403 dbgOut.tprintf( 2, " dimension with index %d name %s has ID %d \n", j, dimName.c_str(), 00404 variableData.varDims[j] ); 00405 } 00406 00407 // Define the variable now: 00408 int errCode = 00409 NCFUNC( def_var )( _fileId, desired_names[i].c_str(), variableData.varDataType, 00410 (int)variableData.varDims.size(), &( variableData.varDims[0] ), &variableData.varId ); 00411 if( errCode != NC_NOERR ) MB_SET_ERR( MB_FAILURE, "Failed to create requested variable " << desired_names[i] ); 00412 00413 dbgOut.tprintf( 2, " for variable %s with desired name %s variable id is %d \n", var_names[i].c_str(), 00414 desired_names[i].c_str(), variableData.varId ); 00415 // Now define the variable, with all dimensions 00416 } 00417 00418 // Define global attributes (exactly copied from the original file for the time being) 00419 // Should we modify some of them (e.g. revision_Id) later? 00420 std::map< std::string, WriteNC::AttData >::iterator attIt; 00421 for( attIt = globalAtts.begin(); attIt != globalAtts.end(); ++attIt ) 00422 { 00423 const std::string& attName = attIt->first; 00424 WriteNC::AttData& attData = attIt->second; 00425 NCDF_SIZE& attLen = attData.attLen; 00426 nc_type& attDataType = attData.attDataType; 00427 const std::string& attValue = attData.attValue; 00428 00429 switch( attDataType ) 00430 { 00431 case NC_BYTE: 00432 case NC_CHAR: 00433 if( NC_NOERR != 00434 NCFUNC( put_att_text )( _fileId, NC_GLOBAL, attName.c_str(), attLen, attValue.c_str() ) ) 00435 MB_SET_ERR( MB_FAILURE, "Failed to define text type attribute" ); 00436 break; 00437 case NC_DOUBLE: 00438 if( NC_NOERR != NCFUNC( put_att_double )( _fileId, NC_GLOBAL, attName.c_str(), NC_DOUBLE, 1, 00439 (double*)attValue.c_str() ) ) 00440 MB_SET_ERR( MB_FAILURE, "Failed to define double type attribute" ); 00441 break; 00442 case NC_FLOAT: 00443 if( NC_NOERR != NCFUNC( put_att_float )( _fileId, NC_GLOBAL, attName.c_str(), NC_FLOAT, 1, 00444 (float*)attValue.c_str() ) ) 00445 MB_SET_ERR( MB_FAILURE, "Failed to define float type attribute" ); 00446 break; 00447 case NC_INT: 00448 if( NC_NOERR != 00449 NCFUNC( put_att_int )( _fileId, NC_GLOBAL, attName.c_str(), NC_INT, 1, (int*)attValue.c_str() ) ) 00450 MB_SET_ERR( MB_FAILURE, "Failed to define int type attribute" ); 00451 break; 00452 case NC_SHORT: 00453 if( NC_NOERR != NCFUNC( put_att_short )( _fileId, NC_GLOBAL, attName.c_str(), NC_SHORT, 1, 00454 (short*)attValue.c_str() ) ) 00455 MB_SET_ERR( MB_FAILURE, "Failed to define short type attribute" ); 00456 break; 00457 default: 00458 MB_SET_ERR( MB_FAILURE, "Unknown attribute data type" ); 00459 } 00460 } 00461 00462 // Take it out of define mode 00463 if( NC_NOERR != NCFUNC( enddef )( _fileId ) ) MB_SET_ERR( MB_FAILURE, "Failed to close define mode" ); 00464 00465 return MB_SUCCESS; 00466 } 00467 00468 ErrorCode NCWriteHelper::write_values( std::vector< std::string >& var_names, std::vector< int >& tstep_nums ) 00469 { 00470 std::set< std::string >& usedCoordinates = _writeNC->usedCoordinates; 00471 std::set< std::string >& dummyVarNames = _writeNC->dummyVarNames; 00472 std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo; 00473 00474 std::vector< WriteNC::VarData > vdatas; 00475 std::vector< WriteNC::VarData > vsetdatas; 00476 00477 // For set variables, include coordinates used by requested var_names 00478 for( std::set< std::string >::iterator setIt = usedCoordinates.begin(); setIt != usedCoordinates.end(); ++setIt ) 00479 { 00480 const std::string& coordName = *setIt; 00481 00482 // Skip dummy coordinate variables (if any) 00483 if( dummyVarNames.find( coordName ) != dummyVarNames.end() ) continue; 00484 00485 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( coordName ); 00486 if( vit == varInfo.end() ) 00487 { 00488 MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << coordName ); 00489 } 00490 00491 vsetdatas.push_back( vit->second ); 00492 } 00493 00494 // Collect non-set and set variables from requested var_names 00495 for( unsigned int i = 0; i < var_names.size(); i++ ) 00496 { 00497 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( var_names[i] ); 00498 if( vit == varInfo.end() ) 00499 { 00500 MB_SET_ERR( MB_FAILURE, "Can't find requested variable " << var_names[i] ); 00501 } 00502 00503 WriteNC::VarData& variableData = vit->second; 00504 if( WriteNC::ENTLOCSET == variableData.entLoc ) 00505 { 00506 // Used coordinates has all ready been included 00507 if( usedCoordinates.find( var_names[i] ) != usedCoordinates.end() ) continue; 00508 00509 vsetdatas.push_back( variableData ); 00510 } 00511 else 00512 vdatas.push_back( variableData ); 00513 } 00514 00515 // Assume that the data ranges do not overlap across processors 00516 // While overlapped writing might still work, we should better not take that risk 00517 write_nonset_variables( vdatas, tstep_nums ); 00518 00519 // Use independent I/O mode put, since this write is only for the root processor 00520 write_set_variables( vsetdatas, tstep_nums ); 00521 00522 return MB_SUCCESS; 00523 } 00524 00525 ErrorCode NCWriteHelper::write_set_variables( std::vector< WriteNC::VarData >& vsetdatas, 00526 std::vector< int >& /* tstep_nums */ ) 00527 { 00528 int success; 00529 00530 // CAUTION: if the NetCDF ID is from a previous call to ncmpi_create rather than ncmpi_open, 00531 // all processors need to call ncmpi_begin_indep_data(). If only the root processor does so, 00532 // ncmpi_begin_indep_data() call will be blocked forever :( 00533 #ifdef MOAB_HAVE_PNETCDF 00534 // Enter independent I/O mode 00535 success = NCFUNC( begin_indep_data )( _fileId ); 00536 if( success ) MB_SET_ERR( MB_FAILURE, "Failed to begin independent I/O mode" ); 00537 #endif 00538 00539 int rank = 0; 00540 #ifdef MOAB_HAVE_MPI 00541 bool& isParallel = _writeNC->isParallel; 00542 if( isParallel ) 00543 { 00544 ParallelComm*& myPcomm = _writeNC->myPcomm; 00545 rank = myPcomm->proc_config().proc_rank(); 00546 } 00547 #endif 00548 if( 0 == rank ) 00549 { 00550 for( unsigned int i = 0; i < vsetdatas.size(); i++ ) 00551 { 00552 WriteNC::VarData& variableData = vsetdatas[i]; 00553 00554 // Set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen) 00555 if( variableData.has_tsteps ) 00556 { 00557 MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing set variables with timesteps is not implemented yet" ); 00558 } 00559 00560 switch( variableData.varDataType ) 00561 { 00562 case NC_DOUBLE: 00563 // Independent I/O mode put 00564 success = NCFUNCP( _vara_double )( _fileId, variableData.varId, &variableData.writeStarts[0], 00565 &variableData.writeCounts[0], 00566 (double*)( variableData.memoryHogs[0] ) ); 00567 if( success ) 00568 MB_SET_ERR( MB_FAILURE, "Failed to write double data for variable " << variableData.varName ); 00569 break; 00570 case NC_INT: 00571 // Independent I/O mode put 00572 success = 00573 NCFUNCP( _vara_int )( _fileId, variableData.varId, &variableData.writeStarts[0], 00574 &variableData.writeCounts[0], (int*)( variableData.memoryHogs[0] ) ); 00575 if( success ) 00576 MB_SET_ERR( MB_FAILURE, "Failed to write int data for variable " << variableData.varName ); 00577 break; 00578 default: 00579 MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double or non-int data is not implemented yet" ); 00580 } 00581 } 00582 } 00583 00584 #ifdef MOAB_HAVE_PNETCDF 00585 // End independent I/O mode 00586 success = NCFUNC( end_indep_data )( _fileId ); 00587 if( success ) MB_SET_ERR( MB_FAILURE, "Failed to end independent I/O mode" ); 00588 #endif 00589 00590 return MB_SUCCESS; 00591 } 00592 00593 ErrorCode ScdNCWriteHelper::collect_mesh_info() 00594 { 00595 Interface*& mbImpl = _writeNC->mbImpl; 00596 std::vector< std::string >& dimNames = _writeNC->dimNames; 00597 std::vector< int >& dimLens = _writeNC->dimLens; 00598 00599 ErrorCode rval; 00600 00601 // Look for time dimension 00602 std::vector< std::string >::iterator vecIt; 00603 if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "time" ) ) != dimNames.end() ) 00604 tDim = vecIt - dimNames.begin(); 00605 else if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "t" ) ) != dimNames.end() ) 00606 tDim = vecIt - dimNames.begin(); 00607 else 00608 { 00609 MB_SET_ERR( MB_FAILURE, "Couldn't find 'time' or 't' dimension" ); 00610 } 00611 nTimeSteps = dimLens[tDim]; 00612 00613 // Get number of levels 00614 if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "lev" ) ) != dimNames.end() ) 00615 levDim = vecIt - dimNames.begin(); 00616 else if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "ilev" ) ) != dimNames.end() ) 00617 levDim = vecIt - dimNames.begin(); 00618 else 00619 { 00620 MB_SET_ERR( MB_FAILURE, "Couldn't find 'lev' or 'ilev' dimension" ); 00621 } 00622 nLevels = dimLens[levDim]; 00623 00624 // __<dim_name>_LOC_MINMAX (for slon, slat, lon and lat) 00625 Tag convTag = 0; 00626 rval = mbImpl->tag_get_handle( "__slon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag __slon_LOC_MINMAX" ); 00627 int val[2]; 00628 rval = mbImpl->tag_get_data( convTag, &_fileSet, 1, val );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag __slon_LOC_MINMAX" ); 00629 lDims[0] = val[0]; 00630 lDims[3] = val[1]; 00631 00632 rval = mbImpl->tag_get_handle( "__slat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag __slat_LOC_MINMAX" ); 00633 rval = mbImpl->tag_get_data( convTag, &_fileSet, 1, val );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag __slat_LOC_MINMAX" ); 00634 lDims[1] = val[0]; 00635 lDims[4] = val[1]; 00636 00637 rval = mbImpl->tag_get_handle( "__lon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag __lon_LOC_MINMAX" ); 00638 rval = mbImpl->tag_get_data( convTag, &_fileSet, 1, val );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag __lon_LOC_MINMAX" ); 00639 lCDims[0] = val[0]; 00640 lCDims[3] = val[1]; 00641 00642 rval = mbImpl->tag_get_handle( "__lat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag __lat_LOC_MINMAX" ); 00643 rval = mbImpl->tag_get_data( convTag, &_fileSet, 1, val );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag __lat_LOC_MINMAX" ); 00644 lCDims[1] = val[0]; 00645 lCDims[4] = val[1]; 00646 00647 // Get local faces 00648 rval = mbImpl->get_entities_by_dimension( _fileSet, 2, localCellsOwned );MB_CHK_SET_ERR( rval, "Trouble getting local faces in current file set" ); 00649 assert( !localCellsOwned.empty() ); 00650 00651 #ifdef MOAB_HAVE_MPI 00652 bool& isParallel = _writeNC->isParallel; 00653 if( isParallel ) 00654 { 00655 ParallelComm*& myPcomm = _writeNC->myPcomm; 00656 int procs = myPcomm->proc_config().proc_size(); 00657 if( procs > 1 ) 00658 { 00659 rval = myPcomm->filter_pstatus( localCellsOwned, PSTATUS_NOT_OWNED, PSTATUS_NOT );MB_CHK_SET_ERR( rval, "Trouble getting owned faces in current file set" ); 00660 } 00661 } 00662 #endif 00663 00664 return MB_SUCCESS; 00665 } 00666 00667 ErrorCode ScdNCWriteHelper::collect_variable_data( std::vector< std::string >& var_names, 00668 std::vector< int >& tstep_nums ) 00669 { 00670 NCWriteHelper::collect_variable_data( var_names, tstep_nums ); 00671 00672 std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo; 00673 00674 for( size_t i = 0; i < var_names.size(); i++ ) 00675 { 00676 std::string varname = var_names[i]; 00677 std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname ); 00678 if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname ); 00679 00680 WriteNC::VarData& currentVarData = vit->second; 00681 #ifndef NDEBUG 00682 std::vector< int >& varDims = currentVarData.varDims; 00683 #endif 00684 00685 // Skip set variables, which were already processed in 00686 // NCWriteHelper::collect_variable_data() 00687 if( WriteNC::ENTLOCSET == currentVarData.entLoc ) continue; 00688 00689 // Set up writeStarts and writeCounts (maximum number of dimensions is 4) 00690 currentVarData.writeStarts.resize( 4 ); 00691 currentVarData.writeCounts.resize( 4 ); 00692 unsigned int dim_idx = 0; 00693 00694 // First: time 00695 if( currentVarData.has_tsteps ) 00696 { 00697 // Non-set variables with timesteps 00698 // 4 dimensions like (time, lev, lat, lon) 00699 // 3 dimensions like (time, lat, lon) 00700 assert( 4 == varDims.size() || 3 == varDims.size() ); 00701 00702 // Time should be the first dimension 00703 assert( tDim == varDims[0] ); 00704 00705 currentVarData.writeStarts[dim_idx] = 0; // This value is timestep dependent, will be set later 00706 currentVarData.writeCounts[dim_idx] = 1; 00707 dim_idx++; 00708 } 00709 else 00710 { 00711 // Non-set variables without timesteps 00712 // 3 dimensions like (lev, lat, lon) 00713 // 2 dimensions like (lat, lon) 00714 assert( 3 == varDims.size() || 2 == varDims.size() ); 00715 } 00716 00717 // Next: lev 00718 if( currentVarData.numLev > 0 ) 00719 { 00720 // Non-set variables with levels 00721 // 4 dimensions like (time, lev, lat, lon) 00722 // 3 dimensions like (lev, lat, lon) 00723 assert( 4 == varDims.size() || 3 == varDims.size() ); 00724 00725 currentVarData.writeStarts[dim_idx] = 0; 00726 currentVarData.writeCounts[dim_idx] = currentVarData.numLev; 00727 dim_idx++; 00728 } 00729 else 00730 { 00731 // Non-set variables without levels 00732 // 3 dimensions like (time, lat, lon) 00733 // 2 dimensions like (lat, lon) 00734 assert( 3 == varDims.size() || 2 == varDims.size() ); 00735 } 00736 00737 // Finally: lat and lon 00738 switch( currentVarData.entLoc ) 00739 { 00740 case WriteNC::ENTLOCFACE: 00741 // Faces 00742 currentVarData.writeStarts[dim_idx] = lCDims[1]; 00743 currentVarData.writeCounts[dim_idx] = lCDims[4] - lCDims[1] + 1; 00744 currentVarData.writeStarts[dim_idx + 1] = lCDims[0]; 00745 currentVarData.writeCounts[dim_idx + 1] = lCDims[3] - lCDims[0] + 1; 00746 break; 00747 default: 00748 MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << varname ); 00749 } 00750 dim_idx += 2; 00751 00752 // Get variable size 00753 currentVarData.sz = 1; 00754 for( std::size_t idx = 0; idx < dim_idx; idx++ ) 00755 currentVarData.sz *= currentVarData.writeCounts[idx]; 00756 } // for (size_t i = 0; i < var_names.size(); i++) 00757 00758 return MB_SUCCESS; 00759 } 00760 00761 // Write CAM-EUL and CAM-FV non-set variables on non-shared quads (e.g. T) 00762 // We assume that there are no variables on vertices and we do not support 00763 // variables on edges (e.g. US in CAM-FV) for the time being 00764 ErrorCode ScdNCWriteHelper::write_nonset_variables( std::vector< WriteNC::VarData >& vdatas, 00765 std::vector< int >& tstep_nums ) 00766 { 00767 Interface*& mbImpl = _writeNC->mbImpl; 00768 00769 int success; 00770 00771 // For each indexed variable tag, write a time step data 00772 for( unsigned int i = 0; i < vdatas.size(); i++ ) 00773 { 00774 WriteNC::VarData& variableData = vdatas[i]; 00775 00776 // Assume this variable is on faces for the time being 00777 switch( variableData.entLoc ) 00778 { 00779 case WriteNC::ENTLOCFACE: 00780 // Faces 00781 break; 00782 default: 00783 MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << variableData.varName ); 00784 } 00785 00786 unsigned int num_timesteps; 00787 unsigned int lat_idx = 0; 00788 unsigned int lon_idx = 1; 00789 if( variableData.has_tsteps ) 00790 { 00791 // Non-set variables with timesteps 00792 // 4 dimensions like (time, lev, lat, lon) 00793 // 3 dimensions like (time, lat, lon) 00794 num_timesteps = tstep_nums.size(); 00795 lat_idx++; 00796 lon_idx++; 00797 } 00798 else 00799 { 00800 // Non-set variables without timesteps 00801 // 3 dimensions like (lev, lat, lon) 00802 // 2 dimensions like (lat, lon) 00803 num_timesteps = 1; 00804 } 00805 00806 unsigned int num_lev; 00807 if( variableData.numLev > 0 ) 00808 { 00809 // Non-set variables with levels 00810 // 4 dimensions like (time, lev, lat, lon) 00811 // 3 dimensions like (lev, lat, lon) 00812 num_lev = variableData.numLev; 00813 lat_idx++; 00814 lon_idx++; 00815 } 00816 else 00817 { 00818 // Non-set variables without levels 00819 // 3 dimensions like (time, lat, lon) 00820 // 2 dimensions like (lat, lon) 00821 num_lev = 1; 00822 } 00823 00824 size_t ni = variableData.writeCounts[lon_idx]; // lon 00825 size_t nj = variableData.writeCounts[lat_idx]; // lat 00826 00827 // At each timestep, we need to transpose tag format (lat, lon, lev) back 00828 // to NC format (lev, lat, lon) for writing 00829 for( unsigned int t = 0; t < num_timesteps; t++ ) 00830 { 00831 // We will write one time step, and count will be one; start will be different 00832 // Use tag_iterate to get tag data (assume that localCellsOwned is contiguous) 00833 // We should also transpose for level so that means deep copy for transpose 00834 if( tDim == variableData.varDims[0] ) variableData.writeStarts[0] = t; // This is start for time 00835 int count; 00836 void* dataptr; 00837 ErrorCode rval = mbImpl->tag_iterate( variableData.varTags[t], localCellsOwned.begin(), 00838 localCellsOwned.end(), count, dataptr );MB_CHK_SET_ERR( rval, "Failed to iterate tag on owned faces" ); 00839 assert( count == (int)localCellsOwned.size() ); 00840 00841 // Now transpose and write tag data 00842 // Use collective I/O mode put (synchronous write) for the time being, we can try 00843 // nonblocking put (request aggregation) later 00844 switch( variableData.varDataType ) 00845 { 00846 case NC_DOUBLE: { 00847 std::vector< double > tmpdoubledata( ni * nj * num_lev ); 00848 if( num_lev > 1 ) 00849 // Transpose (lat, lon, lev) back to (lev, lat, lon) 00850 jik_to_kji( ni, nj, num_lev, &tmpdoubledata[0], (double*)( dataptr ) ); 00851 success = NCFUNCAP( _vara_double )( _fileId, variableData.varId, &variableData.writeStarts[0], 00852 &variableData.writeCounts[0], &tmpdoubledata[0] ); 00853 if( success ) 00854 MB_SET_ERR( MB_FAILURE, "Failed to write double data for variable " << variableData.varName ); 00855 break; 00856 } 00857 default: 00858 MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double data is not implemented yet" ); 00859 } 00860 } 00861 } 00862 00863 return MB_SUCCESS; 00864 } 00865 00866 } /* namespace moab */