1 /* 2 MDAL - Mesh Data Abstraction Library (MIT License) 3 Copyright (C) 2019 Peter Petrik (zilolv at gmail dot com) 4 */ 5 6 #ifndef MDAL_XDMF_HPP 7 #define MDAL_XDMF_HPP 8 9 #include <string> 10 #include <vector> 11 #include <memory> 12 #include <iosfwd> 13 #include <iostream> 14 #include <fstream> 15 #include <utility> 16 17 #include "mdal_data_model.hpp" 18 #include "mdal.h" 19 #include "mdal_hdf5.hpp" 20 #include "mdal_driver.hpp" 21 #include "mdal_xml.hpp" 22 23 namespace MDAL 24 { 25 26 /** 27 * The XdmfDataset reads the data directly from HDF5 file 28 * by usage of hyperslabs retrieval 29 * 30 * http://xdmf.org/index.php/XDMF_Model_and_Format#HyperSlab 31 * HyperSlab consists of 3 rows: start, stride, and count 32 * - Currently we do not support stride other than 1 (every element) 33 * - Assumes BASEMENT 3.x format where the array is nFaces x 1 34 */ 35 struct HyperSlab 36 { 37 size_t startX = 0; // offset X 38 size_t startY = 0; // offset Y 39 size_t count = 0; // number of cells/vertices 40 bool countInFirstColumn = true; 41 bool isScalar; 42 }; 43 44 /** 45 * The XdmfDataset is simple vector or scalar dataset 46 * where values are stored in one HD5 variable 47 * and are lazy loaded on demand. Active flag is always ON. 48 * 49 * The definition is stored in XML file in format: 50 * 51 * <Attribute Name="water_surface" AttributeType="Scalar" Center="Cell"> 52 * <DataItem ItemType="HyperSlab" Dimensions="9 1" Type="HyperSlab"> 53 * <DataItem Dimensions="3 2" Format="XML"> 0 0 1 1 9 1 </DataItem> 54 * <DataItem Dimensions="9 3" Format="HDF"> test.h5:/RESULTS/CellsAll/HydState/0000002 </DataItem> 55 * </DataItem> 56 * </Attribute> 57 */ 58 class XdmfDataset: public Dataset2D 59 { 60 public: 61 XdmfDataset( DatasetGroup *grp, 62 const HyperSlab &slab, 63 const HdfDataset &valuesDs, 64 MDAL::RelativeTimestamp time 65 ); 66 ~XdmfDataset() override; 67 68 size_t scalarData( size_t indexStart, size_t count, double *buffer ) override; 69 size_t vectorData( size_t indexStart, size_t count, double *buffer ) override; 70 71 private: 72 std::vector<hsize_t> offsets( size_t indexStart ); 73 std::vector<hsize_t> selections( size_t copyValues ); 74 75 HdfDataset mHdf5DatasetValues; 76 HyperSlab mHyperSlab; 77 }; 78 79 /** 80 * The XdmfFunctionDataset is a function that 81 * references two or three scalar XdmfDatasets 82 * to create a vector or scalar dataset based on 83 * referenced datasets. Active flag is always ON. 84 * 85 * Currently we do not use any fancy bison/flex based 86 * expression parsing, just supporting few types of 87 * most common function types: 88 * - subtraction (A-B) 89 * - join ( [A, B] vector) 90 * - magnitude 91 * 92 * The definition is stored in XML file in format: 93 * 94 * <Attribute Name="..." AttributeType="Scalar" Center="Cell"> 95 * <DataItem ItemType="Function" Function="$0 - $1" Dimensions="9" > 96 * <DataItem ItemType="HyperSlab" Type="HyperSlab">...</DataItem> 97 * <DataItem ItemType="HyperSlab" Type="HyperSlab">...</DataItem> 98 * </DataItem> 99 * </Attribute> 100 */ 101 class XdmfFunctionDataset: public Dataset2D 102 { 103 public: 104 enum FunctionType 105 { 106 Join = 1, //!< vector: [$0, $1] from 2 scalars 107 Subtract, //!< scalar: $1 - $0, e.g. calculate relative depth 108 Flow, //!< scalar: flow velocity (abs) = sqrt($0/($2-$3)*$0/($2-$3) + $1/($2-$3)*$1/($2-$3)) 109 }; 110 111 XdmfFunctionDataset( DatasetGroup *grp, 112 FunctionType type, 113 const RelativeTimestamp &time 114 ); 115 ~XdmfFunctionDataset() override; 116 117 //! Adds reference XMDF dataset 118 void addReferenceDataset( const HyperSlab &slab, const HdfDataset &hdfDataset, const RelativeTimestamp &time ); 119 //! Swaps first and second reference dataset 120 void swap(); 121 122 size_t scalarData( size_t indexStart, size_t count, double *buffer ) override; 123 size_t vectorData( size_t indexStart, size_t count, double *buffer ) override; 124 125 private: 126 size_t subtractFunction( size_t indexStart, size_t count, double *buffer ); 127 size_t flowFunction( size_t indexStart, size_t count, double *buffer ); 128 size_t joinFunction( size_t indexStart, size_t count, double *buffer ); 129 size_t extractRawData( size_t indexStart, size_t count, size_t nDatasets, std::vector<double> &buf ); 130 131 const FunctionType mType; 132 std::vector<std::shared_ptr<XdmfDataset>> mReferenceDatasets; 133 /** 134 * "fake" base group for reference datasets. 135 * This group is not exposed to public API and 136 * it is just an implementation detail. 137 */ 138 DatasetGroup mBaseReferenceGroup; 139 }; 140 141 class DriverXdmf: public Driver 142 { 143 public: 144 /** 145 * Driver for XDMF Files 146 * 147 * XDMF is combination of XML file with dataset metadata and 148 * HDF5 file with actual data for the datasets 149 * 150 * full file specification http://xdmf.org/index.php/XDMF_Model_and_Format 151 * 152 * XDMF file can have data (vectors) stored in different ways. Currently we 153 * only support format for BASEMENET 3.x solver 154 */ 155 DriverXdmf(); 156 ~DriverXdmf( ) override; 157 DriverXdmf *create() override; 158 159 bool canReadDatasets( const std::string &uri ) override; 160 void load( const std::string &datFile, Mesh *mesh ) override; 161 162 private: 163 /** 164 Parses XML File with this structure, where data is specified as pointers to HDF in Attribute tags 165 166 <?xml version="1.0" ?> 167 <!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" []> 168 <Xdmf Version="2.0"> 169 <Domain> 170 <Topology> ... </Topology> 171 <Geometry> ... </Geometry> 172 <Grid GridType="Collection" Name="..." CollectionType="Temporal"> 173 <Grid GridType="Uniform" Name="Timestep"> 174 <Time TimeType="Single" Name="time = 0.000000" Value="0.000000"> </Time> 175 <Topology></Topology> 176 <Geometry GeometryType="XY" Reference="/Xdmf/Domain/Geometry[1]"></Geometry> 177 <Attribute> ... </Attribute> 178 </Grid> 179 </Grid> 180 <Domain> 181 </Xdmf> 182 */ 183 DatasetGroups parseXdmfXml( ); 184 185 //! Finds a group with a name or creates a new group if does not exists 186 std::shared_ptr<MDAL::DatasetGroup> findGroup( std::map< std::string, std::shared_ptr<MDAL::DatasetGroup> > &groups, 187 const std::string &groupName, 188 bool isScalar ); 189 190 /** 191 * Parses scalar/vector definition for XDMF dataset, e.g. 192 * 193 * <DataItem ItemType="HyperSlab" Dimensions="9 1" Type="HyperSlab"> 194 * <DataItem Dimensions="3 2" Format="XML"> 0 1 1 1 9 1 </DataItem> 195 * <DataItem Dimensions="9 3" Format="HDF"> test.h5:/RESULTS/CellsAll/HydState/0000002 </DataItem> 196 * </DataItem> 197 */ 198 std::pair<HdfDataset, HyperSlab > parseXdmfDataset( const XMLFile &xmfFile, xmlNodePtr itemNod ); 199 200 //! Parses hypeslab specification from string 201 HyperSlab parseHyperSlab( const std::string &str, size_t dimB ); 202 203 /** 204 * Parses hyperslab specification from matrix in DataItem [Dimension] tag 205 206 <DataItem ItemType="Uniform" Dimensions="3 3" Format="XML"> 207 0 0 0 1 1 1 18497 1 1 208 </DataItem> 209 */ 210 HyperSlab parseHyperSlabNode( const XMLFile &xmfFile, xmlNodePtr node ); 211 212 /** 213 * Parses hdf5 dataset from node 214 <DataItem Dimensions="9 3" Format="HDF"> test.h5:/RESULTS/CellsAll/HydState/0000002 </DataItem> 215 */ 216 HdfDataset parseHdf5Node( const XMLFile &xmfFile, xmlNodePtr node ); 217 218 //! Extracts HDF5 filename and HDF5 Path from XML file dirname and fileName:hdfPath syntax 219 void hdf5NamePath( const std::string &dataItemPath, std::string &filePath, std::string &hdf5Path ); 220 221 //! Parses 2d matrix from text, e.g. 3 2 -> [3, 2]. Verifies that it has 2 items 222 std::vector<size_t> parseDimensions2D( const std::string &data ); 223 224 MDAL::Mesh *mMesh = nullptr; 225 std::string mDatFile; 226 std::map< std::string, std::shared_ptr<HdfFile> > mHdfFiles; 227 228 }; 229 230 } // namespace MDAL 231 #endif //MDAL_XDMF_HPP 232