From a123071fec7743c250629c61f9e1ebae2aa83968 Mon Sep 17 00:00:00 2001 From: robin Date: Sun, 21 Apr 2024 14:20:23 +0200 Subject: [PATCH] feat: modules --- linear-interpolation/.gitignore | 6 +++ linear-interpolation/README.md | 39 +++++++++++++++ linear-interpolation/src/CMakeLists.txt | 36 ++++++++++++++ linear-interpolation/src/main.cpp | 18 +++++++ linear-interpolation/src/readdata.cpp | 66 +++++++++++++++++++++++++ linear-interpolation/src/readdata.h | 18 +++++++ linear-interpolation/src/vecutils.cpp | 14 ++++++ linear-interpolation/src/vecutils.h | 47 ++++++++++++++++++ 8 files changed, 244 insertions(+) create mode 100644 linear-interpolation/.gitignore create mode 100644 linear-interpolation/README.md create mode 100644 linear-interpolation/src/CMakeLists.txt create mode 100644 linear-interpolation/src/main.cpp create mode 100644 linear-interpolation/src/readdata.cpp create mode 100644 linear-interpolation/src/readdata.h create mode 100644 linear-interpolation/src/vecutils.cpp create mode 100644 linear-interpolation/src/vecutils.h diff --git a/linear-interpolation/.gitignore b/linear-interpolation/.gitignore new file mode 100644 index 0000000..95abd3d --- /dev/null +++ b/linear-interpolation/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +src/.DS_Store +src/.cache +src/build +.idea +src/cmake-build-debug \ No newline at end of file diff --git a/linear-interpolation/README.md b/linear-interpolation/README.md new file mode 100644 index 0000000..ec2a268 --- /dev/null +++ b/linear-interpolation/README.md @@ -0,0 +1,39 @@ +## Location of data +The data path is hardcoded such that the following tree structure is assumed: +``` +data/ + grid.h5 + hydrodynamic_U.h5 + hydrodynamic_V.h5 +interactive-track-and-trace/ + opening-hdf5/ + ... +``` + +## Compiling +Let the current directory be the `src` directory. Run: +```shell +mkdir build +cd build +cmake .. +make +``` + +### Building with Linux +Makes use of `mdspan` which is not supported by glibc++ at time of writing. See [compiler support](https://en.cppreference.com/w/cpp/compiler_support/23) for `mdspan`. The solution to this is to use Clang and libc++; this is configured in our CMake setup, however the default installation of the `netcdf-cxx` package on at least Arch linux (and suspectedly Debian derivatives as well) specifically builds for the glibc implementation. To get the netcdf C++ bindings functional with the libc++ implementation, one needs to build from source. On Linux, this requires a few changes to the CMake file included with the netcdf-cxx source code, which are detailed below. + +Step-by-step to build the program using clang++ and libc++ on linux: + 1. Download the source code of netcdf-cxx, found at 'https://github.com/Unidata/netcdf-cxx4/releases/tag/v4.3.1' (make sure to download the release source code, as the master branch contains non-compilable code). + 2. Edit the CMakeLists.txt file, by appending '-stdlib=libc++' to the `CMAKE_CXX_FLAGS` variable in line 430. This means line 430 should read: + ```cmake + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wno-unused-variable -Wno-unused-parameter -stdlib=libc++") + ``` + 2. Build the source code with the following: + ```sh + mkdir build && cd build + cmake .. -DCMAKE_CXX_COMPILER=/usr/bin/clang++ + make + ctest + sudo make install + ``` + 3. Now the code should compile through the standard steps described in the Compiling section. diff --git a/linear-interpolation/src/CMakeLists.txt b/linear-interpolation/src/CMakeLists.txt new file mode 100644 index 0000000..b8b6abb --- /dev/null +++ b/linear-interpolation/src/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required (VERSION 3.28) +project (LinearInterpolate) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Force use of libc++ for mdspan support +set(CMAKE_CXX_COMPILER "clang++") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ ") + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +find_package(netCDF REQUIRED) + +add_executable(LinearInterpolate main.cpp + readdata.cpp + readdata.h + vecutils.cpp + vecutils.h) + +execute_process( + COMMAND nc-config --includedir + OUTPUT_VARIABLE NETCDF_INCLUDE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( + COMMAND ncxx4-config --libdir + OUTPUT_VARIABLE NETCDFCXX_LIB_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +target_include_directories(LinearInterpolate PUBLIC ${netCDF_INCLUDE_DIR}) + +find_library(NETCDF_LIB NAMES netcdf-cxx4 netcdf_c++4 PATHS ${NETCDFCXX_LIB_DIR} NO_DEFAULT_PATH) +target_link_libraries(LinearInterpolate ${NETCDF_LIB}) diff --git a/linear-interpolation/src/main.cpp b/linear-interpolation/src/main.cpp new file mode 100644 index 0000000..8792393 --- /dev/null +++ b/linear-interpolation/src/main.cpp @@ -0,0 +1,18 @@ +#include "readdata.h" + +#include + +using namespace std; + +int main() { + auto [vec, size] = readHydrodynamicU(); + + auto arr = std::mdspan(vec.data(), size); + + print3DMatrixSlice(arr, 100); + + auto [times, lats, longs] = readGrid(); + printContentsOfVec(lats); + + return 0; +} diff --git a/linear-interpolation/src/readdata.cpp b/linear-interpolation/src/readdata.cpp new file mode 100644 index 0000000..6cc7726 --- /dev/null +++ b/linear-interpolation/src/readdata.cpp @@ -0,0 +1,66 @@ +#include +#include + +#include + +#include "readdata.h" + +using namespace std; +using namespace netCDF; + +template +vector getVarVector(const NcVar &var) { + int length = 1; + for (NcDim dim : var.getDims()) { + length *= dim.getSize(); + } + + vector vec(length); + + var.getVar(vec.data()); + + return vec; +} + +/** + * Read a 3D matrix from a NetCDF variable. + * Reads data into a contiguous 1D data vector. + * Returns a pair of the size of the matrix (in the form of an extent) with the data vector. + * + * Inteded usage of this function involves using the two returned values + * to create an mdspan: + * + * auto arr = mdspan(vec.data(), size); + */ +template +pair, std::dextents> get3DMat(const NcVar &var) { + if(var.getDimCount() != 3) { + throw invalid_argument("Variable is not 3D"); + } + int timeLength = var.getDim(0).getSize(); + int latLength = var.getDim(1).getSize(); + int longLength = var.getDim(2).getSize(); + vector vec(timeLength*latLength*longLength); + var.getVar(vec.data()); + auto arr = std::mdspan(vec.data(), timeLength, latLength, longLength); + + return {vec, arr.extents()}; +} + +pair, std::dextents> readHydrodynamicU() { + netCDF::NcFile data("../../../../data/hydrodynamic_U.h5", netCDF::NcFile::read); + + multimap< string, NcVar > vars = data.getVars(); + + return get3DMat(vars.find("uo")->second); +} + +tuple, vector, vector> readGrid() { + netCDF::NcFile data("../../../../data/grid.h5", netCDF::NcFile::read); + multimap< string, NcVar > vars = data.getVars(); + vector time = getVarVector(vars.find("times")->second); + vector longitude = getVarVector(vars.find("longitude")->second); + vector latitude = getVarVector(vars.find("latitude")->second); + + return {time, latitude, longitude}; +} \ No newline at end of file diff --git a/linear-interpolation/src/readdata.h b/linear-interpolation/src/readdata.h new file mode 100644 index 0000000..c5effb5 --- /dev/null +++ b/linear-interpolation/src/readdata.h @@ -0,0 +1,18 @@ +#ifndef LINEARINTERPOLATE_READDATA_H +#define LINEARINTERPOLATE_READDATA_H + +#include "vecutils.h" + +/** + * Reads the file hydrodynamic_U.h5 + * @return a pair of the data vector of the contents and its dimensions to be used with mdspan + */ +std::pair, std::dextents> readHydrodynamicU(); + +/** + * Reads the file grid.h5 + * @return a tuple of (times, latitude, longitude) + */ +std::tuple, std::vector, std::vector> readGrid(); + +#endif //LINEARINTERPOLATE_READDATA_H diff --git a/linear-interpolation/src/vecutils.cpp b/linear-interpolation/src/vecutils.cpp new file mode 100644 index 0000000..f367b3d --- /dev/null +++ b/linear-interpolation/src/vecutils.cpp @@ -0,0 +1,14 @@ +#include + +#include "vecutils.h" + +using namespace std; + +void print3DMatrixSlice(const arr3d &arr, int t) { + for (int x = 0; x < arr.extent(1); x++) { + for (int y = 0; y < arr.extent(2); y++) { + print("{:>10.4f} ", arr[t,x,y]); + } + println(""); + } +} diff --git a/linear-interpolation/src/vecutils.h b/linear-interpolation/src/vecutils.h new file mode 100644 index 0000000..5ddeec6 --- /dev/null +++ b/linear-interpolation/src/vecutils.h @@ -0,0 +1,47 @@ +#ifndef LINEARINTERPOLATE_VECUTILS_H +#define LINEARINTERPOLATE_VECUTILS_H + +#include +#include + +template +using arr3d = std::mdspan< + T, + std::dextents< + std::size_t, + 3 + > +>; + +/** + * Print contents of vector + * @tparam T The type of the data inside the vector + * @param vec The vector to be printed + */ +template +void printContentsOfVec(const std::vector& vec) { + for (const auto& element : vec) { + std::print("{} ", element); + + } + std::println(""); +} + +/** + * Print matrix [x,y] for all values arr[t,x,y] + * @param arr matrix to be printed + * @param t value to slice matrix with + */ +template +void print3DMatrixSlice(const arr3d &arr, int t) { + for (int x = 0; x < arr.extent(1); x++) { + for (int y = 0; y < arr.extent(2); y++) { + std::print("{} ", arr[t,x,y]); + } + std::println(""); + } +} + +void print3DMatrixSlice(const arr3d &arr, int t); + +#endif //LINEARINTERPOLATE_VECUTILS_H