Skip to content

Commit

Permalink
Provide C++ tools for accessing examples data (#1166)
Browse files Browse the repository at this point in the history
* started working on #1163

* [ci skip] made STIR version string available in Python

* added path handling utilities in SIRF/common

* moved misplaced file utilities.cpp to SIRF/common

* added C++ implementation of examples_data_path(), fixes #919

* copied version.h to SIRF/src/common as a quick fix for build errors

* replaced quick version.h fix with a proper one

* cast NULL to const char* in append_path calls for safety

* added missing casts of NULL to const char*

* reverted attempted fix in src/common/CMakeLists.txt

* replaced hard coded paths in test4.cpp with those provided by new tools

* removed unused fix_path_separator and append_path

* re-applied quick version.h fix

* tested calling STIR's get_STIR_*_dir() functions from a SIRF C++ test

* added interfaces to get_STIR_*_dir() to STIR.py

* [ci skip] updated CHANGES.md

* fix include path for finding version.h and getenv.h

* add C++ test on get_STIR_examples_dir

* rewrote append_path using variadic templates and clean-up

Using va_args etc is not recommended anymore. The replacement is type-safe.

Also added some doxygen and removed some obsolete declarations.

* replaced Python implementation of examples_data_path with wrapped C++ one

---------

Co-authored-by: Kris Thielemans <[email protected]>
  • Loading branch information
evgueni-ovtchinnikov and KrisThielemans authored May 16, 2023
1 parent e6e69b4 commit 8ea4cac
Show file tree
Hide file tree
Showing 20 changed files with 273 additions and 69 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
- Added setter for acquisition header information and encoding limits. This allows the user to modify the reconstructed k-space dimensions and enables e.g. retrospective motion
resolved or time-resolved reconstructions, or combinations of such dimensions. The acquisition model picks up these changes automatically if the encoding limits are set correctly.

* PET/SPECT
- Added SIRF interfaces to STIR functions to know where its files are: `get_STIR_doc_dir()` and `get_STIR_examples_dir()`.

## v3.4.0

* MR:
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ ENABLE_TESTING()
# create location of SHARE_DIR to be used when creating Shepp Logan phantom during build
set(SHARE_DIR ${CMAKE_INSTALL_PREFIX}/share/SIRF-${VERSION_MAJOR}.${VERSION_MINOR})

configure_file("cmake/version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake/include/sirf/common/version.h")
set(BUILD_INCLUDE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake/include)
configure_file("cmake/version.h.in" "${BUILD_INCLUDE_DIRECTORY}/sirf/common/version.h")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/include/sirf/common/version.h" DESTINATION "${CMAKE_INSTALL_PREFIX}/include/sirf/common/")

if (CMAKE_VERSION VERSION_LESS 3.21.0)
Expand Down
2 changes: 1 addition & 1 deletion data
Submodule data updated from 5bd102 to ef407f
6 changes: 6 additions & 0 deletions examples/Python/PET/acquisition_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#exec('from sirf.' + args['--engine'] + ' import *')
pet_engine = 'sirf.' + args['--engine']
for obj in ['error', 'examples_data_path', 'existing_filepath', \
'get_STIR_version_string', \
'get_STIR_doc_dir', 'get_STIR_examples_dir', \
'AcquisitionData', 'MessageRedirector']:
exec('from ' + pet_engine + ' import ' + obj)

Expand Down Expand Up @@ -70,6 +72,10 @@


def main():
STIR_version = get_STIR_version_string()
print('Using STIR version %s' % STIR_version)
print('STIR doc path: %s' % get_STIR_doc_dir())
print('STIR examples path: %s' % get_STIR_examples_dir())

# direct all engine's messages to files
msg_red = MessageRedirector('info.txt', 'warn.txt', 'errr.txt')
Expand Down
6 changes: 5 additions & 1 deletion src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ set(CMAKE_POSITION_INDEPENDENT_CODE True)

set(cSIRF_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")

add_library(csirf csirf.cpp ImageData.cpp GeometricalInfo.cpp iequals.cpp)
add_library(csirf csirf.cpp ImageData.cpp GeometricalInfo.cpp iequals.cpp utilities.cpp)
target_include_directories(csirf PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>$<INSTALL_INTERFACE:include>"
)
target_include_directories(csirf PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>$<INSTALL_INTERFACE:include>"
)
target_include_directories(csirf PUBLIC
"$<BUILD_INTERFACE:${BUILD_INCLUDE_DIRECTORY}>$<INSTALL_INTERFACE:include>"
)

if ((NOT DISABLE_STIR) AND (NOT DISABLE_Gadgetron) AND (NOT DISABLE_Registration) AND "${STIR_BUILT_WITH_ITK}")
MESSAGE(STATUS "Registration, ISMRMRD and STIR (with ITK) have been built.")
target_link_libraries(csirf PUBLIC iutilities csyn)
Expand Down
20 changes: 6 additions & 14 deletions src/common/Utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os
import sirf
import sirf.pyiutilities as pyiutil
import sirf.pysirf as pysirf
import re
from deprecation import deprecated

Expand Down Expand Up @@ -70,20 +71,11 @@ def examples_data_path(data_type):
Returns the path to PET/MR/Registration data used by SIRF/examples demos.
data_type: either 'PET' or 'MR' or 'Registration'
'''
data_path = os.path.join('share', 'SIRF-{}.{}'.format(sirf.__version_major__, sirf.__version_minor__),
'data', 'examples', data_type)
SIRF_INSTALL_PATH = os.environ.get('SIRF_INSTALL_PATH')
SIRF_DATA_PATH = os.environ.get('SIRF_DATA_PATH')
SIRF_PATH = os.environ.get('SIRF_PATH')
if SIRF_DATA_PATH is not None:
return os.path.join(SIRF_DATA_PATH , 'examples', data_type)
elif SIRF_INSTALL_PATH is not None:
return os.path.join(SIRF_INSTALL_PATH , data_path)
elif SIRF_PATH is not None:
return os.path.join(SIRF_PATH, 'data', 'examples', data_type)
else:
errorMsg = 'You need to set the SIRF_DATA_PATH or SIRF_INSTALL_PATH environment variable to allow finding the raw data.'
raise ValueError(errorMsg)
h = pysirf.cSIRF_examples_data_path(data_type)
check_status(h)
path = pyiutil.charDataFromHandle(h)
pyiutil.deleteDataHandle(h)
return path


def existing_filepath(data_path, file_name):
Expand Down
9 changes: 8 additions & 1 deletion src/common/csirf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ limitations under the License.

#include "sirf/iUtilities/DataHandle.h"
#include "sirf/common/DataContainer.h"
#include "sirf/common/deprecate.h"
#include "sirf/common/iequals.h"
#include "sirf/common/ImageData.h"
#include "sirf/common/utilities.h"
#include "sirf/Syn/utilities.h"
#include "sirf/common/deprecate.h"

using namespace sirf;

Expand Down Expand Up @@ -61,6 +62,12 @@ void* cSIRF_newObject(const char* name)
CATCH;
}

extern "C"
void*
cSIRF_examples_data_path(const char* data_type)
{
return charDataHandleFromCharData(examples_data_path(data_type).c_str());
}

extern "C"
void*
Expand Down
8 changes: 0 additions & 8 deletions src/common/iequals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,5 @@ namespace sirf {
return false;
return true;
}
void fix_path_separator(std::string& path)
{
#ifdef _WIN32
for (int i = 0; i < path.size(); i++)
if (path[i] == '\\')
path[i] = '/';
#endif
}
}

3 changes: 3 additions & 0 deletions src/common/include/sirf/common/csirf.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ extern "C" {
// New SIRF objects
void* cSIRF_newObject(const char* name);

// path to the examples data folder
void* cSIRF_examples_data_path(const char* data_type);

// Data container methods
void* cSIRF_dataItems(const void* ptr_x);
void* cSIRF_isComplex(const void* ptr_x);
Expand Down
4 changes: 2 additions & 2 deletions src/common/include/sirf/common/getenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "sirf/iUtilities/LocalisedException.h"

namespace sirf {
std::string getenv(const char* name, bool throws=false)
inline std::string getenv(const char* name, bool throws=false)
{
const char* value = std::getenv(name);
std::string s;
Expand All @@ -18,4 +18,4 @@ namespace sirf {
}
}

#endif
#endif
5 changes: 2 additions & 3 deletions src/common/include/sirf/common/iequals.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/*!
\file
\ingroup Common
\brief Case insensitive string comparison sirf::iequals.
\brief Defines sirf::iequals.
\author Evgueni Ovtchinnikov
\author SyneRBI
Expand All @@ -20,7 +20,6 @@ namespace sirf {
\brief Case insensitive string comparison, replaces boost::iequals.
*/
bool iequals(const std::string& a, const std::string& b);
void fix_path_separator(std::string& path);
}

#endif
#endif
76 changes: 76 additions & 0 deletions src/common/include/sirf/common/utilities.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
SyneRBI Synergistic Image Reconstruction Framework (SIRF)
Copyright 2023 Rutherford Appleton Laboratory STFC
Copyright 2023 University College London
This is software developed for the Collaborative Computational
Project in Synergistic Reconstruction for Biomedical Imaging (formerly CCP PETMR)
(http://www.ccpsynerbi.ac.uk/).
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*!
\file
\ingroup Common
\author Evgueni Ovtchinnikov
\author Kris Thielemans
*/
#ifndef SIRF_UTILITIES
#define SIRF_UTILITIES

#include <string>

namespace sirf {
//! return the path-separator used by the OS
/*!
\ingroup Common
Usually this will return a forward-slash, but it could be a backslash on Windows.
*/
char path_separator();
///@{
//! concatenate path strings
/*!
\ingroup Common
\par Example:
\code
std::string filename = "somefile.txt";
std:string full_path = append_path("/usr/local", "share", filename);
\endcode
\par warning
The code does not check if there are already trailing path-separators,
nor if the resulting path exists.
*/
template <typename T>
std::string append_path(std::string path, T a)
{
return path + path_separator() + std::string(a);
}
template <typename T, typename... Ts>
std::string append_path(std::string path, T a, Ts... args)
{
return append_path(append_path(path, a), args...);
}
///@{
//! Returns where the examples are installed
/*!
\ingroup Common
\par Example:
\code
std::string p = examples_data_path("PET");
\endcode
*/
std::string examples_data_path(const char* data_type);
}

#endif
60 changes: 60 additions & 0 deletions src/common/utilities.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
SyneRBI Synergistic Image Reconstruction Framework (SIRF)
Copyright 2023 Rutherford Appleton Laboratory STFC
Copyright 2023 University College London
This is software developed for the Collaborative Computational
Project in Synergistic Reconstruction for Biomedical Imaging (formerly CCP PETMR)
(http://www.ccpsynerbi.ac.uk/).
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*!
\file
\ingroup Common
\author Evgueni Ovtchinnikov
\author Kris Thielemans
*/
#include "sirf/common/utilities.h"
#include "sirf/common/version.h"
#include "sirf/common/getenv.h"
#include <sstream>

namespace sirf {
char path_separator()
{
std::string filename = __FILE__;
auto found = filename.find_last_of("/\\");
if (found == std::string::npos)
return '/';
return filename[found];
}

std::string examples_data_path(const char* data_type)
{
std::string SIRF_data_path = sirf::getenv("SIRF_DATA_PATH");
if (SIRF_data_path.length() > 0)
return append_path(SIRF_data_path, "examples", data_type);
std::string SIRF_install_path = sirf::getenv("SIRF_INSTALL_PATH");
if (SIRF_install_path.length() > 0) {
std::stringstream sirf_version;
sirf_version << "SIRF-" << SIRF_VERSION_MAJOR << '.' << SIRF_VERSION_MINOR;
return append_path(SIRF_install_path, "share", sirf_version.str(), "data", "examples", data_type);
}
std::string SIRF_path = sirf::getenv("SIRF_PATH");
if (SIRF_path.length() > 0)
return append_path(SIRF_path, "data", "examples", data_type);
return "";
}
}
27 changes: 27 additions & 0 deletions src/xSTIR/cSTIR/cstir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ limitations under the License.
#include "sirf/STIR/stir_types.h"
#include "sirf/iUtilities/DataHandle.h"
#include "sirf/STIR/cstir_p.h"
#include "stir/find_STIR_config.h"
#include "sirf/STIR/stir_x.h"
#include "stir/config.h"
#include "stir/ImagingModality.h"
#include "stir/Scanner.h"
#include "stir/Verbosity.h"
Expand All @@ -52,6 +54,31 @@ unknownObject(const char* obj, const char* name, const char* file, int line)
return (void*)handle;
}

extern "C"
void*
cSTIR_STIR_version_string()
{
#if defined(STIR_VERSION_STRING)
return charDataHandleFromCharData(STIR_VERSION_STRING);
#else
return charDataHandleFromCharData("unknown");
#endif
}

extern "C"
void*
cSTIR_get_STIR_doc_dir()
{
return charDataHandleFromCharData(get_STIR_doc_dir().c_str());
}

extern "C"
void*
cSTIR_get_STIR_examples_dir()
{
return charDataHandleFromCharData(get_STIR_examples_dir().c_str());
}

template<class Method>
void*
cSTIR_newReconstructionMethod(const char* par_file)
Expand Down
5 changes: 4 additions & 1 deletion src/xSTIR/cSTIR/include/sirf/STIR/cstir.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ extern "C" {
//void* parameter(const void* ptr, const char* obj, const char* name);

// Global
void* cSTIR_setVerbosity(const int verbosity_ptr);
void* cSTIR_STIR_version_string();
void* cSTIR_get_STIR_doc_dir();
void* cSTIR_get_STIR_examples_dir();
void* cSTIR_setVerbosity(const int verbosity_ptr);
void* cSTIR_getVerbosity();
void* cSTIR_setOMPThreads(const int threads);
void* cSTIR_getOMPThreads();
Expand Down
5 changes: 0 additions & 5 deletions src/xSTIR/cSTIR/tests/getenv.h

This file was deleted.

Loading

0 comments on commit 8ea4cac

Please sign in to comment.