diff --git a/source/data_model/gdal/CMakeLists.txt b/source/data_model/gdal/CMakeLists.txt index 8a7470c7d..10b2acbac 100644 --- a/source/data_model/gdal/CMakeLists.txt +++ b/source/data_model/gdal/CMakeLists.txt @@ -14,6 +14,7 @@ add_library(lue_gdal STATIC src/blocks.cpp src/dataset.cpp src/driver.cpp + src/error.cpp src/raster.cpp src/raster_band.cpp ${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp @@ -43,6 +44,8 @@ target_sources(lue_gdal ${CMAKE_CURRENT_BINARY_DIR}/include/lue/gdal/configure.hpp ) +# NOTE: Think twice before adding libraries here. lue::gdal is a simple, thin API around the +# GDAL API. target_link_libraries(lue_gdal PUBLIC GDAL::GDAL diff --git a/source/data_model/gdal/doc/namespace.dox b/source/data_model/gdal/doc/namespace.dox index e5ffcb47b..8b6f9d3a1 100644 --- a/source/data_model/gdal/doc/namespace.dox +++ b/source/data_model/gdal/doc/namespace.dox @@ -4,6 +4,9 @@ namespace lue { @brief Namespace containing a nicer API around the GDAL C++-API and additional code that makes working with the GDAL library a nicer experience + The API tries to be as close to the original GDAL API as possible. There are only a + few utility classes, e.g.: gdal::Blocks and gdal::Raster. + The code is useful in other contexts than LUE: lue::gdal doesn't depend on anything specific to LUE. diff --git a/source/data_model/gdal/include/lue/gdal.hpp b/source/data_model/gdal/include/lue/gdal.hpp index ea74bbfa4..65b8ff1a3 100644 --- a/source/data_model/gdal/include/lue/gdal.hpp +++ b/source/data_model/gdal/include/lue/gdal.hpp @@ -2,6 +2,7 @@ #include "lue/gdal/configure.hpp" #include "lue/gdal/dataset.hpp" #include "lue/gdal/driver.hpp" +#include "lue/gdal/error.hpp" #include "lue/gdal/raster.hpp" #include "lue/gdal/raster_band.hpp" #include "lue/gdal/type_traits.hpp" diff --git a/source/data_model/gdal/include/lue/gdal/dataset.hpp b/source/data_model/gdal/include/lue/gdal/dataset.hpp index 329e3113b..cd67b4fe0 100644 --- a/source/data_model/gdal/include/lue/gdal/dataset.hpp +++ b/source/data_model/gdal/include/lue/gdal/dataset.hpp @@ -36,6 +36,13 @@ namespace lue::gdal { auto try_open_dataset(std::string const& name, GDALAccess open_mode) -> DatasetPtr; + auto create_dataset( + GDALDriver& driver, + std::string const& dataset_name, + Shape const& shape, + Count nr_bands, + GDALDataType data_type) -> DatasetPtr; + auto create_dataset( std::string const& driver_name, std::string const& dataset_name, diff --git a/source/data_model/gdal/include/lue/gdal/define.hpp b/source/data_model/gdal/include/lue/gdal/define.hpp index 78484c0fa..30bdf00c0 100644 --- a/source/data_model/gdal/include/lue/gdal/define.hpp +++ b/source/data_model/gdal/include/lue/gdal/define.hpp @@ -9,6 +9,13 @@ namespace lue::gdal { */ using Count = int; + /*! + @brief Type for offsets + + First coordinate is the y-coordinate, second coordinate is the x-coordinate. The + coordinates are relative to the upper left corner of the raster band. In case of a cell + offset, the upper left cell has offset (0, 0). + */ using Offset = std::array; /*! @@ -19,12 +26,37 @@ namespace lue::gdal { using Shape = std::array; + /*! + @brief Return the number of elements in a shape of a raster (for example) + */ inline auto nr_elements(Shape const& shape) -> Count { return shape[0] * shape[1]; } - using GeoTransform = std::array; + /*! + @brief Type used by GDAL for no-data values + */ + using NoDataValue = double; + + + /*! + @brief Type used by GDAL for coordinates + */ + using Coordinate = double; + + + /*! + @brief Type used by GDAL for extents, e.g. for cell width, cell height + */ + using Extent = double; + + + /*! + @brief Type for representing transformation information + @sa gdal::geo_transform + */ + using GeoTransform = std::array; } // namespace lue::gdal diff --git a/source/data_model/gdal/include/lue/gdal/driver.hpp b/source/data_model/gdal/include/lue/gdal/driver.hpp index 76035b24c..81f0411a8 100644 --- a/source/data_model/gdal/include/lue/gdal/driver.hpp +++ b/source/data_model/gdal/include/lue/gdal/driver.hpp @@ -17,4 +17,6 @@ namespace lue::gdal { auto driver(std::string const& name) -> DriverPtr; + auto delete_dataset(GDALDriver& driver, std::string const& dataset_name) -> void; + } // namespace lue::gdal diff --git a/source/data_model/gdal/include/lue/gdal/error.hpp b/source/data_model/gdal/include/lue/gdal/error.hpp new file mode 100644 index 000000000..20becbfda --- /dev/null +++ b/source/data_model/gdal/include/lue/gdal/error.hpp @@ -0,0 +1,21 @@ +#pragma once + + +namespace lue::gdal { + + + class QuietErrorHandler + { + + public: + + QuietErrorHandler(); + + QuietErrorHandler(QuietErrorHandler const& other) = delete; + + ~QuietErrorHandler(); + + auto operator=(QuietErrorHandler const& other) -> QuietErrorHandler = delete; + }; + +} // namespace lue::gdal diff --git a/source/data_model/gdal/include/lue/gdal/raster.hpp b/source/data_model/gdal/include/lue/gdal/raster.hpp index a58ec0f55..ba98e6eca 100644 --- a/source/data_model/gdal/include/lue/gdal/raster.hpp +++ b/source/data_model/gdal/include/lue/gdal/raster.hpp @@ -6,11 +6,17 @@ namespace lue::gdal { + /*! + @brief Utility class for performing I/O to a raster and its bands + */ class Raster { public: + /*! + @brief Utility class for performing I/O to a raster band + */ class Band { @@ -30,35 +36,50 @@ namespace lue::gdal { [[nodiscard]] auto data_type() const -> GDALDataType; + [[nodiscard]] auto block_size() const -> Shape; + + [[nodiscard]] auto size() const -> Shape; + + + /*! + @sa gdal::no_data_value + */ template [[nodiscard]] auto no_data_value() const -> std::tuple { - return gdal::no_data_value(*_band); + return gdal::no_data_value(*_band_ptr); } - [[nodiscard]] auto blocks() const -> Blocks; - auto read_block(Offset const& block_offset, void* buffer) const -> void; + /*! + @sa gdal::set_no_data_value + */ + template + auto set_no_data_value(Element const value) -> void + { + gdal::set_no_data_value(*_band_ptr, value); + } + - auto read(void* buffer) const -> void; + auto read_block(Offset const& block_offset, void* buffer) -> void; auto write_block(Offset const& block_offset, void* buffer) -> void; - // void write (hl::Raster::Band& raster_band, - // ProgressIndicator& progress_indicator); + auto read(void* buffer) -> void; - private: + auto write(void* buffer) -> void; - // template< - // typename T> - // void write (hl::Raster::Band& raster_band, - // ProgressIndicator& progress_indicator); + auto write(Offset const& offset, Shape const& shape, GDALDataType data_type, void* buffer) + -> void; + + auto write(Shape const& shape, GDALDataType data_type, void* buffer) -> void; - RasterBandPtr _band; - }; + private: + + RasterBandPtr _band_ptr; + }; - explicit Raster(std::string const& dataset_name); explicit Raster(DatasetPtr dataset_ptr); diff --git a/source/data_model/gdal/include/lue/gdal/raster_band.hpp b/source/data_model/gdal/include/lue/gdal/raster_band.hpp index e45a3580f..d228270b7 100644 --- a/source/data_model/gdal/include/lue/gdal/raster_band.hpp +++ b/source/data_model/gdal/include/lue/gdal/raster_band.hpp @@ -19,6 +19,28 @@ namespace lue::gdal { auto band_size(GDALRasterBand& band) -> Shape; + auto read_block(GDALRasterBand& band, Offset const& block_offset, void* buffer) -> void; + + auto write_block(GDALRasterBand& band, Offset const& block_offset, void* buffer) -> void; + + auto read( + GDALRasterBand& band, + Offset const& offset, + Shape const& raster_shape, + GDALDataType data_type, + void* buffer) -> void; + + auto read(GDALRasterBand& band, Shape const& shape, GDALDataType data_type, void* buffer) -> void; + + auto write( + GDALRasterBand& band, + Offset const& offset, + Shape const& raster_shape, + GDALDataType data_type, + void* buffer) -> void; + + auto write(GDALRasterBand& band, Shape const& shape, GDALDataType data_type, void* buffer) -> void; + namespace detail { @@ -52,7 +74,7 @@ namespace lue::gdal { template auto set_no_data_value(GDALRasterBand& band, Element const value) -> CPLErr { - return band.SetNoDataValue(static_cast(value)); + return band.SetNoDataValue(static_cast(value)); } diff --git a/source/data_model/gdal/include/lue/gdal/version.hpp b/source/data_model/gdal/include/lue/gdal/version.hpp index 7b83f2270..1c37695b3 100644 --- a/source/data_model/gdal/include/lue/gdal/version.hpp +++ b/source/data_model/gdal/include/lue/gdal/version.hpp @@ -4,9 +4,6 @@ namespace lue::gdal { - /*! - @brief Return the version of the GDAL library - */ auto version() -> std::string; } // namespace lue::gdal diff --git a/source/data_model/gdal/src/dataset.cpp b/source/data_model/gdal/src/dataset.cpp index 387b43ccb..4b57ecab3 100644 --- a/source/data_model/gdal/src/dataset.cpp +++ b/source/data_model/gdal/src/dataset.cpp @@ -8,6 +8,22 @@ namespace lue::gdal { + namespace { + + auto up_is_north(GeoTransform const& geo_transform) -> bool + { + return geo_transform[2] == 0.0 && geo_transform[4] == 0.0 && geo_transform[5] < 0.0; + } + + + auto cells_are_square(GeoTransform const& geo_transform) -> bool + { + return geo_transform[1] == std::abs(geo_transform[5]); + } + + } // Anonymous namespace + + /*! @brief Open dataset @name @param open_mode Open mode to use: `GDALAccess::GA_ReadOnly` or `GDALAccess::GA_Update` @@ -16,17 +32,7 @@ namespace lue::gdal { */ auto try_open_dataset(std::string const& name, GDALAccess open_mode) -> DatasetPtr { -#ifndef NDEBUG - CPLPushErrorHandler(CPLQuietErrorHandler); -#endif - - DatasetPtr dataset_ptr{static_cast(GDALOpen(name.c_str(), open_mode)), gdal_close}; - -#ifndef NDEBUG - CPLPopErrorHandler(); -#endif - - return dataset_ptr; + return {static_cast(GDALOpen(name.c_str(), open_mode)), gdal_close}; } @@ -56,25 +62,16 @@ namespace lue::gdal { @exception std::runtime_error In case the dataset cannot be created */ auto create_dataset( - std::string const& driver_name, + GDALDriver& driver, std::string const& dataset_name, Shape const& shape, Count nr_bands, GDALDataType data_type) -> DatasetPtr { -#ifndef NDEBUG - CPLPushErrorHandler(CPLQuietErrorHandler); -#endif - DatasetPtr dataset_ptr{ - driver(driver_name) - ->Create(dataset_name.c_str(), shape[1], shape[0], nr_bands, data_type, nullptr), + driver.Create(dataset_name.c_str(), shape[1], shape[0], nr_bands, data_type, nullptr), gdal_close}; -#ifndef NDEBUG - CPLPopErrorHandler(); -#endif - if (!dataset_ptr) { throw std::runtime_error(fmt::format("Raster {} cannot be created", dataset_name)); @@ -84,6 +81,23 @@ namespace lue::gdal { } + /*! + @overload + */ + auto create_dataset( + std::string const& driver_name, + std::string const& dataset_name, + Shape const& shape, + Count nr_bands, + GDALDataType data_type) -> DatasetPtr + { + return create_dataset(*driver(driver_name), dataset_name, shape, nr_bands, data_type); + } + + + /*! + @overload + */ auto create_dataset(std::string const& driver_name, std::string const& dataset_name) -> DatasetPtr { return create_dataset(driver_name, dataset_name, Shape{0, 0}, 0, GDT_Unknown); @@ -100,10 +114,6 @@ namespace lue::gdal { { assert(clone_dataset); -#ifndef NDEBUG - CPLPushErrorHandler(CPLQuietErrorHandler); -#endif - // TODO let GDAL pick the driver and/or use extension(?) DriverPtr driver{gdal::driver("GTiff")}; @@ -111,10 +121,6 @@ namespace lue::gdal { driver->CreateCopy(name.c_str(), clone_dataset.get(), FALSE, nullptr, nullptr, nullptr), gdal_close}; -#ifndef NDEBUG - CPLPopErrorHandler(); -#endif - if (!dataset_ptr) { throw std::runtime_error("Raster " + name + " cannot be created"); @@ -130,6 +136,9 @@ namespace lue::gdal { } + /*! + @brief Return the number of bands in a raster + */ auto nr_raster_bands(GDALDataset& dataset) -> Count { return dataset.GetRasterCount(); @@ -157,10 +166,8 @@ namespace lue::gdal { 1, nr_bands)); } - else - { - throw std::runtime_error(fmt::format("Band {} cannot be obtained", band_nr)); - } + + throw std::runtime_error(fmt::format("Band {} cannot be obtained", band_nr)); } return band_ptr; @@ -210,23 +217,12 @@ namespace lue::gdal { } - auto up_is_north(GeoTransform const& geo_transform) -> bool - { - return geo_transform[2] == 0.0 && geo_transform[4] == 0.0 && geo_transform[5] < 0.0; - } - - - auto cells_are_square(GeoTransform const& geo_transform) -> bool - { - return geo_transform[1] == std::abs(geo_transform[5]); - } - - /*! @brief Return the information about the affine transformation from raster coordinates (row, col indices) to georeferenced coordinates (projected or geographic coordinates) @return Collection of six coefficients + @sa set_geo_transform Index | Meaning ----- | ------- @@ -256,10 +252,14 @@ namespace lue::gdal { } + /*! + @brief Set the transformation information + @sa geo_transform + */ auto set_geo_transform(GDALDataset& dataset, GeoTransform const& geo_transform) -> void { // For some reason, GDAL wants a non-const pointer... - dataset.SetGeoTransform(const_cast(geo_transform.data())); + dataset.SetGeoTransform(const_cast(geo_transform.data())); } } // namespace lue::gdal diff --git a/source/data_model/gdal/src/driver.cpp b/source/data_model/gdal/src/driver.cpp index 2a4f5b749..b0ded5d66 100644 --- a/source/data_model/gdal/src/driver.cpp +++ b/source/data_model/gdal/src/driver.cpp @@ -1,4 +1,5 @@ #include "lue/gdal/driver.hpp" +#include #include @@ -32,10 +33,21 @@ namespace lue::gdal { if (driver_ptr == nullptr) { - throw std::runtime_error("Driver " + name + " is not available"); + throw std::runtime_error(fmt::format("Driver {} is not available", name)); } return driver_ptr; } + + auto delete_dataset(GDALDriver& driver, std::string const& dataset_name) -> void + { + CPLErr const status = driver.Delete(dataset_name.c_str()); + + if (status != CE_None) + { + throw std::runtime_error(fmt::format("Cannot delete dataset {}", dataset_name)); + } + } + } // namespace lue::gdal diff --git a/source/data_model/gdal/src/error.cpp b/source/data_model/gdal/src/error.cpp new file mode 100644 index 000000000..4bd9f9e41 --- /dev/null +++ b/source/data_model/gdal/src/error.cpp @@ -0,0 +1,18 @@ +#include "lue/gdal/error.hpp" +#include + + +namespace lue::gdal { + + QuietErrorHandler::QuietErrorHandler() + { + CPLPushErrorHandler(CPLQuietErrorHandler); + } + + + QuietErrorHandler::~QuietErrorHandler() + { + CPLPopErrorHandler(); + } + +} // namespace lue::gdal diff --git a/source/data_model/gdal/src/raster.cpp b/source/data_model/gdal/src/raster.cpp index 9afdb85c3..f6381b6ab 100644 --- a/source/data_model/gdal/src/raster.cpp +++ b/source/data_model/gdal/src/raster.cpp @@ -1,215 +1,142 @@ #include "lue/gdal/raster.hpp" #include -#include namespace lue::gdal { Raster::Band::Band(RasterBandPtr band): - _band{band} + _band_ptr{band} { - assert(_band); + assert(_band_ptr); } + /*! + @sa gdal::data_type + */ auto Raster::Band::data_type() const -> GDALDataType { - return gdal::data_type(*_band); + return gdal::data_type(*_band_ptr); } - auto Raster::Band::blocks() const -> Blocks + /*! + @sa gdal::shape(GDALRasterBand const&) + */ + auto Raster::Band::size() const -> Shape { - auto [block_size_y, block_size_x] = block_size(*_band); - - assert(block_size_x >= 0); - assert(block_size_y >= 0); - - auto [nr_rows, nr_cols] = band_size(*_band); - - assert(nr_rows >= 0); - assert(nr_cols >= 0); - - // TODO Enlarge given some heuristics: - // - A whole number of times the actual block size (in each dimension) - // - Number of cells below some sensible value (1GB?) - block_size_x *= 10; - block_size_y *= 10; + return gdal::band_size(*_band_ptr); + } - block_size_x = std::min(block_size_x, nr_cols); - block_size_y = std::min(block_size_y, nr_rows); - return {{nr_cols, nr_rows}, {block_size_x, block_size_y}}; + /*! + @sa gdal::block_size + */ + auto Raster::Band::block_size() const -> Shape + { + return gdal::block_size(*_band_ptr); } - auto Raster::Band::read_block(Offset const& block_offset, void* buffer) const -> void + /*! + @sa gdal::read_block + */ + auto Raster::Band::read_block(Offset const& block_offset, void* buffer) -> void { - auto cpl_status = _band->ReadBlock(block_offset[0], block_offset[1], buffer); - - if (cpl_status != CE_None) - { - throw std::runtime_error("Cannot read block from GDAL raster band"); - } + gdal::read_block(*_band_ptr, block_offset, buffer); } - auto Raster::Band::read(void* buffer) const -> void + /*! + @sa gdal::read + */ + auto Raster::Band::read(void* buffer) -> void { - int const nr_rows = _band->GetYSize(); - int const nr_cols = _band->GetXSize(); - auto const datatype = this->data_type(); + gdal::read(*_band_ptr, size(), data_type(), buffer); + } - auto cpl_status = _band->RasterIO( - GF_Read, 0, 0, nr_cols, nr_rows, buffer, nr_cols, nr_rows, datatype, 0, 0, nullptr); - if (cpl_status != CE_None) - { - throw std::runtime_error("Cannot read from GDAL raster band"); - } + /*! + @sa gdal::write + */ + auto Raster::Band::write(void* buffer) -> void + { + gdal::write(*_band_ptr, size(), data_type(), buffer); } + /*! + @sa gdal::write_block + */ auto Raster::Band::write_block(Offset const& block_offset, void* buffer) -> void { - auto cpl_status = _band->WriteBlock(block_offset[0], block_offset[1], buffer); - - if (cpl_status != CE_None) - { - throw std::runtime_error("Cannot write block to GDAL raster band"); - } - } - - - // template< - // typename T> - // void Raster::Band::write( - // hl::Raster::Band& raster_band, - // ProgressIndicator& progress_indicator) - // { - // auto const blocks = this->blocks(); - // std::vector values(blocks.block_size()); - // size_t nr_valid_cells_x; - // size_t nr_valid_cells_y; - // size_t current_block = 0; - // - // for(size_t block_y = 0; block_y < blocks.nr_blocks_y(); - // ++block_y) { - // for(size_t block_x = 0; block_x < blocks.nr_blocks_x(); - // ++block_x) { - // - // read_block(block_x, block_y, values.data()); - // - // std::tie(nr_valid_cells_x, nr_valid_cells_y) = - // blocks.nr_valid_cells(block_x, block_y); - // - // hdf5::Shape const shape = { nr_valid_cells_x * nr_valid_cells_y }; - // auto const memory_dataspace = hdf5::create_dataspace(shape); - // - // hdf5::Offset offset = { - // block_y * blocks.block_size_y(), - // block_x * blocks.block_size_x() - // }; - // hdf5::Count count = { nr_valid_cells_y, nr_valid_cells_x }; - // - // raster_band.write( - // memory_dataspace, hdf5::Hyperslab(offset, count), values.data()); - // - // progress_indicator.update_progress(++current_block); - // } - // } - // } - - // void Raster::Band::write( - // hl::Raster::Band& raster_band, - // ProgressIndicator& progress_indicator) - // { - // auto datatype = _band->GetRasterDataType(); - // - // switch(datatype) { - // case GDT_Byte: { - // write(raster_band, progress_indicator); - // break; - // } - // case GDT_UInt16: { - // write(raster_band, progress_indicator); - // break; - // } - // case GDT_Int16: { - // write(raster_band, progress_indicator); - // break; - // } - // case GDT_UInt32: { - // write(raster_band, progress_indicator); - // break; - // } - // case GDT_Int32: { - // write(raster_band, progress_indicator); - // break; - // } - // case GDT_Float32: { - // write(raster_band, progress_indicator); - // break; - // } - // case GDT_Float64: { - // write(raster_band, progress_indicator); - // break; - // } - // default: { - // throw std::runtime_error("Unsupported datatype"); - // break; - // } - // } - // } + gdal::write_block(*_band_ptr, block_offset, buffer); + } - Raster::Raster(DatasetPtr dataset_ptr): + auto Raster::Band::write( + Offset const& offset, Shape const& shape, GDALDataType const data_type, void* buffer) -> void + { + gdal::write(*_band_ptr, offset, shape, data_type, buffer); + } - _dataset_ptr{std::move(dataset_ptr)} + auto Raster::Band::write(Shape const& shape, GDALDataType const data_type, void* buffer) -> void { - assert(_dataset_ptr); + gdal::write(*_band_ptr, shape, data_type, buffer); } - Raster::Raster(std::string const& dataset_name): + Raster::Raster(DatasetPtr dataset_ptr): - _dataset_ptr{open_dataset(dataset_name, GDALAccess::GA_ReadOnly)} + _dataset_ptr{std::move(dataset_ptr)} { + assert(_dataset_ptr); } + /*! + @sa gdal::shape(GDALDataset const&) + */ auto Raster::shape() const -> Shape { return gdal::shape(*_dataset_ptr); } + /*! + @sa gdal::geo_transform + */ auto Raster::geo_transform() const -> GeoTransform { return gdal::geo_transform(*_dataset_ptr); } + /*! + @sa gdal::set_geo_transform + */ auto Raster::set_geo_transform(GeoTransform const& geo_transform) -> void { gdal::set_geo_transform(*_dataset_ptr, geo_transform); } + /*! + @sa gdal::nr_raster_bands + */ auto Raster::nr_bands() const -> Count { - Count const result{nr_raster_bands(*_dataset_ptr)}; - - assert(result >= 0); - - return result; + return nr_raster_bands(*_dataset_ptr); } + /*! + @sa gdal::raster_band + */ auto Raster::band(Count const band_nr) const -> Band { return Raster::Band{raster_band(*_dataset_ptr, band_nr)}; diff --git a/source/data_model/gdal/src/raster_band.cpp b/source/data_model/gdal/src/raster_band.cpp index 3f2bad1dd..6f477eb33 100644 --- a/source/data_model/gdal/src/raster_band.cpp +++ b/source/data_model/gdal/src/raster_band.cpp @@ -1,4 +1,5 @@ #include "lue/gdal/raster_band.hpp" +#include namespace lue::gdal { @@ -14,8 +15,8 @@ namespace lue::gdal { auto block_size(GDALRasterBand& band) -> Shape { - int size_x; - int size_y; + int size_x{}; + int size_y{}; band.GetBlockSize(&size_x, &size_y); @@ -25,10 +26,107 @@ namespace lue::gdal { auto band_size(GDALRasterBand& band) -> Shape { - int size_x = band.GetXSize(); - int size_y = band.GetYSize(); + return {band.GetYSize(), band.GetXSize()}; + } - return {size_y, size_x}; + + auto read_block(GDALRasterBand& band, Offset const& block_offset, void* buffer) -> void + { + auto const [offset_y, offset_x] = block_offset; + auto cpl_status = band.ReadBlock(offset_x, offset_y, buffer); + + if (cpl_status != CE_None) + { + throw std::runtime_error("Cannot read block from GDAL raster band"); + } + } + + + auto write_block(GDALRasterBand& band, Offset const& block_offset, void* buffer) -> void + { + auto const [offset_y, offset_x] = block_offset; + auto cpl_status = band.WriteBlock(offset_x, offset_y, buffer); + + if (cpl_status != CE_None) + { + throw std::runtime_error("Cannot write block to GDAL raster band"); + } + } + + + auto read( + GDALRasterBand& band, + Offset const& offset, + Shape const& raster_shape, + GDALDataType const data_type, + void* buffer) -> void + { + auto const [offset_y, offset_x] = offset; + auto const [nr_rows, nr_cols] = raster_shape; + + auto cpl_status = band.RasterIO( + GF_Read, + offset_x, + offset_y, + nr_cols, + nr_rows, + buffer, + nr_cols, + nr_rows, + data_type, + 0, + 0, + nullptr); + + if (cpl_status != CE_None) + { + throw std::runtime_error("Cannot read from GDAL raster band"); + } + } + + + auto read(GDALRasterBand& band, Shape const& raster_shape, GDALDataType const data_type, void* buffer) + -> void + { + read(band, {0, 0}, raster_shape, data_type, buffer); + } + + + auto write( + GDALRasterBand& band, + Offset const& offset, + Shape const& raster_shape, + GDALDataType const data_type, + void* buffer) -> void + { + auto const [offset_y, offset_x] = offset; + auto const [nr_rows, nr_cols] = raster_shape; + + auto cpl_status = band.RasterIO( + GF_Write, + offset_x, + offset_y, + nr_cols, + nr_rows, + buffer, + nr_cols, + nr_rows, + data_type, + 0, + 0, + nullptr); + + if (cpl_status != CE_None) + { + throw std::runtime_error("Cannot write to GDAL raster band"); + } + } + + + auto write(GDALRasterBand& band, Shape const& raster_shape, GDALDataType const data_type, void* buffer) + -> void + { + write(band, {0, 0}, raster_shape, data_type, buffer); } } // namespace lue::gdal diff --git a/source/data_model/gdal/src/version.cpp.in b/source/data_model/gdal/src/version.cpp.in index 41df9bda7..1a33720b0 100644 --- a/source/data_model/gdal/src/version.cpp.in +++ b/source/data_model/gdal/src/version.cpp.in @@ -3,6 +3,9 @@ namespace lue::gdal { + /*! + @brief Return the version of the GDAL library + */ auto version() -> std::string { return "${GDAL_VERSION}"; diff --git a/source/data_model/gdal/test/CMakeLists.txt b/source/data_model/gdal/test/CMakeLists.txt index 42ee75c1c..d386faec3 100644 --- a/source/data_model/gdal/test/CMakeLists.txt +++ b/source/data_model/gdal/test/CMakeLists.txt @@ -22,6 +22,7 @@ foreach(name ${names}) target_link_libraries(${test_name} PRIVATE lue::gdal + lue::shared Boost::unit_test_framework ) diff --git a/source/data_model/gdal/test/blocks_test.cpp b/source/data_model/gdal/test/blocks_test.cpp index af45ff668..1086dd2f6 100644 --- a/source/data_model/gdal/test/blocks_test.cpp +++ b/source/data_model/gdal/test/blocks_test.cpp @@ -1,10 +1,68 @@ #define BOOST_TEST_MODULE lue gdal blocks_test #include "lue/gdal/blocks.hpp" +#include "lue/stream.hpp" #include -BOOST_AUTO_TEST_CASE(blocks) +BOOST_AUTO_TEST_CASE(constructor) { - // TODO - BOOST_CHECK(true); + namespace lgd = lue::gdal; + + { + lgd::Shape const raster_shape{60, 40}; + lgd::Shape const block_shape{6, 4}; + lgd::Blocks const blocks{lgd::Blocks{raster_shape, block_shape}}; + + BOOST_CHECK_EQUAL(blocks.raster_shape(), raster_shape); + BOOST_CHECK_EQUAL(blocks.block_shape(), block_shape); + BOOST_CHECK_EQUAL(blocks.shape_in_blocks(), (lgd::Shape{10, 10})); + } + + { + lgd::Shape const raster_shape{60, 40}; + lgd::Shape const block_shape{60, 40}; + lgd::Blocks const blocks{lgd::Blocks{raster_shape, block_shape}}; + + + BOOST_CHECK_EQUAL(blocks.raster_shape(), raster_shape); + BOOST_CHECK_EQUAL(blocks.block_shape(), block_shape); + BOOST_CHECK_EQUAL(blocks.shape_in_blocks(), (lgd::Shape{1, 1})); + } + + { + lgd::Shape const raster_shape{60, 40}; + lgd::Shape const block_shape{1, 1}; + lgd::Blocks const blocks{lgd::Blocks{raster_shape, block_shape}}; + + BOOST_CHECK_EQUAL(blocks.raster_shape(), raster_shape); + BOOST_CHECK_EQUAL(blocks.block_shape(), block_shape); + BOOST_CHECK_EQUAL(blocks.shape_in_blocks(), (lgd::Shape{60, 40})); + } + + { + lgd::Shape const raster_shape{50, 30}; + lgd::Shape const block_shape{6, 4}; + lgd::Blocks const blocks{lgd::Blocks{raster_shape, block_shape}}; + + BOOST_CHECK_EQUAL(blocks.raster_shape(), raster_shape); + BOOST_CHECK_EQUAL(blocks.block_shape(), block_shape); + BOOST_CHECK_EQUAL(blocks.shape_in_blocks(), (lgd::Shape{9, 8})); + } +} + + +BOOST_AUTO_TEST_CASE(shape_in_valid_cells) +{ + namespace lgd = lue::gdal; + + { + lgd::Shape const raster_shape{50, 30}; + lgd::Shape const block_shape{6, 4}; + lgd::Blocks const blocks{lgd::Blocks{raster_shape, block_shape}}; + + BOOST_CHECK_EQUAL(blocks.shape_in_valid_cells(lgd::Offset{0, 0}), block_shape); + BOOST_CHECK_EQUAL(blocks.shape_in_valid_cells(lgd::Offset{8, 0}), (lgd::Shape{2, 4})); + BOOST_CHECK_EQUAL(blocks.shape_in_valid_cells(lgd::Offset{0, 7}), (lgd::Shape{6, 2})); + BOOST_CHECK_EQUAL(blocks.shape_in_valid_cells(lgd::Offset{8, 7}), (lgd::Shape{2, 2})); + } } diff --git a/source/data_model/gdal/test/dataset_test.cpp b/source/data_model/gdal/test/dataset_test.cpp index f0c52c10b..80e29ea30 100644 --- a/source/data_model/gdal/test/dataset_test.cpp +++ b/source/data_model/gdal/test/dataset_test.cpp @@ -1,10 +1,67 @@ #define BOOST_TEST_MODULE lue gdal dataset_test #include "lue/gdal/dataset.hpp" +#include "lue/gdal/driver.hpp" #include +#include -BOOST_AUTO_TEST_CASE(dataset) +BOOST_AUTO_TEST_CASE(try_open_dataset) +{ + namespace lgd = lue::gdal; + + lgd::register_gdal_drivers(); + + std::string const driver_name{"GTiff"}; + std::string const dataset_name{"try_open_dataset.tif"}; + lgd::Shape const raster_shape{60, 40}; + lgd::Count const nr_bands{1}; + GDALDataType const data_type{GDALDataType::GDT_Int32}; + + if (std::filesystem::exists(dataset_name)) + { + lgd::delete_dataset(*lgd::driver(driver_name), dataset_name); + } + + // File does not exist + BOOST_CHECK(!lgd::try_open_dataset(dataset_name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(!lgd::try_open_dataset(dataset_name, GDALAccess::GA_Update)); + + lgd::create_dataset(driver_name, dataset_name, raster_shape, nr_bands, data_type); + + // File exists but is not readable and not writable + std::filesystem::permissions(dataset_name, std::filesystem::perms::none); + BOOST_CHECK(!lgd::try_open_dataset(dataset_name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(!lgd::try_open_dataset(dataset_name, GDALAccess::GA_Update)); + + // File exists but is write-only: not readable + std::filesystem::permissions(dataset_name, std::filesystem::perms::owner_write); + BOOST_CHECK(!lgd::try_open_dataset(dataset_name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(!lgd::try_open_dataset(dataset_name, GDALAccess::GA_Update)); + + // File exists and is read-only: not writable + std::filesystem::permissions(dataset_name, std::filesystem::perms::owner_read); + BOOST_CHECK(lgd::try_open_dataset(dataset_name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(!lgd::try_open_dataset(dataset_name, GDALAccess::GA_Update)); + + // File exists and is readable and writable + std::filesystem::permissions( + dataset_name, std::filesystem::perms::owner_read | std::filesystem::perms::owner_write); + BOOST_CHECK(lgd::try_open_dataset(dataset_name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(lgd::try_open_dataset(dataset_name, GDALAccess::GA_Update)); +} + + +BOOST_AUTO_TEST_CASE(open_dataset) { // TODO - BOOST_CHECK(true); + + // namespace lgd = lue::gdal; + + // lgd::register_gdal_drivers(); + + // std::string const driver_name{"GTiff"}; + // std::string const dataset_name{"open_dataset.tif"}; + // lgd::Shape const raster_shape{60, 40}; + // lgd::Count const nr_bands{1}; + // GDALDataType const data_type{GDALDataType::GDT_Int32}; } diff --git a/source/data_model/translate/include/lue/translate/format/gdal.hpp b/source/data_model/translate/include/lue/translate/format/gdal.hpp index fc7f6ad78..d111851cb 100644 --- a/source/data_model/translate/include/lue/translate/format/gdal.hpp +++ b/source/data_model/translate/include/lue/translate/format/gdal.hpp @@ -10,7 +10,7 @@ namespace lue::utility { auto memory_data_type_to_gdal_data_type(hdf5::Datatype const& data_type) -> GDALDataType; - auto translate_lue_dataset_to_raster( + auto translate_lue_dataset_to_gdal_raster( data_model::Dataset& dataset, std::string const& raster_name, Metadata const& metadata) -> void; auto try_open_gdal_raster_dataset_for_read(std::string const& dataset_name) -> gdal::DatasetPtr; diff --git a/source/data_model/translate/src/command/export.cpp b/source/data_model/translate/src/command/export.cpp index 664fdaf93..c3668604e 100644 --- a/source/data_model/translate/src/command/export.cpp +++ b/source/data_model/translate/src/command/export.cpp @@ -102,7 +102,7 @@ Translate data from the LUE dataset format else if (std::filesystem::path(output_dataset_name).extension() == ".tif") { // Write information from the dataset to one or more rasters - translate_lue_dataset_to_raster(*lue_dataset, output_dataset_name, metadata); + translate_lue_dataset_to_gdal_raster(*lue_dataset, output_dataset_name, metadata); } // else if(std::filesystem::path(output_dataset_name).extension() == ".vtk") { // // Create a VTK file of the dataset. diff --git a/source/data_model/translate/src/format/gdal.cpp b/source/data_model/translate/src/format/gdal.cpp index 350e08839..fa8f8089e 100644 --- a/source/data_model/translate/src/format/gdal.cpp +++ b/source/data_model/translate/src/format/gdal.cpp @@ -5,6 +5,35 @@ namespace lue::utility { + namespace { + + auto blocks(gdal::Shape const& band_shape, gdal::Shape const& block_shape) -> gdal::Blocks + { + auto [block_size_y, block_size_x] = block_shape; + + assert(block_size_x >= 0); + assert(block_size_y >= 0); + + auto [nr_rows, nr_cols] = band_shape; + + assert(nr_rows >= 0); + assert(nr_cols >= 0); + + // TODO Enlarge given some heuristics: + // - A whole number of times the actual block size (in each dimension) + // - Number of cells below some sensible value (1GB?) + block_size_x *= 10; + block_size_y *= 10; + + block_size_x = std::min(block_size_x, nr_cols); + block_size_y = std::min(block_size_y, nr_rows); + + return {{nr_cols, nr_rows}, {block_size_x, block_size_y}}; + } + + } // Anonymous namespace + + auto gdal_data_type_to_memory_data_type(GDALDataType const data_type) -> hdf5::Datatype { hdf5::Datatype result{}; @@ -130,7 +159,7 @@ namespace lue::utility { // locations in time. The 2D array to write to the raster band is // located at the index passed in. - auto const blocks = raster_band.blocks(); + auto const blocks = utility::blocks(raster_band.size(), raster_band.block_size()); auto const& block_shape = blocks.block_shape(); std::vector values(gdal::nr_elements(block_shape)); @@ -164,7 +193,7 @@ namespace lue::utility { hdf5::Hyperslab const hyperslab{offset, count}; value.read(memory_datatype, hyperslab, values.data()); - raster_band.write_block({block_x, block_y}, values.data()); + raster_band.write_block({block_y, block_x}, values.data()); } } } @@ -225,7 +254,7 @@ namespace lue::utility { void lue_to_gdal(data_model::Array const& array, gdal::Raster::Band& raster_band) { // It is assumed here that array only contains a 2D array - auto const blocks = raster_band.blocks(); + auto const blocks = utility::blocks(raster_band.size(), raster_band.block_size()); auto const& block_shape = blocks.block_shape(); std::vector values(gdal::nr_elements(block_shape)); @@ -249,7 +278,7 @@ namespace lue::utility { hdf5::Hyperslab const hyperslab{offset, count}; array.read(memory_datatype, hyperslab, values.data()); - raster_band.write_block({block_x, block_y}, values.data()); + raster_band.write_block({block_y, block_x}, values.data()); } } } @@ -310,7 +339,7 @@ namespace lue::utility { } - auto translate_lue_dataset_to_raster( + auto translate_lue_dataset_to_gdal_raster( data_model::Dataset& dataset, std::string const& raster_name, Metadata const& metadata) -> void { // Figure out which property-sets are selected @@ -669,9 +698,9 @@ namespace lue::utility { template< typename RasterView, typename T> // In-file GDAL element type - void gdal_to_lue(gdal::Raster::Band const& gdal_raster_band, typename RasterView::Layer& lue_raster_layer) + void gdal_to_lue(gdal::Raster::Band& gdal_raster_band, typename RasterView::Layer& lue_raster_layer) { - auto const blocks = gdal_raster_band.blocks(); + auto const blocks = utility::blocks(gdal_raster_band.size(), gdal_raster_band.block_size()); auto const& block_shape = blocks.block_shape(); std::vector values(gdal::nr_elements(block_shape)); @@ -692,7 +721,7 @@ namespace lue::utility { static_cast(nr_valid_cells_x)}; hdf5::Hyperslab hyperslab{offset, count}; - gdal_raster_band.read_block({block_x, block_y}, values.data()); + gdal_raster_band.read_block({block_y, block_x}, values.data()); hdf5::Shape const shape = { static_cast(nr_valid_cells_x * nr_valid_cells_y)}; auto memory_dataspace = hdf5::create_dataspace(shape); @@ -703,7 +732,7 @@ namespace lue::utility { template - void gdal_to_lue(gdal::Raster::Band const& gdal_raster_band, typename RasterView::Layer& lue_raster_layer) + void gdal_to_lue(gdal::Raster::Band& gdal_raster_band, typename RasterView::Layer& lue_raster_layer) { GDALDataType const data_type{gdal_raster_band.data_type()}; @@ -799,7 +828,7 @@ namespace lue::utility { assert(!gdal_dataset_names.empty()); - gdal::Raster const gdal_raster{gdal_dataset_names[0]}; + gdal::Raster const gdal_raster{gdal::open_dataset(gdal_dataset_names[0], GDALAccess::GA_ReadOnly)}; auto const [nr_rows, nr_cols] = gdal_raster.shape(); auto const [west, cell_width, row_rotation, north, col_rotation, cell_height] = gdal_raster.geo_transform(); @@ -837,7 +866,7 @@ namespace lue::utility { for (std::string const& gdal_dataset_name : gdal_dataset_names) { - gdal::Raster const gdal_raster{gdal_dataset_name}; + gdal::Raster const gdal_raster{gdal::open_dataset(gdal_dataset_name, GDALAccess::GA_ReadOnly)}; std::string const raster_layer_name{std::filesystem::path(gdal_dataset_name).stem().string()}; diff --git a/source/data_model/translate/src/format/json.cpp b/source/data_model/translate/src/format/json.cpp index 9d4e60e43..460a8d1fc 100644 --- a/source/data_model/translate/src/format/json.cpp +++ b/source/data_model/translate/src/format/json.cpp @@ -33,7 +33,7 @@ namespace lue { hdf5::Shape read_gdal_raster(std::string const& pathname, Collection& collection) { // Open dataset - gdal::Raster raster{pathname}; + gdal::Raster raster{gdal::open_dataset(pathname, GDALAccess::GA_ReadOnly)}; // Verify dataset is OK for us assert(raster.nr_bands() == 1); @@ -126,7 +126,7 @@ namespace lue { template std::vector read_space_box(std::string const& dataset_name) { - auto const raster = gdal::Raster{dataset_name}; + auto const raster = gdal::Raster{gdal::open_dataset(dataset_name, GDALAccess::GA_ReadOnly)}; auto const [nr_rows, nr_cols] = raster.shape(); auto const [west, cell_width, row_rotation, north, col_rotation, cell_height] = raster.geo_transform(); diff --git a/source/data_model/translate/test/import_test.cpp b/source/data_model/translate/test/import_test.cpp index dcfbd79f4..9b52dcbe8 100644 --- a/source/data_model/translate/test/import_test.cpp +++ b/source/data_model/translate/test/import_test.cpp @@ -3,6 +3,7 @@ #include "lue/translate/format.hpp" #include "lue/validate.hpp" #include +#include /* @@ -354,44 +355,77 @@ BOOST_AUTO_TEST_CASE(new_rasters) BOOST_AUTO_TEST_CASE(raster_round_trip_01) { + namespace ldm = lue::data_model; namespace lgd = lue::gdal; namespace lu = lue::utility; lgd::register_gdal_drivers(); - std::string const gdal_driver_name{"MEM"}; + auto* gdal_driver_ptr = lgd::driver("GTiff"); - // Create an input GDAL raster // - Integral element type // - Set some value as no-data value - std::string const input_raster_name{"raster_round_trip_01_in"}; lgd::Shape const& raster_shape{6, 4}; lue::data_model::Count const nr_bands{1}; - GDALDataType const gdal_data_type{GDT_Int32}; + using Element = std::int32_t; + GDALDataType const gdal_data_type{lgd::data_type_v}; + Element const no_data_value{5}; + std::vector elements(lgd::nr_elements(raster_shape)); + std::iota(elements.begin(), elements.end(), 1); - lgd::DatasetPtr input_dataset_ptr{ - lgd::create_dataset(gdal_driver_name, input_raster_name, raster_shape, nr_bands, gdal_data_type)}; - lgd::Raster input_raster{input_dataset_ptr}; - lgd::Raster::Band band{input_raster.band(1)}; + // Center is at (0, 0) + lgd::Coordinate const west{-20}; + lgd::Coordinate const north{30}; + lgd::Extent const cell_width{10}; + lgd::Extent const cell_height{10}; - // TODO set elements - // TODO set no-data value + lgd::GeoTransform const geo_transform{west, cell_width, 0, north, 0, -cell_height}; + // Create an input GDAL raster + std::string const input_gdal_raster_name{"raster_round_trip_01_in.tif"}; + { + lgd::Raster input_raster{lgd::create_dataset( + *gdal_driver_ptr, input_gdal_raster_name, raster_shape, nr_bands, gdal_data_type)}; + lgd::Raster::Band band{input_raster.band(1)}; - // Import raster into LUE data set + // Set geo-transform + input_raster.set_geo_transform(geo_transform); + // Set no-data value + band.set_no_data_value(no_data_value); - // TODO + // Set elements + band.write(elements.data()); + } + // Import raster into LUE data set + std::string const lue_dataset_name{"raster_round_trip_01.lue"}; + { + bool const add{false}; + lu::Metadata metadata{}; - // Export GDAL raster again - std::string const output_raster_name{"raster_round_trip_01_out"}; + if (ldm::dataset_exists(lue_dataset_name)) + { + ldm::remove_dataset(lue_dataset_name); + } - // Verify imported and exported rasters are the same + lue::utility::translate_gdal_raster_dataset_to_lue( + {input_gdal_raster_name}, lue_dataset_name, add, metadata); + } + // Export GDAL raster again + std::string const output_gdal_raster_name{"raster_round_trip_01_out.tif"}; + { + lu::Metadata metadata{}; + + auto lue_dataset = ldm::open_dataset(lue_dataset_name); + // TODO + // lue::utility::translate_lue_dataset_to_gdal_raster(lue_dataset, output_gdal_raster_name, metadata); + } - // compare_rasters_equal(input_dataset_ptr, output_raster_dataset); // TODO + // Verify imported and exported rasters are the same + // compare_rasters_equal(input_gdal_dataset_ptr, output_raster_dataset); } diff --git a/source/framework/io/src/raster.cpp b/source/framework/io/src/raster.cpp index ba84f1901..f6dd7aa4e 100644 --- a/source/framework/io/src/raster.cpp +++ b/source/framework/io/src/raster.cpp @@ -116,24 +116,15 @@ namespace lue { // not block. ReadLock read_lock{_mutex}; - CPLErr const status{_band_ptr->RasterIO( - GF_Read, - offset[1], - offset[0], - data.shape()[1], - data.shape()[0], - data.data(), - data.shape()[1], - data.shape()[0], - gdal::data_type_v, - 0, - 0, - nullptr)}; - - if (status != CE_None) - { - throw std::runtime_error("Cannot read partition data"); - } + lue::gdal::Offset gdal_offset{ + static_cast(offset[0]), + static_cast(offset[1])}; + lue::gdal::Shape gdal_shape{ + static_cast(data.shape()[0]), + static_cast(data.shape()[1])}; + + lue::gdal::read( + *_band_ptr, gdal_offset, gdal_shape, gdal::data_type_v, data.data()); } @@ -365,31 +356,21 @@ namespace lue { // Open band // Write partition's data - gdal::DatasetPtr dataset_ptr{gdal::open_dataset(name, ::GA_Update)}; - gdal::RasterBandPtr band_ptr{gdal::raster_band(*dataset_ptr)}; + gdal::Raster raster{gdal::open_dataset(name, ::GA_Update)}; + gdal::Raster::Band raster_band{raster.band(1)}; auto partition_server_ptr{hpx::get_ptr(hpx::launch::sync, partition)}; auto data{partition_server_ptr->data()}; auto offset{partition_server_ptr->offset()}; - CPLErr const status{band_ptr->RasterIO( - GF_Write, - offset[1], - offset[0], - data.shape()[1], - data.shape()[0], - data.data(), - data.shape()[1], - data.shape()[0], - gdal::data_type_v, - 0, - 0, - nullptr)}; - - if (status != CE_None) - { - throw std::runtime_error("Cannot write partition data"); - } + lue::gdal::Offset gdal_offset{ + static_cast(offset[0]), + static_cast(offset[1])}; + lue::gdal::Shape gdal_shape{ + static_cast(data.shape()[0]), + static_cast(data.shape()[1])}; + + raster_band.write(gdal_offset, gdal_shape, gdal::data_type_v, data.data()); } diff --git a/source/framework/io/test/raster_test.cpp b/source/framework/io/test/raster_test.cpp index 14d00a3e3..28500c2e4 100644 --- a/source/framework/io/test/raster_test.cpp +++ b/source/framework/io/test/raster_test.cpp @@ -9,8 +9,6 @@ BOOST_AUTO_TEST_CASE(round_trip_1) { - lue::gdal::register_gdal_drivers(); - // int32_t, all valid using Element = std::int32_t; using Array = lue::PartitionedArray; @@ -23,18 +21,16 @@ BOOST_AUTO_TEST_CASE(round_trip_1) lue::write(array_written, name).wait(); - // TODO BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); - // TODO Array array_read{lue::read(name, partition_shape)}; + Array array_read{lue::read(name, partition_shape)}; - // TODO lue::test::check_arrays_are_equal(array_read, array_written); + lue::test::check_arrays_are_equal(array_read, array_written); } BOOST_AUTO_TEST_CASE(round_trip_2) { - lue::gdal::register_gdal_drivers(); - // int32_t, none valid using Element = std::int32_t; using Array = lue::PartitionedArray; @@ -47,18 +43,16 @@ BOOST_AUTO_TEST_CASE(round_trip_2) lue::write(array_written, name).wait(); - // TODO BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); - // TODO Array array_read{lue::read(name, partition_shape)}; + Array array_read{lue::read(name, partition_shape)}; - // TODO lue::test::check_arrays_are_equal(array_read, array_written); + lue::test::check_arrays_are_equal(array_read, array_written); } BOOST_AUTO_TEST_CASE(round_trip_3) { - lue::gdal::register_gdal_drivers(); - // float, all valid using Element = float; using Array = lue::PartitionedArray; @@ -71,18 +65,16 @@ BOOST_AUTO_TEST_CASE(round_trip_3) lue::write(array_written, name).wait(); - // TODO BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); - // TODO Array array_read{lue::read(name, partition_shape)}; + Array array_read{lue::read(name, partition_shape)}; - // TODO lue::test::check_arrays_are_equal(array_read, array_written); + lue::test::check_arrays_are_equal(array_read, array_written); } BOOST_AUTO_TEST_CASE(round_trip_4) { - lue::gdal::register_gdal_drivers(); - // float, none valid using Element = float; using Array = lue::PartitionedArray; @@ -95,9 +87,9 @@ BOOST_AUTO_TEST_CASE(round_trip_4) lue::write(array_written, name).wait(); - // TODO BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); + BOOST_CHECK(lue::gdal::try_open_dataset(name, GDALAccess::GA_ReadOnly)); - // TODO Array array_read{lue::read(name, partition_shape)}; + Array array_read{lue::read(name, partition_shape)}; - // TODO lue::test::check_arrays_are_equal(array_read, array_written); + lue::test::check_arrays_are_equal(array_read, array_written); } diff --git a/source/framework/test/CMakeLists.txt b/source/framework/test/CMakeLists.txt index 7659848e7..8fc01cffd 100644 --- a/source/framework/test/CMakeLists.txt +++ b/source/framework/test/CMakeLists.txt @@ -12,4 +12,5 @@ target_include_directories(lue_framework_test target_link_libraries(lue_framework_test INTERFACE lue::framework_partitioned_array + lue::gdal ) diff --git a/source/framework/test/include/lue/framework/test/hpx_unit_test.hpp b/source/framework/test/include/lue/framework/test/hpx_unit_test.hpp index b636b79bf..0ed0cf4b9 100644 --- a/source/framework/test/include/lue/framework/test/hpx_unit_test.hpp +++ b/source/framework/test/include/lue/framework/test/hpx_unit_test.hpp @@ -1,6 +1,7 @@ #pragma once #define BOOST_TEST_NO_MAIN #define BOOST_TEST_ALTERNATIVE_INIT_API +#include "lue/gdal.hpp" #include #include #include @@ -8,7 +9,7 @@ // https://stellar-group.github.io/hpx/docs/html/hpx.html#hpx.manual.applications -// http://www.boost.org/doc/libs/1_64_0/libs/test/doc/html/boost_test/adv_scenarios/entry_point_overview.html +// ħttps://www.boost.org/doc/libs/1_84_0/libs/test/doc/html/boost_test/adv_scenarios/entry_point_overview.html int hpx_main(int argc, char* argv[]) @@ -22,22 +23,15 @@ int hpx_main(int argc, char* argv[]) int main(int argc, char* argv[]) -// char* envp[]) { - // Blocks until HPX runtime system exists + // Make sure that processes in tests that depend on GDAL drivers have access to the GDAL + // drivers + lue::gdal::register_gdal_drivers(); - // TODO Compare with CMake logic in LueMacro.cmake. We are handling - // this from the outside already and should not hardcode - // this here. - std::vector const cfg{// Use this number of threads per locality. This will utilize - // the same number of cores per locality. - "hpx.os_threads!=4"}; + std::vector const cfg{}; hpx::init_params params{}; params.cfg = {cfg}; - // TODO For some reason HPX complains about test specific arguments not - // being supported. It should skip unsupported arguments and pass them - // on to hpx_main. Not sure why it doesn't in this case. return hpx::init(argc, argv, params); }