STIR 6.5.0
RunTests.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2000 PARAPET partners
3 Copyright (C) 2000-2005, Hammersmith Imanet Ltd
4 Copyright (C) 2013, Kris Thielemans
5 Copyright (C) 2013, 2020, 2022, 2023, 2024 University College London
6 Copyright (C) 2018, University of Hull
7 This file is part of STIR.
8
9 SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
10
11 See STIR/LICENSE.txt for details
12*/
23
26#include "stir/IndexRange.h"
27#include "stir/stream.h"
28#include "stir/Bin.h"
32#include "stir/LORCoordinates.h"
33#include <iostream>
34#include <typeinfo>
35#include <vector>
36#include <complex>
37#include <string>
38
39START_NAMESPACE_STIR
40
74{
75public:
77 explicit RunTests(const double tolerance = 1E-4);
78
80 virtual ~RunTests();
81
83
84 virtual void run_tests() = 0;
85
87 bool is_everything_ok() const;
88
90
91 int main_return_value() const;
92
94 void set_tolerance(const double tolerance);
95
97 double get_tolerance() const;
98
100
104 bool check(const bool, const std::string& str = "");
105
111 bool check_if_equal(const std::string& a, const std::string& b, const std::string& str = "");
112 bool check_if_equal(const double a, const double b, const std::string& str = "");
113 // Note: due to current C++ overloading rules, we need copies for every integer type
114 bool check_if_equal(const short a, const short b, const std::string& str = "");
115 bool check_if_equal(const unsigned short a, const unsigned short b, const std::string& str = "");
116 bool check_if_equal(const int a, const int b, const std::string& str = "");
117 bool check_if_equal(const unsigned int a, const unsigned int b, const std::string& str = "");
118 bool check_if_equal(const long a, const long b, const std::string& str = "");
119 bool check_if_equal(const unsigned long a, const unsigned long b, const std::string& str = "");
120#ifdef BOOST_HAS_LONG_LONG
121 // necessary to cope with std::size_t for instance (on 64 bit systems)
122 bool check_if_equal(const long long a, const long long b, const std::string& str = "");
123 bool check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str = "");
124#endif
125 bool check_if_equal(const Bin& a, const Bin& b, const std::string& str = "")
126 {
127 return this->check_if_equal_generic(a, b, str);
128 }
129 template <class T>
130 bool check_if_equal(const DetectionPosition<T>& a, const DetectionPosition<T>& b, const std::string& str = "")
131 {
132 return this->check_if_equal_generic(a, b, str);
133 }
134 template <class T>
135 bool check_if_equal(const DetectionPositionPair<T>& a, const DetectionPositionPair<T>& b, const std::string& str = "")
136 {
137 return this->check_if_equal_generic(a, b, str);
138 }
139 template <class T>
140 bool check_if_equal(const LORInAxialAndNoArcCorrSinogramCoordinates<T>& a,
141 const LORInAxialAndNoArcCorrSinogramCoordinates<T>& b,
142 const std::string& str = "");
143
144 // VC 6.0 needs definition of template members in the class def unfortunately.
146 template <class T>
147 bool check_if_equal(const std::complex<T> a, const std::complex<T> b, const std::string& str = "")
148 {
149 return check_if_equal(a.real(), b.real(), str) && check_if_equal(a.imag(), b.imag(), str);
150 }
151
152 template <class T>
153 bool check_if_equal(const VectorWithOffset<T>& t1, const VectorWithOffset<T>& t2, const std::string& str = "")
154 {
155 if (t1.get_min_index() != t2.get_min_index() || t1.get_max_index() != t2.get_max_index())
156 {
157 std::cerr << "Error: unequal ranges. " << str << std::endl;
158 return everything_ok = false;
159 }
160
161 for (int i = t1.get_min_index(); i <= t1.get_max_index(); i++)
162 {
163 if (!check_if_equal(t1[i], t2[i], str))
164 {
165 std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n";
166 return everything_ok = false;
167 }
168 }
169 return true;
170 }
171 // VC 6.0 needs definition of template members in the class def unfortunately.
173 template <class T>
174 bool check_if_equal(const std::vector<T>& t1, const std::vector<T>& t2, const std::string& str = "")
175 {
176 if (t1.size() != t2.size())
177 {
178 std::cerr << "Error: unequal ranges. " << str << std::endl;
179 return everything_ok = false;
180 }
181
182 bool all_equal = true;
183 for (unsigned int i = 0; i < t1.size(); i++)
184 {
185 if (!check_if_equal(t1[i], t2[i], str))
186 {
187 std::cerr << "(at vector<" << typeid(T).name() << "> mismatch at index " << i << ")\n";
188 all_equal = false;
189 }
190 }
191 return all_equal;
192 }
193
194 bool check_if_equal(const ProjDataInMemory& t1, const ProjDataInMemory& t2, const std::string& str = "");
195
196 // VC 6.0 needs definition of template members in the class def unfortunately.
197 template <int n>
198 bool check_if_equal(const IndexRange<n>& t1, const IndexRange<n>& t2, const std::string& str = "")
199 {
200 if (t1 != t2)
201 {
202 std::cerr << "Error: unequal ranges. " << str << std::endl;
203 return everything_ok = false;
204 }
205 else
206 return true;
207 }
209 template <int num_dimensions, class coordT>
212 const std::string& str = "")
213 {
214 if (norm(a - b) > tolerance)
215 {
216 std::cerr << "Error : Unequal Coordinate value are " << a << " and " << b << ". " << str << std::endl;
217 everything_ok = false;
218 return false;
219 }
220 else
221 return true;
222 }
223
224
230 bool check_if_zero(const double a, const std::string& str = "");
231 bool check_if_zero(const short a, const std::string& str = "");
232 bool check_if_zero(const unsigned short a, const std::string& str = "");
233 bool check_if_zero(const int a, const std::string& str = "");
234 bool check_if_zero(const unsigned int a, const std::string& str = "");
235 bool check_if_zero(const long a, const std::string& str = "");
236 bool check_if_zero(const unsigned long a, const std::string& str = "");
237#ifdef BOOST_HAS_LONG_LONG
238 bool check_if_zero(const long long a, const std::string& str = "");
239 bool check_if_zero(const unsigned long long a, const std::string& str = "");
240#endif
241
242 // VC needs definition of template members in the class def unfortunately.
244 template <class T>
245 bool check_if_zero(const VectorWithOffset<T>& t, const std::string& str = "")
246 {
247 for (int i = t.get_min_index(); i <= t.get_max_index(); i++)
248 {
249 if (!check_if_zero(t[i], str))
250 {
251 std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n";
252 return false;
253 }
254 }
255 return true;
256 }
257
259 template <int num_dimensions, class coordT>
260 bool check_if_zero(const BasicCoordinate<num_dimensions, coordT>& a, const std::string& str = "")
261 {
262 if (norm(a) > tolerance)
263 {
264 std::cerr << "Error : Coordinate value is " << a << " expected 0s. " << str << std::endl;
265 everything_ok = false;
266 return false;
267 }
268 else
269 return true;
270 }
271
272
274 template <class T1, class T2>
275 inline bool check_if_less(T1 a, T2 b, const std::string& str = "");
276
277protected:
279 double tolerance;
282
284 template <class T>
285 bool check_if_equal_generic(const T& a, const T& b, const std::string& str)
286 {
287 if (a != b)
288 {
289 std::cerr << "Error : unequal values are \n\t" << a << "\n\tand\n\t" << b << "\n\t" << str << std::endl;
290 everything_ok = false;
291 return false;
292 }
293 else
294 return true;
295 }
296
298 template <class T>
299 bool check_if_zero_generic(T a, const std::string& str)
300 {
301 if ((a != static_cast<T>(0)))
302 {
303 std::cerr << "Error : 0 value is " << a << " ." << str << std::endl;
304 everything_ok = false;
305 return false;
306 }
307 else
308 return true;
309 }
310};
311
312END_NAMESPACE_STIR
313
314START_NAMESPACE_STIR
315
318 everything_ok(true)
319{}
320
322{
323#if defined(_DEBUG) && defined(__MSL__)
324 DebugNewReportLeaks();
325#endif
326
327 if (everything_ok)
328 std::cerr << "\nAll tests ok !\n\n" << std::endl;
329 else
330 std::cerr << "\nEnd of tests. Please correct errors !\n\n" << std::endl;
331}
332
333bool
335{
336 return everything_ok;
337}
338
339int
341{
342 return everything_ok ? EXIT_SUCCESS : EXIT_FAILURE;
343}
344
345void
346RunTests::set_tolerance(const double tolerance_v)
347{
348 tolerance = tolerance_v;
349}
350
351double
353{
354 return tolerance;
355}
356
357bool
358RunTests::check(const bool result, const std::string& str)
359{
360 if (!result)
361 {
362 std::cerr << "Error. " << str << std::endl;
363 everything_ok = false;
364 }
365 return result;
366}
367
368bool
369RunTests::check_if_equal(const std::string& a, const std::string& b, const std::string& str)
370{
371 return this->check_if_equal_generic(a, b, str);
372}
373
388bool
389RunTests::check_if_equal(const double a, const double b, const std::string& str)
390{
391 const double diff = fabs(b - a);
392 if (diff <= tolerance)
393 return true;
394
395 const double largest = (std::max(fabs(b), fabs(a)));
396
397 if (diff > tolerance * largest)
398 {
399 std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl;
400 everything_ok = false;
401 return false;
402 }
403 else
404 return true;
405}
406
407bool
408RunTests::check_if_equal(const short a, const short b, const std::string& str)
409{
410 return this->check_if_equal_generic(a, b, str);
411}
412bool
413RunTests::check_if_equal(const unsigned short a, const unsigned short b, const std::string& str)
414{
415 return this->check_if_equal_generic(a, b, str);
416}
417bool
418RunTests::check_if_equal(const int a, const int b, const std::string& str)
419{
420 return this->check_if_equal_generic(a, b, str);
421}
422bool
423RunTests::check_if_equal(const unsigned int a, const unsigned int b, const std::string& str)
424{
425 return this->check_if_equal_generic(a, b, str);
426}
427bool
428RunTests::check_if_equal(const long a, const long b, const std::string& str)
429{
430 return this->check_if_equal_generic(a, b, str);
431}
432bool
433RunTests::check_if_equal(const unsigned long a, const unsigned long b, const std::string& str)
434{
435 return this->check_if_equal_generic(a, b, str);
436}
437#ifdef BOOST_HAS_LONG_LONG
438bool
439RunTests::check_if_equal(const long long a, const long long b, const std::string& str)
440{
441 return this->check_if_equal_generic(a, b, str);
442}
443bool
444RunTests::check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str)
445{
446 return this->check_if_equal_generic(a, b, str);
447}
448#endif
449
450template <class T>
451bool
452RunTests::check_if_equal(const LORInAxialAndNoArcCorrSinogramCoordinates<T>& a,
454 const std::string& str)
455{
456 bool ok = this->check_if_equal(a.radius(), b.radius(), str + ": radius") && this->check_if_equal(a.z1(), b.z1(), str + ": z1")
457 && this->check_if_equal(a.z2(), b.z2(), str + ": z2") && this->check_if_equal(a.beta(), b.beta(), str + ": beta")
458 && this->check_if_equal(a.phi(), b.phi(), str + ": phi")
459 && this->check_if_equal(a.is_swapped(), b.is_swapped(), str + ": is_swapped");
460 if (!ok)
461 std::cerr << "\t(comparing " << a << " and " << b << ")\n";
462 return ok;
463}
464
465bool
466RunTests::check_if_equal(const ProjDataInMemory& t1, const ProjDataInMemory& t2, const std::string& str)
467{
468 if (*t1.get_proj_data_info_sptr() != *t2.get_proj_data_info_sptr())
469 {
470 std::cerr << "Error: unequal proj_data_info. " << str << std::endl;
471 return everything_ok = false;
472 }
473
474 for (auto i1 = t1.begin(), i2 = t2.begin(); i1 != t1.end(); ++i1, ++i2)
475 {
476 if (!check_if_equal(*i1, *i2, str))
477 {
478 return everything_ok = false;
479 }
480 }
481 return true;
482}
483
484bool
485RunTests::check_if_zero(const short a, const std::string& str)
486{
487 return this->check_if_zero_generic(a, str);
488}
489bool
490RunTests::check_if_zero(const unsigned short a, const std::string& str)
491{
492 return this->check_if_zero_generic(a, str);
493}
494bool
495RunTests::check_if_zero(const int a, const std::string& str)
496{
497 return this->check_if_zero_generic(a, str);
498}
499bool
500RunTests::check_if_zero(const unsigned int a, const std::string& str)
501{
502 return this->check_if_zero_generic(a, str);
503}
504bool
505RunTests::check_if_zero(const long a, const std::string& str)
506{
507 return this->check_if_zero_generic(a, str);
508}
509bool
510RunTests::check_if_zero(const unsigned long a, const std::string& str)
511{
512 return this->check_if_zero_generic(a, str);
513}
514#ifdef BOOST_HAS_LONG_LONG
515bool
516RunTests::check_if_zero(const long long a, const std::string& str)
517{
518 return this->check_if_zero_generic(a, str);
519}
520bool
521RunTests::check_if_zero(const unsigned long long a, const std::string& str)
522{
523 return this->check_if_zero_generic(a, str);
524}
525#endif
526
528bool
529RunTests::check_if_zero(const double a, const std::string& str)
530{
531 if (fabs(a) > tolerance)
532 {
533 std::cerr << "Error : 0 value is " << a << " ." << str << std::endl;
534 everything_ok = false;
535 return false;
536 }
537 else
538 return true;
539}
540
541template <class T1, class T2>
542bool
543RunTests::check_if_less(T1 a, T2 b, const std::string& str)
544{
545 if (a >= b)
546 {
547 std::cerr << "Error : " << a << " is larger than " << b << ", " << str << std::endl;
548 everything_ok = false;
549 return false;
550 }
551 else
552 return true;
553}
554
555END_NAMESPACE_STIR
This file declares class stir::BasicCoordinate and some functions acting on stir::BasicCoordinate obj...
Declaration of class stir::Bin.
Declaration of class stir::DetectionPositionPair.
Declaration of class stir::DetectionPosition.
This file defines the stir::IndexRange class.
defines various classes for specifying a line in 3 dimensions
Declaration of class stir::ProjDataInMemory.
defines the stir::VectorWithOffset class
class BasicCoordinate<int num_dimensions, typename coordT> defines num_dimensions -dimensional coordi...
Definition BasicCoordinate.h:57
A class for storing coordinates and value of a single projection bin.
Definition Bin.h:49
A class for storing coordinates of a detection.
Definition DetectionPosition.h:61
This class defines ranges which can be 'irregular'.
Definition IndexRange.h:69
A class for LORs.
Definition LORCoordinates.h:511
A class which reads/writes projection data from/to memory.
Definition ProjDataInMemory.h:39
double get_tolerance() const
Get value used in floating point comparisons (see check_* functions).
Definition RunTests.h:352
bool check_if_equal(const VectorWithOffset< T > &t1, const VectorWithOffset< T > &t2, const std::string &str="")
check equality by comparing ranges and calling check_if_equal on all elements
Definition RunTests.h:153
bool check_if_less(T1 a, T2 b, const std::string &str="")
check if a<b
Definition RunTests.h:543
bool everything_ok
variable storing current status
Definition RunTests.h:281
bool check_if_equal(const BasicCoordinate< num_dimensions, coordT > &a, const BasicCoordinate< num_dimensions, coordT > &b, const std::string &str="")
check equality by comparing norm(a-b) with tolerance
Definition RunTests.h:210
bool check(const bool, const std::string &str="")
Tests if true, str can be used to tell what you are testing.
Definition RunTests.h:358
bool is_everything_ok() const
Returns if all checks were fine upto now.
Definition RunTests.h:334
RunTests(const double tolerance=1E-4)
Default constructor.
Definition RunTests.h:316
double tolerance
tolerance for comparisons with real values
Definition RunTests.h:279
bool check_if_equal(const std::vector< T > &t1, const std::vector< T > &t2, const std::string &str="")
check equality by comparing size and calling check_if_equal on all elements
Definition RunTests.h:174
int main_return_value() const
Handy return value for a main() function.
Definition RunTests.h:340
bool check_if_equal(const std::complex< T > a, const std::complex< T > b, const std::string &str="")
check equality by calling check_if_equal on real and imaginary parts
Definition RunTests.h:147
bool check_if_equal_generic(const T &a, const T &b, const std::string &str)
function that is called by some check_if_equal implementations. It just uses operator!...
Definition RunTests.h:285
bool check_if_zero_generic(T a, const std::string &str)
function that is called by some check_if_zero implementations. It just uses operator!...
Definition RunTests.h:299
virtual ~RunTests()
Destructor, outputs a diagnostic message.
Definition RunTests.h:321
bool check_if_zero(const double a, const std::string &str="")
Definition RunTests.h:529
bool check_if_zero(const VectorWithOffset< T > &t, const std::string &str="")
use check_if_zero on all elements
Definition RunTests.h:245
void set_tolerance(const double tolerance)
Set value used in floating point comparisons (see check_* functions).
Definition RunTests.h:346
bool check_if_zero(const BasicCoordinate< num_dimensions, coordT > &a, const std::string &str="")
compare norm with tolerance
Definition RunTests.h:260
virtual void run_tests()=0
Function (to be overloaded) which does the actual tests.
A templated class for vectors, but with indices starting not from 0.
Definition VectorWithOffset.h:65
int get_max_index() const
get value of last valid index
Definition VectorWithOffset.inl:131
int get_min_index() const
get value of first valid index
Definition VectorWithOffset.inl:124
double norm(const BasicCoordinate< num_dimensions, coordT > &p1)
compute sqrt(inner_product(p1,p1))
Definition BasicCoordinate.inl:426
Input/output of basic vector-like types to/from streams.