Skip to content

Commit

Permalink
adding unit test (#16)
Browse files Browse the repository at this point in the history
* Parallelize phantom creation for improved performance

* update

* update

* Created using Colab

* change cu to cpp in main file

* add warning macro

* rename notebook

* bug fix

* adding unit test

* add scale

* update
  • Loading branch information
aghaeifar authored Dec 22, 2024
1 parent 05a73d9 commit cc5cdd9
Show file tree
Hide file tree
Showing 25 changed files with 632 additions and 346 deletions.
14 changes: 8 additions & 6 deletions .github/workflows/build_cmake.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
name: cmake build
name: build & test

on:
push:
branches: [ "main", "dev" ]
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch: # This is the manual trigger

env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release

jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest

steps:
Expand All @@ -41,4 +39,8 @@ jobs:
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}


# Run Unit Tests
- name: Run Unit Tests
run: |
cd ${{github.workspace}}/build/tests
./spinwalk_test
69 changes: 49 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ cmake_minimum_required(VERSION 3.24)
message(STATUS "CMake version: ${CMAKE_VERSION}")
include(CheckLanguage)

set(project "SpinWalk")
project(${project})
set(project_exe "SpinWalk_exe")
set(project_lib "SpinWalk_lib")
project(${project_exe})

# Find HDF5
find_package(HDF5 REQUIRED COMPONENTS CXX)
Expand All @@ -15,7 +16,7 @@ find_package(TBB REQUIRED)
if(CMAKE_VERSION VERSION_GREATER "3.30")
cmake_policy(SET CMP0167 NEW)
endif()
find_package(Boost COMPONENTS log log_setup REQUIRED)
find_package(Boost REQUIRED COMPONENTS log log_setup)

check_language(CUDA)
# Check for CUDA-capable GPU
Expand All @@ -28,6 +29,8 @@ else()
message("CUDA not found. Compiling without GPU support.")
endif()

find_package(OpenMP)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_compile_definitions(MINI_CASE_SENSITIVE)
Expand All @@ -39,22 +42,21 @@ if(CMAKE_BUILD_TYPE MATCHES Debug)
endif()

# Add Boost and CUDA include directories
include_directories(${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIRS} ./include ./src ./src/shapes)
# Add subfolders
add_subdirectory(./src/dwi)
add_subdirectory(./src/phantom)
add_subdirectory(./src/config)
add_subdirectory(./src/sim)
include_directories(${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIRS} ./include ./src)
# Add modules directory
add_subdirectory(src/dwi)
add_subdirectory(src/phantom)
add_subdirectory(src/config)
add_subdirectory(src/sim)

# Add the executable
set(SOURCES ./src/spinwalk.cu ${SUBCOMMAND_PHANTOM} ${SUBCOMMAND_SIM} ${SUBCOMMAND_DWI} ${SUBCOMMAND_CONFIG})
# Add the sources files
set(SOURCE_MODULES ${SUBCOMMAND_PHANTOM} ${SUBCOMMAND_SIM} ${SUBCOMMAND_DWI} ${SUBCOMMAND_CONFIG})
set(SOURCE_MAIN ./src/spinwalk.cu)

if(CMAKE_CUDA_COMPILER)
add_executable(${project} ${SOURCES})
target_link_libraries(${project} ${CUDA_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_CXX_LIBRARIES} TBB::tbb)
else()
# change extension of the files if CUDA is not found
if(NOT CMAKE_CUDA_COMPILER)
set(RENAMED_SOURCES)
foreach(OLD_FILE ${SOURCES})
foreach(OLD_FILE ${SOURCE_MODULES})
# Get the file name without extension
get_filename_component(DIR ${OLD_FILE} DIRECTORY)
get_filename_component(FILE_NAME_WE ${OLD_FILE} NAME_WE)
Expand All @@ -64,15 +66,42 @@ else()
file(COPY_FILE ${OLD_FILE} ${NEW_FILE})
list(APPEND RENAMED_SOURCES ${NEW_FILE})
endforeach()
add_executable(${project} ${RENAMED_SOURCES})
target_link_libraries(${project} ${Boost_LIBRARIES} ${HDF5_CXX_LIBRARIES} TBB::tbb)
set(SOURCE_MODULES ${RENAMED_SOURCES})

