Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions source/source_base/module_out/sparse_matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,23 @@ void SparseMatrix<T>::printToCSR(std::ostream& ofs, int precision)
size_t count1 = 0;
for (const auto &element : elements)
{
if(count1%6==0) ofs << std::endl;
if(count1%6==0) ofs << '\n';
count1++;
ofs << " " << element.second;
}
ofs << std::endl;
ofs << '\n';
// print the CSR column indices
ofs << " # CSR column indices";
size_t count2 = 0;
for (const auto &element : elements)
{
if(count2%16==0) ofs << std::endl;
if(count2%16==0) ofs << '\n';
count2++;
ofs << " " << element.first.second;
int row = element.first.first;
csr_row_ptr[row + 1]++;
}
ofs << std::endl;
ofs << '\n';

// Compute the row pointers
for (int i = 1; i <= _rows; i++)
Expand All @@ -69,10 +69,11 @@ void SparseMatrix<T>::printToCSR(std::ostream& ofs, int precision)
ofs << " # CSR row pointers";
for (int i = 0; i < csr_row_ptr.size(); i++)
{
if(i%16==0) ofs << std::endl;
if(i%16==0) ofs << '\n';
ofs << " " << csr_row_ptr[i];
}
ofs << std::endl << std::endl;
// Keep the completed CSR payload visible to callers without flushing each line.
ofs << '\n' << std::endl;
}

