/* MDAL - Mesh Data Abstraction Library (MIT License) Copyright (C) 2019 Peter Petrik (zilolv at gmail dot com) */ #ifndef MDAL_XDMF_HPP #define MDAL_XDMF_HPP #include #include #include #include #include #include #include #include "mdal_data_model.hpp" #include "mdal.h" #include "mdal_hdf5.hpp" #include "mdal_driver.hpp" #include "mdal_xml.hpp" namespace MDAL { /** * The XdmfDataset reads the data directly from HDF5 file * by usage of hyperslabs retrieval * * http://xdmf.org/index.php/XDMF_Model_and_Format#HyperSlab * HyperSlab consists of 3 rows: start, stride, and count * - Currently we do not support stride other than 1 (every element) * - Assumes BASEMENT 3.x format where the array is nFaces x 1 */ struct HyperSlab { size_t startX = 0; // offset X size_t startY = 0; // offset Y size_t count = 0; // number of cells/vertices bool countInFirstColumn = true; bool isScalar; }; /** * The XdmfDataset is simple vector or scalar dataset * where values are stored in one HD5 variable * and are lazy loaded on demand. Active flag is always ON. * * The definition is stored in XML file in format: * * * * 0 0 1 1 9 1 * test.h5:/RESULTS/CellsAll/HydState/0000002 * * */ class XdmfDataset: public Dataset2D { public: XdmfDataset( DatasetGroup *grp, const HyperSlab &slab, const HdfDataset &valuesDs, MDAL::RelativeTimestamp time ); ~XdmfDataset() override; size_t scalarData( size_t indexStart, size_t count, double *buffer ) override; size_t vectorData( size_t indexStart, size_t count, double *buffer ) override; private: std::vector offsets( size_t indexStart ); std::vector selections( size_t copyValues ); HdfDataset mHdf5DatasetValues; HyperSlab mHyperSlab; }; /** * The XdmfFunctionDataset is a function that * references two or three scalar XdmfDatasets * to create a vector or scalar dataset based on * referenced datasets. Active flag is always ON. * * Currently we do not use any fancy bison/flex based * expression parsing, just supporting few types of * most common function types: * - subtraction (A-B) * - join ( [A, B] vector) * - magnitude * * The definition is stored in XML file in format: * * * * ... * ... * * */ class XdmfFunctionDataset: public Dataset2D { public: enum FunctionType { Join = 1, //!< vector: [$0, $1] from 2 scalars Subtract, //!< scalar: $1 - $0, e.g. calculate relative depth Flow, //!< scalar: flow velocity (abs) = sqrt($0/($2-$3)*$0/($2-$3) + $1/($2-$3)*$1/($2-$3)) }; XdmfFunctionDataset( DatasetGroup *grp, FunctionType type, const RelativeTimestamp &time ); ~XdmfFunctionDataset() override; //! Adds reference XMDF dataset void addReferenceDataset( const HyperSlab &slab, const HdfDataset &hdfDataset, const RelativeTimestamp &time ); //! Swaps first and second reference dataset void swap(); size_t scalarData( size_t indexStart, size_t count, double *buffer ) override; size_t vectorData( size_t indexStart, size_t count, double *buffer ) override; private: size_t subtractFunction( size_t indexStart, size_t count, double *buffer ); size_t flowFunction( size_t indexStart, size_t count, double *buffer ); size_t joinFunction( size_t indexStart, size_t count, double *buffer ); size_t extractRawData( size_t indexStart, size_t count, size_t nDatasets, std::vector &buf ); const FunctionType mType; std::vector> mReferenceDatasets; /** * "fake" base group for reference datasets. * This group is not exposed to public API and * it is just an implementation detail. */ DatasetGroup mBaseReferenceGroup; }; class DriverXdmf: public Driver { public: /** * Driver for XDMF Files * * XDMF is combination of XML file with dataset metadata and * HDF5 file with actual data for the datasets * * full file specification http://xdmf.org/index.php/XDMF_Model_and_Format * * XDMF file can have data (vectors) stored in different ways. Currently we * only support format for BASEMENET 3.x solver */ DriverXdmf(); ~DriverXdmf( ) override; DriverXdmf *create() override; bool canReadDatasets( const std::string &uri ) override; void load( const std::string &datFile, Mesh *mesh ) override; private: /** Parses XML File with this structure, where data is specified as pointers to HDF in Attribute tags ... ... ... */ DatasetGroups parseXdmfXml( ); //! Finds a group with a name or creates a new group if does not exists std::shared_ptr findGroup( std::map< std::string, std::shared_ptr > &groups, const std::string &groupName, bool isScalar ); /** * Parses scalar/vector definition for XDMF dataset, e.g. * * * 0 1 1 1 9 1 * test.h5:/RESULTS/CellsAll/HydState/0000002 * */ std::pair parseXdmfDataset( const XMLFile &xmfFile, xmlNodePtr itemNod ); //! Parses hypeslab specification from string HyperSlab parseHyperSlab( const std::string &str, size_t dimB ); /** * Parses hyperslab specification from matrix in DataItem [Dimension] tag 0 0 0 1 1 1 18497 1 1 */ HyperSlab parseHyperSlabNode( const XMLFile &xmfFile, xmlNodePtr node ); /** * Parses hdf5 dataset from node test.h5:/RESULTS/CellsAll/HydState/0000002 */ HdfDataset parseHdf5Node( const XMLFile &xmfFile, xmlNodePtr node ); //! Extracts HDF5 filename and HDF5 Path from XML file dirname and fileName:hdfPath syntax void hdf5NamePath( const std::string &dataItemPath, std::string &filePath, std::string &hdf5Path ); //! Parses 2d matrix from text, e.g. 3 2 -> [3, 2]. Verifies that it has 2 items std::vector parseDimensions2D( const std::string &data ); MDAL::Mesh *mMesh = nullptr; std::string mDatFile; std::map< std::string, std::shared_ptr > mHdfFiles; }; } // namespace MDAL #endif //MDAL_XDMF_HPP