Skip to content

Commit

Permalink
[feature] add NetCDF format, fixes #11
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterPetrik committed Oct 4, 2018
1 parent 688dce5 commit 8e7fa75
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 29 deletions.
13 changes: 11 additions & 2 deletions mdal/CMakeLists.txt
Expand Up @@ -34,11 +34,11 @@ ENDIF(HDF5_FOUND)
IF(GDAL_FOUND)
SET(MDAL_SOURCES ${MDAL_SOURCES}
frmts/mdal_gdal.cpp
frmts/mdal_grib.cpp
frmts/mdal_gdal_grib.cpp
)
SET(MDAL_HEADERS ${MDAL_HEADERS}
frmts/mdal_gdal.hpp
frmts/mdal_grib.hpp
frmts/mdal_gdal_grib.hpp
)
ENDIF(GDAL_FOUND)

Expand All @@ -54,6 +54,15 @@ IF(NETCDF_FOUND)
)
ENDIF(NETCDF_FOUND)

IF(GDAL_FOUND AND NETCDF_FOUND)
SET(MDAL_SOURCES ${MDAL_SOURCES}
frmts/mdal_gdal_netcdf.cpp
)
SET(MDAL_HEADERS ${MDAL_HEADERS}
frmts/mdal_gdal_netcdf.hpp
)
ENDIF(GDAL_FOUND AND NETCDF_FOUND)