file(COPY_FILE ./src/spinwalk.cu ./src/spinwalk.cpp)
set(SOURCE_MAIN ./src/spinwalk.cpp)
endif()

set_target_properties(${project} PROPERTIES OUTPUT_NAME "spinwalk")
# Add the executable
add_library(${project_lib} ${SOURCE_MODULES})
add_executable(${project_exe} ${SOURCE_MAIN})

# Add the libraries
if(CMAKE_CUDA_COMPILER)
target_link_libraries(${project_lib} ${CUDA_LIBRARIES})
endif()
if(OpenMP_CXX_FOUND)
message(STATUS "Found OpenMP, adding to target link libraries.")
target_link_libraries(${project_lib} OpenMP::OpenMP_CXX)
else()
message(STATUS "OpenMP not found, skipping.")
endif()
target_link_libraries(${project_lib} ${Boost_LIBRARIES} ${HDF5_CXX_LIBRARIES} TBB::tbb)
target_link_libraries(${project_exe} PRIVATE ${project_lib})

# Set the output name
set_target_properties(${project_exe} PROPERTIES OUTPUT_NAME "spinwalk")
set_target_properties(${project_lib} PROPERTIES OUTPUT_NAME "spinwalk")


# Install the executable
if (UNIX)
install(TARGETS ${project} DESTINATION bin)
install(TARGETS ${project_exe} DESTINATION bin)
install(TARGETS ${project_lib} DESTINATION lib)
endif()

# Add the tests directory
add_subdirectory(tests)

# cmake ..
# cmake --build . --config Release
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
---
### Demo

Jupyter notebooks demonstrating the basic functionality of SpinWalk for [BOLD fMRI contrast](./demo/spinwalk_example.ipynb) and [free diffusion](./demo/spinwalk_dwi.ipynb) simulations can be found in the [demo](./demo) folder.
Jupyter notebooks demonstrating the basic functionality of SpinWalk for [BOLD fMRI contrast](./demo/spinwalk_bold.ipynb) and [free diffusion](./demo/spinwalk_dwi.ipynb) simulations can be found in the [demo](./demo) folder.

