diff --git a/source/source_lcao/module_gint/CMakeLists.txt b/source/source_lcao/module_gint/CMakeLists.txt index 6969abd7e0..247363fd9d 100644 --- a/source/source_lcao/module_gint/CMakeLists.txt +++ b/source/source_lcao/module_gint/CMakeLists.txt @@ -55,4 +55,10 @@ if(ENABLE_COVERAGE) add_coverage(gint) endif() +if(BUILD_TESTING) + if(ENABLE_MPI) + add_subdirectory(test) + endif() +endif() + endif() \ No newline at end of file diff --git a/source/source_lcao/module_gint/test/CMakeLists.txt b/source/source_lcao/module_gint/test/CMakeLists.txt new file mode 100644 index 0000000000..80bb55504c --- /dev/null +++ b/source/source_lcao/module_gint/test/CMakeLists.txt @@ -0,0 +1,25 @@ +remove_definitions(-D__MPI) + +AddTest( + TARGET MODULE_GINT_helper + LIBS parameter ${math_libs} base device + SOURCES gint_helper_test.cpp +) + +AddTest( + TARGET MODULE_GINT_biggrid_info + LIBS parameter ${math_libs} base device + SOURCES biggrid_info_test.cpp ../biggrid_info.cpp +) + +AddTest( + TARGET MODULE_GINT_unitcell_info + LIBS parameter ${math_libs} base device + SOURCES unitcell_info_test.cpp ../unitcell_info.cpp ../biggrid_info.cpp +) + +AddTest( + TARGET MODULE_GINT_localcell_info + LIBS parameter ${math_libs} base device + SOURCES localcell_info_test.cpp ../localcell_info.cpp ../unitcell_info.cpp ../biggrid_info.cpp +) diff --git a/source/source_lcao/module_gint/test/biggrid_info_test.cpp b/source/source_lcao/module_gint/test/biggrid_info_test.cpp new file mode 100644 index 0000000000..d9a22e8657 --- /dev/null +++ b/source/source_lcao/module_gint/test/biggrid_info_test.cpp @@ -0,0 +1,228 @@ +#include "../biggrid_info.h" +#include "gtest/gtest.h" +#include + +/************************************************ + * unit test of BigGridInfo class + ***********************************************/ + +/** + * Tested functions of class BigGridInfo: + * - constructor + * - get_cartesian_coord: convert 3D index to Cartesian coordinate + * - get_direct_coord: convert Cartesian coordinate to direct coordinate + * - max_ext_bgrid_num: calculate maximum extension number for a given radius + * - get_nmx, get_nmy, get_nmz, get_mgrids_num: getter functions for meshgrid dimensions + * - get_mgrids_coord, get_mgrid_coord: getter functions for meshgrid coordinates + * - mgrid_idx_1Dto3D, mgrid_idx_3Dto1D: meshgrid index conversion + */ + +class BigGridInfoTest : public testing::Test +{ +protected: + void SetUp() override + { + // Create a simple cubic biggrid with vectors (4,0,0), (0,4,0), (0,0,4) + // with 2x2x2 meshgrids + biggrid_vec1 = ModuleGint::Vec3d(4.0, 0.0, 0.0); + biggrid_vec2 = ModuleGint::Vec3d(0.0, 4.0, 0.0); + biggrid_vec3 = ModuleGint::Vec3d(0.0, 0.0, 4.0); + nmx = 2; + nmy = 2; + nmz = 2; + + biggrid_info = std::make_shared( + biggrid_vec1, biggrid_vec2, biggrid_vec3, nmx, nmy, nmz); + } + + ModuleGint::Vec3d biggrid_vec1, biggrid_vec2, biggrid_vec3; + int nmx, nmy, nmz; + std::shared_ptr biggrid_info; +}; + +// Test constructor and getter functions +TEST_F(BigGridInfoTest, Constructor) +{ + EXPECT_EQ(biggrid_info->get_nmx(), nmx); + EXPECT_EQ(biggrid_info->get_nmy(), nmy); + EXPECT_EQ(biggrid_info->get_nmz(), nmz); + EXPECT_EQ(biggrid_info->get_mgrids_num(), nmx * nmy * nmz); +} + +// Test get_cartesian_coord with Vec3d +TEST_F(BigGridInfoTest, GetCartesianCoord_Vec3d_Origin) +{ + ModuleGint::Vec3d index_3d(0.0, 0.0, 0.0); + ModuleGint::Vec3d coord = biggrid_info->get_cartesian_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +TEST_F(BigGridInfoTest, GetCartesianCoord_Vec3d_Unit) +{ + ModuleGint::Vec3d index_3d(1.0, 0.0, 0.0); + ModuleGint::Vec3d coord = biggrid_info->get_cartesian_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 4.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); + + index_3d = ModuleGint::Vec3d(0.0, 1.0, 0.0); + coord = biggrid_info->get_cartesian_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 4.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); + + index_3d = ModuleGint::Vec3d(0.0, 0.0, 1.0); + coord = biggrid_info->get_cartesian_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 4.0); +} + +// Test get_cartesian_coord with Vec3i +TEST_F(BigGridInfoTest, GetCartesianCoord_Vec3i_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + ModuleGint::Vec3d coord = biggrid_info->get_cartesian_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +TEST_F(BigGridInfoTest, GetCartesianCoord_Vec3i_Unit) +{ + ModuleGint::Vec3i index_3d(1, 2, 3); + ModuleGint::Vec3d coord = biggrid_info->get_cartesian_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 4.0); + EXPECT_DOUBLE_EQ(coord.y, 8.0); + EXPECT_DOUBLE_EQ(coord.z, 12.0); +} + +// Test get_direct_coord +TEST_F(BigGridInfoTest, GetDirectCoord_Origin) +{ + ModuleGint::Vec3d cart_coord(0.0, 0.0, 0.0); + ModuleGint::Vec3d direct_coord = biggrid_info->get_direct_coord(cart_coord); + EXPECT_NEAR(direct_coord.x, 0.0, 1e-10); + EXPECT_NEAR(direct_coord.y, 0.0, 1e-10); + EXPECT_NEAR(direct_coord.z, 0.0, 1e-10); +} + +TEST_F(BigGridInfoTest, GetDirectCoord_Unit) +{ + ModuleGint::Vec3d cart_coord(4.0, 0.0, 0.0); + ModuleGint::Vec3d direct_coord = biggrid_info->get_direct_coord(cart_coord); + EXPECT_NEAR(direct_coord.x, 1.0, 1e-10); + EXPECT_NEAR(direct_coord.y, 0.0, 1e-10); + EXPECT_NEAR(direct_coord.z, 0.0, 1e-10); + + cart_coord = ModuleGint::Vec3d(0.0, 8.0, 0.0); + direct_coord = biggrid_info->get_direct_coord(cart_coord); + EXPECT_NEAR(direct_coord.x, 0.0, 1e-10); + EXPECT_NEAR(direct_coord.y, 2.0, 1e-10); + EXPECT_NEAR(direct_coord.z, 0.0, 1e-10); +} + +// Test roundtrip conversion +TEST_F(BigGridInfoTest, CoordConversion_Roundtrip) +{ + ModuleGint::Vec3d index_3d(1.5, 2.5, 3.5); + ModuleGint::Vec3d cart_coord = biggrid_info->get_cartesian_coord(index_3d); + ModuleGint::Vec3d result = biggrid_info->get_direct_coord(cart_coord); + EXPECT_NEAR(result.x, index_3d.x, 1e-10); + EXPECT_NEAR(result.y, index_3d.y, 1e-10); + EXPECT_NEAR(result.z, index_3d.z, 1e-10); +} + +// Test max_ext_bgrid_num +TEST_F(BigGridInfoTest, MaxExtBgridNum_SmallRadius) +{ + double r = 2.0; // Half of the biggrid size + ModuleGint::Vec3i ext_num = biggrid_info->max_ext_bgrid_num(r); + // For orthogonal vectors, ext = floor(r / |vec|) + 1 = floor(2/4) + 1 = 1 + EXPECT_EQ(ext_num.x, 1); + EXPECT_EQ(ext_num.y, 1); + EXPECT_EQ(ext_num.z, 1); +} + +TEST_F(BigGridInfoTest, MaxExtBgridNum_LargeRadius) +{ + double r = 10.0; + ModuleGint::Vec3i ext_num = biggrid_info->max_ext_bgrid_num(r); + // For orthogonal vectors with |vec| = 4, ext = floor(10/4) + 1 = 3 + EXPECT_EQ(ext_num.x, 3); + EXPECT_EQ(ext_num.y, 3); + EXPECT_EQ(ext_num.z, 3); +} + +// Test meshgrid index conversion +TEST_F(BigGridInfoTest, MgridIdx_1Dto3D_Origin) +{ + ModuleGint::Vec3i result = biggrid_info->mgrid_idx_1Dto3D(0); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 0); +} + +TEST_F(BigGridInfoTest, MgridIdx_3Dto1D_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + EXPECT_EQ(biggrid_info->mgrid_idx_3Dto1D(index_3d), 0); +} + +TEST_F(BigGridInfoTest, MgridIdx_Conversion_Roundtrip) +{ + for (int i = 0; i < nmx * nmy * nmz; ++i) + { + ModuleGint::Vec3i idx_3d = biggrid_info->mgrid_idx_1Dto3D(i); + EXPECT_EQ(biggrid_info->mgrid_idx_3Dto1D(idx_3d), i); + } +} + +// Test meshgrid coordinates +TEST_F(BigGridInfoTest, GetMgridsCoord) +{ + const std::vector& coords = biggrid_info->get_mgrids_coord(); + EXPECT_EQ(coords.size(), static_cast(nmx * nmy * nmz)); +} + +TEST_F(BigGridInfoTest, GetMgridCoord_Origin) +{ + const ModuleGint::Vec3d& coord = biggrid_info->get_mgrid_coord(0); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +// Test with non-orthogonal biggrid vectors +class BigGridInfoNonOrthTest : public testing::Test +{ +protected: + void SetUp() override + { + // Create a non-orthogonal biggrid + biggrid_vec1 = ModuleGint::Vec3d(4.0, 0.0, 0.0); + biggrid_vec2 = ModuleGint::Vec3d(2.0, 3.464, 0.0); // 60 degree angle + biggrid_vec3 = ModuleGint::Vec3d(0.0, 0.0, 4.0); + nmx = 2; + nmy = 2; + nmz = 2; + + biggrid_info = std::make_shared( + biggrid_vec1, biggrid_vec2, biggrid_vec3, nmx, nmy, nmz); + } + + ModuleGint::Vec3d biggrid_vec1, biggrid_vec2, biggrid_vec3; + int nmx, nmy, nmz; + std::shared_ptr biggrid_info; +}; + +TEST_F(BigGridInfoNonOrthTest, GetCartesianCoord_NonOrth) +{ + ModuleGint::Vec3i index_3d(1, 1, 0); + ModuleGint::Vec3d coord = biggrid_info->get_cartesian_coord(index_3d); + EXPECT_NEAR(coord.x, 6.0, 1e-10); + EXPECT_NEAR(coord.y, 3.464, 1e-3); + EXPECT_NEAR(coord.z, 0.0, 1e-10); +} diff --git a/source/source_lcao/module_gint/test/gint_helper_test.cpp b/source/source_lcao/module_gint/test/gint_helper_test.cpp new file mode 100644 index 0000000000..9b64032bb8 --- /dev/null +++ b/source/source_lcao/module_gint/test/gint_helper_test.cpp @@ -0,0 +1,256 @@ +#include "../gint_helper.h" +#include "gtest/gtest.h" + +/************************************************ + * unit test of gint_helper functions + ***********************************************/ + +/** + * Tested functions: + * - index3Dto1D: convert 3D index to 1D index + * - index1Dto3D: convert 1D index to 3D index + * - pow_int: fast integer power for exponents 0-5 + * - floor_div: floor division for integers + * - ceil_div: ceiling division for integers + */ + +class GintHelperTest : public testing::Test +{ +protected: + void SetUp() override + { + // dimensions for index conversion tests + dim_x = 3; + dim_y = 4; + dim_z = 5; + } + + int dim_x, dim_y, dim_z; +}; + +// Test index3Dto1D function +TEST_F(GintHelperTest, Index3Dto1D_Origin) +{ + EXPECT_EQ(ModuleGint::index3Dto1D(0, 0, 0, dim_x, dim_y, dim_z), 0); +} + +TEST_F(GintHelperTest, Index3Dto1D_ZOnly) +{ + EXPECT_EQ(ModuleGint::index3Dto1D(0, 0, 1, dim_x, dim_y, dim_z), 1); + EXPECT_EQ(ModuleGint::index3Dto1D(0, 0, 4, dim_x, dim_y, dim_z), 4); +} + +TEST_F(GintHelperTest, Index3Dto1D_YOnly) +{ + EXPECT_EQ(ModuleGint::index3Dto1D(0, 1, 0, dim_x, dim_y, dim_z), dim_z); + EXPECT_EQ(ModuleGint::index3Dto1D(0, 3, 0, dim_x, dim_y, dim_z), 3 * dim_z); +} + +TEST_F(GintHelperTest, Index3Dto1D_XOnly) +{ + EXPECT_EQ(ModuleGint::index3Dto1D(1, 0, 0, dim_x, dim_y, dim_z), dim_y * dim_z); + EXPECT_EQ(ModuleGint::index3Dto1D(2, 0, 0, dim_x, dim_y, dim_z), 2 * dim_y * dim_z); +} + +TEST_F(GintHelperTest, Index3Dto1D_Combined) +{ + int id_x = 1, id_y = 2, id_z = 3; + int expected = id_z + id_y * dim_z + id_x * dim_y * dim_z; + EXPECT_EQ(ModuleGint::index3Dto1D(id_x, id_y, id_z, dim_x, dim_y, dim_z), expected); +} + +TEST_F(GintHelperTest, Index3Dto1D_MaxIndex) +{ + int expected = dim_x * dim_y * dim_z - 1; + EXPECT_EQ(ModuleGint::index3Dto1D(dim_x - 1, dim_y - 1, dim_z - 1, dim_x, dim_y, dim_z), expected); +} + +// Test index1Dto3D function +TEST_F(GintHelperTest, Index1Dto3D_Origin) +{ + ModuleGint::Vec3i result = ModuleGint::index1Dto3D(0, dim_x, dim_y, dim_z); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 0); +} + +TEST_F(GintHelperTest, Index1Dto3D_ZOnly) +{ + ModuleGint::Vec3i result = ModuleGint::index1Dto3D(3, dim_x, dim_y, dim_z); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 3); +} + +TEST_F(GintHelperTest, Index1Dto3D_YOnly) +{ + ModuleGint::Vec3i result = ModuleGint::index1Dto3D(dim_z, dim_x, dim_y, dim_z); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 1); + EXPECT_EQ(result.z, 0); +} + +TEST_F(GintHelperTest, Index1Dto3D_XOnly) +{ + ModuleGint::Vec3i result = ModuleGint::index1Dto3D(dim_y * dim_z, dim_x, dim_y, dim_z); + EXPECT_EQ(result.x, 1); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 0); +} + +TEST_F(GintHelperTest, Index1Dto3D_Combined) +{ + int id_x = 1, id_y = 2, id_z = 3; + int index_1d = id_z + id_y * dim_z + id_x * dim_y * dim_z; + ModuleGint::Vec3i result = ModuleGint::index1Dto3D(index_1d, dim_x, dim_y, dim_z); + EXPECT_EQ(result.x, id_x); + EXPECT_EQ(result.y, id_y); + EXPECT_EQ(result.z, id_z); +} + +TEST_F(GintHelperTest, Index1Dto3D_MaxIndex) +{ + int max_index = dim_x * dim_y * dim_z - 1; + ModuleGint::Vec3i result = ModuleGint::index1Dto3D(max_index, dim_x, dim_y, dim_z); + EXPECT_EQ(result.x, dim_x - 1); + EXPECT_EQ(result.y, dim_y - 1); + EXPECT_EQ(result.z, dim_z - 1); +} + +// Test roundtrip conversion +TEST_F(GintHelperTest, IndexConversion_Roundtrip) +{ + for (int x = 0; x < dim_x; ++x) + { + for (int y = 0; y < dim_y; ++y) + { + for (int z = 0; z < dim_z; ++z) + { + int index_1d = ModuleGint::index3Dto1D(x, y, z, dim_x, dim_y, dim_z); + ModuleGint::Vec3i result = ModuleGint::index1Dto3D(index_1d, dim_x, dim_y, dim_z); + EXPECT_EQ(result.x, x); + EXPECT_EQ(result.y, y); + EXPECT_EQ(result.z, z); + } + } + } +} + +// Test pow_int function +TEST(GintHelper, PowInt_Exp0) +{ + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 0), 1.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(3.5, 0), 1.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(-1.5, 0), 1.0); +} + +TEST(GintHelper, PowInt_Exp1) +{ + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 1), 2.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(3.5, 1), 3.5); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(-1.5, 1), -1.5); +} + +TEST(GintHelper, PowInt_Exp2) +{ + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 2), 4.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(3.0, 2), 9.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(-2.0, 2), 4.0); +} + +TEST(GintHelper, PowInt_Exp3) +{ + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 3), 8.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(3.0, 3), 27.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(-2.0, 3), -8.0); +} + +TEST(GintHelper, PowInt_Exp4) +{ + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 4), 16.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(3.0, 4), 81.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(-2.0, 4), 16.0); +} + +TEST(GintHelper, PowInt_Exp5) +{ + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 5), 32.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(3.0, 5), 243.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(-2.0, 5), -32.0); +} + +TEST(GintHelper, PowInt_ExpLarger) +{ + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 6), 64.0); + EXPECT_DOUBLE_EQ(ModuleGint::pow_int(2.0, 10), 1024.0); +} + +// Test floor_div function +TEST(GintHelper, FloorDiv_BothPositive) +{ + EXPECT_EQ(ModuleGint::floor_div(7, 3), 2); + EXPECT_EQ(ModuleGint::floor_div(9, 3), 3); + EXPECT_EQ(ModuleGint::floor_div(10, 3), 3); +} + +TEST(GintHelper, FloorDiv_NegativeDividend) +{ + EXPECT_EQ(ModuleGint::floor_div(-7, 3), -3); + EXPECT_EQ(ModuleGint::floor_div(-9, 3), -3); + EXPECT_EQ(ModuleGint::floor_div(-10, 3), -4); +} + +TEST(GintHelper, FloorDiv_NegativeDivisor) +{ + EXPECT_EQ(ModuleGint::floor_div(7, -3), -3); + EXPECT_EQ(ModuleGint::floor_div(9, -3), -3); + EXPECT_EQ(ModuleGint::floor_div(10, -3), -4); +} + +TEST(GintHelper, FloorDiv_BothNegative) +{ + EXPECT_EQ(ModuleGint::floor_div(-7, -3), 2); + EXPECT_EQ(ModuleGint::floor_div(-9, -3), 3); + EXPECT_EQ(ModuleGint::floor_div(-10, -3), 3); +} + +TEST(GintHelper, FloorDiv_ZeroDividend) +{ + EXPECT_EQ(ModuleGint::floor_div(0, 3), 0); + EXPECT_EQ(ModuleGint::floor_div(0, -3), 0); +} + +// Test ceil_div function +TEST(GintHelper, CeilDiv_BothPositive) +{ + EXPECT_EQ(ModuleGint::ceil_div(7, 3), 3); + EXPECT_EQ(ModuleGint::ceil_div(9, 3), 3); + EXPECT_EQ(ModuleGint::ceil_div(10, 3), 4); +} + +TEST(GintHelper, CeilDiv_NegativeDividend) +{ + EXPECT_EQ(ModuleGint::ceil_div(-7, 3), -2); + EXPECT_EQ(ModuleGint::ceil_div(-9, 3), -3); + EXPECT_EQ(ModuleGint::ceil_div(-10, 3), -3); +} + +TEST(GintHelper, CeilDiv_NegativeDivisor) +{ + EXPECT_EQ(ModuleGint::ceil_div(7, -3), -2); + EXPECT_EQ(ModuleGint::ceil_div(9, -3), -3); + EXPECT_EQ(ModuleGint::ceil_div(10, -3), -3); +} + +TEST(GintHelper, CeilDiv_BothNegative) +{ + EXPECT_EQ(ModuleGint::ceil_div(-7, -3), 3); + EXPECT_EQ(ModuleGint::ceil_div(-9, -3), 3); + EXPECT_EQ(ModuleGint::ceil_div(-10, -3), 4); +} + +TEST(GintHelper, CeilDiv_ZeroDividend) +{ + EXPECT_EQ(ModuleGint::ceil_div(0, 3), 0); + EXPECT_EQ(ModuleGint::ceil_div(0, -3), 0); +} diff --git a/source/source_lcao/module_gint/test/localcell_info_test.cpp b/source/source_lcao/module_gint/test/localcell_info_test.cpp new file mode 100644 index 0000000000..d25701642e --- /dev/null +++ b/source/source_lcao/module_gint/test/localcell_info_test.cpp @@ -0,0 +1,328 @@ +#include "../localcell_info.h" +#include "gtest/gtest.h" +#include + +/************************************************ + * unit test of LocalCellInfo class + ***********************************************/ + +/** + * Tested functions of class LocalCellInfo: + * - constructor + * - getter functions for local cell dimensions + * - bgrid_idx_3Dto1D, bgrid_idx_1Dto3D: local biggrid index conversion + * - get_bgrid_global_idx_3D: get global 3D index + * - get_bgrid_global_idx_1D: get global 1D index + * - get_bgrid_local_idx_3D: get local 3D index + * - get_bgrid_local_idx_1D: get local 1D index + * - get_bgrid_global_coord_3D: get global coordinate + * - is_bgrid_in_lcell: check if biggrid is in local cell + * - mgrid_idx_3Dto1D, mgrid_idx_1Dto3D: local meshgrid index conversion + * - get_mgrid_global_idx_3D: get global 3D index of meshgrid + * - get_mgrid_global_idx_1D: get global 1D index of meshgrid + */ + +class LocalCellInfoTest : public testing::Test +{ +protected: + void SetUp() override + { + // Create a unitcell with 4x4x4 biggrids and 8x8x8 meshgrids + unitcell_vec1 = ModuleGint::Vec3d(16.0, 0.0, 0.0); + unitcell_vec2 = ModuleGint::Vec3d(0.0, 16.0, 0.0); + unitcell_vec3 = ModuleGint::Vec3d(0.0, 0.0, 16.0); + nbx_global = 4; + nby_global = 4; + nbz_global = 4; + nmx_global = 8; + nmy_global = 8; + nmz_global = 8; + + unitcell_info = std::make_shared( + unitcell_vec1, unitcell_vec2, unitcell_vec3, + nbx_global, nby_global, nbz_global, + nmx_global, nmy_global, nmz_global); + + // Create a local cell that covers part of the unitcell + // Starting at (1, 1, 1) with 2x2x2 biggrids + startidx_bx = 1; + startidx_by = 1; + startidx_bz = 1; + nbx_local = 2; + nby_local = 2; + nbz_local = 2; + + localcell_info = std::make_shared( + startidx_bx, startidx_by, startidx_bz, + nbx_local, nby_local, nbz_local, + unitcell_info); + } + + ModuleGint::Vec3d unitcell_vec1, unitcell_vec2, unitcell_vec3; + int nbx_global, nby_global, nbz_global; + int nmx_global, nmy_global, nmz_global; + std::shared_ptr unitcell_info; + + int startidx_bx, startidx_by, startidx_bz; + int nbx_local, nby_local, nbz_local; + std::shared_ptr localcell_info; +}; + +// Test constructor and getter functions +TEST_F(LocalCellInfoTest, Constructor_BigGridDimensions) +{ + EXPECT_EQ(localcell_info->get_startidx_bx(), startidx_bx); + EXPECT_EQ(localcell_info->get_startidx_by(), startidx_by); + EXPECT_EQ(localcell_info->get_startidx_bz(), startidx_bz); + EXPECT_EQ(localcell_info->get_nbx(), nbx_local); + EXPECT_EQ(localcell_info->get_nby(), nby_local); + EXPECT_EQ(localcell_info->get_nbz(), nbz_local); + EXPECT_EQ(localcell_info->get_bgrids_num(), nbx_local * nby_local * nbz_local); +} + +TEST_F(LocalCellInfoTest, Constructor_MeshGridDimensions) +{ + // Each biggrid has 2x2x2 meshgrids (nmx/nbx = 8/4 = 2) + // Local cell has 2x2x2 biggrids + // So local cell has 4x4x4 meshgrids + EXPECT_EQ(localcell_info->get_mgrids_num(), 4 * 4 * 4); +} + +TEST_F(LocalCellInfoTest, Constructor_UnitCellInfo) +{ + EXPECT_EQ(localcell_info->get_unitcell_info(), unitcell_info); + EXPECT_NE(localcell_info->get_bgrid_info(), nullptr); +} + +// Test local biggrid index conversion +TEST_F(LocalCellInfoTest, BgridIdx_1Dto3D_Origin) +{ + ModuleGint::Vec3i result = localcell_info->bgrid_idx_1Dto3D(0); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 0); +} + +TEST_F(LocalCellInfoTest, BgridIdx_3Dto1D_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + EXPECT_EQ(localcell_info->bgrid_idx_3Dto1D(index_3d), 0); +} + +TEST_F(LocalCellInfoTest, BgridIdx_Conversion_Roundtrip) +{ + for (int i = 0; i < nbx_local * nby_local * nbz_local; ++i) + { + ModuleGint::Vec3i idx_3d = localcell_info->bgrid_idx_1Dto3D(i); + EXPECT_EQ(localcell_info->bgrid_idx_3Dto1D(idx_3d), i); + } +} + +// Test get_bgrid_global_idx_3D with Vec3i input +TEST_F(LocalCellInfoTest, GetBgridGlobalIdx3D_Vec3i_Origin) +{ + ModuleGint::Vec3i local_idx(0, 0, 0); + ModuleGint::Vec3i global_idx = localcell_info->get_bgrid_global_idx_3D(local_idx); + EXPECT_EQ(global_idx.x, startidx_bx); + EXPECT_EQ(global_idx.y, startidx_by); + EXPECT_EQ(global_idx.z, startidx_bz); +} + +TEST_F(LocalCellInfoTest, GetBgridGlobalIdx3D_Vec3i_Offset) +{ + ModuleGint::Vec3i local_idx(1, 1, 1); + ModuleGint::Vec3i global_idx = localcell_info->get_bgrid_global_idx_3D(local_idx); + EXPECT_EQ(global_idx.x, startidx_bx + 1); + EXPECT_EQ(global_idx.y, startidx_by + 1); + EXPECT_EQ(global_idx.z, startidx_bz + 1); +} + +// Test get_bgrid_global_idx_3D with int input +TEST_F(LocalCellInfoTest, GetBgridGlobalIdx3D_Int_Origin) +{ + ModuleGint::Vec3i global_idx = localcell_info->get_bgrid_global_idx_3D(0); + EXPECT_EQ(global_idx.x, startidx_bx); + EXPECT_EQ(global_idx.y, startidx_by); + EXPECT_EQ(global_idx.z, startidx_bz); +} + +// Test get_bgrid_global_idx_1D +TEST_F(LocalCellInfoTest, GetBgridGlobalIdx1D) +{ + // Local index 0 corresponds to global (1,1,1) + int global_idx = localcell_info->get_bgrid_global_idx_1D(0); + ModuleGint::Vec3i expected_3d(startidx_bx, startidx_by, startidx_bz); + int expected_1d = unitcell_info->bgrid_idx_3Dto1D(expected_3d); + EXPECT_EQ(global_idx, expected_1d); +} + +// Test get_bgrid_local_idx_3D +TEST_F(LocalCellInfoTest, GetBgridLocalIdx3D) +{ + ModuleGint::Vec3i global_idx(startidx_bx, startidx_by, startidx_bz); + ModuleGint::Vec3i local_idx = localcell_info->get_bgrid_local_idx_3D(global_idx); + EXPECT_EQ(local_idx.x, 0); + EXPECT_EQ(local_idx.y, 0); + EXPECT_EQ(local_idx.z, 0); +} + +TEST_F(LocalCellInfoTest, GetBgridLocalIdx3D_Offset) +{ + ModuleGint::Vec3i global_idx(startidx_bx + 1, startidx_by + 1, startidx_bz + 1); + ModuleGint::Vec3i local_idx = localcell_info->get_bgrid_local_idx_3D(global_idx); + EXPECT_EQ(local_idx.x, 1); + EXPECT_EQ(local_idx.y, 1); + EXPECT_EQ(local_idx.z, 1); +} + +// Test get_bgrid_local_idx_1D with Vec3i input +TEST_F(LocalCellInfoTest, GetBgridLocalIdx1D_Vec3i) +{ + ModuleGint::Vec3i global_idx(startidx_bx, startidx_by, startidx_bz); + int local_idx = localcell_info->get_bgrid_local_idx_1D(global_idx); + EXPECT_EQ(local_idx, 0); +} + +// Test get_bgrid_local_idx_1D with int input +TEST_F(LocalCellInfoTest, GetBgridLocalIdx1D_Int) +{ + ModuleGint::Vec3i global_3d(startidx_bx, startidx_by, startidx_bz); + int global_1d = unitcell_info->bgrid_idx_3Dto1D(global_3d); + int local_idx = localcell_info->get_bgrid_local_idx_1D(global_1d); + EXPECT_EQ(local_idx, 0); +} + +// Test get_bgrid_global_coord_3D +TEST_F(LocalCellInfoTest, GetBgridGlobalCoord3D_Origin) +{ + ModuleGint::Vec3d coord = localcell_info->get_bgrid_global_coord_3D(0); + // Biggrid size = 16/4 = 4, starting at (1,1,1) + EXPECT_DOUBLE_EQ(coord.x, 4.0); + EXPECT_DOUBLE_EQ(coord.y, 4.0); + EXPECT_DOUBLE_EQ(coord.z, 4.0); +} + +// Test is_bgrid_in_lcell +TEST_F(LocalCellInfoTest, IsBgridInLcell_Inside) +{ + ModuleGint::Vec3i idx(startidx_bx, startidx_by, startidx_bz); + EXPECT_TRUE(localcell_info->is_bgrid_in_lcell(idx)); + + idx = ModuleGint::Vec3i(startidx_bx + 1, startidx_by + 1, startidx_bz + 1); + EXPECT_TRUE(localcell_info->is_bgrid_in_lcell(idx)); +} + +TEST_F(LocalCellInfoTest, IsBgridInLcell_Outside) +{ + // Before the local cell + ModuleGint::Vec3i idx(0, 0, 0); + EXPECT_FALSE(localcell_info->is_bgrid_in_lcell(idx)); + + // After the local cell + idx = ModuleGint::Vec3i(startidx_bx + nbx_local, startidx_by, startidx_bz); + EXPECT_FALSE(localcell_info->is_bgrid_in_lcell(idx)); +} + +TEST_F(LocalCellInfoTest, IsBgridInLcell_Boundary) +{ + // Just inside the boundary + ModuleGint::Vec3i idx(startidx_bx + nbx_local - 1, + startidx_by + nby_local - 1, + startidx_bz + nbz_local - 1); + EXPECT_TRUE(localcell_info->is_bgrid_in_lcell(idx)); +} + +// Test local meshgrid index conversion +TEST_F(LocalCellInfoTest, MgridIdx_1Dto3D_Origin) +{ + ModuleGint::Vec3i result = localcell_info->mgrid_idx_1Dto3D(0); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 0); +} + +TEST_F(LocalCellInfoTest, MgridIdx_3Dto1D_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + EXPECT_EQ(localcell_info->mgrid_idx_3Dto1D(index_3d), 0); +} + +TEST_F(LocalCellInfoTest, MgridIdx_Conversion_Roundtrip) +{ + int nm_local = localcell_info->get_mgrids_num(); + for (int i = 0; i < std::min(nm_local, 27); ++i) // Test subset + { + ModuleGint::Vec3i idx_3d = localcell_info->mgrid_idx_1Dto3D(i); + EXPECT_EQ(localcell_info->mgrid_idx_3Dto1D(idx_3d), i); + } +} + +// Test get_mgrid_global_idx_3D +TEST_F(LocalCellInfoTest, GetMgridGlobalIdx3D_Origin) +{ + ModuleGint::Vec3i local_idx(0, 0, 0); + ModuleGint::Vec3i global_idx = localcell_info->get_mgrid_global_idx_3D(local_idx); + // startidx_mx = startidx_bx * (nm/nb) = 1 * 2 = 2 + EXPECT_EQ(global_idx.x, 2); + EXPECT_EQ(global_idx.y, 2); + EXPECT_EQ(global_idx.z, 2); +} + +// Test get_mgrid_global_idx_1D +TEST_F(LocalCellInfoTest, GetMgridGlobalIdx1D_Origin) +{ + int global_idx = localcell_info->get_mgrid_global_idx_1D(0); + ModuleGint::Vec3i expected_3d(2, 2, 2); + int expected_1d = unitcell_info->mgrid_idx_3Dto1D(expected_3d); + EXPECT_EQ(global_idx, expected_1d); +} + +// Test with local cell at origin +class LocalCellInfoOriginTest : public testing::Test +{ +protected: + void SetUp() override + { + unitcell_vec1 = ModuleGint::Vec3d(12.0, 0.0, 0.0); + unitcell_vec2 = ModuleGint::Vec3d(0.0, 12.0, 0.0); + unitcell_vec3 = ModuleGint::Vec3d(0.0, 0.0, 12.0); + + unitcell_info = std::make_shared( + unitcell_vec1, unitcell_vec2, unitcell_vec3, + 3, 3, 3, 6, 6, 6); + + // Local cell at origin covering all biggrids + localcell_info = std::make_shared( + 0, 0, 0, 3, 3, 3, unitcell_info); + } + + ModuleGint::Vec3d unitcell_vec1, unitcell_vec2, unitcell_vec3; + std::shared_ptr unitcell_info; + std::shared_ptr localcell_info; +}; + +TEST_F(LocalCellInfoOriginTest, LocalGlobalConsistency) +{ + // When local cell starts at origin and covers all biggrids, + // local and global indices should be the same + for (int i = 0; i < localcell_info->get_bgrids_num(); ++i) + { + EXPECT_EQ(localcell_info->get_bgrid_global_idx_1D(i), + unitcell_info->bgrid_idx_3Dto1D(localcell_info->bgrid_idx_1Dto3D(i))); + } +} + +TEST_F(LocalCellInfoOriginTest, AllBgridsInLcell) +{ + for (int x = 0; x < 3; ++x) + { + for (int y = 0; y < 3; ++y) + { + for (int z = 0; z < 3; ++z) + { + ModuleGint::Vec3i idx(x, y, z); + EXPECT_TRUE(localcell_info->is_bgrid_in_lcell(idx)); + } + } + } +} diff --git a/source/source_lcao/module_gint/test/unitcell_info_test.cpp b/source/source_lcao/module_gint/test/unitcell_info_test.cpp new file mode 100644 index 0000000000..ae64d25ee0 --- /dev/null +++ b/source/source_lcao/module_gint/test/unitcell_info_test.cpp @@ -0,0 +1,296 @@ +#include "../unitcell_info.h" +#include "gtest/gtest.h" +#include + +/************************************************ + * unit test of UnitCellInfo class + ***********************************************/ + +/** + * Tested functions of class UnitCellInfo: + * - constructor + * - getter functions: get_nbx, get_nby, get_nbz, get_bgrids_num + * - getter functions: get_nmx, get_nmy, get_nmz, get_mgrids_num + * - bgrid_idx_1Dto3D, bgrid_idx_3Dto1D: biggrid index conversion + * - get_bgrid_coord: get Cartesian coordinate of biggrid + * - get_bgrid_idx_3d: get 3D index of biggrid from Cartesian coordinate + * - get_relative_coord: get relative coordinates between two biggrids + * - get_unitcell_idx: get extended unitcell index + * - map_ext_idx_to_ucell: map extended index to unitcell + * - mgrid_idx_1Dto3D, mgrid_idx_3Dto1D: meshgrid index conversion + * - get_mgrid_coord: get Cartesian coordinate of meshgrid + */ + +class UnitCellInfoTest : public testing::Test +{ +protected: + void SetUp() override + { + // Create a simple cubic unitcell with vectors (12,0,0), (0,12,0), (0,0,12) + // with 3x3x3 biggrids and 6x6x6 meshgrids + unitcell_vec1 = ModuleGint::Vec3d(12.0, 0.0, 0.0); + unitcell_vec2 = ModuleGint::Vec3d(0.0, 12.0, 0.0); + unitcell_vec3 = ModuleGint::Vec3d(0.0, 0.0, 12.0); + nbx = 3; + nby = 3; + nbz = 3; + nmx = 6; + nmy = 6; + nmz = 6; + + unitcell_info = std::make_shared( + unitcell_vec1, unitcell_vec2, unitcell_vec3, + nbx, nby, nbz, nmx, nmy, nmz); + } + + ModuleGint::Vec3d unitcell_vec1, unitcell_vec2, unitcell_vec3; + int nbx, nby, nbz; + int nmx, nmy, nmz; + std::shared_ptr unitcell_info; +}; + +// Test constructor and getter functions +TEST_F(UnitCellInfoTest, Constructor_BigGridDimensions) +{ + EXPECT_EQ(unitcell_info->get_nbx(), nbx); + EXPECT_EQ(unitcell_info->get_nby(), nby); + EXPECT_EQ(unitcell_info->get_nbz(), nbz); + EXPECT_EQ(unitcell_info->get_bgrids_num(), nbx * nby * nbz); +} + +TEST_F(UnitCellInfoTest, Constructor_MeshGridDimensions) +{ + EXPECT_EQ(unitcell_info->get_nmx(), nmx); + EXPECT_EQ(unitcell_info->get_nmy(), nmy); + EXPECT_EQ(unitcell_info->get_nmz(), nmz); + EXPECT_EQ(unitcell_info->get_mgrids_num(), nmx * nmy * nmz); +} + +TEST_F(UnitCellInfoTest, Constructor_BigGridInfo) +{ + auto bgrid_info = unitcell_info->get_bgrid_info(); + EXPECT_NE(bgrid_info, nullptr); + // Each biggrid has (nmx/nbx) x (nmy/nby) x (nmz/nbz) = 2x2x2 meshgrids + EXPECT_EQ(bgrid_info->get_nmx(), 2); + EXPECT_EQ(bgrid_info->get_nmy(), 2); + EXPECT_EQ(bgrid_info->get_nmz(), 2); +} + +// Test biggrid index conversion +TEST_F(UnitCellInfoTest, BgridIdx_1Dto3D_Origin) +{ + ModuleGint::Vec3i result = unitcell_info->bgrid_idx_1Dto3D(0); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 0); +} + +TEST_F(UnitCellInfoTest, BgridIdx_3Dto1D_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + EXPECT_EQ(unitcell_info->bgrid_idx_3Dto1D(index_3d), 0); +} + +TEST_F(UnitCellInfoTest, BgridIdx_Conversion_Roundtrip) +{ + for (int i = 0; i < nbx * nby * nbz; ++i) + { + ModuleGint::Vec3i idx_3d = unitcell_info->bgrid_idx_1Dto3D(i); + EXPECT_EQ(unitcell_info->bgrid_idx_3Dto1D(idx_3d), i); + } +} + +// Test get_bgrid_coord with Vec3i +TEST_F(UnitCellInfoTest, GetBgridCoord_Vec3i_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + ModuleGint::Vec3d coord = unitcell_info->get_bgrid_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +TEST_F(UnitCellInfoTest, GetBgridCoord_Vec3i_Unit) +{ + // Biggrid size = unitcell_vec / nb = (4, 4, 4) + ModuleGint::Vec3i index_3d(1, 0, 0); + ModuleGint::Vec3d coord = unitcell_info->get_bgrid_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 4.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); + + index_3d = ModuleGint::Vec3i(0, 2, 0); + coord = unitcell_info->get_bgrid_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 8.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +// Test get_bgrid_coord with int (1D index) +TEST_F(UnitCellInfoTest, GetBgridCoord_1D) +{ + // Index 0 should be origin + ModuleGint::Vec3d coord = unitcell_info->get_bgrid_coord(0); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +// Test get_bgrid_idx_3d +TEST_F(UnitCellInfoTest, GetBgridIdx3D_Origin) +{ + ModuleGint::Vec3d coord(0.0, 0.0, 0.0); + ModuleGint::Vec3i idx = unitcell_info->get_bgrid_idx_3d(coord); + EXPECT_EQ(idx.x, 0); + EXPECT_EQ(idx.y, 0); + EXPECT_EQ(idx.z, 0); +} + +TEST_F(UnitCellInfoTest, GetBgridIdx3D_InFirstBgrid) +{ + // Point inside the first biggrid (size 4x4x4) + ModuleGint::Vec3d coord(2.0, 3.0, 1.0); + ModuleGint::Vec3i idx = unitcell_info->get_bgrid_idx_3d(coord); + EXPECT_EQ(idx.x, 0); + EXPECT_EQ(idx.y, 0); + EXPECT_EQ(idx.z, 0); +} + +TEST_F(UnitCellInfoTest, GetBgridIdx3D_InSecondBgrid) +{ + ModuleGint::Vec3d coord(5.0, 1.0, 1.0); // x > 4, so in second biggrid along x + ModuleGint::Vec3i idx = unitcell_info->get_bgrid_idx_3d(coord); + EXPECT_EQ(idx.x, 1); + EXPECT_EQ(idx.y, 0); + EXPECT_EQ(idx.z, 0); +} + +// Test get_relative_coord +TEST_F(UnitCellInfoTest, GetRelativeCoord_Same) +{ + ModuleGint::Vec3i idx_a(1, 1, 1); + ModuleGint::Vec3i idx_b(1, 1, 1); + ModuleGint::Vec3d rel_coord = unitcell_info->get_relative_coord(idx_a, idx_b); + EXPECT_DOUBLE_EQ(rel_coord.x, 0.0); + EXPECT_DOUBLE_EQ(rel_coord.y, 0.0); + EXPECT_DOUBLE_EQ(rel_coord.z, 0.0); +} + +TEST_F(UnitCellInfoTest, GetRelativeCoord_Different) +{ + ModuleGint::Vec3i idx_a(2, 1, 0); + ModuleGint::Vec3i idx_b(0, 1, 0); + ModuleGint::Vec3d rel_coord = unitcell_info->get_relative_coord(idx_a, idx_b); + // (2-0) * 4 = 8 in x direction + EXPECT_DOUBLE_EQ(rel_coord.x, 8.0); + EXPECT_DOUBLE_EQ(rel_coord.y, 0.0); + EXPECT_DOUBLE_EQ(rel_coord.z, 0.0); +} + +// Test get_unitcell_idx +TEST_F(UnitCellInfoTest, GetUnitcellIdx_InFirstUcell) +{ + ModuleGint::Vec3i idx(0, 1, 2); + ModuleGint::Vec3i ucell_idx = unitcell_info->get_unitcell_idx(idx); + EXPECT_EQ(ucell_idx.x, 0); + EXPECT_EQ(ucell_idx.y, 0); + EXPECT_EQ(ucell_idx.z, 0); +} + +TEST_F(UnitCellInfoTest, GetUnitcellIdx_Extended) +{ + ModuleGint::Vec3i idx(3, 4, 5); // nbx=3, so x=3 is in next unitcell + ModuleGint::Vec3i ucell_idx = unitcell_info->get_unitcell_idx(idx); + EXPECT_EQ(ucell_idx.x, 1); + EXPECT_EQ(ucell_idx.y, 1); + EXPECT_EQ(ucell_idx.z, 1); +} + +TEST_F(UnitCellInfoTest, GetUnitcellIdx_Negative) +{ + ModuleGint::Vec3i idx(-1, -1, -1); + ModuleGint::Vec3i ucell_idx = unitcell_info->get_unitcell_idx(idx); + EXPECT_EQ(ucell_idx.x, -1); + EXPECT_EQ(ucell_idx.y, -1); + EXPECT_EQ(ucell_idx.z, -1); +} + +// Test map_ext_idx_to_ucell +TEST_F(UnitCellInfoTest, MapExtIdxToUcell_InFirstUcell) +{ + ModuleGint::Vec3i idx(1, 1, 1); + ModuleGint::Vec3i mapped_idx = unitcell_info->map_ext_idx_to_ucell(idx); + EXPECT_EQ(mapped_idx.x, 1); + EXPECT_EQ(mapped_idx.y, 1); + EXPECT_EQ(mapped_idx.z, 1); +} + +TEST_F(UnitCellInfoTest, MapExtIdxToUcell_Extended) +{ + ModuleGint::Vec3i idx(4, 5, 6); // should map to (1, 2, 0) + ModuleGint::Vec3i mapped_idx = unitcell_info->map_ext_idx_to_ucell(idx); + EXPECT_EQ(mapped_idx.x, 1); + EXPECT_EQ(mapped_idx.y, 2); + EXPECT_EQ(mapped_idx.z, 0); +} + +TEST_F(UnitCellInfoTest, MapExtIdxToUcell_Negative) +{ + ModuleGint::Vec3i idx(-1, -1, -1); // should map to (2, 2, 2) + ModuleGint::Vec3i mapped_idx = unitcell_info->map_ext_idx_to_ucell(idx); + EXPECT_EQ(mapped_idx.x, 2); + EXPECT_EQ(mapped_idx.y, 2); + EXPECT_EQ(mapped_idx.z, 2); +} + +// Test meshgrid index conversion +TEST_F(UnitCellInfoTest, MgridIdx_1Dto3D_Origin) +{ + ModuleGint::Vec3i result = unitcell_info->mgrid_idx_1Dto3D(0); + EXPECT_EQ(result.x, 0); + EXPECT_EQ(result.y, 0); + EXPECT_EQ(result.z, 0); +} + +TEST_F(UnitCellInfoTest, MgridIdx_3Dto1D_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + EXPECT_EQ(unitcell_info->mgrid_idx_3Dto1D(index_3d), 0); +} + +TEST_F(UnitCellInfoTest, MgridIdx_Conversion_Roundtrip) +{ + for (int i = 0; i < std::min(nmx * nmy * nmz, 27); ++i) // Test subset + { + ModuleGint::Vec3i idx_3d = unitcell_info->mgrid_idx_1Dto3D(i); + EXPECT_EQ(unitcell_info->mgrid_idx_3Dto1D(idx_3d), i); + } +} + +// Test get_mgrid_coord +TEST_F(UnitCellInfoTest, GetMgridCoord_Vec3i_Origin) +{ + ModuleGint::Vec3i index_3d(0, 0, 0); + ModuleGint::Vec3d coord = unitcell_info->get_mgrid_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +TEST_F(UnitCellInfoTest, GetMgridCoord_Vec3i_Unit) +{ + // Meshgrid size = unitcell_vec / nm = (2, 2, 2) + ModuleGint::Vec3i index_3d(1, 0, 0); + ModuleGint::Vec3d coord = unitcell_info->get_mgrid_coord(index_3d); + EXPECT_DOUBLE_EQ(coord.x, 2.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +} + +TEST_F(UnitCellInfoTest, GetMgridCoord_1D) +{ + ModuleGint::Vec3d coord = unitcell_info->get_mgrid_coord(0); + EXPECT_DOUBLE_EQ(coord.x, 0.0); + EXPECT_DOUBLE_EQ(coord.y, 0.0); + EXPECT_DOUBLE_EQ(coord.z, 0.0); +}