ADD_LIBRARY(mdal SHARED
${MDAL_SOURCES}
${MDAL_HEADERS}
Expand Down
12 changes: 6 additions & 6 deletions mdal/frmts/mdal_grib.cpp → mdal/frmts/mdal_gdal_grib.cpp
Expand Up @@ -4,20 +4,20 @@
*/


#include "mdal_grib.hpp"
#include "mdal_gdal_grib.hpp"
#include "mdal_utils.hpp"
#include <string>
#include <limits>

MDAL::LoaderGrib::LoaderGrib( const std::string &gribFile )
MDAL::LoaderGdalGrib::LoaderGdalGrib( const std::string &gribFile )
: MDAL::LoaderGdal( gribFile, "GRIB" ),
mRefTime( std::numeric_limits<double>::min() )
{}

bool MDAL::LoaderGrib::parseBandInfo( const MDAL::GdalDataset *cfGDALDataset,
const metadata_hash &metadata, std::string &band_name,
double *time, bool *is_vector, bool *is_x
)
bool MDAL::LoaderGdalGrib::parseBandInfo( const MDAL::GdalDataset *cfGDALDataset,
const metadata_hash &metadata, std::string &band_name,
double *time, bool *is_vector, bool *is_x
)
{
MDAL_UNUSED( cfGDALDataset );

Expand Down
10 changes: 5 additions & 5 deletions mdal/frmts/mdal_grib.hpp → mdal/frmts/mdal_gdal_grib.hpp
Expand Up @@ -3,8 +3,8 @@
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
*/

#ifndef MDAL_GRIB_HPP
#define MDAL_GRIB_HPP
#ifndef MDAL_GDAL_GRIB_HPP
#define MDAL_GDAL_GRIB_HPP

#include "mdal_gdal.hpp"
#include "mdal_data_model.hpp"
Expand All @@ -14,10 +14,10 @@
namespace MDAL
{

class LoaderGrib: public LoaderGdal
class LoaderGdalGrib: public LoaderGdal
{
public:
LoaderGrib( const std::string &gribFile );
LoaderGdalGrib( const std::string &gribFile );
private:
bool parseBandInfo( const MDAL::GdalDataset *cfGDALDataset,
const metadata_hash &metadata, std::string &band_name,
Expand All @@ -35,4 +35,4 @@ namespace MDAL
};

} // namespace MDAL
#endif // MDAL_GRIB_HPP
#endif // MDAL_GDAL_GRIB_HPP
79 changes: 79 additions & 0 deletions mdal/frmts/mdal_gdal_netcdf.cpp
@@ -0,0 +1,79 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
*/

#include "mdal_gdal_netcdf.hpp"
#include "mdal_utils.hpp"

MDAL::LoaderGdalNetCDF::LoaderGdalNetCDF( const std::string &netCDFFile )
: MDAL::LoaderGdal( netCDFFile, "GRIB" )
, mTimeDiv( 1.0 )
{
}

std::string MDAL::LoaderGdalNetCDF::GDALFileName( const std::string &fileName )
{
#ifdef WIN32
// Force usage of the predefined GDAL driver
// http://gis.stackexchange.com/a/179167
// on Windows, HDF5 driver is checked before NETCDF driver in GDAL
return "NETCDF:\"" + fileName + "\"";
#else
return fileName;
#endif
}

bool MDAL::LoaderGdalNetCDF::parseBandInfo( const MDAL::GdalDataset *cfGDALDataset, const MDAL::LoaderGdal::metadata_hash &metadata, std::string &band_name, double *time, bool *is_vector, bool *is_x )
{
MDAL_UNUSED( cfGDALDataset );

metadata_hash::const_iterator iter;

iter = metadata.find( "netcdf_dim_time" );
if ( iter == metadata.end() ) return true; //FAILURE, skip no-time bands
*time = parseMetadataTime( iter->second ) / mTimeDiv;

// NAME
iter = metadata.find( "long_name" );
if ( iter == metadata.end() )
{
iter = metadata.find( "netcdf_varname" );
if ( iter == metadata.end() ) return true; //FAILURE, should be always present
band_name = iter->second;
}
else
{
band_name = iter->second;
}

// Loop throught all additional dimensions but time
for ( iter = metadata.begin(); iter != metadata.end(); ++iter )
{
std::string key = iter->first;
if ( MDAL::contains( key, "netcdf_dim_" ) )
{
key = MDAL::replace( key, "netcdf_dim_", "" );
if ( key != "time" )
{
band_name += "_" + key + ":" + iter->second;
}
}
}

// Parse X, Y components if present
parseBandIsVector( band_name, is_vector, is_x );

return false; // SUCCESS
}

void MDAL::LoaderGdalNetCDF::parseGlobals( const MDAL::LoaderGdal::metadata_hash &metadata )
{
metadata_hash::const_iterator iter = metadata.find( "time#units" );
if ( iter != metadata.end() )
{
std::string units = iter->second;
mTimeDiv = MDAL::parseTimeUnits( units );
// TODO store reference time from iter->second too, see crayfish_netcdf.cpp
}
}
34 changes: 34 additions & 0 deletions mdal/frmts/mdal_gdal_netcdf.hpp
@@ -0,0 +1,34 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
*/

#ifndef MDAL_GDAL_NETCDF_HPP
#define MDAL_GDAL_NETCDF_HPP

#include "mdal_gdal.hpp"
#include "mdal_data_model.hpp"
#include "mdal.h"
#include <string>

namespace MDAL
{

class LoaderGdalNetCDF: public LoaderGdal
{
public:
LoaderGdalNetCDF( const std::string &netCDFFile );
private:
std::string GDALFileName( const std::string &fileName ) override;
bool parseBandInfo( const MDAL::GdalDataset *cfGDALDataset,
const metadata_hash &metadata, std::string &band_name,
double *time, bool *is_vector, bool *is_x
) override;
void parseGlobals( const metadata_hash &metadata ) override;

//! delimiter to get time in hours
double mTimeDiv;
};

} // namespace MDAL
#endif // MDAL_GDAL_NETCDF_HPP
25 changes: 20 additions & 5 deletions mdal/mdal_loader.cpp
Expand Up @@ -15,13 +15,17 @@
#endif

#ifdef HAVE_GDAL
#include "frmts/mdal_grib.hpp"
#include "frmts/mdal_gdal_grib.hpp"
#endif

#ifdef HAVE_NETCDF
#include "frmts/mdal_3di.hpp"
#endif

#if defined HAVE_GDAL && defined HAVE_NETCDF
#include "frmts/mdal_gdal_netcdf.hpp"
#endif

std::unique_ptr<MDAL::Mesh> MDAL::Loader::load( const std::string &meshFile, MDAL_Status *status )
{
if ( !MDAL::fileExists( meshFile ) )
Expand All @@ -44,11 +48,22 @@ std::unique_ptr<MDAL::Mesh> MDAL::Loader::load( const std::string &meshFile, MDA
#ifdef HAVE_GDAL
if ( !mesh && status && *status == MDAL_Status::Err_UnknownFormat )
{
MDAL::LoaderGrib loader( meshFile );
mesh = loader.load( status );
#ifdef HAVE_NETCDF
if ( MDAL::endsWith( meshFile, ".nc" ) )
{
MDAL::LoaderGdalNetCDF loader( meshFile );
mesh = loader.load( status );
}
else
{
#endif // HAVE_GDAL && HAVE_NETCDF
MDAL::LoaderGdalGrib loader( meshFile );
mesh = loader.load( status );
}
#ifdef HAVE_NETCDF
}
#endif

#endif // HAVE_GDAL && HAVE_NETCDF
#endif // HAVE_GDAL
return mesh;
}

Expand Down
8 changes: 7 additions & 1 deletion tests/CMakeLists.txt
Expand Up @@ -80,7 +80,7 @@ ENDIF(HDF5_FOUND)

IF(GDAL_FOUND)
SET(TESTS ${TESTS}
test_grib.cpp
test_gdal_grib.cpp
)
ENDIF(GDAL_FOUND)

Expand All @@ -90,6 +90,12 @@ SET(TESTS ${TESTS}
)
ENDIF(NETCDF_FOUND)

IF(GDAL_FOUND AND NETCDF_FOUND)
SET(TESTS ${TESTS}
test_gdal_netcdf.cpp
)
ENDIF(GDAL_FOUND AND NETCDF_FOUND)

FOREACH(TESTSRC ${TESTS})
ADD_MDAL_TEST(${TESTSRC})
ENDFOREACH(TESTSRC)
Expand Down
Binary file added tests/data/netcdf/indonesia_nc3.nc
Binary file not shown.
Binary file added tests/data/netcdf/indonesia_nc4.nc
Binary file not shown.
4 changes: 2 additions & 2 deletions tests/test_grib.cpp → tests/test_gdal_grib.cpp
Expand Up @@ -9,7 +9,7 @@
#include "mdal.h"
#include "mdal_testutils.hpp"

TEST( MeshGribTest, ScalarFile )
TEST( MeshGdalGribTest, ScalarFile )
{
std::string path = test_file( "/grib/Madagascar.wave.7days.grb" );
MeshH m = MDAL_LoadMesh( path.c_str() );
Expand Down Expand Up @@ -52,7 +52,7 @@ TEST( MeshGribTest, ScalarFile )
MDAL_CloseMesh( m );
}

TEST( MeshGribTest, VectorFile )
TEST( MeshGdalGribTest, VectorFile )
{
std::string path = test_file( "/grib/Madagascar.wind.7days.grb" );
MeshH m = MDAL_LoadMesh( path.c_str() );
Expand Down
67 changes: 67 additions & 0 deletions tests/test_gdal_netcdf.cpp
@@ -0,0 +1,67 @@
/*
MDAL - Mesh Data Abstraction Library (MIT License)
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
*/
#include "gtest/gtest.h"
#include <string>
#include <vector>

//mdal
#include "mdal.h"
#include "mdal_testutils.hpp"

TEST( MeshGdalNetCDFTest, Indonesia )
{
std::vector<std::string> files;
files.push_back( "indonesia_nc3.nc" );
files.push_back( "indonesia_nc4.nc" );
for ( const std::string &file : files )
{
std::string path = test_file( std::string( "/netcdf/" ) + file );
MeshH m = MDAL_LoadMesh( path.c_str() );
ASSERT_NE( m, nullptr );
MDAL_Status s = MDAL_LastStatus();
EXPECT_EQ( MDAL_Status::None, s );
ASSERT_EQ( 2, MDAL_M_datasetGroupCount( m ) );

DatasetGroupH g = MDAL_M_datasetGroup( m, 1 );
ASSERT_NE( g, nullptr );

int meta_count = MDAL_G_metadataCount( g );
ASSERT_EQ( 1, meta_count );

const char *name = MDAL_G_name( g );
EXPECT_EQ( std::string( "Total cloud cover" ), std::string( name ) );

bool scalar = MDAL_G_hasScalarData( g );
EXPECT_EQ( true, scalar );

bool onVertices = MDAL_G_isOnVertices( g );
EXPECT_EQ( true, onVertices );

ASSERT_EQ( 31, MDAL_G_datasetCount( g ) );
DatasetH ds = MDAL_G_dataset( g, 10 );
ASSERT_NE( ds, nullptr );

bool valid = MDAL_D_isValid( ds );
EXPECT_EQ( true, valid );

bool active = MDAL_D_active( ds, 50 );
EXPECT_EQ( true, active );

int count = MDAL_D_valueCount( ds );
ASSERT_EQ( 234, count );

double value = MDAL_D_value( ds, 50 );
EXPECT_DOUBLE_EQ( 32759, value );

MDAL_CloseMesh( m );
}
}

int main( int argc, char **argv )
{
testing::InitGoogleTest( &argc, argv );
return RUN_ALL_TESTS();
}

0 comments on commit 8e7fa75

Please sign in to comment.