From f91b8978e4d423bed70529bf36da851f9610cca5 Mon Sep 17 00:00:00 2001 From: Pradipta Samanta <samanta@dkrz.de> Date: Thu, 20 Mar 2025 18:46:08 +0100 Subject: [PATCH] added the first test for mo_lib_gradients --- test/c/CMakeLists.txt | 1 + test/c/test_horizontal_gradients.cpp | 211 +++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 test/c/test_horizontal_gradients.cpp diff --git a/test/c/CMakeLists.txt b/test/c/CMakeLists.txt index 90ab1e3..43c9ac4 100644 --- a/test/c/CMakeLists.txt +++ b/test/c/CMakeLists.txt @@ -35,6 +35,7 @@ set(SOURCES test_horizontal_div.cpp test_horizontal_recon.cpp test_horizontal_rot.cpp + test_horizontal_gradients.cpp test_tdma_solver.cpp test_interpolation_vector.cpp test_intp_rbf.cpp diff --git a/test/c/test_horizontal_gradients.cpp b/test/c/test_horizontal_gradients.cpp new file mode 100644 index 0000000..d5a3697 --- /dev/null +++ b/test/c/test_horizontal_gradients.cpp @@ -0,0 +1,211 @@ +// ICON +// +// --------------------------------------------------------------- +// Copyright (C) 2004-2025, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss +// Contact information: icon-model.org +// +// See AUTHORS.TXT for a list of authors +// See LICENSES/ for license information +// SPDX-License-Identifier: BSD-3-Clause +// --------------------------------------------------------------- + +#include <iostream> +#include <random> +#include <vector> + +#include <Kokkos_Core.hpp> +#include <gtest/gtest.h> +#include <dim_helper.hpp> +#include <horizontal/mo_lib_gradients.hpp> +#include <support/mo_lib_loopindices.hpp> + +#include <gtest/gtest.h> +#include <random> +#include <vector> + +template <typename ValueType> +class GradientNormalTest : public ::testing::Test { +protected: + static constexpr int nproma = 3; // inner loop length + static constexpr int nlev = 2; // number of vertical levels + static constexpr int nblks_c = 1; // number of cell blocks + static constexpr int nblks_e = 1; // number of edge blocks + + int i_startblk = 0; + int i_endblk = nblks_e; // Test blocks [0 .. nblks_e-1] + int i_startidx_in = 0; + int i_endidx_in = nproma; // Full range: 0 .. nproma-1 + std::vector<int> slev; + std::vector<int> elev; + bool lacc = false; // Not using ACC-specific behavior. + + std::vector<ValueType> psi_c; + std::vector<int> edge_cell_idx; + std::vector<int> edge_cell_blk; + std::vector<ValueType> inv_dual_edge_length; + std::vector<ValueType> grad_norm_psi_e; + + GradientNormalTest() { + slev.resize(1, 0); + elev.resize(1, nlev); // Full vertical range (0 .. nlev-1) + + psi_c.resize(dim_combine(nproma, nlev, nblks_c)); + edge_cell_idx.resize(dim_combine(nproma, nblks_e, 2)); + edge_cell_blk.resize(dim_combine(nproma, nblks_e, 2)); + inv_dual_edge_length.resize(dim_combine(nproma, nblks_e)); + grad_norm_psi_e.resize(dim_combine(nproma, nlev, nblks_e)); + } +}; + +template <typename ValueType> +class GradientNormal3DTest : public GradientNormalTest<ValueType> {}; + +// Define value types to test (e.g., float and double) +using ValueTypes = ::testing::Types<float, double>; +TYPED_TEST_SUITE(GradientNormal3DTest, ValueTypes); + +TYPED_TEST(GradientNormal3DTest, TestSpecific) { + constexpr int nproma = this->nproma; + constexpr int nlev = this->nlev; + constexpr int nblks_c = this->nblks_c; + constexpr int nblks_e = this->nblks_e; + + const auto &psi_c_at = at<nproma, nlev, nblks_c>; + const auto &edge_cell_at = at<nproma, nblks_e, 2>; + const auto &inv_edge_at = at<nproma, nblks_e>; + const auto &grad_psi_at = at<nproma, nlev, nblks_e>; + + // Initialization with specific values + for (int i = 0; i < nproma; ++i) { + for (int k = 0; k < nlev; ++k) { + this->psi_c[psi_c_at(i, k, 0)] = (i + 1) * (k + 1) * 2.0; // Simple pattern + } + + // Set edge cell indices to point to specific cells + this->edge_cell_idx[edge_cell_at(i, 0, 0)] = i; + this->edge_cell_idx[edge_cell_at(i, 0, 1)] = (i + 1) % nproma; + + // All cells are in the same block for this test + this->edge_cell_blk[edge_cell_at(i, 0, 0)] = 0; + this->edge_cell_blk[edge_cell_at(i, 0, 1)] = 0; + + // Set inverse dual edge length + this->inv_dual_edge_length[inv_edge_at(i, 0)] = 0.5; + + // Initialize grad_norm_psi_e to zero + for (int k = 0; k < nlev; ++k) { + this->grad_norm_psi_e[grad_psi_at(i, k, 0)] = 0.0; + } + } + + // Call the gradient function + grad_fd_norm_lib<TypeParam>( + this->psi_c.data(), this->edge_cell_idx.data(), + this->edge_cell_blk.data(), this->inv_dual_edge_length.data(), + this->grad_norm_psi_e.data(), this->i_startblk, this->i_endblk, + this->i_startidx_in, this->i_endidx_in, this->slev[0], + this->elev[0], this->nproma, this->nlev, this->nblks_c, + this->nblks_e, this->lacc); + + // Expected values based on the initialization + // For edge 0: (cell 1 value - cell 0 value) * inv_dual_edge_length + EXPECT_NEAR(this->grad_norm_psi_e[grad_psi_at(0, 0, 0)], + (this->psi_c[psi_c_at(1, 0, 0)] - this->psi_c[psi_c_at(0, 0, 0)]) * 0.5, + 1e-6); + EXPECT_NEAR(this->grad_norm_psi_e[grad_psi_at(0, 1, 0)], + (this->psi_c[psi_c_at(1, 1, 0)] - this->psi_c[psi_c_at(0, 1, 0)]) * 0.5, + 1e-6); + + // For edge 1: (cell 2 value - cell 1 value) * inv_dual_edge_length + EXPECT_NEAR(this->grad_norm_psi_e[grad_psi_at(1, 0, 0)], + (this->psi_c[psi_c_at(2, 0, 0)] - this->psi_c[psi_c_at(1, 0, 0)]) * 0.5, + 1e-6); + EXPECT_NEAR(this->grad_norm_psi_e[grad_psi_at(1, 1, 0)], + (this->psi_c[psi_c_at(2, 1, 0)] - this->psi_c[psi_c_at(1, 1, 0)]) * 0.5, + 1e-6); + + // For edge 2: (cell 0 value - cell 2 value) * inv_dual_edge_length + EXPECT_NEAR(this->grad_norm_psi_e[grad_psi_at(2, 0, 0)], + (this->psi_c[psi_c_at(0, 0, 0)] - this->psi_c[psi_c_at(2, 0, 0)]) * 0.5, + 1e-6); + EXPECT_NEAR(this->grad_norm_psi_e[grad_psi_at(2, 1, 0)], + (this->psi_c[psi_c_at(0, 1, 0)] - this->psi_c[psi_c_at(2, 1, 0)]) * 0.5, + 1e-6); +} + +TYPED_TEST(GradientNormal3DTest, TestRandom) { + constexpr int nproma = this->nproma; + constexpr int nlev = this->nlev; + constexpr int nblks_c = this->nblks_c; + constexpr int nblks_e = this->nblks_e; + + const auto &psi_c_at = at<nproma, nlev, nblks_c>; + const auto &edge_cell_at = at<nproma, nblks_e, 2>; + const auto &inv_edge_at = at<nproma, nblks_e>; + const auto &grad_psi_at = at<nproma, nlev, nblks_e>; + + // Set up random number generators + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<int> int_distrib(0, nproma - 1); + std::uniform_real_distribution<TypeParam> real_distrib(-10.0, 10.0); + + // Initialization with random values + for (int i = 0; i < nproma; ++i) { + for (int k = 0; k < nlev; ++k) { + this->psi_c[psi_c_at(i, k, 0)] = real_distrib(gen); + } + + // Set random edge cell indices + for (int j = 0; j < 2; ++j) { + this->edge_cell_idx[edge_cell_at(i, 0, j)] = int_distrib(gen); + this->edge_cell_blk[edge_cell_at(i, 0, j)] = 0; // Keep in same block for simplicity + } + + // Random inverse dual edge length + this->inv_dual_edge_length[inv_edge_at(i, 0)] = real_distrib(gen); + + // Initialize grad_norm_psi_e to random values + for (int k = 0; k < nlev; ++k) { + this->grad_norm_psi_e[grad_psi_at(i, k, 0)] = real_distrib(gen); + } + } + + // Call the gradient function + grad_fd_norm_lib<TypeParam>( + this->psi_c.data(), this->edge_cell_idx.data(), + this->edge_cell_blk.data(), this->inv_dual_edge_length.data(), + this->grad_norm_psi_e.data(), this->i_startblk, this->i_endblk, + this->i_startidx_in, this->i_endidx_in, this->slev[0], + this->elev[0], this->nproma, this->nlev, this->nblks_c, + this->nblks_e, this->lacc); + + // Calculate reference values separately and verify results + std::vector<TypeParam> ref_grad_psi_e(nproma * nlev * nblks_e, 0.0); + + for (int jb = this->i_startblk; jb < this->i_endblk; ++jb) { + int i_startidx, i_endidx; + get_indices_e_lib(this->i_startidx_in, this->i_endidx_in, nproma, jb, + this->i_startblk, this->i_endblk, i_startidx, i_endidx); + + for (int jk = this->slev[0]; jk < this->elev[0]; ++jk) { + for (int je = i_startidx; je < i_endidx; ++je) { + ref_grad_psi_e[grad_psi_at(je, jk, jb)] = + (this->psi_c[psi_c_at(this->edge_cell_idx[edge_cell_at(je, jb, 1)], jk, + this->edge_cell_blk[edge_cell_at(je, jb, 1)])] - + this->psi_c[psi_c_at(this->edge_cell_idx[edge_cell_at(je, jb, 0)], jk, + this->edge_cell_blk[edge_cell_at(je, jb, 0)])]) * + this->inv_dual_edge_length[inv_edge_at(je, jb)]; + } + } + } + + // Verify results + for (int i = 0; i < nproma; ++i) { + for (int k = 0; k < nlev; ++k) { + EXPECT_NEAR(this->grad_norm_psi_e[grad_psi_at(i, k, 0)], + ref_grad_psi_e[grad_psi_at(i, k, 0)], 1e-5) + << "Results differ at i=" << i << ", k=" << k; + } + } +} -- GitLab