mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-06 00:07:29 -04:00
update MDAL to 0.1.4 (RC1 for QGIS 3.6)
This commit is contained in:
parent
4048d37a46
commit
928a559aa9
2
external/mdal/frmts/mdal_3di.cpp
vendored
2
external/mdal/frmts/mdal_3di.cpp
vendored
@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
#include "mdal_3di.hpp"
|
||||
#include <netcdf.h>
|
||||
#include <assert.h>
|
||||
|
||||
MDAL::Driver3Di::Driver3Di()
|
||||
: DriverCF(
|
||||
|
351
external/mdal/frmts/mdal_ascii_dat.cpp
vendored
351
external/mdal/frmts/mdal_ascii_dat.cpp
vendored
@ -49,15 +49,203 @@ bool MDAL::DriverAsciiDat::canRead( const std::string &uri )
|
||||
}
|
||||
line = trim( line );
|
||||
|
||||
if ( line != "DATASET" &&
|
||||
line != "SCALAR" &&
|
||||
line != "VECTOR" )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return canReadNewFormat( line ) || canReadOldFormat( line );
|
||||
}
|
||||
|
||||
bool MDAL::DriverAsciiDat::canReadOldFormat( const std::string &line ) const
|
||||
{
|
||||
return MDAL::contains( line, "SCALAR" ) ||
|
||||
MDAL::contains( line, "VECTOR" ) ||
|
||||
MDAL::contains( line, "TS" );
|
||||
}
|
||||
|
||||
bool MDAL::DriverAsciiDat::canReadNewFormat( const std::string &line ) const
|
||||
{
|
||||
return line == "DATASET";
|
||||
}
|
||||
|
||||
|
||||
void MDAL::DriverAsciiDat::loadOldFormat( std::ifstream &in,
|
||||
Mesh *mesh,
|
||||
MDAL_Status *status ) const
|
||||
{
|
||||
std::shared_ptr<DatasetGroup> group; // DAT outputs data
|
||||
std::string groupName( MDAL::baseName( mDatFile ) );
|
||||
std::string line;
|
||||
std::getline( in, line );
|
||||
|
||||
// Read the first line
|
||||
bool isVector = MDAL::contains( line, "VECTOR" );
|
||||
group = std::make_shared< DatasetGroup >(
|
||||
name(),
|
||||
mesh,
|
||||
mDatFile,
|
||||
groupName
|
||||
);
|
||||
group->setIsScalar( !isVector );
|
||||
group->setIsOnVertices( true );
|
||||
|
||||
do
|
||||
{
|
||||
// Replace tabs by spaces,
|
||||
// since basement v.2.8 uses tabs instead of spaces (e.g. 'TS 0\t0.0')
|
||||
line = replace( line, "\t", " " );
|
||||
|
||||
// Trim string for cases when file has inconsistent new line symbols
|
||||
line = MDAL::trim( line );
|
||||
|
||||
// Split to tokens
|
||||
std::vector<std::string> items = split( line, " ", SplitBehaviour::SkipEmptyParts );
|
||||
if ( items.size() < 1 )
|
||||
continue; // empty line?? let's skip it
|
||||
|
||||
std::string cardType = items[0];
|
||||
if ( cardType == "ND" && items.size() >= 2 )
|
||||
{
|
||||
size_t fileNodeCount = toSizeT( items[1] );
|
||||
if ( mesh->verticesCount() != fileNodeCount )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
|
||||
}
|
||||
else if ( cardType == "SCALAR" || cardType == "VECTOR" )
|
||||
{
|
||||
// just ignore - we know the type from earlier...
|
||||
}
|
||||
else if ( cardType == "TS" && items.size() >= 2 )
|
||||
{
|
||||
double t = toDouble( items[ 1 ] );
|
||||
readVertexTimestep( mesh, group, t, isVector, false, in );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream str;
|
||||
str << " Unknown card:" << line;
|
||||
debug( str.str() );
|
||||
}
|
||||
}
|
||||
while ( std::getline( in, line ) );
|
||||
|
||||
if ( !group || group->datasets.size() == 0 )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
|
||||
group->setStatistics( MDAL::calculateStatistics( group ) );
|
||||
mesh->datasetGroups.push_back( group );
|
||||
group.reset();
|
||||
}
|
||||
|
||||
void MDAL::DriverAsciiDat::loadNewFormat( std::ifstream &in,
|
||||
Mesh *mesh,
|
||||
MDAL_Status *status ) const
|
||||
{
|
||||
bool isVector = false;
|
||||
std::shared_ptr<DatasetGroup> group; // DAT outputs data
|
||||
std::string groupName( MDAL::baseName( mDatFile ) );
|
||||
std::string line;
|
||||
|
||||
// see if it contains face-centered results - supported by BASEMENT
|
||||
bool faceCentered = false;
|
||||
if ( contains( groupName, "_els_" ) )
|
||||
faceCentered = true;
|
||||
|
||||
if ( group )
|
||||
group->setIsOnVertices( !faceCentered );
|
||||
|
||||
while ( std::getline( in, line ) )
|
||||
{
|
||||
// Replace tabs by spaces,
|
||||
// since basement v.2.8 uses tabs instead of spaces (e.g. 'TS 0\t0.0')
|
||||
line = replace( line, "\t", " " );
|
||||
|
||||
// Trim string for cases when file has inconsistent new line symbols
|
||||
line = MDAL::trim( line );
|
||||
|
||||
// Split to tokens
|
||||
std::vector<std::string> items = split( line, " ", SplitBehaviour::SkipEmptyParts );
|
||||
if ( items.size() < 1 )
|
||||
continue; // empty line?? let's skip it
|
||||
|
||||
std::string cardType = items[0];
|
||||
if ( cardType == "ND" && items.size() >= 2 )
|
||||
{
|
||||
size_t fileNodeCount = toSizeT( items[1] );
|
||||
if ( mesh->verticesCount() != fileNodeCount )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
|
||||
}
|
||||
else if ( cardType == "NC" && items.size() >= 2 )
|
||||
{
|
||||
size_t fileElemCount = toSizeT( items[1] );
|
||||
if ( mesh->facesCount() != fileElemCount )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
|
||||
}
|
||||
else if ( cardType == "OBJTYPE" )
|
||||
{
|
||||
if ( items[1] != "mesh2d" && items[1] != "\"mesh2d\"" )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
else if ( cardType == "BEGSCL" || cardType == "BEGVEC" )
|
||||
{
|
||||
if ( group )
|
||||
{
|
||||
debug( "New dataset while previous one is still active!" );
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
isVector = cardType == "BEGVEC";
|
||||
|
||||
group = std::make_shared< DatasetGroup >(
|
||||
name(),
|
||||
mesh,
|
||||
mDatFile,
|
||||
groupName
|
||||
);
|
||||
group->setIsScalar( !isVector );
|
||||
group->setIsOnVertices( !faceCentered );
|
||||
}
|
||||
else if ( cardType == "ENDDS" )
|
||||
{
|
||||
if ( !group )
|
||||
{
|
||||
debug( "ENDDS card for no active dataset!" );
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
group->setStatistics( MDAL::calculateStatistics( group ) );
|
||||
mesh->datasetGroups.push_back( group );
|
||||
group.reset();
|
||||
}
|
||||
else if ( cardType == "NAME" && items.size() >= 2 )
|
||||
{
|
||||
if ( !group )
|
||||
{
|
||||
debug( "NAME card for no active dataset!" );
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
|
||||
size_t quoteIdx1 = line.find( '\"' );
|
||||
size_t quoteIdx2 = line.find( '\"', quoteIdx1 + 1 );
|
||||
if ( quoteIdx1 != std::string::npos && quoteIdx2 != std::string::npos )
|
||||
group->setName( line.substr( quoteIdx1 + 1, quoteIdx2 - quoteIdx1 - 1 ) );
|
||||
}
|
||||
else if ( cardType == "TS" && items.size() >= 3 )
|
||||
{
|
||||
double t = toDouble( items[2] );
|
||||
|
||||
if ( faceCentered )
|
||||
{
|
||||
readFaceTimestep( mesh, group, t, isVector, in );
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hasStatus = ( toBool( items[1] ) );
|
||||
readVertexTimestep( mesh, group, t, isVector, hasStatus, in );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream str;
|
||||
str << " Unknown card:" << line;
|
||||
debug( str.str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The DAT format contains "datasets" and each dataset has N-outputs. One output
|
||||
@ -85,147 +273,18 @@ void MDAL::DriverAsciiDat::load( const std::string &datFile, MDAL::Mesh *mesh, M
|
||||
return;
|
||||
}
|
||||
line = trim( line );
|
||||
|
||||
// http://www.xmswiki.com/xms/SMS:ASCII_Dataset_Files_*.dat
|
||||
// Apart from the format specified above, there is an older supported format used in BASEMENT (and SMS?)
|
||||
// which is simpler (has only one dataset in one file, no status flags etc)
|
||||
bool oldFormat;
|
||||
bool isVector = false;
|
||||
|
||||
std::shared_ptr<DatasetGroup> group; // DAT outputs data
|
||||
std::string groupName( MDAL::baseName( mDatFile ) );
|
||||
|
||||
if ( line == "DATASET" )
|
||||
oldFormat = false;
|
||||
else if ( line == "SCALAR" || line == "VECTOR" )
|
||||
if ( canReadNewFormat( line ) )
|
||||
{
|
||||
oldFormat = true;
|
||||
isVector = ( line == "VECTOR" );
|
||||
|
||||
group = std::make_shared< DatasetGroup >(
|
||||
name(),
|
||||
mesh,
|
||||
mDatFile,
|
||||
groupName
|
||||
);
|
||||
group->setIsScalar( !isVector );
|
||||
// we do not need to parse first line again
|
||||
loadNewFormat( in, mesh, status );
|
||||
}
|
||||
else
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
|
||||
// see if it contains face-centered results - supported by BASEMENT
|
||||
bool faceCentered = false;
|
||||
if ( !oldFormat && contains( groupName, "_els_" ) )
|
||||
faceCentered = true;
|
||||
|
||||
if ( group )
|
||||
group->setIsOnVertices( !faceCentered );
|
||||
|
||||
while ( std::getline( in, line ) )
|
||||
{
|
||||
// Replace tabs by spaces,
|
||||
// since basement v.2.8 uses tabs instead of spaces (e.g. 'TS 0\t0.0')
|
||||
line = replace( line, "\t", " " );
|
||||
|
||||
std::vector<std::string> items = split( line, " ", SplitBehaviour::SkipEmptyParts );
|
||||
if ( items.size() < 1 )
|
||||
continue; // empty line?? let's skip it
|
||||
|
||||
std::string cardType = items[0];
|
||||
if ( cardType == "ND" && items.size() >= 2 )
|
||||
{
|
||||
size_t fileNodeCount = toSizeT( items[1] );
|
||||
if ( mesh->verticesCount() != fileNodeCount )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
|
||||
}
|
||||
else if ( !oldFormat && cardType == "NC" && items.size() >= 2 )
|
||||
{
|
||||
size_t fileElemCount = toSizeT( items[1] );
|
||||
if ( mesh->facesCount() != fileElemCount )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_IncompatibleMesh );
|
||||
}
|
||||
else if ( !oldFormat && cardType == "OBJTYPE" )
|
||||
{
|
||||
if ( items[1] != "mesh2d" && items[1] != "\"mesh2d\"" )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
else if ( !oldFormat && ( cardType == "BEGSCL" || cardType == "BEGVEC" ) )
|
||||
{
|
||||
if ( group )
|
||||
{
|
||||
debug( "New dataset while previous one is still active!" );
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
isVector = cardType == "BEGVEC";
|
||||
|
||||
group = std::make_shared< DatasetGroup >(
|
||||
name(),
|
||||
mesh,
|
||||
mDatFile,
|
||||
groupName
|
||||
);
|
||||
group->setIsScalar( !isVector );
|
||||
group->setIsOnVertices( !faceCentered );
|
||||
}
|
||||
else if ( !oldFormat && cardType == "ENDDS" )
|
||||
{
|
||||
if ( !group )
|
||||
{
|
||||
debug( "ENDDS card for no active dataset!" );
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
group->setStatistics( MDAL::calculateStatistics( group ) );
|
||||
mesh->datasetGroups.push_back( group );
|
||||
group.reset();
|
||||
}
|
||||
else if ( !oldFormat && cardType == "NAME" && items.size() >= 2 )
|
||||
{
|
||||
if ( !group )
|
||||
{
|
||||
debug( "NAME card for no active dataset!" );
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
}
|
||||
|
||||
size_t quoteIdx1 = line.find( '\"' );
|
||||
size_t quoteIdx2 = line.find( '\"', quoteIdx1 + 1 );
|
||||
if ( quoteIdx1 != std::string::npos && quoteIdx2 != std::string::npos )
|
||||
group->setName( line.substr( quoteIdx1 + 1, quoteIdx2 - quoteIdx1 - 1 ) );
|
||||
}
|
||||
else if ( oldFormat && ( cardType == "SCALAR" || cardType == "VECTOR" ) )
|
||||
{
|
||||
// just ignore - we know the type from earlier...
|
||||
}
|
||||
else if ( cardType == "TS" && items.size() >= ( oldFormat ? 2 : 3 ) )
|
||||
{
|
||||
double t = toDouble( items[oldFormat ? 1 : 2] );
|
||||
|
||||
if ( faceCentered )
|
||||
{
|
||||
readFaceTimestep( mesh, group, t, isVector, in );
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hasStatus = ( oldFormat ? false : toBool( items[1] ) );
|
||||
readVertexTimestep( mesh, group, t, isVector, hasStatus, in );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream str;
|
||||
str << " Unknown card:" << line;
|
||||
debug( str.str() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( oldFormat )
|
||||
{
|
||||
if ( !group || group->datasets.size() == 0 )
|
||||
EXIT_WITH_ERROR( MDAL_Status::Err_UnknownFormat );
|
||||
|
||||
group->setStatistics( MDAL::calculateStatistics( group ) );
|
||||
mesh->datasetGroups.push_back( group );
|
||||
group.reset();
|
||||
// we need to parse first line again to see
|
||||
// scalar/vector flag or timestep flag
|
||||
in.clear();
|
||||
in.seekg( 0 );
|
||||
loadOldFormat( in, mesh, status );
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +294,7 @@ void MDAL::DriverAsciiDat::readVertexTimestep(
|
||||
double t,
|
||||
bool isVector,
|
||||
bool hasStatus,
|
||||
std::ifstream &stream )
|
||||
std::ifstream &stream ) const
|
||||
{
|
||||
assert( group );
|
||||
size_t faceCount = mesh->facesCount();
|
||||
@ -301,7 +360,7 @@ void MDAL::DriverAsciiDat::readFaceTimestep(
|
||||
std::shared_ptr<DatasetGroup> group,
|
||||
double t,
|
||||
bool isVector,
|
||||
std::ifstream &stream )
|
||||
std::ifstream &stream ) const
|
||||
{
|
||||
assert( group );
|
||||
|
||||
|
34
external/mdal/frmts/mdal_ascii_dat.hpp
vendored
34
external/mdal/frmts/mdal_ascii_dat.hpp
vendored
@ -20,6 +20,29 @@
|
||||
namespace MDAL
|
||||
{
|
||||
|
||||
/**
|
||||
* ASCII Dat format is used by various solvers and the output
|
||||
* from various solvers can have slightly different header.
|
||||
* The format is used by TUFLOW, BASEMENT and HYDRO_AS-2D solvers.
|
||||
*
|
||||
* The most frequent form is based on official SMS documentation
|
||||
* https://www.xmswiki.com/wiki/SMS:ASCII_Dataset_Files_*.dat
|
||||
* The official format only supports data defined on vertices,
|
||||
* both scalar vector. The new format is recognized by keyword
|
||||
* "DATASET" on the first line of the file.
|
||||
*
|
||||
* BASEMENT solver also stores data defined on faces. To recognize
|
||||
* such dataset, the dataset name contains "_els_" substring
|
||||
* (e.g. depth_els_1.dat)
|
||||
*
|
||||
* In one file, there is always one dataset group stored.
|
||||
*
|
||||
* Sometime the "older" datasets may have some part of the
|
||||
* header missing, e.g. the file starts with SCALAR or VECTOR or TS
|
||||
* keyword. The older format does not have "active" flags for faces
|
||||
* and does not recognize most of the keywords. Old format data
|
||||
* are always defined on vertices
|
||||
*/
|
||||
class DriverAsciiDat: public Driver
|
||||
{
|
||||
public:
|
||||
@ -30,22 +53,27 @@ namespace MDAL
|
||||
bool canRead( const std::string &uri ) override;
|
||||
void load( const std::string &datFile, Mesh *mesh, MDAL_Status *status ) override;
|
||||
|
||||
|
||||
private:
|
||||
bool canReadOldFormat( const std::string &line ) const;
|
||||
bool canReadNewFormat( const std::string &line ) const;
|
||||
|
||||
void loadOldFormat( std::ifstream &in, Mesh *mesh, MDAL_Status *status ) const;
|
||||
void loadNewFormat( std::ifstream &in, Mesh *mesh, MDAL_Status *status ) const;
|
||||
|
||||
void readVertexTimestep(
|
||||
const Mesh *mesh,
|
||||
std::shared_ptr<DatasetGroup> group,
|
||||
double t,
|
||||
bool isVector,
|
||||
bool hasStatus,
|
||||
std::ifstream &stream );
|
||||
std::ifstream &stream ) const;
|
||||
|
||||
void readFaceTimestep(
|
||||
const Mesh *mesh,
|
||||
std::shared_ptr<DatasetGroup> group,
|
||||
double t,
|
||||
bool isVector,
|
||||
std::ifstream &stream );
|
||||
std::ifstream &stream ) const;
|
||||
|
||||
std::string mDatFile;
|
||||
};
|
||||
|
7
external/mdal/frmts/mdal_cf.cpp
vendored
7
external/mdal/frmts/mdal_cf.cpp
vendored
@ -5,14 +5,15 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <netcdf.h>
|
||||
#include "math.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mdal_data_model.hpp"
|
||||
#include "mdal_cf.hpp"
|
||||
#include "mdal_utils.hpp"
|
||||
|
||||
#include "math.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define CF_THROW_ERR throw MDAL_Status::Err_UnknownFormat
|
||||
|
||||
MDAL::cfdataset_info_map MDAL::DriverCF::parseDatasetGroupInfo()
|
||||
|
67
external/mdal/frmts/mdal_gdal.cpp
vendored
67
external/mdal/frmts/mdal_gdal.cpp
vendored
@ -259,6 +259,60 @@ void MDAL::DriverGdal::parseRasterBands( const MDAL::GdalDataset *cfGDALDataset
|
||||
}
|
||||
}
|
||||
|
||||
void MDAL::DriverGdal::fixRasterBands()
|
||||
{
|
||||
// go through all bands and find out if both x and y dataset are valid
|
||||
// if such pair if found, make the group scalar by removal of null band pointer
|
||||
// this can happen is parseBandInfo() returns false-positive in vector detection
|
||||
for ( data_hash::iterator band = mBands.begin(); band != mBands.end(); band++ )
|
||||
{
|
||||
if ( band->second.empty() )
|
||||
continue;
|
||||
|
||||
// scalars are always ok
|
||||
bool is_scalar = ( band->second.begin()->second.size() == 1 );
|
||||
if ( is_scalar )
|
||||
continue;
|
||||
|
||||
// check if we have some null bands
|
||||
int needs_fix = false;
|
||||
for ( timestep_map::const_iterator time_step = band->second.begin(); time_step != band->second.end(); time_step++ )
|
||||
{
|
||||
std::vector<GDALRasterBandH> raster_bands = time_step->second;
|
||||
|
||||
if ( !raster_bands[0] )
|
||||
{
|
||||
needs_fix = true;
|
||||
break;
|
||||
}
|
||||
if ( !raster_bands[1] )
|
||||
{
|
||||
needs_fix = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert this vector to scalar
|
||||
if ( needs_fix )
|
||||
{
|
||||
for ( timestep_map::iterator time_step = band->second.begin(); time_step != band->second.end(); time_step++ )
|
||||
{
|
||||
std::vector<GDALRasterBandH> &raster_bands = time_step->second;
|
||||
|
||||
if ( !raster_bands[0] )
|
||||
{
|
||||
raster_bands[0] = raster_bands[1];
|
||||
}
|
||||
// get rid of y-coord
|
||||
raster_bands.resize( 1 );
|
||||
|
||||
// not we should have only 1 band and valid
|
||||
assert( raster_bands[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MDAL::DriverGdal::addDataToOutput( GDALRasterBandH raster_band, std::shared_ptr<MemoryDataset> tos, bool is_vector, bool is_x )
|
||||
{
|
||||
assert( raster_band );
|
||||
@ -335,9 +389,10 @@ void MDAL::DriverGdal::activateFaces( std::shared_ptr<MemoryDataset> tos )
|
||||
Face elem = mMesh->faces.at( idx );
|
||||
for ( size_t i = 0; i < 4; ++i )
|
||||
{
|
||||
const size_t vertexIndex = elem[i];
|
||||
if ( isScalar )
|
||||
{
|
||||
double val = values[elem[i]];
|
||||
double val = values[vertexIndex];
|
||||
if ( std::isnan( val ) )
|
||||
{
|
||||
active[idx] = 0; //NOT ACTIVE
|
||||
@ -346,8 +401,8 @@ void MDAL::DriverGdal::activateFaces( std::shared_ptr<MemoryDataset> tos )
|
||||
}
|
||||
else
|
||||
{
|
||||
double x = values[elem[2 * i]];
|
||||
double y = values[elem[2 * i + 1]];
|
||||
double x = values[2 * vertexIndex];
|
||||
double y = values[2 * vertexIndex + 1];
|
||||
if ( std::isnan( x ) || std::isnan( y ) )
|
||||
{
|
||||
active[idx] = 0; //NOT ACTIVE
|
||||
@ -551,6 +606,12 @@ std::unique_ptr<MDAL::Mesh> MDAL::DriverGdal::load( const std::string &fileName,
|
||||
}
|
||||
}
|
||||
|
||||
// Fix consistency of groups
|
||||
// It can happen that we thought that the
|
||||
// group is vector based on name, but it could be just coicidence
|
||||
// or clash in naming
|
||||
fixRasterBands();
|
||||
|
||||
// Create MDAL datasets
|
||||
addDatasetGroups();
|
||||
}
|
||||
|
1
external/mdal/frmts/mdal_gdal.hpp
vendored
1
external/mdal/frmts/mdal_gdal.hpp
vendored
@ -94,6 +94,7 @@ namespace MDAL
|
||||
void addDatasetGroups();
|
||||
void createMesh();
|
||||
void parseRasterBands( const GdalDataset *cfGDALDataset );
|
||||
void fixRasterBands();
|
||||
|
||||
std::string mFileName;
|
||||
const std::string mGdalDriverName; /* GDAL driver name */
|
||||
|
112
external/mdal/frmts/mdal_hec2d.cpp
vendored
112
external/mdal/frmts/mdal_hec2d.cpp
vendored
@ -164,7 +164,7 @@ void MDAL::DriverHec2D::readFaceOutput( const HdfFile &hdfFile,
|
||||
{
|
||||
for ( size_t c = 0; c < 2; ++c )
|
||||
{
|
||||
size_t cell_idx = face2Cells[2 * i + c] + areaElemStartIndex[nArea];
|
||||
size_t cell_idx = static_cast<size_t>( face2Cells[2 * i + c] ) + areaElemStartIndex[nArea];
|
||||
// Take just maximum
|
||||
if ( std::isnan( values[cell_idx] ) || values[cell_idx] < val )
|
||||
{
|
||||
@ -356,7 +356,7 @@ void MDAL::DriverHec2D::readElemResults(
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<std::string> read2DFlowAreasNames( HdfGroup gGeom2DFlowAreas )
|
||||
std::vector<std::string> MDAL::DriverHec2D::read2DFlowAreasNamesOld( HdfGroup gGeom2DFlowAreas ) const
|
||||
{
|
||||
HdfDataset dsNames = openHdfDataset( gGeom2DFlowAreas, "Names" );
|
||||
std::vector<std::string> names = dsNames.readArrayString();
|
||||
@ -367,6 +367,85 @@ std::vector<std::string> read2DFlowAreasNames( HdfGroup gGeom2DFlowAreas )
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
For 5.0.5+ format
|
||||
|
||||
DATATYPE H5T_COMPOUND {
|
||||
H5T_STRING {
|
||||
STRSIZE 16;
|
||||
STRPAD H5T_STR_NULLTERM;
|
||||
CSET H5T_CSET_ASCII;
|
||||
CTYPE H5T_C_S1;
|
||||
} "Name";
|
||||
H5T_IEEE_F32LE "Mann";
|
||||
H5T_IEEE_F32LE "Cell Vol Tol";
|
||||
H5T_IEEE_F32LE "Cell Min Area Fraction";
|
||||
H5T_IEEE_F32LE "Face Profile Tol";
|
||||
H5T_IEEE_F32LE "Face Area Tol";
|
||||
H5T_IEEE_F32LE "Face Conv Ratio";
|
||||
H5T_IEEE_F32LE "Laminar Depth";
|
||||
H5T_IEEE_F32LE "Spacing dx";
|
||||
H5T_IEEE_F32LE "Spacing dy";
|
||||
H5T_IEEE_F32LE "Shift dx";
|
||||
H5T_IEEE_F32LE "Shift dy";
|
||||
H5T_STD_I32LE "Cell Count";
|
||||
}
|
||||
*/
|
||||
typedef struct FlowAreasAttribute505
|
||||
{
|
||||
char name[HDF_MAX_NAME];
|
||||
float mann;
|
||||
float cellVolTol;
|
||||
float cellMinAreaFraction;
|
||||
float faceProfileTol;
|
||||
float faceAreaTol;
|
||||
float faceConvRatio;
|
||||
float laminarDepth;
|
||||
float spacingDx;
|
||||
float spacingDy;
|
||||
float shifyDx;
|
||||
float shifyDy;
|
||||
int cellCount;
|
||||
} FlowAreasAttribute505;
|
||||
|
||||
|
||||
std::vector<std::string> MDAL::DriverHec2D::read2DFlowAreasNames505( HdfGroup gGeom2DFlowAreas ) const
|
||||
{
|
||||
HdfDataset dsAttributes = openHdfDataset( gGeom2DFlowAreas, "Attributes" );
|
||||
hid_t attributeHID = H5Tcreate( H5T_COMPOUND, sizeof( FlowAreasAttribute505 ) );
|
||||
hid_t stringHID = H5Tcopy( H5T_C_S1 );
|
||||
H5Tset_size( stringHID, HDF_MAX_NAME );
|
||||
H5Tinsert( attributeHID, "Name", HOFFSET( FlowAreasAttribute505, name ), stringHID );
|
||||
H5Tinsert( attributeHID, "Mann", HOFFSET( FlowAreasAttribute505, mann ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Cell Vol Tol", HOFFSET( FlowAreasAttribute505, cellVolTol ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Cell Min Area Fraction", HOFFSET( FlowAreasAttribute505, cellMinAreaFraction ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Face Profile Tol", HOFFSET( FlowAreasAttribute505, faceProfileTol ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Face Area Tol", HOFFSET( FlowAreasAttribute505, faceAreaTol ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Face Conv Ratio", HOFFSET( FlowAreasAttribute505, faceConvRatio ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Laminar Depth", HOFFSET( FlowAreasAttribute505, laminarDepth ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Spacing dx", HOFFSET( FlowAreasAttribute505, spacingDx ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Spacing dy", HOFFSET( FlowAreasAttribute505, spacingDy ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Shift dx", HOFFSET( FlowAreasAttribute505, shifyDx ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Shift dy", HOFFSET( FlowAreasAttribute505, shifyDy ), H5T_NATIVE_FLOAT );
|
||||
H5Tinsert( attributeHID, "Cell Count", HOFFSET( FlowAreasAttribute505, cellCount ), H5T_NATIVE_INT );
|
||||
std::vector<FlowAreasAttribute505> attributes = dsAttributes.readArray<FlowAreasAttribute505>( attributeHID );
|
||||
H5Tclose( attributeHID );
|
||||
H5Tclose( stringHID );
|
||||
std::vector<std::string> names;
|
||||
if ( attributes.empty() )
|
||||
{
|
||||
throw MDAL_Status::Err_InvalidData;
|
||||
}
|
||||
|
||||
for ( const auto &attr : attributes )
|
||||
{
|
||||
std::string dat = std::string( attr.name );
|
||||
names.push_back( MDAL::trim( dat ) );
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
void MDAL::DriverHec2D::setProjection( HdfFile hdfFile )
|
||||
{
|
||||
try
|
||||
@ -474,16 +553,22 @@ bool MDAL::DriverHec2D::canRead( const std::string &uri )
|
||||
{
|
||||
HdfFile hdfFile = openHdfFile( uri );
|
||||
std::string fileType = openHdfAttribute( hdfFile, "File Type" );
|
||||
if ( fileType != "HEC-RAS Results" )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return canReadOldFormat( fileType ) || canReadFormat505( fileType );
|
||||
}
|
||||
catch ( MDAL_Status )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MDAL::DriverHec2D::canReadOldFormat( const std::string &fileType ) const
|
||||
{
|
||||
return fileType == "HEC-RAS Results";
|
||||
}
|
||||
|
||||
bool MDAL::DriverHec2D::canReadFormat505( const std::string &fileType ) const
|
||||
{
|
||||
return fileType == "HEC-RAS Geometry";
|
||||
}
|
||||
|
||||
std::unique_ptr<MDAL::Mesh> MDAL::DriverHec2D::load( const std::string &resultsFile, MDAL_Status *status )
|
||||
@ -498,15 +583,17 @@ std::unique_ptr<MDAL::Mesh> MDAL::DriverHec2D::load( const std::string &resultsF
|
||||
|
||||
// Verify it is correct file
|
||||
std::string fileType = openHdfAttribute( hdfFile, "File Type" );
|
||||
if ( fileType != "HEC-RAS Results" )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
bool oldFormat = canReadOldFormat( fileType );
|
||||
|
||||
HdfGroup gGeom = openHdfGroup( hdfFile, "Geometry" );
|
||||
HdfGroup gGeom2DFlowAreas = openHdfGroup( gGeom, "2D Flow Areas" );
|
||||
|
||||
std::vector<std::string> flowAreaNames = read2DFlowAreasNames( gGeom2DFlowAreas );
|
||||
std::vector<std::string> flowAreaNames;
|
||||
if ( oldFormat )
|
||||
flowAreaNames = read2DFlowAreasNamesOld( gGeom2DFlowAreas );
|
||||
else
|
||||
flowAreaNames = read2DFlowAreasNames505( gGeom2DFlowAreas );
|
||||
|
||||
std::vector<size_t> areaElemStartIndex( flowAreaNames.size() + 1 );
|
||||
|
||||
parseMesh( gGeom2DFlowAreas, areaElemStartIndex, flowAreaNames );
|
||||
@ -520,6 +607,7 @@ std::unique_ptr<MDAL::Mesh> MDAL::DriverHec2D::load( const std::string &resultsF
|
||||
|
||||
// Face centered Values
|
||||
readFaceResults( hdfFile, areaElemStartIndex, flowAreaNames );
|
||||
|
||||
}
|
||||
catch ( MDAL_Status error )
|
||||
{
|
||||
|
26
external/mdal/frmts/mdal_hec2d.hpp
vendored
26
external/mdal/frmts/mdal_hec2d.hpp
vendored
@ -16,6 +16,17 @@
|
||||
|
||||
namespace MDAL
|
||||
{
|
||||
/**
|
||||
* HEC-RAS 2D format.
|
||||
*
|
||||
* This is a HDF5-based format to store mesh and datasets
|
||||
* in a single file. The format supports meshes is multiple
|
||||
* (disconnected) areas.
|
||||
*
|
||||
* There is a small change in the format in HEC-RAS 5.0.5+, where
|
||||
* - Header File Type is different (HEC-RAS Results vs HEC-RAS Geometry)
|
||||
* - Names or areas are stored in different place (names array vs attributes array)
|
||||
*/
|
||||
class DriverHec2D: public Driver
|
||||
{
|
||||
public:
|
||||
@ -30,6 +41,15 @@ namespace MDAL
|
||||
std::unique_ptr< MDAL::MemoryMesh > mMesh;
|
||||
std::string mFileName;
|
||||
|
||||
// Pre 5.0.5 format
|
||||
bool canReadOldFormat( const std::string &fileType ) const;
|
||||
std::vector<std::string> read2DFlowAreasNamesOld( HdfGroup gGeom2DFlowAreas ) const;
|
||||
|
||||
// 5.0.5 + format
|
||||
bool canReadFormat505( const std::string &fileType ) const;
|
||||
std::vector<std::string> read2DFlowAreasNames505( HdfGroup gGeom2DFlowAreas ) const;
|
||||
|
||||
// Common functions
|
||||
void readFaceOutput( const HdfFile &hdfFile,
|
||||
const HdfGroup &rootGroup,
|
||||
const std::vector<size_t> &areaElemStartIndex,
|
||||
@ -37,9 +57,11 @@ namespace MDAL
|
||||
const std::string rawDatasetName,
|
||||
const std::string datasetName,
|
||||
const std::vector<float> × );
|
||||
|
||||
void readFaceResults( const HdfFile &hdfFile,
|
||||
const std::vector<size_t> &areaElemStartIndex,
|
||||
const std::vector<std::string> &flowAreaNames );
|
||||
|
||||
std::shared_ptr<MDAL::MemoryDataset> readElemOutput(
|
||||
const HdfGroup &rootGroup,
|
||||
const std::vector<size_t> &areaElemStartIndex,
|
||||
@ -48,14 +70,18 @@ namespace MDAL
|
||||
const std::string datasetName,
|
||||
const std::vector<float> ×,
|
||||
std::shared_ptr<MDAL::MemoryDataset> bed_elevation );
|
||||
|
||||
std::shared_ptr<MDAL::MemoryDataset> readBedElevation(
|
||||
const HdfGroup &gGeom2DFlowAreas,
|
||||
const std::vector<size_t> &areaElemStartIndex,
|
||||
const std::vector<std::string> &flowAreaNames );
|
||||
|
||||
void setProjection( HdfFile hdfFile );
|
||||
|
||||
void parseMesh( HdfGroup gGeom2DFlowAreas,
|
||||
std::vector<size_t> &areaElemStartIndex,
|
||||
const std::vector<std::string> &flowAreaNames );
|
||||
|
||||
void readElemResults(
|
||||
const HdfFile &hdfFile,
|
||||
std::shared_ptr<MDAL::MemoryDataset> bed_elevation,
|
||||
|
206
external/mdal/frmts/mdal_netcdf.cpp
vendored
Normal file
206
external/mdal/frmts/mdal_netcdf.cpp
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
MDAL - Mesh Data Abstraction Library (MIT License)
|
||||
Copyright (C) 2019 Peter Petrik (zilolv at gmail dot com)
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include <netcdf.h>
|
||||
#include "mdal_netcdf.hpp"
|
||||
#include "mdal.h"
|
||||
#include "mdal_utils.hpp"
|
||||
|
||||
NetCDFFile::NetCDFFile(): mNcid( 0 ) {}
|
||||
|
||||
NetCDFFile::~NetCDFFile()
|
||||
{
|
||||
if ( mNcid != 0 ) nc_close( mNcid );
|
||||
}
|
||||
|
||||
int NetCDFFile::handle() const
|
||||
{
|
||||
return mNcid;
|
||||
}
|
||||
|
||||
void NetCDFFile::openFile( const std::string &fileName )
|
||||
{
|
||||
int res = nc_open( fileName.c_str(), NC_NOWRITE, &mNcid );
|
||||
if ( res != NC_NOERR )
|
||||
{
|
||||
MDAL::debug( nc_strerror( res ) );
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
}
|
||||
|
||||
bool NetCDFFile::hasVariable( const std::string &name ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
int varid;
|
||||
return ( nc_inq_varid( mNcid, name.c_str(), &varid ) == NC_NOERR );
|
||||
}
|
||||
|
||||
std::vector<int> NetCDFFile::readIntArr( const std::string &name, size_t dim ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
std::vector<int> arr_val( dim );
|
||||
if ( nc_get_var_int( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
return arr_val;
|
||||
}
|
||||
|
||||
std::vector<double> NetCDFFile::readDoubleArr( const std::string &name, size_t dim ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
std::vector<double> arr_val( dim );
|
||||
if ( nc_get_var_double( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
return arr_val;
|
||||
}
|
||||
|
||||
bool NetCDFFile::hasArr( const std::string &name ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
int arr_id;
|
||||
return nc_inq_varid( mNcid, name.c_str(), &arr_id ) == NC_NOERR;
|
||||
}
|
||||
|
||||
std::vector<std::string> NetCDFFile::readArrNames() const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
std::vector<std::string> res;
|
||||
int nvars;
|
||||
if ( nc_inq_varids( mNcid, &nvars, nullptr ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
|
||||
std::vector<int> varids( static_cast<size_t>( nvars ) );
|
||||
if ( nc_inq_varids( mNcid, &nvars, varids.data() ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < static_cast<size_t>( nvars ); ++i )
|
||||
{
|
||||
std::vector<char> cname( NC_MAX_NAME + 1 );
|
||||
if ( nc_inq_varname( mNcid, varids[i], cname.data() ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
res.push_back( cname.data() );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int NetCDFFile::getAttrInt( const std::string &name, const std::string &attr_name ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
|
||||
int val;
|
||||
if ( nc_get_att_int( mNcid, arr_id, attr_name.c_str(), &val ) )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
std::string NetCDFFile::getAttrStr( const std::string &name, const std::string &attr_name ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) ) throw MDAL_Status::Err_UnknownFormat;
|
||||
return getAttrStr( attr_name, arr_id );
|
||||
}
|
||||
|
||||
std::string NetCDFFile::getAttrStr( const std::string &name, int varid ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
size_t attlen = 0;
|
||||
|
||||
if ( nc_inq_attlen( mNcid, varid, name.c_str(), &attlen ) )
|
||||
{
|
||||
// attribute is missing
|
||||
return std::string();
|
||||
}
|
||||
|
||||
char *string_attr;
|
||||
string_attr = ( char * ) malloc( attlen + 1 );
|
||||
|
||||
if ( nc_get_att_text( mNcid, varid, name.c_str(), string_attr ) ) throw MDAL_Status::Err_UnknownFormat;
|
||||
string_attr[attlen] = '\0';
|
||||
|
||||
std::string res( string_attr );
|
||||
free( string_attr );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
double NetCDFFile::getFillValue( int varid ) const
|
||||
{
|
||||
return getAttrDouble( varid, "_FillValue" );
|
||||
}
|
||||
|
||||
double NetCDFFile::getAttrDouble( int varid, const std::string &attr_name ) const
|
||||
{
|
||||
double res;
|
||||
if ( nc_get_att_double( mNcid, varid, attr_name.c_str(), &res ) )
|
||||
res = std::numeric_limits<double>::quiet_NaN(); // not present/set
|
||||
return res;
|
||||
}
|
||||
|
||||
int NetCDFFile::getVarId( const std::string &name )
|
||||
{
|
||||
int ncid_val;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
|
||||
return ncid_val;
|
||||
}
|
||||
|
||||
void NetCDFFile::getDimension( const std::string &name, size_t *val, int *ncid_val ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
if ( nc_inq_dimid( mNcid, name.c_str(), ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
|
||||
if ( nc_inq_dimlen( mNcid, *ncid_val, val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
|
||||
void NetCDFFile::getDimensionOptional( const std::string &name, size_t *val, int *ncid_val ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
try
|
||||
{
|
||||
getDimension( name, val, ncid_val );
|
||||
}
|
||||
catch ( MDAL_Status )
|
||||
{
|
||||
*ncid_val = -1;
|
||||
*val = 0;
|
||||
}
|
||||
}
|
175
external/mdal/frmts/mdal_netcdf.hpp
vendored
175
external/mdal/frmts/mdal_netcdf.hpp
vendored
@ -8,168 +8,35 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include <netcdf.h>
|
||||
#include "mdal_utils.hpp"
|
||||
#include "mdal.h"
|
||||
|
||||
//! C++ Wrapper around netcdf C library
|
||||
class NetCDFFile
|
||||
{
|
||||
public:
|
||||
NetCDFFile(): mNcid( 0 ) {}
|
||||
~NetCDFFile()
|
||||
{
|
||||
if ( mNcid != 0 ) nc_close( mNcid );
|
||||
}
|
||||
//! Create file with invalid handle
|
||||
NetCDFFile();
|
||||
//! Closes the file
|
||||
~NetCDFFile();
|
||||
|
||||
int handle() const
|
||||
{
|
||||
return mNcid;
|
||||
}
|
||||
int handle() const;
|
||||
void openFile( const std::string &fileName );
|
||||
bool hasVariable( const std::string &name ) const;
|
||||
|
||||
void openFile( const std::string &fileName )
|
||||
{
|
||||
int res = nc_open( fileName.c_str(), NC_NOWRITE, &mNcid );
|
||||
if ( res != NC_NOERR )
|
||||
{
|
||||
MDAL::debug( nc_strerror( res ) );
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
}
|
||||
std::vector<int> readIntArr( const std::string &name, size_t dim ) const;
|
||||
std::vector<double> readDoubleArr( const std::string &name, size_t dim ) const;
|
||||
bool hasArr( const std::string &name ) const;
|
||||
std::vector<std::string> readArrNames() const;
|
||||
|
||||
bool hasVariable( const std::string &name ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
int varid;
|
||||
return ( nc_inq_varid( mNcid, name.c_str(), &varid ) == NC_NOERR );
|
||||
}
|
||||
|
||||
std::vector<int> readIntArr( const std::string &name, size_t dim ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
std::vector<int> arr_val( dim );
|
||||
if ( nc_get_var_int( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
return arr_val;
|
||||
}
|
||||
|
||||
|
||||
std::vector<double> readDoubleArr( const std::string &name, size_t dim ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
std::vector<double> arr_val( dim );
|
||||
if ( nc_get_var_double( mNcid, arr_id, arr_val.data() ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
return arr_val;
|
||||
}
|
||||
|
||||
|
||||
int getAttrInt( const std::string &name, const std::string &attr_name ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) != NC_NOERR )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
|
||||
int val;
|
||||
if ( nc_get_att_int( mNcid, arr_id, attr_name.c_str(), &val ) )
|
||||
{
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
std::string getAttrStr( const std::string &name, const std::string &attr_name ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
int arr_id;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &arr_id ) ) throw MDAL_Status::Err_UnknownFormat;
|
||||
return getAttrStr( attr_name, arr_id );
|
||||
}
|
||||
|
||||
std::string getAttrStr( const std::string &name, int varid ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
size_t attlen = 0;
|
||||
|
||||
if ( nc_inq_attlen( mNcid, varid, name.c_str(), &attlen ) )
|
||||
{
|
||||
// attribute is missing
|
||||
return std::string();
|
||||
}
|
||||
|
||||
char *string_attr;
|
||||
string_attr = ( char * ) malloc( attlen + 1 );
|
||||
|
||||
if ( nc_get_att_text( mNcid, varid, name.c_str(), string_attr ) ) throw MDAL_Status::Err_UnknownFormat;
|
||||
string_attr[attlen] = '\0';
|
||||
|
||||
std::string res( string_attr );
|
||||
free( string_attr );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
double getFillValue( int varid ) const
|
||||
{
|
||||
double fill;
|
||||
if ( nc_get_att_double( mNcid, varid, "_FillValue", &fill ) )
|
||||
fill = std::numeric_limits<double>::quiet_NaN(); // not present/set
|
||||
return fill;
|
||||
}
|
||||
|
||||
int getVarId( const std::string &name )
|
||||
{
|
||||
int ncid_val;
|
||||
if ( nc_inq_varid( mNcid, name.c_str(), &ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
|
||||
return ncid_val;
|
||||
}
|
||||
|
||||
void getDimension( const std::string &name, size_t *val, int *ncid_val ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
if ( nc_inq_dimid( mNcid, name.c_str(), ncid_val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
|
||||
if ( nc_inq_dimlen( mNcid, *ncid_val, val ) != NC_NOERR ) throw MDAL_Status::Err_UnknownFormat;
|
||||
}
|
||||
|
||||
void getDimensionOptional( const std::string &name, size_t *val, int *ncid_val ) const
|
||||
{
|
||||
assert( mNcid != 0 );
|
||||
|
||||
try
|
||||
{
|
||||
getDimension( name, val, ncid_val );
|
||||
}
|
||||
catch ( MDAL_Status )
|
||||
{
|
||||
*ncid_val = -1;
|
||||
*val = 0;
|
||||
}
|
||||
}
|
||||
int getAttrInt( const std::string &name, const std::string &attr_name ) const;
|
||||
double getAttrDouble( int varid, const std::string &attr_name ) const;
|
||||
std::string getAttrStr( const std::string &name, const std::string &attr_name ) const;
|
||||
std::string getAttrStr( const std::string &name, int varid ) const;
|
||||
double getFillValue( int varid ) const;
|
||||
int getVarId( const std::string &name );
|
||||
void getDimension( const std::string &name, size_t *val, int *ncid_val ) const;
|
||||
void getDimensionOptional( const std::string &name, size_t *val, int *ncid_val ) const;
|
||||
private:
|
||||
int mNcid;
|
||||
|
||||
int mNcid; // C handle to the file
|
||||
};
|
||||
|
||||
#endif // MDAL_NETCDF_HPP
|
||||
|
761
external/mdal/frmts/mdal_sww.cpp
vendored
761
external/mdal/frmts/mdal_sww.cpp
vendored
@ -7,14 +7,11 @@
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <netcdf.h>
|
||||
#include <set>
|
||||
|
||||
#include "mdal_netcdf.hpp"
|
||||
#include "mdal_sww.hpp"
|
||||
|
||||
// threshold for determining whether an element is active (wet)
|
||||
// the format does not explicitly store that information so we
|
||||
// determine that when loading data
|
||||
#define DEPTH_THRESHOLD 0.0001 // in meters
|
||||
#include "mdal_utils.hpp"
|
||||
|
||||
MDAL::DriverSWW::DriverSWW()
|
||||
: Driver( "SWW",
|
||||
@ -29,350 +26,442 @@ MDAL::DriverSWW *MDAL::DriverSWW::create()
|
||||
return new DriverSWW();
|
||||
}
|
||||
|
||||
bool MDAL::DriverSWW::canRead( const std::string &uri )
|
||||
size_t MDAL::DriverSWW::getVertexCount( const NetCDFFile &ncFile ) const
|
||||
{
|
||||
int ncid;
|
||||
int res;
|
||||
|
||||
// open
|
||||
res = nc_open( uri.c_str(), NC_NOWRITE, &ncid );
|
||||
if ( res != NC_NOERR )
|
||||
{
|
||||
MDAL::debug( nc_strerror( res ) );
|
||||
nc_close( ncid );
|
||||
return false;
|
||||
}
|
||||
|
||||
// get dimensions
|
||||
int nVolumesId, nVerticesId, nPointsId, nTimestepsId;
|
||||
if ( nc_inq_dimid( ncid, "number_of_volumes", &nVolumesId ) != NC_NOERR ||
|
||||
nc_inq_dimid( ncid, "number_of_vertices", &nVerticesId ) != NC_NOERR ||
|
||||
nc_inq_dimid( ncid, "number_of_points", &nPointsId ) != NC_NOERR ||
|
||||
nc_inq_dimid( ncid, "number_of_timesteps", &nTimestepsId ) != NC_NOERR )
|
||||
{
|
||||
nc_close( ncid );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
int nPointsId;
|
||||
size_t res;
|
||||
ncFile.getDimension( "number_of_points", &res, &nPointsId );
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<MDAL::Mesh> MDAL::DriverSWW::load( const std::string &resultsFile,
|
||||
MDAL_Status *status )
|
||||
bool MDAL::DriverSWW::canRead( const std::string &uri )
|
||||
{
|
||||
NetCDFFile ncFile;
|
||||
|
||||
try
|
||||
{
|
||||
ncFile.openFile( uri );
|
||||
getVertexCount( ncFile );
|
||||
}
|
||||
catch ( MDAL_Status )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<double> MDAL::DriverSWW::readZCoords( const NetCDFFile &ncFile ) const
|
||||
{
|
||||
size_t nPoints = getVertexCount( ncFile );
|
||||
|
||||
std::vector<double> pz;
|
||||
// newer sww files does have elevation array that is time-dependent
|
||||
if ( ncFile.hasArr( "z" ) )
|
||||
{
|
||||
pz = ncFile.readDoubleArr( "z", nPoints );
|
||||
}
|
||||
else if ( ncFile.hasArr( "elevation" ) )
|
||||
{
|
||||
int zDims = 0;
|
||||
int zid;
|
||||
if ( nc_inq_varid( ncFile.handle(), "elevation", &zid ) == NC_NOERR &&
|
||||
nc_inq_varndims( ncFile.handle(), zid, &zDims ) == NC_NOERR )
|
||||
{
|
||||
if ( zDims == 1 )
|
||||
{
|
||||
// just one elevation for all times, treat as z coord
|
||||
pz = ncFile.readDoubleArr( "elevation", nPoints );
|
||||
}
|
||||
else
|
||||
{
|
||||
pz.resize( nPoints );
|
||||
// fetching "elevation" data for the first timestep,
|
||||
// and threat it as z coord
|
||||
size_t start[2], count[2];
|
||||
const ptrdiff_t stride[2] = {1, 1};
|
||||
start[0] = 0; // t = 0
|
||||
start[1] = 0;
|
||||
count[0] = 1;
|
||||
count[1] = nPoints;
|
||||
nc_get_vars_double( ncFile.handle(), zid, start, count, stride, pz.data() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pz;
|
||||
}
|
||||
|
||||
void MDAL::DriverSWW::addBedElevation( const NetCDFFile &ncFile,
|
||||
MDAL::MemoryMesh *mesh,
|
||||
const std::vector<double> ×
|
||||
) const
|
||||
{
|
||||
if ( ncFile.hasArr( "elevation" ) )
|
||||
{
|
||||
std::shared_ptr<MDAL::DatasetGroup> grp = readScalarGroup( ncFile,
|
||||
mesh,
|
||||
times,
|
||||
"Bed Elevation",
|
||||
"elevation" );
|
||||
mesh->datasetGroups.push_back( grp );
|
||||
}
|
||||
else
|
||||
{
|
||||
MDAL::addBedElevationDatasetGroup( mesh, mesh->vertices );
|
||||
}
|
||||
}
|
||||
|
||||
MDAL::Vertices MDAL::DriverSWW::readVertices( const NetCDFFile &ncFile ) const
|
||||
{
|
||||
size_t nPoints = getVertexCount( ncFile );
|
||||
|
||||
// load mesh data
|
||||
std::vector<double> px = ncFile.readDoubleArr( "x", nPoints );
|
||||
std::vector<double> py = ncFile.readDoubleArr( "y", nPoints );
|
||||
std::vector<double> pz = readZCoords( ncFile );
|
||||
|
||||
// we may need to apply a shift to the X,Y coordinates
|
||||
double xLLcorner = ncFile.getAttrDouble( NC_GLOBAL, "xllcorner" );
|
||||
double yLLcorner = ncFile.getAttrDouble( NC_GLOBAL, "yllcorner" );
|
||||
|
||||
MDAL::Vertices vertices( nPoints );
|
||||
Vertex *vertexPtr = vertices.data();
|
||||
for ( size_t i = 0; i < nPoints; ++i, ++vertexPtr )
|
||||
{
|
||||
vertexPtr->x = px[i] + xLLcorner ;
|
||||
vertexPtr->y = py[i] + yLLcorner ;
|
||||
if ( !pz.empty() ) // missing both "z" and "elevation"
|
||||
vertexPtr->z = pz[i];
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
|
||||
MDAL::Faces MDAL::DriverSWW::readFaces( const NetCDFFile &ncFile ) const
|
||||
{
|
||||
// get dimensions
|
||||
int nVolumesId, nVerticesId;
|
||||
size_t nVolumes, nVertices;
|
||||
ncFile.getDimension( "number_of_volumes", &nVolumes, &nVolumesId );
|
||||
ncFile.getDimension( "number_of_vertices", &nVertices, &nVerticesId );
|
||||
if ( nVertices != 3 )
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
|
||||
std::vector<int> pvolumes = ncFile.readIntArr( "volumes", nVertices * nVolumes );
|
||||
|
||||
MDAL::Faces faces( nVolumes );
|
||||
for ( size_t i = 0; i < nVolumes; ++i )
|
||||
{
|
||||
faces[i].resize( 3 );
|
||||
faces[i][0] = static_cast<size_t>( pvolumes[3 * i + 0] );
|
||||
faces[i][1] = static_cast<size_t>( pvolumes[3 * i + 1] );
|
||||
faces[i][2] = static_cast<size_t>( pvolumes[3 * i + 2] );
|
||||
}
|
||||
return faces;
|
||||
}
|
||||
|
||||
std::vector<double> MDAL::DriverSWW::readTimes( const NetCDFFile &ncFile ) const
|
||||
{
|
||||
size_t nTimesteps;
|
||||
int nTimestepsId;
|
||||
ncFile.getDimension( "number_of_timesteps", &nTimesteps, &nTimestepsId );
|
||||
std::vector<double> times = ncFile.readDoubleArr( "time", nTimesteps );
|
||||
return times;
|
||||
}
|
||||
|
||||
void MDAL::DriverSWW::readDatasetGroups(
|
||||
const NetCDFFile &ncFile,
|
||||
MDAL::MemoryMesh *mesh,
|
||||
const std::vector<double> ×
|
||||
) const
|
||||
{
|
||||
std::set<std::string> parsedVariableNames; // already parsed arrays somewhere else
|
||||
parsedVariableNames.insert( "x" );
|
||||
parsedVariableNames.insert( "y" );
|
||||
parsedVariableNames.insert( "z" );
|
||||
parsedVariableNames.insert( "volumes" );
|
||||
parsedVariableNames.insert( "time" );
|
||||
|
||||
std::vector<std::string> names = ncFile.readArrNames();
|
||||
std::set<std::string> namesSet( names.begin(), names.end() );
|
||||
|
||||
// Add bed elevation group
|
||||
parsedVariableNames.insert( "elevations" );
|
||||
addBedElevation( ncFile, mesh, times );
|
||||
|
||||
for ( const std::string &name : names )
|
||||
{
|
||||
// skip already parsed variables
|
||||
if ( parsedVariableNames.find( name ) == parsedVariableNames.cend() )
|
||||
{
|
||||
std::string xName, yName, groupName( name );
|
||||
bool isVector = parseGroupName( groupName, xName, yName );
|
||||
|
||||
std::shared_ptr<MDAL::DatasetGroup> grp;
|
||||
if ( isVector && ncFile.hasArr( xName ) && ncFile.hasArr( yName ) )
|
||||
{
|
||||
// vector dataset group
|
||||
grp = readVectorGroup(
|
||||
ncFile,
|
||||
mesh,
|
||||
times,
|
||||
groupName,
|
||||
xName,
|
||||
yName );
|
||||
parsedVariableNames.insert( xName );
|
||||
parsedVariableNames.insert( yName );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// scalar dataset group
|
||||
grp = readScalarGroup(
|
||||
ncFile,
|
||||
mesh,
|
||||
times,
|
||||
groupName,
|
||||
name );
|
||||
parsedVariableNames.insert( name );
|
||||
}
|
||||
if ( grp )
|
||||
mesh->datasetGroups.push_back( grp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MDAL::DriverSWW::parseGroupName( std::string &groupName,
|
||||
std::string &xName,
|
||||
std::string &yName ) const
|
||||
{
|
||||
bool isVector = false;
|
||||
std::string baseName( groupName );
|
||||
|
||||
// X and Y variables
|
||||
if ( groupName.size() > 1 )
|
||||
{
|
||||
if ( MDAL::startsWith( groupName, "x" ) )
|
||||
{
|
||||
baseName = groupName.substr( 1, groupName.size() - 1 );
|
||||
xName = groupName;
|
||||
yName = "y" + baseName;
|
||||
isVector = true;
|
||||
}
|
||||
else if ( MDAL::startsWith( groupName, "y" ) )
|
||||
{
|
||||
baseName = groupName.substr( 1, groupName.size() - 1 );
|
||||
xName = "x" + baseName;
|
||||
yName = groupName;
|
||||
isVector = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Maximums
|
||||
groupName = baseName;
|
||||
if ( MDAL::endsWith( baseName, "_range" ) )
|
||||
{
|
||||
groupName = groupName.substr( 0, baseName.size() - 6 ) + "/Maximums";
|
||||
}
|
||||
|
||||
return isVector;
|
||||
}
|
||||
|
||||
std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverSWW::readScalarGroup(
|
||||
const NetCDFFile &ncFile,
|
||||
MDAL::MemoryMesh *mesh,
|
||||
const std::vector<double> ×,
|
||||
const std::string groupName,
|
||||
const std::string arrName
|
||||
) const
|
||||
{
|
||||
size_t nPoints = getVertexCount( ncFile );
|
||||
std::shared_ptr<MDAL::DatasetGroup> mds;
|
||||
|
||||
int varxid;
|
||||
if ( nc_inq_varid( ncFile.handle(), arrName.c_str(), &varxid ) == NC_NOERR )
|
||||
{
|
||||
mds = std::make_shared<MDAL::DatasetGroup> (
|
||||
name(),
|
||||
mesh,
|
||||
mFileName,
|
||||
groupName );
|
||||
mds->setIsOnVertices( true );
|
||||
mds->setIsScalar( true );
|
||||
|
||||
int zDimsX = 0;
|
||||
if ( nc_inq_varndims( ncFile.handle(), varxid, &zDimsX ) != NC_NOERR )
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
|
||||
if ( zDimsX == 1 )
|
||||
{
|
||||
// TIME INDEPENDENT
|
||||
std::shared_ptr<MDAL::MemoryDataset> o = std::make_shared<MDAL::MemoryDataset>( mds.get() );
|
||||
o->setTime( 0.0 );
|
||||
double *values = o->values();
|
||||
std::vector<double> valuesX = ncFile.readDoubleArr( arrName, nPoints );
|
||||
for ( size_t i = 0; i < nPoints; ++i )
|
||||
{
|
||||
values[i] = valuesX[i];
|
||||
}
|
||||
o->setStatistics( MDAL::calculateStatistics( o ) );
|
||||
mds->datasets.push_back( o );
|
||||
}
|
||||
else
|
||||
{
|
||||
// TIME DEPENDENT
|
||||
for ( size_t t = 0; t < times.size(); ++t )
|
||||
{
|
||||
std::shared_ptr<MDAL::MemoryDataset> mto = std::make_shared<MDAL::MemoryDataset>( mds.get() );
|
||||
mto->setTime( static_cast<double>( times[t] ) / 3600. );
|
||||
double *values = mto->values();
|
||||
|
||||
// fetching data for one timestep
|
||||
size_t start[2], count[2];
|
||||
const ptrdiff_t stride[2] = {1, 1};
|
||||
start[0] = t;
|
||||
start[1] = 0;
|
||||
count[0] = 1;
|
||||
count[1] = nPoints;
|
||||
nc_get_vars_double( ncFile.handle(), varxid, start, count, stride, values );
|
||||
mto->setStatistics( MDAL::calculateStatistics( mto ) );
|
||||
mds->datasets.push_back( mto );
|
||||
}
|
||||
}
|
||||
mds->setStatistics( MDAL::calculateStatistics( mds ) );
|
||||
}
|
||||
|
||||
return mds;
|
||||
}
|
||||
|
||||
std::shared_ptr<MDAL::DatasetGroup> MDAL::DriverSWW::readVectorGroup(
|
||||
const NetCDFFile &ncFile,
|
||||
MDAL::MemoryMesh *mesh,
|
||||
const std::vector<double> ×,
|
||||
const std::string groupName,
|
||||
const std::string arrXName,
|
||||
const std::string arrYName
|
||||
) const
|
||||
{
|
||||
size_t nPoints = getVertexCount( ncFile );
|
||||
std::shared_ptr<MDAL::DatasetGroup> mds;
|
||||
|
||||
int varxid, varyid;
|
||||
if ( nc_inq_varid( ncFile.handle(), arrXName.c_str(), &varxid ) == NC_NOERR &&
|
||||
nc_inq_varid( ncFile.handle(), arrYName.c_str(), &varyid ) == NC_NOERR )
|
||||
{
|
||||
mds = std::make_shared<MDAL::DatasetGroup> (
|
||||
name(),
|
||||
mesh,
|
||||
mFileName,
|
||||
groupName );
|
||||
mds->setIsOnVertices( true );
|
||||
mds->setIsScalar( false );
|
||||
|
||||
int zDimsX = 0;
|
||||
int zDimsY = 0;
|
||||
if ( nc_inq_varndims( ncFile.handle(), varxid, &zDimsX ) != NC_NOERR )
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
|
||||
if ( nc_inq_varndims( ncFile.handle(), varyid, &zDimsY ) != NC_NOERR )
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
|
||||
if ( zDimsX != zDimsY )
|
||||
throw MDAL_Status::Err_UnknownFormat;
|
||||
|
||||
std::vector<double> valuesX( nPoints ), valuesY( nPoints );
|
||||
|
||||
if ( zDimsX == 1 )
|
||||
{
|
||||
// TIME INDEPENDENT
|
||||
std::shared_ptr<MDAL::MemoryDataset> o = std::make_shared<MDAL::MemoryDataset>( mds.get() );
|
||||
o->setTime( 0.0 );
|
||||
double *values = o->values();
|
||||
std::vector<double> valuesX = ncFile.readDoubleArr( arrXName, nPoints );
|
||||
std::vector<double> valuesY = ncFile.readDoubleArr( arrYName, nPoints );
|
||||
for ( size_t i = 0; i < nPoints; ++i )
|
||||
{
|
||||
values[2 * i] = valuesX[i];
|
||||
values[2 * i + 1] = valuesY[i];
|
||||
}
|
||||
o->setStatistics( MDAL::calculateStatistics( o ) );
|
||||
mds->datasets.push_back( o );
|
||||
}
|
||||
else
|
||||
{
|
||||
// TIME DEPENDENT
|
||||
for ( size_t t = 0; t < times.size(); ++t )
|
||||
{
|
||||
std::shared_ptr<MDAL::MemoryDataset> mto = std::make_shared<MDAL::MemoryDataset>( mds.get() );
|
||||
mto->setTime( static_cast<double>( times[t] ) / 3600. );
|
||||
double *values = mto->values();
|
||||
|
||||
// fetching data for one timestep
|
||||
size_t start[2], count[2];
|
||||
const ptrdiff_t stride[2] = {1, 1};
|
||||
start[0] = t;
|
||||
start[1] = 0;
|
||||
count[0] = 1;
|
||||
count[1] = nPoints;
|
||||
nc_get_vars_double( ncFile.handle(), varxid, start, count, stride, valuesX.data() );
|
||||
nc_get_vars_double( ncFile.handle(), varyid, start, count, stride, valuesY.data() );
|
||||
|
||||
for ( size_t i = 0; i < nPoints; ++i )
|
||||
{
|
||||
values[2 * i] = static_cast<double>( valuesX[i] );
|
||||
values[2 * i + 1] = static_cast<double>( valuesY[i] );
|
||||
}
|
||||
|
||||
mto->setStatistics( MDAL::calculateStatistics( mto ) );
|
||||
mds->datasets.push_back( mto );
|
||||
}
|
||||
}
|
||||
mds->setStatistics( MDAL::calculateStatistics( mds ) );
|
||||
}
|
||||
|
||||
return mds;
|
||||
}
|
||||
|
||||
std::unique_ptr<MDAL::Mesh> MDAL::DriverSWW::load(
|
||||
const std::string &resultsFile,
|
||||
MDAL_Status *status )
|
||||
{
|
||||
mFileName = resultsFile;
|
||||
if ( status ) *status = MDAL_Status::None;
|
||||
|
||||
int ncid;
|
||||
int res;
|
||||
NetCDFFile ncFile;
|
||||
|
||||
res = nc_open( mFileName.c_str(), NC_NOWRITE, &ncid );
|
||||
if ( res != NC_NOERR )
|
||||
try
|
||||
{
|
||||
MDAL::debug( nc_strerror( res ) );
|
||||
nc_close( ncid );
|
||||
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
// Open file for reading
|
||||
ncFile.openFile( mFileName );
|
||||
|
||||
// get dimensions
|
||||
int nVolumesId, nVerticesId, nPointsId, nTimestepsId;
|
||||
size_t nVolumes, nVertices, nPoints, nTimesteps;
|
||||
if ( nc_inq_dimid( ncid, "number_of_volumes", &nVolumesId ) != NC_NOERR ||
|
||||
nc_inq_dimid( ncid, "number_of_vertices", &nVerticesId ) != NC_NOERR ||
|
||||
nc_inq_dimid( ncid, "number_of_points", &nPointsId ) != NC_NOERR ||
|
||||
nc_inq_dimid( ncid, "number_of_timesteps", &nTimestepsId ) != NC_NOERR )
|
||||
{
|
||||
nc_close( ncid );
|
||||
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
if ( nc_inq_dimlen( ncid, nVolumesId, &nVolumes ) != NC_NOERR ||
|
||||
nc_inq_dimlen( ncid, nVerticesId, &nVertices ) != NC_NOERR ||
|
||||
nc_inq_dimlen( ncid, nPointsId, &nPoints ) != NC_NOERR ||
|
||||
nc_inq_dimlen( ncid, nTimestepsId, &nTimesteps ) != NC_NOERR )
|
||||
{
|
||||
nc_close( ncid );
|
||||
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
|
||||
if ( nVertices != 3 )
|
||||
{
|
||||
MDAL::debug( "Expecting triangular elements!" );
|
||||
nc_close( ncid );
|
||||
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
|
||||
int xid, yid, zid, volumesid, timeid, stageid;
|
||||
if ( nc_inq_varid( ncid, "x", &xid ) != NC_NOERR ||
|
||||
nc_inq_varid( ncid, "y", &yid ) != NC_NOERR ||
|
||||
nc_inq_varid( ncid, "volumes", &volumesid ) != NC_NOERR ||
|
||||
nc_inq_varid( ncid, "time", &timeid ) != NC_NOERR ||
|
||||
nc_inq_varid( ncid, "stage", &stageid ) != NC_NOERR )
|
||||
{
|
||||
nc_close( ncid );
|
||||
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
|
||||
// load mesh data
|
||||
std::vector<float> px( nPoints ), py( nPoints ), pz( nPoints );
|
||||
std::vector<int> pvolumes( nVertices * nVolumes );
|
||||
if ( nc_get_var_float( ncid, xid, px.data() ) != NC_NOERR ||
|
||||
nc_get_var_float( ncid, yid, py.data() ) != NC_NOERR ||
|
||||
nc_get_var_int( ncid, volumesid, pvolumes.data() ) != NC_NOERR )
|
||||
{
|
||||
nc_close( ncid );
|
||||
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
|
||||
// we may need to apply a shift to the X,Y coordinates
|
||||
float xLLcorner = 0, yLLcorner = 0;
|
||||
nc_get_att_float( ncid, NC_GLOBAL, "xllcorner", &xLLcorner );
|
||||
nc_get_att_float( ncid, NC_GLOBAL, "yllcorner", &yLLcorner );
|
||||
|
||||
MDAL::Vertices nodes( nPoints );
|
||||
Vertex *nodesPtr = nodes.data();
|
||||
for ( size_t i = 0; i < nPoints; ++i, ++nodesPtr )
|
||||
{
|
||||
nodesPtr->x = static_cast<double>( px[i] + xLLcorner );
|
||||
nodesPtr->y = static_cast<double>( py[i] + yLLcorner );
|
||||
}
|
||||
|
||||
std::vector<float> times( nTimesteps );
|
||||
nc_get_var_float( ncid, timeid, times.data() );
|
||||
|
||||
int zDims = 0;
|
||||
if ( nc_inq_varid( ncid, "z", &zid ) == NC_NOERR &&
|
||||
nc_get_var_float( ncid, zid, pz.data() ) == NC_NOERR )
|
||||
{
|
||||
// older SWW format: elevation is constant over time
|
||||
|
||||
zDims = 1;
|
||||
}
|
||||
else if ( nc_inq_varid( ncid, "elevation", &zid ) == NC_NOERR &&
|
||||
nc_inq_varndims( ncid, zid, &zDims ) == NC_NOERR &&
|
||||
( ( zDims == 1 && nc_get_var_float( ncid, zid, pz.data() ) == NC_NOERR ) || zDims == 2 ) )
|
||||
{
|
||||
// we're good
|
||||
}
|
||||
else
|
||||
{
|
||||
// neither "z" nor "elevation" are present -> something is going wrong
|
||||
nc_close( ncid );
|
||||
if ( status ) *status = MDAL_Status::Err_UnknownFormat;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
|
||||
MDAL::Faces elements( nVolumes );
|
||||
for ( size_t i = 0; i < nVolumes; ++i )
|
||||
{
|
||||
elements[i].resize( 3 );
|
||||
elements[i][0] = static_cast<size_t>( pvolumes[3 * i + 0] );
|
||||
elements[i][1] = static_cast<size_t>( pvolumes[3 * i + 1] );
|
||||
elements[i][2] = static_cast<size_t>( pvolumes[3 * i + 2] );
|
||||
}
|
||||
std::unique_ptr< MDAL::MemoryMesh > mesh(
|
||||
new MemoryMesh(
|
||||
name(),
|
||||
nodes.size(),
|
||||
elements.size(),
|
||||
3, // triangles
|
||||
computeExtent( nodes ),
|
||||
mFileName
|
||||
)
|
||||
);
|
||||
mesh->faces = elements;
|
||||
mesh->vertices = nodes;
|
||||
|
||||
// Create a dataset for the bed elevation
|
||||
std::shared_ptr<MDAL::DatasetGroup> bedDs = std::make_shared<MDAL::DatasetGroup> (
|
||||
// Read mesh
|
||||
MDAL::Vertices vertices = readVertices( ncFile );
|
||||
MDAL::Faces faces = readFaces( ncFile );
|
||||
std::unique_ptr< MDAL::MemoryMesh > mesh(
|
||||
new MemoryMesh(
|
||||
name(),
|
||||
mesh.get(),
|
||||
mFileName,
|
||||
"Bed Elevation" );
|
||||
bedDs->setIsOnVertices( true );
|
||||
bedDs->setIsScalar( true );
|
||||
vertices.size(),
|
||||
faces.size(),
|
||||
3, // triangles
|
||||
computeExtent( vertices ),
|
||||
mFileName
|
||||
)
|
||||
);
|
||||
mesh->faces = faces;
|
||||
mesh->vertices = vertices;
|
||||
|
||||
// read bed elevations
|
||||
std::vector<std::shared_ptr<MDAL::MemoryDataset>> elevationOutputs;
|
||||
if ( zDims == 1 )
|
||||
{
|
||||
// either "z" or "elevation" with 1 dimension
|
||||
std::shared_ptr<MDAL::MemoryDataset> o = std::make_shared<MDAL::MemoryDataset>( bedDs.get() );
|
||||
o->setTime( 0.0 );
|
||||
double *values = o->values();
|
||||
for ( size_t i = 0; i < nPoints; ++i )
|
||||
{
|
||||
double z = static_cast<double>( pz[i] );
|
||||
values[i] = z;
|
||||
mesh->vertices[i].z = z;
|
||||
}
|
||||
o->setStatistics( MDAL::calculateStatistics( o ) );
|
||||
bedDs->datasets.push_back( o );
|
||||
elevationOutputs.push_back( o );
|
||||
// Read times
|
||||
std::vector<double> times = readTimes( ncFile );
|
||||
|
||||
// Create a dataset(s)
|
||||
readDatasetGroups( ncFile, mesh.get(), times );
|
||||
|
||||
// Success!
|
||||
return std::unique_ptr<Mesh>( mesh.release() );
|
||||
}
|
||||
else if ( zDims == 2 )
|
||||
catch ( MDAL_Status err )
|
||||
{
|
||||
// newer SWW format: elevation may change over time
|
||||
for ( size_t t = 0; t < nTimesteps; ++t )
|
||||
{
|
||||
std::shared_ptr<MDAL::MemoryDataset> toe = std::make_shared<MDAL::MemoryDataset>( bedDs.get() );
|
||||
toe->setTime( static_cast<double>( times[t] ) / 3600. );
|
||||
double *elev = toe->values();
|
||||
|
||||
// fetching "elevation" data for one timestep
|
||||
size_t start[2], count[2];
|
||||
const ptrdiff_t stride[2] = {1, 1};
|
||||
start[0] = t;
|
||||
start[1] = 0;
|
||||
count[0] = 1;
|
||||
count[1] = nPoints;
|
||||
std::vector<float> buffer( nPoints );
|
||||
nc_get_vars_float( ncid, zid, start, count, stride, buffer.data() );
|
||||
for ( size_t i = 0; i < nPoints; ++i )
|
||||
{
|
||||
double val = static_cast<double>( buffer[i] );
|
||||
elev[i] = val;
|
||||
}
|
||||
|
||||
toe->setStatistics( MDAL::calculateStatistics( toe ) );
|
||||
bedDs->datasets.push_back( toe );
|
||||
elevationOutputs.push_back( toe );
|
||||
}
|
||||
if ( status ) *status = err;
|
||||
return std::unique_ptr< MDAL::Mesh >();
|
||||
}
|
||||
|
||||
bedDs->setStatistics( MDAL::calculateStatistics( bedDs ) );
|
||||
mesh->datasetGroups.push_back( bedDs );
|
||||
|
||||
// load results
|
||||
std::shared_ptr<MDAL::DatasetGroup> dss = std::make_shared<MDAL::DatasetGroup> (
|
||||
name(),
|
||||
mesh.get(),
|
||||
mFileName,
|
||||
"Stage" );
|
||||
dss->setIsOnVertices( true );
|
||||
dss->setIsScalar( true );
|
||||
|
||||
std::shared_ptr<MDAL::DatasetGroup> dsd = std::make_shared<MDAL::DatasetGroup> (
|
||||
name(),
|
||||
mesh.get(),
|
||||
mFileName,
|
||||
"Depth" );
|
||||
dsd->setIsOnVertices( true );
|
||||
dsd->setIsScalar( true );
|
||||
|
||||
for ( size_t t = 0; t < nTimesteps; ++t )
|
||||
{
|
||||
const std::shared_ptr<MDAL::MemoryDataset> elevO = elevationOutputs.size() > 1 ? elevationOutputs[t] : elevationOutputs[0];
|
||||
const double *elev = elevO->constValues();
|
||||
|
||||
std::shared_ptr<MDAL::MemoryDataset> tos = std::make_shared<MDAL::MemoryDataset>( dss.get() );
|
||||
tos->setTime( static_cast<double>( times[t] ) / 3600. );
|
||||
double *values = tos->values();
|
||||
|
||||
// fetching "stage" data for one timestep
|
||||
size_t start[2], count[2];
|
||||
const ptrdiff_t stride[2] = {1, 1};
|
||||
start[0] = t;
|
||||
start[1] = 0;
|
||||
count[0] = 1;
|
||||
count[1] = nPoints;
|
||||
std::vector<float> buffer( nPoints );
|
||||
nc_get_vars_float( ncid, stageid, start, count, stride, buffer.data() );
|
||||
for ( size_t i = 0; i < nPoints; ++i )
|
||||
{
|
||||
double val = static_cast<double>( buffer[i] );
|
||||
values[i] = val;
|
||||
}
|
||||
|
||||
// derived data: depth = stage - elevation
|
||||
std::shared_ptr<MDAL::MemoryDataset> tod = std::make_shared<MDAL::MemoryDataset>( dsd.get() );
|
||||
tod->setTime( tos->time() );
|
||||
double *depths = tod->values();
|
||||
int *activeTos = tos->active();
|
||||
int *activeTod = tod->active();
|
||||
|
||||
for ( size_t j = 0; j < nPoints; ++j )
|
||||
depths[j] = values[j] - elev[j];
|
||||
|
||||
// determine which elements are active (wet)
|
||||
for ( size_t elemidx = 0; elemidx < nVolumes; ++elemidx )
|
||||
{
|
||||
const Face &elem = mesh->faces[elemidx];
|
||||
double v0 = depths[elem[0]];
|
||||
double v1 = depths[elem[1]];
|
||||
double v2 = depths[elem[2]];
|
||||
activeTos[elemidx] = v0 > DEPTH_THRESHOLD && v1 > DEPTH_THRESHOLD && v2 > DEPTH_THRESHOLD;
|
||||
activeTod[elemidx] = activeTos[elemidx];
|
||||
}
|
||||
|
||||
tos->setStatistics( MDAL::calculateStatistics( tos ) );
|
||||
dss->datasets.push_back( tos );
|
||||
|
||||
tod->setStatistics( MDAL::calculateStatistics( tod ) );
|
||||
dsd->datasets.push_back( tod );
|
||||
}
|
||||
|
||||
dss->setStatistics( MDAL::calculateStatistics( dss ) );
|
||||
mesh->datasetGroups.push_back( dss );
|
||||
|
||||
dsd->setStatistics( MDAL::calculateStatistics( dsd ) );
|
||||
mesh->datasetGroups.push_back( dsd );
|
||||
|
||||
|
||||
int momentumxid, momentumyid;
|
||||
if ( nc_inq_varid( ncid, "xmomentum", &momentumxid ) == NC_NOERR &&
|
||||
nc_inq_varid( ncid, "ymomentum", &momentumyid ) == NC_NOERR )
|
||||
{
|
||||
std::shared_ptr<MDAL::DatasetGroup> mds = std::make_shared<MDAL::DatasetGroup> (
|
||||
name(),
|
||||
mesh.get(),
|
||||
mFileName,
|
||||
"Momentum" );
|
||||
mds->setIsOnVertices( true );
|
||||
mds->setIsScalar( false );
|
||||
|
||||
std::vector<float> valuesX( nPoints ), valuesY( nPoints );
|
||||
for ( size_t t = 0; t < nTimesteps; ++t )
|
||||
{
|
||||
std::shared_ptr<MDAL::MemoryDataset> mto = std::make_shared<MDAL::MemoryDataset>( mds.get() );
|
||||
mto->setTime( static_cast<double>( times[t] ) / 3600. );
|
||||
double *values = mto->values();
|
||||
|
||||
std::shared_ptr<MDAL::MemoryDataset> mto0 = std::static_pointer_cast<MDAL::MemoryDataset>( dsd->datasets[t] );
|
||||
memcpy( mto->active(), mto0->active(), mesh->facesCount() * sizeof( int ) );
|
||||
|
||||
// fetching "stage" data for one timestep
|
||||
size_t start[2], count[2];
|
||||
const ptrdiff_t stride[2] = {1, 1};
|
||||
start[0] = t;
|
||||
start[1] = 0;
|
||||
count[0] = 1;
|
||||
count[1] = nPoints;
|
||||
nc_get_vars_float( ncid, momentumxid, start, count, stride, valuesX.data() );
|
||||
nc_get_vars_float( ncid, momentumyid, start, count, stride, valuesY.data() );
|
||||
|
||||
for ( size_t i = 0; i < nPoints; ++i )
|
||||
{
|
||||
values[2 * i] = static_cast<double>( valuesX[i] );
|
||||
values[2 * i + 1] = static_cast<double>( valuesY[i] );
|
||||
}
|
||||
|
||||
mto->setStatistics( MDAL::calculateStatistics( mto ) );
|
||||
mds->datasets.push_back( mto );
|
||||
}
|
||||
|
||||
|
||||
mds->setStatistics( MDAL::calculateStatistics( mds ) );
|
||||
mesh->datasetGroups.push_back( mds );
|
||||
}
|
||||
|
||||
nc_close( ncid );
|
||||
|
||||
return std::unique_ptr<Mesh>( mesh.release() );
|
||||
}
|
||||
|
55
external/mdal/frmts/mdal_sww.hpp
vendored
55
external/mdal/frmts/mdal_sww.hpp
vendored
@ -7,15 +7,32 @@
|
||||
#define MDAL_SWW_HPP
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "mdal_data_model.hpp"
|
||||
#include "mdal_memory_data_model.hpp"
|
||||
#include "mdal.h"
|
||||
#include "mdal_driver.hpp"
|
||||
#include "mdal_netcdf.hpp"
|
||||
|
||||
namespace MDAL
|
||||
{
|
||||
// AnuGA format with extension .SWW
|
||||
/**
|
||||
* AnuGA format with extension .SWW
|
||||
*
|
||||
* The format is based on NetCDF storage
|
||||
*
|
||||
* Bed Elevation can be static (== one bed elevation for all timesteps, stored
|
||||
* in "z" variable or "elevation" variable)
|
||||
* or dynamic (each timestep has its own elevation data, stored in "elevation"
|
||||
* variable with multiple dimensions)
|
||||
*
|
||||
* Vector data are recognized by prefix "x" and "y" in the name
|
||||
* Maximums data are recognized by suffix "_range" in the name
|
||||
*/
|
||||
class DriverSWW: public Driver
|
||||
{
|
||||
public:
|
||||
@ -25,7 +42,43 @@ namespace MDAL
|
||||
|
||||
std::unique_ptr< Mesh > load( const std::string &resultsFile, MDAL_Status *status ) override;
|
||||
bool canRead( const std::string &uri ) override;
|
||||
|
||||
private:
|
||||
size_t getVertexCount( const NetCDFFile &ncFile ) const;
|
||||
std::vector<double> readZCoords( const NetCDFFile &ncFile ) const;
|
||||
MDAL::Vertices readVertices( const NetCDFFile &ncFile ) const;
|
||||
MDAL::Faces readFaces( const NetCDFFile &ncFile ) const;
|
||||
std::vector<double> readTimes( const NetCDFFile &ncFile ) const;
|
||||
/**
|
||||
* Finds all variables (arrays) in netcdf file and base on the name add it as
|
||||
* vector or scalar dataset group
|
||||
*/
|
||||
void readDatasetGroups( const NetCDFFile &ncFile, MDAL::MemoryMesh *mesh, const std::vector<double> × ) const;
|
||||
bool parseGroupName( std::string &groupName, std::string &xName, std::string &yName ) const;
|
||||
|
||||
std::shared_ptr<MDAL::DatasetGroup> readScalarGroup(
|
||||
const NetCDFFile &ncFile,
|
||||
MDAL::MemoryMesh *mesh,
|
||||
const std::vector<double> ×,
|
||||
const std::string variableBaseName,
|
||||
const std::string arrName
|
||||
) const;
|
||||
|
||||
std::shared_ptr<MDAL::DatasetGroup> readVectorGroup(
|
||||
const NetCDFFile &ncFile,
|
||||
MDAL::MemoryMesh *mesh,
|
||||
const std::vector<double> ×,
|
||||
const std::string variableBaseName,
|
||||
const std::string arrXName,
|
||||
const std::string arrYName
|
||||
) const;
|
||||
|
||||
void addBedElevation(
|
||||
const NetCDFFile &ncFile,
|
||||
MDAL::MemoryMesh *mesh,
|
||||
const std::vector<double> ×
|
||||
) const;
|
||||
|
||||
std::string mFileName;
|
||||
};
|
||||
} // namespace MDAL
|
||||
|
52
external/mdal/frmts/mdal_xmdf.cpp
vendored
52
external/mdal/frmts/mdal_xmdf.cpp
vendored
@ -139,6 +139,7 @@ void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh, MDAL
|
||||
|
||||
size_t vertexCount = mesh->verticesCount();
|
||||
size_t faceCount = mesh->facesCount();
|
||||
|
||||
std::vector<std::string> rootGroups = file.groups();
|
||||
if ( rootGroups.size() != 1 )
|
||||
{
|
||||
@ -147,44 +148,21 @@ void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh, MDAL
|
||||
return;
|
||||
}
|
||||
HdfGroup gMesh = file.group( rootGroups[0] );
|
||||
|
||||
// TODO: read Times group (e.g. time of peak velocity)
|
||||
|
||||
DatasetGroups groups; // DAT outputs data
|
||||
|
||||
if ( gMesh.pathExists( "Temporal" ) )
|
||||
for ( const std::string &groupName : gMesh.groups() )
|
||||
{
|
||||
HdfGroup gTemporal = gMesh.group( "Temporal" );
|
||||
if ( gTemporal.isValid() )
|
||||
HdfGroup gGroup = gMesh.group( groupName );
|
||||
if ( gGroup.isValid() )
|
||||
{
|
||||
addDatasetGroupsFromXmdfGroup( groups, gTemporal, vertexCount, faceCount );
|
||||
}
|
||||
}
|
||||
|
||||
if ( gMesh.pathExists( "Temporal" ) )
|
||||
{
|
||||
HdfGroup gMaximums = gMesh.group( "Maximums" );
|
||||
if ( gMaximums.isValid() )
|
||||
{
|
||||
for ( const std::string &groupName : gMaximums.groups() )
|
||||
if ( groupName == "Maximums" )
|
||||
{
|
||||
HdfGroup g = gMaximums.group( groupName );
|
||||
std::shared_ptr<MDAL::DatasetGroup> maxGroup = readXmdfGroupAsDatasetGroup( g, groupName + "/Maximums", vertexCount, faceCount );
|
||||
if ( !maxGroup || maxGroup->datasets.size() != 1 )
|
||||
MDAL::debug( "Maximum dataset should have just one timestep!" );
|
||||
else
|
||||
groups.push_back( maxGroup );
|
||||
addDatasetGroupsFromXmdfGroup( groups, gGroup, "/Maximums", vertexCount, faceCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
addDatasetGroupsFromXmdfGroup( groups, gGroup, "", vertexCount, faceCount );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// res_to_res.exe (TUFLOW utiity tool)
|
||||
if ( gMesh.pathExists( "Difference" ) )
|
||||
{
|
||||
HdfGroup gDifference = gMesh.group( "Difference" );
|
||||
if ( gDifference.isValid() )
|
||||
{
|
||||
addDatasetGroupsFromXmdfGroup( groups, gDifference, vertexCount, faceCount );
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,14 +173,20 @@ void MDAL::DriverXmdf::load( const std::string &datFile, MDAL::Mesh *mesh, MDAL
|
||||
);
|
||||
}
|
||||
|
||||
void MDAL::DriverXmdf::addDatasetGroupsFromXmdfGroup( DatasetGroups &groups, const HdfGroup &rootGroup, size_t vertexCount, size_t faceCount )
|
||||
void MDAL::DriverXmdf::addDatasetGroupsFromXmdfGroup( DatasetGroups &groups,
|
||||
const HdfGroup &rootGroup,
|
||||
const std::string &nameSuffix,
|
||||
size_t vertexCount,
|
||||
size_t faceCount )
|
||||
{
|
||||
for ( const std::string &groupName : rootGroup.groups() )
|
||||
{
|
||||
HdfGroup g = rootGroup.group( groupName );
|
||||
std::shared_ptr<DatasetGroup> ds = readXmdfGroupAsDatasetGroup( g, groupName, vertexCount, faceCount );
|
||||
std::shared_ptr<DatasetGroup> ds = readXmdfGroupAsDatasetGroup( g, groupName + nameSuffix, vertexCount, faceCount );
|
||||
if ( ds && ds->datasets.size() > 0 )
|
||||
{
|
||||
groups.push_back( ds );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
21
external/mdal/frmts/mdal_xmdf.hpp
vendored
21
external/mdal/frmts/mdal_xmdf.hpp
vendored
@ -58,6 +58,26 @@ namespace MDAL
|
||||
class DriverXmdf: public Driver
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Driver for XMDF Files
|
||||
*
|
||||
* Structure of the TUFLOW file. Groups are optional since it depends
|
||||
* on tools which groups are created.
|
||||
* - root
|
||||
* - Temporal
|
||||
* - Depth
|
||||
* - Velocity
|
||||
* - ..
|
||||
* - Maximums
|
||||
* - Depth
|
||||
* - Velocity
|
||||
* - ..
|
||||
* - Difference (res_to_res.exe TUFLOW utility tool)
|
||||
* - ..
|
||||
* - Times (e.g. time of peak velocity)
|
||||
* - ..
|
||||
* - ...
|
||||
*/
|
||||
DriverXmdf();
|
||||
~DriverXmdf( ) override = default;
|
||||
DriverXmdf *create() override;
|
||||
@ -77,6 +97,7 @@ namespace MDAL
|
||||
void addDatasetGroupsFromXmdfGroup(
|
||||
DatasetGroups &groups,
|
||||
const HdfGroup &rootGroup,
|
||||
const std::string &nameSuffix,
|
||||
size_t vertexCount,
|
||||
size_t faceCount );
|
||||
};
|
||||
|
2
external/mdal/mdal.cpp
vendored
2
external/mdal/mdal.cpp
vendored
@ -22,7 +22,7 @@ static MDAL_Status sLastStatus;
|
||||
|
||||
const char *MDAL_Version()
|
||||
{
|
||||
return "0.1.3";
|
||||
return "0.1.4";
|
||||
}
|
||||
|
||||
MDAL_Status MDAL_LastStatus()
|
||||
|
24
external/mdal/mdal_utils.cpp
vendored
24
external/mdal/mdal_utils.cpp
vendored
@ -24,6 +24,9 @@ bool MDAL::fileExists( const std::string &filename )
|
||||
|
||||
bool MDAL::startsWith( const std::string &str, const std::string &substr, ContainsBehaviour behaviour )
|
||||
{
|
||||
if ( str.size() < substr.size() )
|
||||
return false;
|
||||
|
||||
if ( behaviour == ContainsBehaviour::CaseSensitive )
|
||||
return str.rfind( substr, 0 ) == 0;
|
||||
else
|
||||
@ -32,6 +35,9 @@ bool MDAL::startsWith( const std::string &str, const std::string &substr, Contai
|
||||
|
||||
bool MDAL::endsWith( const std::string &str, const std::string &substr, ContainsBehaviour behaviour )
|
||||
{
|
||||
if ( str.size() < substr.size() )
|
||||
return false;
|
||||
|
||||
if ( behaviour == ContainsBehaviour::CaseSensitive )
|
||||
return str.rfind( substr ) == ( str.size() - substr.size() );
|
||||
else
|
||||
@ -237,6 +243,24 @@ std::string MDAL::replace( const std::string &str, const std::string &substr, co
|
||||
return res;
|
||||
}
|
||||
|
||||
// http://www.cplusplus.com/faq/sequences/strings/trim/
|
||||
std::string MDAL::trim( const std::string &s, const std::string &delimiters )
|
||||
{
|
||||
return ltrim( rtrim( s, delimiters ), delimiters );
|
||||
}
|
||||
|
||||
// http://www.cplusplus.com/faq/sequences/strings/trim/
|
||||
std::string MDAL::ltrim( const std::string &s, const std::string &delimiters )
|
||||
{
|
||||
return s.substr( s.find_first_not_of( delimiters ) );
|
||||
}
|
||||
|
||||
// http://www.cplusplus.com/faq/sequences/strings/trim/
|
||||
std::string MDAL::rtrim( const std::string &s, const std::string &delimiters )
|
||||
{
|
||||
return s.substr( 0, s.find_last_not_of( delimiters ) + 1 );
|
||||
}
|
||||
|
||||
MDAL::BBox MDAL::computeExtent( const MDAL::Vertices &vertices )
|
||||
{
|
||||
BBox b;
|
||||
|
27
external/mdal/mdal_utils.hpp
vendored
27
external/mdal/mdal_utils.hpp
vendored
@ -67,29 +67,20 @@ namespace MDAL
|
||||
std::vector<std::string> split( const std::string &str, const std::string &delimiter, SplitBehaviour behaviour );
|
||||
std::string join( const std::vector<std::string> parts, const std::string &delimiter );
|
||||
|
||||
// http://www.cplusplus.com/faq/sequences/strings/trim/
|
||||
inline std::string rtrim(
|
||||
//! Right trim
|
||||
std::string rtrim(
|
||||
const std::string &s,
|
||||
const std::string &delimiters = " \f\n\r\t\v" )
|
||||
{
|
||||
return s.substr( 0, s.find_last_not_of( delimiters ) + 1 );
|
||||
}
|
||||
const std::string &delimiters = " \f\n\r\t\v" );
|
||||
|
||||
// http://www.cplusplus.com/faq/sequences/strings/trim/
|
||||
inline std::string ltrim(
|
||||
//! Left trim
|
||||
std::string ltrim(
|
||||
const std::string &s,
|
||||
const std::string &delimiters = " \f\n\r\t\v" )
|
||||
{
|
||||
return s.substr( s.find_first_not_of( delimiters ) );
|
||||
}
|
||||
const std::string &delimiters = " \f\n\r\t\v" );
|
||||
|
||||
// http://www.cplusplus.com/faq/sequences/strings/trim/
|
||||
inline std::string trim(
|
||||
//! Right and left trim
|
||||
std::string trim(
|
||||
const std::string &s,
|
||||
const std::string &delimiters = " \f\n\r\t\v" )
|
||||
{
|
||||
return ltrim( rtrim( s, delimiters ), delimiters );
|
||||
}
|
||||
const std::string &delimiters = " \f\n\r\t\v" );
|
||||
|
||||
// extent
|
||||
BBox computeExtent( const Vertices &vertices );
|
||||
|
@ -88,6 +88,7 @@ IF (WITH_INTERNAL_MDAL)
|
||||
SET(MDAL_LIB_SRCS ${MDAL_LIB_SRCS}
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_cf.cpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_3di.cpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_netcdf.cpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_sww.cpp
|
||||
)
|
||||
SET(MDAL_LIB_HDRS ${MDAL_LIB_HDRS}
|
||||
|
Loading…
x
Reference in New Issue
Block a user