28 cout <<
"Usage: castor-PetScannerLutEx -alias scanner_name [settings]" << endl;
30 cout <<
"[Input settings]:" << endl;
31 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;
32 cout <<
" the resulting file will be written in the scanner repository (default : /config/scanner directory)" << endl;
35 cout <<
" This program is part of the CASToR release version " <<
CASTOR_VERSION <<
"." << endl;
47 int main(
int argc,
char** argv)
52 string scanner_name =
"";
53 string path_to_LUT =
"";
54 string path_to_headerLUT =
"";
55 ofstream LUT_file, header_LUT_file;
60 for (
int i=1; i<argc; i++)
62 string option = (string)argv[i];
64 if (option==
"-h" || option==
"--help" || option==
"-help")
ShowHelp(0);
66 else if (option==
"-alias")
70 cerr <<
"***** castor-PetScannerLutEx :: Argument missing for option: " << option << endl;
73 scanner_name = argv[i+1];
76 path_base.append(
"scanner");
77 path_to_LUT = path_base+
OS_SEP;
78 path_to_headerLUT = path_base+
OS_SEP;
79 path_to_LUT.append(scanner_name.c_str()).append(
".lut");
80 path_to_headerLUT.append(scanner_name.c_str()).append(
".hscan");
85 cerr <<
"***** castor-PetScannerLutEx :: Unknown option '" << option <<
"' !" << endl;
98 if (scanner_name.empty() )
100 cerr <<
"***** castor-PetScannerLutEx :: Please provide an alias for this scanner !" << endl;
106 cout << endl <<
"Generating LUT with the following alias: " << scanner_name <<
"... " << endl << endl;
117 string scanner_modality;
121 int *nb_rsectors_lyr,
124 *nb_trans_submod_lyr,
125 *nb_axial_submod_lyr,
126 *nb_trans_crystal_lyr,
127 *nb_axial_crystal_lyr,
133 *gap_trans_submod_lyr,
134 *gap_axial_submod_lyr,
135 *gap_trans_crystal_lyr,
136 *gap_axial_crystal_lyr,
137 *crystal_size_depth_lyr,
138 *crystal_size_trans_lyr,
139 *crystal_size_axial_lyr,
140 *mean_depth_of_interaction_lyr;
145 nb_rsectors_lyr =
new int[nbLayers];
146 nb_trans_mod_lyr =
new int[nbLayers];
147 nb_axial_mod_lyr =
new int[nbLayers];
148 nb_trans_submod_lyr =
new int[nbLayers];
149 nb_axial_submod_lyr =
new int[nbLayers];
150 nb_trans_crystal_lyr =
new int[nbLayers];
151 nb_axial_crystal_lyr =
new int[nbLayers];
152 nb_crystals_lyr =
new int[nbLayers];
154 radius_lyr =
new FLTNBLUT[nbLayers];
156 gap_trans_mod_lyr =
new FLTNBLUT[nbLayers];
157 gap_axial_mod_lyr =
new FLTNBLUT[nbLayers];
158 gap_trans_submod_lyr =
new FLTNBLUT[nbLayers];
159 gap_axial_submod_lyr =
new FLTNBLUT[nbLayers];
160 gap_trans_crystal_lyr =
new FLTNBLUT[nbLayers];
161 gap_axial_crystal_lyr =
new FLTNBLUT[nbLayers];
162 crystal_size_depth_lyr =
new FLTNBLUT[nbLayers];
163 crystal_size_trans_lyr =
new FLTNBLUT[nbLayers];
164 crystal_size_axial_lyr =
new FLTNBLUT[nbLayers];
165 mean_depth_of_interaction_lyr =
new FLTNBLUT[nbLayers];
170 description =
"User-made LUT of a GATE model of the GE DRX PET scanner system, generated by the castor-PetScannerLutEx script";
171 scanner_modality =
"PET";
175 min_trs_angle_diff = 40.;
181 nb_rsectors_lyr[0] = 70;
182 nb_trans_mod_lyr[0] = 1;
183 nb_axial_mod_lyr[0] = 4;
184 nb_trans_submod_lyr[0] = 1;
185 nb_axial_submod_lyr[0] = 1;
186 nb_trans_crystal_lyr[0] = 9;
187 nb_axial_crystal_lyr[0] = 6;
191 gap_trans_mod_lyr[0] = 0;
192 gap_axial_mod_lyr[0] = 1.75;
193 gap_trans_submod_lyr[0] = 0;
194 gap_axial_submod_lyr[0] = 0;
195 gap_trans_crystal_lyr[0] = 0.065;
196 gap_axial_crystal_lyr[0] = 0.1;
199 crystal_size_depth_lyr[0] = 30;
200 crystal_size_trans_lyr[0] = 4.230;
201 crystal_size_axial_lyr[0] = 6.350;
205 mean_depth_of_interaction_lyr[0] = -1.;
212 int default_dim_trans, default_dim_axial;
213 default_dim_trans = 256;
214 default_dim_axial = 47;
217 FLTNBLUT default_FOV_trans, default_FOV_axial;
218 default_FOV_trans = 700;
219 default_FOV_axial = 153.69;
225 int nb_rsctr_axial_shift = 1;
227 rsctr_zshift =
new FLTNBLUT[nb_rsctr_axial_shift];
230 if(nb_rsctr_axial_shift > 1)
232 for(
int zs=0 ; zs<nb_rsctr_axial_shift ; zs++)
233 rsctr_zshift[zs] = 0.;
237 rsctr_zshift[0] = 0.;
242 for(
int lyr=0 ; lyr<nbLayers ; lyr++)
243 nb_elts += nb_rsectors_lyr[lyr] * nb_trans_mod_lyr[lyr] * nb_axial_mod_lyr[lyr]
244 * nb_trans_submod_lyr[lyr] * nb_axial_submod_lyr[lyr]
245 * nb_trans_crystal_lyr[lyr] * nb_axial_crystal_lyr[lyr];
248 uint32_t nb_cry_cur = 0;
251 uint32_t nb_cry_in_layer = 0;
255 for(
int lyr=0 ; lyr<nbLayers ; lyr++)
264 int nb_rsectors = nb_rsectors_lyr[lyr],
265 nb_trans_mod = nb_trans_mod_lyr[lyr],
266 nb_axial_mod = nb_axial_mod_lyr[lyr],
267 nb_trans_submod = nb_trans_submod_lyr[lyr],
268 nb_axial_submod = nb_axial_submod_lyr[lyr],
269 nb_trans_crystal = nb_trans_crystal_lyr[lyr],
270 nb_axial_crystal = nb_axial_crystal_lyr[lyr];
273 gap_trans_mod = gap_trans_mod_lyr[lyr],
274 gap_axial_mod = gap_axial_mod_lyr[lyr],
275 gap_trans_submod = gap_trans_submod_lyr[lyr],
276 gap_axial_submod = gap_axial_submod_lyr[lyr],
277 gap_trans_crystal = gap_trans_crystal_lyr[lyr],
278 gap_axial_crystal = gap_axial_crystal_lyr[lyr],
279 crystal_size_trans = crystal_size_trans_lyr[lyr],
280 crystal_size_axial = crystal_size_axial_lyr[lyr],
281 crystal_size_depth = crystal_size_depth_lyr[lyr];
284 FLTNBLUT size_trans_submod = nb_trans_crystal*crystal_size_trans + (nb_trans_crystal-1)*gap_trans_crystal;
285 FLTNBLUT size_axial_submod = nb_axial_crystal*crystal_size_axial + (nb_axial_crystal-1)*gap_axial_crystal;
286 FLTNBLUT size_trans_mod = nb_trans_submod*size_trans_submod + (nb_trans_submod-1)*gap_trans_submod;
287 FLTNBLUT size_axial_mod = nb_axial_submod*size_axial_submod + (nb_axial_submod-1)*gap_axial_submod;
289 int nb_mod = nb_axial_mod*nb_trans_mod;
290 int nb_submod = nb_axial_submod*nb_trans_submod;
291 int nb_crystal = nb_trans_crystal*nb_axial_crystal;
293 nb_cry_in_layer = nb_rsectors
298 nb_crystals_lyr[lyr] = nb_cry_in_layer;
300 nb_rings = nb_rsectors
305 int number_crystals_in_ring = nb_crystals_lyr[lyr]/nb_rings;
323 for(
int i = 0; i < nb_rsectors+1 ; i++)
325 crystal_center[i] =
new oMatrix ***[nb_axial_mod*nb_trans_mod];
327 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
329 crystal_center[i][j] =
new oMatrix **[nb_axial_submod*nb_trans_submod];
331 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
333 crystal_center[i][j][k] =
new oMatrix*[nb_axial_crystal*nb_trans_crystal];
335 for (
int l = 0; l<nb_axial_crystal*nb_trans_crystal; l++)
336 crystal_center[i][j][k][l] =
new oMatrix(3,1);
347 for(
int i=0; i<nb_rsectors; i++)
348 rotation_mtx[i] =
new oMatrix(3,3);
350 FLTNBLUT angular_span_rad = angular_span*M_PI/180.;
351 for (
int i = 0; i<nb_rsectors; i++)
373 for (
int i=0; i < nb_mod ; i++)
376 FLTNBLUT y_start_m = (nb_trans_mod*size_trans_mod + (nb_trans_mod-1)*gap_trans_mod) / 2;
377 FLTNBLUT z_start_m = -(nb_axial_mod*size_axial_mod + (nb_axial_mod-1)*gap_axial_mod) / 2 ;
381 y_start_m -= (i%nb_trans_mod) * (size_trans_mod + gap_trans_mod);
382 z_start_m += int(i/nb_trans_mod) * (size_axial_mod + gap_axial_mod);
384 for (
int j=0 ; j < nb_submod ; j++)
389 y_start_sm -= (j%nb_trans_submod) * (size_trans_submod + gap_trans_submod);
390 z_start_sm += int(j/nb_trans_submod) * (size_axial_submod + gap_axial_submod);
392 for (
int k=0 ; k < nb_crystal ; k++)
396 FLTNBLUT Xcrist = radius + crystal_size_depth/2;
397 FLTNBLUT Ycrist = y_start_sm - (k%nb_trans_crystal) * (crystal_size_trans + gap_trans_crystal) - crystal_size_trans/2;
398 FLTNBLUT Zcrist = z_start_sm + int(k/nb_trans_crystal) * (crystal_size_axial + gap_axial_crystal) + crystal_size_axial/2;
416 for (
int rs=0 ; rs<nb_rsectors ; rs++)
420 FLTNBLUT rsector_first_angle_rad = rsector_first_angle*M_PI/180.;
421 FLTNBLUT orientation_angle = remainderf(rsector_first_angle_rad + (
FLTNB)rs*angular_span_rad/((
FLTNB)nb_rsectors), 2.*M_PI);
423 for (
int j=0 ; j<nb_mod ; j++)
424 for (
int k=0 ; k<nb_submod ; k++)
425 for (
int l=0 ; l<nb_crystal ; l++)
428 int cryID = int(j/nb_trans_mod)*nb_axial_submod*nb_axial_crystal*number_crystals_in_ring
429 + int(k/nb_trans_submod)*nb_axial_crystal*number_crystals_in_ring
430 + int(l/nb_trans_crystal)*number_crystals_in_ring
431 + rs*nb_trans_mod*nb_trans_submod*nb_trans_crystal
432 + j/nb_axial_mod*nb_trans_submod*nb_trans_crystal
433 + k/nb_axial_submod*nb_trans_crystal
437 rotation_mtx[rs]->
Multiplication(crystal_center[0][j][k][l], crystal_center[rs+1][j][k][l]);
438 crystal_positionX[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(0,0);
439 crystal_positionY[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(1,0);
440 crystal_positionZ[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(2,0);
441 crystal_positionZ[cryID] += rsctr_zshift[rs%nb_rsctr_axial_shift];
443 crystal_orientationX[cryID] = cos(orientation_angle);
444 crystal_orientationY[cryID] = sin(orientation_angle);
445 crystal_orientationZ[cryID] = 0;
450 nb_cry_cur += nb_crystals_lyr[lyr];
456 cout <<
">>> Start writing binary LUT file for layer #" << lyr <<
"..." << endl;
459 LUT_file.open(path_to_LUT.c_str(), ios::binary | ios::out);
462 LUT_file.open(path_to_LUT.c_str(), ios::binary | ios::out | ios::app);
466 for(
int i=0 ; i<nb_crystals_lyr[lyr] ; i++)
468 LUT_file.write(reinterpret_cast<char*>(&crystal_positionX[i]),
sizeof(
FLTNBLUT));
469 LUT_file.write(reinterpret_cast<char*>(&crystal_positionY[i]),
sizeof(
FLTNBLUT));
470 LUT_file.write(reinterpret_cast<char*>(&crystal_positionZ[i]),
sizeof(
FLTNBLUT));
471 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationX[i]),
sizeof(
FLTNBLUT));
472 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationY[i]),
sizeof(
FLTNBLUT));
473 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationZ[i]),
sizeof(
FLTNBLUT));
477 cout <<
">>> Binary LUT writing OK" << endl;
485 for (
int i = 0; i < nb_rsectors ; i++)
486 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
487 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
488 for (
int l = 0; l<nb_axial_crystal*nb_trans_crystal; l++)
489 delete crystal_center[i][j][k][l];
491 for(
int i = 0; i < nb_rsectors ; i++)
492 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
493 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
494 delete[] crystal_center[i][j][k];
496 for(
int i = 0; i < nb_rsectors ; i++)
497 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
498 delete[] crystal_center[i][j];
500 for(
int i = 0; i < nb_rsectors ; i++)
502 delete[] crystal_center[i];
503 delete rotation_mtx[i];
506 delete[] crystal_center;
507 delete[] rotation_mtx;
508 delete crystal_positionX;
509 delete crystal_positionY;
510 delete crystal_positionZ;
511 delete crystal_orientationX;
512 delete crystal_orientationY;
513 delete crystal_orientationZ;
522 cout <<
">>> Start writing header LUT file..." << endl;
523 header_LUT_file.open(path_to_headerLUT.c_str(), ios::out);
525 header_LUT_file <<
"scanner name:" <<
" " << scanner_name << endl;
526 header_LUT_file <<
"modality:" <<
" " << scanner_modality << endl;
528 header_LUT_file <<
"scanner radius:" <<
" " << radius_lyr[0];
529 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
530 header_LUT_file <<
"," << radius_lyr[lyr] ; header_LUT_file << endl;
532 header_LUT_file <<
"number of rings in scanner:" <<
" " << nb_rings << endl;
533 header_LUT_file <<
"number of elements:" <<
" " << nb_elts << endl;
534 header_LUT_file <<
"number of layers:" <<
" " << nbLayers << endl;
535 header_LUT_file <<
"number of crystals in layer(s):" <<
" " << nb_crystals_lyr[0];
536 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
537 header_LUT_file <<
","<< nb_crystals_lyr[lyr] ; header_LUT_file << endl;
539 header_LUT_file <<
"crystals size depth:" <<
" " << crystal_size_depth_lyr[0];
540 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
541 header_LUT_file <<
","<< crystal_size_depth_lyr[lyr] ; header_LUT_file << endl;
543 header_LUT_file <<
"crystals size transaxial:" <<
" " << crystal_size_trans_lyr[0];
544 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
545 header_LUT_file <<
","<< crystal_size_trans_lyr[lyr] ; header_LUT_file << endl;
547 header_LUT_file <<
"crystals size axial:" <<
" " << crystal_size_axial_lyr[0];
548 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
549 header_LUT_file <<
","<< crystal_size_axial_lyr[lyr] ; header_LUT_file << endl;
553 header_LUT_file <<
"voxels number transaxial:" <<
" " << default_dim_trans << endl;
554 header_LUT_file <<
"voxels number axial:" <<
" " << default_dim_axial << endl;
556 header_LUT_file <<
"field of view transaxial:" <<
" " << default_FOV_trans << endl;
557 header_LUT_file <<
"field of view axial:" <<
" " << default_FOV_axial << endl;
559 header_LUT_file <<
"min angle difference:" <<
" " << min_trs_angle_diff <<
" #deg" << endl;
561 header_LUT_file <<
"mean depth of interaction:" <<
" " << mean_depth_of_interaction_lyr[0];
562 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
563 header_LUT_file <<
","<< mean_depth_of_interaction_lyr[lyr] ;
564 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;
566 header_LUT_file <<
"description:" <<
" " << description << endl;
568 cout <<
">>> Header LUT file writing OK" << endl;
572 delete nb_rsectors_lyr;
573 delete nb_trans_mod_lyr;
574 delete nb_axial_mod_lyr;
575 delete nb_trans_submod_lyr;
576 delete nb_axial_submod_lyr;
577 delete nb_trans_crystal_lyr;
578 delete nb_axial_crystal_lyr;
581 delete gap_trans_mod_lyr;
582 delete gap_axial_mod_lyr;
583 delete gap_trans_submod_lyr;
584 delete gap_axial_submod_lyr;
585 delete gap_trans_crystal_lyr;
586 delete gap_axial_crystal_lyr;
587 delete crystal_size_depth_lyr;
588 delete crystal_size_trans_lyr;
589 delete crystal_size_axial_lyr;
591 cout <<
"Binary file has been created in: " << path_to_LUT << endl;
592 cout <<
"Header file has been created in: " << path_to_headerLUT << endl << endl;
593 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...
int main(int argc, char **argv)
int SetMatriceElt(uint16_t l, uint16_t c, FLTNBLUT a_val)
Set the matrix element corresponding to the argument indices with the provided value.
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 Multiplication(oMatrix *a_Mtx, oMatrix *a_MtxResult)
Multiply the member matrix with the matrix provided in 1st parameter Return the result in the matric ...
Declaration of class oMatrix.
FLTNBLUT GetMatriceElt(uint16_t l, uint16_t c)
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...
void ShowHelp(int a_returnCode)