diff --git a/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt b/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt index 56a2ada86fa..6eb2cac6ec1 100644 --- a/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt +++ b/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt @@ -2,6 +2,7 @@ list(APPEND objects base_matrix.cpp atom_pair.cpp hcontainer.cpp + output_hcontainer.cpp ) add_library( diff --git a/source/module_hamilt_lcao/module_hcontainer/output_hcontainer.cpp b/source/module_hamilt_lcao/module_hcontainer/output_hcontainer.cpp new file mode 100644 index 00000000000..d60421c8d54 --- /dev/null +++ b/source/module_hamilt_lcao/module_hcontainer/output_hcontainer.cpp @@ -0,0 +1,114 @@ +#include "output_hcontainer.h" + +#include + +#include "module_io/sparse_matrix.h" + +namespace hamilt +{ + +/** + * @brief Constructor of Output_HContainer + * @attention ofs should be open outside of this interface + */ +template +Output_HContainer::Output_HContainer(hamilt::HContainer* hcontainer, + const Parallel_Orbitals* ParaV, + const UnitCell& ucell, + std::ostream& ofs, + double sparse_threshold, + int precision) + : _hcontainer(hcontainer), + _ParaV(ParaV), + _ucell(ucell), + _ofs(ofs), + _sparse_threshold(sparse_threshold), + _precision(precision) +{ +} + +template +void Output_HContainer::write() +{ + int size_for_loop_R = this->_hcontainer->size_R_loop(); + int rx, ry, rz; + for (int iR = 0; iR < size_for_loop_R; iR++) + { + this->_hcontainer->loop_R(iR, rx, ry, rz); + this->write_single_R(rx, ry, rz); + } +} + +template +void Output_HContainer::write(int rx_in, int ry_in, int rz_in) +{ + int size_for_loop_R = this->_hcontainer->size_R_loop(); + int rx, ry, rz; + int find_R = 0; + for (int iR = 0; iR < size_for_loop_R; iR++) + { + this->_hcontainer->loop_R(iR, rx, ry, rz); + if (rx == rx_in && ry == ry_in && rz == rz_in) + { + find_R += 1; + this->write_single_R(rx, ry, rz); + break; + } + } + if (find_R == 0) + { + ModuleBase::WARNING_QUIT("Output_HContainer::write", "Cannot find the R vector from the HContaine"); + } +} + +template +void Output_HContainer::write_single_R(int rx, int ry, int rz) +{ + this->_hcontainer->fix_R(rx, ry, rz); + ModuleIO::SparseMatrix sparse_matrix = ModuleIO::SparseMatrix(this->_ParaV->nrow, this->_ParaV->ncol); + int nonzero = 0; + for (int iap = 0; iap < this->_hcontainer->size_atom_pairs(); ++iap) + { + auto atom_pair = this->_hcontainer->get_atom_pair(iap); + int iat1 = atom_pair.get_atom_i(); + int iat2 = atom_pair.get_atom_j(); + int T1 = _ucell.iat2it[iat1]; + int T2 = _ucell.iat2it[iat2]; + int I1 = _ucell.iat2ia[iat1]; + int I2 = _ucell.iat2ia[iat2]; + const int start1 = _ucell.itiaiw2iwt(T1, I1, 0); + const int start2 = _ucell.itiaiw2iwt(T2, I2, 0); + int size1 = _ucell.atoms[T1].nw; + int size2 = _ucell.atoms[T2].nw; + for (int iw1 = 0; iw1 < size1; ++iw1) + { + const int global_index1 = start1 + iw1; + for (int iw2 = 0; iw2 < size2; ++iw2) + { + const int global_index2 = start2 + iw2; + + T tmp_matrix_value = atom_pair.get_matrix_value(global_index1, global_index2); + + if (std::abs(tmp_matrix_value) > _sparse_threshold) + { + nonzero++; + sparse_matrix.addValue(global_index1, global_index2, tmp_matrix_value); + // to do: consider 2D block-cyclic distribution + } + } + } + } + if (nonzero != 0) + { + _ofs << rx << " " << ry << " " << rz << " " << nonzero << std::endl; + sparse_matrix.printToCSR(_ofs, _sparse_threshold, _precision); + } + this->_hcontainer->unfix_R(); +} + +// explicit instantiation of template class with double type +template class Output_HContainer; +// to do: explicit instantiation of template class with std::complex type +// template class Output_HContainer>; + +} // namespace hamilt \ No newline at end of file diff --git a/source/module_hamilt_lcao/module_hcontainer/output_hcontainer.h b/source/module_hamilt_lcao/module_hcontainer/output_hcontainer.h new file mode 100644 index 00000000000..3a8152a409f --- /dev/null +++ b/source/module_hamilt_lcao/module_hcontainer/output_hcontainer.h @@ -0,0 +1,49 @@ +#ifndef OUTPUT_HCONTAINER_H +#define OUTPUT_HCONTAINER_H + +#include "module_cell/unitcell.h" +#include "module_hamilt_lcao/module_hcontainer/hcontainer.h" + +namespace hamilt +{ + +/** + * @brief A class to output the HContainer + */ +template +class Output_HContainer +{ + public: + Output_HContainer(hamilt::HContainer* hcontainer, + const Parallel_Orbitals* ParaV, + const UnitCell& ucell, + std::ostream& ofs, + double sparse_threshold, + int precision); + // write the matrices of all R vectors to the output stream + void write(); + + /** + * write the matrix of a single R vector to the output stream + * rx_in, ry_in, rz_in: the R vector from the input + */ + void write(int rx_in, int ry_in, int rz_in); + + /** + * write the matrix of a single R vector to the output stream + * rx, ry, rz: the R vector from the HContainer + */ + void write_single_R(int rx, int ry, int rz); + + private: + hamilt::HContainer* _hcontainer; + const UnitCell& _ucell; + const Parallel_Orbitals* _ParaV; + std::ostream& _ofs; + double _sparse_threshold; + int _precision; +}; + +} // namespace ModuleIO + +#endif // OUTPUT_HCONTAINER_H \ No newline at end of file diff --git a/source/module_hamilt_lcao/module_hcontainer/test/CMakeLists.txt b/source/module_hamilt_lcao/module_hcontainer/test/CMakeLists.txt index f3a52a683d5..3f801ee2973 100644 --- a/source/module_hamilt_lcao/module_hcontainer/test/CMakeLists.txt +++ b/source/module_hamilt_lcao/module_hcontainer/test/CMakeLists.txt @@ -20,4 +20,10 @@ AddTest( SOURCES test_hcontainer_time.cpp ../base_matrix.cpp ../hcontainer.cpp ../atom_pair.cpp ../../../module_basis/module_ao/parallel_2d.cpp ../../../module_basis/module_ao/parallel_orbitals.cpp tmp_mocks.cpp ) + +AddTest( + TARGET test_output_hcontainer + LIBS base ${math_libs} device + SOURCES output_hcontainer_test.cpp ../output_hcontainer.cpp ../../../module_basis/module_ao/parallel_2d.cpp ../../../module_basis/module_ao/parallel_orbitals.cpp ../../../module_io/sparse_matrix.cpp ../base_matrix.cpp ../hcontainer.cpp ../atom_pair.cpp tmp_mocks.cpp +) endif() \ No newline at end of file diff --git a/source/module_hamilt_lcao/module_hcontainer/test/output_hcontainer_test.cpp b/source/module_hamilt_lcao/module_hcontainer/test/output_hcontainer_test.cpp new file mode 100644 index 00000000000..f4d870c1fd4 --- /dev/null +++ b/source/module_hamilt_lcao/module_hcontainer/test/output_hcontainer_test.cpp @@ -0,0 +1,164 @@ +#include "../output_hcontainer.h" + +#include "../hcontainer.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "module_cell/unitcell.h" + +/************************************************ + * unit test of output_hcontainer.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - write() + * - write the matrices of all R vectors to the output stream + * - write(int rx_in, int ry_in, int rz_in) + * - write the matrix of a single R vector to the output stream + * - write_single_R(int rx, int ry, int rz) + * - write the matrix of a single R vector to the output stream + */ + +class OutputHContainerTest : public testing::Test +{ + protected: + UnitCell ucell; + std::string output; + void SetUp() override + { + ucell.ntype = 1; + ucell.nat = 2; + ucell.atoms = new Atom[ucell.ntype]; + ucell.iat2it = new int[ucell.nat]; + ucell.iat2ia = new int[ucell.nat]; + for (int iat = 0; iat < ucell.nat; iat++) + { + ucell.iat2ia[iat] = iat; + ucell.iat2it[iat] = 0; + } + ucell.atoms[0].nw = 2; + ucell.iwt2iat = new int[4]; + ucell.iwt2iw = new int[4]; + ucell.itia2iat.create(ucell.ntype, ucell.nat); + ucell.iat2iwt.resize(ucell.nat); + ucell.iat2iwt[0] = 0; + ucell.iat2iwt[1] = 2; + ucell.itia2iat(0, 0) = 0; + ucell.itia2iat(0, 1) = 1; + ucell.iwt2iat[0] = 0; + ucell.iwt2iat[1] = 0; + ucell.iwt2iat[2] = 1; + ucell.iwt2iat[3] = 1; + ucell.iwt2iw[0] = 0; + ucell.iwt2iw[1] = 1; + ucell.iwt2iw[2] = 0; + ucell.iwt2iw[3] = 1; + } + void TearDown() override + { + delete[] ucell.atoms; + delete[] ucell.iat2it; + delete[] ucell.iat2ia; + delete[] ucell.iwt2iat; + delete[] ucell.iwt2iw; + } +}; + +TEST_F(OutputHContainerTest, Write) +{ + Parallel_Orbitals ParaV; + ParaV.atom_begin_row.resize(2); + ParaV.atom_begin_col.resize(2); + for (int i = 0; i < 2; i++) + { + ParaV.atom_begin_row[i] = i * 2; + ParaV.atom_begin_col[i] = i * 2; + } + ParaV.nrow = 4; + ParaV.ncol = 4; + std::ofstream ofs("output_hcontainer.log"); + ParaV.set_global2local(4, 4, false, ofs); + // std::cout << "ParaV.global2local_row = " << ParaV.global2local_row(0) << " " << ParaV.global2local_row(1) << " " + // << ParaV.global2local_row(2) << " " << ParaV.global2local_row(3) << std::endl; + // std::cout << "ParaV.global2local_col = " << ParaV.global2local_col(0) << " " << ParaV.global2local_col(1) << " " + // << ParaV.global2local_col(2) << " " << ParaV.global2local_col(3) << std::endl; + ofs.close(); + remove("output_hcontainer.log"); + hamilt::HContainer HR(&ParaV); + double correct_array[16] = {1, 2, 0, 4, 5, 0, 7, 0, 3, 0, 5, 6, 7, 8, 0, 10}; + // correct_array represent a matrix of + // 1 2 0 4 + // 5 0 7 0 + // 3 0 5 6 + // 7 8 0 10 + hamilt::AtomPair ap1(0, 1, 0, 1, 1, &ParaV, correct_array); + hamilt::AtomPair ap2(1, 1, 0, 0, 0, &ParaV, correct_array); + HR.insert_pair(ap1); + HR.insert_pair(ap2); + /* + for (int ir = 0; ir < HR.size_R_loop(); ++ir) + { + int rx, ry, rz; + HR.loop_R(ir, rx, ry, rz); + HR.fix_R(rx, ry, rz); + // std::cout << "rx = " << rx << " ry = " << ry << " rz = " << rz << std::endl; + for (int iap = 0; iap < HR.size_atom_pairs(); ++iap) + { + hamilt::AtomPair& tmp_ap = HR.get_atom_pair(iap); + if (rx == 0 && ry == 1 && rz == 1) + { + EXPECT_DOUBLE_EQ(tmp_ap.get_value(0, 0), 0); + EXPECT_DOUBLE_EQ(tmp_ap.get_value(0, 1), 4); + EXPECT_DOUBLE_EQ(tmp_ap.get_value(1, 0), 7); + EXPECT_DOUBLE_EQ(tmp_ap.get_value(1, 1), 0); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(0, 2), 0); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(0, 3), 4); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(1, 2), 7); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(1, 3), 0); + } + else if (rx == 0 && ry == 0 && rz == 0) + { + EXPECT_DOUBLE_EQ(tmp_ap.get_value(0, 0), 5); + EXPECT_DOUBLE_EQ(tmp_ap.get_value(0, 1), 6); + EXPECT_DOUBLE_EQ(tmp_ap.get_value(1, 0), 0); + EXPECT_DOUBLE_EQ(tmp_ap.get_value(1, 1), 10); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(2, 2), 5); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(2, 3), 6); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(3, 2), 0); + EXPECT_DOUBLE_EQ(tmp_ap.get_matrix_value(3, 3), 10); + } + } + HR.unfix_R(); + } + */ + double sparse_threshold = 0.1; + hamilt::Output_HContainer output_HR(&HR, &ParaV, ucell, std::cout, sparse_threshold, 2); + // the first R + testing::internal::CaptureStdout(); + output_HR.write(0, 1, 1); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("0 1 1 2")); + EXPECT_THAT(output, testing::HasSubstr(" 4.00e+00 7.00e+00")); + EXPECT_THAT(output, testing::HasSubstr(" 3 2")); + EXPECT_THAT(output, testing::HasSubstr(" 0 1 2 2 2")); + // the second R + testing::internal::CaptureStdout(); + output_HR.write(0, 0, 0); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("0 0 0 3")); + EXPECT_THAT(output, testing::HasSubstr(" 5.00e+00 6.00e+00 1.00e+01")); + EXPECT_THAT(output, testing::HasSubstr(" 2 3 3")); + EXPECT_THAT(output, testing::HasSubstr(" 0 0 0 2 3")); + // output all R + testing::internal::CaptureStdout(); + output_HR.write(); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("0 1 1 2")); + EXPECT_THAT(output, testing::HasSubstr(" 4.00e+00 7.00e+00")); + EXPECT_THAT(output, testing::HasSubstr(" 3 2")); + EXPECT_THAT(output, testing::HasSubstr(" 0 1 2 2 2")); + EXPECT_THAT(output, testing::HasSubstr("0 0 0 3")); + EXPECT_THAT(output, testing::HasSubstr(" 5.00e+00 6.00e+00 1.00e+01")); + EXPECT_THAT(output, testing::HasSubstr(" 2 3 3")); + EXPECT_THAT(output, testing::HasSubstr(" 0 0 0 2 3")); +} \ No newline at end of file diff --git a/source/module_io/CMakeLists.txt b/source/module_io/CMakeLists.txt index a324d94bf29..823f66512c9 100644 --- a/source/module_io/CMakeLists.txt +++ b/source/module_io/CMakeLists.txt @@ -50,6 +50,7 @@ if(ENABLE_LCAO) dos_nao.cpp output_dm.cpp output_dm1.cpp + sparse_matrix.cpp ) list(APPEND objects_advanced unk_overlap_lcao.cpp diff --git a/source/module_io/sparse_matrix.cpp b/source/module_io/sparse_matrix.cpp new file mode 100644 index 00000000000..1781d09bcf3 --- /dev/null +++ b/source/module_io/sparse_matrix.cpp @@ -0,0 +1,108 @@ +#include "sparse_matrix.h" + +#include + +#include "module_base/tool_quit.h" + +namespace ModuleIO +{ + +/** + * @brief Add value to the matrix with row and column indices + */ +template +void SparseMatrix::addValue(int row, int col, T value) +{ + if (row < 0 || row >= _rows || col < 0 || col >= _cols) + { + ModuleBase::WARNING_QUIT("SparseMatrix::addValue", "row or col index out of range"); + } + data.push_back(std::make_tuple(row, col, value)); +} + +/** + * @brief Print to CSR format + */ +template +void SparseMatrix::printToCSR(std::ostream& ofs, double threshold, int precision) +{ + // Filter elements greater than the threshold + auto it = std::remove_if(data.begin(), data.end(), [threshold](const std::tuple& elem) { + return std::abs(std::get<2>(elem)) <= threshold; + }); + data.erase(it, data.end()); + + // Sort data by row, then by column + std::sort(data.begin(), data.end(), [](const std::tuple& a, const std::tuple& b) { + if (std::get<0>(a) == std::get<0>(b)) + { + return std::get<1>(a) < std::get<1>(b); + } + return std::get<0>(a) < std::get<0>(b); + }); + + // Initialize the CSR arrays + std::vector csr_row_ptr; + csr_row_ptr.assign(_rows + 1, 0); + + // print the CSR values + for (int i = 0; i < data.size(); i++) + { + ofs << " " << std::fixed << std::scientific << std::setprecision(precision) << std::get<2>(data[i]); + } + ofs << std::endl; + // print the CSR column indices + for (int i = 0; i < data.size(); i++) + { + ofs << " " << std::get<1>(data[i]); + int row = std::get<0>(data[i]); + csr_row_ptr[row + 1]++; + } + ofs << std::endl; + + // Compute the row pointers + for (int i = 1; i <= _rows; i++) + { + csr_row_ptr[i] += csr_row_ptr[i - 1]; + } + + // print the CSR row pointers + for (int i = 0; i < csr_row_ptr.size(); i++) + { + ofs << " " << csr_row_ptr[i]; + } + ofs << std::endl; +} + +/** + * @brief Read CSR data from arrays + */ +template +void SparseMatrix::readCSR(const std::vector& values, + const std::vector& col_ind, + const std::vector& row_ptr) +{ + if (row_ptr.size() != static_cast(_rows) + 1) + { + ModuleBase::WARNING_QUIT("SparseMatrix::readCSR", "Invalid row_ptr size"); + } + if (col_ind.size() != values.size()) + { + ModuleBase::WARNING_QUIT("SparseMatrix::readCSR", "Column indices and values size mismatch"); + } + + data.clear(); + for (int row = 0; row < _rows; row++) + { + for (int idx = row_ptr[row]; idx < row_ptr[row + 1]; idx++) + { + data.push_back(std::make_tuple(row, col_ind[idx], values[idx])); + } + } +} + +// Explicit instantiation of template classes +template class SparseMatrix; +template class SparseMatrix>; + +} // namespace ModuleIO \ No newline at end of file diff --git a/source/module_io/sparse_matrix.h b/source/module_io/sparse_matrix.h new file mode 100644 index 00000000000..40ef07bdeca --- /dev/null +++ b/source/module_io/sparse_matrix.h @@ -0,0 +1,77 @@ +#ifndef SPARSE_MATRIX_H +#define SPARSE_MATRIX_H + +#include +#include +#include +#include + +namespace ModuleIO +{ + +/** + * @brief Sparse matrix class + * + * @tparam T + */ +template +class SparseMatrix +{ + public: + // Default constructor + SparseMatrix() : _rows(0), _cols(0) + { + } + + SparseMatrix(int rows, int cols) : _rows(rows), _cols(cols) + { + } + + // add value to the matrix with row and column indices + void addValue(int row, int col, T value); + + // get data vector + const std::vector>& getData() const + { + return data; + } + + // print data in CSR (Compressed Sparse Row) format + void printToCSR(std::ostream& ofs, double threshold, int precision = 8); + + // read CSR data from arrays + void readCSR(const std::vector& values, const std::vector& col_ind, const std::vector& row_ptr); + + // set number of rows + void setRows(int rows) + { + _rows = rows; + } + + // set number of columns + void setCols(int cols) + { + _cols = cols; + } + + // get number of rows + int getRows() const + { + return _rows; + } + + // get number of columns + int getCols() const + { + return _cols; + } + + private: + int _rows; + int _cols; + std::vector> data; +}; // class SparseMatrix + +} // namespace ModuleIO + +#endif // SPARSE_MATRIX_H \ No newline at end of file diff --git a/source/module_io/test/CMakeLists.txt b/source/module_io/test/CMakeLists.txt index 18afa722d75..54fd360095b 100644 --- a/source/module_io/test/CMakeLists.txt +++ b/source/module_io/test/CMakeLists.txt @@ -114,4 +114,10 @@ AddTest( TARGET io_output_log_test LIBS base ${math_libs} device SOURCES ../output_log.cpp outputlog_test.cpp +) + +AddTest( + TARGET io_sparse_matrix_test + LIBS base ${math_libs} device + SOURCES sparse_matrix_test.cpp ../sparse_matrix.cpp ) \ No newline at end of file diff --git a/source/module_io/test/sparse_matrix_test.cpp b/source/module_io/test/sparse_matrix_test.cpp new file mode 100644 index 00000000000..28a6d5ec41f --- /dev/null +++ b/source/module_io/test/sparse_matrix_test.cpp @@ -0,0 +1,216 @@ +#include "module_io/sparse_matrix.h" + +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +/************************************************ + * unit test of sparse_matrix.cpp + ***********************************************/ + +/** + * - Tested Functions: + * - addValue() + * - Add value to the matrix with row and column indices + * - convertToCSR() + * - Convert to CSR format + * - printCSR() + * - Print data in CSR format + * - readCSR() + * - Read CSR data from arrays + */ + +class SparseMatrixTest : public testing::Test +{ + protected: + ModuleIO::SparseMatrix smd = ModuleIO::SparseMatrix(4, 4); + ModuleIO::SparseMatrix> smc = ModuleIO::SparseMatrix>(4, 4); + std::string output; +}; + +TEST_F(SparseMatrixTest, AddValueDouble) +{ + // Add a value to the matrix with row and column indices + smd.addValue(2, 2, 3.0); + smd.addValue(3, 3, 4.0); + + EXPECT_EQ(smd.getData().size(), 2); + EXPECT_EQ(smd.getCols(), 4); + EXPECT_EQ(smd.getRows(), 4); + + // Check if the value was added correctly + EXPECT_EQ(std::make_tuple(2, 2, 3.0), smd.getData()[0]); + EXPECT_EQ(std::make_tuple(3, 3, 4.0), smd.getData()[1]); +} + +TEST_F(SparseMatrixTest, AddValueDoubleWarning) +{ + // case 1 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smd.addValue(2, -1, 3.0), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); + // case 2 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smd.addValue(-1, 0, 3.0), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); + // case 3 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smd.addValue(2, 4, 3.0), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); + // case 4 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smd.addValue(4, 2, 3.0), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); +} + +TEST_F(SparseMatrixTest, AddValueComplex) +{ + // Add a value to the matrix with row and column indices + smc.addValue(2, 2, std::complex(1.0, 0.0)); + smc.addValue(3, 3, std::complex(0.0, 0.2)); + + EXPECT_EQ(smc.getData().size(), 2); + EXPECT_EQ(smc.getCols(), 4); + EXPECT_EQ(smc.getRows(), 4); + + // Check if the value was added correctly + EXPECT_EQ(std::make_tuple(2, 2, std::complex(1.0, 0.0)), smc.getData()[0]); + EXPECT_EQ(std::make_tuple(3, 3, std::complex(0.0, 0.2)), smc.getData()[1]); +} + +TEST_F(SparseMatrixTest, AddValueComplexWarning) +{ + // case 1 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smc.addValue(2, -1, std::complex(1.0, 0.0)), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); + // case 2 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smc.addValue(-1, 0, std::complex(1.0, 0.0)), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); + // case 3 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smc.addValue(2, 4, std::complex(1.0, 0.0)), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); + // case 4 + testing::internal::CaptureStdout(); + EXPECT_EXIT(smc.addValue(4, 2, std::complex(1.0, 0.0)), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + // test output on screen + EXPECT_THAT(output, testing::HasSubstr("row or col index out of range")); +} + +TEST_F(SparseMatrixTest, CSRDouble) +{ + // test the printCSR function for the following matrix + // 1.0 2.0 0.0 0.0 0.0 0.0 + // 0.0 3.0 0.0 4.0 0.0 0.0 + // 0.0 0.0 5.0 6.0 7.0 0.0 + // 0.0 0.0 0.0 0.0 0.0 8.0 + // the expect output is + // csr_values = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] + // csr_col_ind = [0, 1, 1, 3, 2, 3, 4, 5] + // csr_row_ptr = [0, 2, 4, 7, 8] + ModuleIO::SparseMatrix smd0; + ModuleIO::SparseMatrix smd1; + smd0.setRows(4); + smd0.setCols(6); + smd0.addValue(0, 0, 1.0); + smd0.addValue(0, 1, 2.0); + smd0.addValue(1, 1, 3.0); + smd0.addValue(1, 3, 4.0); + smd0.addValue(2, 2, 5.0); + smd0.addValue(2, 3, 6.0); + smd0.addValue(2, 4, 7.0); + smd0.addValue(3, 5, 8.0); + testing::internal::CaptureStdout(); + smd0.printToCSR(std::cout, 0.0, 2); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("1.00e+00 2.00e+00 3.00e+00 4.00e+00 5.00e+00 6.00e+00 7.00e+00 8.00e+00")); + EXPECT_THAT(output, testing::HasSubstr("0 1 1 3 2 3 4 5")); + EXPECT_THAT(output, testing::HasSubstr("0 2 4 7 8")); + + std::vector expected_csr_values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}; + std::vector expected_csr_col_ind = {0, 1, 1, 3, 2, 3, 4, 5}; + std::vector expected_csr_row_ptr = {0, 2, 4, 7, 8}; + + smd1.setRows(4); + smd1.setCols(6); + smd1.readCSR(expected_csr_values, expected_csr_col_ind, expected_csr_row_ptr); + + for (int i = 0; i < 8; i++) + { + EXPECT_EQ(std::get<0>(smd0.getData()[i]), std::get<0>(smd1.getData()[i])); + EXPECT_EQ(std::get<1>(smd0.getData()[i]), std::get<1>(smd1.getData()[i])); + EXPECT_DOUBLE_EQ(std::get<2>(smd0.getData()[i]), std::get<2>(smd1.getData()[i])); + } +} + +TEST_F(SparseMatrixTest, CSRComplex) +{ + // test the printCSR function for the following matrix + // 1.0 2.0 0.0 0.0 0.0 0.0 + // 0.0 3.0 0.0 4.0 0.0 0.0 + // 0.0 0.0 5.0 6.0 7.0 0.0 + // 0.0 0.0 0.0 0.0 0.0 8.0 + // the expect output is + // csr_values = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] + // csr_col_ind = [0, 1, 1, 3, 2, 3, 4, 5] + // csr_row_ptr = [0, 2, 4, 7, 8] + ModuleIO::SparseMatrix> smc0; + ModuleIO::SparseMatrix> smc1; + smc0.setRows(4); + smc0.setCols(6); + smc0.addValue(0, 0, std::complex(1.0, 0.0)); + smc0.addValue(0, 1, std::complex(2.0, 0.0)); + smc0.addValue(1, 1, std::complex(3.0, 0.0)); + smc0.addValue(1, 3, std::complex(4.0, 0.0)); + smc0.addValue(2, 2, std::complex(5.0, 0.0)); + smc0.addValue(2, 3, std::complex(6.0, 0.0)); + smc0.addValue(2, 4, std::complex(7.0, 0.0)); + smc0.addValue(3, 5, std::complex(8.0, 0.0)); + testing::internal::CaptureStdout(); + smc0.printToCSR(std::cout, 0.5, 1); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("(1.0e+00,0.0e+00) (2.0e+00,0.0e+00) (3.0e+00,0.0e+00) (4.0e+00,0.0e+00) (5.0e+00,0.0e+00) (6.0e+00,0.0e+00) (7.0e+00,0.0e+00) (8.0e+00,0.0e+00)")); + EXPECT_THAT(output, testing::HasSubstr("0 1 1 3 2 3 4 5")); + EXPECT_THAT(output, testing::HasSubstr("0 2 4 7 8")); + + std::vector> expected_csr_values = {std::complex(1.0, 0.0), + std::complex(2.0, 0.0), + std::complex(3.0, 0.0), + std::complex(4.0, 0.0), + std::complex(5.0, 0.0), + std::complex(6.0, 0.0), + std::complex(7.0, 0.0), + std::complex(8.0, 0.0)}; + std::vector expected_csr_col_ind = {0, 1, 1, 3, 2, 3, 4, 5}; + std::vector expected_csr_row_ptr = {0, 2, 4, 7, 8}; + + smc1.setRows(4); + smc1.setCols(6); + smc1.readCSR(expected_csr_values, expected_csr_col_ind, expected_csr_row_ptr); + + for (int i = 0; i < 8; i++) + { + EXPECT_EQ(std::get<0>(smc0.getData()[i]), std::get<0>(smc1.getData()[i])); + EXPECT_EQ(std::get<1>(smc0.getData()[i]), std::get<1>(smc1.getData()[i])); + EXPECT_DOUBLE_EQ((std::get<2>(smc0.getData()[i])).real(), (std::get<2>(smc1.getData()[i])).real()); + EXPECT_DOUBLE_EQ((std::get<2>(smc0.getData()[i])).imag(), (std::get<2>(smc1.getData()[i])).imag()); + } +} \ No newline at end of file diff --git a/source/module_io/test/tmp_mocks.cpp b/source/module_io/test/tmp_mocks.cpp new file mode 100644 index 00000000000..e3d27368b99 --- /dev/null +++ b/source/module_io/test/tmp_mocks.cpp @@ -0,0 +1,46 @@ + +#include "module_cell/unitcell.h" + +// constructor of Atom +Atom::Atom() +{ +} +Atom::~Atom() +{ +} + +Atom_pseudo::Atom_pseudo() +{ +} +Atom_pseudo::~Atom_pseudo() +{ +} + +Magnetism::Magnetism() +{ +} +Magnetism::~Magnetism() +{ +} + +InfoNonlocal::InfoNonlocal() +{ +} +InfoNonlocal::~InfoNonlocal() +{ +} + +pseudo_nc::pseudo_nc() +{ +} +pseudo_nc::~pseudo_nc() +{ +} + +// constructor of UnitCell +UnitCell::UnitCell() +{ +} +UnitCell::~UnitCell() +{ +}