/**
Expand Down
101 changes: 101 additions & 0 deletions source/source_base/test/sparse_matrix_test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "source_base/module_out/sparse_matrix.h"

#include <complex>
#include <iomanip>
#include <sstream>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
Expand Down Expand Up @@ -41,6 +43,105 @@ class SparseMatrixTest : public ::testing::Test
using MyTypes = ::testing::Types<double, std::complex<double>>;
TYPED_TEST_SUITE(SparseMatrixTest, MyTypes);

namespace
{
class CountingBuffer : public std::stringbuf
{
public:
int sync_count = 0;
bool fail_sync = false;

protected:
int sync() override
{
++sync_count;
return fail_sync ? -1 : std::stringbuf::sync();
}
};

double csr_value(double value)
{
return value;
}

std::complex<double> csr_value(std::complex<double> value)
{
return value + std::complex<double>(0.0, -0.25);
}
} // namespace

TYPED_TEST(SparseMatrixTest, BufferedCSRPreservesWrappingPrecisionAndFinalFlush)
{
// Cross both wrapping boundaries (6 values, 16 indices) with an empty row.
ModuleIO::SparseMatrix<TypeParam> matrix(18, 18);
std::vector<TypeParam> values;
for (int row = 16; row >= 0; --row)
{
matrix.insert(row, 17 - row, csr_value(TypeParam(row + 0.125)));
}
matrix.insert(17, 0, TypeParam(1e-10)); // Equality to the threshold stays absent.
for (int row = 0; row < 17; ++row)
{
values.push_back(csr_value(TypeParam(row + 0.125)));
}
const auto original = matrix.getElements();
for (const int precision : {2, 8, 16})
{
CountingBuffer buffer;
std::ostream output(&buffer);
matrix.printToCSR(output, precision);

std::ostringstream expected;
expected << std::scientific << std::setprecision(precision) << " # CSR values";
for (int row = 0; row < 17; ++row)
{
if (row == 0 || row == 6 || row == 12) expected << '\n';
expected << ' ' << values[row];
}
expected << "\n # CSR column indices\n";
for (int col = 17; col > 0; --col)
{
if (col == 1) expected << '\n';
expected << ' ' << col;
}
expected << "\n # CSR row pointers\n";
for (int row = 0; row <= 18; ++row)
{
if (row == 16) expected << '\n';
expected << ' ' << (row < 17 ? row : 17);
}
expected << "\n\n";
EXPECT_EQ(buffer.str(), expected.str());
EXPECT_EQ(buffer.sync_count, 1);
EXPECT_EQ(matrix.getElements(), original);
EXPECT_TRUE(output.good());

matrix.printToCSR(output, precision);
EXPECT_EQ(buffer.str(), expected.str() + expected.str());
EXPECT_EQ(buffer.sync_count, 2);
}
}

TYPED_TEST(SparseMatrixTest, EmptyCSRAndFlushFailure)
{
CountingBuffer buffer;
std::ostream output(&buffer);
this->sm.printToCSR(output, 8);
EXPECT_EQ(buffer.str(), " # CSR values\n # CSR column indices\n # CSR row pointers\n 0 0 0 0 0\n\n");
EXPECT_EQ(buffer.sync_count, 1);

CountingBuffer failing_buffer;
failing_buffer.fail_sync = true;
std::ostream failing_output(&failing_buffer);
this->sm.printToCSR(failing_output, 8);
EXPECT_TRUE(failing_output.bad());
EXPECT_EQ(failing_buffer.sync_count, 1);

std::ostream throwing_output(&failing_buffer);
throwing_output.exceptions(std::ios::badbit);
EXPECT_THROW(this->sm.printToCSR(throwing_output, 8), std::ios_base::failure);
}

TYPED_TEST(SparseMatrixTest, Insert)
{
// Add a value to the matrix with row and column indices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void Output_HContainer<T>::write_single_R(int rx, int ry, int rz)

for (int iap = 0; iap < this->_hcontainer->size_atom_pairs(); ++iap)
{
auto atom_pair = this->_hcontainer->get_atom_pair(iap);
const auto& atom_pair = this->_hcontainer->get_atom_pair(iap);
const int r_index = atom_pair.find_R(rx, ry, rz);
if (r_index < 0) continue;
auto tmp_matrix_info = atom_pair.get_matrix_values(r_index);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "source_hamilt/module_hcontainer/hcontainer.h"
#include "source_hamilt/module_hcontainer/output_hcontainer.h"
#include "source_cell/unitcell.h"
#include <complex>
#include <sstream>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
Expand Down Expand Up @@ -159,3 +162,78 @@ TEST_F(OutputHContainerTest, Write)
EXPECT_THAT(output, testing::HasSubstr(" 2 3 3"));
EXPECT_THAT(output, testing::HasSubstr(" 0 0 0 2 3"));
}

template <typename T>
class OutputHContainerPreservationTest : public testing::Test
{
};

using OutputTypes = testing::Types<double, std::complex<double>>;
TYPED_TEST_SUITE(OutputHContainerPreservationTest, OutputTypes);

TYPED_TEST(OutputHContainerPreservationTest, RepeatedWritesPreserveAllRBlocksAndBackingStorage)
{
Parallel_Orbitals para;
para.set_serial(4, 4);
const int atom_begin[] = {0, 2};
para.set_atomic_trace(atom_begin, 2, 4);
std::vector<TypeParam> first = {TypeParam(1), TypeParam(2), TypeParam(3), TypeParam(4)};
std::vector<TypeParam> second = {TypeParam(5), TypeParam(6), TypeParam(7), TypeParam(8)};
std::vector<TypeParam> empty(4, TypeParam(1e-12));
const auto first_before = first;
const auto second_before = second;
const auto empty_before = empty;
hamilt::HContainer<TypeParam> matrix(&para);
matrix.insert_pair(hamilt::AtomPair<TypeParam>(0, 0, 1, 0, 0, &para, first.data()));
matrix.insert_pair(hamilt::AtomPair<TypeParam>(0, 0, -1, 0, 0, &para, second.data()));
matrix.insert_pair(hamilt::AtomPair<TypeParam>(1, 1, 0, 0, 0, &para, empty.data()));
auto* pair = matrix.find_pair(0, 0);
ASSERT_NE(pair, nullptr);
const auto first_r = pair->get_R_index(0);
const auto second_r = pair->get_R_index(1);
const auto* first_pointer = pair->get_pointer(0);
const auto* second_pointer = pair->get_pointer(1);

std::ostringstream once;
hamilt::Output_HContainer<TypeParam> writer(&matrix, once, 1e-10, 8);
writer.write();
EXPECT_THAT(once.str(), testing::HasSubstr(" -1 0 0 4\n"));
EXPECT_THAT(once.str(), testing::HasSubstr(" 0 0 0 0\n # CSR values\n\n # CSR column indices\n\n"));
EXPECT_LT(once.str().find(" -1 0 0 4\n"), once.str().find(" 1 0 0 4\n"));
const std::string first_output = once.str();
writer.write();
EXPECT_EQ(once.str(), first_output + first_output);

std::ostringstream block;
hamilt::Output_HContainer<TypeParam> single(&matrix, block, 1e-10, 8);
single.write(1, 0, 0);
single.write(-1, 0, 0);
EXPECT_EQ(matrix.size_atom_pairs(), 2); // No R remains fixed after writing.
EXPECT_EQ(matrix.size_R_loop(), 3);
EXPECT_EQ(matrix.find_pair(0, 0), pair);
EXPECT_EQ(pair->get_R_index(0), first_r);
EXPECT_EQ(pair->get_R_index(1), second_r);
EXPECT_EQ(pair->get_pointer(0), first_pointer);
EXPECT_EQ(pair->get_pointer(1), second_pointer);
for (int element = 0; element < 4; ++element)
{
EXPECT_EQ(first_pointer[element], first_before[element]);
EXPECT_EQ(second_pointer[element], second_before[element]);
}
EXPECT_EQ(first, first_before);
EXPECT_EQ(second, second_before);
EXPECT_EQ(empty, empty_before);

// The same container must still be usable by a subsequent gamma-only calculation.
matrix.fix_gamma();
EXPECT_EQ(matrix.size_R_loop(), 1);
for (int element = 0; element < 4; ++element)
{
EXPECT_EQ(matrix.find_pair(0, 0)->get_pointer(0)[element],
first_before[element] + second_before[element]);
}
std::ostringstream gamma;
hamilt::Output_HContainer<TypeParam> gamma_writer(&matrix, gamma, 1e-10, 8);
gamma_writer.write();
EXPECT_THAT(gamma.str(), testing::HasSubstr(" 0 0 0 4\n"));
}
Loading