CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
gDataConversionUtilities.cc
Go to the documentation of this file.
1 /*
2  Implementation of class file gOptions.hh
3 
4  - separators: X
5  - doxygen: X
6  - default initialization: none
7  - CASTOR_DEBUG: none
8  - CASTOR_VERBOSE: none (no verbose member variable)
9 */
10 
11 
20 #include "gVariables.hh"
22 #include <iomanip>
23 
24 /*
25  Miscelleanous functionalities
26  */
27 
28 // =====================================================================
29 // ---------------------------------------------------------------------
30 // ---------------------------------------------------------------------
31 // =====================================================================
32 /*
33  \fn CheckGATECommand
34  \param a_key: string containing a GATE command to recover
35  \param a_line : string containing the line to check
36  \brief Check if the line contains the provided GATE command. In this case, \n
37  parse the line and returns the values in a vector of strings
38  \details Values are converted in mm if 'cm' is found in the line
39  \return the vector of strings containing the elements of the line.
40 */
41 vector<string> CheckGATECommand(const string& a_key, const string& a_line)
42 {
43  vector<string> values;
44 
45  // cut any part after comment symbol
46  string line = a_line;
47 
48  line = (line.find("#") != string::npos) ?
49  line.substr(0, line.find_first_of("#")) :
50  line;
51 
52  size_t foundAdress = line.find(a_key);
53 
54  if (foundAdress != string::npos)
55  {
56  values = Split(a_line);
57  values.erase (values.begin());
58  }
59 
60  ConvertValuesTomm(values);
61  return values;
62 }
63 
64 
65 
66 // =====================================================================
67 // ---------------------------------------------------------------------
68 // ---------------------------------------------------------------------
69 // =====================================================================
70 /*
71  \fn split
72  \param a_line : string to split
73  \brief Split the line provided in parameter into a vector of strings (separator is blankspace)
74  \return vector of string containing the splitted elements of the line
75 */
76 vector<string> Split(string a_line)
77 {
78  string buf;
79  stringstream ss(a_line);
80 
81  vector<string> tokens;
82 
83  while (ss >> buf)
84  tokens.push_back(buf);
85 
86  return tokens;
87 }
88 
89 
90 
91 // =====================================================================
92 // ---------------------------------------------------------------------
93 // ---------------------------------------------------------------------
94 // =====================================================================
95 /*
96  \fn ConvertValuesTomm
97  \param ap_v : vector of strings
98  \brief Check if the vector of strings passed in parameter contains the 'cm' unit \n
99  In this case, convert all its values in mm
100 */
101 void ConvertValuesTomm(vector<string>& ap_v)
102 {
103  // loop on values
104  for(uint16_t i=0; i < ap_v.size(); i++)
105  // check if values were provided in cm
106  if (ap_v[i] == "cm")
107  // Convert all values to mm (skip command key)
108  for (int j=0; j<i; j++)
109  {
110  float val;
111  ConvertFromString(ap_v[j], &val);
112  ap_v[j] = toString(10 * val);
113  }
114 }
115 
116 
117 // =====================================================================
118 // ---------------------------------------------------------------------
119 // ---------------------------------------------------------------------
120 // =====================================================================
121 /*
122  \fn WriteVector
123  \param file : the output file
124  \param a_key : key to write
125  \param a_vals : vector containing the key values
126  \brief Write the key and its values in the file provided in parameter
127  \return 0 if success, positive value otherwise
128 */
129 template <class T>
130 int WriteVector(ofstream& file, const string& a_key, vector <T> a_vals)
131 {
132  int n = a_vals.size();
133 
134  if (n > 0)
135  {
136  file << a_key ;
137  for (int i=0; i < n; i++)
138  {
139  stringstream ss;
140  ss << a_vals[i];
141  if (i == n-1)
142  file << ss.str() << endl;
143  else
144  file << ss.str() << ",";
145  }
146  }
147  else
148  file << a_key << "0" <<endl;
149 
150  return 0;
151 }
152 
153 template int WriteVector(ofstream& file, const string& a_key, vector <double> a_vals);
154 
155 
156 
157 // =====================================================================
158 // ---------------------------------------------------------------------
159 // ---------------------------------------------------------------------
160 // =====================================================================
161 /*
162  \fn WriteVector
163  \param file : the output file
164  \param a_key : key to write
165  \param a_vals : vector containing the key values
166  \brief Write the key and its values in the file provided in parameter
167  \return 0 if success, positive value otherwise
168 */
169 int WriteVector(ofstream& file, const string& a_key, vector <string> a_vals)
170 {
171  int n = a_vals.size();
172 
173  if (n > 0)
174  {
175  file << a_key ;
176  for (int i=0; i < n; i++)
177  {
178  if (i == n-1)
179  file << a_vals[i] << endl;
180  else
181  file << a_vals[i] << ",";
182  }
183  }
184  else
185  file << a_key << "0" <<endl;
186 
187  return 0;
188 }
189 
190 
191 
192 // =====================================================================
193 // ---------------------------------------------------------------------
194 // ---------------------------------------------------------------------
195 // =====================================================================
196 /*
197  \fn WriteVector
198  \param file : the output file
199  \param a_key : key to write
200  \param a_vals : vector containing the key values
201  \brief Write the key and its values contained in a 2 level vector of strings in the file provided in parameter
202  \return 0 if success, positive value otherwise
203 */
204 int WriteVector(ofstream& file, const string& a_key, vector <vector<string> > a_vals)
205 {
206  int n = a_vals.size();
207  file << a_key;
208  for (int i=0; i < n; i++)
209  for (int j=0; j < 3; j++)
210  if (i == n-1 && j == 2)
211  file << a_vals[i][j] << endl;
212  else
213  file << a_vals[i][j] << ",";
214 
215  return 0;
216 }
217 
218 
219 
220 
221 // =====================================================================
222 // ---------------------------------------------------------------------
223 // ---------------------------------------------------------------------
224 // =====================================================================
225 /*
226  \fn GetGATEMacFiles(const string& a_pathMac, vector<string> ap_pathToMacFiles)
227  \param a_pathMac : path to a GATE main macro file
228  \param ap_pathToMacFiles : array containing the paths of macro files
229  \brief Extract the paths to each macro file contained in the main macro file.
230  \return 0 if success, positive value otherwise
231 */
232 int GetGATEMacFiles(const string& a_pathMac, vector<string> &ap_pathToMacFiles)
233 {
234  ifstream mac_file(a_pathMac, ios::in);
235 
236  if(mac_file)
237  {
238  string quickLine;
239 
240  while(getline(mac_file, quickLine))
241  {
242  vector <string> values;
243 
244  values = CheckGATECommand("/control/execute", quickLine);
245 
246  if (values.size()>0)
247  ap_pathToMacFiles.push_back(GetPathOfFile(a_pathMac)+values[0]);
248  }
249  }
250  else
251  {
252  Cerr("***** GetGATEMacFiles() -> Couldn't open mac file "<< a_pathMac << " !" << endl);
253  return -1;
254  }
255 
256  mac_file.close();
257  return 0;
258 }
259 
260 
261 
262 
263 // =====================================================================
264 // ---------------------------------------------------------------------
265 // ---------------------------------------------------------------------
266 // =====================================================================
267 /*
268  \fn GetGATESystemType
269  \param a_pathMac : path to a GATE macro file
270  \brief Read a GATE macro file and identify the system type from the 'gate/systems/' command lines
271  \return system type, as described by the macro GATE_SYS_TYPE, -1 if error
272 */
273 int GetGATESystemType(const string& a_pathMac)
274 {
275  int system_type = GATE_SYS_UNKNOWN;
276 
277  // Recover path to all macro files from the main mac file
278  vector<string> path_mac_files;
279  path_mac_files.push_back(a_pathMac);
280 
281  if(GetGATEMacFiles(a_pathMac , path_mac_files))
282  {
283  Cerr("***** GetGATESystemType() -> Error occured when trying to recover paths to GATE macro files !" << endl);
284  return -1;
285  }
286 
287  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
288  cout << f << " : " << path_mac_files[f] << endl;
289 
290  // Loop on all macro files
291  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
292  {
293  ifstream mac_file(path_mac_files[f], ios::in);
294 
295  if(mac_file)
296  {
297  string line;
298  while(getline(mac_file, line))
299  {
300  // Check a 'gate/systems' command line
301  if(line.find("/gate/systems/") != string::npos )
302  {
303  if(line.find("/gate/systems/ecat") != string::npos )
304  system_type = GATE_SYS_ECAT;
305 
306  if(line.find("/gate/systems/cylindricalPET") != string::npos )
307  system_type = GATE_SYS_CYLINDRICAL;
308 
309  if(line.find("/gate/systems/SPECThead") != string::npos )
310  system_type = GATE_SYS_SPECT;
311 
312  if(line.find("/gate/systems/OPET") != string::npos ||
313  line.find("/gate/systems/CTSCANNER") != string::npos ||
314  line.find("/gate/systems/CPET") != string::npos ||
315  line.find("/gate/systems/ecatAccel") != string::npos ||
316  line.find("/gate/systems/OpticalSystem") != string::npos )
317  {
318  Cerr("unsupported system detected (line = " << line <<") ! "<< endl);
319  Cerr("supported systems for this script are cylindricalPET, SPECThead, and ecat" << endl);
320  }
321  }
322  }
323  }
324  else
325  {
326  Cerr("***** GetGATESystemType() -> Error : Couldn't open mac file "<< path_mac_files[f] << " !" << endl);
327  return -1;
328  }
329 
330  mac_file.close();
331  }
332 
333  return system_type;
334 }
335 
336 
337 
338 
339 // =====================================================================
340 // ---------------------------------------------------------------------
341 // ---------------------------------------------------------------------
342 // =====================================================================
343 /*
344  \fn GetGATEAliasesCylindrical(vector<string> path_mac_files
345  string& rsector_name,
346  string& module_name,
347  string& submodule_name,
348  string& crystal_name,
349  vector<string>& layers_name,
350  int vb )
351  \param path_mac_files
352  \param rsector_name
353  \param module_name
354  \param submodule_name
355  \param crystal_name
356  \param layers_name
357  \param vb
358  \brief Loop over a list of path to GATE macro files passed in parameter
359  to recover aliases of the different parts of a cylindricalPET
360  \return 0 if success, positive value otherwise
361 */
362 int GetGATEAliasesCylindrical(vector<string> path_mac_files,
363  string& rsector_name,
364  string& module_name,
365  string& submodule_name,
366  string& crystal_name,
367  vector<string>& layers_name,
368  int vb )
369 {
370  int depth = 0;
371 
372  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
373  {
374  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
375 
376  if(mac_file)
377  {
378  string quickLine;
379  while(getline(mac_file, quickLine))
380  {
381  vector <string> values;
382 
383  values = CheckGATECommand("/gate/systems/cylindricalPET/rsector/attach", quickLine);
384 
385  if (values.size()>0)
386  {
387  rsector_name = values[0];
388  depth++;
389  }
390 
391  values = CheckGATECommand("/gate/systems/cylindricalPET/module/attach", quickLine);
392  if (values.size()>0)
393  {
394  module_name = values[0];
395  depth++;
396  }
397 
398  values = CheckGATECommand("/gate/systems/cylindricalPET/submodule/attach", quickLine);
399  if (values.size()>0)
400  {
401  submodule_name = values[0];
402  depth++;
403  }
404 
405  values = CheckGATECommand("/gate/systems/cylindricalPET/crystal/attach", quickLine);
406  if (values.size()>0)
407  {
408  crystal_name = values[0];
409  depth++;
410  }
411 
412  // layers
413  for(int l=0 ; l<GATE_NB_MAX_LAYERS ; l++)
414  {
415  stringstream ss;
416  ss << l;
417  values = CheckGATECommand("/gate/systems/cylindricalPET/layer"+ss.str()+"/attach", quickLine);
418  if (values.size()>0)
419  {
420  layers_name.push_back(values[0]);
421  depth++;
422  }
423  }
424 
425  }
426  }
427  else
428  {
429  Cerr("***** GetGATEAliasesCylindrical()->Couldn't open mac file "<< path_mac_files[f] << " !" << endl);
430  return 1;
431  }
432 
433  mac_file.close();
434  }
435 
436 
437  // Check we have the required number of elements for the system
438  if (depth < 2)
439  {
440  Cout("***** GetGATEAliasesCylindrical() :: Error : Missing elements in the system architecture" << endl <<
441  " At least two of the following lines are required :" << endl <<
442  " - /gate/systems/cylindricalPET/rsector/attach" << endl <<
443  " - /gate/systems/cylindricalPET/module/attach" << endl <<
444  " - /gate/systems/cylindricalPET/submodule/attach" << endl <<
445  " - /gate/systems/cylindricalPET/crystal/attach" << endl <<
446  " - /gate/systems/cylindricalPET/layeri[i=0..3]/attach" << endl);
447  return 1;
448  }
449  else
450  {
451  // Interpret the first element as the rsector
452  if(rsector_name.empty())
453  {
454  if(module_name.empty())
455  {
456  //submodule as rsector
457  rsector_name = submodule_name;
458  submodule_name = "";
459  }
460  else
461  {
462  //module as rsector
463  rsector_name = module_name;
464  module_name = "";
465  }
466  }
467 
468  if(vb >= 2)
469  {
470  if(!rsector_name.empty()) Cout("Detected rsector container's name : " << rsector_name << endl);
471  if(!module_name.empty()) Cout("Detected module container's name : " << module_name << endl);
472  if(!submodule_name.empty()) Cout("Detected submodule container's name : " << submodule_name << endl);
473  if(!crystal_name.empty()) Cout("Detected crystal container's name : " << crystal_name << endl);
474  for(size_t l=0 ; l<layers_name.size() ; l++)
475  if(!layers_name[l].empty()) Cout("Detected layer #"<< l << " container's name : " << layers_name[l] << endl);
476  }
477  }
478 
479  return 0;
480 }
481 
482 
483 
484 
485 // =====================================================================
486 // ---------------------------------------------------------------------
487 // ---------------------------------------------------------------------
488 // =====================================================================
489 /*
490  \fn GetGATEAliasesEcat(vector<string> path_mac_files,
491  string& block_name,
492  string& crystal_name,
493  int vb )
494  \param path_mac_files
495  \param block_name
496  \param crystal_name
497  \param vb
498  \brief Loop over a list of path to GATE macro files passed in parameter
499  to recover aliases of the different parts of an ecat system
500  \return 0 if success, positive value otherwise
501 */
502 int GetGATEAliasesEcat(vector<string> path_mac_files,
503  string& block_name,
504  string& crystal_name,
505  int vb )
506 {
507  int depth = 0;
508 
509  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
510  {
511  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
512 
513  if(mac_file)
514  {
515  // Reading the .mac file line by line and finding the names of the different parts of the architecture
516  string quickLine;
517  while(getline(mac_file, quickLine))
518  {
519  vector <string> values;
520 
521  values = CheckGATECommand("/gate/systems/ecat/block/attach", quickLine);
522  if (values.size()>0)
523  {
524  block_name = values[0];
525  depth++;
526  }
527 
528  values = CheckGATECommand("/gate/systems/ecat/crystal/attach", quickLine);
529  if (values.size()>0)
530  {
531  crystal_name = values[0];
532  depth++;
533  }
534  }
535  }
536  else
537  {
538  Cerr("***** GetGATEAliasesEcat()-> Couldn't open mac file "<< path_mac_files[f].c_str()<< " !" << endl);
539  return 1;
540  }
541  }
542 
543 
544  // Check we have the required number of elements for the system
545  if (depth < 2)
546  {
547  Cerr("***** GetGATEAliasesEcat() :: Error : Missing elements in the system architecture" << endl
548  << " The following lines are required :" << endl
549  << " - /gate/systems/ecat/block/attach" << endl
550  << " - /gate/systems/ecat/crystal/attach" << endl);
551  return 1;
552  }
553  else
554  {
555  if(vb >= 2)
556  Cout("First container's name (usually block) is : " << block_name << endl
557  << "Second container's name (usually crystal) is : " << crystal_name << endl);
558  }
559 
560  return 0;
561 }
562 
563 
564 
565 
566 
567 // =====================================================================
568 // ---------------------------------------------------------------------
569 // ---------------------------------------------------------------------
570 // =====================================================================
571 /*
572  \fn GetGATEAliasesSPECT(vector<string> path_mac_files,
573  string& base_name,
574  string& crystal_name,
575  string& pixel_name,
576  int vb )
577  \param path_mac_files
578  \param base_name
579  \param crystal_name
580  \param pixel_name
581  \param vb
582  \brief Loop over a list of path to GATE macro files passed in parameter
583  to recover aliases of the different parts of an ecat system
584  \return 0 if success, positive value otherwise
585 */
586 int GetGATEAliasesSPECT(vector<string> path_mac_files,
587  string& base_name,
588  string& crystal_name,
589  string& pixel_name,
590  int vb )
591 {
592  int depth = 0;
593 
594  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
595  {
596  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
597 
598  if(mac_file)
599  {
600  // Reading the .mac file line by line and finding the names of the different parts of the architecture
601  string quickLine;
602 
603  while(getline(mac_file, quickLine))
604  {
605  vector <string> values;
606 
607  values = CheckGATECommand("/gate/systems/SPECThead/base/attach", quickLine);
608  if (values.size()>0)
609  {
610  base_name = values[0];
611  depth++;
612  }
613 
614  values = CheckGATECommand("/gate/systems/SPECThead/crystal/attach", quickLine);
615  if (values.size()>0)
616  {
617  crystal_name = values[0];
618  depth++;
619  }
620 
621  values = CheckGATECommand("/gate/systems/SPECThead/pixel/attach", quickLine);
622  if (values.size()>0)
623  {
624  pixel_name = values[0];
625  depth++;
626  }
627  }
628 
629  }
630  else
631  {
632  Cerr("***** GetGATEAliasesSPECT()-> Couldn't open mac file "<< path_mac_files[f].c_str()<< " !" << endl);
633  return 1;
634  }
635  }
636 
637  // Check we have the required number of elements for the system
638  if (depth < 1)
639  {
640  Cerr("***** GetGATEAliasesSPECT() :: Error : Missing elements in the system architecture" << endl
641  << " The following line is required :" << endl
642  << " - /gate/systems/SPECThead/crystal/attach" << endl);
643  return 1;
644  }
645  else
646  {
647  if(vb >= 2)
648  Cout("Crystal container's name is : " << crystal_name << endl);
649  }
650 
651  return 0;
652 }
653 
654 
655 
656 
657 // =====================================================================
658 // ---------------------------------------------------------------------
659 // ---------------------------------------------------------------------
660 // =====================================================================
661 /*
662  \fn ConvertIDecat
663  \param nBlocksPerRing
664  \param nBlocksLine
665  \param nCrystalsTransaxial
666  \param nCrystalsAxial
667  \param crystalID
668  \param blockID
669  \brief Compute a CASToR crystal index of a GATE ecat system from its indexes (block/crystal) and the system layout
670  \return CASToR crystal index
671 */
672 uint32_t ConvertIDecat( int32_t nBlocksPerRing,
673  int32_t nBlocksLine,
674  int32_t nCrystalsTransaxial,
675  int32_t nCrystalsAxial,
676  int32_t crystalID,
677  int32_t blockID)
678 {
679  int32_t nCrystalsPerRing = nBlocksPerRing * nCrystalsTransaxial;
680 
681  int32_t ringID = (int32_t)( blockID/nBlocksPerRing ) * nCrystalsAxial
682  + (int32_t)( crystalID/nCrystalsTransaxial );
683 
684  int32_t castorID = nCrystalsPerRing * ringID
685  + nCrystalsTransaxial*( blockID % nBlocksPerRing )
686  + crystalID % nCrystalsTransaxial;
687 
688  return castorID;
689 }
690 
691 
692 
693 // =====================================================================
694 // ---------------------------------------------------------------------
695 // ---------------------------------------------------------------------
696 // =====================================================================
697 /*
698  \fn ConvertIDSPECTRoot1
699  \param a_headID : head index as provided in the root file
700  \param a_rotAngle : rotation angle (deg) as provided in the root file
701  \param a_angStep : angular step (deg) computed from the macro file
702  \param a_nProjectionsByHead : total number of projections for each head
703  \brief Compute a CASToR projection index of a GATE SPECThead system
704  \return CASToR crystal index
705 */
706 uint32_t ConvertIDSPECTRoot1( int32_t a_headID,
707  float_t a_rotAngle,
708  float_t a_angStep,
709  uint32_t a_nProjectionsByHead)
710 {
711  // Compute angular index from the angle position of the head and the angular step
712  int32_t angID = round(a_rotAngle/a_angStep);
713 
714  // Get final index for this head
715  int32_t castorID = a_headID*a_nProjectionsByHead + angID;
716 
717  return castorID;
718 }
719 
720 
721 
722 
723 // =====================================================================
724 // ---------------------------------------------------------------------
725 // ---------------------------------------------------------------------
726 // =====================================================================
727 /*
728  \fn ConvertIDSPECTRoot2
729  \param a_nbSimulatedPixels
730  \param a_nPixTrs
731  \param a_nPixAxl
732  \param a_headID
733  \param a_crystalID
734  \param a_pixelID
735  \param a_rotAngle
736  \param a_headAngPitch
737  \param a_crystalSizeAxl
738  \param a_crystalSizeTrs
739  \param a_gPosX
740  \param a_gPosY
741  \param a_gPosZ
742  \brief Compute a CASToR crystal index of a GATE SPECThead system
743  \return CASToR crystal index. Return a higher number than the max index if error
744 */
745 uint32_t ConvertIDSPECTRoot2( uint32_t a_nbSimulatedPixels,
746  uint32_t a_nPixTrs,
747  uint32_t a_nPixAxl,
748  int32_t a_headID,
749  int32_t a_crystalID,
750  int32_t a_pixelID,
751  float_t a_rotAngle,
752  float_t a_headAngPitch,
753  float_t a_crystalSizeAxl,
754  float_t a_crystalSizeTrs,
755  float_t a_gPosX,
756  float_t a_gPosY,
757  float_t a_gPosZ)
758 {
759  int32_t castorID = 0;
760 
761  // we have a pixel matrix, just return the pixelID
762  if (a_nbSimulatedPixels > 1)
763  {
764  castorID = a_pixelID;
765  }
766  // Compute the pixelID according to the global XYZ positions in the crystal
767  // Cheap implementation. Does not take the DOI into account (would depend on collimator)
768  else
769  {
770  // Compute pixel sizes
771  FLTNB sizePixTrs = a_crystalSizeTrs/a_nPixTrs;
772  FLTNB sizePixAxl = a_crystalSizeAxl/a_nPixAxl;
773 
774  // Compute axial ID
775  uint32_t axialID = (int32_t)(( a_gPosZ + a_nPixAxl/2*sizePixAxl) / sizePixAxl);
776 
777  // Compute transaxial ID
778  // Compute head position angle ( in GATE referential)
779  float_t ang = a_headID*a_headAngPitch + a_rotAngle;
780 
781  // Get transaxial position
782  float_t sin_a = sin(-ang*M_PI/180);
783  float_t cos_a = cos(-ang*M_PI/180);
784  float_t trs_pos = a_gPosX*sin_a + a_gPosY*cos_a ;
785 
786  // Compute transaxial ID
787  uint32_t transID = (int32_t)(( trs_pos + a_nPixTrs/2*sizePixTrs) / sizePixTrs);
788 
789  if(axialID >= 0 && axialID < a_nPixAxl &&
790  transID >= 0 && transID < a_nPixTrs )
791  {
792  castorID = axialID*a_nPixTrs + transID;
793  }
794  else // return more than the max crystal ID to check for errors
795  {
796  castorID = a_nPixAxl*a_nPixTrs;
797  }
798 
799  }
800 
801  return castorID;
802 }
803 
804 
805 
806 
807 // =====================================================================
808 // ---------------------------------------------------------------------
809 // ---------------------------------------------------------------------
810 // =====================================================================
811 /*
812  \fn ConvertIDcylindrical
813  \param nRsectorsPerRing
814  \param nModulesTransaxial
815  \param nModulesAxial
816  \param nSubmodulesTransaxial
817  \param nSubmodulesAxial
818  \param nCrystalsTransaxial
819  \param nCrystalsAxial
820  \param nLayers
821  \param nb_crystal_per_layer
822  \param nLayersRptTransaxial
823  \param nLayersRptAxial
824  \param layerID
825  \param crystalID
826  \param submoduleID
827  \param moduleID
828  \param rsectorID
829  \brief Compute a CASToR crystal index of a GATE cylindricalPET system from its indexes (rsector/module/submodule/crystal) and the system layout
830  \return CASToR crystal index
831 */
832 uint32_t ConvertIDcylindrical(uint32_t nRsectorsPerRing,
833  uint32_t nModulesTransaxial,
834  uint32_t nModulesAxial,
835  uint32_t nSubmodulesTransaxial,
836  uint32_t nSubmodulesAxial,
837  uint32_t nCrystalsTransaxial,
838  uint32_t nCrystalsAxial,
839  uint8_t nLayers,
840  uint32_t* nCrystalPerLayer,
841  vector<uint32_t> nLayersRptTransaxial,
842  vector<uint32_t> nLayersRptAxial,
843  int32_t layerID,
844  int32_t crystalID,
845  int32_t submoduleID,
846  int32_t moduleID,
847  int32_t rsectorID)
848 {
849  // Castor ID definition
850  uint32_t castorID = 0;
851  uint8_t layer = 0;
852 
853  if(nLayersRptTransaxial.size()==0 && nLayersRptAxial.size()==0)
854  {
855  // layerID represents the actual layer level
856 
857  // add the number of crystals contained in previous layers as
858  // CASToR indexes all crystals of a layer ring before the next layer
859  layer = layerID;
860 
861  for(int l=0 ; l<layer; l++)
862  castorID += nCrystalPerLayer[l];
863 
864  int32_t nTrsCrystalsPerSubmodule = nCrystalsTransaxial;
865  int32_t nTrsCrystalsPerModule = nTrsCrystalsPerSubmodule * nSubmodulesTransaxial;
866  int32_t nTrsCrystalsPerRsector = nTrsCrystalsPerModule * nModulesTransaxial;
867  int32_t nCrystalsPerRing = nTrsCrystalsPerRsector * nRsectorsPerRing;
868 
869  int32_t ringID = (int32_t)(moduleID/nModulesTransaxial) * nSubmodulesAxial * nCrystalsAxial
870  + (int32_t)(submoduleID/nSubmodulesTransaxial) * nCrystalsAxial
871  + (int32_t)(crystalID/nCrystalsTransaxial);
872 
873  castorID += nCrystalsPerRing * ringID
874  + nTrsCrystalsPerRsector * rsectorID
875  + nTrsCrystalsPerModule * ( moduleID % nModulesTransaxial )
876  + nTrsCrystalsPerSubmodule * ( submoduleID % nSubmodulesTransaxial )
877  + crystalID % nCrystalsTransaxial;
878  }
879 
880  else
881  {
882  // layerID represents a crystal layer element
883 
884  // Get the total number of crystals in the first layer
885  uint32_t sum_crystals = nLayersRptTransaxial[layer]
886  * nLayersRptAxial[layer];
887 
888  // Get the layer which the crystal belongs to
889  while (layerID >= (int32_t)sum_crystals)
890  {
891  layer++;
892  sum_crystals += nLayersRptTransaxial[layer]
893  * nLayersRptAxial[layer];
894  }
895 
896  // add the number of crystals contained in previous layers as
897  // CASToR indexes all crystals of a layer ring before the next layer
898  for(int l=0 ; l<layer ; l++)
899  castorID += nCrystalPerLayer[l];
900 
901  int32_t nTrsCrystalsPerSubmodule = nCrystalsTransaxial * nLayersRptTransaxial[layer];
902  int32_t nTrsCrystalsPerModule = nTrsCrystalsPerSubmodule * nSubmodulesTransaxial;
903  int32_t nTrsCrystalsPerRsector = nTrsCrystalsPerModule * nModulesTransaxial;
904  int32_t nCrystalsPerRing = nTrsCrystalsPerRsector * nRsectorsPerRing;
905 
906  int32_t ringID = (int32_t)(moduleID/nModulesTransaxial) * nSubmodulesAxial * nCrystalsAxial * nLayersRptAxial[layer]
907  + (int32_t)(submoduleID/nSubmodulesTransaxial) * nCrystalsAxial * nLayersRptAxial[layer]
908  + (int32_t)(crystalID/nCrystalsTransaxial) * nLayersRptAxial[layer];
909 
910  if(nLayersRptTransaxial.empty() || nLayersRptAxial.empty() )
911  ringID += (int32_t)(layerID/nLayersRptTransaxial[layer]);
912 
913  castorID += nCrystalsPerRing * ringID
914  + nTrsCrystalsPerRsector * rsectorID
915  + nTrsCrystalsPerModule * ( moduleID % nModulesTransaxial )
916  + nTrsCrystalsPerSubmodule * ( submoduleID % nSubmodulesTransaxial )
917  + crystalID % nCrystalsTransaxial
918  + layerID % nLayersRptTransaxial[layer];
919 
920  }
921 
922 
923  return castorID;
924 }
925 
926 
927 
928 // =====================================================================
929 // ---------------------------------------------------------------------
930 // ---------------------------------------------------------------------
931 // =====================================================================
932 /*
933  \fn ComputeKindGATEEvent
934  \param eventID1
935  \param eventID2
936  \param comptonPhantom1
937  \param comptonPhantom2
938  \param rayleighPhantom1
939  \param rayleighPhantom2
940  \brief Determine kind of a given coincidence event, from its attributes
941  \return kind of the coincidence : unknown (=0, default), true(=1), single scat(=2), multiple scat(=3), random(=4)) (default value =0)
942 */
943 int ComputeKindGATEEvent(uint32_t eventID1, uint32_t eventID2,
944  int comptonPhantom1, int comptonPhantom2,
945  int rayleighPhantom1, int rayleighPhantom2)
946 {
947  if (eventID1 != eventID2)
948  //random
949  return KIND_RDM;
950  else
951  {
952  if (comptonPhantom1 == 0 && comptonPhantom2 == 0 &&
953  rayleighPhantom1 == 0 && rayleighPhantom2 == 0)
954  //true
955  return KIND_TRUE;
956  else
957  {
958  if (comptonPhantom1 == 1 || comptonPhantom2 == 1 ||
959  rayleighPhantom1 == 1 || rayleighPhantom2 == 1)
960  //single scat
961  return KIND_SCAT;
962  if (comptonPhantom1 > 1 || comptonPhantom2 > 1 ||
963  rayleighPhantom1 > 1 || rayleighPhantom2 > 1)
964  //multiple scat
965  return KIND_MSCAT;
966  }
967  }
968  // unknown
969  return KIND_UNKNOWN;
970 }
971 
972 
973 
974 // =====================================================================
975 // ---------------------------------------------------------------------
976 // ---------------------------------------------------------------------
977 // =====================================================================
978 /*
979  \fn ReadMacCylindrical
980  \param a_pathMac : path to a macro file
981  \param nLayers : nb of crystal layers
982  \param nCrystalsAxial : nb of axial crystals (in a submodule)
983  \param nCrystalsTransaxial : nb of transaxial crystals (in a submodule)
984  \param nLayersRptAxial : Array containing the number of axial crystals in each layer
985  \param nLayersRptTransaxial : Array containing the number of transaxial crystals in each layer
986  \param nSubmodulesAxial : nb of axial submodules (in a module)
987  \param nSubmodulesTransaxial : nb of transaxial submodules (in a module)
988  \param nModulesAxial : nb of axial modules (in a rsector)
989  \param nModulesTransaxial : nb of transaxial modules (in a rsector)
990  \param nRsectorsPerRing : nb of rsectors per ring
991  \param start_time_ms : acquisition start time converted in ms
992  \param duration_ms : acquisition duration converted in ms
993  \param vb : verbosity
994  \brief Recover informations about the scanner element of a cylindricalPET system and acquisition duration, from a GATE macro file
995  \return 0 if success, positive value otherwise
996 */
997 int ReadMacCylindrical(string a_pathMac,
998  uint8_t &nLayers,
999  uint32_t *nb_crystal_per_layer,
1000  uint32_t &nCrystalsTot,
1001  uint32_t &nCrystalsAxial,
1002  uint32_t &nCrystalsTransaxial,
1003  vector<uint32_t> &nLayersRptAxial,
1004  vector<uint32_t> &nLayersRptTransaxial,
1005  uint32_t &nSubmodulesAxial,
1006  uint32_t &nSubmodulesTransaxial,
1007  uint32_t &nModulesAxial,
1008  uint32_t &nModulesTransaxial,
1009  uint32_t &nRsectorsPerRing,
1010  uint32_t &start_time_ms,
1011  uint32_t &duration_ms,
1012  int vb)
1013 {
1014  vector<string> path_mac_files;
1015  path_mac_files.push_back(a_pathMac);
1016 
1017  // Recover path to all macro files from the main mac file
1018  if(GetGATEMacFiles(a_pathMac , path_mac_files))
1019  {
1020  Cerr("***** GetGATESystemType() -> Error occured when trying to recover paths to GATE macro files !" << endl);
1021  return 1;
1022  }
1023 
1024  string rsector_name = "";
1025  string module_name = "";
1026  string submodule_name = "";
1027  string crystal_name = "";
1028  string mod_rptr_type = "cubicArray";
1029  string smod_rptr_type = "cubicArray";
1030  string cry_rptr_type = "cubicArray";
1031  string lay_rptr_type = "cubicArray";
1032 
1033  vector <string> layers_name;
1034  bool is_rsector_Y_axis = false;
1035 
1036  // Recover aliases of the different parts of the architecture
1037  if(GetGATEAliasesCylindrical(path_mac_files, rsector_name, module_name, submodule_name, crystal_name, layers_name, vb) )
1038  {
1039  Cerr("***** GetGATESystemType() -> Error occured when trying to recover aliases for the elements of the cylindricalPET !" << endl);
1040  return 1;
1041  }
1042 
1043  // Recover nb of detected layers
1044  nLayers = layers_name.size();
1045 
1046  // Loop to recover all other informations
1047  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
1048  {
1049  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
1050 
1051  string line;
1052  double time_start =-1.,
1053  time_stop =-1.,
1054  time_slices =-1.;
1055 
1056  while(getline(mac_file, line))
1057  {
1058  vector <string> values;
1059  string kword ="";
1060 
1061 
1062  // RSECTORS
1063 
1064  kword = "/gate/"+rsector_name+"/placement/setTranslation";
1065  values = CheckGATECommand(kword, line);
1066 
1067  // Check where the first rsector has been created
1068  if (values.size()>0)
1069  {
1070  FLTNB rsector_pos_X =0.,
1071  rsector_pos_Y =0.;
1072 
1073  if(ConvertFromString(values[0], &rsector_pos_X) ||
1074  ConvertFromString(values[1], &rsector_pos_Y) )
1075  {
1076  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
1077  return 1;
1078  }
1079 
1080  // Get the axis on which the first rsector is positionned
1081  if(rsector_pos_Y!=0) is_rsector_Y_axis = true;
1082  }
1083 
1084 
1085  kword = "/gate/"+rsector_name+"/ring/setRepeatNumber";
1086  values = CheckGATECommand(kword, line);
1087  if (values.size()>0)
1088  {
1089  if(ConvertFromString( values[0] , &nRsectorsPerRing) )
1090  {
1091  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1092  return 1;
1093  }
1094  }
1095 
1096 
1097  // MODULES
1098 
1099  // Box/cubicArray repeaters
1100  kword = is_rsector_Y_axis ?
1101  "/gate/"+module_name+"/cubicArray/setRepeatNumberX":
1102  "/gate/"+module_name+"/cubicArray/setRepeatNumberY";
1103 
1104  values = CheckGATECommand(kword, line);
1105  if (values.size()>0)
1106  {
1107  if(ConvertFromString( values[0] , &nModulesTransaxial) )
1108  {
1109  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1110  return 1;
1111  }
1112  }
1113 
1114  kword = "/gate/"+module_name+"/cubicArray/setRepeatNumberZ";
1115  values = CheckGATECommand(kword, line);
1116  if (values.size()>0)
1117  {
1118  if(ConvertFromString( values[0] , &nModulesAxial) )
1119  {
1120  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1121  return 1;
1122  }
1123  }
1124 
1125  // linear repeaters instead of box
1126  kword = "/gate/"+module_name+"/linear/setRepeatNumber";
1127  values = CheckGATECommand(kword, line);
1128  if (values.size()>0)
1129  {
1130  if(ConvertFromString( values[0] , &nModulesAxial) )
1131  {
1132  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1133  return 1;
1134  }
1135  }
1136 
1137 
1138  // SUBMODULES
1139 
1140  kword = is_rsector_Y_axis ?
1141  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberX":
1142  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberY";
1143 
1144  values = CheckGATECommand(kword, line);
1145  if (values.size()>0)
1146  {
1147  if(ConvertFromString( values[0] , &nSubmodulesTransaxial) )
1148  {
1149  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1150  return 1;
1151  }
1152  }
1153 
1154  kword = "/gate/"+submodule_name+"/cubicArray/setRepeatNumberZ";
1155  values = CheckGATECommand(kword, line);
1156  if (values.size()>0)
1157  {
1158  if(ConvertFromString( values[0] , &nSubmodulesAxial) )
1159  {
1160  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1161  return 1;
1162  }
1163  }
1164 
1165  // linear repeaters instead of box
1166  kword = "/gate/"+submodule_name+"/linear/setRepeatNumber";
1167  values = CheckGATECommand(kword, line);
1168  if (values.size()>0)
1169  {
1170  if(ConvertFromString( values[0] , &nSubmodulesAxial) )
1171  {
1172  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1173  return 1;
1174  }
1175  }
1176 
1177 
1178 
1179  // CRYSTALS
1180 
1181  kword = is_rsector_Y_axis ?
1182  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
1183  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
1184 
1185  kword = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
1186  values = CheckGATECommand(kword, line);
1187  if (values.size()>0)
1188  {
1189  if(ConvertFromString( values[0] , &nCrystalsTransaxial) )
1190  {
1191  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1192  return 1;
1193  }
1194  }
1195 
1196  kword = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
1197  values = CheckGATECommand(kword, line);
1198  if (values.size()>0)
1199  {
1200  if(ConvertFromString( values[0] , &nCrystalsAxial) )
1201  {
1202  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1203  return 1;
1204  }
1205  }
1206 
1207 
1208  // linear repeaters instead of box
1209  kword = "/gate/"+crystal_name+"/linear/setRepeatNumber";
1210  values = CheckGATECommand(kword, line);
1211  if (values.size()>0)
1212  {
1213  if(ConvertFromString( values[0] , &nCrystalsAxial) )
1214  {
1215  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1216  return 1;
1217  }
1218  }
1219 
1220 
1221  // LAYERS
1222 
1223  // Check if there are any repeaters on crystal layers
1224  for(int l=0 ; l<nLayers ; l++)
1225  {
1226  kword = is_rsector_Y_axis ?
1227  "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberX":
1228  "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberY";
1229 
1230  values = CheckGATECommand(kword, line);
1231  if (values.size()>0)
1232  {
1233  int32_t val;
1234  if(ConvertFromString( values[0] , &val) )
1235  {
1236  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1237  return 1;
1238  }
1239  nLayersRptTransaxial.push_back(val);
1240  }
1241 
1242  kword = "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberZ";
1243  values = CheckGATECommand(kword, line);
1244  if (values.size()>0)
1245  {
1246  int32_t val;
1247  if(ConvertFromString( values[0] , &val) )
1248  {
1249  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1250  return 1;
1251  }
1252  nLayersRptAxial.push_back(val);
1253  }
1254 
1255  // linear repeaters instead of box
1256  kword = "/gate/"+layers_name[l]+"/linear/setRepeatNumber";
1257  values = CheckGATECommand(kword, line);
1258  if (values.size()>0)
1259  {
1260  int32_t val;
1261  if(ConvertFromString( values[0] , &val) )
1262  {
1263  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1264  return 1;
1265  }
1266  nLayersRptAxial.push_back(val);
1267  }
1268 
1269 
1270  }
1271 
1272 
1273  kword = "/gate/application/setTimeStart";
1274  values = CheckGATECommand(kword, line);
1275  if (values.size()>0)
1276  {
1277  if(ConvertFromString( values[0] , &time_start) )
1278  {
1279  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1280  return 1;
1281  }
1282 
1283  // Convert in ms
1284  if (values.size()>1)
1285  {
1286  if(values[1] == "s") time_start *= 1000;
1287  }
1288  else
1289  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1290 
1291  start_time_ms = time_start;
1292  }
1293 
1294  kword = "/gate/application/setTimeStop";
1295  values = CheckGATECommand(kword, line);
1296  if (values.size()>0)
1297  {
1298  if(ConvertFromString( values[0] , &time_stop) )
1299  {
1300  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1301  return 1;
1302  }
1303 
1304  // Convert in ms
1305  if (values.size()>1)
1306  {
1307  if(values[1] == "s") time_stop *= 1000;
1308  }
1309  else
1310  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1311  }
1312 
1313  kword = "/gate/application/addSlice";
1314  values = CheckGATECommand(kword, line);
1315  if (values.size()>0)
1316  {
1317  double time_slice_tmp=0;
1318 
1319  if(ConvertFromString( values[0] , &time_slice_tmp) )
1320  {
1321  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1322  return 1;
1323  }
1324 
1325  // Convert in ms
1326  if (values.size()>1)
1327  {
1328  if(values[1] == "s") time_slice_tmp *= 1000;
1329  }
1330  else
1331  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1332 
1333  time_slices += time_slice_tmp;
1334  }
1335  }
1336 
1337  // Compute duration in ms
1338  duration_ms = (time_slices>0) ?
1339  (uint32_t)(time_slices-time_start) :
1340  duration_ms;
1341 
1342  duration_ms = (time_start>=0 && time_stop>=0) ?
1343  (uint32_t)(time_stop-time_start) :
1344  duration_ms ;
1345 
1346  mac_file.close();
1347  }
1348 
1349  // Computing the total number of crystals in the scanner
1350  if(nLayers == 0)
1351  {
1352  nCrystalsTot = nRsectorsPerRing
1353  * nModulesTransaxial * nModulesAxial
1354  * nSubmodulesTransaxial * nSubmodulesAxial
1355  * nCrystalsTransaxial * nCrystalsAxial;
1356  }
1357  else
1358  for(int l=0 ; l<nLayers ; l++)
1359  {
1360  uint32_t nb_crystals_layer = nRsectorsPerRing
1361  * nModulesTransaxial * nModulesAxial
1362  * nSubmodulesTransaxial * nSubmodulesAxial
1363  * nCrystalsTransaxial * nCrystalsAxial;
1364 
1365  // Add layer elements if repeaters have been used on layers
1366  if(nLayersRptTransaxial.size()>0 || nLayersRptAxial.size()>0 )
1367  nb_crystals_layer *= nLayersRptTransaxial[l] * nLayersRptAxial[l];
1368 
1369  nb_crystal_per_layer[l] = nb_crystals_layer;
1370 
1371  nCrystalsTot += nb_crystals_layer;
1372  }
1373 
1374 
1375  if(vb >= 2)
1376  {
1377  Cout(endl);
1378  Cout("-----------------------------------------------------------" << endl);
1379  Cout("ReadMacCylindrical()-> Information recovered from mac file:" << endl);
1380  Cout("-----------------------------------------------------------" << endl);
1381  Cout("Number of rsectors: " << nRsectorsPerRing << endl);
1382  Cout("Number of axial modules: " << nModulesAxial << endl);
1383  Cout("Number of transaxial modules: " << nModulesTransaxial << endl);
1384  Cout("Number of axial submodules: " << nSubmodulesAxial << endl);
1385  Cout("Number of transaxial submodules: " << nSubmodulesTransaxial << endl);
1386  Cout("Number of axial crystals: " << nCrystalsAxial << endl);
1387  Cout("Number of transaxial crystals: " << nCrystalsTransaxial << endl);
1388  Cout("Number of layers: " << nLayers << endl);
1389  for(int l=0 ; l<nLayers ; l++)
1390  Cout("Layer "<< l <<" : Number of crystals: " << nb_crystal_per_layer << endl);
1391  Cout("Total number of crystals (including layers): " << nCrystalsTot << endl);
1392  Cout("Acquisition start time (ms): " << start_time_ms << endl);
1393  Cout("Acquisition duration (ms): " << duration_ms << endl);
1394  Cout("-----------------------------------------------------------" << endl << endl);
1395  }
1396 
1397  return 0;
1398 }
1399 
1400 
1401 
1402 // =====================================================================
1403 // ---------------------------------------------------------------------
1404 // ---------------------------------------------------------------------
1405 // =====================================================================
1406 /*
1407  \fn ReadMacECAT
1408  \param a_pathMac : path to a macro file
1409  \param nCrystalsAxial : nb of axial crystals
1410  \param nCrystalsTransaxial : nb of transaxial crystals
1411  \param nBlocksLine : nb of axial blocks
1412  \param nBlocksPerRing : nb of blocks per ring
1413  \param start_time_ms : acquisition start time converted in ms
1414  \param duration_ms : acquisition duration converted in ms
1415  \param vb : verbosity
1416  \brief Recover informations about the scanner element of an ECAT system, and acquisition duration, from a GATE macro file
1417  \return 0 if success, positive value otherwise
1418 */
1419 int ReadMacECAT( string a_pathMac,
1420  uint32_t &nCrystalsTot,
1421  uint32_t &nCrystalsAxial,
1422  uint32_t &nCrystalsTransaxial,
1423  uint32_t &nBlocksLine,
1424  uint32_t &nBlocksPerRing,
1425  uint32_t &start_time_ms,
1426  uint32_t &duration_ms,
1427  int vb)
1428 {
1429  // Recover path to all macro files from the main mac file
1430  vector<string> path_mac_files;
1431  path_mac_files.push_back(a_pathMac);
1432  if(GetGATEMacFiles(a_pathMac , path_mac_files))
1433  {
1434  Cerr("***** GetGATESystemType() -> Error occured when trying to recover paths to GATE macro files !" << endl);
1435  return 1;
1436  }
1437 
1438  string block_name = "block";
1439  string crystal_name = "crystal";
1440  bool is_block_Y_axis = false;
1441 
1442  // Recover aliases of the different parts of the architecture
1443  if(GetGATEAliasesEcat(path_mac_files, block_name, crystal_name, vb) )
1444  {
1445  Cerr("***** GetGATESystemType() -> Error occured when trying to recover aliases for the elements of the ecat !" << endl);
1446  return 1;
1447  }
1448 
1449 
1450  // 2nd loop to recover all other informations
1451  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
1452  {
1453  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
1454 
1455  string line;
1456  double time_start=-1.,
1457  time_stop=-1.,
1458  time_slices=-1.;
1459 
1460  while(getline(mac_file, line))
1461  {
1462  vector <string> values;
1463  string kword ="";
1464 
1465  kword = "/gate/"+block_name+"/placement/setTranslation";
1466  values = CheckGATECommand(kword, line);
1467  if (values.size()>0)
1468  {
1469  FLTNB block_pos_X=0.,
1470  block_pos_Y=0.;
1471 
1472  if(ConvertFromString(values[0], &block_pos_X) ||
1473  ConvertFromString(values[1], &block_pos_Y) )
1474  {
1475  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
1476  return 1;
1477  }
1478 
1479  // Get the axis on which the first rsector is positionned
1480  if(block_pos_Y!=0) is_block_Y_axis = true;
1481  }
1482 
1483  kword = "/gate/"+block_name+"/ring/setRepeatNumber";
1484  values = CheckGATECommand(kword, line);
1485  if (values.size()>0)
1486  {
1487  if(ConvertFromString( values[0] , &nBlocksPerRing) )
1488  {
1489  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1490  return 1;
1491  }
1492  }
1493 
1494  kword = "/gate/"+block_name+"/linear/setRepeatNumber";
1495  values = CheckGATECommand(kword, line);
1496  if (values.size()>0)
1497  {
1498  if(ConvertFromString( values[0] , &nBlocksLine) )
1499  {
1500  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1501  return 1;
1502  }
1503  }
1504 
1505  kword = is_block_Y_axis ?
1506  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
1507  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
1508 
1509  values = CheckGATECommand(kword, line);
1510  if (values.size()>0)
1511  {
1512  if(ConvertFromString( values[0] , &nCrystalsTransaxial) )
1513  {
1514  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1515  return 1;
1516  }
1517  }
1518 
1519  kword = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
1520  values = CheckGATECommand(kword, line);
1521  if (values.size()>0)
1522  {
1523  if(ConvertFromString( values[0] , &nCrystalsAxial) )
1524  {
1525  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1526  return 1;
1527  }
1528  }
1529 
1530 
1531  kword = "/gate/application/setTimeStart";
1532  values = CheckGATECommand(kword, line);
1533  if (values.size()>0)
1534  {
1535  if(ConvertFromString( values[0] , &time_start) )
1536  {
1537  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1538  return 1;
1539  }
1540 
1541  // Convert in ms
1542  if (values.size()>1)
1543  {
1544  if(values[1] == "s") time_start *= 1000;
1545  }
1546  else
1547  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1548 
1549  start_time_ms = time_start;
1550  }
1551 
1552  kword = "/gate/application/setTimeStop";
1553  values = CheckGATECommand(kword, line);
1554  if (values.size()>0)
1555  {
1556  if(ConvertFromString( values[0] , &time_stop) )
1557  {
1558  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1559  return 1;
1560  }
1561 
1562  // Convert in ms
1563  if (values.size()>1)
1564  {
1565  if(values[1] == "s") time_stop *= 1000;
1566  }
1567  else
1568  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1569  }
1570 
1571  kword = "/gate/application/addSlice";
1572  values = CheckGATECommand(kword, line);
1573  if (values.size()>0)
1574  {
1575  double time_slice_tmp=0;
1576 
1577  if(ConvertFromString( values[0] , &time_slice_tmp) )
1578  {
1579  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1580  return 1;
1581  }
1582 
1583  // Convert in ms
1584  if (values.size()>1)
1585  {
1586  if(values[1] == "s") time_slice_tmp *= 1000;
1587  }
1588  else
1589  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1590 
1591  time_slices = time_slice_tmp;
1592  }
1593  }
1594 
1595  // Compute duration in ms
1596  duration_ms = (time_slices>0) ?
1597  (uint32_t)(time_slices-time_start) :
1598  duration_ms;
1599 
1600  duration_ms = (time_start>=0 && time_stop>=0) ?
1601  (uint32_t)(time_stop-time_start) :
1602  duration_ms ;
1603 
1604  mac_file.close();
1605  }
1606 
1607  // Computing the total number of crystals in the scanner
1608  nCrystalsTot = nCrystalsTransaxial * nCrystalsAxial
1609  * nBlocksLine * nBlocksPerRing;
1610 
1611 
1612  if(vb >= 2)
1613  {
1614  Cout(endl);
1615  Cout("-----------------------------------------------------" << endl);
1616  Cout("ReadMacECAT()-> Information recovered from mac file:" << endl);
1617  Cout("-----------------------------------------------------" << endl);
1618  Cout("Number of blocks per ring: " << nBlocksPerRing << endl);
1619  Cout("Number of axial blocks: " << nBlocksLine << endl);
1620  Cout("Number of axial crystals: " << nCrystalsAxial << endl);
1621  Cout("Number of transaxial crystals: " << nCrystalsTransaxial << endl);
1622  Cout("Total number of crystals: " << nCrystalsTot << endl);
1623  Cout("Acquisition start time (ms): " << start_time_ms << endl);
1624  Cout("Acquisition duration (ms): " << duration_ms << endl);
1625  Cout("-----------------------------------------------------" << endl << endl);
1626  }
1627 
1628  return 0;
1629 }
1630 
1631 
1632 
1633 // =====================================================================
1634 // ---------------------------------------------------------------------
1635 // ---------------------------------------------------------------------
1636 // =====================================================================
1637 /*
1638  \fn ReadMacSPECT
1639  \param a_pathMac : path to a macro file
1640  \param distToDetector : distance between center of rotation and detector surface
1641  \param nHeads : nb of cameras
1642  \param nPixAxl : nb of transaxial pixels
1643  \param nPixTrs : nb of axial pixels
1644  \param crystalSizeAxl : crystal axial dimension
1645  \param crystalSizeTrs : crystal transaxial dimension
1646  \param head1stAngle : head first angle
1647  \param headAngPitch : angular pitch between heads
1648  \param headRotSpeed : angle between projection
1649  \param headRotDirection : rotation direction of the head (CW or CCW)
1650  \param start_time_ms : acquisition start time converted in ms
1651  \param duration_ms : acquisition duration converted in ms
1652  \param vb : verbosity
1653  \brief Recover informations about the scanner element of an ECAT system, and acquisition duration, from a GATE macro file
1654  \return 0 if success, positive value otherwise
1655 */
1656 int ReadMacSPECT( string a_pathMac,
1657  float_t &a_distToDetector,
1658  uint32_t &a_nHeads,
1659  uint32_t &a_nPixAxl,
1660  uint32_t &a_nPixTrs,
1661  float_t &a_crystalSizeAxl,
1662  float_t &a_crystalSizeTrs,
1663  uint32_t &a_nProjectionsTot,
1664  uint32_t &a_nProjectionsByHead,
1665  float_t &a_head1stAngle,
1666  float_t &a_headAngPitch,
1667  float_t &a_headAngStepDeg,
1668  int &a_headRotDirection,
1669  uint32_t &a_start_time_ms,
1670  uint32_t &a_duration_ms,
1671  int vb)
1672 {
1673  // Recover path to all macro files from the main mac file
1674  vector<string> path_mac_files;
1675  path_mac_files.push_back(a_pathMac);
1676 
1677  if(GetGATEMacFiles(a_pathMac , path_mac_files))
1678  {
1679  Cerr("***** GetGATESystemType() -> Error occured when trying to recover paths to GATE macro files !" << endl);
1680  return 1;
1681  }
1682 
1683  string head_name = "SPECThead";
1684  string crystal_name = "crystal";
1685  string pixel_name = "pixel";
1686  string head_orbit_name = "";
1687  bool is_head_Y_axis = false;
1688 
1689  // Recover aliases of the different parts of the architecture
1690  if(GetGATEAliasesSPECT(path_mac_files, head_name, crystal_name, pixel_name, vb) )
1691  {
1692  Cerr("***** GetGATESystemType() -> Error occured when trying to recover aliases for the elements of the ecat !" << endl);
1693  return 1;
1694  }
1695 
1696  // Init variables to recover some data
1697  double time_start=-1.,
1698  time_stop=-1.,
1699  time_slice=-1,
1700  time_slices=-1.,
1701  time_slice_ms=-1.,
1702  head_rot_speed =-1.;
1703 
1704  // 2nd loop to recover all other informations
1705  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
1706  {
1707  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
1708 
1709  string line;
1710 
1711  while(getline(mac_file, line))
1712  {
1713  vector <string> values;
1714  string kword ="";
1715  kword = "/gate/"+head_name+"/placement/setTranslation";
1716  values = CheckGATECommand(kword, line);
1717  if (values.size()>0)
1718  {
1719  FLTNB head_pos_X=0.,
1720  head_pos_Y=0.;
1721 
1722  if(ConvertFromString(values[0], &head_pos_X) ||
1723  ConvertFromString(values[1], &head_pos_Y) )
1724  {
1725  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
1726  return 1;
1727  }
1728 
1729  // Get the axis on which the first rsector is positionned
1730  if(head_pos_Y!=0) is_head_Y_axis = true;
1731 
1732  a_distToDetector = is_head_Y_axis ? abs(head_pos_Y) : abs(head_pos_X) ;
1733  }
1734 
1735 
1736 
1737  kword = "/gate/"+head_name+"/ring/setRepeatNumber";
1738  values = CheckGATECommand(kword, line);
1739  if (values.size()>0)
1740  {
1741  if(ConvertFromString(values[0], &a_nHeads))
1742  {
1743  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
1744  return 1;
1745  }
1746  }
1747 
1748  kword = "/gate/"+head_name+"/ring/setFirstAngle";
1749  values = CheckGATECommand(kword, line);
1750  if (values.size()>0)
1751  {
1752  if(ConvertFromString(values[0], &a_head1stAngle))
1753  {
1754  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
1755  return 1;
1756  }
1757  }
1758 
1759  kword = "/gate/"+head_name+"/ring/setAngularPitch";
1760  values = CheckGATECommand(kword, line);
1761  if (values.size()>0)
1762  {
1763  if(ConvertFromString(values[0], &a_headAngPitch))
1764  {
1765  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
1766  return 1;
1767  }
1768  }
1769 
1770  kword = "/gate/"+head_name+"/moves/insert";
1771  values = CheckGATECommand(kword, line);
1772  if (values.size()>0)
1773  {
1774  if(ConvertFromString(values[0], &head_orbit_name))
1775  {
1776  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
1777  return 1;
1778  }
1779  }
1780 
1781  kword = "/gate/"+head_name+"/"+head_orbit_name+"/setSpeed";
1782  values = CheckGATECommand(kword, line);
1783  if (values.size()>0)
1784  {
1785  if(ConvertFromString(values[0], &head_rot_speed))
1786  {
1787  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
1788  return 1;
1789  }
1790  }
1791 
1792  kword = "/gate/"+head_name+"/"+head_orbit_name+"/setPoint2";
1793  values = CheckGATECommand(kword, line);
1794  if (values.size()>0)
1795  {
1796  int rot_direction;
1797  if(ConvertFromString(values[2], &rot_direction))
1798  {
1799  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
1800  return 1;
1801  }
1802 
1803  a_headRotDirection = rot_direction>0 ? GEO_ROT_CW : GEO_ROT_CCW;
1804  }
1805 
1806  // --- Crystals ---
1807  kword = is_head_Y_axis ?
1808  "/gate/"+crystal_name+"/geometry/setXLength":
1809  "/gate/"+crystal_name+"/geometry/setYLength";
1810 
1811  values = CheckGATECommand(kword, line);
1812  if (values.size()>0)
1813  {
1814  if(ConvertFromString(values[0], &a_crystalSizeTrs) )
1815  {
1816  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
1817  return 1;
1818  }
1819 
1820  }
1821 
1822  kword = "/gate/"+crystal_name+"/geometry/setZLength";
1823  values = CheckGATECommand(kword, line);
1824  if (values.size()>0)
1825  {
1826  if(ConvertFromString(values[0], &a_crystalSizeAxl) )
1827  {
1828  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
1829  return 1;
1830  }
1831  }
1832 
1833 
1834  // --- Pixels ---
1835  kword = is_head_Y_axis ?
1836  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberX":
1837  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberY";
1838 
1839 
1840  values = CheckGATECommand(kword, line);
1841  if (values.size()>0)
1842  {
1843  if(ConvertFromString(values[0], &a_nPixTrs) )
1844  {
1845  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
1846  return 1;
1847  }
1848  }
1849 
1850  kword = "/gate/"+pixel_name+"/cubicArray/setRepeatNumberZ";
1851  values = CheckGATECommand(kword, line);
1852  if (values.size()>0)
1853  {
1854  if(ConvertFromString(values[0], &a_nPixAxl) )
1855  {
1856  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
1857  return 1;
1858  }
1859  }
1860 
1861  kword = "/gate/application/setTimeStart";
1862  values = CheckGATECommand(kword, line);
1863  if (values.size()>0)
1864  {
1865  if(ConvertFromString( values[0] , &time_start) )
1866  {
1867  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1868  return 1;
1869  }
1870 
1871  // Convert in ms
1872  if (values.size()>1)
1873  {
1874  if(values[1] == "s") time_start *= 1000;
1875  }
1876  else
1877  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1878 
1879  a_start_time_ms = time_start;
1880  }
1881 
1882  kword = "/gate/application/setTimeSlice";
1883  values = CheckGATECommand(kword, line);
1884  if (values.size()>0)
1885  {
1886  if(ConvertFromString( values[0] , &time_slice) )
1887  {
1888  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1889  return 1;
1890  }
1891 
1892  // Convert in ms
1893  if (values.size()>1)
1894  {
1895  if(values[1] == "s") time_slice *= 1000;
1896  }
1897  else
1898  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1899 
1900  time_slice_ms = time_slice;
1901  }
1902 
1903  kword = "/gate/application/setTimeStop";
1904  values = CheckGATECommand(kword, line);
1905  if (values.size()>0)
1906  {
1907  if(ConvertFromString( values[0] , &time_stop) )
1908  {
1909  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1910  return 1;
1911  }
1912 
1913  // Convert in ms
1914  if (values.size()>1)
1915  {
1916  if(values[1] == "s") time_stop *= 1000;
1917  }
1918  else
1919  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1920  }
1921 
1922  kword = "/gate/application/addSlice";
1923  values = CheckGATECommand(kword, line);
1924  if (values.size()>0)
1925  {
1926  double time_slice_tmp=0;
1927 
1928  if(ConvertFromString( values[0] , &time_slice_tmp) )
1929  {
1930  Cerr("***** dataConversionUtilities::readMacECAT()-> Error occured while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1931  return 1;
1932  }
1933 
1934  // Convert in ms
1935  if (values.size()>1)
1936  {
1937  if(values[1] == "s") time_slice_tmp *= 1000;
1938  }
1939  else
1940  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1941 
1942  time_slices = time_slice_tmp;
1943  }
1944  }
1945 
1946  // Compute duration in ms
1947 
1948  // Time slices were provided
1949  a_duration_ms = (time_slices>0) ?
1950  (uint32_t)(time_slices-time_start) :
1951  a_duration_ms;
1952 
1953  // Time stop/start is provided
1954  a_duration_ms = (time_start>=0 && time_stop>=0) ?
1955  (uint32_t)(time_stop-time_start) :
1956  a_duration_ms;
1957 
1958 
1959  // Compute the nb of projections and total number of crystals in the system
1960  a_nProjectionsByHead = a_duration_ms / time_slice_ms;
1961  a_nProjectionsTot = a_nHeads*a_nProjectionsByHead;
1962 
1963  // Compute angular pitch if not provided in the mac files (=-1)
1964  a_headAngPitch = (a_headAngPitch<0) ?
1965  360./a_nHeads :
1966  a_headAngPitch ;
1967 
1968  a_headAngStepDeg = head_rot_speed*time_slice_ms/1000.;
1969 
1970  if(head_rot_speed<0)
1971  {
1972  Cerr("***** GetGATESystemType() -> Error couldn't find line '/gate/"+head_name+"/"+head_orbit_name+"/setSpeed' !" << endl);
1973  Cerr(" This information is mandatory to compute the projection angle step." << endl);
1974  return 1;
1975  }
1976 
1977  if(time_slice_ms<0)
1978  {
1979  Cerr("***** GetGATESystemType() -> Error couldn't find line '/gate/application/setTimeSlice' !" << endl);
1980  Cerr(" This information is mandatory to compute the projection angle step." << endl);
1981  return 1;
1982  }
1983 
1984  if(a_duration_ms == 0)
1985  {
1986  if(time_stop <0)
1987  {
1988  Cerr("***** GetGATESystemType() -> Error couldn't compute acquisition find line '/gate/application/setTimeStop' !" << endl);
1989  Cerr(" This information is mandatory to compute the acquisition duration." << endl);
1990  return 1;
1991  }
1992  if(time_start <0)
1993  {
1994  Cerr("***** GetGATESystemType() -> Error couldn't compute acquisition find line '/gate/application/setTimeStart' !" << endl);
1995  Cerr(" This information is mandatory to compute the acquisition duration." << endl);
1996  return 1;
1997  }
1998  }
1999 
2000  mac_file.close();
2001  } // end loop on .mac files
2002 
2003  if(vb >= 2)
2004  {
2005  Cout(endl);
2006  Cout("-----------------------------------------------------" << endl);
2007  Cout("ReadMacSPECT()-> Information recovered from mac file:" << endl);
2008  Cout("-----------------------------------------------------" << endl);
2009  Cout("Distance to detector: " << a_distToDetector << endl);
2010  Cout("Number of heads: " << a_nHeads << endl);
2011  Cout("Number of axial pixels: " << a_nPixAxl << endl);
2012  Cout("Number of transaxial pixels: " << a_nPixTrs << endl);
2013  Cout("Crystal axial size: " << a_crystalSizeAxl << endl);
2014  Cout("Crystal transaxial size: " << a_crystalSizeTrs << endl);
2015  Cout("Number of projections per head: " << a_nProjectionsByHead << endl);
2016  Cout("Total number of projections: " << a_nProjectionsTot << endl);
2017  Cout("Head(s) first transaxial angle: " << a_head1stAngle << endl);
2018  Cout("Head(s) angular pitch: " << a_headAngPitch << endl);
2019  Cout("Angular step between projections (deg): " << a_headAngStepDeg << endl);
2020  Cout("Rotation direction (0=CW, 1=CCW): " << a_headRotDirection << endl);
2021  Cout("Acquisition start time (ms): " << a_start_time_ms << endl);
2022  Cout("Acquisition duration (ms): " << a_duration_ms << endl);
2023  Cout("-----------------------------------------------------" << endl << endl);
2024  }
2025 
2026  return 0;
2027 }
2028 
2029 
2030 
2031 
2032 // =====================================================================
2033 // ---------------------------------------------------------------------
2034 // ---------------------------------------------------------------------
2035 // =====================================================================
2036 /*
2037  \fn ReadIntfSPECT
2038  \param a_pathIntf : path to the interfile header
2039  \param distToDetector : distance between center of rotation and detector surface
2040  \param nHeads : nb of cameras
2041  \param nPixAxl : nb of transaxial pixels
2042  \param nPixTrs : nb of axial pixels
2043  \param crystalSizeAxl : crystal axial dimension
2044  \param crystalSizeTrs : crystal transaxial dimension
2045  \param head1stAngle : head first angle
2046  \param headAngPitch : angular pitch between heads
2047  \param headRotSpeed : angle between projection
2048  \param headRotDirection : rotation direction of the head (CW or CCW)
2049  \param start_time_ms : acquisition start time converted in ms
2050  \param duration_ms : acquisition duration converted in ms
2051  \param vb : verbosity
2052  \brief Recover informations about the scanner element of an ECAT system, and acquisition duration, from a GATE macro file
2053  \return 0 if success, positive value otherwise
2054 */
2055 int ReadIntfSPECT(string a_pathIntf,
2056  float_t &a_distToDetector,
2057  uint32_t &a_nHeads,
2058  uint32_t &a_nPixAxl,
2059  uint32_t &a_nPixTrs,
2060  float_t &a_crystalSizeAxl,
2061  float_t &a_crystalSizeTrs,
2062  uint32_t &a_nProjectionsTot,
2063  uint32_t &a_nProjectionsByHead,
2064  float_t &a_head1stAngle,
2065  float_t &a_headAngPitchDeg,
2066  float_t &a_headAngStepDeg,
2067  int &a_headRotDirection,
2068  uint32_t &a_start_time_ms,
2069  uint32_t &a_duration_ms,
2070  int vb)
2071 {
2072  // Read all required information in Interfile header
2073 
2074  string key;
2075 
2076  key = "matrix size [1]";
2077  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nPixTrs, 1, KEYWORD_MANDATORY))
2078  {
2079  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2080  Cerr(" Either key not found or conversion error" << endl);
2081  return 1;
2082  }
2083 
2084  key = "matrix size [2]";
2085  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nPixAxl, 1, KEYWORD_MANDATORY))
2086  {
2087  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2088  Cerr(" Either key not found or conversion error" << endl);
2089  return 1;
2090  }
2091 
2092  FLTNB size_pix_trs = 1.,
2093  size_pix_axl = 1.;
2094 
2095  key = "scaling factor (mm/pixel) [1]";
2096  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_pix_trs, 1, KEYWORD_MANDATORY))
2097  {
2098  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2099  Cerr(" Either key not found or conversion error" << endl);
2100  return 1;
2101  }
2102 
2103  key = "scaling factor (mm/pixel) [2]";
2104  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_pix_axl, 1, KEYWORD_MANDATORY))
2105  {
2106  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2107  Cerr(" Either key not found or conversion error" << endl);
2108  return 1;
2109  }
2110 
2111  key = "total number of images";
2112  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nProjectionsTot, 1, KEYWORD_MANDATORY))
2113  {
2114  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2115  Cerr(" Either key not found or conversion error" << endl);
2116  return 1;
2117  }
2118 
2119  key = "number of projections";
2120  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nProjectionsByHead, 1, KEYWORD_MANDATORY))
2121  {
2122  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2123  Cerr(" Either key not found or conversion error" << endl);
2124  return 1;
2125  }
2126 
2127  key = "number of detector heads";
2128  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nHeads, 1, KEYWORD_MANDATORY))
2129  {
2130  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2131  Cerr(" Either key not found or conversion error" << endl);
2132  return 1;
2133  }
2134 
2135  key = "study duration (sec)";
2136  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_duration_ms, 1, KEYWORD_MANDATORY))
2137  {
2138  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2139  Cerr(" Either key not found or conversion error" << endl);
2140  return 1;
2141  }
2142  // convert duration in ms
2143  a_duration_ms *= 1000;
2144 
2145 
2146  FLTNB size_crystal_X =0.,
2147  size_crystal_Y =0.;
2148 
2149  key = "crystal x dimension (cm)";
2150  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_crystal_X, 1, KEYWORD_OPTIONAL) == 1)
2151  {
2152  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2153  Cerr(" Either key not found or conversion error" << endl);
2154  return 1;
2155  }
2156 
2157  key = "crystal y dimension (cm)";
2158  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_crystal_Y, 1, KEYWORD_OPTIONAL) == 1)
2159  {
2160  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2161  Cerr(" Either key not found or conversion error" << endl);
2162  return 1;
2163  }
2164 
2165  key = "crystal z dimension (cm)";
2166  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_crystalSizeAxl, 1, KEYWORD_OPTIONAL) == 1)
2167  {
2168  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2169  Cerr(" Either key not found or conversion error" << endl);
2170  return 1;
2171  }
2172 
2173  // Just pick the larger value to get the transaxial crystal size
2174  // convert in mm (values in cm in Interfile)
2175  if(size_crystal_X>0 && size_crystal_Y>0)
2176  a_crystalSizeTrs = (size_crystal_X>size_crystal_Y) ? size_crystal_X*10. : size_crystal_Y*10.;
2177  a_crystalSizeAxl = (a_crystalSizeAxl>0) ? a_crystalSizeAxl*10. : a_crystalSizeAxl ;
2178 
2179 
2180  FLTNB head_pos_X =-1.,
2181  head_pos_Y =-1.,
2182  head_pos_Z =-1.;
2183 
2184  key = "head x translation (cm)";
2185  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &head_pos_X, 1, KEYWORD_OPTIONAL) == 1)
2186  {
2187  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2188  Cerr(" Either key not found or conversion error" << endl);
2189  return 1;
2190  }
2191 
2192  key = "head y translation (cm)";
2193  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &head_pos_Y, 1, KEYWORD_OPTIONAL) == 1)
2194  {
2195  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2196  Cerr(" Either key not found or conversion error" << endl);
2197  return 1;
2198  }
2199 
2200  key = "head z translation (cm)";
2201  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &head_pos_Z, 1, KEYWORD_OPTIONAL) == 1)
2202  {
2203  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2204  Cerr(" Either key not found or conversion error" << endl);
2205  return 1;
2206  }
2207 
2208  // Pick the largest value to initialize distance betweeen COR and detector, converted in mm (cm by default)
2209  if(head_pos_X > head_pos_Y)
2210  a_distToDetector = head_pos_X > head_pos_Z ? head_pos_X*10 : head_pos_Z*10;
2211  else
2212  a_distToDetector = head_pos_Y > head_pos_Z ? head_pos_Y*10 : head_pos_Z*10;
2213 
2214 
2215  key = "direction of rotation";
2216  string rot_dir;
2217  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &rot_dir, 1, KEYWORD_MANDATORY))
2218  {
2219  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2220  Cerr(" Either key not found or conversion error" << endl);
2221  return 1;
2222  }
2223 
2224  a_headRotDirection = (rot_dir == "CCW") ? GEO_ROT_CCW : GEO_ROT_CW ;
2225 
2226  // Could have several keys with this name (each for each head)
2227  // It will recover the value corresponding to the first match
2228  key = "start angle";
2229  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_head1stAngle, 1, KEYWORD_MANDATORY))
2230  {
2231  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2232  Cerr(" Either key not found or conversion error" << endl);
2233  return 1;
2234  }
2235 
2236  key = "extent of rotation";
2237  uint32_t extent_rotation =360;
2238  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &extent_rotation, 1, KEYWORD_MANDATORY))
2239  {
2240  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2241  Cerr(" Either key not found or conversion error" << endl);
2242  return 1;
2243  }
2244 
2245  a_headAngStepDeg = (FLTNB)extent_rotation / a_nProjectionsByHead;
2246 
2247  float_t first_angle = 0;
2248  float_t second_angle = extent_rotation;
2249 
2250  key = "start angle";
2251  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &first_angle, 1, KEYWORD_MANDATORY))
2252  {
2253  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2254  Cerr(" Either key not found or conversion error" << endl);
2255  return 1;
2256  }
2257 
2258  key = "start angle";
2259  if(IntfKeyGetRecurringValueFromFile(a_pathIntf.c_str(), key.c_str(), &second_angle, 1, KEYWORD_MANDATORY, 1))
2260  {
2261  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2262  Cerr(" Either key not found or conversion error" << endl);
2263  return 1;
2264  }
2265 
2266  a_headAngPitchDeg = second_angle - first_angle;
2267 
2268  return 0;
2269 }
2270 
2271 
2272 
2273 
2274 // =====================================================================
2275 // ---------------------------------------------------------------------
2276 // ---------------------------------------------------------------------
2277 // =====================================================================
2278 /*
2279  \fn CreateGeomWithCylindrical()
2280  \param a_pathMac : string containing the path to a GATE macro file
2281  \param a_pathGeom : string containing the path to a CASToR output geom file
2282  \brief Read a GATE macro file containing the description of a cylindricalPET system, and convert it to a geom file
2283  \return 0 if success, positive value otherwise
2284 */
2285 int CreateGeomWithCylindrical(string a_pathMac, string a_pathGeom)
2286 {
2287  /* Declaring variables */
2288 
2289  // Scanner
2290  string modality;
2291  string scanner_name = GetFileFromPath(a_pathGeom.substr(0,a_pathGeom.find(".geom")));
2292  double scanner_radius = 0.;
2293  uint32_t number_of_elements = 0;
2294  string description = "PET system extracted from GATE macro: " + a_pathMac;
2295 
2296  // Rsectors
2297  string rsector_name = "";
2298  uint32_t number_of_rsectors = 1;
2299  double rsector_first_angle = 0.;
2300  double rsector_angular_span = 360.;
2301  double rsector_pos_X = 0.;
2302  double rsector_pos_Y = 0.;
2303  uint32_t rsector_nb_zshifts = 0;
2304  vector <double> vec_rsector_Z_Shift;
2305  bool is_rsector_Y_axis = false;
2306 
2307  // Modules
2308  string module_name = "";
2309  uint32_t number_of_modules_trans = 1;
2310  uint32_t number_of_modules_axial = 1;
2311  double module_step_trans = 0.;
2312  double module_step_axial = 0.;
2313  double module_size_Y;
2314  double module_size_Z;
2315 
2316  // Submodules
2317  string submodule_name = "";
2318  uint32_t number_of_submodules_trans = 1;
2319  uint32_t number_of_submodules_axial = 1;
2320  double submodule_step_trans = 0.;
2321  double submodule_step_axial = 0.;
2322  double submodule_size_Y;
2323  double submodule_size_Z;
2324 
2325  // Crystals
2326  string crystal_name = "";
2327  uint32_t number_of_crystals_trans = 1;
2328  uint32_t number_of_crystals_axial = 1;
2329  double crystal_step_trans = 0.;
2330  double crystal_step_axial = 0.;
2331  double crystal_size_depth = 0.;
2332  double crystal_size_trans = 0.;
2333  double crystal_size_axial = 0.;
2334 
2335 
2336  // Layers
2337  int number_of_layers = 0;
2338  string n_layers = "1"; //default value for number_of_layers
2339  vector <uint32_t> number_of_lyr_elts_trans;
2340  vector <uint32_t> number_of_lyr_elts_axial;
2341 
2342  vector <string> layers_names;
2343  vector <vector <double> > layers_positions;
2344  vector <double> layers_size_depth;
2345  vector <double> layers_size_trans;
2346  vector <double> layers_size_axial;
2347 
2348  vector <double> layers_step_trans;
2349  vector <double> layers_step_axial;
2350 
2351  // Optional
2352  uint32_t voxels_number_trans;
2353  uint32_t voxels_number_axial;
2354  double fov_trans;
2355  double fov_axial;
2356  double mean_depth_of_interaction = -1.;
2357  double min_angle_diff = 0.;
2358 
2359 
2360 
2361 
2362 
2363  // If we have multiple layers, we need to enter multiple values in the .geom.
2364  vector <string> vec_scanner_radius;
2365 
2366  // Rsector vectors
2367  vector <string> vec_number_of_rsectors;
2368  vector <string> vec_rsector_first_angle;
2369 
2370 
2371  // Module vectors
2372  vector <string> vec_number_of_modules_trans;
2373  vector <string> vec_number_of_modules_axial;
2374  vector <string> vec_module_gap_trans;
2375  vector <string> vec_module_gap_axial;
2376 
2377  // Submodule vectors
2378  vector <string> vec_number_of_submodules_trans;
2379  vector <string> vec_number_of_submodules_axial;
2380  vector <string> vec_submodule_gap_trans;
2381  vector <string> vec_submodule_gap_axial;
2382 
2383  // Crystal vectors
2384  vector <string> vec_number_of_crystals_trans;
2385  vector <string> vec_number_of_crystals_axial;
2386  vector <string> vec_crystal_gap_trans;
2387  vector <string> vec_crystal_gap_axial;
2388 
2389  // Optionnal
2390  vector <string> vec_mean_depth_of_interaction;
2391  vector <string> vec_min_angle_diff;
2392 
2393  vector<string> path_mac_files;
2394  path_mac_files.push_back(a_pathMac);
2395 
2396  // Recover path to all macro files from the main mac file
2397  if(GetGATEMacFiles(a_pathMac , path_mac_files))
2398  {
2399  Cerr("***** GetGATESystemType() -> Error occured when trying to recover paths to GATE macro files !" << endl);
2400  return 1;
2401  }
2402 
2403  // Recover aliases of the different parts of the architecture
2404  if(GetGATEAliasesCylindrical(path_mac_files, rsector_name, module_name, submodule_name, crystal_name, layers_names, 2) )
2405  {
2406  Cerr("***** GetGATESystemType() -> Error occured when trying to recover aliases for the elements of the cylindricalPET !" << endl);
2407  return 1;
2408  }
2409 
2410  // Recover nb of detected layers
2411  n_layers = layers_names.size();
2412 
2413 
2414  // Loop to recover all other informations
2415  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
2416  {
2417  ifstream systemMac(path_mac_files[f].c_str(), ios::in);
2418 
2419  // Reading the .mac file line by line and update the variables if a matching adress is found
2420  string line;
2421  while(getline(systemMac, line))
2422  {
2423  vector <string> values;
2424 
2425  // Scanner
2426  modality = "PET";
2427 
2428  string entry = "";
2429 
2430  entry = "/gate/"+rsector_name+"/placement/setTranslation";
2431  values = CheckGATECommand(entry, line);
2432 
2433  // Assumes that first rsector located on the X or Y axis
2434  if (values.size()>0)
2435  {
2436  if(ConvertFromString(values[0], &rsector_pos_X) ||
2437  ConvertFromString(values[1], &rsector_pos_Y) )
2438  {
2439  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2440  return 1;
2441  }
2442 
2443  // Check first rsector cartesian coordinates is 0 on X or Y axis
2444  // Throw error otherwise
2445  if(rsector_pos_X!=0 && rsector_pos_Y !=0)
2446  {
2447  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2448  Cerr(" Rsector cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
2449  return 1;
2450  }
2451 
2452  // Get the axis on which the first rsector is positionned
2453  if(rsector_pos_Y!=0) is_rsector_Y_axis = true;
2454 
2455  scanner_radius += is_rsector_Y_axis ? abs(rsector_pos_Y) : abs(rsector_pos_X) ;
2456  }
2457 
2458  // Adjust scanner radius (from center to rsector surface) according to block size
2459  entry = is_rsector_Y_axis ?
2460  "/gate/"+rsector_name+"/geometry/setYLength" :
2461  "/gate/"+rsector_name+"/geometry/setXLength";
2462 
2463  values = CheckGATECommand(entry, line);
2464  if (values.size()>0)
2465  {
2466  double rsector_size = 0.;
2467  if(ConvertFromString(values[0], &rsector_size) )
2468  {
2469  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2470  return 1;
2471  }
2472 
2473  scanner_radius -= rsector_size/2;
2474  }
2475 
2476  // axial FOV computed from rsector z-length
2477  entry = "/gate/"+rsector_name+"/geometry/setZLength";
2478  values = CheckGATECommand(entry, line);
2479  if (values.size()>0)
2480  {
2481  if(ConvertFromString(values[0], &fov_axial) )
2482  {
2483  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2484  return 1;
2485  }
2486 
2487  // 4mm voxels by default
2488  voxels_number_axial = fov_axial/4 + 1;
2489  }
2490 
2491  // --- Rsectors ---
2492 
2493  entry = "/gate/"+rsector_name+"/ring/setModuloNumber";
2494  values = CheckGATECommand(entry, line);
2495  if (values.size()>0)
2496  {
2497  if(ConvertFromString(values[0], &rsector_nb_zshifts) )
2498  {
2499  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2500  return 1;
2501  }
2502  }
2503 
2504  entry = "/gate/"+rsector_name+"/ring/setRepeatNumber";
2505  values = CheckGATECommand(entry, line);
2506  if (values.size()>0)
2507  {
2508  if(ConvertFromString(values[0], &number_of_rsectors) )
2509  {
2510  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2511  return 1;
2512  }
2513  }
2514 
2515  entry = "/gate/"+rsector_name+"/ring/setFirstAngle";
2516  values = CheckGATECommand(entry, line);
2517  if (values.size()>0)
2518  {
2519  if(ConvertFromString(values[0], &rsector_first_angle) )
2520  {
2521  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2522  return 1;
2523  }
2524  }
2525 
2526  entry = "/gate/"+rsector_name+"/ring/setAngularSpan";
2527  values = CheckGATECommand(entry, line);
2528  if (values.size()>0)
2529  {
2530  if(ConvertFromString(values[0], &rsector_angular_span) )
2531  {
2532  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2533  return 1;
2534  }
2535  }
2536 
2537  // Up to 8 zshifts in Gate
2538  for (int i=1; i <8; i++)
2539  {
2540  entry = "/gate/"+rsector_name+"/ring/setZShift"+toString(i);
2541  values = CheckGATECommand(entry, line);
2542  if (values.size()>0)
2543  {
2544  double zshift = 0.;
2545  if(ConvertFromString(values[0], &zshift) )
2546  {
2547  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2548  return 1;
2549  }
2550 
2551  vec_rsector_Z_Shift.push_back(zshift);
2552  }
2553  }
2554 
2555 
2556 
2557  // --- Modules ---
2558 
2559  entry = is_rsector_Y_axis ?
2560  "/gate/"+module_name+"/cubicArray/setRepeatNumberX":
2561  "/gate/"+module_name+"/cubicArray/setRepeatNumberY";
2562 
2563  values = CheckGATECommand(entry, line);
2564  if (values.size()>0)
2565  {
2566  if(ConvertFromString(values[0], &number_of_modules_trans) )
2567  {
2568  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2569  return 1;
2570  }
2571  }
2572 
2573 
2574 
2575 
2576  entry = "/gate/"+module_name+"/cubicArray/setRepeatNumberZ";
2577  values = CheckGATECommand(entry, line);
2578 
2579  if (values.size()>0)
2580  {
2581  if(ConvertFromString(values[0], &number_of_modules_axial) )
2582  {
2583  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2584  return 1;
2585  }
2586  }
2587 
2588 
2589  entry = is_rsector_Y_axis ?
2590  "/gate/"+module_name+"/geometry/setXLength":
2591  "/gate/"+module_name+"/geometry/setYLength";
2592 
2593  values = CheckGATECommand(entry, line);
2594  if (values.size()>0)
2595  {
2596  if(ConvertFromString(values[0], &module_size_Y) )
2597  {
2598  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2599  return 1;
2600  }
2601  }
2602 
2603 
2604  entry = "/gate/"+module_name+"/geometry/setZLength";
2605  values = CheckGATECommand(entry, line);
2606  if (values.size()>0)
2607  {
2608  if(ConvertFromString(values[0], &module_size_Z) )
2609  {
2610  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2611  return 1;
2612  }
2613  }
2614 
2615  entry = "/gate/"+module_name+"/cubicArray/setRepeatVector";
2616  values = CheckGATECommand(entry, line);
2617  if (values.size()>0)
2618  {
2619  string trs_step = is_rsector_Y_axis ?
2620  values[0] :
2621  values[1] ;
2622 
2623  if(ConvertFromString(trs_step, &module_step_trans) ||
2624  ConvertFromString(values[2], &module_step_axial))
2625  {
2626  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2627  return 1;
2628  }
2629  }
2630 
2631 
2632 
2633 
2634  // linear repeaters instead of box
2635  entry = "/gate/"+module_name+"/linear/setRepeatNumber";
2636  values = CheckGATECommand(entry, line);
2637 
2638  if (values.size()>0)
2639  {
2640  if(ConvertFromString(values[0] , &number_of_modules_axial) )
2641  {
2642  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2643  return 1;
2644  }
2645  }
2646 
2647  entry = "/gate/"+module_name+"/linear/setRepeatVector";
2648  values = CheckGATECommand(entry, line);
2649  if (values.size()>0)
2650  {
2651  if(ConvertFromString(values[2], &module_step_axial))
2652  {
2653  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2654  return 1;
2655  }
2656  }
2657 
2658 
2659  // --- Submodules ---
2660  entry = is_rsector_Y_axis ?
2661  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberX":
2662  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberY";
2663 
2664 
2665  values = CheckGATECommand(entry, line);
2666  if (values.size()>0)
2667  {
2668  if(ConvertFromString(values[0], &number_of_submodules_trans) )
2669  {
2670  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2671  return 1;
2672  }
2673  }
2674 
2675  entry = "/gate/"+submodule_name+"/cubicArray/setRepeatNumberZ";
2676  values = CheckGATECommand(entry, line);
2677  if (values.size()>0)
2678  {
2679  if(ConvertFromString(values[0], &number_of_submodules_axial) )
2680  {
2681  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2682  return 1;
2683  }
2684  }
2685 
2686 
2687 
2688 
2689  entry = is_rsector_Y_axis ?
2690  "/gate/"+submodule_name+"/geometry/setXLength":
2691  "/gate/"+submodule_name+"/geometry/setYLength";
2692 
2693  values = CheckGATECommand(entry, line);
2694  if (values.size()>0)
2695  {
2696  if(ConvertFromString(values[0], &submodule_size_Y) )
2697  {
2698  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2699  return 1;
2700  }
2701  }
2702 
2703  entry = "/gate/"+submodule_name+"/geometry/setZLength";
2704  values = CheckGATECommand(entry, line);
2705  if (values.size()>0)
2706  {
2707  if(ConvertFromString(values[0], &submodule_size_Z) )
2708  {
2709  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2710  return 1;
2711  }
2712  }
2713 
2714  entry = "/gate/"+submodule_name+"/cubicArray/setRepeatVector";
2715  values = CheckGATECommand(entry, line);
2716  if (values.size()>0)
2717  {
2718  string trs_step = is_rsector_Y_axis ?
2719  values[0] :
2720  values[1] ;
2721 
2722  if(ConvertFromString(trs_step, &submodule_step_trans) ||
2723  ConvertFromString(values[2], &submodule_step_axial) )
2724  {
2725  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2726  return 1;
2727  }
2728  }
2729 
2730 
2731 
2732  // linear repeaters instead of box
2733  entry = "/gate/"+submodule_name+"/linear/setRepeatNumber";
2734  values = CheckGATECommand(entry, line);
2735 
2736  if (values.size()>0)
2737  {
2738  if(ConvertFromString( values[0] , &number_of_submodules_axial) )
2739  {
2740  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2741  return 1;
2742  }
2743  }
2744 
2745 
2746  entry = "/gate/"+submodule_name+"/linear/setRepeatVector";
2747  values = CheckGATECommand(entry, line);
2748  if (values.size()>0)
2749  {
2750  if(ConvertFromString(values[2], &submodule_step_axial))
2751  {
2752  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2753  return 1;
2754  }
2755  }
2756 
2757 
2758 
2759 
2760 
2761  // --- Crystals ---
2762  entry = is_rsector_Y_axis ?
2763  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
2764  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
2765 
2766 
2767  values = CheckGATECommand(entry, line);
2768  if (values.size()>0)
2769  {
2770  if(ConvertFromString(values[0], &number_of_crystals_trans) )
2771  {
2772  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2773  return 1;
2774  }
2775  }
2776 
2777  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
2778  values = CheckGATECommand(entry, line);
2779  if (values.size()>0)
2780  {
2781  if(ConvertFromString(values[0], &number_of_crystals_axial) )
2782  {
2783  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2784  return 1;
2785  }
2786  }
2787 
2788 
2789  entry = "/gate/"+crystal_name+"/geometry/setXLength";
2790  values = CheckGATECommand(entry, line);
2791  if (values.size()>0)
2792  {
2793  double x_length;
2794  if(ConvertFromString(values[0], &x_length) )
2795  {
2796  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2797  return 1;
2798  }
2799 
2800  if (is_rsector_Y_axis)
2801  crystal_size_trans = x_length;
2802  else
2803  crystal_size_depth = x_length;
2804  }
2805 
2806  entry = "/gate/"+crystal_name+"/geometry/setYLength";
2807  values = CheckGATECommand(entry, line);
2808  if (values.size()>0)
2809  {
2810  double y_length;
2811  if(ConvertFromString(values[0], &y_length) )
2812  {
2813  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2814  return 1;
2815  }
2816 
2817  if (is_rsector_Y_axis)
2818  crystal_size_depth = y_length;
2819  else
2820  crystal_size_trans = y_length;
2821 
2822  }
2823 
2824  entry = "/gate/"+crystal_name+"/geometry/setZLength";
2825  values = CheckGATECommand(entry, line);
2826  if (values.size()>0)
2827  {
2828  if(ConvertFromString(values[0], &crystal_size_axial) )
2829  {
2830  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2831  return 1;
2832  }
2833  }
2834 
2835  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatVector";
2836  values = CheckGATECommand(entry, line);
2837  if (values.size()>0)
2838  {
2839  string trs_step = is_rsector_Y_axis ?
2840  values[0] :
2841  values[1] ;
2842 
2843  if(ConvertFromString(trs_step, &crystal_step_trans) ||
2844  ConvertFromString(values[2], &crystal_step_axial) )
2845  {
2846  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2847  return 1;
2848  }
2849  }
2850 
2851  // linear repeaters instead of box
2852  entry = "/gate/"+crystal_name+"/linear/setRepeatNumber";
2853  values = CheckGATECommand(entry, line);
2854 
2855  if (values.size()>0)
2856  {
2857  if(ConvertFromString( values[0] , &number_of_crystals_axial) )
2858  {
2859  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2860  return 1;
2861  }
2862  }
2863 
2864  entry = "/gate/"+crystal_name+"/linear/setRepeatVector";
2865  values = CheckGATECommand(entry, line);
2866  if (values.size()>0)
2867  {
2868  if(ConvertFromString(values[2], &crystal_step_axial))
2869  {
2870  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2871  return 1;
2872  }
2873  }
2874 
2875 
2876 
2877 
2878  // --- Layers ---
2879  entry = "/gate/"+crystal_name+"/daughters/name";
2880  values = CheckGATECommand(entry, line);
2881  if (values.size()>0)
2882  {
2883  layers_names.push_back(values[0]);
2884  number_of_layers++;
2885  }
2886 
2887  // loop on the layers to get their specific information as they are integrated in layers_names.
2888  for (int i=0; i < number_of_layers; i++)
2889  {
2890  // assumes that first block is positionned on the x-axis
2891  entry = "/gate/"+layers_names[i]+"/placement/setTranslation";
2892  values = CheckGATECommand(entry, line);
2893 
2894  if (values.size()>0)
2895  {
2896  vector<double> layer_pos;
2897  for(int d=0 ; d<3 ; d++)
2898  {
2899  double pos;
2900  if(ConvertFromString(values[d], &pos) )
2901  {
2902  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2903  return 1;
2904  }
2905  layer_pos.push_back(pos);
2906  }
2907 
2908  if(is_rsector_Y_axis)
2909  {
2910  double pos = layer_pos[1];
2911  layer_pos[1] = layer_pos[0];
2912  layer_pos[0] = pos;
2913  }
2914 
2915  layers_positions.push_back(layer_pos);
2916  }
2917 
2918 
2919  // assumes that first block is positionned on the x-axis
2920  entry = "/gate/"+layers_names[i]+"/geometry/setXLength";
2921  values = CheckGATECommand(entry, line);
2922 
2923  if (values.size()>0)
2924  {
2925  double xlength;
2926  if(ConvertFromString(values[0], &xlength) )
2927  {
2928  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2929  return 1;
2930  }
2931 
2932  if (is_rsector_Y_axis)
2933  layers_size_trans.push_back(xlength);
2934  else
2935  layers_size_depth.push_back(xlength);
2936  }
2937 
2938  // assumes that first block is positionned on the x-axis
2939  entry = "/gate/"+layers_names[i]+"/geometry/setYLength";
2940  values = CheckGATECommand(entry, line);
2941  if (values.size()>0)
2942  {
2943  double ylength;
2944  if(ConvertFromString(values[0], &ylength) )
2945  {
2946  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2947  return 1;
2948  }
2949  if (is_rsector_Y_axis)
2950  layers_size_depth.push_back(ylength);
2951  else
2952  layers_size_trans.push_back(ylength);
2953  }
2954 
2955  entry = "/gate/"+layers_names[i]+"/geometry/setZLength";
2956  values = CheckGATECommand(entry, line);
2957  if (values.size()>0)
2958  {
2959  double zlength;
2960  if(ConvertFromString(values[0], &zlength) )
2961  {
2962  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2963  return 1;
2964  }
2965  layers_size_axial.push_back(zlength);
2966  }
2967 
2968  // Check if a repeater if applied to the layers elements
2969  // In this case, the total number of crystals for a layer[i]
2970  // will be crystal elts*layers elts[i]
2971  entry = is_rsector_Y_axis ?
2972  "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberX":
2973  "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberY";
2974 
2975  values = CheckGATECommand(entry, line);
2976  if (values.size()>0)
2977  {
2978  uint32_t step_trs;
2979  if(ConvertFromString(values[0], &step_trs))
2980  {
2981  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2982  return 1;
2983  }
2984  number_of_lyr_elts_trans.push_back(step_trs);
2985  }
2986 
2987  entry = "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberZ";
2988  values = CheckGATECommand(entry, line);
2989  if (values.size()>0)
2990  {
2991  uint32_t step_axl;
2992  if(ConvertFromString(values[0], &step_axl))
2993  {
2994  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
2995  return 1;
2996  }
2997  number_of_lyr_elts_axial.push_back(step_axl);
2998  }
2999 
3000  entry = "/gate/"+layers_names[i]+"/cubicArray/setRepeatVector";
3001  values = CheckGATECommand(entry, line);
3002  if (values.size()>0)
3003  {
3004  string trs_step = is_rsector_Y_axis ?
3005  values[0] :
3006  values[1] ;
3007 
3008  double step_trs, step_axl;
3009  if(ConvertFromString(trs_step, &step_trs) ||
3010  ConvertFromString(values[2], &step_axl) )
3011  {
3012  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
3013  return 1;
3014  }
3015 
3016 
3017  layers_step_trans.push_back(step_trs);
3018  layers_step_axial.push_back(step_axl);
3019  }
3020 
3021 
3022  // linear repeaters instead of box
3023  entry = "/gate/"+layers_names[i]+"/linear/setRepeatNumber";
3024  values = CheckGATECommand(entry, line);
3025 
3026  if (values.size()>0)
3027  {
3028  uint32_t step_axl;
3029  if(ConvertFromString( values[0] , &step_axl) )
3030  {
3031  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
3032  return 1;
3033  }
3034  number_of_lyr_elts_axial.push_back(step_axl);
3035  }
3036 
3037 
3038  entry = "/gate/"+layers_names[i]+"/linear/setRepeatVector";
3039  values = CheckGATECommand(entry, line);
3040  if (values.size()>0)
3041  {
3042  double step_axl;
3043  if(ConvertFromString(values[2], &step_axl))
3044  {
3045  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
3046  return 1;
3047  }
3048 
3049  layers_step_axial.push_back(step_axl);
3050  }
3051 
3052  }
3053 
3054 
3055  entry = "/gate/digitizer/Coincidences/minSectorDifference";
3056  values = CheckGATECommand(entry, line);
3057  if (values.size()>0)
3058  {
3059  FLTNB min_sector_diff= 0.;
3060 
3061  if(ConvertFromString(values[0], &min_sector_diff))
3062  {
3063  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
3064  return 1;
3065  }
3066 
3067  min_angle_diff = 360./number_of_rsectors*min_sector_diff;
3068  }
3069 
3070  }
3071  systemMac.close();
3072 
3073  }
3074 
3075  // Compute total number of crystal elements
3076  if(number_of_layers == 0)
3077  {
3078  number_of_elements = number_of_rsectors
3079  * number_of_modules_trans
3080  * number_of_modules_axial
3081  * number_of_submodules_trans
3082  * number_of_submodules_axial
3083  * number_of_crystals_trans
3084  * number_of_crystals_axial;
3085  }
3086  else
3087  for(int l=0 ; l<number_of_layers ; l++)
3088  {
3089  int32_t nb_crystals_layer = number_of_rsectors
3090  * number_of_modules_trans
3091  * number_of_modules_axial
3092  * number_of_submodules_trans
3093  * number_of_submodules_axial
3094  * number_of_crystals_trans
3095  * number_of_crystals_axial;
3096 
3097  // Add layer elements if repeaters have been used on layers
3098  if(number_of_lyr_elts_trans.size()>0 || number_of_lyr_elts_axial.size()>0 )
3099  nb_crystals_layer *= number_of_lyr_elts_trans[l] * number_of_lyr_elts_axial[l];
3100 
3101  number_of_elements += nb_crystals_layer;
3102  }
3103 
3104 
3105  // Transaxial FOV defined as scanner radius / 2
3106  fov_trans = scanner_radius/2;
3107  // 4mm voxels by default
3108  voxels_number_trans = fov_trans/2 + 1;
3109 
3110 
3111  // Compute gaps
3112  if (module_step_axial - module_size_Z >= 0)
3113  module_step_axial = module_step_axial - module_size_Z;
3114 
3115  if (module_step_trans - module_size_Y >= 0)
3116  module_step_trans =module_step_trans - module_size_Y;
3117 
3118  if (submodule_step_axial - submodule_size_Z >= 0)
3119  submodule_step_axial = submodule_step_axial - submodule_size_Z;
3120 
3121  if (submodule_step_trans - submodule_size_Y >= 0)
3122  submodule_step_trans = submodule_step_trans - submodule_size_Y;
3123 
3124  if (crystal_step_axial - crystal_size_axial >= 0)
3125  crystal_step_axial = crystal_step_axial - crystal_size_axial;
3126 
3127  if (crystal_step_trans - crystal_size_trans >= 0)
3128  crystal_step_trans = crystal_step_trans - crystal_size_trans;
3129 
3130 
3131  // Compute first angle
3132  // CASToR x and y axis for rotation inverted in comparison with GATE
3133  rsector_first_angle -= round(atan2f(rsector_pos_X , rsector_pos_Y) * 180. / M_PI);
3134 
3135  // Computing the other parts of variables, if their is more than one layer
3136  if (number_of_layers > 0)
3137  {
3138  for (int l=0; l < number_of_layers ; l++)
3139  {
3140  // Scanner vectors
3141  vec_scanner_radius.push_back( toString(scanner_radius+layers_positions[l][0]) );
3142 
3143  // Rsector vectors
3144  vec_number_of_rsectors.push_back( toString(number_of_rsectors) );
3145  vec_rsector_first_angle.push_back( toString(rsector_first_angle) );
3146 
3147  // Module vectors
3148  vec_number_of_modules_trans.push_back( toString(number_of_modules_trans) );
3149  vec_number_of_modules_axial.push_back( toString(number_of_modules_axial) );
3150  vec_module_gap_trans.push_back( toString(module_step_trans) );
3151  vec_module_gap_axial.push_back( toString(module_step_axial) );
3152 
3153  // Submodule vectors
3154  vec_number_of_submodules_trans.push_back( toString(number_of_submodules_trans) );
3155  vec_number_of_submodules_axial.push_back( toString(number_of_submodules_axial) );
3156  vec_submodule_gap_trans.push_back( toString(submodule_step_trans) );
3157  vec_submodule_gap_axial.push_back( toString(submodule_step_axial) );
3158 
3159  // Crystal vectors
3160  uint32_t nb_tot_trs_cry = (number_of_lyr_elts_trans.size()>0) ?
3161  number_of_lyr_elts_trans[l]*number_of_crystals_trans :
3162  number_of_crystals_trans ;
3163 
3164  uint32_t nb_tot_axl_cry = (number_of_lyr_elts_axial.size()>0) ?
3165  number_of_lyr_elts_axial[l]*number_of_crystals_axial :
3166  number_of_crystals_axial ;
3167 
3168  vec_number_of_crystals_trans.push_back( toString(nb_tot_trs_cry) );
3169  vec_number_of_crystals_axial.push_back( toString(nb_tot_axl_cry) );
3170 
3171 
3172 
3173  if(layers_step_trans.size()>0 &&
3174  layers_step_trans.size()>0)
3175  {
3176  if (layers_step_trans[l] - layers_size_trans[l] >= 0)
3177  crystal_step_trans = layers_step_trans[l] - layers_size_trans[l];
3178 
3179  if (layers_step_axial[l] - layers_size_axial[l] >= 0)
3180  crystal_step_axial = layers_step_axial[l] - layers_size_axial[l];
3181  }
3182  else
3183  {
3184  crystal_step_trans = crystal_step_trans ;
3185  crystal_step_axial = crystal_step_axial ;
3186  }
3187 
3188  vec_crystal_gap_trans.push_back( toString(crystal_step_trans) );
3189  vec_crystal_gap_axial.push_back( toString(crystal_step_axial) );
3190 
3191  // Optionnal
3192  vec_mean_depth_of_interaction.push_back( toString(mean_depth_of_interaction) );
3193  vec_min_angle_diff.push_back( toString(min_angle_diff) );
3194  }
3195  }
3196  else
3197  {
3198  // Layer dimensions = crystal dimensions
3199  layers_size_depth.push_back( crystal_size_depth );
3200  layers_size_trans.push_back( crystal_size_trans );
3201  layers_size_axial.push_back( crystal_size_axial );
3202 
3203 
3204  // Scanner vectors
3205  vec_scanner_radius.push_back( toString(scanner_radius) );
3206 
3207  // Rsector vectors
3208  vec_number_of_rsectors.push_back( toString(number_of_rsectors) );
3209  vec_rsector_first_angle.push_back( toString(rsector_first_angle) );
3210 
3211  // Module vectors
3212  vec_number_of_modules_trans.push_back( toString(number_of_modules_trans) );
3213  vec_number_of_modules_axial.push_back( toString(number_of_modules_axial) );
3214  vec_module_gap_trans.push_back( toString(module_step_trans) );
3215  vec_module_gap_axial.push_back( toString(module_step_axial) );
3216 
3217  // Submodule vectors
3218  vec_number_of_submodules_trans.push_back( toString(number_of_submodules_trans) );
3219  vec_number_of_submodules_axial.push_back( toString(number_of_submodules_axial) );
3220  vec_submodule_gap_trans.push_back( toString(submodule_step_trans) );
3221  vec_submodule_gap_axial.push_back( toString(submodule_step_axial) );
3222 
3223  // Crystal vectors
3224  vec_number_of_crystals_trans.push_back( toString(number_of_crystals_trans) );
3225  vec_number_of_crystals_axial.push_back( toString(number_of_crystals_axial) );
3226  vec_crystal_gap_trans.push_back( toString(crystal_step_trans) );
3227  vec_crystal_gap_axial.push_back( toString(crystal_step_axial) );
3228 
3229  // Optionnal
3230  vec_mean_depth_of_interaction.push_back( toString(mean_depth_of_interaction) );
3231  vec_min_angle_diff.push_back( toString(min_angle_diff) );
3232 
3233  // Update the real number of layers
3234  number_of_layers = 1;
3235  }
3236 
3237 
3238  // Write the .geom file
3239  ofstream fileGeom(a_pathGeom.c_str(), ios::out | ios::trunc);
3240  if(fileGeom)
3241  {
3242  fileGeom <<"# comments" << endl;
3243  fileGeom <<"# Y _________ "<< endl;
3244  fileGeom <<"# | / _ \\ \\ "<< endl;
3245  fileGeom <<"# | | / \\ | |"<< endl;
3246  fileGeom <<"# |_____ Z | | | | |"<< endl;
3247  fileGeom <<"# \\ | | | | |" << endl;
3248  fileGeom <<"# \\ | \\_/ | |" << endl;
3249  fileGeom <<"# X \\___/_____/" << endl;
3250  fileGeom <<"# Left-handed axis orientation"<< endl;
3251  fileGeom <<"# scanner axis is z" << endl;
3252  fileGeom <<"# positions in millimeters"<< endl;
3253  fileGeom <<"# Use comma without space as separator in the tables." << endl;
3254 
3255  fileGeom << ""<< endl;
3256 
3257  // Mandatory fields
3258  fileGeom << "# MANDATORY FIELDS"<< endl;
3259  fileGeom << "modality : " << modality << endl;
3260  fileGeom << "scanner name : " << scanner_name << endl;
3261  fileGeom << "number of elements : " << number_of_elements << endl;
3262  fileGeom << "number of layers : " << number_of_layers << endl;
3263  fileGeom << "" << endl;
3264  fileGeom << "voxels number transaxial : " << voxels_number_trans << endl;
3265  fileGeom << "voxels number axial : " << voxels_number_axial << endl;
3266 
3267  fileGeom << "field of view transaxial : " << fov_trans << endl;
3268  fileGeom << "field of view axial : " << fov_axial << endl << endl;
3269  fileGeom << "description : " << description << endl;
3270  fileGeom << "" << endl;
3271  WriteVector(fileGeom,"scanner radius : ",vec_scanner_radius);
3272  WriteVector(fileGeom,"number of rsectors : ",vec_number_of_rsectors);
3273  WriteVector(fileGeom,"number of crystals transaxial : ",vec_number_of_crystals_trans);
3274  WriteVector(fileGeom, "number of crystals axial : ",vec_number_of_crystals_axial);
3275  fileGeom << ""<< endl;
3276  WriteVector(fileGeom, "crystals size depth : ", layers_size_depth);
3277  WriteVector(fileGeom, "crystals size transaxial : ", layers_size_trans);
3278  WriteVector(fileGeom, "crystals size axial : ", layers_size_axial);
3279  fileGeom << ""<< endl;
3280  fileGeom << ""<< endl;
3281 
3282  // Optional fields
3283  fileGeom << "# OPTIONAL FIELDS"<< endl;
3284  WriteVector(fileGeom,"rsectors first angle : ",vec_rsector_first_angle);
3285  WriteVector(fileGeom,"number of modules transaxial : ",vec_number_of_modules_trans);
3286  WriteVector(fileGeom, "number of modules axial : ",vec_number_of_modules_axial);
3287  WriteVector(fileGeom,"module gap transaxial : ",vec_module_gap_trans);
3288  WriteVector(fileGeom,"module gap axial : ",vec_module_gap_axial);
3289  WriteVector(fileGeom,"number of submodules transaxial : ",vec_number_of_submodules_trans);
3290  WriteVector(fileGeom, "number of submodules axial : ",vec_number_of_submodules_axial);
3291  WriteVector(fileGeom,"submodule gap transaxial : ",vec_submodule_gap_trans);
3292  WriteVector(fileGeom,"submodule gap axial : ",vec_submodule_gap_axial);
3293  WriteVector(fileGeom,"crystal gap transaxial : ",vec_crystal_gap_trans);
3294  WriteVector(fileGeom,"crystal gap axial : ",vec_crystal_gap_axial);
3295  WriteVector(fileGeom, "mean depth of interaction : ", vec_mean_depth_of_interaction);
3296  fileGeom << "rotation direction : CCW " << endl; // default for GATE
3297  fileGeom << ""<< endl;
3298 
3299  // Write only if different from default values
3300  if(min_angle_diff > 0.) fileGeom << "min angle difference : " << min_angle_diff << endl;
3301 
3302  // Convert angular span to the CASToR convention
3303  if(rsector_angular_span >= 360.0005 ||
3304  rsector_angular_span <= 359.9995 ) // GATE bounds
3305  {
3306  rsector_angular_span *= (number_of_rsectors+1)/number_of_rsectors;
3307  fileGeom << "rsectors angular span : " << rsector_angular_span << endl;
3308  }
3309 
3310  if(rsector_nb_zshifts > 0) fileGeom << "rsectors nbZShift :" << rsector_nb_zshifts << endl;
3311  if(!vec_rsector_Z_Shift.empty()) WriteVector(fileGeom, "rsectors ZShift : ", vec_rsector_Z_Shift);
3312 
3313  fileGeom.close();
3314 
3315  cout << "Output geom file written at :" << a_pathGeom << endl;
3316  }
3317  else
3318  {
3319  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Couldn't open geom file for writing "<< a_pathGeom << " !" << endl);
3320  return 1;
3321  }
3322 
3323 
3324 
3325  return 0;
3326 }
3327 
3328 
3329 
3330 // =====================================================================
3331 // ---------------------------------------------------------------------
3332 // ---------------------------------------------------------------------
3333 // =====================================================================
3334 /*
3335  \fn CreateGeomWithECAT()
3336  \param a_pathMac : string containing the path to a GATE macro file
3337  \param a_pathGeom : string containing the path to a CASToR output geom file
3338  \brief Read a GATE macro file containing the description of an ecat system, and convert it to a geom file
3339  \return 0 if success, positive value otherwise
3340 */
3341 int CreateGeomWithECAT(string a_pathMac, string a_pathGeom)
3342 {
3343  /* Declaring variables */
3344 
3345  // Scanner
3346  string modality;
3347  string scanner_name = GetFileFromPath(a_pathGeom.substr(0,a_pathGeom.find_first_of(".geom")));
3348  double scanner_radius = 0.;
3349  uint32_t number_of_elements = 0;
3350  string description = "ECAT system extracted from GATE macro: " + a_pathMac;
3351 
3352  // blocks
3353  string block_name = "block";
3354  uint32_t number_of_blocks = 1;
3355  uint32_t number_of_blocks_trans = 1;
3356  uint32_t number_of_blocks_axial = 1;
3357  double block_step_trans = 0.;
3358  double block_step_axial = 0.;
3359  double block_size_Y;
3360  double block_size_Z;
3361  double block_pos_X = 0.;
3362  double block_pos_Y = 0.;
3363  double block_first_angle = 0.;
3364  double block_angular_span = 360.;
3365  uint32_t block_nb_zshifts = 0;
3366  vector <double> vec_block_Z_Shift;
3367  bool is_block_Y_axis = false;
3368 
3369 
3370 
3371  // Crystals
3372  string crystal_name = "crystal";
3373  uint32_t number_of_crystals_trans = 1;
3374  uint32_t number_of_crystals_axial = 1;
3375  double crystal_step_trans = 0.;
3376  double crystal_step_axial = 0.;
3377  double crystal_size_depth = 0.;
3378  double crystal_size_trans = 0.;
3379  double crystal_size_axial = 0.;
3380 
3381  // Optional
3382  uint32_t voxels_number_trans;
3383  uint32_t voxels_number_axial;
3384  double fov_trans;
3385  double fov_axial;
3386  double min_angle_diff = 0.;
3387 
3388  vector<string> path_mac_files;
3389  path_mac_files.push_back(a_pathMac);
3390 
3391  // Recover path to all macro files from the main mac file
3392  if(GetGATEMacFiles(a_pathMac , path_mac_files))
3393  {
3394  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Error occured when trying to recover paths to GATE macro files !" << endl);
3395  return 1;
3396  }
3397 
3398 
3399  // Recover aliases of the different parts of the architecture
3400  if(GetGATEAliasesEcat(path_mac_files, block_name, crystal_name, 2) )
3401  {
3402  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Error occured when trying to recover aliases for the elements of the ecat !" << endl);
3403  return 1;
3404  }
3405 
3406 
3407  // Loop to recover all other informations
3408  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
3409  {
3410  ifstream systemMac(path_mac_files[f].c_str(), ios::in);
3411 
3412  string line;
3413  while(getline(systemMac, line))
3414  {
3415  // Scanner
3416  modality = "PET";
3417  vector <string> values;
3418  string entry = "";
3419 
3420 
3421  entry = "/gate/"+block_name+"/placement/setTranslation";
3422  values = CheckGATECommand(entry, line);
3423  if (values.size()>0)
3424  {
3425  if(ConvertFromString(values[0], &block_pos_X) ||
3426  ConvertFromString(values[1], &block_pos_Y) )
3427  {
3428  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3429  return 1;
3430  }
3431 
3432  // Check first block cartesian coordinates is 0 on X or Y axis
3433  // Throw error otherwise
3434  if(block_pos_X!=0 && block_pos_Y !=0)
3435  {
3436  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3437  Cerr(" Block cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
3438  return 1;
3439  }
3440 
3441  // Get the axis on which the first rsector is positionned
3442  if(block_pos_Y!=0) is_block_Y_axis = true;
3443 
3444  scanner_radius += is_block_Y_axis ? abs(block_pos_Y) : abs(block_pos_X) ;
3445  }
3446 
3447 
3448  // Adjust scanner radius (from center to block surface) according to block size
3449  entry = is_block_Y_axis ?
3450  "/gate/"+block_name+"/geometry/setYLength" :
3451  "/gate/"+block_name+"/geometry/setXLength";
3452 
3453  values = CheckGATECommand(entry, line);
3454  if (values.size()>0)
3455  {
3456  double block_size = 0.;
3457  if(ConvertFromString(values[0], &block_size) )
3458  {
3459  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
3460  return 1;
3461  }
3462 
3463  scanner_radius -= block_size/2;
3464  }
3465 
3466 
3467 
3468  entry = "/gate/"+block_name+"/geometry/setZLength";
3469  values = CheckGATECommand(entry, line);
3470  if (values.size()>0)
3471  {
3472  if(ConvertFromString(values[0], &fov_axial))
3473  {
3474  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3475  return 1;
3476  }
3477  // 4mm voxels by default
3478  voxels_number_axial = fov_axial/4 + 1;
3479  }
3480 
3481 
3482  // blocks
3483  entry = "/gate/"+block_name+"/ring/setRepeatNumber";
3484  values = CheckGATECommand(entry, line);
3485  if (values.size()>0)
3486  {
3487  if(ConvertFromString(values[0], &number_of_blocks))
3488  {
3489  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3490  return 1;
3491  }
3492  }
3493 
3494 
3495  entry = "/gate/"+block_name+"/ring/setFirstAngle";
3496  values = CheckGATECommand(entry, line);
3497  if (values.size()>0)
3498  {
3499  if(ConvertFromString(values[0], &block_first_angle))
3500  {
3501  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3502  return 1;
3503  }
3504  }
3505 
3506 
3507  entry = "/gate/"+block_name+"/ring/setAngularSpan";
3508  values = CheckGATECommand(entry, line);
3509  if (values.size()>0)
3510  {
3511  if(ConvertFromString(values[0], &block_angular_span))
3512  {
3513  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3514  return 1;
3515  }
3516  }
3517 
3518  entry = "/gate/"+block_name+"/ring/setModuloNumber";
3519  values = CheckGATECommand(entry, line);
3520  if (values.size()>0)
3521  {
3522  if(ConvertFromString(values[0], &block_nb_zshifts) )
3523  {
3524  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
3525  return 1;
3526  }
3527  }
3528 
3529  for (int i=1; i<8; i++)
3530  {
3531  entry = "/gate/"+block_name+"/ring/setZShift"+toString(i);
3532  values = CheckGATECommand(entry, line);
3533  if (values.size()>0)
3534  {
3535  double zshift;
3536  if(ConvertFromString(values[0], &zshift))
3537  {
3538  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3539  return 1;
3540  }
3541  vec_block_Z_Shift.push_back(zshift);
3542  }
3543  }
3544 
3545 
3546 
3547 
3548  // Modules
3549  entry = "/gate/"+block_name+"/linear/setRepeatNumber";
3550  values = CheckGATECommand(entry, line);
3551  if (values.size()>0)
3552  {
3553  if(ConvertFromString(values[0], &number_of_blocks_axial))
3554  {
3555  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3556  return 1;
3557  }
3558  }
3559 
3560  entry = is_block_Y_axis ?
3561  "/gate/"+block_name+"/geometry/setXLength":
3562  "/gate/"+block_name+"/geometry/setYLength";
3563 
3564  values = CheckGATECommand(entry, line);
3565  if (values.size()>0)
3566  {
3567  if(ConvertFromString(values[0], &block_size_Y))
3568  {
3569  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3570  return 1;
3571  }
3572  }
3573 
3574  entry = "/gate/"+block_name+"/geometry/setZLength";
3575  values = CheckGATECommand(entry, line);
3576  if (values.size()>0)
3577  {
3578  if(ConvertFromString(values[0], &block_size_Z))
3579  {
3580  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3581  return 1;
3582  }
3583  }
3584 
3585  entry = "/gate/"+block_name+"/linear/setRepeatVector";
3586  values = CheckGATECommand(entry, line);
3587  if (values.size()>0)
3588  {
3589  if(ConvertFromString(values[2], &block_step_axial))
3590  {
3591  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3592  return 1;
3593  }
3594  }
3595 
3596 
3597 
3598  // Crystals
3599 
3600  // assumes that first block is positionned on the x-axis
3601  entry = is_block_Y_axis ?
3602  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
3603  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
3604 
3605  values = CheckGATECommand(entry, line);
3606  if (values.size()>0)
3607  {
3608  if(ConvertFromString(values[0], &number_of_crystals_trans))
3609  {
3610  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3611  return 1;
3612  }
3613  }
3614 
3615  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
3616  values = CheckGATECommand(entry, line);
3617  if (values.size()>0)
3618  {
3619  if(ConvertFromString(values[0], &number_of_crystals_axial))
3620  {
3621  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3622  return 1;
3623  }
3624  }
3625 
3626 
3627  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatVector";
3628  values = CheckGATECommand(entry, line);
3629  if (values.size()>0)
3630  {
3631  string trs_step = is_block_Y_axis ?
3632  values[0] :
3633  values[1] ;
3634 
3635  if(ConvertFromString(values[1], &crystal_step_trans) ||
3636  ConvertFromString(values[2], &crystal_step_axial) )
3637  {
3638  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3639  return 1;
3640  }
3641  }
3642 
3643 
3644  // assumes that first block is positionned on the x-axis
3645  entry = "/gate/"+crystal_name+"/geometry/setXLength";
3646  values = CheckGATECommand(entry, line);
3647  if (values.size()>0)
3648  {
3649  double x_length;
3650  if(ConvertFromString(values[0], &x_length))
3651  {
3652  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3653  return 1;
3654  }
3655 
3656  if (is_block_Y_axis)
3657  crystal_size_trans = x_length;
3658  else
3659  crystal_size_depth = x_length;
3660  }
3661 
3662 
3663  // assumes that first block is positionned on the x-axis
3664  entry = "/gate/"+crystal_name+"/geometry/setYLength";
3665  values = CheckGATECommand(entry, line);
3666  if (values.size()>0)
3667  {
3668  double y_length;
3669  if(ConvertFromString(values[0], &y_length))
3670  {
3671  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3672  return 1;
3673  }
3674 
3675  if (is_block_Y_axis)
3676  crystal_size_depth = y_length;
3677  else
3678  crystal_size_trans = y_length;
3679  }
3680 
3681  entry = "/gate/"+crystal_name+"/geometry/setZLength";
3682  values = CheckGATECommand(entry, line);
3683  if (values.size()>0)
3684  {
3685  if(ConvertFromString(values[0], &crystal_size_axial))
3686  {
3687  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3688  return 1;
3689  }
3690  }
3691 
3692 
3693 
3694 
3695  entry = "/gate/digitizer/Coincidences/minSectorDifference";
3696  values = CheckGATECommand(entry, line);
3697  if (values.size()>0)
3698  {
3699  double min_sector_diff;
3700  if(ConvertFromString(values[0], &min_sector_diff))
3701  {
3702  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occured while trying to parse line: " << line<< endl);
3703  return 1;
3704  }
3705  min_angle_diff = 360/number_of_blocks*min_sector_diff;
3706  }
3707 
3708  }
3709  systemMac.close();
3710  }
3711 
3712  number_of_elements = number_of_blocks *
3713  number_of_blocks_axial *
3714  number_of_crystals_trans *
3715  number_of_crystals_axial;
3716 
3717  // Transaxial FOV defined as scanner radius / 2
3718  fov_trans = scanner_radius/2;
3719  // 4mm voxels by default
3720  voxels_number_trans = fov_trans/2 + 1;
3721 
3722  if (crystal_step_axial - crystal_size_axial >= 0)
3723  crystal_step_axial = crystal_step_axial - crystal_size_axial;
3724 
3725  if (crystal_step_trans - crystal_size_trans >= 0)
3726  crystal_step_trans = crystal_step_trans - crystal_size_trans;
3727 
3728  if (block_step_axial - block_size_Z >= 0)
3729  block_step_axial = block_step_axial - block_size_Z;
3730 
3731  if (block_step_trans - block_size_Y >= 0)
3732  block_step_trans = block_step_trans - block_size_Y;
3733 
3734  // CASToR x and y axis for rotation inverted in comparison with GATE
3735  block_first_angle -= round(atan2f(block_pos_X , block_pos_Y) * 180. / M_PI);
3736 
3737 
3738  // Writing the .geom file
3739  ofstream fileGeom(a_pathGeom.c_str(), ios::out | ios::trunc);
3740 
3741  if(fileGeom)
3742  {
3743  fileGeom <<"# comments" << endl;
3744  fileGeom <<"# Y _________ "<< endl;
3745  fileGeom <<"# | / _ \\ \\ "<< endl;
3746  fileGeom <<"# | | / \\ | |"<< endl;
3747  fileGeom <<"# |_____ Z | | | | |"<< endl;
3748  fileGeom <<"# \\ | | | | |" << endl;
3749  fileGeom <<"# \\ | \\_/ | |" << endl;
3750  fileGeom <<"# X \\___/_____/" << endl;
3751  fileGeom <<"# Left-handed axis orientation"<< endl;
3752  fileGeom <<"# scanner axis is z" << endl;
3753  fileGeom <<"# positions in millimeters"<< endl;
3754  fileGeom <<"# Use comma without space as separator in the tables." << endl;
3755 
3756 
3757  fileGeom << "modality : " << modality << endl;
3758  fileGeom << "scanner name : " << scanner_name << endl;
3759  fileGeom << "number of elements : " << number_of_elements << endl;
3760  fileGeom << "number of layers : " << "1" << endl;
3761  fileGeom << "" << endl;
3762  fileGeom << "# default reconstruction parameters" << endl;
3763  fileGeom << "voxels number transaxial : " << voxels_number_trans << endl;
3764  fileGeom << "voxels number axial : " << voxels_number_axial << endl;
3765 
3766  fileGeom << "field of view transaxial : " << fov_trans << endl;
3767  fileGeom << "field of view axial : " << fov_axial << endl;
3768  fileGeom << "" << endl;
3769  fileGeom << "description : " << description << endl;
3770  fileGeom << "" << endl;
3771  fileGeom << "scanner radius : " << scanner_radius << endl;
3772  fileGeom << "number of rsectors : " << number_of_blocks << endl;
3773  fileGeom << "number of crystals transaxial : " << number_of_crystals_trans << endl;
3774  fileGeom << "number of crystals axial : " << number_of_crystals_axial << endl;
3775 
3776  fileGeom << ""<< endl;
3777  fileGeom << "# The 4 following parameters could be defined in arrays (SizeLayer1,SizeLayer2,SizeLayer3,etc..) if their is more than one layer"<< endl;
3778  fileGeom << "crystals size depth : " << crystal_size_depth << endl;
3779  fileGeom << "crystals size transaxial : " << crystal_size_trans << endl;
3780  fileGeom << "crystals size axial : " << crystal_size_axial << endl;
3781  fileGeom << ""<< endl;
3782 
3783  // Optional fields
3784  fileGeom << "rsectors first angle : " << block_first_angle << endl;
3785  fileGeom << "number of modules transaxial : " << number_of_blocks_trans << endl;
3786  fileGeom << "number of modules axial : " << number_of_blocks_axial << endl;
3787  fileGeom << "module gap transaxial : " << block_step_trans << endl;
3788  fileGeom << "module gap axial : " << block_step_axial << endl;
3789  fileGeom << "crystal gap transaxial : " << crystal_step_trans << endl;
3790  fileGeom << "crystal gap axial : " << crystal_step_axial << endl;
3791  fileGeom << "rotation direction : CCW " << endl; // default for GATE
3792  fileGeom << ""<< endl;
3793 
3794  // Write only if different from default values
3795  if(min_angle_diff > 0.) fileGeom << "min angle difference : " << min_angle_diff << endl;
3796 
3797  // Convert angular span to the CASToR convention
3798  if(block_angular_span >= 360.0005 ||
3799  block_angular_span <= 359.9995 ) // GATE bounds
3800  {
3801  block_angular_span *= (number_of_blocks+1)/number_of_blocks;
3802  fileGeom << "rsectors angular span : " << block_angular_span << endl;
3803  }
3804 
3805  if(block_nb_zshifts > 0) fileGeom << "rsectors nbZShift :" << block_nb_zshifts << endl;
3806  if(!vec_block_Z_Shift.empty()) WriteVector(fileGeom, "rsectors ZShift : ", vec_block_Z_Shift);
3807 
3808  fileGeom.close();
3809 
3810  Cout("Output geom file written at :" << a_pathGeom << endl);
3811  }
3812  else
3813  {
3814  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Couldn't open geom file for writing "<< a_pathGeom << " !" << endl);
3815  return 1;
3816  }
3817 
3818  return 0;
3819 }
3820 
3821 
3822 
3823 
3824 // =====================================================================
3825 // ---------------------------------------------------------------------
3826 // ---------------------------------------------------------------------
3827 // =====================================================================
3828 /*
3829  \fn CreateGeomWithSPECT()
3830  \param a_pathMac : string containing the path to a GATE macro file
3831  \param a_pathGeom : string containing the path to a CASToR output geom file
3832  \brief Read a GATE macro file containing the description of a SPECThead system, and convert it to a geom file
3833  \return 0 if success, positive value otherwise
3834 */
3835 int CreateGeomWithSPECT(string a_pathMac, string a_pathGeom)
3836 {
3837  /* Declaring variables */
3838  string modality;
3839  string scanner_name = GetFileFromPath(a_pathGeom.substr(0,a_pathGeom.find_first_of(".geom")));
3840  FLTNB scanner_radius = -1.;
3841  string description = "SPECT camera extracted from GATE macro: " + a_pathMac;
3842 
3843  // head(s)
3844  string head_name = "SPECThead"; // not used. Correspond to SPECThead
3845  uint32_t number_of_heads = 0;
3846  FLTNB head_pos_X = 0.;
3847  FLTNB head_pos_Y = 0.;
3848  FLTNB head_first_angle = 0.;
3849  FLTNB head_angular_pitch = -1.;
3850  string head_orbit_name = "";
3851  FLTNB head_rotation_speed = 0.;
3852  bool is_head_Y_axis = false;
3853 
3854  // crystal
3855  string crystal_name = "crystal";
3856  FLTNB crystal_size_trans = 0.;
3857  FLTNB crystal_size_axial = 0.;
3858  FLTNB crystal_depth = 0;
3859 
3860  // pixel
3861  string pixel_name = "pixel";
3862  uint32_t number_of_pixels_trans = 1;
3863  uint32_t number_of_pixels_axial = 1;
3864  FLTNB pix_size_trans = 0.;
3865  FLTNB pix_size_axial = 0.;
3866  FLTNB pix_step_trans = 0.;
3867  FLTNB pix_step_axial = 0.;
3868 
3869  // collimator parameters
3870  string focal_model_trs = "constant";
3871  uint16_t nb_coeff_model_trs = 1;
3872  FLTNB coeff_model_trs = 0.;
3873  string focal_model_axl = "constant";
3874  uint16_t nb_coeff_model_axl = 1;
3875  FLTNB coeff_model_axl = 0.;
3876 
3877  // others
3878  uint32_t voxels_number_trans;
3879  uint32_t voxels_number_axial;
3880  double fov_trans;
3881  double fov_axial;
3882 
3883  vector<string> path_mac_files;
3884  path_mac_files.push_back(a_pathMac);
3885 
3886  // Recover path to all macro files from the main mac file
3887  if(GetGATEMacFiles(a_pathMac , path_mac_files))
3888  {
3889  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Error occured when trying to recover paths to GATE macro files !" << endl);
3890  return 1;
3891  }
3892 
3893 
3894  // Recover aliases of the different parts of the architecture
3895  if(GetGATEAliasesSPECT(path_mac_files, head_name, crystal_name, pixel_name, 2) )
3896  {
3897  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Error occured when trying to recover aliases for the elements of the SPECThead !" << endl);
3898  return 1;
3899  }
3900 
3901  // Loop to recover all other informations
3902  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
3903  {
3904  ifstream systemMac(path_mac_files[f].c_str(), ios::in);
3905 
3906  string line;
3907  while(getline(systemMac, line))
3908  {
3909  // Scanner
3910  modality = "SPECT_CONVERGENT";
3911  vector <string> values;
3912  string entry = "";
3913 
3914  // assumes that first block is positionned on the x-axis
3915  entry = "/gate/"+head_name+"/placement/setTranslation";
3916  values = CheckGATECommand(entry, line);
3917  if (values.size()>0)
3918  {
3919  if(ConvertFromString(values[0], &head_pos_X) ||
3920  ConvertFromString(values[1], &head_pos_Y) )
3921  {
3922  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
3923  return 1;
3924  }
3925 
3926  // Check first block cartesian coordinates is 0 on X or Y axis
3927  // Throw error otherwise
3928  if(head_pos_X!=0 && head_pos_Y !=0)
3929  {
3930  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
3931  Cerr(" Block cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
3932  return 1;
3933  }
3934 
3935  // Get the axis on which the first rsector is positionned
3936  if(head_pos_Y!=0) is_head_Y_axis = true;
3937 
3938  scanner_radius = is_head_Y_axis ? abs(head_pos_Y) : abs(head_pos_X) ;
3939  }
3940 
3941 
3942  entry = "/gate/"+head_name+"/geometry/setZLength";
3943  values = CheckGATECommand(entry, line);
3944  if (values.size()>0)
3945  {
3946  if(ConvertFromString(values[0], &fov_axial))
3947  {
3948  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
3949  return 1;
3950  }
3951  // 4mm voxels by default
3952  voxels_number_axial = fov_axial/4 + 1;
3953  }
3954 
3955 
3956  entry = "/gate/"+head_name+"/ring/setRepeatNumber";
3957  values = CheckGATECommand(entry, line);
3958  if (values.size()>0)
3959  {
3960  if(ConvertFromString(values[0], &number_of_heads))
3961  {
3962  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
3963  return 1;
3964  }
3965  }
3966 
3967 
3968  entry = "/gate/"+head_name+"/ring/setFirstAngle";
3969  values = CheckGATECommand(entry, line);
3970  if (values.size()>0)
3971  {
3972  if(ConvertFromString(values[0], &head_first_angle))
3973  {
3974  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
3975  return 1;
3976  }
3977  }
3978 
3979 
3980  entry = "/gate/"+head_name+"/ring/setAngularPitch";
3981  values = CheckGATECommand(entry, line);
3982  if (values.size()>0)
3983  {
3984  if(ConvertFromString(values[0], &head_angular_pitch))
3985  {
3986  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
3987  return 1;
3988  }
3989  }
3990 
3991  entry = "/gate/"+head_name+"/moves/insert";
3992  values = CheckGATECommand(entry, line);
3993  if (values.size()>0)
3994  {
3995  if(ConvertFromString(values[0], &head_orbit_name))
3996  {
3997  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
3998  return 1;
3999  }
4000  }
4001 
4002  entry = "/gate/"+head_orbit_name+"/setSpeed";
4003  values = CheckGATECommand(entry, line);
4004  if (values.size()>0)
4005  {
4006  if(ConvertFromString(values[0], &head_rotation_speed))
4007  {
4008  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occured while trying to parse line: " << line<< endl);
4009  return 1;
4010  }
4011  }
4012 
4013 
4014 
4015  // --- Crystals ---
4016  entry = "/gate/"+crystal_name+"/geometry/setXLength";
4017  values = CheckGATECommand(entry, line);
4018  if (values.size()>0)
4019  {
4020  double x_length;
4021  if(ConvertFromString(values[0], &x_length) )
4022  {
4023  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4024  return 1;
4025  }
4026 
4027  if (is_head_Y_axis)
4028  crystal_size_trans = x_length;
4029  else
4030  crystal_depth = x_length;
4031  }
4032 
4033  entry = "/gate/"+crystal_name+"/geometry/setYLength";
4034  values = CheckGATECommand(entry, line);
4035  if (values.size()>0)
4036  {
4037  double y_length;
4038  if(ConvertFromString(values[0], &y_length) )
4039  {
4040  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4041  return 1;
4042  }
4043 
4044  if (is_head_Y_axis)
4045  crystal_depth = y_length;
4046  else
4047  crystal_size_trans = y_length;
4048 
4049  }
4050 
4051  entry = "/gate/"+crystal_name+"/geometry/setZLength";
4052  values = CheckGATECommand(entry, line);
4053  if (values.size()>0)
4054  {
4055  if(ConvertFromString(values[0], &crystal_size_axial) )
4056  {
4057  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4058  return 1;
4059  }
4060  }
4061 
4062 
4063 
4064 
4065 
4066  // --- Pixels ---
4067  entry = is_head_Y_axis ?
4068  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberX":
4069  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberY";
4070 
4071 
4072  values = CheckGATECommand(entry, line);
4073  if (values.size()>0)
4074  {
4075  if(ConvertFromString(values[0], &number_of_pixels_trans) )
4076  {
4077  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4078  return 1;
4079  }
4080  }
4081 
4082  entry = "/gate/"+pixel_name+"/cubicArray/setRepeatNumberZ";
4083  values = CheckGATECommand(entry, line);
4084  if (values.size()>0)
4085  {
4086  if(ConvertFromString(values[0], &number_of_pixels_axial) )
4087  {
4088  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4089  return 1;
4090  }
4091  }
4092 
4093 
4094  entry = "/gate/"+pixel_name+"/geometry/setXLength";
4095  values = CheckGATECommand(entry, line);
4096  if (values.size()>0)
4097  {
4098  double x_length;
4099  if(ConvertFromString(values[0], &x_length) )
4100  {
4101  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4102  return 1;
4103  }
4104 
4105  if (is_head_Y_axis)
4106  pix_size_trans = x_length;
4107  }
4108 
4109  entry = "/gate/"+pixel_name+"/geometry/setYLength";
4110  values = CheckGATECommand(entry, line);
4111  if (values.size()>0)
4112  {
4113  double y_length;
4114  if(ConvertFromString(values[0], &y_length) )
4115  {
4116  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4117  return 1;
4118  }
4119 
4120  if (!is_head_Y_axis)
4121  pix_size_trans = y_length;
4122 
4123  }
4124 
4125  entry = "/gate/"+pixel_name+"/geometry/setZLength";
4126  values = CheckGATECommand(entry, line);
4127  if (values.size()>0)
4128  {
4129  if(ConvertFromString(values[0], &pix_size_axial) )
4130  {
4131  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4132  return 1;
4133  }
4134  }
4135 
4136 
4137  entry = "/gate/"+pixel_name+"/cubicArray/setRepeatVector";
4138  values = CheckGATECommand(entry, line);
4139  if (values.size()>0)
4140  {
4141  string trs_step = is_head_Y_axis ?
4142  values[0] :
4143  values[1] ;
4144 
4145  if(ConvertFromString(trs_step, &pix_step_trans) ||
4146  ConvertFromString(values[2], &pix_step_axial) )
4147  {
4148  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4149  return 1;
4150  }
4151  }
4152 
4153 
4154  // collimator parameter
4155  entry = is_head_Y_axis ?
4156  "/gate/fanbeam/geometry/setFocalDistanceY":
4157  "/gate/fanbeam/geometry/setFocalDistanceX";
4158 
4159  entry = "/gate/fanbeam/geometry/setFocalDistanceX";
4160  values = CheckGATECommand(entry, line);
4161  if (values.size()>0)
4162  {
4163  if(ConvertFromString(values[0], &coeff_model_trs) )
4164  {
4165  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occured while trying to parse line: " << line<< endl);
4166  return 1;
4167  }
4168 
4169  focal_model_trs = "polynomial";
4170  }
4171 
4172  }
4173  systemMac.close();
4174  }
4175 
4176  // Transaxial FOV defined as scanner radius / 2
4177  fov_trans = scanner_radius/2;
4178  // 4mm voxels by default
4179  voxels_number_trans = fov_trans/2 + 1;
4180 
4181  uint32_t nb_pixels = number_of_pixels_axial * number_of_pixels_trans;
4182 
4183  pix_size_axial = nb_pixels>1 ? pix_size_axial : crystal_size_axial;
4184  pix_size_trans = nb_pixels>1 ? pix_size_trans : crystal_size_trans;
4185 
4186  // Compute gaps
4187  if (pix_step_axial - pix_size_axial >= 0)
4188  pix_step_axial = pix_step_axial - pix_size_axial;
4189 
4190  if (pix_step_trans - pix_size_trans >= 0)
4191  pix_step_trans = pix_step_trans - pix_size_trans;
4192 
4193 
4194  // CASToR x and y axis for rotation inverted in comparison with GATE
4195  head_first_angle = round(atan2f(head_pos_X , head_pos_Y) * 180. / M_PI)
4196  - head_first_angle;
4197 
4198 
4199  // Writing the .geom file
4200  ofstream fileGeom(a_pathGeom.c_str(), ios::out | ios::trunc);
4201 
4202  if(fileGeom)
4203  {
4204  fileGeom << "modality : " << modality << endl;
4205  fileGeom << "scanner name : " << scanner_name << endl;
4206  fileGeom << "number of detector heads : " << number_of_heads << endl;
4207  fileGeom << "trans number of pixels : " << number_of_pixels_trans << endl;
4208  fileGeom << "trans pixel size : " << pix_size_trans << endl;
4209  fileGeom << "trans gap size : " << pix_step_trans << endl;
4210  fileGeom << "axial number of pixels : " << number_of_pixels_axial << endl;
4211  fileGeom << "axial pixel size : " << pix_size_axial << endl;
4212  fileGeom << "axial gap size : " << pix_step_axial << endl;
4213 
4214  fileGeom << "detector depth : " << crystal_depth << endl;
4215 
4216  fileGeom << "scanner radius : " << scanner_radius;
4217  for(size_t h=1 ; h<number_of_heads ; h++)
4218  fileGeom << "," << scanner_radius;
4219  fileGeom << endl;
4220 
4221  fileGeom << "# Collimator configuration : "<< endl << endl;
4222  for(size_t h=0 ; h<number_of_heads ; h++)
4223  {
4224  fileGeom << "head" << h+1 << ":" << endl;
4225  fileGeom << "trans focal model: " << focal_model_trs << endl;
4226  fileGeom << "trans number of coef model: " << nb_coeff_model_trs << endl;
4227  fileGeom << "trans parameters: " << coeff_model_trs << endl;
4228  fileGeom << "axial focal model: " << focal_model_axl << endl;
4229  fileGeom << "axial number of coef model: " << nb_coeff_model_axl << endl;
4230  fileGeom << "axial parameters: " << coeff_model_axl << endl;
4231  fileGeom << endl;
4232  }
4233 
4234  fileGeom << "" << endl;
4235  fileGeom << "# default reconstruction parameters" << endl;
4236  fileGeom << "voxels number transaxial : " << voxels_number_trans << endl;
4237  fileGeom << "voxels number axial : " << voxels_number_axial << endl;
4238 
4239  fileGeom << "field of view transaxial : " << fov_trans << endl;
4240  fileGeom << "field of view axial : " << fov_axial << endl << endl ;
4241  fileGeom << ""<< endl;
4242 
4243  fileGeom << "# description" << endl;
4244  fileGeom << "description : " << description << endl;
4245 
4246  fileGeom.close();
4247 
4248  Cout("Output geom file written at :" << a_pathGeom << endl);
4249  }
4250  else
4251  {
4252  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Couldn't open geom file for writing "<< a_pathGeom << " !" << endl);
4253  return 1;
4254  }
4255 
4256  return 0;
4257 }
int ReadMacECAT(string a_pathMac, uint32_t &nCrystalsTot, uint32_t &nCrystalsAxial, uint32_t &nCrystalsTransaxial, uint32_t &nBlocksLine, uint32_t &nBlocksPerRing, uint32_t &start_time_ms, uint32_t &duration_ms, int vb)
Recover informations about the scanner element of an ECAT system and acquisition duration, from a GATE macro file.
This header file is mainly used to declare some macro definitions and all includes needed from the st...
uint32_t ConvertIDecat(int32_t nBlocksPerRing, int32_t nBlocksLine, int32_t nCrystalsTransaxial, int32_t nCrystalsAxial, int32_t crystalID, int32_t blockID)
Compute a CASToR crystal index of a GATE ecat system from its indexes (block/crystal) and the system ...
#define GATE_SYS_UNKNOWN
#define KIND_RDM
#define FLTNB
Definition: gVariables.hh:55
This file gathers various function dedicated to data conversion in order to convert various type of G...
int IntfKeyGetRecurringValueFromFile(const string &a_pathToHeader, const string &a_key, T *ap_return, int a_nbElts, int a_mandatoryFlag, uint16_t a_nbOccurrences)
int ReadMacCylindrical(string a_pathMac, uint8_t &nLayers, uint32_t *nb_crystal_per_layer, uint32_t &nCrystalsTot, uint32_t &nCrystalsAxial, uint32_t &nCrystalsTransaxial, vector< uint32_t > &nLayersRptAxial, vector< uint32_t > &nLayersRptTransaxial, uint32_t &nSubmodulesAxial, uint32_t &nSubmodulesTransaxial, uint32_t &nModulesAxial, uint32_t &nModulesTransaxial, uint32_t &nRsectorsPerRing, uint32_t &start_time_ms, uint32_t &duration_ms, int vb)
Recover informations about the scanner element of a cylindricalPET system and acquisition duration...
#define GATE_SYS_ECAT
#define GEO_ROT_CCW
Definition: vScanner.hh:30
#define KIND_TRUE
vector< string > CheckGATECommand(const string &a_key, const string &a_line)
Check if the line contains the provided GATE command. In this case, parse the line and returns the va...
uint32_t ConvertIDcylindrical(uint32_t nRsectorsPerRing, uint32_t nModulesTransaxial, uint32_t nModulesAxial, uint32_t nSubmodulesTransaxial, uint32_t nSubmodulesAxial, uint32_t nCrystalsTransaxial, uint32_t nCrystalsAxial, uint8_t nLayers, uint32_t *nCrystalPerLayer, vector< uint32_t > nLayersRptTransaxial, vector< uint32_t > nLayersRptAxial, int32_t layerID, int32_t crystalID, int32_t submoduleID, int32_t moduleID, int32_t rsectorID)
Compute a CASToR crystal index of a GATE cylindricalPET system from its indexes (rsector/module/submo...
int GetGATEAliasesCylindrical(vector< string > path_mac_files, string &rsector_name, string &module_name, string &submodule_name, string &crystal_name, vector< string > &layers_name, int vb)
Loop over a list of path to GATE macro files passed in parameter to recover aliases of the different ...
int IntfKeyGetValueFromFile(const string &a_pathToHeader, const string &a_key, T *ap_return, int a_nbElts, int a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_pathToHeader" interfile header matching the "a_keyword" key passed...
Definition: oInterfileIO.cc:52
#define GATE_SYS_SPECT
#define KIND_UNKNOWN
string GetFileFromPath(const string &a_pathToFile)
Simply return the file from a path string passed in parameter.
Definition: gOptions.cc:1119
int ConvertFromString(const string &a_str, string *a_result)
Copy the 'a_str' string in the position pointed by 'a_result'.
Definition: gOptions.cc:749
int GetGATEMacFiles(const string &a_pathMac, vector< string > &ap_pathToMacFiles)
Extract the paths to each macro file contained in the main macro file.
#define Cerr(MESSAGE)
#define KIND_SCAT
int CreateGeomWithSPECT(string a_pathMac, string a_pathGeom)
Read a GATE macro file containing the description of a SPECThead system, and convert it to a geom fil...
int ReadIntfSPECT(string a_pathIntf, float_t &a_distToDetector, uint32_t &a_nHeads, uint32_t &a_nPixAxl, uint32_t &a_nPixTrs, float_t &a_crystalSizeAxl, float_t &a_crystalSizeTrs, uint32_t &a_nProjectionsTot, uint32_t &a_nProjectionsByHead, float_t &a_head1stAngle, float_t &a_headAngPitchDeg, float_t &a_headAngStepDeg, int &a_headRotDirection, uint32_t &a_start_time_ms, uint32_t &a_duration_ms, int vb)
Recover informations about the scanner element of an ECAT system, and acquisition duration...
void ConvertValuesTomm(vector< string > &ap_v)
Check if the vector of strings passed in parameter contains the 'cm' unit In this case...
int ReadMacSPECT(string a_pathMac, float_t &a_distToDetector, uint32_t &a_nHeads, uint32_t &a_nPixAxl, uint32_t &a_nPixTrs, float_t &a_crystalSizeAxl, float_t &a_crystalSizeTrs, uint32_t &a_nProjectionsTot, uint32_t &a_nProjectionsByHead, float_t &a_head1stAngle, float_t &a_headAngPitch, float_t &a_headAngStepDeg, int &a_headRotDirection, uint32_t &a_start_time_ms, uint32_t &a_duration_ms, int vb)
Recover informations about the scanner element of an ECAT system, and acquisition duration...
int ComputeKindGATEEvent(uint32_t eventID1, uint32_t eventID2, int comptonPhantom1, int comptonPhantom2, int rayleighPhantom1, int rayleighPhantom2)
Determine kind of a given coincidence event, from its attributes.
#define KEYWORD_MANDATORY
Definition: gOptions.hh:25
#define KEYWORD_OPTIONAL
Definition: gOptions.hh:27
#define GATE_SYS_CYLINDRICAL
int GetGATEAliasesEcat(vector< string > path_mac_files, string &block_name, string &crystal_name, int vb)
Loop over a list of path to GATE macro files passed in parameter to recover aliases of the different ...
uint32_t ConvertIDSPECTRoot2(uint32_t a_nbSimulatedPixels, uint32_t a_nPixTrs, uint32_t a_nPixAxl, int32_t a_headID, int32_t a_crystalID, int32_t a_pixelID, float_t a_rotAngle, float_t a_headAngPitch, float_t a_crystalSizeAxl, float_t a_crystalSizeTrs, float_t a_gPosX, float_t a_gPosY, float_t a_gPosZ)
Compute a CASToR crystal index of a GATE SPECThead system.
string toString(T a_val)
Convert a value of any type into string.
string GetPathOfFile(const string &a_pathToFile)
Simply return the path to the directory of a file path string passed in parameter.
Definition: gOptions.cc:1144
int CreateGeomWithCylindrical(string a_pathMac, string a_pathGeom)
Read a GATE macro file containing the description of a cylindricalPET system, and convert it to a geo...
uint32_t ConvertIDSPECTRoot1(int32_t a_headID, float_t a_rotAngle, float_t a_angStep, uint32_t a_nProjectionsByHead)
Compute a CASToR projection index of a GATE SPECThead system.
#define GATE_NB_MAX_LAYERS
int CreateGeomWithECAT(string a_pathMac, string a_pathGeom)
Read a GATE macro file containing the description of an ecat system, and convert it to a geom file...
#define KIND_MSCAT
vector< string > Split(string a_line)
Split the line provided in parameter into a vector of strings (separator is blankspace) ...
#define Cout(MESSAGE)
int WriteVector(ofstream &file, const string &a_key, vector< T > a_vals)
Write the key and its values in the file provided in parameter.
#define GEO_ROT_CW
Definition: vScanner.hh:28
int GetGATESystemType(const string &a_pathMac)
Read a GATE macro file and identify the system type from the 'gate/systems/' command lines...
int GetGATEAliasesSPECT(vector< string > path_mac_files, string &base_name, string &crystal_name, string &pixel_name, int vb)
Loop over a list of path to GATE macro files passed in parameter to recover aliases of the different ...