From 1ea0cfa5f6d3fe5bcd16567f71b376331fbeaa49 Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Thu, 20 Jul 2023 11:23:58 +0100 Subject: [PATCH 1/3] add OSSPS set_relaxation_gamma --- doc/UserGuide.md | 1 + src/xSTIR/cSTIR/cstir_p.cpp | 2 ++ src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h | 3 +++ src/xSTIR/pSTIR/STIR.py | 5 +++++ 4 files changed, 11 insertions(+) diff --git a/doc/UserGuide.md b/doc/UserGuide.md index 6891575fc..c0fdee4b9 100644 --- a/doc/UserGuide.md +++ b/doc/UserGuide.md @@ -520,6 +520,7 @@ Class for reconstructor objects using Ordered Subsets Separable Paraboloidal Sur OSSPSReconstructor Constructor. Creates new OSSPS reconstructor object. set_relaxation_parameter Sets relaxation parameter. + set_relaxation_gamma Sets relaxation gamma parameter. ##### FullySampledReconstructor (MR) diff --git a/src/xSTIR/cSTIR/cstir_p.cpp b/src/xSTIR/cSTIR/cstir_p.cpp index 2e6ceec68..f7d3cfcea 100644 --- a/src/xSTIR/cSTIR/cstir_p.cpp +++ b/src/xSTIR/cSTIR/cstir_p.cpp @@ -1139,6 +1139,8 @@ sirf::cSTIR_setOSSPSParameter(DataHandle* hp, const char* name, const DataHandle objectFromHandle(hp); if (sirf::iequals(name, "relaxation_parameter")) recon.relaxation_parameter_value() = dataFromHandle(hv); + else if (sirf::iequals(name, "relaxation_gamma")) + recon.relaxation_gamma_value() = dataFromHandle(hv); else return parameterNotFound(name, __FILE__, __LINE__); return new DataHandle; diff --git a/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h b/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h index 1ae732545..61bb16603 100644 --- a/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h +++ b/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h @@ -1140,6 +1140,9 @@ The actual algorithm is described in float& relaxation_parameter_value() { return relaxation_parameter; } + float& relaxation_gamma_value() { + return relaxation_gamma; + } }; class xSTIR_FBP2DReconstruction : public stir::FBP2DReconstruction { diff --git a/src/xSTIR/pSTIR/STIR.py b/src/xSTIR/pSTIR/STIR.py index b62823a96..a7e3365c5 100644 --- a/src/xSTIR/pSTIR/STIR.py +++ b/src/xSTIR/pSTIR/STIR.py @@ -3456,6 +3456,11 @@ def set_relaxation_parameter(self, value): parms.set_float_par( self.handle, self.name, 'relaxation_parameter', value) + def set_relaxation_gamma(self, value): + """Sets relaxation gamma parameter.""" + parms.set_float_par( + self.handle, self.name, 'relaxation_gamma', value) + def make_Poisson_loglikelihood(acq_data, likelihood_type='LinearModelForMean', acq_model=None): From 9095bd3470739c7841f1dfaeca5c532cc2ccae21 Mon Sep 17 00:00:00 2001 From: Evgueni Ovtchinnikov Date: Thu, 20 Jul 2023 15:47:26 +0000 Subject: [PATCH 2/3] added set/get methods for OSSPSReconstructor parameters --- src/xSTIR/cSTIR/cstir_p.cpp | 8 ++++++++ src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h | 3 +++ src/xSTIR/pSTIR/STIR.py | 17 +++++++++++++++++ src/xSTIR/pSTIR/STIR_params.py | 15 +++++++++++++++ src/xSTIR/pSTIR/tests/tests_three.py | 6 ++++++ 5 files changed, 49 insertions(+) diff --git a/src/xSTIR/cSTIR/cstir_p.cpp b/src/xSTIR/cSTIR/cstir_p.cpp index f7d3cfcea..c5e72cf1d 100644 --- a/src/xSTIR/cSTIR/cstir_p.cpp +++ b/src/xSTIR/cSTIR/cstir_p.cpp @@ -1141,6 +1141,8 @@ sirf::cSTIR_setOSSPSParameter(DataHandle* hp, const char* name, const DataHandle recon.relaxation_parameter_value() = dataFromHandle(hv); else if (sirf::iequals(name, "relaxation_gamma")) recon.relaxation_gamma_value() = dataFromHandle(hv); + else if (sirf::iequals(name, "upper_bound")) + recon.upper_bound_value() = dataFromHandle(hv); else return parameterNotFound(name, __FILE__, __LINE__); return new DataHandle; @@ -1151,6 +1153,12 @@ sirf::cSTIR_OSSPSParameter(const DataHandle* handle, const char* name) { xSTIR_OSSPSReconstruction3DF& recon = objectFromHandle(handle); + if (sirf::iequals(name, "relaxation_parameter")) + return dataHandle(recon.relaxation_parameter_value()); + else if (sirf::iequals(name, "relaxation_gamma")) + return dataHandle(recon.relaxation_gamma_value()); + else if (sirf::iequals(name, "upper_bound")) + return dataHandle(recon.upper_bound_value()); return parameterNotFound(name, __FILE__, __LINE__); } diff --git a/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h b/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h index 61bb16603..c46d241d4 100644 --- a/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h +++ b/src/xSTIR/cSTIR/include/sirf/STIR/stir_x.h @@ -1143,6 +1143,9 @@ The actual algorithm is described in float& relaxation_gamma_value() { return relaxation_gamma; } + double& upper_bound_value() { + return upper_bound; + } }; class xSTIR_FBP2DReconstruction : public stir::FBP2DReconstruction { diff --git a/src/xSTIR/pSTIR/STIR.py b/src/xSTIR/pSTIR/STIR.py index a7e3365c5..8d853596a 100644 --- a/src/xSTIR/pSTIR/STIR.py +++ b/src/xSTIR/pSTIR/STIR.py @@ -3461,6 +3461,23 @@ def set_relaxation_gamma(self, value): parms.set_float_par( self.handle, self.name, 'relaxation_gamma', value) + def set_upper_bound(self, value): + """Sets upper bound parameter.""" + parms.set_double_par( + self.handle, self.name, 'upper_bound', value) + + def get_relaxation_parameter(self): + """Returns relaxation parameter value.""" + return parms.float_par(self.handle, self.name, 'relaxation_parameter') + + def get_relaxation_gamma(self): + """Returns relaxation gamma value.""" + return parms.float_par(self.handle, self.name, 'relaxation_gamma') + + def get_upper_bound(self): + """Returns upper bound value.""" + return parms.double_par(self.handle, self.name, 'upper_bound') + def make_Poisson_loglikelihood(acq_data, likelihood_type='LinearModelForMean', acq_model=None): diff --git a/src/xSTIR/pSTIR/STIR_params.py b/src/xSTIR/pSTIR/STIR_params.py index ce2d35614..3731e3e77 100644 --- a/src/xSTIR/pSTIR/STIR_params.py +++ b/src/xSTIR/pSTIR/STIR_params.py @@ -56,12 +56,19 @@ def set_bool_par(handle, group, par, value): set_parameter(handle, group, par, h, inspect.stack()[1]) pyiutil.deleteDataHandle(h) + def set_float_par(handle, group, par, value): h = pyiutil.floatDataHandle(float(value)) set_parameter(handle, group, par, h, inspect.stack()[1]) pyiutil.deleteDataHandle(h) +def set_double_par(handle, group, par, value): + h = pyiutil.doubleDataHandle(float(value)) + set_parameter(handle, group, par, h, inspect.stack()[1]) + pyiutil.deleteDataHandle(h) + + def bool_par(handle, group, par): h = parameter(handle, group, par) check_status(h, inspect.stack()[1]) @@ -144,6 +151,14 @@ def float_pars(handle, group, par, n): return value +def double_par(handle, group, par): + h = parameter(handle, group, par) + check_status(h) + v = pyiutil.doubleDataFromHandle(h) + pyiutil.deleteDataHandle(h) + return v + + def parameter_handle(hs, group, par): handle = parameter(hs, group, par) check_status(handle, inspect.stack()[1]) diff --git a/src/xSTIR/pSTIR/tests/tests_three.py b/src/xSTIR/pSTIR/tests/tests_three.py index 4f1298d3b..6fbcfc7ad 100644 --- a/src/xSTIR/pSTIR/tests/tests_three.py +++ b/src/xSTIR/pSTIR/tests/tests_three.py @@ -46,6 +46,12 @@ def test_main(rec=False, verb=False, throw=True): recon.set_num_subiterations(2) recon.set_objective_function(obj_fun) recon.set_input(acq_data) + recon.set_relaxation_parameter(2) + recon.set_relaxation_gamma(.3) + recon.set_upper_bound(4e5) + test.check_if_equal_within_tolerance(2, recon.get_relaxation_parameter(), rel_tol=1e-5) + test.check_if_equal_within_tolerance(.3, recon.get_relaxation_gamma(), rel_tol=1e-5) + test.check_if_equal_within_tolerance(4e5, recon.get_upper_bound(), rel_tol=1e-5) if verb: print('setting up, please wait...') recon.set_up(image_data) From 839892546f2d382cebce4860bffb2a119323b9c5 Mon Sep 17 00:00:00 2001 From: Evgueni Ovtchinnikov Date: Wed, 6 Dec 2023 16:40:07 +0000 Subject: [PATCH 3/3] updated CHANGES.md [ci skip] --- CHANGES.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0a1f7227b..f65d44892 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,30 @@ # ChangeLog +## v3.6.0 + +* PET: + - added extra members to ScatterEstimation to set behaviour of OSEM used during scatter estimation + - added test for scatter simulation and estimation + - added missing `set`/`get` methods for OSSPS `relaxation_parameter`, `relaxation_gamma` and `upper_bound`. + +* CMake/building: + - default `DISABLE_MATLAB` to `ON` as our Matlab support is out-of-date and could + generate conflicts with Python shared libraries. + +* Demo scripts: + - replaced importing reconstruction engines by +``` + exec('from sirf.' + args['--engine'] + ' import *') +``` + with importing via `importlib.import_module` thus getting rid of Codacy complaints about undefined modules. + +* Python interfaces for the reconstruction engines: + - Several allocate methods in STIR.py, Gadgetron.py and Reg.py are replaced with just one allocate in DataContainer class that does not copy data between Python and C++. + - `return None` in the method `Datacontainer.shape()` replaced with more Pythonesque `return (0,)`. + +* MR + - Handling of "irregular" ISMRMRD acquisitions hit what appears to be a bug in recent Gadgetron (HEAD detached at 0670db84). A quick fix applied, Gadgetron issue to be raised. + ## v3.5.0 * GitHub Action: remove temporarily the Ubuntu 20.04 build, #1178