51 cout <<
"Usage: castor-PetScannerLutEx -alias scanner_name [settings]" << endl;
53 cout <<
"[Input settings]:" << endl;
54 cout <<
" -alias scanner_name : give the alias of the scanner for which the LUT will be generated (suggested template Modality-Constructor-Model (ex: PET_GE_DLS)" << endl;
55 cout <<
" the resulting file will be written in the scanner repository (default : /config/scanner directory)" << endl;
58 cout <<
" This program is part of the CASToR release version " <<
CASTOR_VERSION <<
"." << endl;
69 int main(
int argc,
char** argv)
74 string scanner_name =
"";
75 string path_to_LUT =
"";
76 string path_to_headerLUT =
"";
77 ofstream LUT_file, header_LUT_file;
82 for (
int i=1; i<argc; i++)
84 string option = (string)argv[i];
86 if (option==
"-h" || option==
"--help" || option==
"-help")
ShowHelp(0);
88 else if (option==
"-alias")
92 cerr <<
"***** castor-PetScannerLutEx :: Argument missing for option: " << option << endl;
95 scanner_name = argv[i+1];
98 path_base.append(
"scanner");
99 path_to_LUT = path_base+
OS_SEP;
100 path_to_headerLUT = path_base+
OS_SEP;
101 path_to_LUT.append(scanner_name.c_str()).append(
".lut");
102 path_to_headerLUT.append(scanner_name.c_str()).append(
".hscan");
107 cerr <<
"***** castor-PetScannerLutEx :: Unknown option '" << option <<
"' !" << endl;
120 if (scanner_name.empty() )
122 cerr <<
"***** castor-PetScannerLutEx :: Please provide an alias for this scanner !" << endl;
128 cout << endl <<
"Generating LUT with the following alias: " << scanner_name <<
"... " << endl << endl;
139 string scanner_modality;
143 int *nb_rsectors_lyr,
146 *nb_trans_submod_lyr,
147 *nb_axial_submod_lyr,
148 *nb_trans_crystal_lyr,
149 *nb_axial_crystal_lyr,
155 *gap_trans_submod_lyr,
156 *gap_axial_submod_lyr,
157 *gap_trans_crystal_lyr,
158 *gap_axial_crystal_lyr,
159 *crystal_size_depth_lyr,
160 *crystal_size_trans_lyr,
161 *crystal_size_axial_lyr,
162 *mean_depth_of_interaction_lyr;
167 nb_rsectors_lyr =
new int[nbLayers];
168 nb_trans_mod_lyr =
new int[nbLayers];
169 nb_axial_mod_lyr =
new int[nbLayers];
170 nb_trans_submod_lyr =
new int[nbLayers];
171 nb_axial_submod_lyr =
new int[nbLayers];
172 nb_trans_crystal_lyr =
new int[nbLayers];
173 nb_axial_crystal_lyr =
new int[nbLayers];
174 nb_crystals_lyr =
new int[nbLayers];
176 radius_lyr =
new FLTNBLUT[nbLayers];
178 gap_trans_mod_lyr =
new FLTNBLUT[nbLayers];
179 gap_axial_mod_lyr =
new FLTNBLUT[nbLayers];
180 gap_trans_submod_lyr =
new FLTNBLUT[nbLayers];
181 gap_axial_submod_lyr =
new FLTNBLUT[nbLayers];
182 gap_trans_crystal_lyr =
new FLTNBLUT[nbLayers];
183 gap_axial_crystal_lyr =
new FLTNBLUT[nbLayers];
184 crystal_size_depth_lyr =
new FLTNBLUT[nbLayers];
185 crystal_size_trans_lyr =
new FLTNBLUT[nbLayers];
186 crystal_size_axial_lyr =
new FLTNBLUT[nbLayers];
187 mean_depth_of_interaction_lyr =
new FLTNBLUT[nbLayers];
192 description =
"User-made LUT of a GATE model of the GE DRX PET scanner system, generated by the castor-PetScannerLutEx script";
193 scanner_modality =
"PET";
197 min_trs_angle_diff = 40.;
203 nb_rsectors_lyr[0] = 70;
204 nb_trans_mod_lyr[0] = 1;
205 nb_axial_mod_lyr[0] = 4;
206 nb_trans_submod_lyr[0] = 1;
207 nb_axial_submod_lyr[0] = 1;
208 nb_trans_crystal_lyr[0] = 9;
209 nb_axial_crystal_lyr[0] = 6;
213 gap_trans_mod_lyr[0] = 0;
214 gap_axial_mod_lyr[0] = 1.75;
215 gap_trans_submod_lyr[0] = 0;
216 gap_axial_submod_lyr[0] = 0;
217 gap_trans_crystal_lyr[0] = 0.065;
218 gap_axial_crystal_lyr[0] = 0.1;
221 crystal_size_depth_lyr[0] = 30;
222 crystal_size_trans_lyr[0] = 4.230;
223 crystal_size_axial_lyr[0] = 6.350;
227 mean_depth_of_interaction_lyr[0] = -1.;
234 int default_dim_trans, default_dim_axial;
235 default_dim_trans = 256;
236 default_dim_axial = 47;
239 FLTNBLUT default_FOV_trans, default_FOV_axial;
240 default_FOV_trans = 700;
241 default_FOV_axial = 153.69;
247 int nb_rsctr_axial_shift = 1;
249 rsctr_zshift =
new FLTNBLUT[nb_rsctr_axial_shift];
252 if(nb_rsctr_axial_shift > 1)
254 for(
int zs=0 ; zs<nb_rsctr_axial_shift ; zs++)
255 rsctr_zshift[zs] = 0.;
259 rsctr_zshift[0] = 0.;
264 for(
int lyr=0 ; lyr<nbLayers ; lyr++)
265 nb_elts += nb_rsectors_lyr[lyr] * nb_trans_mod_lyr[lyr] * nb_axial_mod_lyr[lyr]
266 * nb_trans_submod_lyr[lyr] * nb_axial_submod_lyr[lyr]
267 * nb_trans_crystal_lyr[lyr] * nb_axial_crystal_lyr[lyr];
270 uint32_t nb_cry_cur = 0;
273 uint32_t nb_cry_in_layer = 0;
277 for(
int lyr=0 ; lyr<nbLayers ; lyr++)
286 int nb_rsectors = nb_rsectors_lyr[lyr],
287 nb_trans_mod = nb_trans_mod_lyr[lyr],
288 nb_axial_mod = nb_axial_mod_lyr[lyr],
289 nb_trans_submod = nb_trans_submod_lyr[lyr],
290 nb_axial_submod = nb_axial_submod_lyr[lyr],
291 nb_trans_crystal = nb_trans_crystal_lyr[lyr],
292 nb_axial_crystal = nb_axial_crystal_lyr[lyr];
295 gap_trans_mod = gap_trans_mod_lyr[lyr],
296 gap_axial_mod = gap_axial_mod_lyr[lyr],
297 gap_trans_submod = gap_trans_submod_lyr[lyr],
298 gap_axial_submod = gap_axial_submod_lyr[lyr],
299 gap_trans_crystal = gap_trans_crystal_lyr[lyr],
300 gap_axial_crystal = gap_axial_crystal_lyr[lyr],
301 crystal_size_trans = crystal_size_trans_lyr[lyr],
302 crystal_size_axial = crystal_size_axial_lyr[lyr],
303 crystal_size_depth = crystal_size_depth_lyr[lyr];
306 FLTNBLUT size_trans_submod = nb_trans_crystal*crystal_size_trans + (nb_trans_crystal-1)*gap_trans_crystal;
307 FLTNBLUT size_axial_submod = nb_axial_crystal*crystal_size_axial + (nb_axial_crystal-1)*gap_axial_crystal;
308 FLTNBLUT size_trans_mod = nb_trans_submod*size_trans_submod + (nb_trans_submod-1)*gap_trans_submod;
309 FLTNBLUT size_axial_mod = nb_axial_submod*size_axial_submod + (nb_axial_submod-1)*gap_axial_submod;
311 int nb_mod = nb_axial_mod*nb_trans_mod;
312 int nb_submod = nb_axial_submod*nb_trans_submod;
313 int nb_crystal = nb_trans_crystal*nb_axial_crystal;
315 nb_cry_in_layer = nb_rsectors
320 nb_crystals_lyr[lyr] = nb_cry_in_layer;
322 nb_rings = nb_rsectors
327 int number_crystals_in_ring = nb_crystals_lyr[lyr]/nb_rings;
345 for(
int i = 0; i < nb_rsectors+1 ; i++)
347 crystal_center[i] =
new oMatrix ***[nb_axial_mod*nb_trans_mod];
349 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
351 crystal_center[i][j] =
new oMatrix **[nb_axial_submod*nb_trans_submod];
353 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
355 crystal_center[i][j][k] =
new oMatrix*[nb_axial_crystal*nb_trans_crystal];
357 for (
int l = 0; l<nb_axial_crystal*nb_trans_crystal; l++)
358 crystal_center[i][j][k][l] =
new oMatrix(3,1);
369 for(
int i=0; i<nb_rsectors; i++)
370 rotation_mtx[i] =
new oMatrix(3,3);
372 FLTNBLUT angular_span_rad = angular_span*M_PI/180.;
373 for (
int i = 0; i<nb_rsectors; i++)
395 for (
int i=0; i < nb_mod ; i++)
398 FLTNBLUT y_start_m = (nb_trans_mod*size_trans_mod + (nb_trans_mod-1)*gap_trans_mod) / 2;
399 FLTNBLUT z_start_m = -(nb_axial_mod*size_axial_mod + (nb_axial_mod-1)*gap_axial_mod) / 2 ;
403 y_start_m -= (i%nb_trans_mod) * (size_trans_mod + gap_trans_mod);
404 z_start_m += int(i/nb_trans_mod) * (size_axial_mod + gap_axial_mod);
406 for (
int j=0 ; j < nb_submod ; j++)
411 y_start_sm -= (j%nb_trans_submod) * (size_trans_submod + gap_trans_submod);
412 z_start_sm += int(j/nb_trans_submod) * (size_axial_submod + gap_axial_submod);
414 for (
int k=0 ; k < nb_crystal ; k++)
418 FLTNBLUT Xcrist = radius + crystal_size_depth/2;
419 FLTNBLUT Ycrist = y_start_sm - (k%nb_trans_crystal) * (crystal_size_trans + gap_trans_crystal) - crystal_size_trans/2;
420 FLTNBLUT Zcrist = z_start_sm + int(k/nb_trans_crystal) * (crystal_size_axial + gap_axial_crystal) + crystal_size_axial/2;
438 for (
int rs=0 ; rs<nb_rsectors ; rs++)
442 FLTNBLUT rsector_first_angle_rad = rsector_first_angle*M_PI/180.;
443 FLTNBLUT orientation_angle = remainderf(rsector_first_angle_rad + (
FLTNB)rs*angular_span_rad/((
FLTNB)nb_rsectors), 2.*M_PI);
445 for (
int j=0 ; j<nb_mod ; j++)
446 for (
int k=0 ; k<nb_submod ; k++)
447 for (
int l=0 ; l<nb_crystal ; l++)
450 int cryID = int(j/nb_trans_mod)*nb_axial_submod*nb_axial_crystal*number_crystals_in_ring
451 + int(k/nb_trans_submod)*nb_axial_crystal*number_crystals_in_ring
452 + int(l/nb_trans_crystal)*number_crystals_in_ring
453 + rs*nb_trans_mod*nb_trans_submod*nb_trans_crystal
454 + j/nb_axial_mod*nb_trans_submod*nb_trans_crystal
455 + k/nb_axial_submod*nb_trans_crystal
459 rotation_mtx[rs]->
Multiplication(crystal_center[0][j][k][l], crystal_center[rs+1][j][k][l]);
460 crystal_positionX[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(0,0);
461 crystal_positionY[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(1,0);
462 crystal_positionZ[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(2,0);
463 crystal_positionZ[cryID] += rsctr_zshift[rs%nb_rsctr_axial_shift];
465 crystal_orientationX[cryID] = cos(orientation_angle);
466 crystal_orientationY[cryID] = sin(orientation_angle);
467 crystal_orientationZ[cryID] = 0;
472 nb_cry_cur += nb_crystals_lyr[lyr];
478 cout <<
">>> Start writing binary LUT file for layer #" << lyr <<
"..." << endl;
481 LUT_file.open(path_to_LUT.c_str(), ios::binary | ios::out);
484 LUT_file.open(path_to_LUT.c_str(), ios::binary | ios::out | ios::app);
488 for(
int i=0 ; i<nb_crystals_lyr[lyr] ; i++)
490 LUT_file.write(reinterpret_cast<char*>(&crystal_positionX[i]),
sizeof(
FLTNBLUT));
491 LUT_file.write(reinterpret_cast<char*>(&crystal_positionY[i]),
sizeof(
FLTNBLUT));
492 LUT_file.write(reinterpret_cast<char*>(&crystal_positionZ[i]),
sizeof(
FLTNBLUT));
493 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationX[i]),
sizeof(
FLTNBLUT));
494 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationY[i]),
sizeof(
FLTNBLUT));
495 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationZ[i]),
sizeof(
FLTNBLUT));
499 cout <<
">>> Binary LUT writing OK" << endl;
507 for (
int i = 0; i < nb_rsectors ; i++)
508 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
509 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
510 for (
int l = 0; l<nb_axial_crystal*nb_trans_crystal; l++)
511 delete crystal_center[i][j][k][l];
513 for(
int i = 0; i < nb_rsectors ; i++)
514 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
515 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
516 delete[] crystal_center[i][j][k];
518 for(
int i = 0; i < nb_rsectors ; i++)
519 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
520 delete[] crystal_center[i][j];
522 for(
int i = 0; i < nb_rsectors ; i++)
524 delete[] crystal_center[i];
525 delete rotation_mtx[i];
528 delete[] crystal_center;
529 delete[] rotation_mtx;
530 delete[] crystal_positionX;
531 delete[] crystal_positionY;
532 delete[] crystal_positionZ;
533 delete[] crystal_orientationX;
534 delete[] crystal_orientationY;
535 delete[] crystal_orientationZ;
544 cout <<
">>> Start writing header LUT file..." << endl;
545 header_LUT_file.open(path_to_headerLUT.c_str(), ios::out);
547 header_LUT_file <<
"scanner name:" <<
" " << scanner_name << endl;
548 header_LUT_file <<
"modality:" <<
" " << scanner_modality << endl;
550 header_LUT_file <<
"scanner radius:" <<
" " << radius_lyr[0];
551 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
552 header_LUT_file <<
"," << radius_lyr[lyr] ; header_LUT_file << endl;
554 header_LUT_file <<
"number of rings in scanner:" <<
" " << nb_rings << endl;
555 header_LUT_file <<
"number of elements:" <<
" " << nb_elts << endl;
556 header_LUT_file <<
"number of layers:" <<
" " << nbLayers << endl;
557 header_LUT_file <<
"number of crystals in layer(s):" <<
" " << nb_crystals_lyr[0];
558 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
559 header_LUT_file <<
","<< nb_crystals_lyr[lyr] ; header_LUT_file << endl;
561 header_LUT_file <<
"crystals size depth:" <<
" " << crystal_size_depth_lyr[0];
562 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
563 header_LUT_file <<
","<< crystal_size_depth_lyr[lyr] ; header_LUT_file << endl;
565 header_LUT_file <<
"crystals size transaxial:" <<
" " << crystal_size_trans_lyr[0];
566 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
567 header_LUT_file <<
","<< crystal_size_trans_lyr[lyr] ; header_LUT_file << endl;
569 header_LUT_file <<
"crystals size axial:" <<
" " << crystal_size_axial_lyr[0];
570 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
571 header_LUT_file <<
","<< crystal_size_axial_lyr[lyr] ; header_LUT_file << endl;
575 header_LUT_file <<
"voxels number transaxial:" <<
" " << default_dim_trans << endl;
576 header_LUT_file <<
"voxels number axial:" <<
" " << default_dim_axial << endl;
578 header_LUT_file <<
"field of view transaxial:" <<
" " << default_FOV_trans << endl;
579 header_LUT_file <<
"field of view axial:" <<
" " << default_FOV_axial << endl;
581 header_LUT_file <<
"min angle difference:" <<
" " << min_trs_angle_diff <<
" #deg" << endl;
583 header_LUT_file <<
"mean depth of interaction:" <<
" " << mean_depth_of_interaction_lyr[0];
584 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
585 header_LUT_file <<
","<< mean_depth_of_interaction_lyr[lyr] ;
586 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;
588 header_LUT_file <<
"description:" <<
" " << description << endl;
590 cout <<
">>> Header LUT file writing OK" << endl;
594 delete nb_rsectors_lyr;
595 delete nb_trans_mod_lyr;
596 delete nb_axial_mod_lyr;
597 delete nb_trans_submod_lyr;
598 delete nb_axial_submod_lyr;
599 delete nb_trans_crystal_lyr;
600 delete nb_axial_crystal_lyr;
603 delete gap_trans_mod_lyr;
604 delete gap_axial_mod_lyr;
605 delete gap_trans_submod_lyr;
606 delete gap_axial_submod_lyr;
607 delete gap_trans_crystal_lyr;
608 delete gap_axial_crystal_lyr;
609 delete crystal_size_depth_lyr;
610 delete crystal_size_trans_lyr;
611 delete crystal_size_axial_lyr;
613 cout <<
"Binary file has been created in: " << path_to_LUT << endl;
614 cout <<
"Header file has been created in: " << path_to_headerLUT << endl << endl;
615 cout <<
"End of LUT generation" << endl << endl;
This header file is mainly used to declare some macro definitions and all includes needed from the st...
FLTNB GetMatriceElt(uint16_t l, uint16_t c)
int main(int argc, char **argv)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
const string & GetPathToConfigDir()
Return the path to the CASTOR config directory.
int SetMatriceElt(uint16_t l, uint16_t c, FLTNB a_val)
Set the matrix element corresponding to the argument indices with the provided value.
Declaration of class oMatrix.
Declaration of class sOutputManager.
Structure designed for basic matrices operations.
This file is used for all kind of different functions designed for options parsing and ASCII file rea...
int Multiplication(oMatrix *ap_Mtx, oMatrix *ap_MtxResult)
Multiply the member matrix with the matrix provided in 1st parameter Return the result in the matric ...
void ShowHelp(int a_returnCode)