1 /*
2 MDAL - Mesh Data Abstraction Library (MIT License)
3 Copyright (C) 2018 Lutra Consulting Limited
4 */
5
6 #include <vector>
7 #include <string>
8 #include <string.h>
9 #include <sstream>
10 #include <iostream>
11 #include <fstream>
12 #include <memory>
13 #include <algorithm>
14 #include <map>
15 #include <cmath>
16 #include <limits>
17
18 #include "mdal_xdmf.hpp"
19 #include "mdal_utils.hpp"
20 #include "mdal_data_model.hpp"
21 #include "mdal_xml.hpp"
22 #include "mdal_logger.hpp"
23
XdmfDataset(MDAL::DatasetGroup * grp,const MDAL::HyperSlab & slab,const HdfDataset & valuesDs,RelativeTimestamp time)24 MDAL::XdmfDataset::XdmfDataset( MDAL::DatasetGroup *grp,
25 const MDAL::HyperSlab &slab,
26 const HdfDataset &valuesDs,
27 RelativeTimestamp time )
28 : MDAL::Dataset2D( grp )
29 , mHdf5DatasetValues( valuesDs )
30 , mHyperSlab( slab )
31 {
32 setTime( time );
33 }
34
35 MDAL::XdmfDataset::~XdmfDataset() = default;
36
offsets(size_t indexStart)37 std::vector<hsize_t> MDAL::XdmfDataset::offsets( size_t indexStart )
38 {
39 std::vector<hsize_t> ret( 2 );
40 ret[0] = mHyperSlab.startX + indexStart;
41 ret[1] = mHyperSlab.startY;
42 return ret;
43 }
44
selections(size_t copyValues)45 std::vector<hsize_t> MDAL::XdmfDataset::selections( size_t copyValues )
46 {
47 std::vector<hsize_t> ret( 2 );
48 if ( mHyperSlab.countInFirstColumn )
49 {
50 ret[0] = copyValues;
51 ret[1] = mHyperSlab.isScalar ? 1 : 3;
52 }
53 else
54 {
55 ret[0] = mHyperSlab.isScalar ? 1 : 3;
56 ret[1] = copyValues;
57 }
58 return ret;
59 }
60
scalarData(size_t indexStart,size_t count,double * buffer)61 size_t MDAL::XdmfDataset::scalarData( size_t indexStart, size_t count, double *buffer )
62 {
63 assert( group()->isScalar() ); //checked in C API interface
64 assert( mHyperSlab.isScalar );
65
66 size_t nValues = mHyperSlab.count;
67 if ( ( count < 1 ) || ( indexStart >= nValues ) )
68 return 0;
69 size_t copyValues = std::min( nValues - indexStart, count );
70
71 std::vector<hsize_t> off = offsets( indexStart );
72 std::vector<hsize_t> counts = selections( copyValues );
73 std::vector<double> values = mHdf5DatasetValues.readArrayDouble( off, counts );
74 if ( values.empty() )
75 return 0;
76
77 const double *input = values.data();
78 memcpy( buffer, input, copyValues * sizeof( double ) );
79 return copyValues;
80 }
81
82
vectorData(size_t indexStart,size_t count,double * buffer)83 size_t MDAL::XdmfDataset::vectorData( size_t indexStart, size_t count, double *buffer )
84 {
85 assert( !group()->isScalar() ); //checked in C API interface
86 assert( !mHyperSlab.isScalar );
87
88 size_t nValues = mHyperSlab.count;
89 if ( ( count < 1 ) || ( indexStart >= nValues ) )
90 return 0;
91 size_t copyValues = std::min( nValues - indexStart, count );
92
93 std::vector<hsize_t> off = offsets( indexStart );
94 std::vector<hsize_t> counts = selections( copyValues );
95 std::vector<double> values = mHdf5DatasetValues.readArrayDouble( off, counts );
96 if ( values.empty() )
97 return 0;
98
99 const double *input = values.data();
100 for ( size_t j = 0; j < copyValues; ++j )
101 {
102 buffer[2 * j] = input[3 * j];
103 buffer[2 * j + 1] = input[3 * j + 1];
104 }
105 return copyValues;
106 }
107
108 // //////////////////////////////////////////////////////////////////////////////
109 // //////////////////////////////////////////////////////////////////////////////
110 // //////////////////////////////////////////////////////////////////////////////
111
112
XdmfFunctionDataset(MDAL::DatasetGroup * grp,MDAL::XdmfFunctionDataset::FunctionType type,const RelativeTimestamp & time)113 MDAL::XdmfFunctionDataset::XdmfFunctionDataset(
114 MDAL::DatasetGroup *grp,
115 MDAL::XdmfFunctionDataset::FunctionType type,
116 const RelativeTimestamp &time )
117 : MDAL::Dataset2D( grp )
118 , mType( type )
119 , mBaseReferenceGroup( "XDMF", grp->mesh(), grp->uri() )
120 {
121 setTime( time );
122 mBaseReferenceGroup.setIsScalar( true );
123 mBaseReferenceGroup.setDataLocation( grp->dataLocation() );
124 mBaseReferenceGroup.setName( "Base group for reference datasets" );
125 }
126
127 MDAL::XdmfFunctionDataset::~XdmfFunctionDataset() = default;
128
addReferenceDataset(const HyperSlab & slab,const HdfDataset & hdfDataset,const MDAL::RelativeTimestamp & time)129 void MDAL::XdmfFunctionDataset::addReferenceDataset(
130 const HyperSlab &slab,
131 const HdfDataset &hdfDataset,
132 const MDAL::RelativeTimestamp &time )
133 {
134 std::shared_ptr<MDAL::XdmfDataset> xdmfDataset = std::make_shared<MDAL::XdmfDataset>(
135 &mBaseReferenceGroup,
136 slab,
137 hdfDataset,
138 time
139 );
140 mReferenceDatasets.push_back( xdmfDataset );
141 }
142
swap()143 void MDAL::XdmfFunctionDataset::swap()
144 {
145 if ( mReferenceDatasets.size() < 2 )
146 return;
147 std::swap( mReferenceDatasets[0], mReferenceDatasets[1] );
148 }
149
scalarData(size_t indexStart,size_t count,double * buffer)150 size_t MDAL::XdmfFunctionDataset::scalarData( size_t indexStart, size_t count, double *buffer )
151 {
152 assert( group()->isScalar() ); //checked in C API interface
153 assert( mType != FunctionType::Join );
154
155 if ( mType == FunctionType::Subtract )
156 return subtractFunction( indexStart, count, buffer );
157
158 if ( mType == FunctionType::Flow )
159 return flowFunction( indexStart, count, buffer );
160
161 return 0;
162 }
163
vectorData(size_t indexStart,size_t count,double * buffer)164 size_t MDAL::XdmfFunctionDataset::vectorData( size_t indexStart, size_t count, double *buffer )
165 {
166 assert( !group()->isScalar() ); //checked in C API interface
167 assert( mType == FunctionType::Join );
168
169 return joinFunction( indexStart, count, buffer );
170 }
171
subtractFunction(size_t indexStart,size_t count,double * buffer)172 size_t MDAL::XdmfFunctionDataset::subtractFunction( size_t indexStart, size_t count, double *buffer )
173 {
174 std::vector<double> buf( 2 * count, std::numeric_limits<double>::quiet_NaN() );
175 size_t copyVals = extractRawData( indexStart, count, 2, buf );
176 for ( size_t j = 0; j < copyVals; ++j )
177 {
178 double x0 = buf[j];
179 double x1 = buf[count + j];
180 if ( !std::isnan( x0 ) && !std::isnan( x1 ) )
181 buffer[j] = x1 - x0;
182 }
183 return copyVals;
184 }
185
flowFunction(size_t indexStart,size_t count,double * buffer)186 size_t MDAL::XdmfFunctionDataset::flowFunction( size_t indexStart, size_t count, double *buffer )
187 {
188 std::vector<double> buf( 4 * count, std::numeric_limits<double>::quiet_NaN() );
189 size_t copyVals = extractRawData( indexStart, count, 4, buf );
190 for ( size_t j = 0; j < copyVals; ++j )
191 {
192 double x0 = buf[1 * count + j];
193 double x1 = buf[1 * count + j];
194 double x2 = buf[2 * count + j];
195 double x3 = buf[3 * count + j];
196
197 if ( !std::isnan( x0 ) &&
198 !std::isnan( x1 ) &&
199 !std::isnan( x2 ) &&
200 !MDAL::equals( x2, x3 )
201 )
202 {
203 double diff = x2 - x3;
204 buffer[j] = sqrt( ( x0 / diff ) * ( x0 / diff ) + ( x1 / diff ) * ( x1 / diff ) );
205 }
206 }
207 return copyVals;
208 }
209
joinFunction(size_t indexStart,size_t count,double * buffer)210 size_t MDAL::XdmfFunctionDataset::joinFunction( size_t indexStart, size_t count, double *buffer )
211 {
212 std::vector<double> buf( 2 * count, std::numeric_limits<double>::quiet_NaN() );
213 size_t copyVals = extractRawData( indexStart, count, 2, buf );
214 for ( size_t j = 0; j < copyVals; ++j )
215 {
216 double x = buf[j];
217 double y = buf[count + j];
218 if ( !std::isnan( x ) && !std::isnan( y ) )
219 {
220 buffer[2 * j] = x;
221 buffer[2 * j + 1] = y;
222 }
223 }
224 return copyVals;
225 }
226
extractRawData(size_t indexStart,size_t count,size_t nDatasets,std::vector<double> & buf)227 size_t MDAL::XdmfFunctionDataset::extractRawData( size_t indexStart, size_t count, size_t nDatasets, std::vector< double > &buf )
228 {
229 assert( buf.size() == nDatasets * count );
230
231 if ( mReferenceDatasets.size() < nDatasets )
232 return 0;
233
234 if ( !mReferenceDatasets[0]->group()->isScalar() )
235 return 0;
236
237 size_t ret = mReferenceDatasets[0]->scalarData( indexStart, count, buf.data() );
238 for ( size_t i = 1; i < nDatasets ; ++i )
239 {
240 if ( !mReferenceDatasets[i]->group()->isScalar() )
241 return 0;
242 size_t ret1 = mReferenceDatasets[i]->scalarData( indexStart, count, buf.data() + count * i );
243 if ( ret != ret1 )
244 return 0;
245 }
246 return ret;
247 }
248
249 // //////////////////////////////////////////////////////////////////////////////
250 // //////////////////////////////////////////////////////////////////////////////
251 // //////////////////////////////////////////////////////////////////////////////
252
parseHyperSlab(const std::string & str,size_t dimX)253 MDAL::HyperSlab MDAL::DriverXdmf::parseHyperSlab( const std::string &str, size_t dimX )
254 {
255 std::stringstream slabSS( str );
256 std::vector<std::vector<size_t>> data( 3, std::vector<size_t>( dimX ) );
257 size_t i = 0;
258 size_t number;
259 while ( slabSS >> number )
260 {
261 data[i / dimX][i % dimX] = number;
262 i++;
263 }
264 if ( i != 3 * dimX )
265 {
266 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "hyperSlab dimensions mismatch" );
267 }
268
269 MDAL::HyperSlab slab;
270 slab.startX = data[0][0];
271 slab.startY = data[0][1];
272 size_t countX = data[2][0];
273 size_t countY = data[2][1];
274
275 if ( ( data[1][0] != 1 ) || ( data[1][1] != 1 ) )
276 {
277 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "only hyperSlab with stride 1 are supported" );
278 }
279
280 // sort
281 if ( ( countX < countY ) && ( countY != 3 ) )
282 {
283 std::swap( countX, countY );
284 slab.countInFirstColumn = false;
285 }
286 else
287 {
288 slab.countInFirstColumn = true;
289 }
290 slab.count = countX;
291
292 if ( countY == 1 )
293 {
294 slab.isScalar = true;
295 }
296 else if ( countY == 3 )
297 {
298 slab.isScalar = false;
299 }
300 else
301 {
302 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "hyperSlab dimensions mismatch, not scalar or vector" );
303 }
304
305 return slab;
306 }
307
parseHyperSlabNode(const XMLFile & xmfFile,xmlNodePtr node)308 MDAL::HyperSlab MDAL::DriverXdmf::parseHyperSlabNode( const XMLFile &xmfFile, xmlNodePtr node )
309 {
310 std::string slabDimS = xmfFile.attribute( node, "Dimensions" );
311 std::vector<size_t> slabDim = parseDimensions2D( slabDimS );
312 if ( slabDim[0] != 3 || ( slabDim[1] != 2 && slabDim[1] != 3 ) )
313 {
314 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Only two-dimensional slab array with dim 3x3 is supported (1)" );
315 }
316
317 std::string slabS = xmfFile.content( node );
318 HyperSlab slab = parseHyperSlab( slabS, slabDim[1] );
319 return slab;
320 }
321
parseHdf5Node(const XMLFile & xmfFile,xmlNodePtr node)322 HdfDataset MDAL::DriverXdmf::parseHdf5Node( const XMLFile &xmfFile, xmlNodePtr node )
323 {
324 std::string snapshotDimS = xmfFile.attribute( node, "Dimensions" );
325 std::vector<size_t> snapshotDim = parseDimensions2D( snapshotDimS );
326
327 std::string hdf5Name, hdf5Path;
328 hdf5NamePath( xmfFile.content( node ), hdf5Name, hdf5Path );
329
330 std::shared_ptr<HdfFile> hdfFile;
331 if ( mHdfFiles.count( hdf5Name ) == 0 )
332 {
333 hdfFile = std::make_shared<HdfFile>( hdf5Name, HdfFile::ReadOnly );
334 mHdfFiles[hdf5Name] = hdfFile;
335 }
336 else
337 {
338 hdfFile = mHdfFiles[hdf5Name];
339 }
340
341 HdfDataset hdfDataset( hdfFile->id(), hdf5Path );
342 return hdfDataset;
343 }
344
hdf5NamePath(const std::string & dataItemPath,std::string & filePath,std::string & hdf5Path)345 void MDAL::DriverXdmf::hdf5NamePath( const std::string &dataItemPath, std::string &filePath, std::string &hdf5Path )
346 {
347 std::string dirName = MDAL::dirName( mDatFile );
348 std::string path( dataItemPath );
349 size_t endpos = path.find_last_not_of( " \t\n" );
350 if ( std::string::npos != endpos )
351 {
352 path.erase( endpos + 1 );
353 }
354 size_t startpos = path.find_first_not_of( " \t\n" );
355 if ( std::string::npos != startpos )
356 {
357 path.erase( 0, startpos );
358 }
359
360 std::vector<std::string> chunks = MDAL::split( path, ":" );
361 if ( chunks.size() != 2 )
362 {
363 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "must be in format fileName:hdfPath" );
364 }
365
366 filePath = dirName + "/" + chunks[0];
367 hdf5Path = chunks[1];
368 }
369
parseDimensions2D(const std::string & data)370 std::vector<size_t> MDAL::DriverXdmf::parseDimensions2D( const std::string &data )
371 {
372 std::stringstream slabDimSS( data );
373 std::vector<size_t> slabDim;
374 size_t number;
375 while ( slabDimSS >> number )
376 slabDim.push_back( number );
377 if ( slabDim.size() != 2 )
378 {
379 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Only two-dimensional slab array is supported" );
380 }
381 return slabDim;
382 }
383
parseXdmfDataset(const XMLFile & xmfFile,xmlNodePtr itemNod)384 std::pair<HdfDataset, MDAL::HyperSlab> MDAL::DriverXdmf::parseXdmfDataset(
385 const XMLFile &xmfFile,
386 xmlNodePtr itemNod )
387 {
388 size_t facesCount = mMesh->facesCount();
389
390 size_t dim = xmfFile.querySizeTAttribute( itemNod, "Dimensions" );
391 if ( dim != facesCount )
392 {
393 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Dataset dimensions should correspond to the number of mesh elements" );
394 }
395
396 xmlNodePtr node1 = xmfFile.getCheckChild( itemNod, "DataItem" );
397 xmlNodePtr node2 = xmfFile.getCheckSibling( node1, "DataItem" );
398
399 std::string format1 = xmfFile.attribute( node1, "Format" );
400 std::string format2 = xmfFile.attribute( node2, "Format" );
401
402 if ( ( format1 == "XML" ) && ( format2 == "HDF" ) )
403 {
404 HyperSlab slab = parseHyperSlabNode( xmfFile, node1 );
405 HdfDataset hdfDataset = parseHdf5Node( xmfFile, node2 );
406 return std::make_pair( hdfDataset, slab );
407 }
408 else
409 {
410 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Only XML hyperSlab and HDF dataset Format supported" );
411 }
412 }
413
parseXdmfXml()414 MDAL::DatasetGroups MDAL::DriverXdmf::parseXdmfXml( )
415 {
416 std::map< std::string, std::shared_ptr<MDAL::DatasetGroup> > groups;
417 size_t nTimesteps = 0;
418
419 XMLFile xmfFile;
420 xmfFile.openFile( mDatFile );
421
422 xmlNodePtr elem = xmfFile.getCheckRoot( "Xdmf" );
423 elem = xmfFile.getCheckChild( elem, "Domain" );
424 elem = xmfFile.getCheckChild( elem, "Grid" );
425
426 xmfFile.checkAttribute( elem, "GridType", "Collection", "Expecting Collection Grid Type" );
427 xmfFile.checkAttribute( elem, "CollectionType", "Temporal", "Expecting Temporal Collection Type" );
428
429 elem = xmfFile.getCheckChild( elem, "Grid" );
430
431 for ( xmlNodePtr gridNod = elem;
432 gridNod != nullptr;
433 gridNod = xmfFile.getCheckSibling( gridNod, "Grid", false ) )
434 {
435 ++nTimesteps;
436 xmlNodePtr timeNod = xmfFile.getCheckChild( gridNod, "Time" );
437 RelativeTimestamp time( xmfFile.queryDoubleAttribute( timeNod, "Value" ), RelativeTimestamp::hours ); //units, supposed to be hours
438 xmlNodePtr scalarNod = xmfFile.getCheckChild( gridNod, "Attribute" );
439
440 for ( ;
441 scalarNod != nullptr;
442 scalarNod = xmfFile.getCheckSibling( scalarNod, "Attribute", false ) )
443 {
444 xmfFile.checkAttribute( scalarNod, "Center", "Cell", "Only cell centered data is currently supported" );
445 if ( !xmfFile.checkAttribute( scalarNod, "AttributeType", "Scalar" ) &&
446 !xmfFile.checkAttribute( scalarNod, "AttributeType", "Vector" ) )
447 {
448 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Only scalar and vector data are currently supported" );
449 }
450 std::string groupName = xmfFile.attribute( scalarNod, "Name" );
451 if ( groupName.empty() )
452 {
453 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Group name cannot be empty" );
454 }
455
456 xmlNodePtr itemNod = xmfFile.getCheckChild( scalarNod, "DataItem" );
457
458 if ( xmfFile.checkAttribute( itemNod, "ItemType", "Function" ) )
459 {
460 std::string function = xmfFile.attribute( itemNod, "Function" );
461 function = MDAL::replace( function, " ", "" );
462 XdmfFunctionDataset::FunctionType type;
463 bool reversed = false;
464 bool isScalar = true;
465 if ( function == "sqrt($0/($2-$3)*$0/($2-$3)+$1/($2-$3)*$1/($2-$3))" )
466 {
467 type = XdmfFunctionDataset::Flow;
468 }
469 else if ( function == "$0-$1" )
470 {
471 reversed = true;
472 type = XdmfFunctionDataset::Subtract;
473 }
474 else if ( function == "$1-$0" )
475 {
476 type = XdmfFunctionDataset::Subtract;
477 }
478 else if ( ( function == "JOIN($0,$1,0*$1)" ) || ( function == "JOIN($0,$1,0)" ) )
479 {
480 type = XdmfFunctionDataset::Join;
481 isScalar = false;
482 }
483
484 std::shared_ptr<MDAL::DatasetGroup> group = findGroup( groups, groupName, isScalar );
485 std::shared_ptr<MDAL::XdmfFunctionDataset> xdmfFunctionDataset = std::make_shared<MDAL::XdmfFunctionDataset>(
486 group.get(),
487 type,
488 time
489 );
490
491 xmlNodePtr dataNod = xmfFile.getCheckChild( itemNod, "DataItem" );
492 for ( ;
493 dataNod != nullptr;
494 dataNod = xmfFile.getCheckSibling( dataNod, "DataItem", false ) )
495 {
496 if (
497 xmfFile.checkAttribute( dataNod, "ItemType", "HyperSlab" ) ||
498 xmfFile.checkAttribute( dataNod, "Type", "HyperSlab" ) )
499 {
500 std::pair<HdfDataset, HyperSlab> data = parseXdmfDataset( xmfFile, dataNod );
501 xdmfFunctionDataset->addReferenceDataset( data.second, data.first, time );
502 }
503 else
504 {
505 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Expecting HyperSlab Types under Function" );
506 }
507 }
508
509 if ( reversed )
510 {
511 xdmfFunctionDataset->swap();
512 }
513
514 // This basically forces to load all data to calculate statistics!
515 const MDAL::Statistics stats = MDAL::calculateStatistics( xdmfFunctionDataset );
516 xdmfFunctionDataset->setStatistics( stats );
517 group->datasets.push_back( xdmfFunctionDataset );
518 }
519 else if (
520 xmfFile.checkAttribute( itemNod, "ItemType", "HyperSlab" ) ||
521 xmfFile.checkAttribute( itemNod, "Type", "HyperSlab" ) )
522 {
523 std::pair<HdfDataset, HyperSlab> data = parseXdmfDataset( xmfFile, itemNod );
524 std::shared_ptr<MDAL::DatasetGroup> group = findGroup( groups, groupName, data.second.isScalar );
525 std::shared_ptr<MDAL::XdmfDataset> xdmfDataset = std::make_shared<MDAL::XdmfDataset>(
526 group.get(),
527 data.second,
528 data.first,
529 time
530 );
531 // This basically forces to load all data to calculate statistics!
532 const MDAL::Statistics stats = MDAL::calculateStatistics( xdmfDataset );
533 xdmfDataset->setStatistics( stats );
534 group->datasets.push_back( xdmfDataset );
535 }
536 else
537 {
538 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Expecting Function or HyperSlab Type" );
539 }
540 }
541 }
542
543 // check groups
544 DatasetGroups ret;
545 for ( const auto &group : groups )
546 {
547 std::shared_ptr<MDAL::DatasetGroup> grp = group.second;
548 if ( grp->datasets.size() != nTimesteps )
549 {
550 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Invalid group, missing timesteps" );
551 }
552
553 const MDAL::Statistics stats = MDAL::calculateStatistics( grp );
554 grp->setStatistics( stats );
555 // verify the integrity of the dataset
556 if ( !std::isnan( stats.minimum ) )
557 ret.push_back( grp );
558 }
559
560 return ret;
561 }
562
findGroup(std::map<std::string,std::shared_ptr<MDAL::DatasetGroup>> & groups,const std::string & groupName,bool isScalar)563 std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverXdmf::findGroup( std::map<std::string, std::shared_ptr<MDAL::DatasetGroup> > &groups,
564 const std::string &groupName,
565 bool isScalar )
566 {
567 std::shared_ptr<MDAL::DatasetGroup> group;
568 if ( groups.count( groupName ) == 0 )
569 {
570 group = std::make_shared<MDAL::DatasetGroup>(
571 "XDMF",
572 mMesh,
573 mDatFile,
574 groupName
575 );
576 group->setIsScalar( isScalar );
577 group->setDataLocation( MDAL_DataLocation::DataOnFaces ); //only center-based implemented
578 groups[groupName] = group;
579 }
580 else
581 {
582 group = groups[groupName];
583 if ( group->isScalar() != isScalar )
584 {
585 throw MDAL::Error( MDAL_Status::Err_UnknownFormat, "Inconsistent groups" );
586 }
587 }
588 return group;
589 }
590
591
DriverXdmf()592 MDAL::DriverXdmf::DriverXdmf()
593 : Driver( "XDMF",
594 "XDMF",
595 "*.xdmf;;*.xmf",
596 Capability::ReadDatasets )
597 {
598 }
599
600 MDAL::DriverXdmf::~DriverXdmf() = default;
601
create()602 MDAL::DriverXdmf *MDAL::DriverXdmf::create()
603 {
604 return new DriverXdmf();
605 }
606
canReadDatasets(const std::string & uri)607 bool MDAL::DriverXdmf::canReadDatasets( const std::string &uri )
608 {
609 XMLFile xmfFile;
610 try
611 {
612 xmfFile.openFile( uri );
613 xmlNodePtr root = xmfFile.getCheckRoot( "Xdmf" );
614 xmfFile.checkAttribute( root, "Version", "2.0", "Invalid version" );
615 }
616 catch ( MDAL_Status )
617 {
618 return false;
619 }
620 catch ( MDAL::Error )
621 {
622 return false;
623 }
624 return true;
625 }
626
load(const std::string & datFile,MDAL::Mesh * mesh)627 void MDAL::DriverXdmf::load( const std::string &datFile,
628 MDAL::Mesh *mesh )
629 {
630 assert( mesh );
631
632 mDatFile = datFile;
633 mMesh = mesh;
634
635 MDAL::Log::resetLastStatus();
636
637 if ( !MDAL::fileExists( mDatFile ) )
638 {
639 MDAL::Log::error( MDAL_Status::Err_FileNotFound, name(), "File could not be found " + mDatFile );
640 return;
641 }
642
643 try
644 {
645 // parse XML
646 DatasetGroups groups = parseXdmfXml( );
647 // add groups to mesh
648 for ( const auto &group : groups )
649 {
650 mMesh->datasetGroups.push_back( group );
651 }
652 }
653 catch ( MDAL_Status err )
654 {
655 MDAL::Log::error( err, "Error occurred while loading file " + mDatFile );
656 }
657 catch ( MDAL::Error err )
658 {
659 MDAL::Log::error( err, name() );
660 }
661 }
662