Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detach the EHVec class from Matrix #303

Merged
merged 5 commits into from
Jun 5, 2023
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
8 changes: 0 additions & 8 deletions tdms/include/arrays.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,14 +523,6 @@ class DetectorSensitivityArrays {
*/
class CCoefficientMatrix : public Matrix<double> {};

/**
* Temporary storage 'vector'
*/
class EHVec : public Matrix<fftw_complex> {
public:
~EHVec();
};

/**
* Container for storing snapshots of the full-field
*/
Expand Down
47 changes: 47 additions & 0 deletions tdms/include/arrays/eh_vec.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* @file eh_vec.h
* @author William Graham ([email protected])
* @brief Declaration for the storage class used when performing Fourier
* transforms via fftw
*/
#pragma once

#include <fftw3.h>

/**
* @brief Storage class for Fourier transform values, obtained when performing
* the pseudo-spectral timestep.
* @details Storage is organised as a 2D buffer of fftw_complex types, of size
* n_rows_ by n_cols. Elements can be accessed via the [] operator.
*/
class EHVec {
protected:
int n_rows_ = 0;
int n_cols_ = 0;

fftw_complex **data_ = nullptr;

/** @brief Free the memory assigned to this instance */
void free_memory();

public:
EHVec() = default;

fftw_complex *operator[](int col_index) { return data_[col_index]; }

/**
* @brief Allocate storage for this instance. Existing storage will be lost
* (if present).
* @details Reallocation of an already-allocated EHVec frees the current
* buffer before reassigning the new buffer. Any values stored in the old
* buffer are lost, EVEN IF THE NEW BUFFER IS OF GREATER SIZE THAN THE OLD
* BUFFER.
* @param n_rows,n_cols Shape of storage to allocate.
*/
void allocate(int n_rows, int n_cols);

/** @brief Determine whether the instance has memory allocated. */
bool is_allocated() const { return data_ != nullptr; }

~EHVec() { free_memory(); }
};
1 change: 1 addition & 0 deletions tdms/include/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <complex>

#include "arrays.h"
#include "arrays/eh_vec.h"
#include "cell_coordinate.h"
#include "dimensions.h"
#include "input_flags.h"
Expand Down
1 change: 1 addition & 0 deletions tdms/include/simulation_manager/simulation_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <vector>

#include "arrays.h"
#include "arrays/eh_vec.h"
#include "cell_coordinate.h"
#include "globals.h"
#include "input_flags.h"
Expand Down
8 changes: 0 additions & 8 deletions tdms/src/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,3 @@ DetectorSensitivityArrays::~DetectorSensitivityArrays() {
fftw_free(v);
fftw_destroy_plan(plan);
}

EHVec::~EHVec() {
if (has_elements()) {
for (int i = 0; i < n_rows; i++) fftw_free(matrix[i]);
free(matrix);
}
matrix = nullptr;
}
28 changes: 28 additions & 0 deletions tdms/src/arrays/eh_vec.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "arrays/eh_vec.h"

#include <spdlog/spdlog.h>

void EHVec::free_memory() {
if (is_allocated()) {
for (int i = 0; i < n_rows_; i++) { fftw_free(data_[i]); }
free(data_);
}
data_ = nullptr;
}

void EHVec::allocate(int n_rows, int n_cols) {
// If already allocated we need to clean up old memory before resizing!
if (is_allocated()) {
spdlog::warn("EHVec is already assigned - freeing old memory before "
"reallocating!");
free_memory();
}

n_rows_ = n_rows;
n_cols_ = n_cols;

data_ = (fftw_complex **) malloc(n_rows_ * sizeof(fftw_complex *));
for (int i = 0; i < n_rows_; i++) {
data_[i] = (fftw_complex *) malloc(n_cols_ * sizeof(fftw_complex));
}
}
12 changes: 0 additions & 12 deletions tdms/tests/include/array_test_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,6 @@ class PupilTest : public AbstractArrayTest {
std::string get_class_name() override { return "Pupil"; }
};

/** @brief Unit tests for EHVec */
class EHVecTest : public AbstractArrayTest {
private:
const int n_rows = 4, n_cols = 8;

// allocate() needs testing
void test_other_methods() override;

public:
std::string get_class_name() override { return "EHVec"; }
};

/** @brief Unit tests for Tensor3D */
class Tensor3DTest : public AbstractArrayTest {
private:
Expand Down
34 changes: 34 additions & 0 deletions tdms/tests/unit/array_tests/test_EHVec.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <catch2/catch_test_macros.hpp>
#include <spdlog/spdlog.h>

#include "arrays/eh_vec.h"
#include "unit_test_utils.h"

using tdms_tests::is_close;

TEST_CASE("EHVec") {
const int REAL = 0, IMAG = 1;
const int n_rows = 4, n_cols = 8;
EHVec eh;

// allocate memory
REQUIRE(!eh.is_allocated());
eh.allocate(n_rows, n_cols);
REQUIRE(eh.is_allocated());
spdlog::info("Completed assignment");

// check that we an assign fftw_complexes to the elements
eh[0][0][REAL] = 1.;
eh[0][0][IMAG] = 0.;
eh[0][1][REAL] = 0.;
eh[0][1][IMAG] = 1.;
fftw_complex fftw_unit{1., 0.};
fftw_complex fftw_imag_unit{0., 1.};

bool elements_set_correctly =
is_close(eh[0][0][REAL], fftw_unit[REAL]) &&
is_close(eh[0][0][IMAG], fftw_unit[IMAG]) &&
is_close(eh[0][1][REAL], fftw_imag_unit[REAL]) &&
is_close(eh[0][1][IMAG], fftw_imag_unit[IMAG]);
REQUIRE(elements_set_correctly);
}
31 changes: 1 addition & 30 deletions tdms/tests/unit/array_tests/test_Matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@
* @file test_Matrix.cpp
* @author William Graham ([email protected])
* @brief Tests for the Matrix class and its subclasses (Vertices,
* GratingStructure, Pupil, EHVec)
* GratingStructure, Pupil)
*/
#include <catch2/catch_test_macros.hpp>
#include <spdlog/spdlog.h>

#include "array_test_class.h"
#include "arrays.h"
#include "unit_test_utils.h"

using tdms_tests::is_close;

void MatrixTest::test_correct_construction() {
// create a Matrix via the default constructor
Expand Down Expand Up @@ -162,36 +159,10 @@ void PupilTest::test_correct_construction() {
}
}

void EHVecTest::test_other_methods() {
const int REAL = 0, IMAG = 1;
EHVec eh;

// allocate memory
eh.allocate(n_rows, n_cols);
REQUIRE(eh.has_elements());

// check that we an assign fftw_complexes to the elements
eh[0][0][REAL] = 1.;
eh[0][0][IMAG] = 0.;
eh[0][1][REAL] = 0.;
eh[0][1][IMAG] = 1.;
fftw_complex fftw_unit{1., 0.};
fftw_complex fftw_imag_unit{0., 1.};

bool elements_set_correctly =
is_close(eh[0][0][REAL], fftw_unit[REAL]) &&
is_close(eh[0][0][IMAG], fftw_unit[IMAG]) &&
is_close(eh[0][1][REAL], fftw_imag_unit[REAL]) &&
is_close(eh[0][1][IMAG], fftw_imag_unit[IMAG]);
REQUIRE(elements_set_correctly);
}

TEST_CASE("Matrix") { MatrixTest().run_all_class_tests(); }

TEST_CASE("Vertices") { VerticesTest().run_all_class_tests(); }

TEST_CASE("GratingStructure") { GratingStructureTest().run_all_class_tests(); }

TEST_CASE("Pupil") { PupilTest().run_all_class_tests(); }

TEST_CASE("EHVec") { EHVecTest().run_all_class_tests(); }