1 #include "WriteNC.hpp"
2 #include "moab/CN.hpp"
3 #include "MBTagConventions.hpp"
4 #include "MBParallelConventions.h"
5 #include "moab/Interface.hpp"
6 #include "moab/Range.hpp"
7 #include "moab/WriteUtilIface.hpp"
8 #include "moab/FileOptions.hpp"
9 #include "NCWriteHelper.hpp"
10
11 #include <fstream>
12 #include <map>
13 #include <set>
14
15 #include <iostream>
16 #include <sstream>
17
18 #ifdef WIN32
19 #ifdef size_t
20 #undef size_t
21 #endif
22 #endif
23
24 namespace moab
25 {
26
27 WriterIface* WriteNC::factory( Interface* iface )
28 {
29 return new WriteNC( iface );
30 }
31
32 WriteNC::WriteNC( Interface* impl )
33 : mbImpl( impl ), dbgOut( stderr ),
34 #ifdef MOAB_HAVE_MPI
35 myPcomm( NULL ),
36 #endif
37 noMesh( false ), noVars( false ), append( false ), mGlobalIdTag( 0 ), isParallel( false ), myHelper( NULL )
38 {
39 assert( impl != NULL );
40 impl->query_interface( mWriteIface );
41 }
42
43 WriteNC::~WriteNC()
44 {
45 mbImpl->release_interface( mWriteIface );
46 if( myHelper != NULL ) delete myHelper;
47 }
48
49
50 ErrorCode WriteNC::write_file( const char* file_name,
51 const bool overwrite,
52 const FileOptions& options,
53 const EntityHandle* file_set,
54 const int num_set,
55 const std::vector< std::string >&,
56 const Tag*,
57 int,
58 int )
59 {
60 ErrorCode rval;
61
62 std::vector< std::string > var_names;
63 std::vector< std::string > desired_names;
64 std::vector< int > tstep_nums;
65 std::vector< double > tstep_vals;
66
67
68 mGlobalIdTag = mbImpl->globalId_tag();
69
70
71 if( num_set != 1 ) MB_SET_ERR( MB_FAILURE, "We should write only one set (the file set used to read data into)" );
72
73 rval = parse_options( options, var_names, desired_names, tstep_nums, tstep_vals );MB_CHK_SET_ERR( rval, "Trouble parsing option string" );
74
75
76
77
78 rval = process_conventional_tags( *file_set );MB_CHK_SET_ERR( rval, "Trouble processing conventional tags" );
79
80
81 if( append )
82 dbgOut.tprintf( 1, "opening file %s for appending \n", file_name );
83 else
84 dbgOut.tprintf( 1, "creating file %s\n", file_name );
85 fileName = file_name;
86 int success;
87
88 if( append )
89 {
90 int omode = NC_WRITE;
91 #ifdef MOAB_HAVE_PNETCDF
92 if( isParallel )
93 success = NCFUNC( open )( myPcomm->proc_config().proc_comm(), file_name, omode, MPI_INFO_NULL, &fileId );
94 else
95 success = NCFUNC( open )( MPI_COMM_SELF, file_name, omode, MPI_INFO_NULL, &fileId );
96 #else
97
98 success = NCFUNC( open )( file_name, omode, &fileId );
99 #endif
100 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble opening file " << file_name << " for appending" );
101 }
102 else
103 {
104 int cmode = overwrite ? NC_CLOBBER : NC_NOCLOBBER;
105 #ifdef MOAB_HAVE_PNETCDF
106 if( isParallel )
107 success = NCFUNC( create )( myPcomm->proc_config().proc_comm(), file_name, cmode, MPI_INFO_NULL, &fileId );
108 else
109 success = NCFUNC( create )( MPI_COMM_SELF, file_name, cmode, MPI_INFO_NULL, &fileId );
110 #else
111
112 success = NCFUNC( create )( file_name, cmode, &fileId );
113 #endif
114 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble creating file " << file_name << " for writing" );
115 }
116
117 if( NULL != myHelper ) delete myHelper;
118
119
120 myHelper = NCWriteHelper::get_nc_helper( this, fileId, options, *file_set );
121 if( NULL == myHelper )
122 {
123 MB_SET_ERR( MB_FAILURE, "Failed to get NCWriteHelper class instance" );
124 }
125
126 rval = myHelper->collect_mesh_info();MB_CHK_SET_ERR( rval, "Trouble collecting mesh information" );
127
128 rval = myHelper->collect_variable_data( var_names, tstep_nums );MB_CHK_SET_ERR( rval, "Trouble collecting variable data" );
129
130 rval = myHelper->init_file( var_names, desired_names, append );MB_CHK_SET_ERR( rval, "Trouble initializing file" );
131
132 rval = myHelper->write_values( var_names, tstep_nums );MB_CHK_SET_ERR( rval, "Trouble writing values to file" );
133
134 success = NCFUNC( close )( fileId );
135 if( success ) MB_SET_ERR( MB_FAILURE, "Trouble closing file" );
136
137 return MB_SUCCESS;
138 }
139
140 ErrorCode WriteNC::parse_options( const FileOptions& opts,
141 std::vector< std::string >& var_names,
142 std::vector< std::string >& desired_names,
143 std::vector< int >& tstep_nums,
144 std::vector< double >& tstep_vals )
145 {
146 int tmpval;
147 if( MB_SUCCESS == opts.get_int_option( "DEBUG_IO", 1, tmpval ) )
148 {
149 dbgOut.set_verbosity( tmpval );
150 dbgOut.set_prefix( "NCWrite" );
151 }
152
153 ErrorCode rval = opts.get_strs_option( "VARIABLE", var_names );
154 if( MB_TYPE_OUT_OF_RANGE == rval )
155 noVars = true;
156 else
157 noVars = false;
158
159 rval = opts.get_strs_option( "RENAME", desired_names );
160 if( MB_ENTITY_NOT_FOUND == rval )
161 {
162 if( !noVars )
163 {
164 desired_names.resize( var_names.size() );
165 std::copy( var_names.begin(), var_names.end(), desired_names.begin() );
166 }
167 }
168
169 assert( desired_names.size() == var_names.size() );
170
171 opts.get_ints_option( "TIMESTEP", tstep_nums );
172 opts.get_reals_option( "TIMEVAL", tstep_vals );
173 rval = opts.get_null_option( "NOMESH" );
174 if( MB_SUCCESS == rval ) noMesh = true;
175
176 rval = opts.get_null_option( "APPEND" );
177 if( MB_SUCCESS == rval ) append = true;
178
179 if( 2 <= dbgOut.get_verbosity() )
180 {
181 if( !var_names.empty() )
182 {
183 std::cerr << "Variables requested: ";
184 for( unsigned int i = 0; i < var_names.size(); i++ )
185 std::cerr << var_names[i];
186 std::cerr << std::endl;
187 }
188 if( !tstep_nums.empty() )
189 {
190 std::cerr << "Timesteps requested: ";
191 for( unsigned int i = 0; i < tstep_nums.size(); i++ )
192 std::cerr << tstep_nums[i];
193 std::cerr << std::endl;
194 }
195 if( !tstep_vals.empty() )
196 {
197 std::cerr << "Time vals requested: ";
198 for( unsigned int i = 0; i < tstep_vals.size(); i++ )
199 std::cerr << tstep_vals[i];
200 std::cerr << std::endl;
201 }
202 }
203
204
205 #ifdef MOAB_HAVE_MPI
206 isParallel = ( opts.match_option( "PARALLEL", "WRITE_PART" ) != MB_ENTITY_NOT_FOUND );
207
208 if( !isParallel )
209
210
211
212 return MB_SUCCESS;
213
214 int pcomm_no = 0;
215 rval = opts.get_int_option( "PARALLEL_COMM", pcomm_no );
216 if( MB_TYPE_OUT_OF_RANGE == rval )
217 {
218 MB_SET_ERR( rval, "Invalid value for PARALLEL_COMM option" );
219 }
220
221 myPcomm = ParallelComm::get_pcomm( mbImpl, pcomm_no );
222 if( 0 == myPcomm )
223 {
224 myPcomm = new ParallelComm( mbImpl, MPI_COMM_WORLD );
225 }
226
227 #ifndef MOAB_HAVE_PNETCDF
228 const int procs = myPcomm->proc_config().proc_size();
229 if( procs > 1 )
230 {
231 MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Attempt to launch NC writer in parallel without pnetcdf support" );
232 }
233 #endif
234
235 const int rank = myPcomm->proc_config().proc_rank();
236 dbgOut.set_rank( rank );
237 #endif
238
239 return MB_SUCCESS;
240 }
241
242
243
244 ErrorCode WriteNC::process_conventional_tags( EntityHandle fileSet )
245 {
246 ErrorCode rval;
247
248
249 Tag dimNamesTag = 0;
250 std::string tag_name = "__DIM_NAMES";
251 const void* data = NULL;
252 int dimNamesSz = 0;
253 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_OPAQUE, dimNamesTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
254 rval = mbImpl->tag_get_by_ptr( dimNamesTag, &fileSet, 1, &data, &dimNamesSz );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
255 const char* p = static_cast< const char* >( data );
256 dbgOut.tprintf( 1, "__DIM_NAMES tag has string length %d\n", dimNamesSz );
257
258 std::size_t start = 0;
259
260 Tag dimLensTag = 0;
261 tag_name = "__DIM_LENS";
262 data = NULL;
263 int dimLensSz = 0;
264 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_INTEGER, dimLensTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
265 rval = mbImpl->tag_get_by_ptr( dimLensTag, &fileSet, 1, &data, &dimLensSz );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
266 const int* int_p = static_cast< const int* >( data );
267 dbgOut.tprintf( 1, "__DIM_LENS tag has %d values\n", dimLensSz );
268
269 int idxDim = 0;
270
271 for( std::size_t i = 0; i != static_cast< std::size_t >( dimNamesSz ); i++ )
272 {
273 if( p[i] == '\0' )
274 {
275 std::string dim_name( &p[start], i - start );
276 int len = int_p[idxDim];
277 dimNames.push_back( dim_name );
278 dimLens.push_back( len );
279 dbgOut.tprintf( 2, "Dimension %s has length %d\n", dim_name.c_str(), len );
280
281
282
286 start = i + 1;
287 idxDim++;
288 }
289 }
290
291 Tag meshTypeTag = 0;
292 tag_name = "__MESH_TYPE";
293 data = NULL;
294 int meshTypeSz = 0;
295 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_OPAQUE, meshTypeTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
296 rval = mbImpl->tag_get_by_ptr( meshTypeTag, &fileSet, 1, &data, &meshTypeSz );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
297 p = static_cast< const char* >( data );
298 grid_type = std::string( &p[0], meshTypeSz );
299 dbgOut.tprintf( 2, "Mesh type: %s\n", grid_type.c_str() );
300
301
302 Tag varNamesLocsTag = 0;
303 tag_name = "__VAR_NAMES_LOCATIONS";
304 data = NULL;
305 int varNamesLocsSz = 0;
306 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_INTEGER, varNamesLocsTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
307 rval = mbImpl->tag_get_by_ptr( varNamesLocsTag, &fileSet, 1, &data, &varNamesLocsSz );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
308 int_p = static_cast< const int* >( data );
309 std::vector< int > varNamesLocs( varNamesLocsSz );
310 std::copy( int_p, int_p + varNamesLocsSz, varNamesLocs.begin() );
311
312 Tag varNamesTag = 0;
313 tag_name = "__VAR_NAMES";
314 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_OPAQUE, varNamesTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
315 data = NULL;
316 int varNamesSz = 0;
317 rval = mbImpl->tag_get_by_ptr( varNamesTag, &fileSet, 1, &data, &varNamesSz );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
318 dbgOut.tprintf( 2, "__VAR_NAMES tag has string length %d\n", varNamesSz );
319 p = static_cast< const char* >( data );
320
321 start = 0;
322 int idxVar = 0;
323 int sz;
324
325 for( std::size_t i = 0; i != static_cast< std::size_t >( varNamesSz ); i++ )
326 {
327 if( p[i] == '\0' )
328 {
329 std::string var_name( &p[start], i - start );
330
331 dbgOut.tprintf( 2, "var name: %s index %d \n", var_name.c_str(), idxVar );
332
333
334
335
336 VarData& variableDataStruct = varInfo[var_name];
337 variableDataStruct.varName = var_name;
338 variableDataStruct.entLoc = varNamesLocs[idxVar];
339
340 dbgOut.tprintf( 2, "at var name %s varInfo size %d \n", var_name.c_str(), (int)varInfo.size() );
341
342 sz = 0;
343 Tag dims_tag = 0;
344 std::string dim_names = "__" + var_name + "_DIMS";
345 rval = mbImpl->tag_get_handle( dim_names.c_str(), 0, MB_TYPE_OPAQUE, dims_tag, MB_TAG_ANY );
346 if( MB_SUCCESS != rval )
347 {
348 if( MB_TAG_NOT_FOUND == rval )
349 {
350 dbgOut.tprintf( 2, "tag : %s not found, continue \n", dim_names.c_str() );
351 start = i + 1;
352 idxVar++;
353 continue;
354 }
355 MB_SET_ERR( rval, "Trouble getting conventional tag " << dim_names );
356 }
357 rval = mbImpl->tag_get_length( dims_tag, sz );MB_CHK_SET_ERR( rval, "Trouble getting size of dimensions for variable " << var_name );
358 sz /= sizeof( Tag );
359
360
361 dbgOut.tprintf( 2, "var name: %s has %d dimensions \n", var_name.c_str(), sz );
362
363 variableDataStruct.varDims.resize( sz );
364 const void* ptr = NULL;
365 rval = mbImpl->tag_get_by_ptr( dims_tag, &fileSet, 1, &ptr );
366
367 const Tag* ptags = static_cast< const moab::Tag* >( ptr );
368 for( std::size_t j = 0; j != static_cast< std::size_t >( sz ); j++ )
369 {
370 std::string dim_name;
371 rval = mbImpl->tag_get_name( ptags[j], dim_name );MB_CHK_SET_ERR( rval, "Trouble getting dimension of variable " << var_name );
372 dbgOut.tprintf( 2, "var name: %s has %s as dimension \n", var_name.c_str(), dim_name.c_str() );
373 std::vector< std::string >::iterator vit = std::find( dimNames.begin(), dimNames.end(), dim_name );
374 if( vit == dimNames.end() )
375 MB_SET_ERR( MB_FAILURE, "Dimension " << dim_name << " not found for variable " << var_name );
376 variableDataStruct.varDims[j] = (int)( vit - dimNames.begin() );
377
378 }
379
380
381 std::stringstream ssTagName;
382 ssTagName << "__" << var_name << "_ATTRIBS";
383 tag_name = ssTagName.str();
384 Tag varAttTag = 0;
385 rval =
386 mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_OPAQUE, varAttTag, MB_TAG_SPARSE | MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
387 const void* varAttPtr = NULL;
388 int varAttSz = 0;
389 rval = mbImpl->tag_get_by_ptr( varAttTag, &fileSet, 1, &varAttPtr, &varAttSz );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
390 if( MB_SUCCESS == rval ) dbgOut.tprintf( 2, "Tag retrieved for variable %s\n", tag_name.c_str() );
391
392 std::string attribString( (char*)varAttPtr, (char*)varAttPtr + varAttSz );
393 if( attribString == "NO_ATTRIBS" )
394 {
395
396 variableDataStruct.numAtts = 0;
397 }
398 else if( attribString == "DUMMY_VAR" )
399 {
400
401 variableDataStruct.numAtts = 0;
402 dummyVarNames.insert( variableDataStruct.varName );
403 }
404 else
405 {
406 ssTagName << "_LEN";
407 tag_name = ssTagName.str();
408 Tag varAttLenTag = 0;
409 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_INTEGER, varAttLenTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
410 int varAttLenSz = 0;
411 rval = mbImpl->tag_get_length( varAttLenTag, varAttLenSz );MB_CHK_SET_ERR( rval, "Trouble getting length of conventional tag " << tag_name );
412 std::vector< int > varAttLen( varAttLenSz );
413 rval = mbImpl->tag_get_data( varAttLenTag, &fileSet, 1, &varAttLen[0] );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
414
415 rval = process_concatenated_attribute( varAttPtr, varAttSz, varAttLen, variableDataStruct.varAtts );MB_CHK_SET_ERR( rval, "Trouble processing attributes of variable " << var_name );
416
417 if( MB_SUCCESS == rval ) dbgOut.tprintf( 2, "Tag metadata for variable %s\n", tag_name.c_str() );
418 }
419
420
421 start = i + 1;
422 idxVar++;
423 }
424 }
425
426
427 tag_name = "__GLOBAL_ATTRIBS";
428 Tag globalAttTag = 0;
429 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_OPAQUE, globalAttTag, MB_TAG_SPARSE | MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
430 std::vector< int > gattLen;
431
432 const void* gattptr = NULL;
433 int globalAttSz = 0;
434 rval = mbImpl->tag_get_by_ptr( globalAttTag, &fileSet, 1, &gattptr, &globalAttSz );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
435
436 if( MB_SUCCESS == rval ) dbgOut.tprintf( 2, "Tag value retrieved for %s size %d\n", tag_name.c_str(), globalAttSz );
437
438
439 tag_name = "__GLOBAL_ATTRIBS_LEN";
440 Tag globalAttLenTag = 0;
441
442 rval = mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_INTEGER, globalAttLenTag, MB_TAG_ANY );MB_CHK_SET_ERR( rval, "Trouble getting conventional tag " << tag_name );
443 int sizeGAtt = 0;
444 rval = mbImpl->tag_get_length( globalAttLenTag, sizeGAtt );MB_CHK_SET_ERR( rval, "Trouble getting length of conventional tag " << tag_name );
445 gattLen.resize( sizeGAtt );
446 rval = mbImpl->tag_get_data( globalAttLenTag, &fileSet, 1, &gattLen[0] );MB_CHK_SET_ERR( rval, "Trouble getting data of conventional tag " << tag_name );
447 if( MB_SUCCESS == rval ) dbgOut.tprintf( 2, "Tag retrieved for variable %s\n", tag_name.c_str() );
448
449 rval = process_concatenated_attribute( gattptr, globalAttSz, gattLen, globalAtts );MB_CHK_SET_ERR( rval, "Trouble processing global attributes" );
450
451 return MB_SUCCESS;
452 }
453
454
455 ErrorCode WriteNC::process_concatenated_attribute( const void* attPtr,
456 int attSz,
457 std::vector< int >& attLen,
458 std::map< std::string, AttData >& attributes )
459 {
460 std::size_t start = 0;
461 std::size_t att_counter = 0;
462 std::string concatString( (char*)attPtr, (char*)attPtr + attSz );
463
464 for( std::size_t i = 0; i != (size_t)attSz; i++ )
465 {
466 if( concatString[i] == '\0' )
467 {
468 std::string att_name( &concatString[start], i - start );
469 start = i + 1;
470 while( concatString[i] != ';' )
471 ++i;
472 std::string data_type( &concatString[start], i - start );
473 ++i;
474 start = i;
475 i = attLen[att_counter];
476 if( concatString[i] != ';' ) MB_SET_ERR( MB_FAILURE, "Error parsing attributes" );
477
478 std::string data_val( &concatString[start], i - start );
479 start = i + 1;
480
481 AttData& attrib = attributes[att_name];
482 attrib.attValue = data_val;
483 attrib.attLen = data_val.size();
484
485 if( data_type == "char" )
486 attrib.attDataType = NC_CHAR;
487 else if( data_type == "double" )
488 attrib.attDataType = NC_DOUBLE;
489 else if( data_type == "float" )
490 attrib.attDataType = NC_FLOAT;
491 else if( data_type == "int" )
492 attrib.attDataType = NC_INT;
493 else if( data_type == "short" )
494 attrib.attDataType = NC_SHORT;
495
496 ++att_counter;
497 dbgOut.tprintf( 2, " Process attribute %s with value %s \n", att_name.c_str(), data_val.c_str() );
498 }
499 }
500
501 return MB_SUCCESS;
502 }
503
504 }