8 #include "iScannerPET.hh" 9 #include "sOutputManager.hh" 10 #include "sScannerManager.hh" 83 Cout(
"iScannerPET::DescribeSpecific() -> Here is some specific content of the PET scanner" << endl);
91 if(l>0)
Cout(
" --> Layer "<<l<<
":"<< endl);
127 if (
m_verbose>=
VERBOSE_NORMAL)
Cout(
"iScannerPET::Instantiate() -> Create scanner structure and read parameters from configuration file"<< endl);
136 Cerr(
"***** iScannerPET::Instantiate() -> An error occurred while trying to read the number of layers in the scanner header file !" << endl);
142 Cerr(
"***** iScannerPET::Instantiate() -> Incorrect value for the number of layer (must be >0) !" << endl);
148 Cerr(
"***** iScannerPET::Instantiate() -> An error occurred while trying to read the number of elements in the scanner header file !" << endl);
176 if (a_scannerFileIsLUT)
183 Cerr(
"***** iScannerPET::Instantiate() -> An error occurred while trying to read the crystals size in the scanner header file !" << endl);
194 Cerr(
"***** iScannerPET::Instantiate() -> An error occurred while trying to read the crystals size in the scanner header file !" << endl);
211 Cerr(
"***** iScannerPET::Instantiate() -> An error occurred while trying to read the mean depth of interaction in the scanner header file !" << endl);
216 Cerr(
"***** iScannerPET::Instantiate() -> An error occurred while trying to read the min angle difference in the scanner header file !" << endl);
221 Cerr(
"***** iScannerPET::Instantiate() -> An error occurred while trying to read the multiple bed displacement in the scanner header file !" << endl);
251 if (
m_verbose>=
VERBOSE_NORMAL)
Cout(
"iScannerPET::BuildLUT() -> Build LUT for scanner elements coordinates and orientations"<< endl);
254 if (!a_scannerFileIsLUT)
258 Cerr(
"***** iScannerPET::BuildLUT() -> A problem occurred while generating scanner LUT !" << endl);
266 Cerr(
"***** iScannerPET::BuildLUT() -> A problem occurred while loading scanner LUT !" << endl);
291 Cerr(
"***** iScannerPET::CheckParameters() -> Scanner type not initialized !" << endl);
296 Cerr(
"***** iScannerPET::CheckParameters() -> Verbosity not initialized !" << endl);
301 Cerr(
"***** iScannerPET::CheckParameters() -> Incorrect value for the number of layer (must be >0) !" << endl);
306 Cerr(
"***** iScannerPET::CheckParameters() -> Number of crystals not initialized !" << endl);
311 Cerr(
"***** iScannerPET::CheckParameters() -> Number of crystals in layer(s) not initialized !" << endl);
316 Cerr(
"***** iScannerPET::CheckParameters() -> Crystals central positions not initialized !" << endl);
321 Cerr(
"***** iScannerPET::CheckParameters() -> Crystals orientations not initialized !" << endl);
326 Cerr(
"***** iScannerPET::CheckParameters() -> Crystals dimensions not initialized !" << endl);
331 Cout(
"***** iScannerPET::CheckParameters() -> Mean depth of interaction not initialized !" << endl);
336 Cerr(
"***** iScannerPET::CheckParameters() -> Minimum angle difference not initialized !" << endl);
341 Cerr(
"***** iScannerPET::CheckParameters() -> Scanner type not initialized !" << endl);
346 Cerr(
"***** iScannerPET::CheckParameters() -> Scanner type not initialized !" << endl);
373 Cerr(
"***** iScannerPET::Initialize() -> Parameters have not been checked !" << endl);
411 Cerr(
"***** iScannerPET::LoadLUT() -> An error occurred while trying to read a mandatory parameter in the scanner header file !" << endl);
419 scanner_lut_file = scanner_lut_file.substr(0, scanner_lut_file.find_last_of(
".")).append(
".lut");
422 FILE* LUT_file = fopen(scanner_lut_file.c_str(),
"rb");
425 Cerr(
"***** iScannerPET::LoadLUT() -> Input LUT file '" << scanner_lut_file <<
"' is missing or corrupted !" << endl);
430 int nb_data_read = 0;
435 nb_data_read += fread(&buffer,
sizeof(
FLTNBLUT),1,LUT_file);
437 nb_data_read += fread(&buffer,
sizeof(
FLTNBLUT),1,LUT_file);
439 nb_data_read += fread(&buffer,
sizeof(
FLTNBLUT),1,LUT_file);
442 nb_data_read += fread(&buffer,
sizeof(
FLTNBLUT),1,LUT_file);
444 nb_data_read += fread(&buffer,
sizeof(
FLTNBLUT),1,LUT_file);
446 nb_data_read += fread(&buffer,
sizeof(
FLTNBLUT),1,LUT_file);
454 if (nb_data_read!=m_nbCrystals*6)
456 Cerr(
"***** iScannerPET::LoadLUT() -> Failed to read all data in input LUT file '" << scanner_lut_file <<
"' !" << endl);
489 int *nb_ang_rsector_lyr,
499 *rsector_first_angle_lyr,
500 *rsector_angular_span_lyr,
501 *gap_axl_rsector_lyr,
506 *gap_trs_crystal_lyr,
507 *gap_axl_crystal_lyr;
529 string rotation_direction =
"";
541 Cerr(
"***** iScannerPET::ComputeLUT() -> An error occurred while trying to read a mandatory parameter for scanner LUT generation in the scanner header file !" << endl);
551 nb_axl_rsector_lyr[ l ] =1;
552 nb_trs_mod_lyr[ l ] =1;
553 nb_axl_mod_lyr[ l ] =1;
554 nb_trs_submod_lyr[ l ] = 1;
555 nb_axl_submod_lyr[ l ] = 1;
556 gap_axl_rsector_lyr[ l ] = 0.;
557 gap_trs_mod_lyr[ l ] = 0.;
558 gap_axl_mod_lyr[ l ] = 0.;
559 gap_trs_submod_lyr[ l ] = 0.;
560 gap_axl_submod_lyr[ l ] = 0.;
561 gap_trs_crystal_lyr[ l ] = 0.;
562 gap_axl_crystal_lyr[ l ] = 0.;
563 rsector_first_angle_lyr[ l ] = 0;
564 rsector_angular_span_lyr[ l ] = 360.;
583 Cerr(
"***** iScannerPET::ComputeLUT() -> An error occurred while trying to read an optionnal parameter for scanner LUT generation in the scanner header file !" << endl);
588 uint16_t *p_nbRings =
new uint16_t[
m_nbLayers];
590 p_nbRings[lyr] = nb_axl_rsector_lyr[ lyr ]
591 * nb_axl_mod_lyr[ lyr ]
592 * nb_axl_submod_lyr[ lyr ]
593 * nb_axl_crystal_lyr[ lyr ];
598 Cerr(
"***** iScannerPET::ComputeLUT() ->Error occurred while trying to initialize head rotation orientation " << endl);
605 int rsector_nb_zshift;
613 Cerr(
"***** iScannerPET::ComputeLUT() -> Error occurred when trying to read z-shift nb !" << endl);
617 else if( rvalue > 1 || rsector_nb_zshift==0)
619 rsector_nb_zshift = 1;
620 zshift =
new FLTNBLUT[rsector_nb_zshift];
626 zshift =
new FLTNBLUT[rsector_nb_zshift];
630 Cerr(
"***** iScannerPET::ComputeLUT() -> No data found about modules z-shift in the scanner header file, whereas z-shift is enabled !" << endl);
636 int nb_crystals_cur = 0;
644 int nb_ang_rsector = nb_ang_rsector_lyr[lyr],
645 nb_axl_rsector = nb_axl_rsector_lyr[lyr],
646 nb_trs_mod = nb_trs_mod_lyr[lyr],
647 nb_axl_mod = nb_axl_mod_lyr[lyr],
648 nb_trs_submod = nb_trs_submod_lyr[lyr],
649 nb_axl_submod = nb_axl_submod_lyr[lyr],
650 nb_trs_crystal = nb_trs_crystal_lyr[lyr],
651 nb_axl_crystal = nb_axl_crystal_lyr[lyr];
654 rsector_first_angle = rsector_first_angle_lyr[lyr],
655 angular_span = rsector_angular_span_lyr[lyr],
656 gap_axl_rsector = gap_axl_rsector_lyr[lyr],
657 gap_trs_mod = gap_trs_mod_lyr[lyr],
658 gap_axl_mod = gap_axl_mod_lyr[lyr],
659 gap_trs_submod = gap_trs_submod_lyr[lyr],
660 gap_axl_submod = gap_axl_submod_lyr[lyr],
661 gap_trs_crystal = gap_trs_crystal_lyr[lyr],
662 gap_axl_crystal = gap_axl_crystal_lyr[lyr];
666 FLTNBLUT size_trs_mod = nb_trs_submod*size_trs_submod + (nb_trs_submod-1)*gap_trs_submod;
667 FLTNBLUT size_axl_mod = nb_axl_submod*size_axl_submod + (nb_axl_submod-1)*gap_axl_submod;
668 FLTNBLUT size_trs_rsector = nb_trs_mod*size_trs_mod + (nb_trs_mod-1)*gap_trs_mod;
669 FLTNBLUT size_axl_rsector = nb_axl_mod*size_axl_mod + (nb_axl_mod-1)*gap_axl_mod;
672 int nb_rsectors = nb_ang_rsector * nb_axl_rsector;
673 int nb_mod = nb_axl_mod * nb_trs_mod;
674 int nb_submod = nb_axl_submod * nb_trs_submod;
675 int nb_crystal = nb_axl_crystal * nb_trs_crystal;
678 int nb_crystals = nb_rsectors*nb_mod*nb_submod*nb_crystal + nb_crystals_cur;
679 if(m_nbCrystals<nb_crystals)
681 Cerr(
"***** iScannerPET::ComputeLUT() -> Computed number of crystals computed from the geom file ("<< nb_crystals
682 <<
") > not consistent with the total number of crystals (including potential layers) provided in the geom file ("<< m_nbCrystals <<
") !" << endl);
696 oMatrix ******crystal_center =
new oMatrix *****[nb_ang_rsector+1];
698 for(
int rsa = 0; rsa < nb_ang_rsector+1 ; rsa++)
700 crystal_center[rsa] =
new oMatrix ****[ nb_axl_rsector ];
702 for (
int i = 0; i<nb_axl_rsector ; i++)
704 crystal_center[rsa][i] =
new oMatrix ***[ nb_mod ];
706 for (
int j = 0; j<nb_mod ; j++)
708 crystal_center[rsa][i][j] =
new oMatrix **[ nb_submod ];
710 for (
int k = 0; k<nb_submod; k++)
712 crystal_center[rsa][i][j][k] =
new oMatrix*[ nb_crystal ];
714 for (
int l = 0; l<nb_crystal; l++)
716 crystal_center[rsa][i][j][k][l] =
new oMatrix(3,1);
728 for(
int i=0; i<nb_ang_rsector; i++)
729 rotation_mtx[i] =
new oMatrix(3,3);
732 FLTNBLUT rsector_first_angle_rad = rsector_first_angle*M_PI/180.;
733 FLTNBLUT angular_span_rad = angular_span*M_PI/180.;
739 for (
int i = 0; i<nb_ang_rsector; i++)
741 FLTNBLUT angle = remainderf(rsector_first_angle_rad + ((
FLTNBLUT)i)*angular_span_rad/((
FLTNBLUT)(nb_ang_rsector)), 2.*M_PI);
755 for (
int r=0; r < nb_axl_rsector ; r++)
758 FLTNBLUT x_start_r = (-dir*size_trs_rsector) / 2.;
759 FLTNBLUT z_start_r = -(nb_axl_rsector*size_axl_rsector + (nb_axl_rsector-1)*gap_axl_rsector) / 2.;
761 z_start_r += r * (size_axl_rsector + gap_axl_rsector);
763 for (
int i=0; i < nb_mod ; i++)
771 x_start_m += dir*(i%nb_trs_mod) * (size_trs_mod + gap_trs_mod);
772 z_start_m += int(i/nb_trs_mod) * (size_axl_mod + gap_axl_mod);
774 for (
int j=0 ; j < nb_submod ; j++)
779 x_start_sm += dir*(j%nb_trs_submod) * (size_trs_submod + gap_trs_submod);
780 z_start_sm += int(j/nb_trs_submod) * (size_axl_submod + gap_axl_submod);
782 for (
int k=0 ; k < nb_crystal ; k++)
803 for (
int rsa=0 ; rsa<nb_ang_rsector ; rsa++)
804 for (
int rs=0 ; rs<nb_axl_rsector ; rs++)
805 for (
int m=0 ; m<nb_mod ; m++)
806 for (
int sm=0 ; sm<nb_submod ; sm++)
807 for (
int c=0 ; c<nb_crystal ; c++)
810 int cryID = rs * nb_axl_mod * nb_axl_submod * nb_axl_crystal * number_crystals_in_ring
811 + int(m/nb_trs_mod) * nb_axl_submod * nb_axl_crystal * number_crystals_in_ring
812 + int(sm/nb_trs_submod) * nb_axl_crystal * number_crystals_in_ring
813 + int(c/nb_trs_crystal) * number_crystals_in_ring
814 + rsa * nb_trs_mod * nb_trs_submod * nb_trs_crystal
815 + m%nb_trs_mod * nb_trs_submod * nb_trs_crystal
816 + sm%nb_trs_submod * nb_trs_crystal
821 rotation_mtx[rsa]->
Multiplication(crystal_center[0][rs][m][sm][c], crystal_center[rsa+1][rs][m][sm][c]);
839 for (
int rsa = 0; rsa<nb_ang_rsector+1 ; rsa++)
840 for (
int i = 0; i<nb_axl_rsector ; i++)
841 for (
int j = 0; j<nb_mod; j++)
842 for (
int k = 0; k<nb_submod; k++)
843 for (
int l = 0; l<nb_crystal; l++)
845 delete crystal_center[rsa][i][j][k][l];
849 for(
int rsa = 0; rsa < nb_ang_rsector+1 ; rsa++)
850 for(
int i = 0; i < nb_axl_rsector ; i++)
851 for (
int j = 0; j<nb_mod; j++)
852 for (
int k = 0; k<nb_submod; k++)
854 delete[] crystal_center[rsa][i][j][k];
857 for(
int rsa = 0; rsa < nb_ang_rsector+1 ; rsa++)
858 for(
int i = 0; i < nb_axl_rsector ; i++)
859 for (
int j = 0; j<nb_mod; j++)
861 delete[] crystal_center[rsa][i][j];
864 for(
int rsa = 0; rsa < nb_ang_rsector+1 ; rsa++)
865 for(
int i = 0; i < nb_axl_rsector ; i++)
867 delete[] crystal_center[rsa][i];
870 for(
int rsa = 0; rsa < nb_ang_rsector+1 ; rsa++)
871 delete[] crystal_center[rsa];
874 for(
int i = 0; i < nb_ang_rsector ; i++)
875 delete rotation_mtx[i];
877 delete[] crystal_center;
878 delete[] rotation_mtx;
890 string path_to_LUT = path_to_geom_file.substr(0, path_to_geom_file.find_last_of(
"."));
891 string path_to_header_LUT = path_to_LUT +
".ghscan";
892 path_to_LUT.append(
".glut");
896 ofstream LUT_file, header_LUT_file;
897 LUT_file.open(path_to_LUT.c_str(), ios::binary | ios::out);
915 header_LUT_file.open(path_to_header_LUT.c_str(), ios::out);
917 string scanner_name = path_to_geom_file.substr(0, path_to_geom_file.find_last_of(
"."));
918 header_LUT_file <<
"scanner name:" <<
" " <<
GetFileFromPath(scanner_name) << endl;
919 header_LUT_file <<
"modality:" <<
" " <<
"PET" << endl;
921 header_LUT_file <<
"scanner radius:" <<
" " << radius_lyr[0];
923 header_LUT_file <<
"," << radius_lyr[lyr] ;
924 header_LUT_file << endl;
926 header_LUT_file <<
"number of elements:" <<
" " << m_nbCrystals << endl;
927 header_LUT_file <<
"number of layers:" <<
" " << m_nbLayers << endl;
930 header_LUT_file <<
","<< mp_nbCrystalsInLayer[lyr] ;
931 header_LUT_file << endl;
935 header_LUT_file <<
","<< mp_sizeCrystalDepth[lyr] ;
936 header_LUT_file << endl;
940 header_LUT_file <<
","<< mp_sizeCrystalTrans[lyr] ;
941 header_LUT_file << endl;
945 header_LUT_file <<
","<< mp_sizeCrystalAxial[lyr] ;
946 header_LUT_file << endl;
949 uint32_t def_dim_trs = 0, def_dim_axl = 0;
950 FLTNB def_FOV_trs = -1., def_FOV_axl = -1;
957 Cerr(
"***** iScannerPET::ComputeLUT() -> Error occurred when trying to read transaxial/axial dimensions and voxel sizes from scanner geom file !" << endl);
961 header_LUT_file <<
"voxels number transaxial:" <<
" " << def_dim_trs << endl;
962 header_LUT_file <<
"voxels number axial:" <<
" " << def_dim_axl << endl;
964 header_LUT_file <<
"field of view transaxial:" <<
" " << def_FOV_trs << endl;
965 header_LUT_file <<
"field of view axial:" <<
" " << def_FOV_axl << endl;
971 header_LUT_file <<
"," << mp_meanDepthOfInteraction[lyr] ;
972 header_LUT_file <<
" #optional (default value : center of crystal ). Input value must correspond to the distance from the crystal surface, or negative value if default" << endl;
976 if(
m_verbose>=2)
Cout(
"iScannerPET::ComputeLUT() -> Header LUT file writing completed" << endl);
980 delete[] nb_ang_rsector_lyr;
981 delete[] nb_axl_rsector_lyr;
982 delete[] nb_trs_mod_lyr;
983 delete[] nb_axl_mod_lyr;
984 delete[] nb_trs_submod_lyr;
985 delete[] nb_axl_submod_lyr;
986 delete[] nb_trs_crystal_lyr;
987 delete[] nb_axl_crystal_lyr;
990 delete[] rsector_angular_span_lyr;
991 delete[] rsector_first_angle_lyr;
993 delete[] gap_axl_rsector_lyr;
994 delete[] gap_trs_mod_lyr;
995 delete[] gap_axl_mod_lyr;
996 delete[] gap_trs_submod_lyr;
997 delete[] gap_axl_submod_lyr;
998 delete[] gap_trs_crystal_lyr;
999 delete[] gap_axl_crystal_lyr;
1028 FLTNB ap_Position1[3],
FLTNB ap_Position2[3],
1029 FLTNB ap_Orientation1[3],
FLTNB ap_Orientation2[3],
1035 if (a_index1<0 || a_index1>=m_nbCrystals)
1037 Cerr(
"***** iScannerPET::GetPositionsAndOrientations() -> Crystal index 1 (" << a_index1 <<
") out of range [0:" << m_nbCrystals-1 <<
"] !" << endl);
1040 if (a_index2<0 || a_index2>=m_nbCrystals)
1042 Cerr(
"***** iScannerPET::GetPositionsAndOrientations() -> Crystal index 2 (" << a_index2 <<
") out of range [0:" << m_nbCrystals-1 <<
"] !" << endl);
1059 FLTNB depth = mp_meanDepthOfInteraction[
GetLayer(a_index1)] - mp_sizeCrystalDepth[
GetLayer(a_index1)]/2.;
1065 else if (ap_POI1[2]<0.)
1070 else if (ap_POI1[0]==0. && ap_POI1[1]==0.)
1072 FLTNB depth = ap_POI1[2] - mp_sizeCrystalDepth[
GetLayer(a_index1)]/2.;
1086 FLTNB depth = mp_meanDepthOfInteraction[
GetLayer(a_index2)] - mp_sizeCrystalDepth[
GetLayer(a_index2)]/2.;
1092 else if (ap_POI2[2]<0.)
1097 else if (ap_POI2[0]==0. && ap_POI2[1]==0.)
1099 FLTNB depth = ap_POI2[2] - mp_sizeCrystalDepth[
GetLayer(a_index2)]/2.;
1145 FLTNB ap_Position1[3],
FLTNB ap_Position2[3],
1146 FLTNB ap_Orientation1[3],
FLTNB ap_Orientation2[3] )
1151 if (a_index1<0 || a_index1>=m_nbCrystals)
1153 Cerr(
"***** iScannerPET::GetRdmPositionsAndOrientations() -> Crystal index 1 (" << a_index1 <<
") out of range [0:" << m_nbCrystals-1 <<
"] !" << endl);
1156 if (a_index2<0 || a_index2>=m_nbCrystals)
1158 Cerr(
"***** iScannerPET::GetRdmPositionsAndOrientations() -> Crystal index 2 (" << a_index2 <<
") out of range [0:" << m_nbCrystals-1 <<
"] !" << endl);
1162 if (mp_sizeCrystalTrans[
GetLayer(a_index1)]<=0. || mp_sizeCrystalAxial[
GetLayer(a_index1)]<=0. ||
1163 mp_sizeCrystalTrans[
GetLayer(a_index2)]<=0. || mp_sizeCrystalAxial[
GetLayer(a_index2)]<=0. )
1165 Cerr(
"***** iScannerPET::GetRdmPositionsAndOrientations() -> Crystal sizes are unknown or equal to 0. Crystal dimensions are mandatory for this function !" << endl);
1179 FLTNB size_crystalTrans1 = mp_sizeCrystalTrans[
GetLayer(a_index1)];
1180 FLTNB size_crystalAxial1 = mp_sizeCrystalAxial[
GetLayer(a_index1)];
1181 FLTNB size_crystalDepth1 = mp_sizeCrystalDepth[
GetLayer(a_index1)];
1182 FLTNB axial1 = (rdm_axl1-0.5) * size_crystalAxial1;
1183 FLTNB trans1 = (rdm_trs1-0.5) * size_crystalTrans1;
1184 FLTNB depth1 = (rdm_depth1-0.5) * size_crystalDepth1;
1196 FLTNB mDOI1 = mp_meanDepthOfInteraction[
GetLayer(a_index1) ];
1199 depth1 = -size_crystalDepth1*0.5 + mDOI1;
1200 depth1 += mDOI1 < size_crystalDepth1/2 ?
1201 (rdm_depth1-0.5)*mDOI1*2 :
1202 (rdm_depth1-0.5)*(size_crystalDepth1-mDOI1)*2 ;
1209 ap_Orientation1[0] = uX;
1210 ap_Orientation1[1] = uY;
1211 ap_Orientation1[2] = uZ;
1214 FLTNB trans_VecNorm;
1217 FLTNB axial_VecNorm;
1222 trans_VecNorm = 1.0;
1224 axial_VecNorm = sqrt( pow(uX, 2) + pow(uY, 2));
1229 trans_VecNorm = sqrt( pow(uX, 2) + pow(uY, 2));
1230 axial_z = (pow(uX, 2) + pow(uY, 2)) / uZ;
1231 axial_VecNorm = sqrt( pow(uX, 2) + pow(uY, 2) + pow(axial_z, 2));
1236 - trans1 * uY / trans_VecNorm
1237 - axial1 * uX / axial_VecNorm;
1241 + trans1 * uX / trans_VecNorm
1242 - axial1 * uY / axial_VecNorm;
1247 + axial1 * axial_z / axial_VecNorm;
1258 FLTNB size_crystalTrans2 = mp_sizeCrystalTrans[
GetLayer(a_index2)];
1259 FLTNB size_crystalAxial2 = mp_sizeCrystalAxial[
GetLayer(a_index2)];
1260 FLTNB size_crystalDepth2 = mp_sizeCrystalDepth[
GetLayer(a_index2)];
1261 FLTNB axial2 = (rdm_axl2-0.5) * size_crystalAxial2;
1262 FLTNB trans2 = (rdm_trs2-0.5) * size_crystalTrans2;
1263 FLTNB depth2 = (rdm_depth2-0.5) * size_crystalDepth2;
1273 FLTNB mDOI2 = mp_meanDepthOfInteraction[
GetLayer(a_index2) ];
1276 depth2 = -size_crystalDepth2*0.5 + mDOI2;
1277 depth2 += mDOI2 < size_crystalDepth2*0.5 ?
1278 (rdm_depth2-0.5)*mDOI2*2 :
1279 (rdm_depth2-0.5)*(size_crystalDepth2-mDOI2)*2 ;
1286 ap_Orientation2[0] = uX;
1287 ap_Orientation2[1] = uY;
1288 ap_Orientation2[2] = uZ;
1293 trans_VecNorm = 1.0;
1295 axial_VecNorm = sqrt( pow(uX, 2) + pow(uY, 2));
1300 trans_VecNorm = sqrt( pow(uX, 2) + pow(uY, 2));
1301 axial_z = (pow(uX, 2) + pow(uY, 2)) / uZ;
1302 axial_VecNorm = sqrt( pow(uX, 2) + pow(uY, 2) + pow(axial_z, 2));
1307 - trans2 * uY / trans_VecNorm
1308 - axial2 * uX / axial_VecNorm;
1312 + trans2 * uX / trans_VecNorm
1313 - axial2 * uY / axial_VecNorm;
1318 + axial2 * axial_z / axial_VecNorm;
1348 FLTNB depth1 = (shoot1-0.5) * mp_sizeCrystalDepth[
GetLayer(a_index1)];
1358 FLTNB depth2 = (shoot2-0.5) * mp_sizeCrystalDepth[
GetLayer(a_index2)];
1384 FLTNB ap_CornerInf1[3],
FLTNB ap_CornerSup1[3],
1385 FLTNB ap_CornerInf2[3],
FLTNB ap_CornerSup2[3])
1389 if (a_index1<0 || a_index1>=m_nbCrystals || a_index2<0 || a_index2>=m_nbCrystals)
1391 Cerr(
"***** iScannerPET::GetTwoCorners() -> Crystal index out of range !" << endl);
1395 if (mp_sizeCrystalTrans[
GetLayer(a_index1)]<=0. || mp_sizeCrystalAxial[
GetLayer(a_index1)]<=0. ||
1396 mp_sizeCrystalTrans[
GetLayer(a_index2)]<=0. || mp_sizeCrystalAxial[
GetLayer(a_index2)]<=0. )
1398 Cerr(
"***** iScannerPET::GetRdmPositionsAndOrientations() -> Crystal sizes are unknown or equal to 0. Crystal dimensions are mandatory for this function !" << endl);
1402 Cerr(
"***** iScannerPET::GetTwoCorners() -> Not implemented yet !" << endl);
1412 FLTNB ap_pos_line_point1[3],
FLTNB ap_pos_line_point2[3],
1413 FLTNB ap_pos_point1_x[4],
FLTNB ap_pos_point1_y[4],
FLTNB ap_pos_point1_z[4],
1414 FLTNB ap_pos_point2_x[4],
FLTNB ap_pos_point2_y[4],
FLTNB ap_pos_point2_z[4]
1419 if( a_index1 < 0 || a_index1 >= m_nbCrystals
1420 || a_index2 < 0 || a_index2 >= m_nbCrystals )
1422 Cerr(
"***** iScannerPET::GetEdgesCenterPositions() -> Crystal indices out of range !" << endl);
1427 FLTNB half_crystal_trans_1 = mp_sizeCrystalTrans[
GetLayer(a_index1)] / 2.0;
1428 FLTNB half_crystal_axial_1 = mp_sizeCrystalAxial[
GetLayer(a_index1)] / 2.0;
1429 FLTNB half_crystal_trans_2 = mp_sizeCrystalTrans[
GetLayer(a_index2)] / 2.0;
1430 FLTNB half_crystal_axial_2 = mp_sizeCrystalAxial[
GetLayer(a_index2)] / 2.0;
1435 ap_pos_point1_x[ 0 ] = ap_pos_line_point1[ 0 ] - half_crystal_trans_1 * mp_crystalOrientationY[ a_index1 ];
1436 ap_pos_point1_x[ 1 ] = ap_pos_line_point1[ 0 ] + half_crystal_trans_1 * mp_crystalOrientationY[ a_index1 ];
1437 ap_pos_point1_x[ 2 ] = ap_pos_line_point1[ 0 ];
1438 ap_pos_point1_x[ 3 ] = ap_pos_line_point1[ 0 ];
1441 ap_pos_point1_y[ 0 ] = ap_pos_line_point1[ 1 ] + half_crystal_trans_1 * mp_crystalOrientationX[ a_index1 ];
1442 ap_pos_point1_y[ 1 ] = ap_pos_line_point1[ 1 ] - half_crystal_trans_1 * mp_crystalOrientationX[ a_index1 ];
1443 ap_pos_point1_y[ 2 ] = ap_pos_line_point1[ 1 ];
1444 ap_pos_point1_y[ 3 ] = ap_pos_line_point1[ 1 ];
1447 ap_pos_point1_z[ 0 ] = ap_pos_line_point1[ 2 ];
1448 ap_pos_point1_z[ 1 ] = ap_pos_line_point1[ 2 ];
1449 ap_pos_point1_z[ 2 ] = ap_pos_line_point1[ 2 ] - half_crystal_axial_1;
1450 ap_pos_point1_z[ 3 ] = ap_pos_line_point1[ 2 ] + half_crystal_axial_1;
1455 ap_pos_point2_x[ 0 ] = ap_pos_line_point2[ 0 ] + half_crystal_trans_2 * mp_crystalOrientationY[ a_index2 ];
1456 ap_pos_point2_x[ 1 ] = ap_pos_line_point2[ 0 ] - half_crystal_trans_2 * mp_crystalOrientationY[ a_index2 ];
1457 ap_pos_point2_x[ 2 ] = ap_pos_line_point2[ 0 ];
1458 ap_pos_point2_x[ 3 ] = ap_pos_line_point2[ 0 ];
1461 ap_pos_point2_y[ 0 ] = ap_pos_line_point2[ 1 ] - half_crystal_trans_2 * mp_crystalOrientationX[ a_index2 ];
1462 ap_pos_point2_y[ 1 ] = ap_pos_line_point2[ 1 ] + half_crystal_trans_2 * mp_crystalOrientationX[ a_index2 ];
1463 ap_pos_point2_y[ 2 ] = ap_pos_line_point2[ 1 ];
1464 ap_pos_point2_y[ 3 ] = ap_pos_line_point2[ 1 ];
1467 ap_pos_point2_z[ 0 ] = ap_pos_line_point2[ 2 ];
1468 ap_pos_point2_z[ 1 ] = ap_pos_line_point2[ 2 ];
1469 ap_pos_point2_z[ 2 ] = ap_pos_line_point2[ 2 ] - half_crystal_axial_2;
1470 ap_pos_point2_z[ 3 ] = ap_pos_line_point2[ 2 ] + half_crystal_axial_2;
1491 int sum_crystals = mp_nbCrystalsInLayer[layer];
1493 while (a_idx >= sum_crystals)
1496 sum_crystals += mp_nbCrystalsInLayer[layer];
1527 FLTNB abs_angle = mp_crystalOrientationX[a_elt1]*mp_crystalOrientationX[a_elt2]
1528 + mp_crystalOrientationY[a_elt1]*mp_crystalOrientationY[a_elt2];
1531 abs_angle = (abs_angle>1.) ? 1 : abs_angle;
1532 abs_angle = (abs_angle<-1.) ? -1 : abs_angle;
1534 FLTNB angle_diff = acos(abs_angle);
1569 Cerr(
"***** iScannerPET::GetGeometricInfoFromDataFile() -> Error while reading max number of ring difference in the header data file '" << endl);
1596 Cerr(
"***** iScannerPET::PROJ_GetPETSpecificParameters() -> Parameters have not been checked !" << endl);
1616 cout <<
"This scanner class is dedicated to the description of PET systems." << endl;
int GetPositionWithRandomDepth(int a_index1, int a_index2, FLTNB ap_Position1[3], FLTNB ap_Position2[3])
int CheckParameters()
Check if all parameters have been correctly initialized.
FLTNB * mp_crystalOrientationZ
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
static sRandomNumberGenerator * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int Instantiate(bool a_scannerFileIsLUT)
int IsAvailableLOR(int a_elt1, int a_elt2)
FLTNB * mp_sizeCrystalTrans
#define VERBOSE_DEBUG_MAX
FLTNB * mp_sizeCrystalAxial
int Initialize()
Check general initialization and set several parameters to their default value.
int GetTwoCorners(int a_index1, int a_index2, FLTNB ap_CornerInf1[3], FLTNB ap_CornerSup1[3], FLTNB ap_CornerInf2[3], FLTNB ap_CornerSup2[3])
FLTNB m_minAngleDifference
FLTNB m_defaultBedDisplacementInMm
string GetPathToScannerFile()
int GetRdmPositionsAndOrientations(int a_index1, int a_index2, FLTNB ap_Position1[3], FLTNB ap_Position2[3], FLTNB ap_Orientation1[3], FLTNB ap_Orientation2[3])
bool FLTNBIsEqual(FLTNB a, FLTNB b, FLTNB a_eps)
Comparison of FLTNB numbers.
FLTNB * mp_meanDepthOfInteraction
int GetEdgesCenterPositions(int a_index1, int a_index2, FLTNB ap_pos_line_point1[3], FLTNB ap_pos_line_point2[3], FLTNB ap_pos_point1_x[4], FLTNB ap_pos_point1_y[4], FLTNB ap_pos_point1_z[4], FLTNB ap_pos_point2_x[4], FLTNB ap_pos_point2_y[4], FLTNB ap_pos_point2_z[4])
FLTNB * mp_sizeCrystalDepth
int GetGeometricInfoFromDataFile(string a_pathToDataFilename)
virtual int SetRotDirection(string a_rotDirection)
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
Singleton class that Instantiate and initialize the scanner object.
FLTNB * mp_crystalOrientationX
int GetPositionsAndOrientations(int a_index1, int a_index2, FLTNB ap_Position1[3], FLTNB ap_Position2[3], FLTNB ap_Orientation1[3], FLTNB ap_Orientation2[3], FLTNB *ap_POI1=NULL, FLTNB *ap_POI2=NULL)
int * mp_nbCrystalsInLayer
bool SaveLUTFlag()
Get flag indicating a LUT generated by a geom file should be written on disk or not.
int PROJ_GetPETSpecificParameters(FLTNB *ap_maxAxialDiffmm)
HPFLTNB GenerateRdmNber()
Generate a random number for the thread which index is recovered from the OpenMP function.
bool m_allParametersChecked
#define KEYWORD_MANDATORY
oMatrix * mp_positionMatrix_out
oMatrix * mp_positionMatrix_ref
Singleton class that generate a thread-safe random generator number for openMP As singleton...
int LoadLUT()
Load a precomputed scanner LUT.
iScannerPET()
iScannerPET constructor. Initialize the member variables to their default values. ...
FLTNB * mp_crystalCentralPositionY
void ShowHelp()
Display help.
Structure designed for basic matrices operations.
FLTNB * mp_crystalOrientationY
oMatrix * mp_rotationMatrix
~iScannerPET()
iScannerPET destructor.
string GetFileFromPath(const string &a_pathToFile)
Simply return the file from a path string passed in parameter.
#define VERBOSE_DEBUG_LIGHT
int BuildLUT(bool a_scannerFileIsLUT)
int Multiplication(oMatrix *ap_Mtx, oMatrix *ap_MtxResult)
void DescribeSpecific()
Implementation of the pure virtual eponym function that simply prints info about the scanner...
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
int SetMatriceElt(uint16_t l, uint16_t c, HPFLTNB a_val)
Generic class for scanner objects.
#define KEYWORD_OPTIONAL_ERROR
FLTNB * mp_crystalCentralPositionX
#define VERBOSE_DEBUG_EVENT
int ComputeLUT()
Compute the LUT of the scanner from a generic (.geom) file.
FLTNB * mp_crystalCentralPositionZ