From f8fb42a5e830768a77332389d98f3fb35d24010f Mon Sep 17 00:00:00 2001 From: NikEfth Date: Mon, 21 Dec 2020 21:52:02 -0500 Subject: [PATCH 1/8] Virtual xtal interface. Update CListModeDataROOT.cxx, Scanner.h, and 4 more files... --- src/IO/InterfileHeader.cxx | 28 ++++ src/IO/InterfilePDFSHeaderSPECT.cxx | 4 + src/buildblock/Scanner.cxx | 127 +++++++++++------- src/include/stir/IO/InterfileHeader.h | 2 + src/include/stir/Scanner.h | 8 ++ src/listmode_buildblock/CListModeDataROOT.cxx | 29 ++-- 6 files changed, 134 insertions(+), 64 deletions(-) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index b1539e150c..f120df5384 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -600,6 +600,12 @@ InterfilePDFSHeader::InterfilePDFSHeader() num_transaxial_crystals_per_block = 0; add_key("number of crystals_per_block in transaxial direction", &num_transaxial_crystals_per_block); + num_virtual_axial_crystals_per_block = 0; + add_key("number of virtual crystals_per_block in axial direction", + &num_virtual_axial_crystals_per_block); + num_virtual_transaxial_crystals_per_block = 0; + add_key("number of virtual crystals_per_block in transaxial direction", + &num_virtual_transaxial_crystals_per_block); num_axial_crystals_per_singles_unit = -1; add_key("number of crystals_per_singles_unit in axial direction", &num_axial_crystals_per_singles_unit); @@ -1095,6 +1101,10 @@ bool InterfilePDFSHeader::post_processing() num_axial_crystals_per_block = guessed_scanner_ptr->get_num_axial_crystals_per_block(); if (num_transaxial_crystals_per_block<=0) num_transaxial_crystals_per_block = guessed_scanner_ptr->get_num_transaxial_crystals_per_block(); + if (num_virtual_axial_crystals_per_block<=0) + num_virtual_axial_crystals_per_block = guessed_scanner_ptr->get_num_virtual_axial_crystals_per_block(); + if (num_virtual_transaxial_crystals_per_block<=0) + num_virtual_transaxial_crystals_per_block = guessed_scanner_ptr->get_num_virtual_transaxial_crystals_per_block(); if (num_axial_crystals_per_singles_unit < 0) num_axial_crystals_per_singles_unit = guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit(); @@ -1192,6 +1202,22 @@ bool InterfilePDFSHeader::post_processing() num_transaxial_crystals_per_block, guessed_scanner_ptr->get_num_transaxial_crystals_per_block()); mismatch_between_header_and_guess = true; } + if ( + guessed_scanner_ptr->get_num_virtual_axial_crystals_per_block()>0 && + num_virtual_axial_crystals_per_block!= guessed_scanner_ptr->get_num_virtual_axial_crystals_per_block()) + { + warning("Interfile warning: num_virtual_axial_crystals_per_block (%d) is expected to be %d.\n", + num_virtual_axial_crystals_per_block, guessed_scanner_ptr->get_num_virtual_axial_crystals_per_block()); + mismatch_between_header_and_guess = true; + } + if ( + guessed_scanner_ptr->get_num_virtual_transaxial_crystals_per_block()>0 && + num_virtual_transaxial_crystals_per_block!= guessed_scanner_ptr->get_num_virtual_transaxial_crystals_per_block()) + { + warning("Interfile warning: num_transaxial_crystals_per_block (%d) is expected to be %d.\n", + num_transaxial_crystals_per_block, guessed_scanner_ptr->get_num_transaxial_crystals_per_block()); + mismatch_between_header_and_guess = true; + } if ( guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit() > 0 && num_axial_crystals_per_singles_unit != guessed_scanner_ptr->get_num_axial_crystals_per_singles_unit() ) @@ -1302,6 +1328,8 @@ bool InterfilePDFSHeader::post_processing() num_transaxial_blocks_per_bucket, num_axial_crystals_per_block, num_transaxial_crystals_per_block, + num_virtual_axial_crystals_per_block, + num_virtual_transaxial_crystals_per_block, num_axial_crystals_per_singles_unit, num_transaxial_crystals_per_singles_unit, num_detector_layers, diff --git a/src/IO/InterfilePDFSHeaderSPECT.cxx b/src/IO/InterfilePDFSHeaderSPECT.cxx index 6012292fee..ba2513079f 100644 --- a/src/IO/InterfilePDFSHeaderSPECT.cxx +++ b/src/IO/InterfilePDFSHeaderSPECT.cxx @@ -159,7 +159,9 @@ bool InterfilePDFSHeaderSPECT::post_processing() const int num_axial_blocks_per_bucket = -1; const int num_transaxial_blocks_per_bucket = -1; const int num_axial_crystals_per_block = -1; + const int num_virtual_axial_crystals_per_block=0; const int num_transaxial_crystals_per_block = -1; + const int num_virtual_transaxial_crystals_per_block = 0; const int num_axial_crystals_per_singles_unit = -1; const int num_transaxial_crystals_per_singles_unit = -1; const int num_detector_layers = 1; @@ -181,6 +183,8 @@ bool InterfilePDFSHeaderSPECT::post_processing() num_transaxial_blocks_per_bucket, num_axial_crystals_per_block, num_transaxial_crystals_per_block, + num_virtual_axial_crystals_per_block, + num_virtual_transaxial_crystals_per_block, num_axial_crystals_per_singles_unit, num_transaxial_crystals_per_singles_unit, num_detector_layers)); diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index 51a7a1301d..be10ca8274 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -124,7 +124,7 @@ Scanner::Scanner(Type scanner_type) set_params(E931, string_list("ECAT 931"), 8, 192, 2 * 256, 510.0F, 7.0F, 13.5F, 3.129F, 0.0F, - 2, 4, 4, 8, 4, 8 * 4, 1, + 2, 4, 4, 8, 0, 0, 4, 8 * 4, 1, 0.37f, 511.f); // 16 BUCKETS per ring in TWO rings - i.e. 32 buckets in total @@ -135,7 +135,7 @@ Scanner::Scanner(Type scanner_type) set_params(E951, string_list("ECAT 951"), 16, 192, 2 * 256, 510.0F, 7.0F, 6.75F, 3.12932F, 0.0F, - 1, 4, 8, 8, 8, 8 * 4, 1); + 1, 4, 8, 8, 0, 0, 8, 8 * 4, 1); break; case E953: @@ -143,7 +143,7 @@ Scanner::Scanner(Type scanner_type) set_params(E953, string_list("ECAT 953"), 16, 160, 2 * 192, 382.5F, 7.0F, 6.75F, 3.12932F, static_cast(15.*_PI/180), - 1, 4, 8, 8, 8, 8 * 4, 1); + 1, 4, 8, 8, 0, 0, 8, 8 * 4, 1); break; case E921: @@ -151,7 +151,7 @@ Scanner::Scanner(Type scanner_type) set_params(E921, string_list("ECAT 921", "ECAT EXACT", "EXACT"), 24, 192, 2* 192, 412.5F, 7.0F, 6.75F, 3.375F, static_cast(15.*_PI/180), - 1, 4, 8, 8, 8, 8 * 4, 1); + 1, 4, 8, 8, 0, 0, 8, 8 * 4, 1); break; case E925: @@ -159,7 +159,7 @@ Scanner::Scanner(Type scanner_type) set_params(E925, string_list("ECAT 925", "ECAT ART"), 24, 192, 2* 192, 412.5F, 7.0F, 6.75F, 3.375F, static_cast(15.*_PI/180), - 3, 4, 8, 8, 8, 8 * 4, 1); + 3, 4, 8, 8, 0, 0, 8, 8 * 4, 1); break; @@ -168,7 +168,7 @@ Scanner::Scanner(Type scanner_type) set_params(E961,string_list("ECAT 961", "ECAT HR"), 24, 336, 2* 392, 412.0F, 7.0F, 6.25F, 1.650F, static_cast(13.*_PI/180), - 1, 8, 8, 7, 8, 7 * 8, 1); + 1, 8, 8, 7, 0, 0, 8, 7 * 8, 1); break; case E962: @@ -176,7 +176,7 @@ Scanner::Scanner(Type scanner_type) set_params(E962,string_list("ECAT 962","ECAT HR+"), 32, 288, 2* 288, 412.0F, 7.0F, 4.85F, 2.25F, 0.0F, - 4, 3, 8, 8, 8, 8 * 3, 1); + 4, 3, 8, 8, 0, 0, 8, 8 * 3, 1); break; case E966: @@ -184,7 +184,7 @@ Scanner::Scanner(Type scanner_type) set_params(E966, string_list("ECAT EXACT 3D", "EXACT 3D", "ECAT HR++","ECAT 966"), 48, 288, 2* 288, 412.0F, 7.0F, 4.850F, 2.250F, 0.0, - 6, 2, 8, 8, 2 * 8, 8 * 2, 1); + 6, 2, 8, 8, 0, 0, 2 * 8, 8 * 2, 1); break; case E1080: @@ -192,7 +192,7 @@ Scanner::Scanner(Type scanner_type) set_params(E1080, string_list("ECAT 1080", "Biograph 16", "1080"), 41, 336, 2* 336, 412.0F, 7.0F, 4.0F, 2.000F, 0.0F, - 1, 2, 13+1, 13+1, 0, 0, 1);// TODO bucket/singles info? + 1, 2, 13, 13, 1, 1, 0, 0, 1);// TODO bucket/singles info? // Transaxial blocks have 13 physical crystals and a gap at the // 14th crystal where the counts are zero. // There are 39 rings with 13 axial crystals per block. Two virtual @@ -206,7 +206,7 @@ Scanner::Scanner(Type scanner_type) set_params(Siemens_mMR, string_list("Siemens mMR", "mMR", "2008"), 64, 344, 2* 252, 328.0F, 7.0F, 4.0625F, 2.08626F, 0.0F, - 2, 1, 8, 9, 16, 9, 1, + 2, 1, 8, 9, 0, 0, 16, 9, 1, 0.145f, 511.f); // TODO bucket/singles info incorrect? 224 buckets in total, but not sure how distributed break; @@ -215,7 +215,7 @@ Scanner::Scanner(Type scanner_type) set_params(Siemens_mCT, string_list("Siemens mCT", "mCT", "2011", "1104" /* used in norm files */, "1094" /* used in attenuation files */), 55, 400, (13+1)*48, 421.0F, 7.0F, 4.054F, 2.005F, 0.0F, - 4, 1, 13+1, 13+1, 0,0, 1 ); // TODO singles info incorrect + 4, 1, 13, 13, 1, 1, 0,0, 1 ); // TODO singles info incorrect // energy: 435-650 // 13 TOF bins break; @@ -225,7 +225,7 @@ Scanner::Scanner(Type scanner_type) set_params(RPT, string_list("PRT-1", "RPT"), 16, 128, 2 * 192, 380.0F - 7.0F, 7.0F, 6.75F, 3.1088F, 0.0F, - 1, 4, 8, 8, 8, 32, 1); + 1, 4, 8, 8, 0, 0, 8, 32, 1); // Default 7.0mm average interaction depth. // This 7mm taken off the inner ring radius so that the effective radius remains 380mm @@ -236,7 +236,7 @@ Scanner::Scanner(Type scanner_type) set_params(RATPET, string_list("RATPET"), 8, 56, 2 * 56, 115 / 2.F, 7.0F, 6.25F, 1.65F, 0.0F, - 1, 16, 8, 7, 8, 0, 1); // HR block, 4 buckets per ring + 1, 16, 8, 7, 0, 0, 8, 0, 1); // HR block, 4 buckets per ring // Default 7.0mm average interaction depth. // 8 x 0 crystals per singles unit because not known @@ -248,7 +248,7 @@ Scanner::Scanner(Type scanner_type) set_params(PANDA, string_list("PANDA"), 1 /*NumRings*/, 512 /*MaxBinsNonArcCor*/, 512 /*MaxBinsArcCor*/, 2048 /*NumDetPerRing*/, /*MeanInnerRadius*/ 75.5/2.F, /*AverageDoI*/ 10.F, /*Ring Spacing*/ 3.F, /*BinSize*/ 0.1F, /*IntrinsicTilt*/ 0.F, - 1, 1, 1, 1, 0, 0, 1); + 1, 1, 1, 1, 0, 0, 0, 0, 1); break; case nanoPET: @@ -257,7 +257,7 @@ Scanner::Scanner(Type scanner_type) 81, 39*3, /* We could also model gaps in the future as one detector so 39->39+1, while 1 (point source), 3 (mouse) or 5 (rats) */ 39*3, /* Just put the same with NonArcCor for now*/ 12 * 39, 174.F, 5.0F, 1.17F, 1.17F, /* Actual size is 1.12 and 0.05 is the thickness of the optical reflector */ 0.0F, /* not sure for this */ - 0,0,0,0,0,0, 1); + 0,0,0,0,0,0, 0,0, 1); break; case HYPERimage: @@ -265,7 +265,7 @@ Scanner::Scanner(Type scanner_type) set_params(HYPERimage, string_list("HYPERimage"), /*Modelling the gap with one fake crystal */ 22, 239, 245, 490, 103.97F, 3.0F, 1.4F, 1.4F, /* Actual size is 1.3667 and assume 0.0333 is the thickness of the optical reflector */ 0.F, - 0,0,0,0,0,0,1); + 0,0,0,0,0, 0,0,0,1); break; @@ -277,7 +277,7 @@ Scanner::Scanner(Type scanner_type) set_params(Advance, string_list("GE Advance", "Advance"), 18, 283, 281, 2 * 336, 471.875F - 8.4F, 8.4F, 8.5F, 1.970177F, 0.0F, //TODO view offset shouldn't be zero - 3, 2, 6, 6, 1, 1, 1); + 3, 2, 6, 6, 0, 0, 1, 1, 1); break; case DiscoveryLS: @@ -285,7 +285,7 @@ Scanner::Scanner(Type scanner_type) set_params(DiscoveryLS, string_list("GE Discovery LS", "Discovery LS"), 18, 283, 281, 2 * 336, 471.875F - 8.4F, 8.4F, 8.5F, 1.970177F, 0.0F, //TODO view offset shouldn't be zero - 3, 2, 6, 6, 1, 1, 1); + 3, 2, 6, 6, 0, 0, 1, 1, 1); break; case DiscoveryST: @@ -296,7 +296,7 @@ Scanner::Scanner(Type scanner_type) 24, 249, 221, 2 * 210, 886.2F/2.F, 8.4F, 6.54F, 3.195F, static_cast(-4.54224*_PI/180),//sign? - 4, 2, 6, 6, 1, 1, 1);// TODO not sure about sign of view_offset + 4, 2, 6, 6, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset break; case DiscoverySTE: @@ -305,7 +305,7 @@ Scanner::Scanner(Type scanner_type) 24, 329, 293, 2 * 280, 886.2F/2.F, 8.4F, 6.54F, 2.397F, static_cast(-4.5490*_PI/180),//sign? - 4, 2, 6, 8, 1, 1, 1);// TODO not sure about sign of view_offset + 4, 2, 6, 8, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset break; case DiscoveryRX: @@ -321,7 +321,7 @@ Scanner::Scanner(Type scanner_type) static_cast(-4.5950*_PI/180),//sign? 4, 2, - 6, 9, 1, 1, 1);// TODO not sure about sign of view_offset + 6, 9, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset break; case Discovery600: @@ -338,7 +338,7 @@ Scanner::Scanner(Type scanner_type) static_cast(-4.5490*_PI/180),//sign? TODO value 4, 2, - 6, 8, 1, 1, 1); + 6, 8, 0, 0, 1, 1, 1); break; @@ -356,7 +356,7 @@ case PETMR_Signa: static_cast(-5.23*_PI/180),//sign? TODO value 5, 4, - 9, 4, 1, 1, 1, + 9, 4, 0, 0, 1, 1, 1, 0.105F, // energy resolution from Levin et al. TMI 2016 511.F); break; @@ -376,7 +376,7 @@ break; static_cast(-5.021*_PI/180),//sign? TODO value 4, 2, - 6, 9, 1, 1, 1 + 6, 9, 0, 0, 1, 1, 1 #ifdef STIR_TOF , (short int)(55), @@ -403,6 +403,7 @@ break; static_cast(-4.399*_PI/180), //TODO check sign 3, 4, 9, 4, + 0, 0, 1, 1, 1, 0.0944F, // energy resolution from Hsu et al. 2017 @@ -425,6 +426,7 @@ break; static_cast(-4.399*_PI/180), //TODO check sign 4, 4, 9, 4, + 0, 0, 1, 1, 1, 0.0944F, // energy resolution from Hsu et al. 2017 @@ -436,7 +438,7 @@ break; set_params(HZLR, string_list("Positron HZL/R"), 32, 256, 2 * 192, 780.0F, 7.0F, 5.1875F, 2.F, 0.0F, - 0, 0, 0, 0, 0,0, 1); + 0, 0, 0, 0, 0, 0, 0,0, 1); // Default 7.0mm average interaction depth. // crystals per singles unit etc unknown break; @@ -446,7 +448,7 @@ break; set_params(HRRT, string_list("HRRT"), 104, 288, 2 * 288, 234.765F, 7.0F, 2.4375F, 1.21875F, 0.0F, - 0, 0, 0, 0, 0, 0, 2); // added by Dylan Togane + 0, 0, 0, 0, 0, 0, 0, 0, 2); // added by Dylan Togane // warning: used 7.0mm average interaction depth. // crystals per singles unit etc unknown break; @@ -480,6 +482,7 @@ break; 6.3F, 4.3F, 0.0F, 1, 0, 29, 0 /* 23* or 22*/, + 0, 0, 29, 0 /* all detectors in a ring? */, 1); break; @@ -493,6 +496,7 @@ break; 0, 0, 0, 0, // Not considering any gap, but this is per module 28 flat modules in total, while 420 PMTs 0, 0 /* Not sure about these, but shouldn't be important */, + 0, 0, 1); break; @@ -500,7 +504,7 @@ break; set_params(HiDAC, string_list("HiDAC"), 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, 0, 0); break; @@ -509,7 +513,7 @@ break; set_params(User_defined_scanner, string_list("Userdefined"), 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, 0, 0); break; @@ -518,7 +522,7 @@ break; set_params(Unknown_scanner, string_list("Unknown"), 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, 0, 0); break; @@ -535,6 +539,7 @@ Scanner::Scanner(Type type_v, const list& list_of_names_v, float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -550,6 +555,7 @@ Scanner::Scanner(Type type_v, const list& list_of_names_v, ring_spacing_v, bin_size_v, intrinsic_tilt_v, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, + num_virtual_axial_crystals_per_block_v, num_virtual_transaxial_crystals_per_block_v, num_axial_crystals_per_singles_unit_v, num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, @@ -567,6 +573,7 @@ Scanner::Scanner(Type type_v, const string& name, float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -582,6 +589,7 @@ Scanner::Scanner(Type type_v, const string& name, ring_spacing_v, bin_size_v, intrinsic_tilt_v, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, + num_virtual_axial_crystals_per_block_v, num_virtual_transaxial_crystals_per_block_v, num_axial_crystals_per_singles_unit_v, num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, @@ -607,6 +615,7 @@ set_params(Type type_v,const list& list_of_names_v, float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -622,6 +631,7 @@ set_params(Type type_v,const list& list_of_names_v, ring_spacing_v, bin_size_v, intrinsic_tilt_v, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, + num_virtual_axial_crystals_per_block_v, num_virtual_transaxial_crystals_per_block_v, num_axial_crystals_per_singles_unit_v, num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, @@ -643,6 +653,7 @@ set_params(Type type_v,const list& list_of_names_v, float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -664,6 +675,8 @@ set_params(Type type_v,const list& list_of_names_v, num_axial_blocks_per_bucket = num_axial_blocks_per_bucket_v; num_axial_crystals_per_block= num_axial_crystals_per_block_v; num_transaxial_crystals_per_block= num_transaxial_crystals_per_block_v; + num_virtual_axial_crystals_per_block= num_virtual_axial_crystals_per_block_v; + num_virtual_transaxial_crystals_per_block= num_virtual_transaxial_crystals_per_block_v; num_axial_crystals_per_singles_unit = num_axial_crystals_per_singles_unit_v; num_transaxial_crystals_per_singles_unit = num_transaxial_crystals_per_singles_unit_v; num_detector_layers = num_detector_layers_v; @@ -682,14 +695,15 @@ int Scanner:: get_num_virtual_axial_crystals_per_block() const { - switch(get_type()) - { - case E1080: - case Siemens_mCT: - return 1; - default: - return 0; - } +// switch(get_type()) +// { +// case E1080: +// case Siemens_mCT: +// return 1; +// default: +// return 0; +// } + return num_virtual_axial_crystals_per_block; } /*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). @@ -698,24 +712,23 @@ int Scanner:: get_num_virtual_transaxial_crystals_per_block() const { - switch(get_type()) - { - case E1080: - case Siemens_mCT: - case Siemens_mMR: - return 1; - default: - return 0; - } +// switch(get_type()) +// { +// case E1080: +// case Siemens_mCT: +// case Siemens_mMR: +// return 1; +// default: +// return 0; +// } + return num_virtual_transaxial_crystals_per_block; } /*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ void Scanner:: set_num_virtual_axial_crystals_per_block(int val) { - //num_virtual_axial_crystals_per_block = val; - if (this->get_num_virtual_axial_crystals_per_block() != val) - error("Scanner::set_num_virtual_axial_crystals_per_block not really implemented yet"); + num_virtual_axial_crystals_per_block = val; } /*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ @@ -723,9 +736,7 @@ void Scanner:: set_num_virtual_transaxial_crystals_per_block(int val) { - //num_virtual_transaxial_crystals_per_block = val; - if (this->get_num_virtual_transaxial_crystals_per_block() != val) - error("Scanner::set_num_virtual_transaxial_crystals_per_block not really implemented yet"); + num_virtual_transaxial_crystals_per_block = val; } @@ -898,6 +909,8 @@ if (!close_enough(energy_resolution, scanner.energy_resolution) && (num_axial_blocks_per_bucket == scanner.num_axial_blocks_per_bucket) && (num_axial_crystals_per_block == scanner.num_axial_crystals_per_block) && (num_transaxial_crystals_per_block == scanner.num_transaxial_crystals_per_block) && + (num_virtual_axial_crystals_per_block == scanner.num_virtual_axial_crystals_per_block) && + (num_virtual_transaxial_crystals_per_block == scanner.num_virtual_transaxial_crystals_per_block) && (num_detector_layers == scanner.num_detector_layers) && (num_axial_crystals_per_singles_unit == scanner.num_axial_crystals_per_singles_unit) && (num_transaxial_crystals_per_singles_unit == scanner.num_transaxial_crystals_per_singles_unit); @@ -960,6 +973,10 @@ Scanner::parameter_info() const << get_num_axial_crystals_per_block() << '\n' << "Number of crystals per block in transaxial direction := " << get_num_transaxial_crystals_per_block() << '\n' + << "Number of Virtual crystals per block in axial direction := " + << get_num_virtual_axial_crystals_per_block() << '\n' + << "Number of Virtual crystals per block in transaxial direction := " + << get_num_virtual_transaxial_crystals_per_block() << '\n' << "Number of detector layers := " << get_num_detector_layers() << '\n' << "Number of crystals per singles unit in axial direction := " @@ -1061,6 +1078,10 @@ Scanner* Scanner::ask_parameters() ask_num("Enter number of axial crystals per block: ",0,12,8); int TransaxialCrystalsPerBlock = ask_num("Enter number of transaxial crystals per block: ",0,12,8); + int VirtualAxialCrystalsPerBlock = + ask_num("Enter number of virtual axial crystals per block: ",0,12,0); + int VirtualTransaxialCrystalsPerBlock = + ask_num("Enter number of virtual transaxial crystals per block: ",0,12,0); int AxialCrstalsPerSinglesUnit = ask_num("Enter number of axial crystals per singles unit: ", 0, NoRings, 1); int TransaxialCrystalsPerSinglesUnit = @@ -1085,6 +1106,7 @@ Scanner* Scanner::ask_parameters() RingSpacing, BinSize,intrTilt*float(_PI)/180, AxialBlocksPerBucket,TransBlocksPerBucket, AxialCrystalsPerBlock,TransaxialCrystalsPerBlock, + VirtualAxialCrystalsPerBlock, VirtualTransaxialCrystalsPerBlock, AxialCrstalsPerSinglesUnit, TransaxialCrystalsPerSinglesUnit, num_detector_layers, EnergyResolution, @@ -1098,6 +1120,7 @@ Scanner* Scanner::ask_parameters() RingSpacing, BinSize,intrTilt*float(_PI)/180, AxialBlocksPerBucket,TransBlocksPerBucket, AxialCrystalsPerBlock,TransaxialCrystalsPerBlock, + VirtualAxialCrystalsPerBlock, VirtualTransaxialCrystalsPerBlock, AxialCrstalsPerSinglesUnit, TransaxialCrystalsPerSinglesUnit, num_detector_layers); diff --git a/src/include/stir/IO/InterfileHeader.h b/src/include/stir/IO/InterfileHeader.h index 271c2ad380..bf667c7ef1 100644 --- a/src/include/stir/IO/InterfileHeader.h +++ b/src/include/stir/IO/InterfileHeader.h @@ -284,6 +284,8 @@ class InterfilePDFSHeader : public InterfileHeader int num_transaxial_blocks_per_bucket; int num_axial_crystals_per_block; int num_transaxial_crystals_per_block; + int num_virtual_axial_crystals_per_block; + int num_virtual_transaxial_crystals_per_block; int num_axial_crystals_per_singles_unit; int num_transaxial_crystals_per_singles_unit; int num_detector_layers; diff --git a/src/include/stir/Scanner.h b/src/include/stir/Scanner.h index 6780bcc4cf..7d33e07651 100644 --- a/src/include/stir/Scanner.h +++ b/src/include/stir/Scanner.h @@ -138,6 +138,7 @@ class Scanner float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -157,6 +158,7 @@ class Scanner float ring_spacing_v, float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -383,6 +385,10 @@ class Scanner int num_axial_blocks_per_bucket; /* axial blocks per bucket */ int num_axial_crystals_per_block; /* number of crystals in the axial direction */ int num_transaxial_crystals_per_block;/* number of transaxial crystals */ + //! Number of axial virtual crystals per block + int num_virtual_axial_crystals_per_block; + //! Number of transaxial virtual crystals per block + int num_virtual_transaxial_crystals_per_block; int num_detector_layers; int num_axial_crystals_per_singles_unit; @@ -415,6 +421,7 @@ class Scanner float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -433,6 +440,7 @@ class Scanner float bin_size_v, float intrinsic_tilt_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 6bd87b0dce..9e1ba19ae3 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -145,17 +145,15 @@ CListModeDataROOT(const std::string& hroot_filename) this->root_file_sptr->get_num_axial_crystals_per_block_v(), /*num_transaxial_crystals_per_block_v*/ this->root_file_sptr->get_num_transaxial_crystals_per_block_v(), + num_virtual_axial_crystals_per_block, + num_virtual_transaxial_crystals_per_block, /*num_axial_crystals_per_singles_unit_v*/ this->root_file_sptr->get_num_axial_crystals_per_singles_unit(), /*num_transaxial_crystals_per_singles_unit_v*/ this->root_file_sptr->get_num_trans_crystals_per_singles_unit(), /*num_detector_layers_v*/ 1 )); } - // have to do this here currently as these variables cannot be set via the constructor - if (num_virtual_axial_crystals_per_block>=0) - this_scanner_sptr->set_num_virtual_axial_crystals_per_block(num_virtual_axial_crystals_per_block); - if (num_virtual_transaxial_crystals_per_block>=0) - this_scanner_sptr->set_num_virtual_transaxial_crystals_per_block(num_virtual_transaxial_crystals_per_block); + // put virtual block info in root_file_sptr this->root_file_sptr->set_num_virtual_axial_crystals_per_block(this_scanner_sptr->get_num_virtual_axial_crystals_per_block()); this->root_file_sptr->set_num_virtual_transaxial_crystals_per_block(this_scanner_sptr->get_num_virtual_transaxial_crystals_per_block()); @@ -263,7 +261,8 @@ check_scanner_match_geometry(std::string& ret, const shared_ptr& scanne if (scanner_sptr->get_num_rings() != root_file_sptr->get_num_rings()) { - stream << "the number of rings, "; + stream << "the number of rings ("<< scanner_sptr->get_num_rings() << ", " << + root_file_sptr->get_num_rings() << "), "; ok = false; } @@ -275,23 +274,28 @@ check_scanner_match_geometry(std::string& ret, const shared_ptr& scanne if (scanner_sptr->get_num_axial_blocks_per_bucket() != root_file_sptr->get_num_axial_blocks_per_bucket_v()) { - stream << "the number of axial blocks per bucket, "; + stream << "the number of axial blocks per bucket ("<< scanner_sptr->get_num_axial_blocks_per_bucket() << ", " << + root_file_sptr->get_num_axial_blocks_per_bucket_v() << "), "; ok = false; } if(scanner_sptr->get_num_transaxial_blocks_per_bucket() != root_file_sptr->get_num_transaxial_blocks_per_bucket_v()) { - stream << "the number of transaxial blocks per bucket, "; + stream << "the number of transaxial blocks per bucket ("<< scanner_sptr->get_num_transaxial_blocks_per_bucket() << ", " << + root_file_sptr->get_num_transaxial_blocks_per_bucket_v() << "), "; ok = false; } - if(scanner_sptr->get_num_axial_crystals_per_block() != root_file_sptr->get_num_axial_crystals_per_block_v()) + if((scanner_sptr->get_num_axial_crystals_per_block() + + scanner_sptr->get_num_virtual_axial_crystals_per_block()) != root_file_sptr->get_num_axial_crystals_per_block_v()) { - stream << "the number of axial crystals per block, "; + stream << "the number of axial crystals per block ("<< scanner_sptr->get_num_axial_crystals_per_block() << ", " << + root_file_sptr->get_num_axial_crystals_per_block_v() << "), "; ok = false; } - if(scanner_sptr->get_num_transaxial_crystals_per_block() != root_file_sptr->get_num_transaxial_crystals_per_block_v()) + if((scanner_sptr->get_num_transaxial_crystals_per_block() + + scanner_sptr->get_num_virtual_transaxial_crystals_per_block())!= root_file_sptr->get_num_transaxial_crystals_per_block_v()) { stream << "the number of transaxial crystals per block, "; ok = false; @@ -305,7 +309,8 @@ check_scanner_match_geometry(std::string& ret, const shared_ptr& scanne if(scanner_sptr->get_num_transaxial_crystals_per_singles_unit() != root_file_sptr->get_num_trans_crystals_per_singles_unit()) { - stream << "the number of transaxial crystals per singles unit, "; + stream << "the number of transaxial crystals per singles unit ("<< scanner_sptr->get_num_transaxial_crystals_per_singles_unit() << ", " << + root_file_sptr->get_num_trans_crystals_per_singles_unit() << "), "; ok = false; } From 4c65b2f0b4dd065eb149a98b5dc3100e0e25ac06 Mon Sep 17 00:00:00 2001 From: NikEfth Date: Tue, 22 Dec 2020 00:55:25 -0500 Subject: [PATCH 2/8] Test_Scanner pass and able to run lm_to_projdata Update CListModeDataROOT.cxx, Scanner.inl, and 2 more files... --- src/buildblock/Scanner.cxx | 39 +++++++++++++++++-- src/include/stir/Scanner.h | 2 + src/include/stir/Scanner.inl | 2 +- src/listmode_buildblock/CListModeDataROOT.cxx | 8 ++-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index be10ca8274..a9c5c2e3bf 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -723,6 +723,39 @@ get_num_virtual_transaxial_crystals_per_block() const // } return num_virtual_transaxial_crystals_per_block; } + +int +Scanner:: +get_num_virtual_axial_crystals() const +{ +// switch(get_type()) +// { +// case E1080: +// case Siemens_mCT: +// return 1; +// default: +// return 0; +// } + return num_virtual_axial_crystals_per_block * get_num_axial_blocks(); +} + +/*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). + */ +int +Scanner:: +get_num_virtual_transaxial_crystals() const +{ +// switch(get_type()) +// { +// case E1080: +// case Siemens_mCT: +// case Siemens_mMR: +// return 1; +// default: +// return 0; +// } + return num_virtual_transaxial_crystals_per_block * get_num_transaxial_blocks(); +} /*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ void Scanner:: @@ -757,12 +790,12 @@ check_consistency() const { const int dets_per_ring = get_num_transaxial_blocks() * - get_num_transaxial_crystals_per_block(); + (get_num_transaxial_crystals_per_block() + get_num_virtual_transaxial_crystals_per_block()); if ( dets_per_ring != get_num_detectors_per_ring()) - { + { warning("Scanner %s: inconsistent transaxial block info", this->get_name().c_str()); - return Succeeded::no; + return Succeeded::no; } } } diff --git a/src/include/stir/Scanner.h b/src/include/stir/Scanner.h index 7d33e07651..156b39544d 100644 --- a/src/include/stir/Scanner.h +++ b/src/include/stir/Scanner.h @@ -280,6 +280,8 @@ class Scanner //@{! int get_num_virtual_axial_crystals_per_block() const; int get_num_virtual_transaxial_crystals_per_block() const; + int get_num_virtual_axial_crystals() const; + int get_num_virtual_transaxial_crystals() const; void set_num_virtual_axial_crystals_per_block(int); void set_num_virtual_transaxial_crystals_per_block(int); //@} diff --git a/src/include/stir/Scanner.inl b/src/include/stir/Scanner.inl index 4ce80d1c20..c38f289cf2 100644 --- a/src/include/stir/Scanner.inl +++ b/src/include/stir/Scanner.inl @@ -160,7 +160,7 @@ Scanner::get_num_axial_blocks() const int Scanner::get_num_transaxial_blocks() const { - return num_detectors_per_ring/num_transaxial_crystals_per_block; + return num_detectors_per_ring/(num_transaxial_crystals_per_block+num_virtual_transaxial_crystals_per_block); } int diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 9e1ba19ae3..b1f46e7f97 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -266,9 +266,10 @@ check_scanner_match_geometry(std::string& ret, const shared_ptr& scanne ok = false; } - if (scanner_sptr->get_num_detectors_per_ring() != root_file_sptr->get_num_dets_per_ring()) + if ((scanner_sptr->get_num_detectors_per_ring() - scanner_sptr->get_num_virtual_transaxial_crystals()) != root_file_sptr->get_num_dets_per_ring()) { - stream << "the number of detector per ring, "; + stream << "the number of detector per ring ("<< (scanner_sptr->get_num_detectors_per_ring() - scanner_sptr->get_num_virtual_transaxial_crystals()) << ", " << + root_file_sptr->get_num_dets_per_ring() << "), "; ok = false; } @@ -297,7 +298,8 @@ check_scanner_match_geometry(std::string& ret, const shared_ptr& scanne if((scanner_sptr->get_num_transaxial_crystals_per_block() + scanner_sptr->get_num_virtual_transaxial_crystals_per_block())!= root_file_sptr->get_num_transaxial_crystals_per_block_v()) { - stream << "the number of transaxial crystals per block, "; + stream << "the number of transaxial crystals per block ("<< scanner_sptr->get_num_transaxial_crystals_per_block() << ", " << + root_file_sptr->get_num_transaxial_crystals_per_block_v() << "), "; ok = false; } From ac7d7c03894c56273ba304a733b49e70b2719491 Mon Sep 17 00:00:00 2001 From: NikEfth Date: Tue, 22 Dec 2020 01:06:29 -0500 Subject: [PATCH 3/8] Forgot to commit the hunk for the rings. Update Scanner.cxx --- src/buildblock/Scanner.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index a9c5c2e3bf..dd9658b711 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -826,7 +826,7 @@ check_consistency() const { const int dets_axial = get_num_axial_blocks() * - get_num_axial_crystals_per_block(); + (get_num_axial_crystals_per_block() + get_num_virtual_axial_crystals_per_block()); if ( dets_axial != (get_num_rings() + get_num_virtual_axial_crystals_per_block())) { warning("Scanner %s: inconsistent axial block info: %d vs %d", From a72bfdf8d0ef80de5903bf92878d4096d80d42ee Mon Sep 17 00:00:00 2001 From: NikEfth Date: Tue, 22 Dec 2020 01:47:02 -0500 Subject: [PATCH 4/8] Update Scanner.cxx to be able to apply to gap on every block, or group blocks. --- src/buildblock/Scanner.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index dd9658b711..5646781e85 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -861,12 +861,12 @@ check_consistency() const this->get_name().c_str()); else { - if ( get_num_detectors_per_ring() % get_num_transaxial_crystals_per_singles_unit() != 0) + if ( get_num_detectors_per_ring() % (get_num_transaxial_crystals_per_singles_unit() + get_num_virtual_transaxial_crystals_per_block()) != 0) { warning("Scanner %s: inconsistent transaxial singles unit info:\n" - "\tnum_detectors_per_ring %d should be a multiple of num_transaxial_crystals_per_singles_unit %d", + "\tnum_detectors_per_ring %d should be a multiple of num_transaxial_crystals_per_singles_unit + virtual %d", this->get_name().c_str(), - get_num_detectors_per_ring(), get_num_transaxial_crystals_per_singles_unit()); + get_num_detectors_per_ring(), (get_num_transaxial_crystals_per_singles_unit() + get_num_virtual_transaxial_crystals_per_block())); return Succeeded::no; } if ( get_num_transaxial_crystals_per_bucket() % get_num_transaxial_crystals_per_singles_unit() != 0) From 5bea447453f1c8229aab32af96f4712fb5bb2e45 Mon Sep 17 00:00:00 2001 From: Nikos Efthimiou Date: Tue, 22 Dec 2020 13:58:32 -0500 Subject: [PATCH 5/8] Update src/buildblock/Scanner.cxx Co-authored-by: Kris Thielemans --- src/buildblock/Scanner.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index 5646781e85..41761641b7 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -739,8 +739,6 @@ get_num_virtual_axial_crystals() const return num_virtual_axial_crystals_per_block * get_num_axial_blocks(); } -/*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). - */ int Scanner:: get_num_virtual_transaxial_crystals() const From ca8438a5727b8114caa8de6172642b8b3a8de555 Mon Sep 17 00:00:00 2001 From: Nikos Efthimiou Date: Tue, 22 Dec 2020 14:03:33 -0500 Subject: [PATCH 6/8] Update src/IO/InterfileHeader.cxx Co-authored-by: Kris Thielemans --- src/IO/InterfileHeader.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index f120df5384..ea81f98a31 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -1203,7 +1203,7 @@ bool InterfilePDFSHeader::post_processing() mismatch_between_header_and_guess = true; } if ( - guessed_scanner_ptr->get_num_virtual_axial_crystals_per_block()>0 && + guessed_scanner_ptr->get_num_virtual_axial_crystals_per_block()>=0 && num_virtual_axial_crystals_per_block!= guessed_scanner_ptr->get_num_virtual_axial_crystals_per_block()) { warning("Interfile warning: num_virtual_axial_crystals_per_block (%d) is expected to be %d.\n", From c46df951434372850f650303e20292c64aee82a0 Mon Sep 17 00:00:00 2001 From: NikEfth Date: Tue, 22 Dec 2020 21:17:55 -0500 Subject: [PATCH 7/8] Initial commit for additional gaps on every bucket. --- src/buildblock/Scanner.cxx | 137 ++++++++---------- src/include/stir/Scanner.h | 18 ++- src/include/stir/Scanner.inl | 10 ++ src/listmode_buildblock/CListModeDataROOT.cxx | 6 + 4 files changed, 93 insertions(+), 78 deletions(-) diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index 5646781e85..8515002dd5 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -124,7 +124,7 @@ Scanner::Scanner(Type scanner_type) set_params(E931, string_list("ECAT 931"), 8, 192, 2 * 256, 510.0F, 7.0F, 13.5F, 3.129F, 0.0F, - 2, 4, 4, 8, 0, 0, 4, 8 * 4, 1, + 2, 4, 4, 8, 0, 0, 4, 0, 0, 8 * 4, 1, 0.37f, 511.f); // 16 BUCKETS per ring in TWO rings - i.e. 32 buckets in total @@ -135,7 +135,7 @@ Scanner::Scanner(Type scanner_type) set_params(E951, string_list("ECAT 951"), 16, 192, 2 * 256, 510.0F, 7.0F, 6.75F, 3.12932F, 0.0F, - 1, 4, 8, 8, 0, 0, 8, 8 * 4, 1); + 1, 4, 8, 8, 0, 0, 0, 0, 8, 8 * 4, 1); break; case E953: @@ -143,7 +143,7 @@ Scanner::Scanner(Type scanner_type) set_params(E953, string_list("ECAT 953"), 16, 160, 2 * 192, 382.5F, 7.0F, 6.75F, 3.12932F, static_cast(15.*_PI/180), - 1, 4, 8, 8, 0, 0, 8, 8 * 4, 1); + 1, 4, 8, 8, 0, 0, 0, 0, 8, 8 * 4, 1); break; case E921: @@ -151,7 +151,7 @@ Scanner::Scanner(Type scanner_type) set_params(E921, string_list("ECAT 921", "ECAT EXACT", "EXACT"), 24, 192, 2* 192, 412.5F, 7.0F, 6.75F, 3.375F, static_cast(15.*_PI/180), - 1, 4, 8, 8, 0, 0, 8, 8 * 4, 1); + 1, 4, 8, 8, 0, 0, 0, 0, 8, 8 * 4, 1); break; case E925: @@ -159,7 +159,7 @@ Scanner::Scanner(Type scanner_type) set_params(E925, string_list("ECAT 925", "ECAT ART"), 24, 192, 2* 192, 412.5F, 7.0F, 6.75F, 3.375F, static_cast(15.*_PI/180), - 3, 4, 8, 8, 0, 0, 8, 8 * 4, 1); + 3, 4, 8, 8, 0, 0, 0, 0, 8, 8 * 4, 1); break; @@ -168,7 +168,7 @@ Scanner::Scanner(Type scanner_type) set_params(E961,string_list("ECAT 961", "ECAT HR"), 24, 336, 2* 392, 412.0F, 7.0F, 6.25F, 1.650F, static_cast(13.*_PI/180), - 1, 8, 8, 7, 0, 0, 8, 7 * 8, 1); + 1, 8, 8, 7, 0, 0, 0, 0, 8, 7 * 8, 1); break; case E962: @@ -176,7 +176,7 @@ Scanner::Scanner(Type scanner_type) set_params(E962,string_list("ECAT 962","ECAT HR+"), 32, 288, 2* 288, 412.0F, 7.0F, 4.85F, 2.25F, 0.0F, - 4, 3, 8, 8, 0, 0, 8, 8 * 3, 1); + 4, 3, 8, 8, 0, 0, 0, 0, 8, 8 * 3, 1); break; case E966: @@ -184,7 +184,7 @@ Scanner::Scanner(Type scanner_type) set_params(E966, string_list("ECAT EXACT 3D", "EXACT 3D", "ECAT HR++","ECAT 966"), 48, 288, 2* 288, 412.0F, 7.0F, 4.850F, 2.250F, 0.0, - 6, 2, 8, 8, 0, 0, 2 * 8, 8 * 2, 1); + 6, 2, 8, 8, 0, 0, 0, 0, 2 * 8, 8 * 2, 1); break; case E1080: @@ -192,7 +192,7 @@ Scanner::Scanner(Type scanner_type) set_params(E1080, string_list("ECAT 1080", "Biograph 16", "1080"), 41, 336, 2* 336, 412.0F, 7.0F, 4.0F, 2.000F, 0.0F, - 1, 2, 13, 13, 1, 1, 0, 0, 1);// TODO bucket/singles info? + 1, 2, 13, 13, 1, 1, 0, 0, 0, 0, 1);// TODO bucket/singles info? // Transaxial blocks have 13 physical crystals and a gap at the // 14th crystal where the counts are zero. // There are 39 rings with 13 axial crystals per block. Two virtual @@ -206,7 +206,7 @@ Scanner::Scanner(Type scanner_type) set_params(Siemens_mMR, string_list("Siemens mMR", "mMR", "2008"), 64, 344, 2* 252, 328.0F, 7.0F, 4.0625F, 2.08626F, 0.0F, - 2, 1, 8, 9, 0, 0, 16, 9, 1, + 2, 1, 8, 9, 0, 0, 0, 0, 16, 9, 1, 0.145f, 511.f); // TODO bucket/singles info incorrect? 224 buckets in total, but not sure how distributed break; @@ -215,7 +215,7 @@ Scanner::Scanner(Type scanner_type) set_params(Siemens_mCT, string_list("Siemens mCT", "mCT", "2011", "1104" /* used in norm files */, "1094" /* used in attenuation files */), 55, 400, (13+1)*48, 421.0F, 7.0F, 4.054F, 2.005F, 0.0F, - 4, 1, 13, 13, 1, 1, 0,0, 1 ); // TODO singles info incorrect + 4, 1, 13, 13, 1, 1, 0, 0, 0,0, 1 ); // TODO singles info incorrect // energy: 435-650 // 13 TOF bins break; @@ -225,7 +225,7 @@ Scanner::Scanner(Type scanner_type) set_params(RPT, string_list("PRT-1", "RPT"), 16, 128, 2 * 192, 380.0F - 7.0F, 7.0F, 6.75F, 3.1088F, 0.0F, - 1, 4, 8, 8, 0, 0, 8, 32, 1); + 1, 4, 8, 8, 0, 0, 0, 0, 8, 32, 1); // Default 7.0mm average interaction depth. // This 7mm taken off the inner ring radius so that the effective radius remains 380mm @@ -236,7 +236,7 @@ Scanner::Scanner(Type scanner_type) set_params(RATPET, string_list("RATPET"), 8, 56, 2 * 56, 115 / 2.F, 7.0F, 6.25F, 1.65F, 0.0F, - 1, 16, 8, 7, 0, 0, 8, 0, 1); // HR block, 4 buckets per ring + 1, 16, 8, 7, 0, 0, 0, 0, 8, 0, 1); // HR block, 4 buckets per ring // Default 7.0mm average interaction depth. // 8 x 0 crystals per singles unit because not known @@ -248,7 +248,7 @@ Scanner::Scanner(Type scanner_type) set_params(PANDA, string_list("PANDA"), 1 /*NumRings*/, 512 /*MaxBinsNonArcCor*/, 512 /*MaxBinsArcCor*/, 2048 /*NumDetPerRing*/, /*MeanInnerRadius*/ 75.5/2.F, /*AverageDoI*/ 10.F, /*Ring Spacing*/ 3.F, /*BinSize*/ 0.1F, /*IntrinsicTilt*/ 0.F, - 1, 1, 1, 1, 0, 0, 0, 0, 1); + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1); break; case nanoPET: @@ -257,7 +257,7 @@ Scanner::Scanner(Type scanner_type) 81, 39*3, /* We could also model gaps in the future as one detector so 39->39+1, while 1 (point source), 3 (mouse) or 5 (rats) */ 39*3, /* Just put the same with NonArcCor for now*/ 12 * 39, 174.F, 5.0F, 1.17F, 1.17F, /* Actual size is 1.12 and 0.05 is the thickness of the optical reflector */ 0.0F, /* not sure for this */ - 0,0,0,0,0,0, 0,0, 1); + 0,0,0,0,0,0, 0, 0, 0, 0, 1); break; case HYPERimage: @@ -265,7 +265,7 @@ Scanner::Scanner(Type scanner_type) set_params(HYPERimage, string_list("HYPERimage"), /*Modelling the gap with one fake crystal */ 22, 239, 245, 490, 103.97F, 3.0F, 1.4F, 1.4F, /* Actual size is 1.3667 and assume 0.0333 is the thickness of the optical reflector */ 0.F, - 0,0,0,0,0, 0,0,0,1); + 0,0,0,0,0, 0,0, 0, 0,0,1); break; @@ -277,7 +277,7 @@ Scanner::Scanner(Type scanner_type) set_params(Advance, string_list("GE Advance", "Advance"), 18, 283, 281, 2 * 336, 471.875F - 8.4F, 8.4F, 8.5F, 1.970177F, 0.0F, //TODO view offset shouldn't be zero - 3, 2, 6, 6, 0, 0, 1, 1, 1); + 3, 2, 6, 6, 0, 0, 0, 0, 1, 1, 1); break; case DiscoveryLS: @@ -285,7 +285,7 @@ Scanner::Scanner(Type scanner_type) set_params(DiscoveryLS, string_list("GE Discovery LS", "Discovery LS"), 18, 283, 281, 2 * 336, 471.875F - 8.4F, 8.4F, 8.5F, 1.970177F, 0.0F, //TODO view offset shouldn't be zero - 3, 2, 6, 6, 0, 0, 1, 1, 1); + 3, 2, 6, 6, 0, 0, 0, 0, 1, 1, 1); break; case DiscoveryST: @@ -296,7 +296,7 @@ Scanner::Scanner(Type scanner_type) 24, 249, 221, 2 * 210, 886.2F/2.F, 8.4F, 6.54F, 3.195F, static_cast(-4.54224*_PI/180),//sign? - 4, 2, 6, 6, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset + 4, 2, 6, 6, 0, 0, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset break; case DiscoverySTE: @@ -305,7 +305,7 @@ Scanner::Scanner(Type scanner_type) 24, 329, 293, 2 * 280, 886.2F/2.F, 8.4F, 6.54F, 2.397F, static_cast(-4.5490*_PI/180),//sign? - 4, 2, 6, 8, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset + 4, 2, 6, 8, 0, 0, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset break; case DiscoveryRX: @@ -321,7 +321,7 @@ Scanner::Scanner(Type scanner_type) static_cast(-4.5950*_PI/180),//sign? 4, 2, - 6, 9, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset + 6, 9, 0, 0, 0, 0, 1, 1, 1);// TODO not sure about sign of view_offset break; case Discovery600: @@ -338,7 +338,7 @@ Scanner::Scanner(Type scanner_type) static_cast(-4.5490*_PI/180),//sign? TODO value 4, 2, - 6, 8, 0, 0, 1, 1, 1); + 6, 8, 0, 0, 0, 0, 1, 1, 1); break; @@ -356,7 +356,7 @@ case PETMR_Signa: static_cast(-5.23*_PI/180),//sign? TODO value 5, 4, - 9, 4, 0, 0, 1, 1, 1, + 9, 4, 0, 0, 0, 0, 1, 1, 1, 0.105F, // energy resolution from Levin et al. TMI 2016 511.F); break; @@ -376,7 +376,7 @@ break; static_cast(-5.021*_PI/180),//sign? TODO value 4, 2, - 6, 9, 0, 0, 1, 1, 1 + 6, 9, 0, 0, 0, 0, 1, 1, 1 #ifdef STIR_TOF , (short int)(55), @@ -404,6 +404,7 @@ break; 3, 4, 9, 4, 0, 0, + 0, 0, 1, 1, 1, 0.0944F, // energy resolution from Hsu et al. 2017 @@ -427,6 +428,7 @@ break; 4, 4, 9, 4, 0, 0, + 0, 0, 1, 1, 1, 0.0944F, // energy resolution from Hsu et al. 2017 @@ -438,7 +440,7 @@ break; set_params(HZLR, string_list("Positron HZL/R"), 32, 256, 2 * 192, 780.0F, 7.0F, 5.1875F, 2.F, 0.0F, - 0, 0, 0, 0, 0, 0, 0,0, 1); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); // Default 7.0mm average interaction depth. // crystals per singles unit etc unknown break; @@ -448,7 +450,7 @@ break; set_params(HRRT, string_list("HRRT"), 104, 288, 2 * 288, 234.765F, 7.0F, 2.4375F, 1.21875F, 0.0F, - 0, 0, 0, 0, 0, 0, 0, 0, 2); // added by Dylan Togane + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2); // added by Dylan Togane // warning: used 7.0mm average interaction depth. // crystals per singles unit etc unknown break; @@ -482,6 +484,7 @@ break; 6.3F, 4.3F, 0.0F, 1, 0, 29, 0 /* 23* or 22*/, + 0, 0, 0, 0, 29, 0 /* all detectors in a ring? */, 1); @@ -495,7 +498,8 @@ break; 4.F, 4.F, 0.F, 0, 0, 0, 0, // Not considering any gap, but this is per module 28 flat modules in total, while 420 PMTs - 0, 0 /* Not sure about these, but shouldn't be important */, + 0, 0 /* Not sure about these, but shouldn't be important */, + 0, 0, 0, 0, 1); break; @@ -504,7 +508,7 @@ break; set_params(HiDAC, string_list("HiDAC"), 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; @@ -513,7 +517,7 @@ break; set_params(User_defined_scanner, string_list("Userdefined"), 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; @@ -522,7 +526,7 @@ break; set_params(Unknown_scanner, string_list("Unknown"), 0, 0, 0, 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; @@ -540,6 +544,7 @@ Scanner::Scanner(Type type_v, const list& list_of_names_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -556,6 +561,7 @@ Scanner::Scanner(Type type_v, const list& list_of_names_v, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, num_virtual_axial_crystals_per_block_v, num_virtual_transaxial_crystals_per_block_v, + num_virtual_axial_crystals_per_bucket_v, num_virtual_transaxial_crystals_per_bucket_v, num_axial_crystals_per_singles_unit_v, num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, @@ -574,6 +580,7 @@ Scanner::Scanner(Type type_v, const string& name, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -590,6 +597,7 @@ Scanner::Scanner(Type type_v, const string& name, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, num_virtual_axial_crystals_per_block_v, num_virtual_transaxial_crystals_per_block_v, + num_virtual_axial_crystals_per_bucket_v, num_virtual_transaxial_crystals_per_bucket_v, num_axial_crystals_per_singles_unit_v, num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, @@ -616,6 +624,7 @@ set_params(Type type_v,const list& list_of_names_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -632,6 +641,7 @@ set_params(Type type_v,const list& list_of_names_v, num_axial_blocks_per_bucket_v, num_transaxial_blocks_per_bucket_v, num_axial_crystals_per_block_v, num_transaxial_crystals_per_block_v, num_virtual_axial_crystals_per_block_v, num_virtual_transaxial_crystals_per_block_v, + num_virtual_axial_crystals_per_bucket_v, num_virtual_transaxial_crystals_per_bucket_v, num_axial_crystals_per_singles_unit_v, num_transaxial_crystals_per_singles_unit_v, num_detector_layers_v, @@ -654,6 +664,7 @@ set_params(Type type_v,const list& list_of_names_v, int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -677,6 +688,8 @@ set_params(Type type_v,const list& list_of_names_v, num_transaxial_crystals_per_block= num_transaxial_crystals_per_block_v; num_virtual_axial_crystals_per_block= num_virtual_axial_crystals_per_block_v; num_virtual_transaxial_crystals_per_block= num_virtual_transaxial_crystals_per_block_v; + num_virtual_axial_crystals_per_bucket = num_virtual_axial_crystals_per_bucket_v; + num_virtual_transaxial_crystals_per_bucket = num_virtual_transaxial_crystals_per_bucket_v; num_axial_crystals_per_singles_unit = num_axial_crystals_per_singles_unit_v; num_transaxial_crystals_per_singles_unit = num_transaxial_crystals_per_singles_unit_v; num_detector_layers = num_detector_layers_v; @@ -689,74 +702,34 @@ set_params(Type type_v,const list& list_of_names_v, } -/*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). - */ int Scanner:: get_num_virtual_axial_crystals_per_block() const { -// switch(get_type()) -// { -// case E1080: -// case Siemens_mCT: -// return 1; -// default: -// return 0; -// } return num_virtual_axial_crystals_per_block; } -/*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). - */ int Scanner:: get_num_virtual_transaxial_crystals_per_block() const { -// switch(get_type()) -// { -// case E1080: -// case Siemens_mCT: -// case Siemens_mMR: -// return 1; -// default: -// return 0; -// } return num_virtual_transaxial_crystals_per_block; } int Scanner:: -get_num_virtual_axial_crystals() const +get_num_virtual_axial_crystals_per_bucket() const { -// switch(get_type()) -// { -// case E1080: -// case Siemens_mCT: -// return 1; -// default: -// return 0; -// } - return num_virtual_axial_crystals_per_block * get_num_axial_blocks(); + return num_virtual_axial_crystals_per_bucket; } -/*! \todo The current list is bound to be incomplete. would be better to stick it in set_params(). - */ int Scanner:: -get_num_virtual_transaxial_crystals() const +get_num_virtual_transaxial_crystals_per_bucket() const { -// switch(get_type()) -// { -// case E1080: -// case Siemens_mCT: -// case Siemens_mMR: -// return 1; -// default: -// return 0; -// } - return num_virtual_transaxial_crystals_per_block * get_num_transaxial_blocks(); + return num_virtual_transaxial_crystals_per_bucket; } -/*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ + void Scanner:: set_num_virtual_axial_crystals_per_block(int val) @@ -764,7 +737,7 @@ set_num_virtual_axial_crystals_per_block(int val) num_virtual_axial_crystals_per_block = val; } -/*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ + void Scanner:: set_num_virtual_transaxial_crystals_per_block(int val) @@ -944,6 +917,8 @@ if (!close_enough(energy_resolution, scanner.energy_resolution) && (num_transaxial_crystals_per_block == scanner.num_transaxial_crystals_per_block) && (num_virtual_axial_crystals_per_block == scanner.num_virtual_axial_crystals_per_block) && (num_virtual_transaxial_crystals_per_block == scanner.num_virtual_transaxial_crystals_per_block) && + (num_virtual_axial_crystals_per_bucket == scanner.num_virtual_axial_crystals_per_bucket) && + (num_virtual_transaxial_crystals_per_bucket == scanner.num_virtual_transaxial_crystals_per_bucket) && (num_detector_layers == scanner.num_detector_layers) && (num_axial_crystals_per_singles_unit == scanner.num_axial_crystals_per_singles_unit) && (num_transaxial_crystals_per_singles_unit == scanner.num_transaxial_crystals_per_singles_unit); @@ -1010,6 +985,10 @@ Scanner::parameter_info() const << get_num_virtual_axial_crystals_per_block() << '\n' << "Number of Virtual crystals per block in transaxial direction := " << get_num_virtual_transaxial_crystals_per_block() << '\n' + << "Number of Virtual crystals per bucket in axial direction := " + << get_num_virtual_axial_crystals_per_bucket() << '\n' + << "Number of Virtual crystals per bucket in transaxial direction := " + << get_num_virtual_transaxial_crystals_per_bucket() << '\n' << "Number of detector layers := " << get_num_detector_layers() << '\n' << "Number of crystals per singles unit in axial direction := " @@ -1115,6 +1094,10 @@ Scanner* Scanner::ask_parameters() ask_num("Enter number of virtual axial crystals per block: ",0,12,0); int VirtualTransaxialCrystalsPerBlock = ask_num("Enter number of virtual transaxial crystals per block: ",0,12,0); + int VirtualAxialCrystalsPerBucket = + ask_num("Enter number of virtual axial crystals per bucket: ",0,12,0); + int VirtualTransaxialCrystalsPerBucket = + ask_num("Enter number of virtual transaxial crystals per bucket: ",0,12,0); int AxialCrstalsPerSinglesUnit = ask_num("Enter number of axial crystals per singles unit: ", 0, NoRings, 1); int TransaxialCrystalsPerSinglesUnit = @@ -1140,6 +1123,7 @@ Scanner* Scanner::ask_parameters() AxialBlocksPerBucket,TransBlocksPerBucket, AxialCrystalsPerBlock,TransaxialCrystalsPerBlock, VirtualAxialCrystalsPerBlock, VirtualTransaxialCrystalsPerBlock, + VirtualAxialCrystalsPerBucket, VirtualTransaxialCrystalsPerBucket, AxialCrstalsPerSinglesUnit, TransaxialCrystalsPerSinglesUnit, num_detector_layers, EnergyResolution, @@ -1154,6 +1138,7 @@ Scanner* Scanner::ask_parameters() AxialBlocksPerBucket,TransBlocksPerBucket, AxialCrystalsPerBlock,TransaxialCrystalsPerBlock, VirtualAxialCrystalsPerBlock, VirtualTransaxialCrystalsPerBlock, + VirtualAxialCrystalsPerBucket, VirtualTransaxialCrystalsPerBucket, AxialCrstalsPerSinglesUnit, TransaxialCrystalsPerSinglesUnit, num_detector_layers); diff --git a/src/include/stir/Scanner.h b/src/include/stir/Scanner.h index 156b39544d..4bc8fb8d56 100644 --- a/src/include/stir/Scanner.h +++ b/src/include/stir/Scanner.h @@ -139,6 +139,7 @@ class Scanner int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -159,6 +160,7 @@ class Scanner int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -192,8 +194,12 @@ class Scanner //! get number of rings inline int get_num_rings() const; + //! get number of rings + axial gaps + inline int get_num_logical_rings() const; //! get the number of detectors per ring inline int get_num_detectors_per_ring() const; + //! get the number of detectors and gaps per ring + inline int get_num_logical_detectors_per_ring() const; //! get the maximum number of arccorrected tangential positions /*! \warning name is not in standard STIR terminology. Should be \c get_max_num_non_arccorrected_tangential_poss() or so. @@ -280,8 +286,10 @@ class Scanner //@{! int get_num_virtual_axial_crystals_per_block() const; int get_num_virtual_transaxial_crystals_per_block() const; - int get_num_virtual_axial_crystals() const; - int get_num_virtual_transaxial_crystals() const; + + int get_num_virtual_axial_crystals_per_bucket() const; + int get_num_virtual_transaxial_crystals_per_bucket() const; + void set_num_virtual_axial_crystals_per_block(int); void set_num_virtual_transaxial_crystals_per_block(int); //@} @@ -396,6 +404,10 @@ class Scanner int num_axial_crystals_per_singles_unit; int num_transaxial_crystals_per_singles_unit; + int num_virtual_axial_crystals_per_bucket; + + int num_virtual_transaxial_crystals_per_bucket; + //! //! \brief energy_resolution //! \author Nikos Efthimiou @@ -424,6 +436,7 @@ class Scanner int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, @@ -443,6 +456,7 @@ class Scanner int num_axial_blocks_per_bucket_v, int num_transaxial_blocks_per_bucket_v, int num_axial_crystals_per_block_v, int num_transaxial_crystals_per_block_v, int num_virtual_axial_crystals_per_block_v, int num_virtual_transaxial_crystals_per_block_v, + int num_virtual_axial_crystals_per_bucket_v, int num_virtual_transaxial_crystals_per_bucket_v, int num_axial_crystals_per_singles_unit_v, int num_transaxial_crystals_per_singles_unit_v, int num_detector_layers_v, diff --git a/src/include/stir/Scanner.inl b/src/include/stir/Scanner.inl index c38f289cf2..8576def297 100644 --- a/src/include/stir/Scanner.inl +++ b/src/include/stir/Scanner.inl @@ -52,6 +52,16 @@ Scanner::get_num_detectors_per_ring() const { return num_detectors_per_ring;} int +Scanner::get_num_logical_rings() const +{ return num_rings + get_num_virtual_axial_crystals_per_bucket() * get_num_axial_buckets() + + get_num_virtual_axial_crystals_per_block() * get_num_axial_blocks(); +} +int +Scanner::get_num_logical_detectors_per_ring() const +{ + return num_detectors_per_ring+ get_num_virtual_transaxial_crystals_per_bucket() * get_num_transaxial_buckets() + + get_num_virtual_transaxial_crystals_per_block() * get_num_transaxial_blocks();} +int Scanner::get_max_num_non_arccorrected_bins() const { return max_num_non_arccorrected_bins;} diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index b1f46e7f97..46cc03e56c 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -46,6 +46,8 @@ CListModeDataROOT(const std::string& hroot_filename) std::string error_str; int num_virtual_axial_crystals_per_block = -1; // -1 means: use scanner default int num_virtual_transaxial_crystals_per_block = -1; // -1 means: use scanner default + int num_virtual_axial_crystals_per_bucket = -1; // -1 means: use scanner default + int num_virtual_transaxial_crystals_per_bucket = -1; // -1 means: use scanner default this->parser.add_start_key("ROOT header"); this->parser.add_stop_key("End ROOT header"); @@ -64,6 +66,8 @@ CListModeDataROOT(const std::string& hroot_filename) this->parser.add_key("Default number of arc-corrected bins", &this->default_num_arccorrected_bins); this->parser.add_key("Number of virtual axial crystals per block", &num_virtual_axial_crystals_per_block); this->parser.add_key("Number of virtual transaxial crystals per block", &num_virtual_transaxial_crystals_per_block); + this->parser.add_key("Number of virtual axial crystals per bucket", &num_virtual_axial_crystals_per_bucket); + this->parser.add_key("Number of virtual transaxial crystals per bucket", &num_virtual_transaxial_crystals_per_bucket); // end Scanner and physical dimensions. // ROOT related @@ -147,6 +151,8 @@ CListModeDataROOT(const std::string& hroot_filename) this->root_file_sptr->get_num_transaxial_crystals_per_block_v(), num_virtual_axial_crystals_per_block, num_virtual_transaxial_crystals_per_block, + num_virtual_axial_crystals_per_bucket, + num_virtual_transaxial_crystals_per_bucket, /*num_axial_crystals_per_singles_unit_v*/ this->root_file_sptr->get_num_axial_crystals_per_singles_unit(), /*num_transaxial_crystals_per_singles_unit_v*/ From 61fc99731756e35c2528c0013accea79de6ff98d Mon Sep 17 00:00:00 2001 From: NikEfth Date: Wed, 23 Dec 2020 19:17:35 -0500 Subject: [PATCH 8/8] Proposal for Scanner template with virtual crystals after blocks and buckets. --- src/buildblock/Scanner.cxx | 35 ++++++++++++++-------------- src/include/stir/Scanner.h | 17 +++++++------- src/include/stir/Scanner.inl | 45 +++++++++++++++++++++--------------- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index 8515002dd5..4accd5b51e 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -124,7 +124,7 @@ Scanner::Scanner(Type scanner_type) set_params(E931, string_list("ECAT 931"), 8, 192, 2 * 256, 510.0F, 7.0F, 13.5F, 3.129F, 0.0F, - 2, 4, 4, 8, 0, 0, 4, 0, 0, 8 * 4, 1, + 2, 4, 4, 8, 0, 0, 0, 0, 4, 8 * 4, 1, 0.37f, 511.f); // 16 BUCKETS per ring in TWO rings - i.e. 32 buckets in total @@ -190,7 +190,7 @@ Scanner::Scanner(Type scanner_type) case E1080: // data added by Robert Barnett, Westmead Hospital, Sydney set_params(E1080, string_list("ECAT 1080", "Biograph 16", "1080"), - 41, 336, 2* 336, + 39, 336, 13*48, 412.0F, 7.0F, 4.0F, 2.000F, 0.0F, 1, 2, 13, 13, 1, 1, 0, 0, 0, 0, 1);// TODO bucket/singles info? // Transaxial blocks have 13 physical crystals and a gap at the @@ -213,9 +213,9 @@ Scanner::Scanner(Type scanner_type) case Siemens_mCT: // 13x13 blocks, 1 virtual "crystal" along axial and transaxial direction, 48 blocks along the ring, 4 blocks in axial direction set_params(Siemens_mCT, string_list("Siemens mCT", "mCT", "2011", "1104" /* used in norm files */, "1094" /* used in attenuation files */), - 55, 400, (13+1)*48, + 52, 400, 13*48, 421.0F, 7.0F, 4.054F, 2.005F, 0.0F, - 4, 1, 13, 13, 1, 1, 0, 0, 0,0, 1 ); // TODO singles info incorrect + 4, 1, 13, 13, 1, 1, 0, 0, 0, 0, 1 ); // TODO singles info incorrect // energy: 435-650 // 13 TOF bins break; @@ -761,13 +761,14 @@ check_consistency() const this->get_name().c_str()); else { - const int dets_per_ring = - get_num_transaxial_blocks() * - (get_num_transaxial_crystals_per_block() + get_num_virtual_transaxial_crystals_per_block()); - if ( dets_per_ring != get_num_detectors_per_ring()) + const int dets_per_ring = + get_num_transaxial_buckets() * get_num_transaxial_blocks_per_bucket() * + get_num_transaxial_crystals_per_block()+ + get_num_transaxial_buckets()*get_num_virtual_transaxial_crystals_per_bucket(); + if ( dets_per_ring != get_num_detectors_per_ring()) { - warning("Scanner %s: inconsistent transaxial block info", - this->get_name().c_str()); + warning("Scanner %s: inconsistent transaxial block info %d instead of %d", + this->get_name().c_str(), dets_per_ring, get_num_detectors_per_ring()); return Succeeded::no; } } @@ -798,13 +799,13 @@ check_consistency() const else { const int dets_axial = - get_num_axial_blocks() * - (get_num_axial_crystals_per_block() + get_num_virtual_axial_crystals_per_block()); - if ( dets_axial != (get_num_rings() + get_num_virtual_axial_crystals_per_block())) + get_num_axial_buckets() * get_num_axial_blocks_per_bucket() * + get_num_axial_crystals_per_block() + get_num_axial_buckets()*get_num_virtual_axial_crystals_per_bucket(); + if ( dets_axial != get_num_rings()) { warning("Scanner %s: inconsistent axial block info: %d vs %d", this->get_name().c_str(), - dets_axial, get_num_rings() + get_num_virtual_axial_crystals_per_block()); + dets_axial, get_num_rings()); return Succeeded::no; } } @@ -955,7 +956,7 @@ Scanner::parameter_info() const s << "Scanner type := " << get_name() <<'\n'; s << "Number of rings := " << num_rings << '\n'; - s << "Number of detectors per ring := " << get_num_detectors_per_ring() << '\n'; + s << "Number of detectors per ring := " << num_detectors_per_ring << '\n'; s << "Inner ring diameter (cm) := " << get_inner_ring_radius()*2./10 << '\n' << "Average depth of interaction (cm) := " << get_average_depth_of_interaction() / 10 << '\n' @@ -978,9 +979,9 @@ Scanner::parameter_info() const << "Number of blocks per bucket in axial direction := " << get_num_axial_blocks_per_bucket() << '\n' << "Number of crystals per block in axial direction := " - << get_num_axial_crystals_per_block() << '\n' + << num_axial_crystals_per_block << '\n' << "Number of crystals per block in transaxial direction := " - << get_num_transaxial_crystals_per_block() << '\n' + << num_transaxial_crystals_per_block << '\n' << "Number of Virtual crystals per block in axial direction := " << get_num_virtual_axial_crystals_per_block() << '\n' << "Number of Virtual crystals per block in transaxial direction := " diff --git a/src/include/stir/Scanner.h b/src/include/stir/Scanner.h index 4bc8fb8d56..68a25eddce 100644 --- a/src/include/stir/Scanner.h +++ b/src/include/stir/Scanner.h @@ -116,7 +116,7 @@ class Scanner to flag up an error and do some guess work in trying to recognise the scanner from any given parameters. */ - enum Type {E931, E951, E953, E921, E925, E961, E962, E966, E1080, Siemens_mMR,Siemens_mCT, RPT,HiDAC, + enum Type {E931, Siemens_mCT, E951, E953, E921, E925, E961, E962, E966, E1080, Siemens_mMR, RPT,HiDAC, Advance, DiscoveryLS, DiscoveryST, DiscoverySTE, DiscoveryRX, Discovery600, PETMR_Signa, Discovery690, DiscoveryMI3ring, DiscoveryMI4ring, HZLR, RATPET, PANDA, HYPERimage, nanoPET, HRRT, Allegro, GeminiTF, User_defined_scanner, Unknown_scanner}; @@ -192,14 +192,11 @@ class Scanner //! \name Functions returning geometrical info //@{ - //! get number of rings + //! get number of rings. This function returns the total number of rings + gaps inline int get_num_rings() const; - //! get number of rings + axial gaps - inline int get_num_logical_rings() const; - //! get the number of detectors per ring + //! get the number of detectors per ring. This function returns the total + //! number of detectors + gasp in the ring. inline int get_num_detectors_per_ring() const; - //! get the number of detectors and gaps per ring - inline int get_num_logical_detectors_per_ring() const; //! get the maximum number of arccorrected tangential positions /*! \warning name is not in standard STIR terminology. Should be \c get_max_num_non_arccorrected_tangential_poss() or so. @@ -314,9 +311,11 @@ class Scanner // zlong, 08-04-2004, add set_methods //! set scanner type inline void set_type(const Type & new_type); - //! set number of rings + //! set number of rings. This function will set the total number of rings + //! reseting the virtual crystals to the axial direction to 0. inline void set_num_rings(const int & new_num); - //! set the namber of detectors per ring + //! set the namber of detectors per ring. This function will set the total number + //! of detectors per ring, reseting the number of virtual crystals to 0. inline void set_num_detectors_per_ring(const int & new_num) ; //! set the maximum number of arccorrected bins inline void set_max_num_non_arccorrected_bins(const int & new_num) ; diff --git a/src/include/stir/Scanner.inl b/src/include/stir/Scanner.inl index 8576def297..e2c8935efb 100644 --- a/src/include/stir/Scanner.inl +++ b/src/include/stir/Scanner.inl @@ -46,21 +46,17 @@ Scanner::get_type() const int Scanner::get_num_rings() const -{ return num_rings;} -int -Scanner::get_num_detectors_per_ring() const { - return num_detectors_per_ring;} -int -Scanner::get_num_logical_rings() const -{ return num_rings + get_num_virtual_axial_crystals_per_bucket() * get_num_axial_buckets() + + return num_rings + get_num_virtual_axial_crystals_per_bucket() * get_num_axial_buckets() + get_num_virtual_axial_crystals_per_block() * get_num_axial_blocks(); } int -Scanner::get_num_logical_detectors_per_ring() const +Scanner::get_num_detectors_per_ring() const { - return num_detectors_per_ring+ get_num_virtual_transaxial_crystals_per_bucket() * get_num_transaxial_buckets() + - get_num_virtual_transaxial_crystals_per_block() * get_num_transaxial_blocks();} + return num_detectors_per_ring + get_num_virtual_transaxial_crystals_per_bucket() * get_num_transaxial_buckets() + + get_num_virtual_transaxial_crystals_per_block() * get_num_transaxial_blocks(); +} + int Scanner::get_max_num_non_arccorrected_bins() const { return max_num_non_arccorrected_bins;} @@ -126,13 +122,15 @@ Scanner::get_num_axial_blocks_per_bucket() const int Scanner::get_num_axial_crystals_per_block() const { - return num_axial_crystals_per_block; + return num_axial_crystals_per_block + + get_num_virtual_axial_crystals_per_block(); } int Scanner::get_num_transaxial_crystals_per_block()const { - return num_transaxial_crystals_per_block; + return (num_transaxial_crystals_per_block + + get_num_virtual_transaxial_crystals_per_block()); } @@ -141,7 +139,8 @@ Scanner::get_num_axial_crystals_per_bucket() const { return get_num_axial_blocks_per_bucket() * - get_num_axial_crystals_per_block(); + get_num_axial_crystals_per_block() + + get_num_virtual_axial_crystals_per_bucket(); } @@ -150,7 +149,8 @@ Scanner::get_num_transaxial_crystals_per_bucket() const { return get_num_transaxial_blocks_per_bucket() * - get_num_transaxial_crystals_per_block(); + get_num_transaxial_crystals_per_block() + + get_num_virtual_transaxial_crystals_per_bucket(); } int @@ -164,25 +164,28 @@ Scanner::get_num_axial_blocks() const { // when using virtual crystals between blocks, there won't be one at the end, so we // need to take this into account. - return (num_rings+get_num_virtual_axial_crystals_per_block())/num_axial_crystals_per_block; + return (num_rings)/num_axial_crystals_per_block; } int Scanner::get_num_transaxial_blocks() const { - return num_detectors_per_ring/(num_transaxial_crystals_per_block+num_virtual_transaxial_crystals_per_block); + return num_transaxial_crystals_per_block == 0 ? num_detectors_per_ring : + num_detectors_per_ring/(num_transaxial_crystals_per_block); } int Scanner::get_num_axial_buckets() const { - return get_num_axial_blocks()/num_axial_blocks_per_bucket; + return num_axial_blocks_per_bucket == 0 ? get_num_axial_blocks() : + get_num_axial_blocks()/num_axial_blocks_per_bucket; } int Scanner::get_num_transaxial_buckets() const { - return get_num_transaxial_blocks()/num_transaxial_blocks_per_bucket; + return num_transaxial_blocks_per_bucket== 0 ? get_num_transaxial_blocks() : + get_num_transaxial_blocks()/num_transaxial_blocks_per_bucket; } @@ -250,11 +253,15 @@ void Scanner::set_type(const Type & new_type) void Scanner::set_num_rings(const int & new_num) { + num_virtual_axial_crystals_per_bucket = 0; + num_virtual_axial_crystals_per_block = 0; num_rings = new_num; } -void Scanner::set_num_detectors_per_ring(const int & new_num) +void Scanner::set_num_detectors_per_ring(const int & new_num) { + num_virtual_transaxial_crystals_per_bucket = 0; + num_virtual_transaxial_crystals_per_block = 0; num_detectors_per_ring = new_num; }