From b2415d8c4d361ceb5cb44145b9237ea3c9231953 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 23 Apr 2024 12:21:08 +0200 Subject: [PATCH] removed mdspan requirement --- .gitignore | 1 + linear-interpolation/.gitignore | 3 +- linear-interpolation/src/CMakeLists.txt | 10 +---- linear-interpolation/src/UVGrid.cpp | 52 ++++++++++++++++++++---- linear-interpolation/src/UVGrid.h | 39 ++++++++++++++---- linear-interpolation/src/Vel.cpp | 33 +++++++++++++++ linear-interpolation/src/Vel.h | 44 ++++++++++++++++++++ linear-interpolation/src/interpolate.cpp | 52 ++++++++++++++---------- linear-interpolation/src/interpolate.h | 20 ++++++++- linear-interpolation/src/main.cpp | 45 ++++++++++++++++++-- linear-interpolation/src/point.cpp | 11 ----- linear-interpolation/src/point.h | 27 ------------ linear-interpolation/src/readdata.cpp | 33 ++------------- linear-interpolation/src/readdata.h | 10 ++--- linear-interpolation/src/vecutils.cpp | 24 ----------- linear-interpolation/src/vecutils.h | 48 ---------------------- 16 files changed, 255 insertions(+), 197 deletions(-) create mode 100644 linear-interpolation/src/Vel.cpp create mode 100644 linear-interpolation/src/Vel.h delete mode 100644 linear-interpolation/src/point.cpp delete mode 100644 linear-interpolation/src/point.h delete mode 100644 linear-interpolation/src/vecutils.cpp delete mode 100644 linear-interpolation/src/vecutils.h diff --git a/.gitignore b/.gitignore index 5ca0973..08302ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store +.idea diff --git a/linear-interpolation/.gitignore b/linear-interpolation/.gitignore index 95abd3d..34ddd4b 100644 --- a/linear-interpolation/.gitignore +++ b/linear-interpolation/.gitignore @@ -3,4 +3,5 @@ src/.DS_Store src/.cache src/build .idea -src/cmake-build-debug \ No newline at end of file +src/cmake-build-debug +src/cmake-build-release diff --git a/linear-interpolation/src/CMakeLists.txt b/linear-interpolation/src/CMakeLists.txt index e293e85..9428e41 100644 --- a/linear-interpolation/src/CMakeLists.txt +++ b/linear-interpolation/src/CMakeLists.txt @@ -4,10 +4,6 @@ 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) @@ -15,14 +11,12 @@ find_package(netCDF REQUIRED) add_executable(LinearInterpolate main.cpp readdata.cpp readdata.h - vecutils.cpp - vecutils.h interpolate.cpp interpolate.h UVGrid.cpp UVGrid.h - point.h - point.cpp) + Vel.h + Vel.cpp) execute_process( COMMAND nc-config --includedir diff --git a/linear-interpolation/src/UVGrid.cpp b/linear-interpolation/src/UVGrid.cpp index aa493eb..16eabc6 100644 --- a/linear-interpolation/src/UVGrid.cpp +++ b/linear-interpolation/src/UVGrid.cpp @@ -1,18 +1,42 @@ -#include #include +#include #include "UVGrid.h" #include "readdata.h" +#define sizeError2 "The sizes of the hydrodynamic data files are different" +#define sizeError "The sizes of the hydrodynamicU or -V files does not correspond with the sizes of the grid file" + using namespace std; UVGrid::UVGrid() { - auto [us, sizeU] = readHydrodynamicU(); - auto [vs, sizeV] = readHydrodynamicV(); - // Assuming sizeU == sizeV - uvData = views::zip(us, vs) | ranges::to(); - uvMatrix = mdspan(uvData.data(), sizeU); + auto us = readHydrodynamicU(); + auto vs = readHydrodynamicV(); + if (us.size() != vs.size()) { + throw domain_error(sizeError2); + } + tie(times, lats, lons) = readGrid(); + + timeSize = times.size(); + latSize = lats.size(); + lonSize = lons.size(); + + size_t gridSize = timeSize * latSize * lonSize; + if (gridSize != us.size()) { + throw domain_error(sizeError); + } + + uvData = views::zip(us, vs) + | views::transform([](auto pair) { + return Vel(pair); + }) + | ranges::to(); +} + +const Vel &UVGrid::operator[](size_t timeIndex, size_t latIndex, size_t lonIndex) const { + size_t index = timeIndex * (latSize * lonSize) + latIndex * lonIndex + lonIndex; + return uvData[index]; } double UVGrid::lonStep() const { @@ -20,9 +44,19 @@ double UVGrid::lonStep() const { } double UVGrid::latStep() const { - return lats[1]-lats[0]; + return lats[1] - lats[0]; } int UVGrid::timeStep() const { - return times[1]-times[0]; -} \ No newline at end of file + return times[1] - times[0]; +} + +void UVGrid::printSlice(size_t t) { + for (int x = 0; x < latSize; x++) { + for (int y = 0; y < lonSize; y++) { + auto [u,v] = (*this)[t,x,y]; + print("({:>7.4f}, {:>7.4f}) ", u, v); + } + println(""); + } +} diff --git a/linear-interpolation/src/UVGrid.h b/linear-interpolation/src/UVGrid.h index 23642f3..613bd77 100644 --- a/linear-interpolation/src/UVGrid.h +++ b/linear-interpolation/src/UVGrid.h @@ -2,29 +2,54 @@ #define LINEARINTERPOLATE_UVGRID_H #include -#include "vecutils.h" -#include "point.h" +#include "Vel.h" class UVGrid { private: /** - * u == Eastward Current Velocity in the Water Column - * v == Northward Current Velocity in the Water Column + * 1D data vector of all the us and vs */ - std::vector uvData; + std::vector uvData; public: UVGrid(); - // The step functions assume regular spacing + size_t timeSize; + size_t latSize; + size_t lonSize; + + /** + * Assuming grid is a regular grid, gives the longitudinal spacing of grid. + * @return longitudinal spacing + */ double lonStep() const; + + /** + * Assuming grid is a regular grid, gives the latitudinal spacing of grid. + * @return latitudinal spacing + */ double latStep() const; + + /** + * Assuming grid is a regular grid, gives the time spacing of grid. + * @return time spacing + */ int timeStep() const; std::vector times; std::vector lats; std::vector lons; - arr3d uvMatrix; + /** + * The 3D index into the data + * @return Velocity at that index + */ + const Vel& operator[](size_t timeIndex, size_t latIndex, size_t lonIndex) const; + + // Friend declaration for the stream insertion operator + friend std::ostream& operator<<(std::ostream& os, const UVGrid& vel); + + void printSlice(size_t t); }; + #endif //LINEARINTERPOLATE_UVGRID_H diff --git a/linear-interpolation/src/Vel.cpp b/linear-interpolation/src/Vel.cpp new file mode 100644 index 0000000..803e8f2 --- /dev/null +++ b/linear-interpolation/src/Vel.cpp @@ -0,0 +1,33 @@ +#include "Vel.h" +#include + +Vel::Vel(double u, double v) : u(u), v(v) {} + +Vel::Vel(const std::pair& p) : u(p.first), v(p.second) {} + +Vel& Vel::operator=(const std::pair& p) { + u = p.first; + v = p.second; + return *this; +} + +Vel Vel::operator+(const Vel& other) const { + return Vel(u + other.u, v + other.v); +} + +Vel& Vel::operator+=(const Vel& other) { + u += other.u; + v += other.v; + return *this; +} + +template +Vel Vel::operator/(Scalar scalar) const { + if (scalar == 0) throw std::runtime_error("Division by zero"); + return Vel(u / scalar, v / scalar); +} + +std::ostream& operator<<(std::ostream& os, const Vel& vel) { + os << "(" << vel.u << ", " << vel.v << ")"; + return os; +} diff --git a/linear-interpolation/src/Vel.h b/linear-interpolation/src/Vel.h new file mode 100644 index 0000000..ec7ce52 --- /dev/null +++ b/linear-interpolation/src/Vel.h @@ -0,0 +1,44 @@ +#ifndef LINEARINTERPOLATE_VEL_H +#define LINEARINTERPOLATE_VEL_H + +#include +#include +#include +#include + +class Vel { +public: + double u; // Eastward Current Velocity in the Water Column + double v; // Northward Current Velocity in the Water Column + + Vel(double u, double v); + Vel(const std::pair& p); // Conversion constructor + Vel& operator=(const std::pair& p); + + // Operator + to add two Vel objects + Vel operator+(const Vel& other) const; + + // Operator += to add another Vel object to this object + Vel& operator+=(const Vel& other); + + // Operator * to multiply Vel by a scalar, defined as a member template + template + Vel operator*(Scalar scalar) const { + return Vel(u * scalar, v * scalar); + } + + // Operator / to divide Vel by a scalar, defined as a member template + template + Vel operator/(Scalar scalar) const; + + // Friend declaration for the stream insertion operator + friend std::ostream& operator<<(std::ostream& os, const Vel& vel); +}; + +// Non-member function for scalar multiplication on the left +template +Vel operator*(Scalar scalar, const Vel& p) { + return Vel(p.u * scalar, p.v * scalar); +} + +#endif //LINEARINTERPOLATE_VEL_H diff --git a/linear-interpolation/src/interpolate.cpp b/linear-interpolation/src/interpolate.cpp index f39e801..579e241 100644 --- a/linear-interpolation/src/interpolate.cpp +++ b/linear-interpolation/src/interpolate.cpp @@ -1,39 +1,37 @@ #include - #include +#include + #include "interpolate.h" using namespace std; -// Inspired by https://numerical.recipes/book.html Chapter 3.6 -point bilinearInterpolate(const UVGrid &uvGrid, std::tuple timeLatLon) { - auto [time, lat, lon] = timeLatLon; - +Vel bilinearInterpolate(const UVGrid &uvGrid, int time, double lat, double lon) { double latStep = uvGrid.latStep(); double lonStep = uvGrid.lonStep(); int timeStep = uvGrid.timeStep(); - int latIndex = (lat-uvGrid.lats[0])/latStep; - int lonIndex = (lon-uvGrid.lons[0])/lonStep; - int timeIndex = (time-uvGrid.times[0])/timeStep; + int latIndex = (lat - uvGrid.lats[0]) / latStep; + int lonIndex = (lon - uvGrid.lons[0]) / lonStep; + int timeIndex = (time - uvGrid.times[0]) / timeStep; - double timeRatio = (static_cast(time)-uvGrid.times[timeIndex])/timeStep; - double latRatio = (lat-uvGrid.lats[latIndex]) / latStep; - double lonRatio = (lon-uvGrid.lons[lonIndex]) / lonStep; + double timeRatio = (static_cast(time) - uvGrid.times[timeIndex]) / timeStep; + double latRatio = (lat - uvGrid.lats[latIndex]) / latStep; + double lonRatio = (lon - uvGrid.lons[lonIndex]) / lonStep; - point point = {0, 0}; - for(int time = 0; time <= 1; time++) { - for(int lat = 0; lat <= 1; lat++) { - for(int lon = 0; lon <= 1; lon++) { - auto vertex = uvGrid.uvMatrix[ - timeIndex + time < uvGrid.uvMatrix.extent(0) ? timeIndex + 1 : timeIndex, - latIndex + lat < uvGrid.uvMatrix.extent(1) ? latIndex + 1 : latIndex, - lonIndex + lon < uvGrid.uvMatrix.extent(2) ? lonIndex + 1 : lonIndex + Vel point = {0, 0}; + for (int timeOffset = 0; timeOffset <= 1; timeOffset++) { + for (int latOffset = 0; latOffset <= 1; latOffset++) { + for (int lonOffset = 0; lonOffset <= 1; lonOffset++) { + auto vertex = uvGrid[ + timeIndex + 1 < uvGrid.timeSize ? timeIndex + timeOffset : timeIndex, + latIndex + 1 < uvGrid.latSize ? latIndex + latOffset : latIndex, + lonIndex + 1 < uvGrid.lonSize ? lonIndex + lonOffset : lonIndex ]; - double timeRation = (1 - time)*(1-timeRatio) + time*timeRatio; - double latRation = (1 - lat)*(1-latRatio) + lat*latRatio; - double lonRation = (1 - lon)*(1-lonRatio) + lon*lonRatio; + double timeRation = (1 - timeOffset) * (1 - timeRatio) + timeOffset * timeRatio; + double latRation = (1 - latOffset) * (1 - latRatio) + latOffset * latRatio; + double lonRation = (1 - lonOffset) * (1 - lonRatio) + lonOffset * lonRatio; point += timeRation * latRation * lonRation * vertex; } } @@ -41,3 +39,13 @@ point bilinearInterpolate(const UVGrid &uvGrid, std::tuple return point; } + +vector bilinearInterpolate(const UVGrid &uvGrid, vector> points) { + auto results = points + | std::views::transform([&uvGrid](const auto &point) { + auto [time, lat, lon] = point; + return bilinearInterpolate(uvGrid, time, lat, lon); + }) + | std::ranges::to>(); + return results; +} diff --git a/linear-interpolation/src/interpolate.h b/linear-interpolation/src/interpolate.h index 131b747..68b58f7 100644 --- a/linear-interpolation/src/interpolate.h +++ b/linear-interpolation/src/interpolate.h @@ -5,8 +5,24 @@ #include "UVGrid.h" -point bilinearInterpolate(const UVGrid &uvGrid, std::tuple timeLatLong); +/** + * Bilinearly interpolate the point (time, lat, lon) to produce the interpolated velocity. + * Since it is in 3D, this means that it interpolates against 8 points (excluding edges). + * As described in https://numerical.recipes/book.html Chapter 3.6 + * @param uvGrid velocity grid + * @param time time of point + * @param lat latitude of point + * @param lon longitude of point + * @return interpolated velocity + */ +Vel bilinearInterpolate(const UVGrid &uvGrid, int time, double lat, double lon); -std::vector bilinearInterpolate(); +/** + * Helper function for bilnearly interpolating a vector of points + * @param uvGrid velocity grid + * @param points vector of points + * @return interpolated velocities + */ +std::vector bilinearInterpolate(const UVGrid &uvGrid, std::vector> points); #endif //LINEARINTERPOLATE_INTERPOLATE_H diff --git a/linear-interpolation/src/main.cpp b/linear-interpolation/src/main.cpp index dc36897..8d2c16e 100644 --- a/linear-interpolation/src/main.cpp +++ b/linear-interpolation/src/main.cpp @@ -1,13 +1,52 @@ #include "interpolate.h" +#include "Vel.h" +#include +#include using namespace std; int main() { UVGrid uvGrid; - auto p = bilinearInterpolate(uvGrid, {392400, 53, -14.5}); + uvGrid.printSlice(100); - println("({}, {})", p.first, p.second); - p = bilinearInterpolate(uvGrid, {802400, 62, -14.5}); + int N = 10000000; // Number of points + + int time_start = 0; + int time_end = 31536000; + + double lat_start = 46.125; + double lat_end = 62.625; + + double lon_start = -15.875; + double lon_end = 12.875; + + // Calculate increments + double lat_step = (lat_end - lat_start) / (N - 1); + double lon_step = (lon_end - lon_start) / (N - 1); + int time_step = (time_end - time_start) / (N - 1); + + vector> points; + + for(int i = 0; i < N; i++) { + points.push_back({time_start+time_step*i, lat_start+lat_step*i, lon_start+lon_step*i}); + } + + auto start = std::chrono::high_resolution_clock::now(); + + auto x = bilinearInterpolate(uvGrid, points); + + auto stop = std::chrono::high_resolution_clock::now(); + + auto duration = std::chrono::duration_cast(stop - start); + + println("Time taken for {} points was {} seconds", N, duration.count()/1000.); + + // Do something with result in case of optimisation + double sum = 0; + for (auto [u,v]: x) { + sum += u + v; + } + println("Sum = {}", sum); return 0; } diff --git a/linear-interpolation/src/point.cpp b/linear-interpolation/src/point.cpp deleted file mode 100644 index a84800f..0000000 --- a/linear-interpolation/src/point.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "point.h" - -point operator+(const point& p1, const point& p2) { - return {p1.first + p2.first, p1.second + p2.second}; -} - -point& operator+=(point& p1, const point& p2) { - p1.first += p2.first; - p1.second += p2.second; - return p1; -} \ No newline at end of file diff --git a/linear-interpolation/src/point.h b/linear-interpolation/src/point.h deleted file mode 100644 index 4a22f35..0000000 --- a/linear-interpolation/src/point.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef LINEARINTERPOLATE_POINT_H -#define LINEARINTERPOLATE_POINT_H - -#include - -using point = std::pair; // {u, v} - -point operator+(const point& p1, const point& p2); - -point& operator+=(point& p1, const point& p2); - -template -point operator*(const point& p, Scalar scalar) { - return {p.first * scalar, p.second * scalar}; -} - -template -point operator*(Scalar scalar, const point& p) { - return {p.first * scalar, p.second * scalar}; -} - -template -point operator/(const point& p, Scalar scalar) { - return {p.first / scalar, p.second / scalar}; -} - -#endif //LINEARINTERPOLATE_POINT_H diff --git a/linear-interpolation/src/readdata.cpp b/linear-interpolation/src/readdata.cpp index bc4f364..d556c6f 100644 --- a/linear-interpolation/src/readdata.cpp +++ b/linear-interpolation/src/readdata.cpp @@ -22,45 +22,20 @@ vector getVarVector(const NcVar &var) { 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() { +vector readHydrodynamicU() { netCDF::NcFile data("../../../../data/hydrodynamic_U.h5", netCDF::NcFile::read); multimap< string, NcVar > vars = data.getVars(); - return get3DMat(vars.find("uo")->second); + return getVarVector(vars.find("uo")->second); } -pair, std::dextents> readHydrodynamicV() { +vector readHydrodynamicV() { netCDF::NcFile data("../../../../data/hydrodynamic_V.h5", netCDF::NcFile::read); multimap< string, NcVar > vars = data.getVars(); - return get3DMat(vars.find("vo")->second); + return getVarVector(vars.find("vo")->second); } tuple, vector, vector> readGrid() { diff --git a/linear-interpolation/src/readdata.h b/linear-interpolation/src/readdata.h index 3008924..6e4c2c9 100644 --- a/linear-interpolation/src/readdata.h +++ b/linear-interpolation/src/readdata.h @@ -1,19 +1,17 @@ #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 + * @return the data vector of us */ -std::pair, std::dextents> readHydrodynamicU(); +std::vector readHydrodynamicU(); /** * reads the file hydrodynamic_V.h5 - * @return a pair of the data vector of the contents and its dimensions to be used with mdspan + * @return the data vector of vs */ -std::pair, std::dextents> readHydrodynamicV(); +std::vector readHydrodynamicV(); /** * Reads the file grid.h5 diff --git a/linear-interpolation/src/vecutils.cpp b/linear-interpolation/src/vecutils.cpp deleted file mode 100644 index 1b02df9..0000000 --- a/linear-interpolation/src/vecutils.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#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(""); - } -} - -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++) { - auto [u,v] = arr[t,x,y]; - print("({:>7.4f}, {:>7.4f}) ", u, v); - } - println(""); - } -} diff --git a/linear-interpolation/src/vecutils.h b/linear-interpolation/src/vecutils.h deleted file mode 100644 index 8bf3691..0000000 --- a/linear-interpolation/src/vecutils.h +++ /dev/null @@ -1,48 +0,0 @@ -#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); -void print3DMatrixSlice(const arr3d> &arr, int t); - -#endif //LINEARINTERPOLATE_VECUTILS_H