14 #include "gVariables.hh" 15 #include "gOptions.hh" 16 #include "sOutputManager.hh" 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;
46 int main(
int argc,
char** argv)
55 MPI_Init(&argc, &argv);
56 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
57 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
58 if (mpi_rank!=0)
return 0;
64 string scanner_name =
"";
65 string path_to_LUT =
"";
66 string path_to_headerLUT =
"";
67 ofstream LUT_file, header_LUT_file;
72 for (
int i=1; i<argc; i++)
74 string option = (string)argv[i];
76 if (option==
"-h" || option==
"--help" || option==
"-help")
ShowHelp(0);
78 else if (option==
"-alias")
82 cerr <<
"***** castor-PetScannerLutEx :: Argument missing for option: " << option << endl;
85 scanner_name = argv[i+1];
88 path_base.append(
"scanner");
89 path_to_LUT = path_base+
OS_SEP;
90 path_to_headerLUT = path_base+
OS_SEP;
91 path_to_LUT.append(scanner_name.c_str()).append(
".lut");
92 path_to_headerLUT.append(scanner_name.c_str()).append(
".hscan");
97 cerr <<
"***** castor-PetScannerLutEx :: Unknown option '" << option <<
"' !" << endl;
110 if (scanner_name.empty() )
112 cerr <<
"***** castor-PetScannerLutEx :: Please provide an alias for this scanner !" << endl;
118 cout << endl <<
"Generating LUT with the following alias: " << scanner_name <<
"... " << endl << endl;
129 string scanner_modality;
133 int *nb_rsectors_lyr,
136 *nb_trans_submod_lyr,
137 *nb_axial_submod_lyr,
138 *nb_trans_crystal_lyr,
139 *nb_axial_crystal_lyr,
145 *gap_trans_submod_lyr,
146 *gap_axial_submod_lyr,
147 *gap_trans_crystal_lyr,
148 *gap_axial_crystal_lyr,
149 *crystal_size_depth_lyr,
150 *crystal_size_trans_lyr,
151 *crystal_size_axial_lyr,
152 *mean_depth_of_interaction_lyr;
157 nb_rsectors_lyr =
new int[nbLayers];
158 nb_trans_mod_lyr =
new int[nbLayers];
159 nb_axial_mod_lyr =
new int[nbLayers];
160 nb_trans_submod_lyr =
new int[nbLayers];
161 nb_axial_submod_lyr =
new int[nbLayers];
162 nb_trans_crystal_lyr =
new int[nbLayers];
163 nb_axial_crystal_lyr =
new int[nbLayers];
164 nb_crystals_lyr =
new int[nbLayers];
166 radius_lyr =
new FLTNBLUT[nbLayers];
168 gap_trans_mod_lyr =
new FLTNBLUT[nbLayers];
169 gap_axial_mod_lyr =
new FLTNBLUT[nbLayers];
170 gap_trans_submod_lyr =
new FLTNBLUT[nbLayers];
171 gap_axial_submod_lyr =
new FLTNBLUT[nbLayers];
172 gap_trans_crystal_lyr =
new FLTNBLUT[nbLayers];
173 gap_axial_crystal_lyr =
new FLTNBLUT[nbLayers];
174 crystal_size_depth_lyr =
new FLTNBLUT[nbLayers];
175 crystal_size_trans_lyr =
new FLTNBLUT[nbLayers];
176 crystal_size_axial_lyr =
new FLTNBLUT[nbLayers];
177 mean_depth_of_interaction_lyr =
new FLTNBLUT[nbLayers];
182 description =
"User-made LUT of a GATE model of the GE DRX PET scanner system, generated by the castor-PetScannerLutEx script";
183 scanner_modality =
"PET";
187 min_trs_angle_diff = 40.;
193 nb_rsectors_lyr[0] = 70;
194 nb_trans_mod_lyr[0] = 1;
195 nb_axial_mod_lyr[0] = 4;
196 nb_trans_submod_lyr[0] = 1;
197 nb_axial_submod_lyr[0] = 1;
198 nb_trans_crystal_lyr[0] = 9;
199 nb_axial_crystal_lyr[0] = 6;
203 gap_trans_mod_lyr[0] = 0;
204 gap_axial_mod_lyr[0] = 1.75;
205 gap_trans_submod_lyr[0] = 0;
206 gap_axial_submod_lyr[0] = 0;
207 gap_trans_crystal_lyr[0] = 0.065;
208 gap_axial_crystal_lyr[0] = 0.1;
211 crystal_size_depth_lyr[0] = 30;
212 crystal_size_trans_lyr[0] = 4.230;
213 crystal_size_axial_lyr[0] = 6.350;
217 mean_depth_of_interaction_lyr[0] = -1.;
224 int default_dim_trans, default_dim_axial;
225 default_dim_trans = 256;
226 default_dim_axial = 47;
229 FLTNBLUT default_FOV_trans, default_FOV_axial;
230 default_FOV_trans = 700;
231 default_FOV_axial = 153.69;
237 int nb_rsctr_axial_shift = 1;
239 rsctr_zshift =
new FLTNBLUT[nb_rsctr_axial_shift];
242 if(nb_rsctr_axial_shift > 1)
244 for(
int zs=0 ; zs<nb_rsctr_axial_shift ; zs++)
245 rsctr_zshift[zs] = 0.;
249 rsctr_zshift[0] = 0.;
254 for(
int lyr=0 ; lyr<nbLayers ; lyr++)
255 nb_elts += nb_rsectors_lyr[lyr] * nb_trans_mod_lyr[lyr] * nb_axial_mod_lyr[lyr]
256 * nb_trans_submod_lyr[lyr] * nb_axial_submod_lyr[lyr]
257 * nb_trans_crystal_lyr[lyr] * nb_axial_crystal_lyr[lyr];
260 uint32_t nb_cry_cur = 0;
263 uint32_t nb_cry_in_layer = 0;
267 for(
int lyr=0 ; lyr<nbLayers ; lyr++)
276 int nb_rsectors = nb_rsectors_lyr[lyr],
277 nb_trans_mod = nb_trans_mod_lyr[lyr],
278 nb_axial_mod = nb_axial_mod_lyr[lyr],
279 nb_trans_submod = nb_trans_submod_lyr[lyr],
280 nb_axial_submod = nb_axial_submod_lyr[lyr],
281 nb_trans_crystal = nb_trans_crystal_lyr[lyr],
282 nb_axial_crystal = nb_axial_crystal_lyr[lyr];
285 gap_trans_mod = gap_trans_mod_lyr[lyr],
286 gap_axial_mod = gap_axial_mod_lyr[lyr],
287 gap_trans_submod = gap_trans_submod_lyr[lyr],
288 gap_axial_submod = gap_axial_submod_lyr[lyr],
289 gap_trans_crystal = gap_trans_crystal_lyr[lyr],
290 gap_axial_crystal = gap_axial_crystal_lyr[lyr],
291 crystal_size_trans = crystal_size_trans_lyr[lyr],
292 crystal_size_axial = crystal_size_axial_lyr[lyr],
293 crystal_size_depth = crystal_size_depth_lyr[lyr];
296 FLTNBLUT size_trans_submod = nb_trans_crystal*crystal_size_trans + (nb_trans_crystal-1)*gap_trans_crystal;
297 FLTNBLUT size_axial_submod = nb_axial_crystal*crystal_size_axial + (nb_axial_crystal-1)*gap_axial_crystal;
298 FLTNBLUT size_trans_mod = nb_trans_submod*size_trans_submod + (nb_trans_submod-1)*gap_trans_submod;
299 FLTNBLUT size_axial_mod = nb_axial_submod*size_axial_submod + (nb_axial_submod-1)*gap_axial_submod;
301 int nb_mod = nb_axial_mod*nb_trans_mod;
302 int nb_submod = nb_axial_submod*nb_trans_submod;
303 int nb_crystal = nb_trans_crystal*nb_axial_crystal;
305 nb_cry_in_layer = nb_rsectors
310 nb_crystals_lyr[lyr] = nb_cry_in_layer;
312 nb_rings = nb_rsectors
317 int number_crystals_in_ring = nb_crystals_lyr[lyr]/nb_rings;
335 for(
int i = 0; i < nb_rsectors+1 ; i++)
337 crystal_center[i] =
new oMatrix ***[nb_axial_mod*nb_trans_mod];
339 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
341 crystal_center[i][j] =
new oMatrix **[nb_axial_submod*nb_trans_submod];
343 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
345 crystal_center[i][j][k] =
new oMatrix*[nb_axial_crystal*nb_trans_crystal];
347 for (
int l = 0; l<nb_axial_crystal*nb_trans_crystal; l++)
348 crystal_center[i][j][k][l] =
new oMatrix(3,1);
359 for(
int i=0; i<nb_rsectors; i++)
360 rotation_mtx[i] =
new oMatrix(3,3);
362 FLTNBLUT angular_span_rad = angular_span*M_PI/180.;
363 for (
int i = 0; i<nb_rsectors; i++)
385 for (
int i=0; i < nb_mod ; i++)
388 FLTNBLUT y_start_m = (nb_trans_mod*size_trans_mod + (nb_trans_mod-1)*gap_trans_mod) / 2;
389 FLTNBLUT z_start_m = -(nb_axial_mod*size_axial_mod + (nb_axial_mod-1)*gap_axial_mod) / 2 ;
393 y_start_m -= (i%nb_trans_mod) * (size_trans_mod + gap_trans_mod);
394 z_start_m += int(i/nb_trans_mod) * (size_axial_mod + gap_axial_mod);
396 for (
int j=0 ; j < nb_submod ; j++)
401 y_start_sm -= (j%nb_trans_submod) * (size_trans_submod + gap_trans_submod);
402 z_start_sm += int(j/nb_trans_submod) * (size_axial_submod + gap_axial_submod);
404 for (
int k=0 ; k < nb_crystal ; k++)
408 FLTNBLUT Xcrist = radius + crystal_size_depth/2;
409 FLTNBLUT Ycrist = y_start_sm - (k%nb_trans_crystal) * (crystal_size_trans + gap_trans_crystal) - crystal_size_trans/2;
410 FLTNBLUT Zcrist = z_start_sm + int(k/nb_trans_crystal) * (crystal_size_axial + gap_axial_crystal) + crystal_size_axial/2;
428 for (
int rs=0 ; rs<nb_rsectors ; rs++)
432 FLTNBLUT rsector_first_angle_rad = rsector_first_angle*M_PI/180.;
433 FLTNBLUT orientation_angle = remainderf(rsector_first_angle_rad + (
FLTNB)rs*angular_span_rad/((
FLTNB)nb_rsectors), 2.*M_PI);
435 for (
int j=0 ; j<nb_mod ; j++)
436 for (
int k=0 ; k<nb_submod ; k++)
437 for (
int l=0 ; l<nb_crystal ; l++)
440 int cryID = int(j/nb_trans_mod)*nb_axial_submod*nb_axial_crystal*number_crystals_in_ring
441 + int(k/nb_trans_submod)*nb_axial_crystal*number_crystals_in_ring
442 + int(l/nb_trans_crystal)*number_crystals_in_ring
443 + rs*nb_trans_mod*nb_trans_submod*nb_trans_crystal
444 + j/nb_axial_mod*nb_trans_submod*nb_trans_crystal
445 + k/nb_axial_submod*nb_trans_crystal
449 rotation_mtx[rs]->
Multiplication(crystal_center[0][j][k][l], crystal_center[rs+1][j][k][l]);
450 crystal_positionX[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(0,0);
451 crystal_positionY[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(1,0);
452 crystal_positionZ[cryID] = crystal_center[rs+1][j][k][l]->
GetMatriceElt(2,0);
453 crystal_positionZ[cryID] += rsctr_zshift[rs%nb_rsctr_axial_shift];
455 crystal_orientationX[cryID] = cos(orientation_angle);
456 crystal_orientationY[cryID] = sin(orientation_angle);
457 crystal_orientationZ[cryID] = 0;
462 nb_cry_cur += nb_crystals_lyr[lyr];
468 cout <<
">>> Start writing binary LUT file for layer #" << lyr <<
"..." << endl;
471 LUT_file.open(path_to_LUT.c_str(), ios::binary | ios::out);
474 LUT_file.open(path_to_LUT.c_str(), ios::binary | ios::out | ios::app);
478 for(
int i=0 ; i<nb_crystals_lyr[lyr] ; i++)
480 LUT_file.write(reinterpret_cast<char*>(&crystal_positionX[i]),
sizeof(
FLTNBLUT));
481 LUT_file.write(reinterpret_cast<char*>(&crystal_positionY[i]),
sizeof(
FLTNBLUT));
482 LUT_file.write(reinterpret_cast<char*>(&crystal_positionZ[i]),
sizeof(
FLTNBLUT));
483 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationX[i]),
sizeof(
FLTNBLUT));
484 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationY[i]),
sizeof(
FLTNBLUT));
485 LUT_file.write(reinterpret_cast<char*>(&crystal_orientationZ[i]),
sizeof(
FLTNBLUT));
489 cout <<
">>> Binary LUT writing OK" << endl;
497 for (
int i = 0; i < nb_rsectors ; i++)
498 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
499 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
500 for (
int l = 0; l<nb_axial_crystal*nb_trans_crystal; l++)
501 delete crystal_center[i][j][k][l];
503 for(
int i = 0; i < nb_rsectors ; i++)
504 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
505 for (
int k = 0; k<nb_axial_submod*nb_trans_submod; k++)
506 delete[] crystal_center[i][j][k];
508 for(
int i = 0; i < nb_rsectors ; i++)
509 for (
int j = 0; j<nb_axial_mod*nb_trans_mod; j++)
510 delete[] crystal_center[i][j];
512 for(
int i = 0; i < nb_rsectors ; i++)
514 delete[] crystal_center[i];
515 delete rotation_mtx[i];
518 delete[] crystal_center;
519 delete[] rotation_mtx;
520 delete[] crystal_positionX;
521 delete[] crystal_positionY;
522 delete[] crystal_positionZ;
523 delete[] crystal_orientationX;
524 delete[] crystal_orientationY;
525 delete[] crystal_orientationZ;
534 cout <<
">>> Start writing header LUT file..." << endl;
535 header_LUT_file.open(path_to_headerLUT.c_str(), ios::out);
537 header_LUT_file <<
"scanner name:" <<
" " << scanner_name << endl;
538 header_LUT_file <<
"modality:" <<
" " << scanner_modality << endl;
540 header_LUT_file <<
"scanner radius:" <<
" " << radius_lyr[0];
541 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
542 header_LUT_file <<
"," << radius_lyr[lyr] ;
543 header_LUT_file << endl;
545 header_LUT_file <<
"number of rings in scanner:" <<
" " << nb_rings << endl;
546 header_LUT_file <<
"number of elements:" <<
" " << nb_elts << endl;
547 header_LUT_file <<
"number of layers:" <<
" " << nbLayers << endl;
548 header_LUT_file <<
"number of crystals in layer(s):" <<
" " << nb_crystals_lyr[0];
549 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
550 header_LUT_file <<
","<< nb_crystals_lyr[lyr] ;
551 header_LUT_file << endl;
553 header_LUT_file <<
"crystals size depth:" <<
" " << crystal_size_depth_lyr[0];
554 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
555 header_LUT_file <<
","<< crystal_size_depth_lyr[lyr] ;
556 header_LUT_file << endl;
558 header_LUT_file <<
"crystals size transaxial:" <<
" " << crystal_size_trans_lyr[0];
559 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
560 header_LUT_file <<
","<< crystal_size_trans_lyr[lyr] ;
561 header_LUT_file << endl;
563 header_LUT_file <<
"crystals size axial:" <<
" " << crystal_size_axial_lyr[0];
564 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
565 header_LUT_file <<
","<< crystal_size_axial_lyr[lyr] ;
566 header_LUT_file << endl;
570 header_LUT_file <<
"voxels number transaxial:" <<
" " << default_dim_trans << endl;
571 header_LUT_file <<
"voxels number axial:" <<
" " << default_dim_axial << endl;
573 header_LUT_file <<
"field of view transaxial:" <<
" " << default_FOV_trans << endl;
574 header_LUT_file <<
"field of view axial:" <<
" " << default_FOV_axial << endl;
576 header_LUT_file <<
"min angle difference:" <<
" " << min_trs_angle_diff <<
" #deg" << endl;
578 header_LUT_file <<
"mean depth of interaction:" <<
" " << mean_depth_of_interaction_lyr[0];
579 for (
int lyr=1 ; lyr<nbLayers ; lyr++)
580 header_LUT_file <<
","<< mean_depth_of_interaction_lyr[lyr] ;
581 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;
583 header_LUT_file <<
"description:" <<
" " << description << endl;
585 cout <<
">>> Header LUT file writing OK" << endl;
589 delete nb_rsectors_lyr;
590 delete nb_trans_mod_lyr;
591 delete nb_axial_mod_lyr;
592 delete nb_trans_submod_lyr;
593 delete nb_axial_submod_lyr;
594 delete nb_trans_crystal_lyr;
595 delete nb_axial_crystal_lyr;
598 delete gap_trans_mod_lyr;
599 delete gap_axial_mod_lyr;
600 delete gap_trans_submod_lyr;
601 delete gap_axial_submod_lyr;
602 delete gap_trans_crystal_lyr;
603 delete gap_axial_crystal_lyr;
604 delete crystal_size_depth_lyr;
605 delete crystal_size_trans_lyr;
606 delete crystal_size_axial_lyr;
608 cout <<
"Binary file has been created in: " << path_to_LUT << endl;
609 cout <<
"Header file has been created in: " << path_to_headerLUT << endl << endl;
610 cout <<
"End of LUT generation" << endl << endl;
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.
HPFLTNB GetMatriceElt(uint16_t l, uint16_t c)
Structure designed for basic matrices operations.
int Multiplication(oMatrix *ap_Mtx, oMatrix *ap_MtxResult)
int SetMatriceElt(uint16_t l, uint16_t c, HPFLTNB a_val)