Skip to content

Commit

Permalink
Detach the EHVec class from Matrix (#303)
Browse files Browse the repository at this point in the history
* Rewrite EHVec in new file

* Adjust include headers that need EHVec class

* Fix tests for EHVec

* Fix tests, fix seg-fault bug in constructor

* Add docstrings to EHVec class
  • Loading branch information
willGraham01 authored Jun 5, 2023
1 parent b51fbf0 commit f673023
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 58 deletions.
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(); }

0 comments on commit f673023

Please sign in to comment.