Below are example plots generated by SpinWalk, showing BOLD sensitivity as a function of vessel size for Gradient Echo (GRE) and Spin Echo (SE) sequences. Some [literature](#Literature) is provided as a reference to help understand the intended outcomes of these simulations.

Expand Down
3 changes: 2 additions & 1 deletion containers/Dockerfile_CPU
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ RUN rm -rf ./build && cmake -B ./build && cmake --build ./build --config Release
# Stage 2: Runtime
FROM ubuntu:24.04
USER root
RUN apt-get update && apt install -y libboost-log1.83.0 libtbb-dev libhdf5-103-1 --no-install-recommends && apt-get clean && apt-get -y autoremove && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt install -y libboost-log1.83.0 libtbb-dev libhdf5-103-1 libomp5 --no-install-recommends && apt-get clean && apt-get -y autoremove && rm -rf /var/lib/apt/lists/*
COPY --from=builder /opt/SpinWalk/build/spinwalk /usr/local/bin/
COPY --from=builder /opt/SpinWalk/build/tests/spinwalk_test /usr/local/bin/
LABEL org.opencontainers.image.authors="Ali Aghaeifar"

# docker run --rm -it -v /DATA2:/mnt/DATA2 spinwalk_cpu:ubuntu24.04 bash
1 change: 1 addition & 0 deletions containers/create_dockers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
pushd "$SCRIPT_DIR" > /dev/null

# docker system prune -a --volumes --force
docker system prune --force

CUDA_VERSIONS=("12.0.0" "12.2.0" "12.6.3")

Expand Down
105 changes: 53 additions & 52 deletions demo/spinwalk_example.ipynb → demo/spinwalk_bold.ipynb

Large diffs are not rendered by default.

144 changes: 74 additions & 70 deletions demo/spinwalk_dwi.ipynb

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define DEFINITIONS_H

#define VERSION_MAJOR 1
#define VERSION_MINOR 17
#define VERSION_MINOR 18
#define VERSION_PATCH 2

// Helper macros to stringify values
Expand All @@ -12,6 +12,7 @@
#define SPINWALK_VERSION STRINGIFY(VERSION_MAJOR) "." STRINGIFY(VERSION_MINOR) "." STRINGIFY(VERSION_PATCH)

#define ERR_MSG "\033[1;31mError:\033[0m "
#define WARN_MSG "\033[1;33mWarning:\033[0m "

// #define MINI_CASE_SENSITIVE

Expand Down
6 changes: 3 additions & 3 deletions src/phantom/handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ namespace phantom {
if (args.cylinder){
std::cout << "Generating cylinder phantom..." << std::endl;
cylinder cyl(args.fov, args.resolution, args.dchi, args.oxy_level, args.radius, args.volume_fraction, args.orientation, args.seed, args.output);
status = status && cyl.run();
status = status && cyl.run(true);
}
if (args.sphere){
std::cout << "Generating sphere phantom..." << std::endl;
sphere sph(args.fov, args.resolution, args.dchi, args.oxy_level, args.radius, args.volume_fraction, args.seed,args.output);
status = status && sph.run();
status = status && sph.run(true);
}
std::cout << "Done." << std::endl;
return true;
return status;
}
}
10 changes: 5 additions & 5 deletions src/phantom/phantom_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ phantom_base::phantom_base()
m_fov = 0;
m_resolution = 0;
m_seed = std::random_device{}();
set_blood_parameters(0.273e-6 * 0.4, 0, 10.0);
set_parameters(0.273e-6 * 0.4, 0, 10.0);
set_filename();
}

phantom_base::phantom_base(float fov_um, size_t resolution, float dChi, float Y, float BVF, int32_t seed, std::string filename)
:phantom_base()
{
set_space(fov_um, resolution);
set_blood_parameters(dChi, Y, BVF);
set_parameters(dChi, Y, BVF);
set_filename(filename);
if(seed >= 0)
m_seed = seed;
Expand All @@ -47,11 +47,11 @@ void phantom_base::set_space(float fov_um, size_t resolution)
this->m_resolution = resolution;
}

void phantom_base::set_blood_parameters(float dChi, float Y, float BVF)
void phantom_base::set_parameters(float dChi, float Y, float volume_fraction)
{
this->m_dChi = dChi;
this->m_Y = Y;
this->m_BVF = BVF;
this->m_volume_fraction = volume_fraction;
m_calc_fieldmap = Y >= 0;
}

Expand Down Expand Up @@ -92,7 +92,7 @@ bool phantom_base::save() const
// blood volume fraction
std::vector<size_t> dims_1(1, 1);
HighFive::DataSet dataset_BVF = file.createDataSet<float>("bvf", HighFive::DataSpace(dims_1));
dataset_BVF.write_raw(&m_BVF);
dataset_BVF.write_raw(&m_volume_fraction);

return true;
}
Expand Down
9 changes: 5 additions & 4 deletions src/phantom/phantom_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ class phantom_base
{
public:
phantom_base();
phantom_base(float fov_um, size_t resolution, float dChi, float Y, float BVF, int32_t seed, std::string filename);
phantom_base(float fov_um, size_t resolution, float dChi, float Y, float volume_fraction, int32_t seed, std::string filename);
virtual ~phantom_base();
void set_space(float fov_um, size_t resolution);
void set_blood_parameters(float dChi, float Y, float BVF = 10.0);
void set_parameters(float dChi, float Y, float volume_fraction = 10.0);
void set_filename(std::string filename = "shape.h5");
virtual bool run(){return true;};
virtual bool run(bool write_to_disk) = 0;
virtual bool save() const;
virtual bool create_grid();
virtual bool generate_shapes() = 0;
virtual bool generate_mask_fieldmap() = 0;
float get_actual_volume_fraction() const {return m_volume_fraction;}

friend std::ostream& operator<<(std::ostream& os, const phantom_base& obj);

Expand All @@ -44,7 +45,7 @@ class phantom_base
std::vector<int8_t> m_mask;
size_t m_resolution;
float m_fov, m_dChi, m_Y;
float m_BVF; // blood volume fraction
float m_volume_fraction; // volume fraction
std::string m_filename;
float B0[3] = {0.f, 0.f, 1.f};
bool m_calc_fieldmap;
Expand Down
Loading

0 comments on commit cc5cdd9

Please sign in to comment.