CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
src/management/gDataConversionUtilities.cc
Go to the documentation of this file.
1 
9 #include "gVariables.hh"
10 #include "gDataConversionUtilities.hh"
11 #include <iomanip>
12 
13 /*
14  Miscelleanous functionalities
15  */
16 
17 // =====================================================================
18 // ---------------------------------------------------------------------
19 // ---------------------------------------------------------------------
20 // =====================================================================
21 /*
22  \fn CheckGATECommand
23  \param a_key: string containing a GATE command to recover
24  \param a_line : string containing the line to check
25  \brief Check if the line contains the provided GATE command. In this case, \n
26  parse the line and returns the values in a vector of strings
27  \details Values are converted in mm if 'cm' is found in the line
28  \return the vector of strings containing the elements of the line.
29 */
30 vector<string> CheckGATECommand(const string& a_key, const string& a_line)
31 {
32  vector<string> values;
33 
34  // cut any part after comment symbol
35  string line = a_line;
36 
37  line = (line.find("#") != string::npos) ?
38  line.substr(0, line.find_first_of("#")) :
39  line;
40 
41  size_t foundAdress = line.find(a_key);
42 
43  if (foundAdress != string::npos)
44  {
45  values = Split(a_line);
46  values.erase (values.begin());
47  }
48 
49  ConvertValuesTomm(values);
50  return values;
51 }
52 
53 
54 
55 // =====================================================================
56 // ---------------------------------------------------------------------
57 // ---------------------------------------------------------------------
58 // =====================================================================
59 /*
60  \fn split
61  \param a_line : string to split
62  \brief Split the line provided in parameter into a vector of strings (separator is blankspace)
63  \return vector of string containing the splitted elements of the line
64 */
65 vector<string> Split(string a_line)
66 {
67  string buf;
68  stringstream ss(a_line);
69 
70  vector<string> tokens;
71 
72  while (ss >> buf)
73  tokens.push_back(buf);
74 
75  return tokens;
76 }
77 
78 
79 
80 // =====================================================================
81 // ---------------------------------------------------------------------
82 // ---------------------------------------------------------------------
83 // =====================================================================
84 /*
85  \fn ConvertValuesTomm
86  \param ap_v : vector of strings
87  \brief Check if the vector of strings passed in parameter contains the 'cm' unit \n
88  In this case, convert all its values in mm
89 */
90 void ConvertValuesTomm(vector<string>& ap_v)
91 {
92  // loop on values
93  for(uint16_t i=0; i < ap_v.size(); i++)
94  // check if values were provided in cm
95  if (ap_v[i] == "cm")
96  // Convert all values to mm (skip command key)
97  for (int j=0; j<i; j++)
98  {
99  float val;
100  ConvertFromString(ap_v[j], &val);
101  ap_v[j] = toString(10 * val);
102  }
103 }
104 
105 
106 // =====================================================================
107 // ---------------------------------------------------------------------
108 // ---------------------------------------------------------------------
109 // =====================================================================
110 /*
111  \fn WriteVector
112  \param file : the output file
113  \param a_key : key to write
114  \param a_vals : vector containing the key values
115  \brief Write the key and its values in the file provided in parameter
116  \return 0 if success, positive value otherwise
117 */
118 template <class T>
119 int WriteVector(ofstream& file, const string& a_key, vector <T> a_vals)
120 {
121  int n = a_vals.size();
122 
123  if (n > 0)
124  {
125  file << a_key ;
126  for (int i=0; i < n; i++)
127  {
128  stringstream ss;
129  ss << a_vals[i];
130  if (i == n-1)
131  file << ss.str() << endl;
132  else
133  file << ss.str() << ",";
134  }
135  }
136  else
137  file << a_key << "0" <<endl;
138 
139  return 0;
140 }
141 
142 template int WriteVector(ofstream& file, const string& a_key, vector <double> a_vals);
143 
144 
145 
146 // =====================================================================
147 // ---------------------------------------------------------------------
148 // ---------------------------------------------------------------------
149 // =====================================================================
150 /*
151  \fn WriteVector
152  \param file : the output file
153  \param a_key : key to write
154  \param a_vals : vector containing the key values
155  \brief Write the key and its values in the file provided in parameter
156  \return 0 if success, positive value otherwise
157 */
158 int WriteVector(ofstream& file, const string& a_key, vector <string> a_vals)
159 {
160  int n = a_vals.size();
161 
162  if (n > 0)
163  {
164  file << a_key ;
165  for (int i=0; i < n; i++)
166  {
167  if (i == n-1)
168  file << a_vals[i] << endl;
169  else
170  file << a_vals[i] << ",";
171  }
172  }
173  else
174  file << a_key << "0" <<endl;
175 
176  return 0;
177 }
178 
179 
180 
181 // =====================================================================
182 // ---------------------------------------------------------------------
183 // ---------------------------------------------------------------------
184 // =====================================================================
185 /*
186  \fn WriteVector
187  \param file : the output file
188  \param a_key : key to write
189  \param a_vals : vector containing the key values
190  \brief Write the key and its values contained in a 2 level vector of strings in the file provided in parameter
191  \return 0 if success, positive value otherwise
192 */
193 int WriteVector(ofstream& file, const string& a_key, vector <vector<string> > a_vals)
194 {
195  int n = a_vals.size();
196  file << a_key;
197  for (int i=0; i < n; i++)
198  for (int j=0; j < 3; j++)
199  if (i == n-1 && j == 2)
200  file << a_vals[i][j] << endl;
201  else
202  file << a_vals[i][j] << ",";
203 
204  return 0;
205 }
206 
207 
208 
209 
210 // =====================================================================
211 // ---------------------------------------------------------------------
212 // ---------------------------------------------------------------------
213 // =====================================================================
214 /*
215  \fn GetGATEMacFiles(const string& a_pathMac, vector<string> ap_pathToMacFiles)
216  \param a_pathMac : path to a GATE main macro file
217  \param ap_pathToMacFiles : array containing the paths of macro files
218  \brief Extract the paths to each macro file contained in the main macro file.
219  \return 0 if success, positive value otherwise
220 */
221 int GetGATEMacFiles(const string& a_pathMac, vector<string> &ap_pathToMacFiles)
222 {
223  ifstream mac_file(a_pathMac, ios::in);
224 
225  if(mac_file)
226  {
227  string quickLine;
228 
229  while(getline(mac_file, quickLine))
230  {
231  vector <string> values;
232 
233  values = CheckGATECommand("/control/execute", quickLine);
234 
235  if (values.size()>0)
236  {
237  // Check if a full path has been provided (start with '/' )
238  // Give just values in this case
239  char first_char = values[0].at(0);
240 
241  if(first_char == '/')
242  ap_pathToMacFiles.push_back(values[0]);
243  // Just concatenate path otherwise
244  else
245  ap_pathToMacFiles.push_back(GetPathOfFile(a_pathMac)+values[0]);
246 
247  }
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 occurred 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 = (uint32_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 = (uint32_t)(( trs_pos + a_nPixTrs/2*sizePixTrs) / sizePixTrs);
788 
789  if ( axialID < a_nPixAxl && transID < a_nPixTrs )
790  {
791  castorID = axialID*a_nPixTrs + transID;
792  }
793  else // return more than the max crystal ID to check for errors
794  {
795  castorID = a_nPixAxl*a_nPixTrs;
796  }
797 
798  }
799 
800  return castorID;
801 }
802 
803 
804 
805 
806 uint32_t ConvertIDcylindrical(uint32_t nRsectorsAngPos,
807  uint32_t nRsectorsAxial,
808  bool a_invertDetOrder,
809  int a_rsectorIdOrder,
810  bool a_lyrRptFlag,
811  uint32_t nModulesTransaxial,
812  uint32_t nModulesAxial,
813  uint32_t nSubmodulesTransaxial,
814  uint32_t nSubmodulesAxial,
815  uint32_t nCrystalsTransaxial,
816  uint32_t nCrystalsAxial,
817  uint8_t nLayers,
818  uint32_t* nCrystalPerLayer,
819  vector<uint32_t> nLayersRptTransaxial,
820  vector<uint32_t> nLayersRptAxial,
821  int32_t layerID,
822  int32_t crystalID,
823  int32_t submoduleID,
824  int32_t moduleID,
825  int32_t rsectorID)
826 {
827  // Castor ID definition
828  uint32_t castorID = 0;
829  int32_t layer = 0;
830 
831  if(nLayersRptTransaxial.size()==0 && nLayersRptAxial.size()==0)
832  {
833  // layerID represents the actual layer level
834 
835  // add the number of crystals contained in previous layers as
836  // CASToR indexes all crystals of a layer ring before the next layer
837  layer = layerID;
838 
839  for(int l=0 ; l<layer; l++)
840  castorID += nCrystalPerLayer[l];
841 
842  int32_t nTrsCrystalsPerSubmodule = nCrystalsTransaxial;
843  int32_t nTrsCrystalsPerModule = nTrsCrystalsPerSubmodule * nSubmodulesTransaxial;
844  int32_t nTrsCrystalsPerRsector = nTrsCrystalsPerModule * nModulesTransaxial;
845  int32_t nCrystalsPerRing = nTrsCrystalsPerRsector * nRsectorsAngPos;
846 
847  // Rsector axial(=ring) and transaxial(=angular) ID
848  // Fastest ordering orientation (axial or transaxial) depends on the repeaters
849  int32_t rsectorAxlID = 0 ;
850  int32_t rsectorTrsID = 0 ;
851 
852  // standard, transaxial first
853  if(a_rsectorIdOrder == 0)
854  {
855  rsectorAxlID = rsectorID/nRsectorsAngPos ;
856  rsectorTrsID = (int32_t)(rsectorID%nRsectorsAngPos) ;
857  }
858  else // using cubic array, axial first
859  {
860  rsectorAxlID = rsectorID%nRsectorsAxial ;
861  rsectorTrsID = (int32_t)(rsectorID/nRsectorsAxial) ;
862  }
863 
864 
865  // Compute axial ID
866  int32_t ringID = rsectorAxlID * nModulesAxial * nSubmodulesAxial * nCrystalsAxial
867  + (int32_t)(moduleID/nModulesTransaxial) * nSubmodulesAxial * nCrystalsAxial
868  + (int32_t)(submoduleID/nSubmodulesTransaxial) * nCrystalsAxial
869  + (int32_t)(crystalID/nCrystalsTransaxial);
870 
871  // Recover transaxial ID for each element
872  moduleID = moduleID % nModulesTransaxial;
873  submoduleID = submoduleID % nSubmodulesTransaxial;
874  crystalID = crystalID % nCrystalsTransaxial;
875 
876  // Reverse transaxial ordering
877  if( a_invertDetOrder )
878  {
879  moduleID = nModulesTransaxial-1 - moduleID;
880  submoduleID = nSubmodulesTransaxial-1 - submoduleID;
881  crystalID = nCrystalsTransaxial-1 - crystalID;
882  }
883 
884  // Compute final ID
885  castorID += nCrystalsPerRing * ringID
886  + nTrsCrystalsPerRsector * rsectorTrsID
887  + nTrsCrystalsPerModule * moduleID
888  + nTrsCrystalsPerSubmodule * submoduleID
889  + crystalID;
890  }
891 
892  else
893  {
894 
895  // layerID represents a crystal layer element
896 
897  // Get the total number of crystals in the first layer
898  uint32_t sum_detectors_prev_layers = 0;
899 
900  // Get the layer which the crystal belongs to
901  // (Compare layer ID to sum of nb detectors in previous layors +
902  // detectors in actual layers)
903  while ( layerID >= (int32_t)( sum_detectors_prev_layers
904  + ( nLayersRptTransaxial[layer]
905  * nLayersRptAxial[layer]) ) )
906  {
907  // recover nb detectors in previous layers
908  sum_detectors_prev_layers += nLayersRptTransaxial[layer]
909  * nLayersRptAxial[layer];
910 
911  layer++; // increment layer
912  }
913 
914  // layerID contain index of all the detectors in all layer levels
915  // if not in the 1st layer, substract the IDs of the previous layers
916  // so that layerID variable indexes detectors only in the actual layer
917  if (layer>0)layerID -= sum_detectors_prev_layers;
918 
919  // add the number of crystals contained in previous layers as
920  // CASToR indexes all crystals of a layer ring before the next layer
921  for(int l=0 ; l<layer ; l++)
922  castorID += nCrystalPerLayer[l];
923 
924  int32_t nTrsCrystalsPerSubmodule = nCrystalsTransaxial * nLayersRptTransaxial[layer];
925  int32_t nTrsCrystalsPerModule = nTrsCrystalsPerSubmodule * nSubmodulesTransaxial;
926  int32_t nTrsCrystalsPerRsector = nTrsCrystalsPerModule * nModulesTransaxial;
927  int32_t nCrystalsPerRing = nTrsCrystalsPerRsector * nRsectorsAngPos;
928 
929  // Rsector axial(=ring) and transaxial(=angular) ID
930  // Fastest ordering orientation (axial or transaxial) depends on the repeaters
931  int32_t rsectorAxlID = 0 ;
932  int32_t rsectorTrsID = 0 ;
933 
934  // standard, transaxial first
935  if(a_rsectorIdOrder == 0)
936  {
937  rsectorAxlID = rsectorID/nRsectorsAngPos ;
938  rsectorTrsID = (int32_t)(rsectorID%nRsectorsAngPos) ;
939  }
940  else // using cubic array, axial first
941  {
942  rsectorAxlID = rsectorID%nRsectorsAxial ;
943  rsectorTrsID = (int32_t)(rsectorID/nRsectorsAxial) ;
944  }
945 
946 
947  // Compute axial ID
948  int32_t ringID = rsectorAxlID * nModulesAxial * nSubmodulesAxial * nCrystalsAxial * nLayersRptAxial[layer]
949  + (int32_t)(moduleID/nModulesTransaxial) * nSubmodulesAxial * nCrystalsAxial * nLayersRptAxial[layer]
950  + (int32_t)(submoduleID/nSubmodulesTransaxial) * nCrystalsAxial * nLayersRptAxial[layer]
951  + (int32_t)(crystalID/nCrystalsTransaxial) * nLayersRptAxial[layer];
952 
953  // Add layer contribution to axial ID
954  if(!nLayersRptTransaxial.empty() )
955  ringID += (int32_t)(layerID/nLayersRptTransaxial[layer]);
956 
957 
958  // Recover transaxial ID for each element
959  moduleID = moduleID % nModulesTransaxial;
960  submoduleID = submoduleID % nSubmodulesTransaxial;
961  crystalID = crystalID % nCrystalsTransaxial;
962  layerID = layerID % nLayersRptTransaxial[layer];
963 
964  // Reverse transaxial ordering
965  if( a_invertDetOrder )
966  {
967  moduleID = nModulesTransaxial-1 - moduleID;
968  submoduleID = nSubmodulesTransaxial-1 - submoduleID;
969  crystalID = nCrystalsTransaxial-1 - crystalID;
970  layerID = nLayersRptTransaxial[layer]-1 - layerID;
971  }
972 
973  // Compute final ID
974  castorID += nCrystalsPerRing * ringID
975  + nTrsCrystalsPerRsector * rsectorTrsID
976  + nTrsCrystalsPerModule * moduleID
977  + nTrsCrystalsPerSubmodule * submoduleID
978  + crystalID
979  + layerID;
980  }
981 
982  return castorID;
983 }
984 
985 
986 
987 // =====================================================================
988 // ---------------------------------------------------------------------
989 // ---------------------------------------------------------------------
990 // =====================================================================
991 /*
992  \fn ComputeKindGATEEvent
993  \param eventID1
994  \param eventID2
995  \param comptonPhantom1
996  \param comptonPhantom2
997  \param rayleighPhantom1
998  \param rayleighPhantom2
999  \brief Determine kind of a given coincidence event, from its attributes
1000  \return kind of the coincidence : unknown (=0, default), true(=1), single scat(=2), multiple scat(=3), random(=4)) (default value =0)
1001 */
1002 int ComputeKindGATEEvent(int32_t eventID1, int32_t eventID2,
1003  int comptonPhantom1, int comptonPhantom2,
1004  int rayleighPhantom1, int rayleighPhantom2)
1005 {
1006  if ( (eventID1 != eventID2)
1007  || eventID1 == -2 // noise single
1008  || eventID2 == -2 )
1009  //random
1010  return KIND_RDM;
1011  else
1012  {
1013  if (comptonPhantom1 == 0 && comptonPhantom2 == 0 &&
1014  rayleighPhantom1 == 0 && rayleighPhantom2 == 0)
1015  //true
1016  return KIND_TRUE;
1017  else
1018  {
1019  if (comptonPhantom1 == 1 || comptonPhantom2 == 1 ||
1020  rayleighPhantom1 == 1 || rayleighPhantom2 == 1)
1021  //single scat
1022  return KIND_SCAT;
1023  if (comptonPhantom1 > 1 || comptonPhantom2 > 1 ||
1024  rayleighPhantom1 > 1 || rayleighPhantom2 > 1)
1025  //multiple scat
1026  return KIND_MSCAT;
1027  }
1028  }
1029  // unknown
1030  return KIND_UNKNOWN;
1031 }
1032 
1033 
1034 
1035 // =====================================================================
1036 // ---------------------------------------------------------------------
1037 // ---------------------------------------------------------------------
1038 // =====================================================================
1039 /*
1040  \fn ReadMacCylindrical
1041  \param a_pathMac : path to a macro file
1042  \param nLayers : nb of crystal layers
1043  \param nCrystalsAxial : nb of axial crystals (in a submodule)
1044  \param nCrystalsTransaxial : nb of transaxial crystals (in a submodule)
1045  \param nLayersRptAxial : Array containing the number of axial crystals in each layer
1046  \param nLayersRptTransaxial : Array containing the number of transaxial crystals in each layer
1047  \param nSubmodulesAxial : nb of axial submodules (in a module)
1048  \param nSubmodulesTransaxial : nb of transaxial submodules (in a module)
1049  \param nModulesAxial : nb of axial modules (in a rsector)
1050  \param nModulesTransaxial : nb of transaxial modules (in a rsector)
1051  \param nRsectorsAxial : nb of axial rsectors
1052  \param nRsectorsAngPos : nb of rsectors per ring
1053  \param inverted_det_order : reverse ordering orientation of detectors depending on first rsector location
1054  \param rsector_id_order : ordering of rsector id
1055  \param start_time_ms : acquisition start time converted in ms
1056  \param duration_ms : acquisition duration converted in ms
1057  \param pet_coinc_window : coincidence window (required for TOF parameters)
1058  \param lyr_rpt_flag : flag to indicate layers are defined using repeater variable. Required for crystal indexing
1059  \param vb : verbosity
1060  \brief Recover informations about the scanner element of a cylindricalPET system and acquisition duration, from a GATE macro file
1061  \return 0 if success, positive value otherwise
1062 */
1063 int ReadMacCylindrical(string a_pathMac,
1064  uint8_t &nLayers,
1065  uint32_t *nb_crystal_per_layer,
1066  uint32_t &nCrystalsTot,
1067  uint32_t &nCrystalsAxial,
1068  uint32_t &nCrystalsTransaxial,
1069  vector<uint32_t> &nLayersRptAxial,
1070  vector<uint32_t> &nLayersRptTransaxial,
1071  uint32_t &nSubmodulesAxial,
1072  uint32_t &nSubmodulesTransaxial,
1073  uint32_t &nModulesAxial,
1074  uint32_t &nModulesTransaxial,
1075  uint32_t &nRsectorsAxial,
1076  uint32_t &nRsectorsAngPos,
1077  bool &invert_det_order,
1078  int &rsector_id_order,
1079  uint32_t &start_time_ms,
1080  uint32_t &duration_ms,
1081  FLTNB &pet_coinc_window,
1082  bool &lyr_rpt_flag,
1083  int vb)
1084 {
1085  vector<string> path_mac_files;
1086  path_mac_files.push_back(a_pathMac);
1087 
1088  // Recover path to all macro files from the main mac file
1089  if(GetGATEMacFiles(a_pathMac , path_mac_files))
1090  {
1091  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover paths to GATE macro files !" << endl);
1092  return 1;
1093  }
1094 
1095  string rsector_name = "";
1096  string module_name = "";
1097  string submodule_name = "";
1098  string crystal_name = "";
1099  string mod_rptr_type = "cubicArray";
1100  string smod_rptr_type = "cubicArray";
1101  string cry_rptr_type = "cubicArray";
1102  string lay_rptr_type = "cubicArray";
1103 
1104  // variables for linear repeater
1105  int mod_linear_nb = 0;
1106  int subm_linear_nb = 0;
1107  int cry_linear_nb = 0;
1108  vector<int> lay_linear_nb;
1109 
1110  vector <string> layers_name;
1111  vector<uint32_t> nLayersRptDepth;
1112  bool is_rsector_Y_axis = false;
1113 
1114  // Recover aliases of the different parts of the architecture
1115  if(GetGATEAliasesCylindrical(path_mac_files, rsector_name, module_name, submodule_name, crystal_name, layers_name, vb) )
1116  {
1117  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover aliases for the elements of the cylindricalPET !" << endl);
1118  return 1;
1119  }
1120 
1121  // Recover nb of detected layers
1122  nLayers = layers_name.size();
1123 
1124  // Loop to recover all other informations
1125  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
1126  {
1127  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
1128 
1129  string line;
1130  double time_start =-1.,
1131  time_stop =-1.,
1132  time_slices =-1.;
1133 
1134  while(getline(mac_file, line))
1135  {
1136  vector <string> values;
1137  string kword ="";
1138 
1139 
1140  // RSECTORS
1141 
1142  kword = "/gate/"+rsector_name+"/placement/setTranslation";
1143  values = CheckGATECommand(kword, line);
1144 
1145  // Check where the first rsector has been created
1146  if (values.size()>0)
1147  {
1148  FLTNB rsector_pos_X =0.,
1149  rsector_pos_Y =0.;
1150 
1151  if(ConvertFromString(values[0], &rsector_pos_X) ||
1152  ConvertFromString(values[1], &rsector_pos_Y) )
1153  {
1154  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1155  return 1;
1156  }
1157 
1158  // Get the axis on which the first rsector is positionned
1159  if(rsector_pos_Y!=0) is_rsector_Y_axis = true;
1160 
1161  // Get the detector ordering depending on the position of the first rsector
1162  // (inverted if located on top (Y-axis with positive value)
1163  // or on the X axis with negative value)
1164 
1165  if(rsector_pos_Y > 0 || rsector_pos_X < 0)
1166  invert_det_order = true;
1167 
1168  }
1169 
1170 
1171  kword = "/gate/"+rsector_name+"/ring/setRepeatNumber";
1172  values = CheckGATECommand(kword, line);
1173  if (values.size()>0)
1174  {
1175  if(ConvertFromString( values[0] , &nRsectorsAngPos) )
1176  {
1177  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1178  return 1;
1179  }
1180  }
1181 
1182 
1183  // Check if (axial) linear repeaters for rsectors
1184  kword = "/gate/"+rsector_name+"/linear/setRepeatNumber";
1185  values = CheckGATECommand(kword, line);
1186  if (values.size()>0)
1187  {
1188  if(ConvertFromString(values[0], &nRsectorsAxial) )
1189  {
1190  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1191  return 1;
1192  }
1193  }
1194 
1195 
1196  // Check if cubic array repeaters for rsectors
1197  kword = "/gate/"+rsector_name+"/cubicArray/setRepeatNumberZ";
1198  values = CheckGATECommand(kword, line);
1199 
1200  if (values.size()>0)
1201  {
1202  // Using a cubic array after a ring repeater (nRsectorsAngPos>1) leads to rsector being ordered axially first (and not transaxially)
1203  // Track this using a flag
1204  rsector_id_order = nRsectorsAngPos>1 ? 1 : 0 ;
1205 
1206  if(ConvertFromString(values[0], &nRsectorsAxial) )
1207  {
1208  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1209  return 1;
1210  }
1211  }
1212 
1213 
1214 
1215 
1216  // MODULES
1217 
1218  // Box/cubicArray repeaters
1219  kword = is_rsector_Y_axis ?
1220  "/gate/"+module_name+"/cubicArray/setRepeatNumberX":
1221  "/gate/"+module_name+"/cubicArray/setRepeatNumberY";
1222 
1223  values = CheckGATECommand(kword, line);
1224  if (values.size()>0)
1225  {
1226  if(ConvertFromString( values[0] , &nModulesTransaxial) )
1227  {
1228  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1229  return 1;
1230  }
1231  }
1232 
1233  kword = "/gate/"+module_name+"/cubicArray/setRepeatNumberZ";
1234  values = CheckGATECommand(kword, line);
1235  if (values.size()>0)
1236  {
1237  if(ConvertFromString( values[0] , &nModulesAxial) )
1238  {
1239  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1240  return 1;
1241  }
1242  }
1243 
1244  // linear repeaters instead of box
1245  kword = "/gate/"+module_name+"/linear/setRepeatNumber";
1246  values = CheckGATECommand(kword, line);
1247  if (values.size()>0)
1248  {
1249  //if(ConvertFromString( values[0] , &nModulesAxial) )
1250  if(ConvertFromString(values[0] , &mod_linear_nb) )
1251  {
1252  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1253  return 1;
1254  }
1255  }
1256 
1257  // linear repeaters instead of box, but with cubicArray
1258  kword = "/gate/"+module_name+"/cubicArray/setRepeatNumber ";
1259  values = CheckGATECommand(kword, line);
1260  if (values.size()>0)
1261  {
1262  //if(ConvertFromString( values[0] , &nModulesAxial) )
1263  if(ConvertFromString(values[0] , &mod_linear_nb) )
1264  {
1265  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1266  return 1;
1267  }
1268  }
1269 
1270  // linear keyword ...
1271  double module_step_trs=0., module_step_axl=0.;
1272 
1273  kword = "/gate/"+module_name+"/linear/setRepeatVector";
1274  values = CheckGATECommand(kword, line);
1275  if (values.size()>0)
1276  {
1277  string trs_step = is_rsector_Y_axis ?
1278  values[0] :
1279  values[1] ;
1280 
1281  if(ConvertFromString(trs_step, &module_step_trs) ||
1282  ConvertFromString(values[2], &module_step_axl))
1283  {
1284  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1285  return 1;
1286  }
1287 
1288  // Set linear number depending on step position
1289  if(module_step_trs > 0) // linear repeater for trs
1290  nModulesTransaxial = mod_linear_nb;
1291  else if (module_step_axl > 0) // linear repeater for axl
1292  nModulesAxial = mod_linear_nb;
1293  else // something wrong
1294  {
1295  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with module linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1296  return 1;
1297  }
1298  }
1299 
1300  // or cubicArray keyword ...
1301  if(mod_linear_nb>0)
1302  {
1303  kword = "/gate/"+module_name+"/cubicArray/setRepeatVector";
1304  values = CheckGATECommand(kword, line);
1305  if (values.size()>0)
1306  {
1307  string trs_step = is_rsector_Y_axis ?
1308  values[0] :
1309  values[1] ;
1310 
1311  if(ConvertFromString(trs_step, &module_step_trs) ||
1312  ConvertFromString(values[2], &module_step_axl))
1313  {
1314  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1315  return 1;
1316  }
1317 
1318  // Set linear number depending on step position
1319  if(module_step_trs > 0) // linear repeater for trs
1320  nModulesTransaxial = mod_linear_nb;
1321  else if (module_step_axl > 0) // linear repeater for axl
1322  nModulesAxial = mod_linear_nb;
1323  else // something wrong
1324  {
1325  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with module linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1326  return 1;
1327  }
1328  }
1329  }
1330 
1331 
1332 
1333 
1334 
1335  // SUBMODULES
1336 
1337  kword = is_rsector_Y_axis ?
1338  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberX":
1339  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberY";
1340 
1341  values = CheckGATECommand(kword, line);
1342  if (values.size()>0)
1343  {
1344  if(ConvertFromString( values[0] , &nSubmodulesTransaxial) )
1345  {
1346  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1347  return 1;
1348  }
1349  }
1350 
1351  kword = "/gate/"+submodule_name+"/cubicArray/setRepeatNumberZ";
1352  values = CheckGATECommand(kword, line);
1353  if (values.size()>0)
1354  {
1355  if(ConvertFromString( values[0] , &nSubmodulesAxial) )
1356  {
1357  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1358  return 1;
1359  }
1360  }
1361 
1362  // linear repeaters instead of box
1363  kword = "/gate/"+submodule_name+"/linear/setRepeatNumber";
1364  values = CheckGATECommand(kword, line);
1365  if (values.size()>0)
1366  {
1367  //if(ConvertFromString( values[0] , &nSubmodulesAxial) )
1368  if(ConvertFromString( values[0] , &subm_linear_nb) )
1369  {
1370  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1371  return 1;
1372  }
1373  }
1374 
1375  // linear repeaters instead of box, but with cubicArray
1376  kword = "/gate/"+submodule_name+"/cubicArray/setRepeatNumber ";
1377  values = CheckGATECommand(kword, line);
1378  if (values.size()>0)
1379  {
1380  //if(ConvertFromString( values[0] , &nSubmodulesAxial) )
1381  if(ConvertFromString( values[0] , &subm_linear_nb) )
1382  {
1383  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1384  return 1;
1385  }
1386  }
1387 
1388  // linear keyword ...
1389  double submodule_step_trs=0., submodule_step_axl=0.;
1390 
1391  kword = "/gate/"+submodule_name+"/linear/setRepeatVector";
1392  values = CheckGATECommand(kword, line);
1393  if (values.size()>0)
1394  {
1395  string trs_step = is_rsector_Y_axis ?
1396  values[0] :
1397  values[1] ;
1398 
1399  if(ConvertFromString(trs_step, &submodule_step_trs) ||
1400  ConvertFromString(values[2], &submodule_step_axl))
1401  {
1402  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1403  return 1;
1404  }
1405 
1406  // Set linear number depending on step position
1407  if(submodule_step_trs > 0) // linear repeater for trs
1408  nSubmodulesTransaxial = subm_linear_nb;
1409  else if (submodule_step_axl > 0) // linear repeater for axl
1410  nSubmodulesAxial = subm_linear_nb;
1411  else // something wrong
1412  {
1413  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with submodule linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1414  return 1;
1415  }
1416  }
1417 
1418  // ... or cubicArray keyword ...
1419  if(subm_linear_nb>0)
1420  {
1421  kword = "/gate/"+submodule_name+"/cubicArray/setRepeatVector";
1422  values = CheckGATECommand(kword, line);
1423  if (values.size()>0)
1424  {
1425  string trs_step = is_rsector_Y_axis ?
1426  values[0] :
1427  values[1] ;
1428 
1429  if(ConvertFromString(trs_step, &submodule_step_trs) ||
1430  ConvertFromString(values[2], &submodule_step_axl))
1431  {
1432  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1433  return 1;
1434  }
1435 
1436  // Set linear number depending on step position
1437  if(submodule_step_trs > 0) // linear repeater for trs
1438  nSubmodulesTransaxial = subm_linear_nb;
1439  else if (submodule_step_axl > 0) // linear repeater for axl
1440  nSubmodulesAxial = subm_linear_nb;
1441  else // something wrong
1442  {
1443  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with submodule linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1444  return 1;
1445  }
1446  }
1447  }
1448 
1449 
1450  // CRYSTALS
1451 
1452  kword = is_rsector_Y_axis ?
1453  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
1454  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
1455 
1456  values = CheckGATECommand(kword, line);
1457  if (values.size()>0)
1458  {
1459  if(ConvertFromString( values[0] , &nCrystalsTransaxial) )
1460  {
1461  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1462  return 1;
1463  }
1464  }
1465 
1466  kword = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
1467  values = CheckGATECommand(kword, line);
1468  if (values.size()>0)
1469  {
1470  if(ConvertFromString( values[0] , &nCrystalsAxial) )
1471  {
1472  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1473  return 1;
1474  }
1475  }
1476 
1477 
1478  // linear repeaters instead of box
1479  kword = "/gate/"+crystal_name+"/linear/setRepeatNumber";
1480  values = CheckGATECommand(kword, line);
1481  if (values.size()>0)
1482  {
1483  //if(ConvertFromString( values[0] , &nCrystalsAxial) )
1484  if(ConvertFromString( values[0] , &cry_linear_nb) )
1485  {
1486  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1487  return 1;
1488  }
1489  }
1490 
1491  // linear repeaters instead of box, but with cubicArray
1492  kword = "/gate/"+crystal_name+"/cubicArray/setRepeatNumber ";
1493  values = CheckGATECommand(kword, line);
1494  if (values.size()>0)
1495  {
1496  //if(ConvertFromString( values[0] , &nCrystalsAxial) )
1497  if(ConvertFromString( values[0] , &cry_linear_nb) )
1498  {
1499  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1500  return 1;
1501  }
1502  }
1503 
1504  // look for repeater to identify positionning (transaxial or axial)
1505  // linear keyword ...
1506  double crystal_step_trs=0., crystal_step_axl=0.;
1507 
1508  kword = "/gate/"+crystal_name+"/linear/setRepeatVector";
1509  values = CheckGATECommand(kword, line);
1510  if (values.size()>0)
1511  {
1512  string trs_step = is_rsector_Y_axis ?
1513  values[0] :
1514  values[1] ;
1515 
1516  if(ConvertFromString(trs_step, &crystal_step_trs) ||
1517  ConvertFromString(values[2], &crystal_step_axl))
1518  {
1519  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1520  return 1;
1521  }
1522 
1523  // Set linear number depending on step position
1524  if(crystal_step_trs > 0) // linear repeater for trs
1525  nCrystalsTransaxial = cry_linear_nb;
1526  else if (crystal_step_axl > 0) // linear repeater for axl
1527  nCrystalsAxial = cry_linear_nb;
1528  else // something wrong
1529  {
1530  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with crystal linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1531  return 1;
1532  }
1533  }
1534 
1535  // or cubicArray keyword ...
1536  if(cry_linear_nb>0)
1537  {
1538  kword = "/gate/"+crystal_name+"/cubicArray/setRepeatVector";
1539  values = CheckGATECommand(kword, line);
1540  if (values.size()>0)
1541  {
1542  string trs_step = is_rsector_Y_axis ?
1543  values[0] :
1544  values[1] ;
1545 
1546  if(ConvertFromString(trs_step, &crystal_step_trs) ||
1547  ConvertFromString(values[2], &crystal_step_axl))
1548  {
1549  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1550  return 1;
1551  }
1552 
1553  // Set linear number depending on step position
1554  if(crystal_step_trs > 0) // linear repeater for trs
1555  nCrystalsTransaxial = cry_linear_nb;
1556  else if (crystal_step_axl > 0) // linear repeater for axl
1557  nCrystalsAxial = cry_linear_nb;
1558  else // something wrong
1559  {
1560  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with crystal linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1561  return 1;
1562  }
1563  }
1564  }
1565 
1566  // LAYERS
1567 
1568  // Check if there are any repeaters on crystal layers
1569  for(int l=0 ; l<nLayers ; l++)
1570  {
1571  // In case of layers defined using repeaters, the loop is not required.
1572  // The flag is expected to be set to true only in a special case of this loop
1573  if(lyr_rpt_flag)
1574  break;
1575 
1576  kword = is_rsector_Y_axis ?
1577  "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberX":
1578  "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberY";
1579 
1580  values = CheckGATECommand(kword, line);
1581  if (values.size()>0)
1582  {
1583  int32_t val;
1584  if(ConvertFromString( values[0] , &val) )
1585  {
1586  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1587  return 1;
1588  }
1589  nLayersRptTransaxial.push_back(val);
1590  }
1591 
1592 
1593  // Specific case if layers are defined using a (cubic array) repeater
1594  // The recovered value would be >1
1595  kword = is_rsector_Y_axis ?
1596  "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberY":
1597  "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberX";
1598 
1599  values = CheckGATECommand(kword, line);
1600  if (values.size()>0)
1601  {
1602  uint32_t val;
1603  if(ConvertFromString(values[0], &val))
1604  {
1605  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1606  return 1;
1607  }
1608 
1609  nLayersRptDepth.push_back(val);
1610  }
1611 
1612 
1613  kword = "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumberZ";
1614  values = CheckGATECommand(kword, line);
1615  if (values.size()>0)
1616  {
1617  int32_t val;
1618  if(ConvertFromString( values[0] , &val) )
1619  {
1620  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1621  return 1;
1622  }
1623  nLayersRptAxial.push_back(val);
1624  }
1625 
1626  // linear repeaters instead of box
1627  kword = "/gate/"+layers_name[l]+"/linear/setRepeatNumber";
1628  values = CheckGATECommand(kword, line);
1629  if (values.size()>0)
1630  {
1631  int32_t val;
1632  if(ConvertFromString( values[0] , &val) )
1633  {
1634  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1635  return 1;
1636  }
1637  lay_linear_nb.push_back(val);
1638  }
1639 
1640  // linear repeaters instead of box, but with cubicArray
1641  kword = "/gate/"+layers_name[l]+"/cubicArray/setRepeatNumber ";
1642  values = CheckGATECommand(kword, line);
1643  if (values.size()>0)
1644  {
1645  int32_t val;
1646  if(ConvertFromString( values[0] , &val) )
1647  {
1648  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1649  return 1;
1650  }
1651  lay_linear_nb.push_back(val);
1652  }
1653 
1654  // look for repeater to identify positionning (transaxial or axial)
1655 
1656  // linear keyword ...
1657  kword = "/gate/"+layers_name[l]+"/linear/setRepeatVector";
1658  values = CheckGATECommand(kword, line);
1659  if (values.size()>0)
1660  {
1661  string trs_step = is_rsector_Y_axis ?
1662  values[0] :
1663  values[1] ;
1664 
1665  string dph_step = is_rsector_Y_axis ?
1666  values[1] :
1667  values[0] ;
1668 
1669  double step_trs=0., step_axl=0., step_dph=0.;
1670  if(ConvertFromString(trs_step, &step_trs) ||
1671  ConvertFromString(values[2], &step_axl) ||
1672  ConvertFromString(dph_step, &step_dph) )
1673  {
1674  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1675  return 1;
1676  }
1677 
1678  if(step_trs > 0) // linear repeater for trs
1679  nLayersRptTransaxial.push_back(lay_linear_nb[l]);
1680  else if (step_axl > 0) // linear repeater for axl
1681  nLayersRptAxial.push_back(lay_linear_nb[l]);
1682  else if (step_dph > 0)
1683  nLayersRptDepth.push_back(lay_linear_nb[l]);
1684  else // something wrong
1685  {
1686  Cerr("***** dataConversionUtilities::readMacCylindrical()-> There seems to be a problem with layer linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1687  return 1;
1688  }
1689 
1690  }
1691 
1692  // ... or cubicArray keyword ...
1693  if((int)lay_linear_nb.size()>l && lay_linear_nb[ l ]>0)
1694  {
1695  kword= "/gate/"+layers_name[l]+"/cubicArray/setRepeatVector";
1696  values = CheckGATECommand(kword, line);
1697  if (values.size()>0)
1698  {
1699  string trs_step = is_rsector_Y_axis ?
1700  values[0] :
1701  values[1] ;
1702 
1703  string dph_step = is_rsector_Y_axis ?
1704  values[1] :
1705  values[0] ;
1706 
1707  double step_trs=0., step_axl=0., step_dph=0.;
1708  if(ConvertFromString(trs_step, &step_trs) ||
1709  ConvertFromString(values[2], &step_axl) ||
1710  ConvertFromString(dph_step, &step_dph) )
1711  {
1712  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
1713  return 1;
1714  }
1715 
1716  if(step_trs > 0) // linear repeater for trs
1717  nLayersRptTransaxial.push_back(lay_linear_nb[l]);
1718  else if (step_axl > 0) // linear repeater for axl
1719  nLayersRptAxial.push_back(lay_linear_nb[l]);
1720  else if (step_dph > 0)
1721  nLayersRptDepth.push_back(lay_linear_nb[l]);
1722  else // something wrong
1723  {
1724  Cerr("***** dataConversionUtilities::readMacCylindrical()-> There seems to be a problem with layer linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
1725  return 1;
1726  }
1727  }
1728  }
1729 
1730  // layers are declared using depth repeater variables
1731  // Set up the flag accordingly to get out of the layer loop
1732  if (nLayersRptDepth.size() > 0)
1733  lyr_rpt_flag = true;
1734 
1735  } // end of loop on layers
1736 
1737 
1738  kword = "/gate/application/setTimeStart";
1739  values = CheckGATECommand(kword, line);
1740  if (values.size()>0)
1741  {
1742  if(ConvertFromString( values[0] , &time_start) )
1743  {
1744  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1745  return 1;
1746  }
1747 
1748  // Convert in ms
1749  if (values.size()>1)
1750  {
1751  if(values[1] == "s") time_start *= 1000;
1752  }
1753  else
1754  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1755 
1756  start_time_ms = time_start;
1757  }
1758 
1759  kword = "/gate/application/setTimeStop";
1760  values = CheckGATECommand(kword, line);
1761  if (values.size()>0)
1762  {
1763  if(ConvertFromString( values[0] , &time_stop) )
1764  {
1765  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1766  return 1;
1767  }
1768 
1769  // Convert in ms
1770  if (values.size()>1)
1771  {
1772  if(values[1] == "s") time_stop *= 1000;
1773  }
1774  else
1775  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1776  }
1777 
1778  kword = "/gate/application/addSlice";
1779  values = CheckGATECommand(kword, line);
1780  if (values.size()>0)
1781  {
1782  double time_slice_tmp=0;
1783 
1784  if(ConvertFromString( values[0] , &time_slice_tmp) )
1785  {
1786  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1787  return 1;
1788  }
1789 
1790  // Convert in ms
1791  if (values.size()>1)
1792  {
1793  if(values[1] == "s") time_slice_tmp *= 1000;
1794  }
1795  else
1796  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
1797 
1798  time_slices += time_slice_tmp;
1799  }
1800 
1801  kword = "/gate/digitizer/Coincidences/setWindow";
1802  values = CheckGATECommand(kword, line);
1803  if (values.size()>0)
1804  {
1805  if(ConvertFromString( values[0] , &pet_coinc_window) )
1806  {
1807  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
1808  return 1;
1809  }
1810 
1811  // Convert to ns
1812  if (values.size()>1)
1813  {
1814  if(values[1] == "ns") pet_coinc_window *= 1000.;
1815  else if (values[1] == "us") pet_coinc_window *= 1000000.;
1816  else if (values[1] == "ps") ;
1817  else
1818  {
1819  Cerr("***** dataConversionUtilities::readMacCylindrical()-> ERROR : can't read unit of '"<< kword << ". Must be ns, ps or us !!!");
1820  return 1;
1821  }
1822 
1823  }
1824  else
1825  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in ns");
1826 
1827  }
1828 
1829  }
1830 
1831  // Compute duration in ms
1832  duration_ms = (time_slices>0) ?
1833  (uint32_t)(time_slices-time_start) :
1834  duration_ms;
1835 
1836  duration_ms = (time_start>=0 && time_stop>=0) ?
1837  (uint32_t)(time_stop-time_start) :
1838  duration_ms ;
1839 
1840  mac_file.close();
1841  }
1842 
1843  // Processing layers declated in repeaters
1844  if (nLayersRptDepth.size() > 0)
1845  {
1846  // First check there is a conflict with the different ways of declaring layers
1847  if (nLayers>1)
1848  // problem
1849  {
1850  Cerr("***** dataConversionUtilities::readMacCylindrical()-> Conflicting declaration of layers using both crystal/daughter command and a depth level with a linear or cubic array repeater. Only one approach can be managed"<< endl);
1851  return 1;
1852  }
1853  else
1854  {
1855  nLayers = nLayersRptDepth[ 0 ];
1856  // Layers defined by cubic arrays:
1857  // Propagate all geometric infos from the 1st layer to the other layers
1858  for (size_t l=1 ; l<nLayersRptDepth[ 0 ] ; l++)
1859  {
1860  if( nLayersRptTransaxial.size() > 0 ) nLayersRptTransaxial.push_back( nLayersRptTransaxial[ 0 ] );
1861  if( nLayersRptAxial.size() > 0 ) nLayersRptAxial.push_back( nLayersRptAxial[ 0 ] );
1862  }
1863  }
1864  }
1865 
1866 
1867  // Computing the total number of crystals in the scanner
1868  if(nLayers == 0)
1869  {
1870  nCrystalsTot = nRsectorsAngPos * nRsectorsAxial
1871  * nModulesTransaxial * nModulesAxial
1872  * nSubmodulesTransaxial * nSubmodulesAxial
1873  * nCrystalsTransaxial * nCrystalsAxial;
1874  }
1875  else
1876  for(int l=0 ; l<nLayers ; l++)
1877  {
1878  uint32_t nb_crystals_layer = nRsectorsAngPos * nRsectorsAxial
1879  * nModulesTransaxial * nModulesAxial
1880  * nSubmodulesTransaxial * nSubmodulesAxial
1881  * nCrystalsTransaxial * nCrystalsAxial;
1882 
1883  // Add layer elements if repeaters have been used on layers
1884  if(nLayersRptTransaxial.size()>0 || nLayersRptAxial.size()>0 )
1885  nb_crystals_layer *= nLayersRptTransaxial[l] * nLayersRptAxial[l];
1886 
1887  nb_crystal_per_layer[l] = nb_crystals_layer;
1888 
1889  nCrystalsTot += nb_crystals_layer;
1890  }
1891 
1892 
1893  if(vb >= 2)
1894  {
1895  Cout(endl);
1896  Cout("-----------------------------------------------------------" << endl);
1897  Cout("ReadMacCylindrical()-> Information recovered from mac file:" << endl);
1898  Cout("-----------------------------------------------------------" << endl);
1899  Cout("Number of rsectors angular position: " << nRsectorsAngPos << endl);
1900  Cout("Number of axial rsectors: " << nRsectorsAxial << endl);
1901  Cout("Number of axial modules: " << nModulesAxial << endl);
1902  Cout("Number of transaxial modules: " << nModulesTransaxial << endl);
1903  Cout("Number of axial submodules: " << nSubmodulesAxial << endl);
1904  Cout("Number of transaxial submodules: " << nSubmodulesTransaxial << endl);
1905  Cout("Number of axial crystals: " << nCrystalsAxial << endl);
1906  Cout("Number of transaxial crystals: " << nCrystalsTransaxial << endl);
1907  if (nLayers>=1)
1908  {
1909  Cout("Number of layers: " << (uint16_t)nLayers << endl); // cast to uint16_t for output purposes
1910  for(int l=0 ; l<nLayers ; l++)
1911  Cout("Layer "<< l <<" : Number of crystals: " << nb_crystal_per_layer[l] << endl);
1912  }
1913  Cout("Total number of crystals (including layers): " << nCrystalsTot << endl);
1914  Cout("Acquisition start time (ms): " << start_time_ms << endl);
1915  Cout("Acquisition duration (ms): " << duration_ms << endl);
1916  Cout("-----------------------------------------------------------" << endl << endl);
1917  }
1918 
1919  return 0;
1920 }
1921 
1922 
1923 
1924 // =====================================================================
1925 // ---------------------------------------------------------------------
1926 // ---------------------------------------------------------------------
1927 // =====================================================================
1928 /*
1929  \fn ReadMacECAT
1930  \param a_pathMac : path to a macro file
1931  \param nCrystalsAxial : nb of axial crystals
1932  \param nCrystalsTransaxial : nb of transaxial crystals
1933  \param nBlocksLine : nb of axial blocks
1934  \param nBlocksPerRing : nb of blocks per ring
1935  \param start_time_ms : acquisition start time converted in ms
1936  \param duration_ms : acquisition duration converted in ms
1937  \param pet_coinc_window : coincidence window (required for TOF parameters)
1938  \param vb : verbosity
1939  \brief Recover informations about the scanner element of an ECAT system, and acquisition duration, from a GATE macro file
1940  \return 0 if success, positive value otherwise
1941 */
1942 int ReadMacECAT( string a_pathMac,
1943  uint32_t &nCrystalsTot,
1944  uint32_t &nCrystalsAxial,
1945  uint32_t &nCrystalsTransaxial,
1946  uint32_t &nBlocksLine,
1947  uint32_t &nBlocksPerRing,
1948  uint32_t &start_time_ms,
1949  uint32_t &duration_ms,
1950  FLTNB &pet_coinc_window,
1951  int vb)
1952 {
1953  // Recover path to all macro files from the main mac file
1954  vector<string> path_mac_files;
1955  path_mac_files.push_back(a_pathMac);
1956  if(GetGATEMacFiles(a_pathMac , path_mac_files))
1957  {
1958  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover paths to GATE macro files !" << endl);
1959  return 1;
1960  }
1961 
1962  string block_name = "block";
1963  string crystal_name = "crystal";
1964  bool is_block_Y_axis = false;
1965 
1966  // Recover aliases of the different parts of the architecture
1967  if(GetGATEAliasesEcat(path_mac_files, block_name, crystal_name, vb) )
1968  {
1969  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover aliases for the elements of the ecat !" << endl);
1970  return 1;
1971  }
1972 
1973 
1974  // 2nd loop to recover all other informations
1975  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
1976  {
1977  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
1978 
1979  string line;
1980  double time_start=-1.,
1981  time_stop=-1.,
1982  time_slices=-1.;
1983 
1984  while(getline(mac_file, line))
1985  {
1986  vector <string> values;
1987  string kword ="";
1988 
1989  kword = "/gate/"+block_name+"/placement/setTranslation";
1990  values = CheckGATECommand(kword, line);
1991  if (values.size()>0)
1992  {
1993  FLTNB block_pos_X=0.,
1994  block_pos_Y=0.;
1995 
1996  if(ConvertFromString(values[0], &block_pos_X) ||
1997  ConvertFromString(values[1], &block_pos_Y) )
1998  {
1999  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2000  return 1;
2001  }
2002 
2003  // Get the axis on which the first rsector is positionned
2004  if(block_pos_Y!=0) is_block_Y_axis = true;
2005  }
2006 
2007  kword = "/gate/"+block_name+"/ring/setRepeatNumber";
2008  values = CheckGATECommand(kword, line);
2009  if (values.size()>0)
2010  {
2011  if(ConvertFromString( values[0] , &nBlocksPerRing) )
2012  {
2013  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2014  return 1;
2015  }
2016  }
2017 
2018  kword = "/gate/"+block_name+"/linear/setRepeatNumber";
2019  values = CheckGATECommand(kword, line);
2020  if (values.size()>0)
2021  {
2022  if(ConvertFromString( values[0] , &nBlocksLine) )
2023  {
2024  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2025  return 1;
2026  }
2027  }
2028 
2029  kword = is_block_Y_axis ?
2030  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
2031  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
2032 
2033  values = CheckGATECommand(kword, line);
2034  if (values.size()>0)
2035  {
2036  if(ConvertFromString( values[0] , &nCrystalsTransaxial) )
2037  {
2038  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2039  return 1;
2040  }
2041  }
2042 
2043  kword = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
2044  values = CheckGATECommand(kword, line);
2045  if (values.size()>0)
2046  {
2047  if(ConvertFromString( values[0] , &nCrystalsAxial) )
2048  {
2049  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2050  return 1;
2051  }
2052  }
2053 
2054 
2055  kword = "/gate/application/setTimeStart";
2056  values = CheckGATECommand(kword, line);
2057  if (values.size()>0)
2058  {
2059  if(ConvertFromString( values[0] , &time_start) )
2060  {
2061  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2062  return 1;
2063  }
2064 
2065  // Convert in ms
2066  if (values.size()>1)
2067  {
2068  if(values[1] == "s") time_start *= 1000;
2069  }
2070  else
2071  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
2072 
2073  start_time_ms = time_start;
2074  }
2075 
2076  kword = "/gate/application/setTimeStop";
2077  values = CheckGATECommand(kword, line);
2078  if (values.size()>0)
2079  {
2080  if(ConvertFromString( values[0] , &time_stop) )
2081  {
2082  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2083  return 1;
2084  }
2085 
2086  // Convert in ms
2087  if (values.size()>1)
2088  {
2089  if(values[1] == "s") time_stop *= 1000;
2090  }
2091  else
2092  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
2093  }
2094 
2095  kword = "/gate/application/addSlice";
2096  values = CheckGATECommand(kword, line);
2097  if (values.size()>0)
2098  {
2099  double time_slice_tmp=0;
2100 
2101  if(ConvertFromString( values[0] , &time_slice_tmp) )
2102  {
2103  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2104  return 1;
2105  }
2106 
2107  // Convert in ms
2108  if (values.size()>1)
2109  {
2110  if(values[1] == "s") time_slice_tmp *= 1000;
2111  }
2112  else
2113  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
2114 
2115  time_slices = time_slice_tmp;
2116  }
2117 
2118  kword = "/gate/digitizer/Coincidences/setWindow";
2119  values = CheckGATECommand(kword, line);
2120  if (values.size()>0)
2121  {
2122  if(ConvertFromString( values[0] , &pet_coinc_window) )
2123  {
2124  Cerr("***** dataConversionUtilities::readMacCylindrical()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2125  return 1;
2126  }
2127 
2128  // Convert to ns
2129  if (values.size()>1)
2130  {
2131  if(values[1] == "ns") pet_coinc_window *= 1000.;
2132  else if (values[1] == "us") pet_coinc_window *= 1000000.;
2133  else if (values[1] == "ps") ;
2134  else
2135  {
2136  Cerr("***** dataConversionUtilities::readMacCylindrical()-> ERROR : can't read unit of '"<< kword << ". Must be ns, ps or us !!!");
2137  return 1;
2138  }
2139 
2140  }
2141  else
2142  Cerr("***** dataConversionUtilities::readMacCylindrical()-> WARNING : can't read unit of '"<< kword << ". Assuming time in ns");
2143 
2144  }
2145  }
2146 
2147  // Compute duration in ms
2148  duration_ms = (time_slices>0) ?
2149  (uint32_t)(time_slices-time_start) :
2150  duration_ms;
2151 
2152  duration_ms = (time_start>=0 && time_stop>=0) ?
2153  (uint32_t)(time_stop-time_start) :
2154  duration_ms ;
2155 
2156  mac_file.close();
2157  }
2158 
2159  // Computing the total number of crystals in the scanner
2160  nCrystalsTot = nCrystalsTransaxial * nCrystalsAxial
2161  * nBlocksLine * nBlocksPerRing;
2162 
2163 
2164  if(vb >= 2)
2165  {
2166  Cout(endl);
2167  Cout("-----------------------------------------------------" << endl);
2168  Cout("ReadMacECAT()-> Information recovered from mac file:" << endl);
2169  Cout("-----------------------------------------------------" << endl);
2170  Cout("Number of blocks per ring: " << nBlocksPerRing << endl);
2171  Cout("Number of axial blocks: " << nBlocksLine << endl);
2172  Cout("Number of axial crystals: " << nCrystalsAxial << endl);
2173  Cout("Number of transaxial crystals: " << nCrystalsTransaxial << endl);
2174  Cout("Total number of crystals: " << nCrystalsTot << endl);
2175  Cout("Acquisition start time (ms): " << start_time_ms << endl);
2176  Cout("Acquisition duration (ms): " << duration_ms << endl);
2177  Cout("-----------------------------------------------------" << endl << endl);
2178  }
2179 
2180  return 0;
2181 }
2182 
2183 
2184 
2185 // =====================================================================
2186 // ---------------------------------------------------------------------
2187 // ---------------------------------------------------------------------
2188 // =====================================================================
2189 /*
2190  \fn ReadMacSPECT
2191  \param a_pathMac : path to a macro file
2192  \param distToDetector : distance between center of rotation and detector surface
2193  \param nHeads : nb of cameras
2194  \param nPixAxl : nb of transaxial pixels
2195  \param nPixTrs : nb of axial pixels
2196  \param crystalSizeAxl : crystal axial dimension
2197  \param crystalSizeTrs : crystal transaxial dimension
2198  \param head1stAngle : head first angle
2199  \param headAngPitch : angular pitch between heads
2200  \param headRotSpeed : angle between projection
2201  \param headRotDirection : rotation direction of the head (CW or CCW)
2202  \param start_time_ms : acquisition start time converted in ms
2203  \param duration_ms : acquisition duration converted in ms
2204  \param vb : verbosity
2205  \brief Recover informations about the scanner element of an ECAT system, and acquisition duration, from a GATE macro file
2206  \return 0 if success, positive value otherwise
2207 */
2208 int ReadMacSPECT( string a_pathMac,
2209  float_t &a_distToDetector,
2210  uint32_t &a_nHeads,
2211  uint32_t &a_nPixAxl,
2212  uint32_t &a_nPixTrs,
2213  float_t &a_crystalSizeAxl,
2214  float_t &a_crystalSizeTrs,
2215  uint32_t &a_nProjectionsTot,
2216  uint32_t &a_nProjectionsByHead,
2217  float_t &a_head1stAngle,
2218  float_t &a_headAngPitch,
2219  float_t &a_headAngStepDeg,
2220  int &a_headRotDirection,
2221  uint32_t &a_start_time_ms,
2222  uint32_t &a_duration_ms,
2223  int vb)
2224 {
2225  // Recover path to all macro files from the main mac file
2226  vector<string> path_mac_files;
2227  path_mac_files.push_back(a_pathMac);
2228 
2229  if(GetGATEMacFiles(a_pathMac , path_mac_files))
2230  {
2231  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover paths to GATE macro files !" << endl);
2232  return 1;
2233  }
2234 
2235  string head_name = "SPECThead";
2236  string crystal_name = "crystal";
2237  string pixel_name = "pixel";
2238  string head_orbit_name = "";
2239  bool is_head_Y_axis = false;
2240 
2241  // Recover aliases of the different parts of the architecture
2242  if(GetGATEAliasesSPECT(path_mac_files, head_name, crystal_name, pixel_name, vb) )
2243  {
2244  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover aliases for the elements of the ecat !" << endl);
2245  return 1;
2246  }
2247 
2248  // Init variables to recover some data
2249  double time_start=-1.,
2250  time_stop=-1.,
2251  time_slice=-1,
2252  time_slices=-1.,
2253  time_slice_ms=-1.,
2254  head_rot_speed =-1.;
2255 
2256  // 2nd loop to recover all other informations
2257  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
2258  {
2259  ifstream mac_file(path_mac_files[f].c_str(), ios::in);
2260 
2261  string line;
2262 
2263  while(getline(mac_file, line))
2264  {
2265  vector <string> values;
2266  string kword ="";
2267  kword = "/gate/"+head_name+"/placement/setTranslation";
2268  values = CheckGATECommand(kword, line);
2269  if (values.size()>0)
2270  {
2271  FLTNB head_pos_X=0.,
2272  head_pos_Y=0.;
2273 
2274  if(ConvertFromString(values[0], &head_pos_X) ||
2275  ConvertFromString(values[1], &head_pos_Y) )
2276  {
2277  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2278  return 1;
2279  }
2280 
2281  // Get the axis on which the first rsector is positionned
2282  if(head_pos_Y!=0) is_head_Y_axis = true;
2283 
2284  a_distToDetector = is_head_Y_axis ? abs(head_pos_Y) : abs(head_pos_X) ;
2285  }
2286 
2287 
2288 
2289  kword = "/gate/"+head_name+"/ring/setRepeatNumber";
2290  values = CheckGATECommand(kword, line);
2291  if (values.size()>0)
2292  {
2293  if(ConvertFromString(values[0], &a_nHeads))
2294  {
2295  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2296  return 1;
2297  }
2298  }
2299 
2300  kword = "/gate/"+head_name+"/ring/setFirstAngle";
2301  values = CheckGATECommand(kword, line);
2302  if (values.size()>0)
2303  {
2304  if(ConvertFromString(values[0], &a_head1stAngle))
2305  {
2306  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2307  return 1;
2308  }
2309  }
2310 
2311  kword = "/gate/"+head_name+"/ring/setAngularPitch";
2312  values = CheckGATECommand(kword, line);
2313  if (values.size()>0)
2314  {
2315  if(ConvertFromString(values[0], &a_headAngPitch))
2316  {
2317  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2318  return 1;
2319  }
2320  }
2321 
2322  kword = "/gate/"+head_name+"/moves/insert";
2323  values = CheckGATECommand(kword, line);
2324  if (values.size()>0)
2325  {
2326  if(ConvertFromString(values[0], &head_orbit_name))
2327  {
2328  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2329  return 1;
2330  }
2331  }
2332 
2333  kword = "/gate/"+head_name+"/"+head_orbit_name+"/setSpeed";
2334  values = CheckGATECommand(kword, line);
2335  if (values.size()>0)
2336  {
2337  if(ConvertFromString(values[0], &head_rot_speed))
2338  {
2339  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2340  return 1;
2341  }
2342  }
2343 
2344  kword = "/gate/"+head_name+"/"+head_orbit_name+"/setPoint2";
2345  values = CheckGATECommand(kword, line);
2346  if (values.size()>0)
2347  {
2348  int rot_direction;
2349  if(ConvertFromString(values[2], &rot_direction))
2350  {
2351  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
2352  return 1;
2353  }
2354 
2355  a_headRotDirection = rot_direction>0 ? GEO_ROT_CW : GEO_ROT_CCW;
2356  }
2357 
2358  // --- Crystals ---
2359  kword = is_head_Y_axis ?
2360  "/gate/"+crystal_name+"/geometry/setXLength":
2361  "/gate/"+crystal_name+"/geometry/setYLength";
2362 
2363  values = CheckGATECommand(kword, line);
2364  if (values.size()>0)
2365  {
2366  if(ConvertFromString(values[0], &a_crystalSizeTrs) )
2367  {
2368  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
2369  return 1;
2370  }
2371 
2372  }
2373 
2374  kword = "/gate/"+crystal_name+"/geometry/setZLength";
2375  values = CheckGATECommand(kword, line);
2376  if (values.size()>0)
2377  {
2378  if(ConvertFromString(values[0], &a_crystalSizeAxl) )
2379  {
2380  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
2381  return 1;
2382  }
2383  }
2384 
2385 
2386  // --- Pixels ---
2387  kword = is_head_Y_axis ?
2388  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberX":
2389  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberY";
2390 
2391 
2392  values = CheckGATECommand(kword, line);
2393  if (values.size()>0)
2394  {
2395  if(ConvertFromString(values[0], &a_nPixTrs) )
2396  {
2397  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
2398  return 1;
2399  }
2400  }
2401 
2402  kword = "/gate/"+pixel_name+"/cubicArray/setRepeatNumberZ";
2403  values = CheckGATECommand(kword, line);
2404  if (values.size()>0)
2405  {
2406  if(ConvertFromString(values[0], &a_nPixAxl) )
2407  {
2408  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
2409  return 1;
2410  }
2411  }
2412 
2413  kword = "/gate/application/setTimeStart";
2414  values = CheckGATECommand(kword, line);
2415  if (values.size()>0)
2416  {
2417  if(ConvertFromString( values[0] , &time_start) )
2418  {
2419  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2420  return 1;
2421  }
2422 
2423  // Convert in ms
2424  if (values.size()>1)
2425  {
2426  if(values[1] == "s") time_start *= 1000;
2427  }
2428  else
2429  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
2430 
2431  a_start_time_ms = time_start;
2432  }
2433 
2434  kword = "/gate/application/setTimeSlice";
2435  values = CheckGATECommand(kword, line);
2436  if (values.size()>0)
2437  {
2438  if(ConvertFromString( values[0] , &time_slice) )
2439  {
2440  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2441  return 1;
2442  }
2443 
2444  // Convert in ms
2445  if (values.size()>1)
2446  {
2447  if(values[1] == "s") time_slice *= 1000;
2448  }
2449  else
2450  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
2451 
2452  time_slice_ms = time_slice;
2453  }
2454 
2455  kword = "/gate/application/setTimeStop";
2456  values = CheckGATECommand(kword, line);
2457  if (values.size()>0)
2458  {
2459  if(ConvertFromString( values[0] , &time_stop) )
2460  {
2461  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2462  return 1;
2463  }
2464 
2465  // Convert in ms
2466  if (values.size()>1)
2467  {
2468  if(values[1] == "s") time_stop *= 1000;
2469  }
2470  else
2471  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
2472  }
2473 
2474  kword = "/gate/application/addSlice";
2475  values = CheckGATECommand(kword, line);
2476  if (values.size()>0)
2477  {
2478  double time_slice_tmp=0;
2479 
2480  if(ConvertFromString( values[0] , &time_slice_tmp) )
2481  {
2482  Cerr("***** dataConversionUtilities::readMacECAT()->Error occurred while trying to get value from entry '"<< kword << "' in file " << path_mac_files[f] << "!");
2483  return 1;
2484  }
2485 
2486  // Convert in ms
2487  if (values.size()>1)
2488  {
2489  if(values[1] == "s") time_slice_tmp *= 1000;
2490  }
2491  else
2492  Cerr("***** dataConversionUtilities::readMacECAT()-> WARNING : can't read unit of '"<< kword << ". Assuming time in seconds");
2493 
2494  time_slices = time_slice_tmp;
2495  }
2496  }
2497 
2498  // Compute duration in ms
2499 
2500  // Time slices were provided
2501  a_duration_ms = (time_slices>0) ?
2502  (uint32_t)(time_slices-time_start) :
2503  a_duration_ms;
2504 
2505  // Time stop/start is provided
2506  a_duration_ms = (time_start>=0 && time_stop>=0) ?
2507  (uint32_t)(time_stop-time_start) :
2508  a_duration_ms;
2509 
2510 
2511  // Compute the nb of projections and total number of crystals in the system
2512  a_nProjectionsByHead = a_duration_ms / time_slice_ms;
2513  a_nProjectionsTot = a_nHeads*a_nProjectionsByHead;
2514 
2515  // Compute angular pitch if not provided in the mac files (=-1)
2516  a_headAngPitch = (a_headAngPitch<0) ?
2517  360./a_nHeads :
2518  a_headAngPitch ;
2519 
2520  a_headAngStepDeg = head_rot_speed*time_slice_ms/1000.;
2521 
2522  if(head_rot_speed<0)
2523  {
2524  Cerr("***** GetGATESystemType() -> Error couldn't find line '/gate/"+head_name+"/"+head_orbit_name+"/setSpeed' !" << endl);
2525  Cerr(" This information is mandatory to compute the projection angle step." << endl);
2526  return 1;
2527  }
2528 
2529  if(time_slice_ms<0)
2530  {
2531  Cerr("***** GetGATESystemType() -> Error couldn't find line '/gate/application/setTimeSlice' !" << endl);
2532  Cerr(" This information is mandatory to compute the projection angle step." << endl);
2533  return 1;
2534  }
2535 
2536  if(a_duration_ms == 0)
2537  {
2538  if(time_stop <0)
2539  {
2540  Cerr("***** GetGATESystemType() -> Error couldn't compute acquisition find line '/gate/application/setTimeStop' !" << endl);
2541  Cerr(" This information is mandatory to compute the acquisition duration." << endl);
2542  return 1;
2543  }
2544  if(time_start <0)
2545  {
2546  Cerr("***** GetGATESystemType() -> Error couldn't compute acquisition find line '/gate/application/setTimeStart' !" << endl);
2547  Cerr(" This information is mandatory to compute the acquisition duration." << endl);
2548  return 1;
2549  }
2550  }
2551 
2552  mac_file.close();
2553  } // end loop on .mac files
2554 
2555  if(vb >= 2)
2556  {
2557  Cout(endl);
2558  Cout("-----------------------------------------------------" << endl);
2559  Cout("ReadMacSPECT()-> Information recovered from mac file:" << endl);
2560  Cout("-----------------------------------------------------" << endl);
2561  Cout("Distance to detector: " << a_distToDetector << endl);
2562  Cout("Number of heads: " << a_nHeads << endl);
2563  Cout("Number of axial pixels: " << a_nPixAxl << endl);
2564  Cout("Number of transaxial pixels: " << a_nPixTrs << endl);
2565  Cout("Crystal axial size: " << a_crystalSizeAxl << endl);
2566  Cout("Crystal transaxial size: " << a_crystalSizeTrs << endl);
2567  Cout("Number of projections per head: " << a_nProjectionsByHead << endl);
2568  Cout("Total number of projections: " << a_nProjectionsTot << endl);
2569  Cout("Head(s) first transaxial angle: " << a_head1stAngle << endl);
2570  Cout("Head(s) angular pitch: " << a_headAngPitch << endl);
2571  Cout("Angular step between projections (deg): " << a_headAngStepDeg << endl);
2572  Cout("Rotation direction (0=CW, 1=CCW): " << a_headRotDirection << endl);
2573  Cout("Acquisition start time (ms): " << a_start_time_ms << endl);
2574  Cout("Acquisition duration (ms): " << a_duration_ms << endl);
2575  Cout("-----------------------------------------------------" << endl << endl);
2576  }
2577 
2578  return 0;
2579 }
2580 
2581 
2582 
2583 
2584 // =====================================================================
2585 // ---------------------------------------------------------------------
2586 // ---------------------------------------------------------------------
2587 // =====================================================================
2588 /*
2589  \fn ReadIntfSPECT
2590  \param a_pathIntf : path to the interfile header
2591  \param distToDetector : distance between center of rotation and detector surface
2592  \param nHeads : nb of cameras
2593  \param nPixAxl : nb of transaxial pixels
2594  \param nPixTrs : nb of axial pixels
2595  \param crystalSizeAxl : crystal axial dimension
2596  \param crystalSizeTrs : crystal transaxial dimension
2597  \param head1stAngle : head first angle
2598  \param headAngPitch : angular pitch between heads
2599  \param headRotSpeed : angle between projection
2600  \param headRotDirection : rotation direction of the head (CW or CCW)
2601  \param start_time_ms : acquisition start time converted in ms
2602  \param duration_ms : acquisition duration converted in ms
2603  \param vb : verbosity
2604  \brief Recover informations about the scanner element of an ECAT system, and acquisition duration, from a GATE macro file
2605  \return 0 if success, positive value otherwise
2606 */
2607 int ReadIntfSPECT(string a_pathIntf,
2608  float_t &a_distToDetector,
2609  uint32_t &a_nHeads,
2610  uint32_t &a_nPixAxl,
2611  uint32_t &a_nPixTrs,
2612  float_t &a_crystalSizeAxl,
2613  float_t &a_crystalSizeTrs,
2614  uint32_t &a_nProjectionsTot,
2615  uint32_t &a_nProjectionsByHead,
2616  float_t &a_head1stAngle,
2617  float_t &a_headAngPitchDeg,
2618  float_t &a_headAngStepDeg,
2619  int &a_headRotDirection,
2620  uint32_t &a_start_time_ms,
2621  uint32_t &a_duration_ms,
2622  int vb)
2623 {
2624  // Read all required information in Interfile header
2625 
2626  string key;
2627 
2628  key = "matrix size [1]";
2629  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nPixTrs, 1, KEYWORD_MANDATORY))
2630  {
2631  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2632  Cerr(" Either key not found or conversion error" << endl);
2633  return 1;
2634  }
2635 
2636  key = "matrix size [2]";
2637  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nPixAxl, 1, KEYWORD_MANDATORY))
2638  {
2639  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2640  Cerr(" Either key not found or conversion error" << endl);
2641  return 1;
2642  }
2643 
2644  FLTNB size_pix_trs = 1.,
2645  size_pix_axl = 1.;
2646 
2647  key = "scaling factor (mm/pixel) [1]";
2648  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_pix_trs, 1, KEYWORD_MANDATORY))
2649  {
2650  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2651  Cerr(" Either key not found or conversion error" << endl);
2652  return 1;
2653  }
2654 
2655  key = "scaling factor (mm/pixel) [2]";
2656  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_pix_axl, 1, KEYWORD_MANDATORY))
2657  {
2658  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2659  Cerr(" Either key not found or conversion error" << endl);
2660  return 1;
2661  }
2662 
2663  key = "total number of images";
2664  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nProjectionsTot, 1, KEYWORD_MANDATORY))
2665  {
2666  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2667  Cerr(" Either key not found or conversion error" << endl);
2668  return 1;
2669  }
2670 
2671  key = "number of projections";
2672  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nProjectionsByHead, 1, KEYWORD_MANDATORY))
2673  {
2674  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2675  Cerr(" Either key not found or conversion error" << endl);
2676  return 1;
2677  }
2678 
2679  key = "number of detector heads";
2680  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_nHeads, 1, KEYWORD_MANDATORY))
2681  {
2682  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2683  Cerr(" Either key not found or conversion error" << endl);
2684  return 1;
2685  }
2686 
2687  key = "study duration (sec)";
2688  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_duration_ms, 1, KEYWORD_MANDATORY))
2689  {
2690  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2691  Cerr(" Either key not found or conversion error" << endl);
2692  return 1;
2693  }
2694  // convert duration in ms
2695  a_duration_ms *= 1000;
2696 
2697 
2698  FLTNB size_crystal_X =0.,
2699  size_crystal_Y =0.;
2700 
2701  key = "crystal x dimension (cm)";
2702  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_crystal_X, 1, KEYWORD_OPTIONAL) == 1)
2703  {
2704  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2705  Cerr(" Either key not found or conversion error" << endl);
2706  return 1;
2707  }
2708 
2709  key = "crystal y dimension (cm)";
2710  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &size_crystal_Y, 1, KEYWORD_OPTIONAL) == 1)
2711  {
2712  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2713  Cerr(" Either key not found or conversion error" << endl);
2714  return 1;
2715  }
2716 
2717  key = "crystal z dimension (cm)";
2718  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_crystalSizeAxl, 1, KEYWORD_OPTIONAL) == 1)
2719  {
2720  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2721  Cerr(" Either key not found or conversion error" << endl);
2722  return 1;
2723  }
2724 
2725  // Just pick the larger value to get the transaxial crystal size
2726  // convert in mm (values in cm in Interfile)
2727  if(size_crystal_X>0 && size_crystal_Y>0)
2728  a_crystalSizeTrs = (size_crystal_X>size_crystal_Y) ? size_crystal_X*10. : size_crystal_Y*10.;
2729  a_crystalSizeAxl = (a_crystalSizeAxl>0) ? a_crystalSizeAxl*10. : a_crystalSizeAxl ;
2730 
2731 
2732  FLTNB head_pos_X =-1.,
2733  head_pos_Y =-1.,
2734  head_pos_Z =-1.;
2735 
2736  key = "head x translation (cm)";
2737  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &head_pos_X, 1, KEYWORD_OPTIONAL) == 1)
2738  {
2739  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2740  Cerr(" Either key not found or conversion error" << endl);
2741  return 1;
2742  }
2743 
2744  key = "head y translation (cm)";
2745  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &head_pos_Y, 1, KEYWORD_OPTIONAL) == 1)
2746  {
2747  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2748  Cerr(" Either key not found or conversion error" << endl);
2749  return 1;
2750  }
2751 
2752  key = "head z translation (cm)";
2753  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &head_pos_Z, 1, KEYWORD_OPTIONAL) == 1)
2754  {
2755  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2756  Cerr(" Either key not found or conversion error" << endl);
2757  return 1;
2758  }
2759 
2760  // Pick the largest value to initialize distance betweeen COR and detector, converted in mm (cm by default)
2761  if(head_pos_X > head_pos_Y)
2762  a_distToDetector = head_pos_X > head_pos_Z ? head_pos_X*10 : head_pos_Z*10;
2763  else
2764  a_distToDetector = head_pos_Y > head_pos_Z ? head_pos_Y*10 : head_pos_Z*10;
2765 
2766 
2767  key = "direction of rotation";
2768  string rot_dir;
2769  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &rot_dir, 1, KEYWORD_MANDATORY))
2770  {
2771  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2772  Cerr(" Either key not found or conversion error" << endl);
2773  return 1;
2774  }
2775 
2776  a_headRotDirection = (rot_dir == "CCW") ? GEO_ROT_CCW : GEO_ROT_CW ;
2777 
2778  // Could have several keys with this name (each for each head)
2779  // It will recover the value corresponding to the first match
2780  key = "start angle";
2781  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &a_head1stAngle, 1, KEYWORD_MANDATORY))
2782  {
2783  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2784  Cerr(" Either key not found or conversion error" << endl);
2785  return 1;
2786  }
2787 
2788  key = "extent of rotation";
2789  uint32_t extent_rotation =360;
2790  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &extent_rotation, 1, KEYWORD_MANDATORY))
2791  {
2792  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2793  Cerr(" Either key not found or conversion error" << endl);
2794  return 1;
2795  }
2796 
2797  a_headAngStepDeg = (FLTNB)extent_rotation / a_nProjectionsByHead;
2798 
2799  float_t first_angle = 0;
2800  float_t second_angle = extent_rotation;
2801 
2802  key = "start angle";
2803  if(IntfKeyGetValueFromFile(a_pathIntf.c_str(), key.c_str(), &first_angle, 1, KEYWORD_MANDATORY))
2804  {
2805  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2806  Cerr(" Either key not found or conversion error" << endl);
2807  return 1;
2808  }
2809 
2810  key = "start angle";
2811  if(IntfKeyGetRecurringValueFromFile(a_pathIntf.c_str(), key.c_str(), &second_angle, 1, KEYWORD_MANDATORY, 1))
2812  {
2813  Cerr("***** castor-GATERootToCastor :: Error when trying to read key: '"<< key << "' in interfile : " << a_pathIntf << "!" << endl);
2814  Cerr(" Either key not found or conversion error" << endl);
2815  return 1;
2816  }
2817 
2818  a_headAngPitchDeg = second_angle - first_angle;
2819 
2820  return 0;
2821 }
2822 
2823 
2824 
2825 
2826 // =====================================================================
2827 // ---------------------------------------------------------------------
2828 // ---------------------------------------------------------------------
2829 // =====================================================================
2830 /*
2831  \fn CreateGeomWithCylindrical()
2832  \param a_pathMac : string containing the path to a GATE macro file
2833  \param a_pathGeom : string containing the path to a CASToR output geom file
2834  \brief Read a GATE macro file containing the description of a cylindricalPET system, and convert it to a geom file
2835  \return 0 if success, positive value otherwise
2836 */
2837 int CreateGeomWithCylindrical(string a_pathMac, string a_pathGeom)
2838 {
2839  /* Declaring variables */
2840 
2841  // Scanner
2842  string modality;
2843  string scanner_name = GetFileFromPath(a_pathGeom.substr(0,a_pathGeom.find(".geom")));
2844  double scanner_radius = 0.;
2845  uint32_t number_of_elements = 0;
2846  string description = "PET system extracted from GATE macro: " + a_pathMac;
2847 
2848  // Rsectors
2849  string rsector_name = "";
2850  uint32_t number_of_rsectors_ang = 1; // repeater on a ring
2851  uint32_t number_of_rsectors_axl = 1; // linear repeater
2852  double rsector_step_axl = 0.;
2853  double rsector_gap_axl = 0.;
2854  double rsector_first_angle = 0.;
2855  double rsector_angular_span = 360.;
2856  double rsector_pos_X = 0.;
2857  double rsector_pos_Y = 0.;
2858  uint32_t rsector_nb_zshifts = 0;
2859  vector <double> vec_rsector_Z_Shift;
2860  bool is_rsector_Y_axis = false;
2861  double rsector_size_trs;
2862  double rsector_size_axl;
2863 
2864  // Modules
2865  string module_name = "";
2866  uint32_t number_of_modules_trs = 1;
2867  uint32_t number_of_modules_axl = 1;
2868  double module_step_trs = 0.;
2869  double module_step_axl = 0.;
2870  double module_gap_trs = 0.;
2871  double module_gap_axl = 0.;
2872  double module_size_trs;
2873  double module_size_axl;
2874 
2875  // Submodules
2876  string submodule_name = "";
2877  uint32_t number_of_submodules_trs = 1;
2878  uint32_t number_of_submodules_axl = 1;
2879  double submodule_step_trs = 0.;
2880  double submodule_step_axl = 0.;
2881  double submodule_gap_trs = 0.;
2882  double submodule_gap_axl = 0.;
2883  double submodule_size_trs;
2884  double submodule_size_axl;
2885 
2886  // Crystals
2887  string crystal_name = "";
2888  uint32_t number_of_crystals_trs = 1;
2889  uint32_t number_of_crystals_axl = 1;
2890  double crystal_step_trs = 0.;
2891  double crystal_step_axl = 0.;
2892  double crystal_gap_trs = 0.;
2893  double crystal_gap_axl = 0.;
2894  double crystal_size_depth = 0.;
2895  double crystal_size_trs = 0.;
2896  double crystal_size_axl = 0.;
2897 
2898 
2899  // Layers
2900  uint16_t number_of_layers = 0;
2901  string n_layers = "1"; //default value for number_of_layers
2902  vector <uint32_t> number_of_lyr_elts_trs;
2903  vector <uint32_t> number_of_lyr_elts_axl;
2904  vector <uint32_t> number_of_lyr_elts_dph;
2905 
2906  vector <string> layers_names;
2907  vector <vector <double> > layers_positions;
2908  vector <double> layers_size_depth;
2909  vector <double> layers_size_trs;
2910  vector <double> layers_size_axl;
2911 
2912  vector <double> layers_step_trs;
2913  vector <double> layers_step_axl;
2914  vector <double> layers_step_dph;
2915 
2916  // Optional
2917  uint32_t voxels_number_trs;
2918  uint32_t voxels_number_axl;
2919  double fov_trs,
2920  fov_axl;
2921  double mean_depth_of_interaction = -1.;
2922  double min_angle_diff = 0.;
2923 
2924  // variables for linear repeaters
2925  int mod_linear_nb = 0;
2926  int subm_linear_nb = 0;
2927  int cry_linear_nb = 0;
2928  vector <int> layer_linear_nb;
2929 
2930 
2931  // If we have multiple layers, we need to enter multiple values in the .geom.
2932  vector <string> vec_scanner_radius;
2933 
2934  // Rsector vectors
2935  vector <string> vec_number_of_rsectors_ang;
2936  vector <string> vec_number_of_rsectors_axl;
2937  vector <string> vec_rsector_gap_axl;
2938  vector <string> vec_rsector_first_angle;
2939 
2940 
2941  // Module vectors
2942  vector <string> vec_number_of_modules_trs;
2943  vector <string> vec_number_of_modules_axl;
2944  vector <string> vec_module_gap_trs;
2945  vector <string> vec_module_gap_axl;
2946 
2947  // Submodule vectors
2948  vector <string> vec_number_of_submodules_trs;
2949  vector <string> vec_number_of_submodules_axl;
2950  vector <string> vec_submodule_gap_trs;
2951  vector <string> vec_submodule_gap_axl;
2952 
2953  // Crystal vectors
2954  vector <string> vec_number_of_crystals_trs;
2955  vector <string> vec_number_of_crystals_axl;
2956  vector <string> vec_crystal_gap_trs;
2957  vector <string> vec_crystal_gap_axl;
2958 
2959  // Optionnal
2960  vector <string> vec_mean_depth_of_interaction;
2961  vector <string> vec_min_angle_diff;
2962 
2963  vector<string> path_mac_files;
2964  path_mac_files.push_back(a_pathMac);
2965 
2966  // Recover path to all macro files from the main mac file
2967  if(GetGATEMacFiles(a_pathMac , path_mac_files))
2968  {
2969  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover paths to GATE macro files !" << endl);
2970  return 1;
2971  }
2972 
2973  // Recover aliases of the different parts of the architecture
2974  if(GetGATEAliasesCylindrical(path_mac_files, rsector_name, module_name, submodule_name, crystal_name, layers_names, 2) )
2975  {
2976  Cerr("***** GetGATESystemType() ->Error occurred when trying to recover aliases for the elements of the cylindricalPET !" << endl);
2977  return 1;
2978  }
2979 
2980  // Recover nb of detected layers
2981  n_layers = layers_names.size();
2982 
2983 
2984  // Loop to recover all other informations
2985  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
2986  {
2987  ifstream systemMac(path_mac_files[f].c_str(), ios::in);
2988 
2989  // Reading the .mac file line by line and update the variables if a matching adress is found
2990  string line;
2991  while(getline(systemMac, line))
2992  {
2993  vector <string> values;
2994 
2995  // Scanner
2996  modality = "PET";
2997 
2998  string entry = "";
2999 
3000  entry = "/gate/"+rsector_name+"/placement/setTranslation";
3001  values = CheckGATECommand(entry, line);
3002 
3003  // Assumes that first rsector located on the X or Y axis
3004  if (values.size()>0)
3005  {
3006  if(ConvertFromString(values[0], &rsector_pos_X) ||
3007  ConvertFromString(values[1], &rsector_pos_Y) )
3008  {
3009  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3010  return 1;
3011  }
3012 
3013  // Check first rsector cartesian coordinates is 0 on X or Y axis
3014  // Throw error otherwise
3015  if(rsector_pos_X!=0 && rsector_pos_Y !=0)
3016  {
3017  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3018  Cerr(" Rsector cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
3019  return 1;
3020  }
3021 
3022  // Get the axis on which the first rsector is positionned
3023  if(rsector_pos_Y!=0) is_rsector_Y_axis = true;
3024 
3025  // Adjust scanner radius to the center position of the rsector
3026  scanner_radius += is_rsector_Y_axis ? abs(rsector_pos_Y) : abs(rsector_pos_X) ;
3027  }
3028 
3029  // Old version accounting on the rsector depth to be equal to the detector depth
3030  // in order to get the position of the detector surface.
3031  // Current version tracks the 'setTranslation' commands to get to the actual detector surface position
3032  /*
3033  // Adjust scanner radius (from center to rsector surface) according to block size
3034  entry = is_rsector_Y_axis ?
3035  "/gate/"+rsector_name+"/geometry/setYLength" :
3036  "/gate/"+rsector_name+"/geometry/setXLength";
3037 
3038  values = CheckGATECommand(entry, line);
3039  if (values.size()>0)
3040  {
3041  double rsector_size_depth = 0.;
3042  if(ConvertFromString(values[0], &rsector_size_depth) )
3043  {
3044  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3045  return 1;
3046  }
3047 
3048  scanner_radius -= rsector_size_depth/2;
3049  }
3050  */
3051 
3052 
3053  // rsector transaxial size
3054  entry = is_rsector_Y_axis ?
3055  "/gate/"+rsector_name+"/geometry/setXLength":
3056  "/gate/"+rsector_name+"/geometry/setYLength";
3057 
3058  values = CheckGATECommand(entry, line);
3059  if (values.size()>0)
3060  {
3061  if(ConvertFromString(values[0], &rsector_size_trs) )
3062  {
3063  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3064  return 1;
3065  }
3066  }
3067 
3068 
3069 
3070  // --- Rsectors ---
3071 
3072  entry = "/gate/"+rsector_name+"/ring/setModuloNumber";
3073  values = CheckGATECommand(entry, line);
3074  if (values.size()>0)
3075  {
3076  if(ConvertFromString(values[0], &rsector_nb_zshifts) )
3077  {
3078  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3079  return 1;
3080  }
3081  }
3082 
3083  entry = "/gate/"+rsector_name+"/ring/setRepeatNumber";
3084  values = CheckGATECommand(entry, line);
3085  if (values.size()>0)
3086  {
3087  if(ConvertFromString(values[0], &number_of_rsectors_ang) )
3088  {
3089  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3090  return 1;
3091  }
3092  }
3093 
3094 
3095 
3096  // Check if (axial) linear repeaters for rsectors
3097 
3098  // int rsector_linear_rpt
3099  // get setRptVector with either linear or cubicarray keyword (must be one or the other)
3100  // get values x y z
3101  // if more than one value -> error
3102  // get the value >0 and update accordingly
3103 
3104  entry = "/gate/"+rsector_name+"/linear/setRepeatNumber";
3105  values = CheckGATECommand(entry, line);
3106  if (values.size()>0)
3107  {
3108  if(ConvertFromString(values[0], &number_of_rsectors_axl) )
3109  {
3110  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3111  return 1;
3112  }
3113  }
3114 
3115 
3116 
3117 
3118  entry = "/gate/"+rsector_name+"/linear/setRepeatVector";
3119  values = CheckGATECommand(entry, line);
3120  if (values.size()>0)
3121  {
3122  if(ConvertFromString(values[2], &rsector_step_axl) )
3123  {
3124  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3125  return 1;
3126  }
3127  }
3128 
3129 
3130 
3131 
3132 
3133  // Check if cubic array repeaters for rsectors
3134  entry = is_rsector_Y_axis ?
3135  "/gate/"+rsector_name+"/cubicArray/setRepeatNumberX":
3136  "/gate/"+rsector_name+"/cubicArray/setRepeatNumberY";
3137 
3138  values = CheckGATECommand(entry, line);
3139  if (values.size()>0)
3140  {
3141  uint32_t number_of_rsectors_trs;
3142 
3143  if(ConvertFromString(values[0], &number_of_rsectors_trs) )
3144  {
3145  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3146  return 1;
3147  }
3148 
3149  // Check if more than one transaxial rsector is present.
3150  // Not currently implemented as the geometry model can vary according to whether a ring repeater is inserted before or after the cubicarray repeater
3151  // Throw error in this situation
3152  if(number_of_rsectors_trs>1)
3153  {
3154  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Error while trying to parse line: " << line<< endl);
3155  Cerr(" The GATE system contains more than one 'transaxial' rsector " << endl);
3156  Cerr(" The current implementation does not support such cylindricalPET model" << endl);
3157  Cerr(" Manual implementation of the system is required (ex: model the transaxial rsectors as modules)" << endl);
3158  return 1;
3159  }
3160  }
3161 
3162 
3163  entry = "/gate/"+rsector_name+"/cubicArray/setRepeatNumberZ";
3164  values = CheckGATECommand(entry, line);
3165 
3166  if (values.size()>0)
3167  {
3168  if(ConvertFromString(values[0], &number_of_rsectors_axl) )
3169  {
3170  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3171  return 1;
3172  }
3173  }
3174 
3175 
3176  entry = "/gate/"+rsector_name+"/cubicArray/setRepeatVector";
3177  values = CheckGATECommand(entry, line);
3178  if (values.size()>0)
3179  {
3180  if(ConvertFromString(values[2], &rsector_step_axl))
3181  {
3182  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3183  return 1;
3184  }
3185  }
3186 
3187 
3188 
3189  // axial FOV computed from rsector z-length
3190  entry = "/gate/"+rsector_name+"/geometry/setZLength";
3191  values = CheckGATECommand(entry, line);
3192  if (values.size()>0)
3193  {
3194  if(ConvertFromString(values[0], &rsector_size_axl) )
3195  {
3196  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3197  return 1;
3198  }
3199 
3200  }
3201 
3202 
3203  entry = "/gate/"+rsector_name+"/ring/setFirstAngle";
3204  values = CheckGATECommand(entry, line);
3205  if (values.size()>0)
3206  {
3207  if(ConvertFromString(values[0], &rsector_first_angle) )
3208  {
3209  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3210  return 1;
3211  }
3212  }
3213 
3214  entry = "/gate/"+rsector_name+"/ring/setAngularSpan";
3215  values = CheckGATECommand(entry, line);
3216  if (values.size()>0)
3217  {
3218  if(ConvertFromString(values[0], &rsector_angular_span) )
3219  {
3220  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3221  return 1;
3222  }
3223  }
3224 
3225  // Up to 8 zshifts in Gate
3226  for (int i=1; i <8; i++)
3227  {
3228  entry = "/gate/"+rsector_name+"/ring/setZShift"+toString(i);
3229  values = CheckGATECommand(entry, line);
3230  if (values.size()>0)
3231  {
3232  double zshift = 0.;
3233  if(ConvertFromString(values[0], &zshift) )
3234  {
3235  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3236  return 1;
3237  }
3238 
3239  vec_rsector_Z_Shift.push_back(zshift);
3240  }
3241  }
3242 
3243 
3244 
3245  // --- Modules ---
3246 
3247  // Check for any translation and adjust scanner radius position accordingly
3248  entry = "/gate/"+module_name+"/placement/setTranslation";
3249  values = CheckGATECommand(entry, line);
3250 
3251  FLTNB module_pos_X =0.,
3252  module_pos_Y =0.;
3253 
3254  // Assumes that module located on the X or Y axis
3255  if (values.size()>0)
3256  {
3257  if(ConvertFromString(values[0], &module_pos_X) ||
3258  ConvertFromString(values[1], &module_pos_Y) )
3259  {
3260  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3261  return 1;
3262  }
3263 
3264  // Check first module cartesian coordinates is 0 on X or Y axis
3265  // Throw error otherwise
3266  if(module_pos_X!=0 && module_pos_Y !=0)
3267  {
3268  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3269  Cerr(" Module cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
3270  return 1;
3271  }
3272 
3273  // Adjust scanner radius to the center position of module
3274  scanner_radius += is_rsector_Y_axis ? module_pos_Y : module_pos_X ;
3275  }
3276 
3277 
3278 
3279  entry = is_rsector_Y_axis ?
3280  "/gate/"+module_name+"/cubicArray/setRepeatNumberX":
3281  "/gate/"+module_name+"/cubicArray/setRepeatNumberY";
3282 
3283  values = CheckGATECommand(entry, line);
3284  if (values.size()>0)
3285  {
3286  if(ConvertFromString(values[0], &number_of_modules_trs) )
3287  {
3288  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3289  return 1;
3290  }
3291  }
3292 
3293 
3294 
3295 
3296  entry = "/gate/"+module_name+"/cubicArray/setRepeatNumberZ";
3297  values = CheckGATECommand(entry, line);
3298 
3299  if (values.size()>0)
3300  {
3301  if(ConvertFromString(values[0], &number_of_modules_axl) )
3302  {
3303  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3304  return 1;
3305  }
3306  }
3307 
3308 
3309  entry = is_rsector_Y_axis ?
3310  "/gate/"+module_name+"/geometry/setXLength":
3311  "/gate/"+module_name+"/geometry/setYLength";
3312 
3313  values = CheckGATECommand(entry, line);
3314  if (values.size()>0)
3315  {
3316  if(ConvertFromString(values[0], &module_size_trs) )
3317  {
3318  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3319  return 1;
3320  }
3321  }
3322 
3323 
3324  entry = "/gate/"+module_name+"/geometry/setZLength";
3325  values = CheckGATECommand(entry, line);
3326  if (values.size()>0)
3327  {
3328  if(ConvertFromString(values[0], &module_size_axl) )
3329  {
3330  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3331  return 1;
3332  }
3333  }
3334 
3335  entry = "/gate/"+module_name+"/cubicArray/setRepeatVector";
3336  values = CheckGATECommand(entry, line);
3337  if (values.size()>0)
3338  {
3339  string trs_step = is_rsector_Y_axis ?
3340  values[0] :
3341  values[1] ;
3342 
3343  if(ConvertFromString(trs_step, &module_step_trs) ||
3344  ConvertFromString(values[2], &module_step_axl))
3345  {
3346  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3347  return 1;
3348  }
3349  }
3350 
3351 
3352 
3353 
3354  // linear repeaters instead of box
3355  entry = "/gate/"+module_name+"/linear/setRepeatNumber";
3356  values = CheckGATECommand(entry, line);
3357 
3358  if (values.size()>0)
3359  {
3360  //if(ConvertFromString(values[0] , &number_of_modules_axl) )
3361  if(ConvertFromString(values[0] , &mod_linear_nb) )
3362  {
3363  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3364  return 1;
3365  }
3366  }
3367 
3368  // linear repeaters instead of box, but with cubicArray...
3369  entry = "/gate/"+module_name+"/cubicArray/setRepeatNumber ";
3370  values = CheckGATECommand(entry, line);
3371 
3372  if (values.size()>0)
3373  {
3374  //if(ConvertFromString(values[0] , &number_of_modules_axl) )
3375  if(ConvertFromString(values[0] , &mod_linear_nb) )
3376  {
3377  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3378  return 1;
3379  }
3380  }
3381 
3382 
3383  // linear keyword ...
3384  entry = "/gate/"+module_name+"/linear/setRepeatVector";
3385  values = CheckGATECommand(entry, line);
3386  if (values.size()>0)
3387  {
3388  string trs_step = is_rsector_Y_axis ?
3389  values[0] :
3390  values[1] ;
3391 
3392  if(ConvertFromString(trs_step, &module_step_trs) ||
3393  ConvertFromString(values[2], &module_step_axl))
3394  {
3395  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3396  return 1;
3397  }
3398 
3399  // Set linear number depending on step position
3400  if(module_step_trs > 0) // linear repeater for trs
3401  number_of_modules_trs = mod_linear_nb;
3402  else if (module_step_axl > 0) // linear repeater for axl
3403  number_of_modules_axl = mod_linear_nb;
3404  else // something wrong
3405  {
3406  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with module linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
3407  return 1;
3408  }
3409  }
3410 
3411  // or cubicArray keyword ...
3412  // If repeater is linear (mod_linear_nb>0), set linear number depending on step position
3413  if(mod_linear_nb>0)
3414  {
3415  entry = "/gate/"+module_name+"/cubicArray/setRepeatVector";
3416  values = CheckGATECommand(entry, line);
3417  if (values.size()>0)
3418  {
3419  string trs_step = is_rsector_Y_axis ?
3420  values[0] :
3421  values[1] ;
3422 
3423  if(ConvertFromString(trs_step, &module_step_trs) ||
3424  ConvertFromString(values[2], &module_step_axl))
3425  {
3426  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3427  return 1;
3428  }
3429 
3430 
3431  if(module_step_trs > 0) // linear repeater for trs
3432  number_of_modules_trs = mod_linear_nb;
3433  else if (module_step_axl > 0) // linear repeater for axl
3434  number_of_modules_axl = mod_linear_nb;
3435  else // something wrong
3436  {
3437  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with module linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
3438  return 1;
3439  }
3440 
3441  }
3442  }
3443 
3444  // --- Submodules ---
3445 
3446  // Check for any translation and adjust scanner radius position accordingly
3447  entry = "/gate/"+submodule_name+"/placement/setTranslation";
3448  values = CheckGATECommand(entry, line);
3449 
3450  FLTNB submodule_pos_X =0.,
3451  submodule_pos_Y =0.;
3452 
3453  // Assumes that submodule located on the X or Y axis
3454  if (values.size()>0)
3455  {
3456  if(ConvertFromString(values[0], &submodule_pos_X) ||
3457  ConvertFromString(values[1], &submodule_pos_Y) )
3458  {
3459  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3460  return 1;
3461  }
3462 
3463  // Check first module cartesian coordinates is 0 on X or Y axis
3464  // Throw error otherwise
3465  if(submodule_pos_X!=0 && submodule_pos_Y !=0)
3466  {
3467  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3468  Cerr(" Submodule cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
3469  return 1;
3470  }
3471 
3472  // Adjust scanner radius to the center position of submodule
3473  scanner_radius += is_rsector_Y_axis ? submodule_pos_Y : submodule_pos_X ;
3474  }
3475 
3476 
3477 
3478  entry = is_rsector_Y_axis ?
3479  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberX":
3480  "/gate/"+submodule_name+"/cubicArray/setRepeatNumberY";
3481 
3482 
3483  values = CheckGATECommand(entry, line);
3484  if (values.size()>0)
3485  {
3486  if(ConvertFromString(values[0], &number_of_submodules_trs) )
3487  {
3488  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3489  return 1;
3490  }
3491  }
3492 
3493  entry = "/gate/"+submodule_name+"/cubicArray/setRepeatNumberZ";
3494  values = CheckGATECommand(entry, line);
3495  if (values.size()>0)
3496  {
3497  if(ConvertFromString(values[0], &number_of_submodules_axl) )
3498  {
3499  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3500  return 1;
3501  }
3502  }
3503 
3504 
3505 
3506 
3507  entry = is_rsector_Y_axis ?
3508  "/gate/"+submodule_name+"/geometry/setXLength":
3509  "/gate/"+submodule_name+"/geometry/setYLength";
3510 
3511  values = CheckGATECommand(entry, line);
3512  if (values.size()>0)
3513  {
3514  if(ConvertFromString(values[0], &submodule_size_trs) )
3515  {
3516  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3517  return 1;
3518  }
3519  }
3520 
3521  entry = "/gate/"+submodule_name+"/geometry/setZLength";
3522  values = CheckGATECommand(entry, line);
3523  if (values.size()>0)
3524  {
3525  if(ConvertFromString(values[0], &submodule_size_axl) )
3526  {
3527  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3528  return 1;
3529  }
3530  }
3531 
3532  entry = "/gate/"+submodule_name+"/cubicArray/setRepeatVector";
3533  values = CheckGATECommand(entry, line);
3534  if (values.size()>0)
3535  {
3536  string trs_step = is_rsector_Y_axis ?
3537  values[0] :
3538  values[1] ;
3539 
3540  if(ConvertFromString(trs_step, &submodule_step_trs) ||
3541  ConvertFromString(values[2], &submodule_step_axl) )
3542  {
3543  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3544  return 1;
3545  }
3546  }
3547 
3548 
3549 
3550  // linear repeaters instead of box
3551  entry = "/gate/"+submodule_name+"/linear/setRepeatNumber";
3552  values = CheckGATECommand(entry, line);
3553 
3554  if (values.size()>0)
3555  {
3556  //if(ConvertFromString( values[0] , &number_of_submodules_axl) )
3557  if(ConvertFromString( values[0] , &subm_linear_nb) )
3558  {
3559  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3560  return 1;
3561  }
3562  }
3563 
3564  // linear repeaters instead of box, but using cubicArray
3565  entry = "/gate/"+submodule_name+"/cubicArray/setRepeatNumber ";
3566  values = CheckGATECommand(entry, line);
3567 
3568  if (values.size()>0)
3569  {
3570  //if(ConvertFromString( values[0] , &number_of_submodules_axl) )
3571  if(ConvertFromString( values[0] , &subm_linear_nb) )
3572  {
3573  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3574  return 1;
3575  }
3576  }
3577 
3578  // linear keyword ...
3579  entry = "/gate/"+submodule_name+"/linear/setRepeatVector";
3580  values = CheckGATECommand(entry, line);
3581  if (values.size()>0)
3582  {
3583  string trs_step = is_rsector_Y_axis ?
3584  values[0] :
3585  values[1] ;
3586 
3587  if(ConvertFromString(trs_step, &submodule_step_trs) ||
3588  ConvertFromString(values[2], &submodule_step_axl))
3589  {
3590  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3591  return 1;
3592  }
3593 
3594  // Set linear number depending on step position
3595  if(submodule_step_trs > 0) // linear repeater for trs
3596  number_of_submodules_trs = subm_linear_nb;
3597  else if (submodule_step_axl > 0) // linear repeater for axl
3598  number_of_submodules_axl = subm_linear_nb;
3599  else // something wrong
3600  {
3601  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with submodule linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
3602  return 1;
3603  }
3604  }
3605 
3606  // ... or cubicArray keyword ...
3607  // If repeater is linear (subm_linear_nb>0), set linear number depending on step position
3608  if(subm_linear_nb>0)
3609  {
3610  entry = "/gate/"+submodule_name+"/cubicArray/setRepeatVector";
3611  values = CheckGATECommand(entry, line);
3612  if (values.size()>0)
3613  {
3614  string trs_step = is_rsector_Y_axis ?
3615  values[0] :
3616  values[1] ;
3617 
3618  if(ConvertFromString(trs_step, &submodule_step_trs) ||
3619  ConvertFromString(values[2], &submodule_step_axl))
3620  {
3621  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3622  return 1;
3623  }
3624 
3625 
3626  // Set linear number depending on step position
3627  if(submodule_step_trs > 0) // linear repeater for trs
3628  number_of_submodules_trs = subm_linear_nb;
3629  else if (submodule_step_axl > 0) // linear repeater for axl
3630  number_of_submodules_axl = subm_linear_nb;
3631  else // something wrong
3632  {
3633  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with submodule linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
3634  return 1;
3635  }
3636  }
3637 
3638  }
3639 
3640 
3641 
3642 
3643 
3644  // --- Crystals ---
3645 
3646  // Check for any translation and adjust scanner radius position accordingly
3647  entry = "/gate/"+crystal_name+"/placement/setTranslation";
3648  values = CheckGATECommand(entry, line);
3649 
3650  FLTNB crystal_pos_X =0.,
3651  crystal_pos_Y =0.;
3652 
3653  // Assumes that submodule located on the X or Y axis
3654  if (values.size()>0)
3655  {
3656  if(ConvertFromString(values[0], &crystal_pos_X) ||
3657  ConvertFromString(values[1], &crystal_pos_Y) )
3658  {
3659  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3660  return 1;
3661  }
3662 
3663  // Check first module cartesian coordinates is 0 on X or Y axis
3664  // Throw error otherwise
3665  if(crystal_pos_X!=0 && crystal_pos_Y !=0)
3666  {
3667  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3668  Cerr(" Crystal cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
3669  return 1;
3670  }
3671 
3672  // Adjust scanner radius to the center position of crystal
3673  scanner_radius += is_rsector_Y_axis ? crystal_pos_Y : crystal_pos_X ;
3674  }
3675 
3676 
3677 
3678  entry = is_rsector_Y_axis ?
3679  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
3680  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
3681 
3682  values = CheckGATECommand(entry, line);
3683  if (values.size()>0)
3684  {
3685  if(ConvertFromString(values[0], &number_of_crystals_trs) )
3686  {
3687  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3688  return 1;
3689  }
3690 
3691  }
3692 
3693  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
3694  values = CheckGATECommand(entry, line);
3695  if (values.size()>0)
3696  {
3697  if(ConvertFromString(values[0], &number_of_crystals_axl) )
3698  {
3699  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3700  return 1;
3701  }
3702  }
3703 
3704 
3705  entry = "/gate/"+crystal_name+"/geometry/setXLength";
3706  values = CheckGATECommand(entry, line);
3707  if (values.size()>0)
3708  {
3709  double x_length;
3710  if(ConvertFromString(values[0], &x_length) )
3711  {
3712  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3713  return 1;
3714  }
3715 
3716  if (is_rsector_Y_axis)
3717  crystal_size_trs = x_length;
3718  else
3719  crystal_size_depth = x_length;
3720  }
3721 
3722  entry = "/gate/"+crystal_name+"/geometry/setYLength";
3723  values = CheckGATECommand(entry, line);
3724  if (values.size()>0)
3725  {
3726  double y_length;
3727  if(ConvertFromString(values[0], &y_length) )
3728  {
3729  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3730  return 1;
3731  }
3732 
3733  if (is_rsector_Y_axis)
3734  crystal_size_depth = y_length;
3735  else
3736  crystal_size_trs = y_length;
3737 
3738  }
3739 
3740  entry = "/gate/"+crystal_name+"/geometry/setZLength";
3741  values = CheckGATECommand(entry, line);
3742  if (values.size()>0)
3743  {
3744  if(ConvertFromString(values[0], &crystal_size_axl) )
3745  {
3746  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3747  return 1;
3748  }
3749  }
3750 
3751  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatVector";
3752  values = CheckGATECommand(entry, line);
3753  if (values.size()>0)
3754  {
3755  string trs_step = is_rsector_Y_axis ?
3756  values[0] :
3757  values[1] ;
3758 
3759  if(ConvertFromString(trs_step, &crystal_step_trs) ||
3760  ConvertFromString(values[2], &crystal_step_axl) )
3761  {
3762  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3763  return 1;
3764  }
3765  }
3766 
3767  // linear repeaters instead of box
3768  entry = "/gate/"+crystal_name+"/linear/setRepeatNumber";
3769  values = CheckGATECommand(entry, line);
3770 
3771  if (values.size()>0)
3772  {
3773  //if(ConvertFromString( values[0] , &number_of_crystals_axl) )
3774  if(ConvertFromString( values[0] , &cry_linear_nb) )
3775  {
3776  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3777  return 1;
3778  }
3779  }
3780 
3781  // linear repeaters instead of box, but with cubicArray
3782  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatNumber ";
3783  values = CheckGATECommand(entry, line);
3784 
3785  if (values.size()>0)
3786  {
3787  //if(ConvertFromString( values[0] , &number_of_crystals_axl) )
3788  if(ConvertFromString( values[0] , &cry_linear_nb) )
3789  {
3790  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3791  return 1;
3792  }
3793  }
3794 
3795  // linear keyword ...
3796  entry = "/gate/"+crystal_name+"/linear/setRepeatVector";
3797  values = CheckGATECommand(entry, line);
3798  if (values.size()>0)
3799  {
3800  string trs_step = is_rsector_Y_axis ?
3801  values[0] :
3802  values[1] ;
3803 
3804  if(ConvertFromString(trs_step, &crystal_step_trs) ||
3805  ConvertFromString(values[2], &crystal_step_axl))
3806  {
3807  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3808  return 1;
3809  }
3810 
3811  // Set linear number depending on step position
3812  if(crystal_step_trs > 0) // linear repeater for trs
3813  number_of_crystals_trs = cry_linear_nb;
3814  else if (crystal_step_axl > 0) // linear repeater for axl
3815  number_of_crystals_axl = cry_linear_nb;
3816  else // something wrong
3817  {
3818  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with crystal linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
3819  return 1;
3820  }
3821  }
3822 
3823  // or cubicArray keyword ...
3824  // If repeater is linear (cry_linear_nb>0), set linear number depending on step position
3825  if(cry_linear_nb>0)
3826  {
3827  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatVector";
3828  values = CheckGATECommand(entry, line);
3829  if (values.size()>0)
3830  {
3831  string trs_step = is_rsector_Y_axis ?
3832  values[0] :
3833  values[1] ;
3834 
3835  if(ConvertFromString(trs_step, &crystal_step_trs) ||
3836  ConvertFromString(values[2], &crystal_step_axl))
3837  {
3838  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3839  return 1;
3840  }
3841 
3842  // Set linear number depending on step position
3843  if(crystal_step_trs > 0) // linear repeater for trs
3844  number_of_crystals_trs = cry_linear_nb;
3845  else if (crystal_step_axl > 0) // linear repeater for axl
3846  number_of_crystals_axl = cry_linear_nb;
3847  else // something wrong
3848  {
3849  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with crystal linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
3850  return 1;
3851  }
3852  }
3853  }
3854 
3855 
3856 
3857  // --- Layers ---
3858  entry = "/gate/"+crystal_name+"/daughters/name";
3859  values = CheckGATECommand(entry, line);
3860  if (values.size()>0)
3861  {
3862  layers_names.push_back(values[0]);
3863  number_of_layers++;
3864  }
3865 
3866  // loop on the layers to get their specific information as they are integrated in layers_names.
3867  for (int i=0; i < number_of_layers; i++)
3868  {
3869  // assumes that first block is positionned on the x-axis
3870  entry = "/gate/"+layers_names[i]+"/placement/setTranslation";
3871  values = CheckGATECommand(entry, line);
3872 
3873  if (values.size()>0)
3874  {
3875  vector<double> layer_pos;
3876  for(int d=0 ; d<3 ; d++)
3877  {
3878  double pos;
3879  if(ConvertFromString(values[d], &pos) )
3880  {
3881  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3882  return 1;
3883  }
3884  layer_pos.push_back(pos);
3885  }
3886 
3887  if(is_rsector_Y_axis)
3888  {
3889  double pos = layer_pos[1];
3890  layer_pos[1] = layer_pos[0];
3891  layer_pos[0] = pos;
3892  }
3893 
3894  layers_positions.push_back(layer_pos);
3895  }
3896 
3897 
3898  // assumes that first block is positionned on the x-axis
3899  entry = "/gate/"+layers_names[i]+"/geometry/setXLength";
3900  values = CheckGATECommand(entry, line);
3901 
3902  if (values.size()>0)
3903  {
3904  double xlength;
3905  if(ConvertFromString(values[0], &xlength) )
3906  {
3907  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3908  return 1;
3909  }
3910 
3911  if (is_rsector_Y_axis)
3912  layers_size_trs.push_back(xlength);
3913  else
3914  layers_size_depth.push_back(xlength);
3915  }
3916 
3917  // assumes that first block is positionned on the x-axis
3918  entry = "/gate/"+layers_names[i]+"/geometry/setYLength";
3919  values = CheckGATECommand(entry, line);
3920  if (values.size()>0)
3921  {
3922  double ylength;
3923  if(ConvertFromString(values[0], &ylength) )
3924  {
3925  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3926  return 1;
3927  }
3928  if (is_rsector_Y_axis)
3929  layers_size_depth.push_back(ylength);
3930  else
3931  layers_size_trs.push_back(ylength);
3932  }
3933 
3934  entry = "/gate/"+layers_names[i]+"/geometry/setZLength";
3935  values = CheckGATECommand(entry, line);
3936  if (values.size()>0)
3937  {
3938  double zlength;
3939  if(ConvertFromString(values[0], &zlength) )
3940  {
3941  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3942  return 1;
3943  }
3944  layers_size_axl.push_back(zlength);
3945  }
3946 
3947  // Check if a repeater if applied to the layers elements
3948  // In this case, the total number of crystals for a layer[i]
3949  // will be crystal elts*layers elts[i]
3950  entry = is_rsector_Y_axis ?
3951  "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberX":
3952  "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberY";
3953 
3954  values = CheckGATECommand(entry, line);
3955  if (values.size()>0)
3956  {
3957  uint32_t step_trs;
3958  if(ConvertFromString(values[0], &step_trs))
3959  {
3960  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3961  return 1;
3962  }
3963 
3964  number_of_lyr_elts_trs.push_back(step_trs);
3965  }
3966 
3967  entry = is_rsector_Y_axis ?
3968  "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberY":
3969  "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberX";
3970 
3971  values = CheckGATECommand(entry, line);
3972  if (values.size()>0)
3973  {
3974  uint32_t step_dph;
3975  if(ConvertFromString(values[0], &step_dph))
3976  {
3977  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3978  return 1;
3979  }
3980 
3981  number_of_lyr_elts_dph.push_back(step_dph);
3982  }
3983 
3984 
3985  entry = "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumberZ";
3986  values = CheckGATECommand(entry, line);
3987  if (values.size()>0)
3988  {
3989  uint32_t step_axl;
3990  if(ConvertFromString(values[0], &step_axl))
3991  {
3992  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
3993  return 1;
3994  }
3995  number_of_lyr_elts_axl.push_back(step_axl);
3996  }
3997 
3998  entry = "/gate/"+layers_names[i]+"/cubicArray/setRepeatVector";
3999  values = CheckGATECommand(entry, line);
4000  if (values.size()>0)
4001  {
4002  string trs_step = is_rsector_Y_axis ?
4003  values[0] :
4004  values[1] ;
4005 
4006  string dph_step = is_rsector_Y_axis ?
4007  values[1] :
4008  values[0] ;
4009 
4010  double step_trs=0., step_axl=0., step_dph=0.;
4011  if(ConvertFromString(trs_step, &step_trs) ||
4012  ConvertFromString(values[2], &step_axl) ||
4013  ConvertFromString(dph_step, &step_dph) )
4014  {
4015  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4016  return 1;
4017  }
4018 
4019  if(step_trs > 0) // linear repeater for trs
4020  {
4021  layers_step_trs.push_back(step_trs);
4022  }
4023  else if (step_axl > 0) // linear repeater for axl
4024  {
4025  layers_step_axl.push_back(step_axl);
4026  }
4027  else if (step_dph > 0)
4028  layers_step_dph.push_back(step_dph);
4029  else // something wrong
4030  {
4031  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with layer linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
4032  return 1;
4033  }
4034  }
4035 
4036 
4037  // linear repeaters instead of box
4038  entry = "/gate/"+layers_names[i]+"/linear/setRepeatNumber";
4039  values = CheckGATECommand(entry, line);
4040 
4041  if (values.size()>0)
4042  {
4043  uint32_t nb;
4044  if(ConvertFromString( values[0] , &nb) )
4045  {
4046  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4047  return 1;
4048  }
4049  layer_linear_nb.push_back(nb);
4050  }
4051 
4052  // linear repeaters instead of box, but with cubicArray
4053  entry = "/gate/"+layers_names[i]+"/cubicArray/setRepeatNumber ";
4054  values = CheckGATECommand(entry, line);
4055 
4056  if (values.size()>0)
4057  {
4058  uint32_t nb;
4059  if(ConvertFromString( values[0] , &nb) )
4060  {
4061  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4062  return 1;
4063  }
4064  layer_linear_nb.push_back(nb);
4065  }
4066 
4067  // linear keyword ...
4068  entry = "/gate/"+layers_names[i]+"/linear/setRepeatVector";
4069  values = CheckGATECommand(entry, line);
4070  if (values.size()>0)
4071  {
4072  string trs_step = is_rsector_Y_axis ?
4073  values[0] :
4074  values[1] ;
4075 
4076  string dph_step = is_rsector_Y_axis ?
4077  values[1] :
4078  values[0] ;
4079 
4080  double step_trs=0., step_axl=0., step_dph=0.;
4081  if(ConvertFromString(trs_step, &step_trs) ||
4082  ConvertFromString(values[2], &step_axl) ||
4083  ConvertFromString(dph_step, &step_dph) )
4084  {
4085  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4086  return 1;
4087  }
4088 
4089  if(step_trs > 0) // linear repeater for trs
4090  {
4091  number_of_lyr_elts_trs.push_back(layer_linear_nb[ i ]);
4092  layers_step_trs.push_back(step_trs);
4093  }
4094  else if (step_axl > 0) // linear repeater for axl
4095  {
4096  number_of_lyr_elts_axl.push_back(layer_linear_nb[ i ]);
4097  layers_step_axl.push_back(step_axl);
4098  }
4099  else if (step_dph > 0)
4100  {
4101  number_of_lyr_elts_dph.push_back(layer_linear_nb[ i ]);
4102  layers_step_dph.push_back(step_dph);
4103  }
4104  else // something wrong
4105  {
4106  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with layer linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
4107  return 1;
4108  }
4109 
4110  }
4111 
4112 
4113  // ... or cubicArray keyword ...
4114  // If repeater is linear (cry_linear_nb>0), set linear number depending on step position
4115  if((int)layer_linear_nb.size()>i && layer_linear_nb[ i ]>0)
4116  {
4117  entry = "/gate/"+layers_names[i]+"/cubicArray/setRepeatVector";
4118  values = CheckGATECommand(entry, line);
4119  if (values.size()>0)
4120  {
4121  string trs_step = is_rsector_Y_axis ?
4122  values[0] :
4123  values[1] ;
4124 
4125  string dph_step = is_rsector_Y_axis ?
4126  values[1] :
4127  values[0] ;
4128 
4129 
4130  double step_trs=0., step_axl=0., step_dph=0.;
4131  if(ConvertFromString(trs_step, &step_trs) ||
4132  ConvertFromString(values[2], &step_axl) ||
4133  ConvertFromString(dph_step, &step_dph) )
4134  {
4135  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4136  return 1;
4137  }
4138 
4139 
4140  if(step_trs > 0) // linear repeater for trs
4141  {
4142  number_of_lyr_elts_trs.push_back(layer_linear_nb[ i ]);
4143  layers_step_trs.push_back(step_trs);
4144  }
4145  else if (step_axl > 0) // linear repeater for axl
4146  {
4147  number_of_lyr_elts_axl.push_back(layer_linear_nb[ i ]);
4148  layers_step_axl.push_back(step_axl);
4149  }
4150  else if (step_dph > 0)
4151  {
4152  number_of_lyr_elts_dph.push_back(layer_linear_nb[ i ]);
4153  layers_step_dph.push_back(step_dph);
4154  }
4155  else // something wrong
4156  {
4157  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> There seems to be a problem with layer linear repeater. Please report the error to the castor mailing-list! At line " << line<< endl);
4158  return 1;
4159  }
4160  }
4161  }
4162 
4163  } // end of loop on layers
4164 
4165 
4166  entry = "/gate/digitizer/Coincidences/minSectorDifference";
4167  values = CheckGATECommand(entry, line);
4168  if (values.size()>0)
4169  {
4170  FLTNB min_sector_diff= 0.;
4171 
4172  if(ConvertFromString(values[0], &min_sector_diff))
4173  {
4174  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4175  return 1;
4176  }
4177 
4178  min_angle_diff = 360./number_of_rsectors_ang*min_sector_diff;
4179  }
4180 
4181  }
4182  systemMac.close();
4183  }
4184 
4185  // Processing layers declated in repeaters
4186  if (number_of_lyr_elts_dph.size() > 0)
4187  {
4188  // First check there is a conflict with the different ways of declaring layers
4189  if (number_of_layers>1)
4190  // problem
4191  {
4192  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conflicting declaration of layers using both crystal/daughter command and a depth level with a linear or cubic array repeater. Only one approach can be managed"<< endl);
4193  return 1;
4194  }
4195  else
4196  {
4197  // Layers defined by cubic arrays:
4198  // Propagate all geometric infos from the 1st layer to the other layers
4199  for (size_t l=1 ; l<number_of_lyr_elts_dph[ 0 ] ; l++)
4200  {
4201  if( number_of_lyr_elts_trs.size() > 0 ) number_of_lyr_elts_trs.push_back( number_of_lyr_elts_trs[ 0 ] );
4202  if( number_of_lyr_elts_axl.size() > 0 ) number_of_lyr_elts_axl.push_back( number_of_lyr_elts_axl[ 0 ] );
4203 
4204  if( layers_size_depth.size() > 0 ) layers_size_depth.push_back( layers_size_depth[ 0 ] );
4205  if( layers_size_trs.size() > 0 ) layers_size_trs.push_back( layers_size_trs[ 0 ] );
4206  if( layers_size_axl.size() > 0 ) layers_size_axl.push_back( layers_size_axl[ 0 ] );
4207 
4208  if( layers_step_trs.size() > 0 ) layers_step_trs.push_back( layers_step_trs[ 0 ] );
4209  if( layers_step_axl.size() > 0 ) layers_step_axl.push_back( layers_step_axl[ 0 ] );
4210 
4211  // Only recover here the depth of each layer according to the steps
4212  vector<double> layer_pos;
4213  layer_pos.push_back(layers_positions[ 0 ][ 0 ] + l*layers_step_dph[ 0 ]);
4214 
4215  layers_positions.push_back(layer_pos);
4216  }
4217 
4218  number_of_layers = number_of_lyr_elts_dph[ 0 ];
4219  }
4220  }
4221 
4222  // Compute total number of crystal elements
4223  if(number_of_layers == 0)
4224  {
4225  number_of_elements = number_of_rsectors_ang
4226  * number_of_rsectors_axl
4227  * number_of_modules_trs
4228  * number_of_modules_axl
4229  * number_of_submodules_trs
4230  * number_of_submodules_axl
4231  * number_of_crystals_trs
4232  * number_of_crystals_axl;
4233  }
4234  else
4235  for(int l=0 ; l<number_of_layers ; l++)
4236  {
4237  int32_t nb_crystals_layer = number_of_rsectors_ang
4238  * number_of_rsectors_axl
4239  * number_of_modules_trs
4240  * number_of_modules_axl
4241  * number_of_submodules_trs
4242  * number_of_submodules_axl
4243  * number_of_crystals_trs
4244  * number_of_crystals_axl;
4245 
4246  // Add layer elements if repeaters have been used on layers
4247  if(number_of_lyr_elts_trs.size()>0 || number_of_lyr_elts_axl.size()>0 )
4248  nb_crystals_layer *= number_of_lyr_elts_trs[l] * number_of_lyr_elts_axl[l];
4249 
4250  number_of_elements += nb_crystals_layer;
4251  }
4252 
4253  // Compute sizes and gaps of each cylindrical PET structures.
4254 
4255  // Compute crystal gaps
4256  if (crystal_step_axl - crystal_size_axl >= 0)
4257  crystal_gap_axl = crystal_step_axl - crystal_size_axl;
4258 
4259  if (crystal_step_trs - crystal_size_trs >= 0)
4260  crystal_gap_trs = crystal_step_trs - crystal_size_trs;
4261 
4262  // Compute submodule size from crystals size, gaps & number
4263  submodule_size_axl = crystal_size_axl*number_of_crystals_axl + crystal_gap_axl*(number_of_crystals_axl-1);
4264  submodule_size_trs = crystal_size_trs*number_of_crystals_trs + crystal_gap_trs*(number_of_crystals_trs-1);
4265 
4266  // Compute submodule gaps
4267  if (submodule_step_axl - submodule_size_axl >= 0)
4268  submodule_gap_axl = submodule_step_axl - submodule_size_axl;
4269 
4270  if (submodule_step_trs - submodule_size_trs >= 0)
4271  submodule_gap_trs = submodule_step_trs - submodule_size_trs;
4272 
4273  // Compute module size from submodule size, gaps & number
4274  module_size_axl = submodule_size_axl*number_of_submodules_axl + submodule_gap_axl*(number_of_submodules_axl-1);
4275  module_size_trs = submodule_size_trs*number_of_submodules_trs + submodule_gap_trs*(number_of_submodules_trs-1);
4276 
4277  // Compute module gaps
4278  if (module_step_axl - module_size_axl >= 0)
4279  module_gap_axl = module_step_axl - module_size_axl;
4280 
4281  if (module_step_trs - module_size_trs >= 0)
4282  module_gap_trs = module_step_trs - module_size_trs;
4283 
4284  // Compute rsector size from crystals size, gaps & number
4285  rsector_size_axl = module_size_axl*number_of_modules_axl + module_gap_axl*(number_of_modules_axl-1);
4286  rsector_size_trs = module_size_trs*number_of_modules_trs + module_gap_trs*(number_of_modules_trs-1);
4287 
4288 
4289  // Compute rsector gaps.
4290  if (rsector_step_axl - rsector_size_axl >= 0)
4291  rsector_gap_axl = rsector_step_axl - rsector_size_axl;
4292 
4293 
4294  // Axial FOV
4295  fov_axl = rsector_size_axl * number_of_rsectors_axl // rsectors
4296  + (number_of_rsectors_axl-1)*rsector_gap_axl; // gaps
4297 
4298  // Just use twice the total number of crystals to arbitrary define a number of voxels
4299  //voxels_number_axl = fov_axl/4 + 1;
4300  voxels_number_axl = ( number_of_crystals_axl
4301  * number_of_submodules_axl
4302  * number_of_modules_axl
4303  * number_of_rsectors_axl )
4304  * 2;
4305 
4306  // Transaxial FOV defined as half diameter/1.5
4307  fov_trs = (2*scanner_radius ) / 1.5;
4308 
4309  // Arbitrary define the transaxial voxel size as axial_voxel_size / 1.5
4310  //voxels_number_trs = fov_trs/4 + 1;
4311  voxels_number_trs = ( number_of_crystals_trs
4312  * number_of_submodules_trs
4313  * number_of_modules_trs
4314  * number_of_rsectors_ang )
4315  / 3;
4316 
4317 
4318  // Compute first angle
4319  // CASToR x and y axis for rotation inverted in comparison with GATE
4320  rsector_first_angle -= round(atan2f(rsector_pos_X , rsector_pos_Y) * 180. / M_PI);
4321 
4322  // Computing the other parts of variables, if their is more than one layer
4323  if (number_of_layers > 0)
4324  {
4325  for (uint16_t l=0; l < number_of_layers ; l++)
4326  {
4327  // Scanner vectors
4328  double rad = scanner_radius;
4329  if (layers_positions.size()>l) rad += layers_positions[ l ][ 0 ];
4330  if (layers_size_depth.size()>l) rad -= layers_size_depth[ l ] / 2.;
4331  vec_scanner_radius.push_back( toString( rad ) );
4332 
4333  // Rsector vectors
4334  vec_number_of_rsectors_ang.push_back( toString(number_of_rsectors_ang) );
4335  vec_number_of_rsectors_axl.push_back( toString(number_of_rsectors_axl) );
4336  vec_rsector_gap_axl.push_back( toString(rsector_gap_axl) );
4337  vec_rsector_first_angle.push_back( toString(rsector_first_angle) );
4338 
4339  // Module vectors
4340  vec_number_of_modules_trs.push_back( toString(number_of_modules_trs) );
4341  vec_number_of_modules_axl.push_back( toString(number_of_modules_axl) );
4342  vec_module_gap_trs.push_back( toString(module_gap_trs) );
4343  vec_module_gap_axl.push_back( toString(module_gap_axl) );
4344 
4345  // Submodule vectors
4346  vec_number_of_submodules_trs.push_back( toString(number_of_submodules_trs) );
4347  vec_number_of_submodules_axl.push_back( toString(number_of_submodules_axl) );
4348  vec_submodule_gap_trs.push_back( toString(submodule_gap_trs) );
4349  vec_submodule_gap_axl.push_back( toString(submodule_gap_axl) );
4350 
4351  // Crystal vectors
4352  uint32_t nb_tot_trs_cry = (number_of_lyr_elts_trs.size()>0) ?
4353  number_of_lyr_elts_trs[l]*number_of_crystals_trs :
4354  number_of_crystals_trs ;
4355 
4356  uint32_t nb_tot_axl_cry = (number_of_lyr_elts_axl.size()>0) ?
4357  number_of_lyr_elts_axl[l]*number_of_crystals_axl :
4358  number_of_crystals_axl ;
4359 
4360  vec_number_of_crystals_trs.push_back( toString(nb_tot_trs_cry) );
4361  vec_number_of_crystals_axl.push_back( toString(nb_tot_axl_cry) );
4362 
4363 
4364  // Compute the gap from the layer variables
4365  // If those variables have not been set, use the crystals gap previously computed
4366  if(layers_step_trs.size()>0 ||
4367  layers_step_axl.size()>0)
4368  {
4369  if (layers_step_trs[l] - layers_size_trs[l] >= 0)
4370  crystal_gap_trs = layers_step_trs[l] - layers_size_trs[l];
4371 
4372  if (layers_step_axl[l] - layers_size_axl[l] >= 0)
4373  crystal_gap_axl = layers_step_axl[l] - layers_size_axl[l];
4374  }
4375 
4376  vec_crystal_gap_trs.push_back( toString(crystal_gap_trs) );
4377  vec_crystal_gap_axl.push_back( toString(crystal_gap_axl) );
4378 
4379  // Optional
4380  vec_mean_depth_of_interaction.push_back( toString(mean_depth_of_interaction) );
4381  vec_min_angle_diff.push_back( toString(min_angle_diff) );
4382  }
4383  }
4384  else
4385  {
4386  // Layer dimensions = crystal dimensions
4387  layers_size_depth.push_back( crystal_size_depth );
4388  layers_size_trs.push_back( crystal_size_trs );
4389  layers_size_axl.push_back( crystal_size_axl );
4390 
4391 
4392  // Scanner vectors
4393  vec_scanner_radius.push_back( toString(scanner_radius - crystal_size_depth/2) );
4394 
4395  // Rsector vectors
4396  vec_number_of_rsectors_ang.push_back( toString(number_of_rsectors_ang) );
4397  vec_number_of_rsectors_axl.push_back( toString(number_of_rsectors_axl) );
4398  vec_rsector_gap_axl.push_back( toString(rsector_gap_axl) );
4399  vec_rsector_first_angle.push_back( toString(rsector_first_angle) );
4400 
4401  // Module vectors
4402  vec_number_of_modules_trs.push_back( toString(number_of_modules_trs) );
4403  vec_number_of_modules_axl.push_back( toString(number_of_modules_axl) );
4404  vec_module_gap_trs.push_back( toString(module_gap_trs) );
4405  vec_module_gap_axl.push_back( toString(module_gap_axl) );
4406 
4407  // Submodule vectors
4408  vec_number_of_submodules_trs.push_back( toString(number_of_submodules_trs) );
4409  vec_number_of_submodules_axl.push_back( toString(number_of_submodules_axl) );
4410  vec_submodule_gap_trs.push_back( toString(submodule_gap_trs) );
4411  vec_submodule_gap_axl.push_back( toString(submodule_gap_axl) );
4412 
4413  // Crystal vectors
4414  vec_number_of_crystals_trs.push_back( toString(number_of_crystals_trs) );
4415  vec_number_of_crystals_axl.push_back( toString(number_of_crystals_axl) );
4416  vec_crystal_gap_trs.push_back( toString(crystal_gap_trs) );
4417  vec_crystal_gap_axl.push_back( toString(crystal_gap_axl) );
4418 
4419  // Optionnal
4420  vec_mean_depth_of_interaction.push_back( toString(mean_depth_of_interaction) );
4421  vec_min_angle_diff.push_back( toString(min_angle_diff) );
4422 
4423  // Update the real number of layers
4424  number_of_layers = 1;
4425  }
4426 
4427  // Write the .geom file
4428  ofstream fileGeom(a_pathGeom.c_str(), ios::out | ios::trunc);
4429  if(fileGeom)
4430  {
4431  fileGeom <<"# comments" << endl;
4432  fileGeom <<"# Y _________ "<< endl;
4433  fileGeom <<"# | / _ \\ \\ "<< endl;
4434  fileGeom <<"# | | / \\ | |"<< endl;
4435  fileGeom <<"# |_____ Z | | | | |"<< endl;
4436  fileGeom <<"# \\ | | | | |" << endl;
4437  fileGeom <<"# \\ | \\_/ | |" << endl;
4438  fileGeom <<"# X \\___/_____/" << endl;
4439  fileGeom <<"# Left-handed axis orientation"<< endl;
4440  fileGeom <<"# scanner axis is z" << endl;
4441  fileGeom <<"# positions in millimeters"<< endl;
4442  fileGeom <<"# Use comma without space as separator in the tables." << endl;
4443 
4444  fileGeom << ""<< endl;
4445 
4446  // Mandatory fields
4447  fileGeom << "# MANDATORY FIELDS"<< endl;
4448  fileGeom << "modality : " << modality << endl;
4449  fileGeom << "scanner name : " << scanner_name << endl;
4450  fileGeom << "number of elements : " << number_of_elements << endl;
4451  fileGeom << "number of layers : " << number_of_layers << endl;
4452  fileGeom << "" << endl;
4453  fileGeom << "voxels number transaxial : " << voxels_number_trs << endl;
4454  fileGeom << "voxels number axial : " << voxels_number_axl << endl;
4455 
4456  fileGeom << "field of view transaxial : " << fov_trs << endl;
4457  fileGeom << "field of view axial : " << fov_axl << endl << endl;
4458  fileGeom << "description : " << description << endl;
4459  fileGeom << "" << endl;
4460  WriteVector(fileGeom,"scanner radius : ",vec_scanner_radius);
4461  WriteVector(fileGeom,"number of rsectors : ",vec_number_of_rsectors_ang);
4462  WriteVector(fileGeom,"number of crystals transaxial : ",vec_number_of_crystals_trs);
4463  WriteVector(fileGeom, "number of crystals axial : ",vec_number_of_crystals_axl);
4464  fileGeom << ""<< endl;
4465  WriteVector(fileGeom, "crystals size depth : ", layers_size_depth);
4466  WriteVector(fileGeom, "crystals size transaxial : ", layers_size_trs);
4467  WriteVector(fileGeom, "crystals size axial : ", layers_size_axl);
4468  fileGeom << ""<< endl;
4469  fileGeom << ""<< endl;
4470 
4471  // Optional fields
4472  fileGeom << "# OPTIONAL FIELDS"<< endl;
4473  WriteVector(fileGeom,"rsectors first angle : ",vec_rsector_first_angle);
4474  WriteVector(fileGeom, "number of rsectors axial : ",vec_number_of_rsectors_axl);
4475  WriteVector(fileGeom,"rsector gap axial : ",vec_rsector_gap_axl);
4476  WriteVector(fileGeom,"number of modules transaxial : ",vec_number_of_modules_trs);
4477  WriteVector(fileGeom, "number of modules axial : ",vec_number_of_modules_axl);
4478  WriteVector(fileGeom,"module gap transaxial : ",vec_module_gap_trs);
4479  WriteVector(fileGeom,"module gap axial : ",vec_module_gap_axl);
4480  WriteVector(fileGeom,"number of submodules transaxial : ",vec_number_of_submodules_trs);
4481  WriteVector(fileGeom, "number of submodules axial : ",vec_number_of_submodules_axl);
4482  WriteVector(fileGeom,"submodule gap transaxial : ",vec_submodule_gap_trs);
4483  WriteVector(fileGeom,"submodule gap axial : ",vec_submodule_gap_axl);
4484  WriteVector(fileGeom,"crystal gap transaxial : ",vec_crystal_gap_trs);
4485  WriteVector(fileGeom,"crystal gap axial : ",vec_crystal_gap_axl);
4486  WriteVector(fileGeom, "mean depth of interaction : ", vec_mean_depth_of_interaction);
4487  fileGeom << "rotation direction : CCW " << endl; // default for GATE
4488  fileGeom << ""<< endl;
4489 
4490  // Write only if different from default values
4491  if(min_angle_diff > 0.) fileGeom << "min angle difference : " << min_angle_diff << endl;
4492 
4493  // Convert angular span to the CASToR convention
4494  if(rsector_angular_span >= 360.0005 ||
4495  rsector_angular_span <= 359.9995 ) // GATE bounds
4496  {
4497  rsector_angular_span *= (double)number_of_rsectors_ang/(double)(number_of_rsectors_ang-1);
4498  fileGeom << "rsectors angular span : " << rsector_angular_span << endl;
4499  }
4500 
4501  if(rsector_nb_zshifts > 0) fileGeom << "rsectors nbZShift :" << rsector_nb_zshifts << endl;
4502  if(!vec_rsector_Z_Shift.empty()) WriteVector(fileGeom, "rsectors ZShift : ", vec_rsector_Z_Shift);
4503 
4504  fileGeom.close();
4505 
4506  cout << "Output geom file written at :" << a_pathGeom << endl;
4507  }
4508  else
4509  {
4510  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Couldn't open geom file for writing "<< a_pathGeom << " !" << endl);
4511  return 1;
4512  }
4513 
4514 
4515 
4516  return 0;
4517 }
4518 
4519 
4520 
4521 // =====================================================================
4522 // ---------------------------------------------------------------------
4523 // ---------------------------------------------------------------------
4524 // =====================================================================
4525 /*
4526  \fn CreateGeomWithECAT()
4527  \param a_pathMac : string containing the path to a GATE macro file
4528  \param a_pathGeom : string containing the path to a CASToR output geom file
4529  \brief Read a GATE macro file containing the description of an ecat system, and convert it to a geom file
4530  \return 0 if success, positive value otherwise
4531 */
4532 int CreateGeomWithECAT(string a_pathMac, string a_pathGeom)
4533 {
4534  /* Declaring variables */
4535 
4536  // Scanner
4537  string modality;
4538  string scanner_name = GetFileFromPath(a_pathGeom.substr(0,a_pathGeom.find_first_of(".geom")));
4539  double scanner_radius = 0.;
4540  uint32_t number_of_elements = 0;
4541  string description = "ECAT system extracted from GATE macro: " + a_pathMac;
4542 
4543  // blocks
4544  string block_name = "block";
4545  uint32_t number_of_blocks = 1;
4546  uint32_t number_of_blocks_trs = 1;
4547  uint32_t number_of_blocks_axl = 1;
4548  double block_step_trs = 0.;
4549  double block_step_axl = 0.;
4550  double block_gap_trs = 0.;
4551  double block_gap_axl = 0.;
4552  double block_size_Y;
4553  double block_size_Z;
4554  double block_pos_X = 0.;
4555  double block_pos_Y = 0.;
4556  double block_first_angle = 0.;
4557  double block_angular_span = 360.;
4558  uint32_t block_nb_zshifts = 0;
4559  vector <double> vec_block_Z_Shift;
4560  bool is_block_Y_axis = false;
4561 
4562 
4563 
4564  // Crystals
4565  string crystal_name = "crystal";
4566  uint32_t number_of_crystals_trs = 1;
4567  uint32_t number_of_crystals_axl = 1;
4568  double crystal_step_trs = 0.;
4569  double crystal_step_axl = 0.;
4570  double crystal_gap_trs = 0.;
4571  double crystal_gap_axl = 0.;
4572  double crystal_size_depth = 0.;
4573  double crystal_size_trs = 0.;
4574  double crystal_size_axl = 0.;
4575 
4576  // Optional
4577  uint32_t voxels_number_trs;
4578  uint32_t voxels_number_axl;
4579  double fov_trs;
4580  double fov_axl;
4581  double min_angle_diff = 0.;
4582 
4583  vector<string> path_mac_files;
4584  path_mac_files.push_back(a_pathMac);
4585 
4586  // Recover path to all macro files from the main mac file
4587  if(GetGATEMacFiles(a_pathMac , path_mac_files))
4588  {
4589  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()->Error occurred when trying to recover paths to GATE macro files !" << endl);
4590  return 1;
4591  }
4592 
4593 
4594  // Recover aliases of the different parts of the architecture
4595  if(GetGATEAliasesEcat(path_mac_files, block_name, crystal_name, 2) )
4596  {
4597  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()->Error occurred when trying to recover aliases for the elements of the ecat !" << endl);
4598  return 1;
4599  }
4600 
4601 
4602  // Loop to recover all other informations
4603  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
4604  {
4605  ifstream systemMac(path_mac_files[f].c_str(), ios::in);
4606 
4607  string line;
4608  while(getline(systemMac, line))
4609  {
4610  // Scanner
4611  modality = "PET";
4612  vector <string> values;
4613  string entry = "";
4614 
4615 
4616  entry = "/gate/"+block_name+"/placement/setTranslation";
4617  values = CheckGATECommand(entry, line);
4618  if (values.size()>0)
4619  {
4620  if(ConvertFromString(values[0], &block_pos_X) ||
4621  ConvertFromString(values[1], &block_pos_Y) )
4622  {
4623  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4624  return 1;
4625  }
4626 
4627  // Check first block cartesian coordinates is 0 on X or Y axis
4628  // Throw error otherwise
4629  if(block_pos_X!=0 && block_pos_Y !=0)
4630  {
4631  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4632  Cerr(" Block cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
4633  return 1;
4634  }
4635 
4636  // Get the axis on which the first rsector is positionned
4637  if(block_pos_Y!=0) is_block_Y_axis = true;
4638 
4639  scanner_radius += is_block_Y_axis ? abs(block_pos_Y) : abs(block_pos_X) ;
4640  }
4641 
4642 
4643  // Old version accounting on the rsector depth to be equal to the detector depth
4644  // in order to get the position of the detector surface.
4645  // Current version tracks the 'setTranslation' commands to get to the actual detector surface position
4646  /*
4647  entry = is_block_Y_axis ?
4648  "/gate/"+block_name+"/geometry/setYLength" :
4649  "/gate/"+block_name+"/geometry/setXLength";
4650 
4651  values = CheckGATECommand(entry, line);
4652  if (values.size()>0)
4653  {
4654  double block_size = 0.;
4655  if(ConvertFromString(values[0], &block_size) )
4656  {
4657  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4658  return 1;
4659  }
4660 
4661  scanner_radius -= block_size/2;
4662  }
4663  */
4664 
4665 
4666  entry = "/gate/"+block_name+"/geometry/setZLength";
4667  values = CheckGATECommand(entry, line);
4668  if (values.size()>0)
4669  {
4670  if(ConvertFromString(values[0], &fov_axl))
4671  {
4672  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4673  return 1;
4674  }
4675  // 4mm voxels by default
4676  voxels_number_axl = fov_axl/4 + 1;
4677  }
4678 
4679 
4680  // blocks
4681  entry = "/gate/"+block_name+"/ring/setRepeatNumber";
4682  values = CheckGATECommand(entry, line);
4683  if (values.size()>0)
4684  {
4685  if(ConvertFromString(values[0], &number_of_blocks))
4686  {
4687  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4688  return 1;
4689  }
4690  }
4691 
4692 
4693  entry = "/gate/"+block_name+"/ring/setFirstAngle";
4694  values = CheckGATECommand(entry, line);
4695  if (values.size()>0)
4696  {
4697  if(ConvertFromString(values[0], &block_first_angle))
4698  {
4699  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4700  return 1;
4701  }
4702  }
4703 
4704 
4705  entry = "/gate/"+block_name+"/ring/setAngularSpan";
4706  values = CheckGATECommand(entry, line);
4707  if (values.size()>0)
4708  {
4709  if(ConvertFromString(values[0], &block_angular_span))
4710  {
4711  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4712  return 1;
4713  }
4714  }
4715 
4716  entry = "/gate/"+block_name+"/ring/setModuloNumber";
4717  values = CheckGATECommand(entry, line);
4718  if (values.size()>0)
4719  {
4720  if(ConvertFromString(values[0], &block_nb_zshifts) )
4721  {
4722  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4723  return 1;
4724  }
4725  }
4726 
4727  for (int i=1; i<8; i++)
4728  {
4729  entry = "/gate/"+block_name+"/ring/setZShift"+toString(i);
4730  values = CheckGATECommand(entry, line);
4731  if (values.size()>0)
4732  {
4733  double zshift;
4734  if(ConvertFromString(values[0], &zshift))
4735  {
4736  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4737  return 1;
4738  }
4739  vec_block_Z_Shift.push_back(zshift);
4740  }
4741  }
4742 
4743 
4744 
4745 
4746  // Modules
4747  entry = "/gate/"+block_name+"/linear/setRepeatNumber";
4748  values = CheckGATECommand(entry, line);
4749  if (values.size()>0)
4750  {
4751  if(ConvertFromString(values[0], &number_of_blocks_axl))
4752  {
4753  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4754  return 1;
4755  }
4756  }
4757 
4758 
4759  entry = "/gate/"+block_name+"/linear/setRepeatVector";
4760  values = CheckGATECommand(entry, line);
4761  if (values.size()>0)
4762  {
4763  if(ConvertFromString(values[2], &block_step_axl))
4764  {
4765  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4766  return 1;
4767  }
4768  }
4769 
4770 
4771 
4772  // Crystals
4773 
4774  entry = "/gate/"+crystal_name+"/placement/setTranslation";
4775  values = CheckGATECommand(entry, line);
4776 
4777  FLTNB crystal_pos_X =0.,
4778  crystal_pos_Y =0.;
4779 
4780  if (values.size()>0)
4781  {
4782  if(ConvertFromString(values[0], &crystal_pos_X) ||
4783  ConvertFromString(values[1], &crystal_pos_Y) )
4784  {
4785  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4786  return 1;
4787  }
4788 
4789  // Check first crystal cartesian coordinates is 0 on X or Y axis
4790  // Throw error otherwise
4791  if(crystal_pos_X!=0 && crystal_pos_Y !=0)
4792  {
4793  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4794  Cerr(" Block cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
4795  return 1;
4796  }
4797 
4798  scanner_radius += is_block_Y_axis ? crystal_pos_Y : crystal_pos_X ;
4799  }
4800 
4801  // Adjust scanner radius (from center to block surface) according to crystal size
4802  entry = is_block_Y_axis ?
4803  "/gate/"+crystal_name+"/geometry/setYLength" :
4804  "/gate/"+crystal_name+"/geometry/setXLength";
4805 
4806  values = CheckGATECommand(entry, line);
4807  if (values.size()>0)
4808  {
4809  double crystal_size = 0.;
4810  if(ConvertFromString(values[0], &crystal_size) )
4811  {
4812  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
4813  return 1;
4814  }
4815 
4816  scanner_radius -= crystal_size/2;
4817  }
4818 
4819 
4820 
4821  // assumes that first block is positionned on the x-axis
4822  entry = is_block_Y_axis ?
4823  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberX":
4824  "/gate/"+crystal_name+"/cubicArray/setRepeatNumberY";
4825 
4826  values = CheckGATECommand(entry, line);
4827  if (values.size()>0)
4828  {
4829  if(ConvertFromString(values[0], &number_of_crystals_trs))
4830  {
4831  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4832  return 1;
4833  }
4834  }
4835 
4836  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatNumberZ";
4837  values = CheckGATECommand(entry, line);
4838  if (values.size()>0)
4839  {
4840  if(ConvertFromString(values[0], &number_of_crystals_axl))
4841  {
4842  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4843  return 1;
4844  }
4845  }
4846 
4847 
4848  entry = "/gate/"+crystal_name+"/cubicArray/setRepeatVector";
4849  values = CheckGATECommand(entry, line);
4850  if (values.size()>0)
4851  {
4852  string trs_step = is_block_Y_axis ?
4853  values[0] :
4854  values[1] ;
4855 
4856  if(ConvertFromString(values[1], &crystal_step_trs) ||
4857  ConvertFromString(values[2], &crystal_step_axl) )
4858  {
4859  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4860  return 1;
4861  }
4862  }
4863 
4864 
4865  // assumes that first block is positionned on the x-axis
4866  entry = "/gate/"+crystal_name+"/geometry/setXLength";
4867  values = CheckGATECommand(entry, line);
4868  if (values.size()>0)
4869  {
4870  double x_length;
4871  if(ConvertFromString(values[0], &x_length))
4872  {
4873  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4874  return 1;
4875  }
4876 
4877  if (is_block_Y_axis)
4878  crystal_size_trs = x_length;
4879  else
4880  crystal_size_depth = x_length;
4881  }
4882 
4883 
4884  // assumes that first block is positionned on the x-axis
4885  entry = "/gate/"+crystal_name+"/geometry/setYLength";
4886  values = CheckGATECommand(entry, line);
4887  if (values.size()>0)
4888  {
4889  double y_length;
4890  if(ConvertFromString(values[0], &y_length))
4891  {
4892  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4893  return 1;
4894  }
4895 
4896  if (is_block_Y_axis)
4897  crystal_size_depth = y_length;
4898  else
4899  crystal_size_trs = y_length;
4900  }
4901 
4902  entry = "/gate/"+crystal_name+"/geometry/setZLength";
4903  values = CheckGATECommand(entry, line);
4904  if (values.size()>0)
4905  {
4906  if(ConvertFromString(values[0], &crystal_size_axl))
4907  {
4908  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4909  return 1;
4910  }
4911  }
4912 
4913 
4914 
4915 
4916  entry = "/gate/digitizer/Coincidences/minSectorDifference";
4917  values = CheckGATECommand(entry, line);
4918  if (values.size()>0)
4919  {
4920  double min_sector_diff;
4921  if(ConvertFromString(values[0], &min_sector_diff))
4922  {
4923  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Conversion error occurred while trying to parse line: " << line<< endl);
4924  return 1;
4925  }
4926  min_angle_diff = 360/number_of_blocks*min_sector_diff;
4927  }
4928 
4929  }
4930  systemMac.close();
4931  }
4932 
4933  number_of_elements = number_of_blocks *
4934  number_of_blocks_axl *
4935  number_of_crystals_trs *
4936  number_of_crystals_axl;
4937 
4938 
4939 
4940  // Transaxial FOV defined as scanner radius / 2
4941  fov_trs = (2*scanner_radius ) / 1.5;
4942 
4943  // 4mm voxels by default
4944  voxels_number_trs = ( number_of_crystals_trs
4945  * number_of_blocks_trs)
4946  / 3;
4947 
4948 
4949  if (crystal_step_axl - crystal_size_axl >= 0)
4950  crystal_gap_axl = crystal_step_axl - crystal_size_axl;
4951 
4952  if (crystal_step_trs - crystal_size_trs >= 0)
4953  crystal_gap_trs = crystal_step_trs - crystal_size_trs;
4954 
4955 
4956  // Compute submodule size from crystals size, gaps & number
4957  block_size_Z = crystal_size_axl*number_of_crystals_axl + crystal_gap_axl*(number_of_crystals_axl-1);
4958  block_size_Y = crystal_size_trs*number_of_crystals_trs + crystal_gap_trs*(number_of_crystals_trs-1);
4959 
4960  // Compute submodule gaps
4961  if (block_step_axl - block_size_Z >= 0)
4962  block_gap_axl = block_step_axl - block_size_Z;
4963 
4964  if (block_step_trs - block_size_Y >= 0)
4965  block_gap_trs = block_step_trs - block_size_Y;
4966 
4967  // CASToR x and y axis for rotation inverted in comparison with GATE
4968  block_first_angle -= round(atan2f(block_pos_X , block_pos_Y) * 180. / M_PI);
4969 
4970 
4971  // Writing the .geom file
4972  ofstream fileGeom(a_pathGeom.c_str(), ios::out | ios::trunc);
4973 
4974  if(fileGeom)
4975  {
4976  fileGeom <<"# comments" << endl;
4977  fileGeom <<"# Y _________ "<< endl;
4978  fileGeom <<"# | / _ \\ \\ "<< endl;
4979  fileGeom <<"# | | / \\ | |"<< endl;
4980  fileGeom <<"# |_____ Z | | | | |"<< endl;
4981  fileGeom <<"# \\ | | | | |" << endl;
4982  fileGeom <<"# \\ | \\_/ | |" << endl;
4983  fileGeom <<"# X \\___/_____/" << endl;
4984  fileGeom <<"# Left-handed axis orientation"<< endl;
4985  fileGeom <<"# scanner axis is z" << endl;
4986  fileGeom <<"# positions in millimeters"<< endl;
4987  fileGeom <<"# Use comma without space as separator in the tables." << endl;
4988 
4989 
4990  fileGeom << "modality : " << modality << endl;
4991  fileGeom << "scanner name : " << scanner_name << endl;
4992  fileGeom << "number of elements : " << number_of_elements << endl;
4993  fileGeom << "number of layers : " << "1" << endl;
4994  fileGeom << "" << endl;
4995  fileGeom << "# default reconstruction parameters" << endl;
4996  fileGeom << "voxels number transaxial : " << voxels_number_trs << endl;
4997  fileGeom << "voxels number axial : " << voxels_number_axl << endl;
4998 
4999  fileGeom << "field of view transaxial : " << fov_trs << endl;
5000  fileGeom << "field of view axial : " << fov_axl << endl;
5001  fileGeom << "" << endl;
5002  fileGeom << "description : " << description << endl;
5003  fileGeom << "" << endl;
5004  fileGeom << "scanner radius : " << scanner_radius << endl;
5005  fileGeom << "number of rsectors : " << number_of_blocks << endl;
5006  fileGeom << "number of crystals transaxial : " << number_of_crystals_trs << endl;
5007  fileGeom << "number of crystals axial : " << number_of_crystals_axl << endl;
5008 
5009  fileGeom << ""<< endl;
5010  fileGeom << "# The 4 following parameters could be defined in arrays (SizeLayer1,SizeLayer2,SizeLayer3,etc..) if their is more than one layer"<< endl;
5011  fileGeom << "crystals size depth : " << crystal_size_depth << endl;
5012  fileGeom << "crystals size transaxial : " << crystal_size_trs << endl;
5013  fileGeom << "crystals size axial : " << crystal_size_axl << endl;
5014  fileGeom << ""<< endl;
5015 
5016  // Optional fields
5017  fileGeom << "rsectors first angle : " << block_first_angle << endl;
5018  fileGeom << "number of modules transaxial : " << number_of_blocks_trs << endl;
5019  fileGeom << "number of modules axial : " << number_of_blocks_axl << endl;
5020  fileGeom << "module gap transaxial : " << block_gap_trs << endl;
5021  fileGeom << "module gap axial : " << block_gap_axl << endl;
5022  fileGeom << "crystal gap transaxial : " << crystal_gap_trs << endl;
5023  fileGeom << "crystal gap axial : " << crystal_gap_axl << endl;
5024  fileGeom << "rotation direction : CCW " << endl; // default for GATE
5025  fileGeom << ""<< endl;
5026 
5027  // Write only if different from default values
5028  if(min_angle_diff > 0.) fileGeom << "min angle difference : " << min_angle_diff << endl;
5029 
5030  // Convert angular span to the CASToR convention
5031  if(block_angular_span >= 360.0005 ||
5032  block_angular_span <= 359.9995 ) // GATE bounds
5033  {
5034  block_angular_span *= (double)(number_of_blocks)/(double)(number_of_blocks-1);
5035  fileGeom << "rsectors angular span : " << block_angular_span << endl;
5036  }
5037 
5038  if(block_nb_zshifts > 0) fileGeom << "rsectors nbZShift :" << block_nb_zshifts << endl;
5039  if(!vec_block_Z_Shift.empty()) WriteVector(fileGeom, "rsectors ZShift : ", vec_block_Z_Shift);
5040 
5041  fileGeom.close();
5042 
5043  Cout("Output geom file written at :" << a_pathGeom << endl);
5044  }
5045  else
5046  {
5047  Cerr("***** dataConversionUtilities::CreateGeomWithECAT()-> Couldn't open geom file for writing "<< a_pathGeom << " !" << endl);
5048  return 1;
5049  }
5050 
5051  return 0;
5052 }
5053 
5054 
5055 
5056 
5057 // =====================================================================
5058 // ---------------------------------------------------------------------
5059 // ---------------------------------------------------------------------
5060 // =====================================================================
5061 /*
5062  \fn CreateGeomWithSPECT()
5063  \param a_pathMac : string containing the path to a GATE macro file
5064  \param a_pathGeom : string containing the path to a CASToR output geom file
5065  \brief Read a GATE macro file containing the description of a SPECThead system, and convert it to a geom file
5066  \return 0 if success, positive value otherwise
5067 */
5068 int CreateGeomWithSPECT(string a_pathMac, string a_pathGeom)
5069 {
5070  /* Declaring variables */
5071  string modality;
5072  string scanner_name = GetFileFromPath(a_pathGeom.substr(0,a_pathGeom.find_first_of(".geom")));
5073  FLTNB scanner_radius = -1.;
5074  string description = "SPECT camera extracted from GATE macro: " + a_pathMac;
5075 
5076  // head(s)
5077  string head_name = "SPECThead"; // not used. Correspond to SPECThead
5078  uint32_t number_of_heads = 0;
5079  FLTNB head_pos_X = 0.;
5080  FLTNB head_pos_Y = 0.;
5081  FLTNB head_first_angle = 0.;
5082  FLTNB head_angular_pitch = -1.;
5083  string head_orbit_name = "";
5084  FLTNB head_rotation_speed = 0.;
5085  bool is_head_Y_axis = false;
5086 
5087  // crystal
5088  string crystal_name = "crystal";
5089  FLTNB crystal_size_trs = 0.;
5090  FLTNB crystal_size_axl = 0.;
5091  FLTNB crystal_depth = 0;
5092 
5093  // pixel
5094  string pixel_name = "pixel";
5095  uint32_t number_of_pixels_trs = 1;
5096  uint32_t number_of_pixels_axl = 1;
5097  FLTNB pix_size_trs = 0.;
5098  FLTNB pix_size_axl = 0.;
5099  FLTNB pix_step_trs = 0.;
5100  FLTNB pix_step_axl = 0.;
5101  FLTNB pix_gap_trs = 0.;
5102  FLTNB pix_gap_axl = 0.;
5103 
5104  // collimator parameters
5105  string focal_model_trs = "constant";
5106  uint16_t nb_coeff_model_trs = 1;
5107  FLTNB coeff_model_trs = 0.;
5108  string focal_model_axl = "constant";
5109  uint16_t nb_coeff_model_axl = 1;
5110  FLTNB coeff_model_axl = 0.;
5111 
5112  // others
5113  uint32_t voxels_number_trs;
5114  uint32_t voxels_number_axl;
5115  double fov_trs;
5116  double fov_axl;
5117 
5118  vector<string> path_mac_files;
5119  path_mac_files.push_back(a_pathMac);
5120 
5121  // Recover path to all macro files from the main mac file
5122  if(GetGATEMacFiles(a_pathMac , path_mac_files))
5123  {
5124  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()->Error occurred when trying to recover paths to GATE macro files !" << endl);
5125  return 1;
5126  }
5127 
5128 
5129  // Recover aliases of the different parts of the architecture
5130  if(GetGATEAliasesSPECT(path_mac_files, head_name, crystal_name, pixel_name, 2) )
5131  {
5132  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()->Error occurred when trying to recover aliases for the elements of the SPECThead !" << endl);
5133  return 1;
5134  }
5135 
5136  // Loop to recover all other informations
5137  for(uint16_t f=0 ; f<path_mac_files.size() ; f++)
5138  {
5139  ifstream systemMac(path_mac_files[f].c_str(), ios::in);
5140 
5141  string line;
5142  while(getline(systemMac, line))
5143  {
5144  // Scanner
5145  modality = "SPECT_CONVERGENT";
5146  vector <string> values;
5147  string entry = "";
5148 
5149  // assumes that first block is positionned on the x-axis
5150  entry = "/gate/"+head_name+"/placement/setTranslation";
5151  values = CheckGATECommand(entry, line);
5152  if (values.size()>0)
5153  {
5154  if(ConvertFromString(values[0], &head_pos_X) ||
5155  ConvertFromString(values[1], &head_pos_Y) )
5156  {
5157  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5158  return 1;
5159  }
5160 
5161  // Check first block cartesian coordinates is 0 on X or Y axis
5162  // Throw error otherwise
5163  if(head_pos_X!=0 && head_pos_Y !=0)
5164  {
5165  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5166  Cerr(" Block cartesian coordinates on either the X or Y axis expected to be equal to 0 "<< endl);
5167  return 1;
5168  }
5169 
5170  // Get the axis on which the first rsector is positionned
5171  if(head_pos_Y!=0) is_head_Y_axis = true;
5172 
5173  scanner_radius = is_head_Y_axis ? abs(head_pos_Y) : abs(head_pos_X) ;
5174  }
5175 
5176 
5177  entry = "/gate/"+head_name+"/geometry/setZLength";
5178  values = CheckGATECommand(entry, line);
5179  if (values.size()>0)
5180  {
5181  if(ConvertFromString(values[0], &fov_axl))
5182  {
5183  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5184  return 1;
5185  }
5186  // 4mm voxels by default
5187  voxels_number_axl = fov_axl/4 + 1;
5188  }
5189 
5190 
5191  entry = "/gate/"+head_name+"/ring/setRepeatNumber";
5192  values = CheckGATECommand(entry, line);
5193  if (values.size()>0)
5194  {
5195  if(ConvertFromString(values[0], &number_of_heads))
5196  {
5197  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5198  return 1;
5199  }
5200  }
5201 
5202 
5203  entry = "/gate/"+head_name+"/ring/setFirstAngle";
5204  values = CheckGATECommand(entry, line);
5205  if (values.size()>0)
5206  {
5207  if(ConvertFromString(values[0], &head_first_angle))
5208  {
5209  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5210  return 1;
5211  }
5212  }
5213 
5214 
5215  entry = "/gate/"+head_name+"/ring/setAngularPitch";
5216  values = CheckGATECommand(entry, line);
5217  if (values.size()>0)
5218  {
5219  if(ConvertFromString(values[0], &head_angular_pitch))
5220  {
5221  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5222  return 1;
5223  }
5224  }
5225 
5226  entry = "/gate/"+head_name+"/moves/insert";
5227  values = CheckGATECommand(entry, line);
5228  if (values.size()>0)
5229  {
5230  if(ConvertFromString(values[0], &head_orbit_name))
5231  {
5232  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5233  return 1;
5234  }
5235  }
5236 
5237  entry = "/gate/"+head_orbit_name+"/setSpeed";
5238  values = CheckGATECommand(entry, line);
5239  if (values.size()>0)
5240  {
5241  if(ConvertFromString(values[0], &head_rotation_speed))
5242  {
5243  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Conversion error occurred while trying to parse line: " << line<< endl);
5244  return 1;
5245  }
5246  }
5247 
5248 
5249 
5250  // --- Crystals ---
5251  entry = "/gate/"+crystal_name+"/geometry/setXLength";
5252  values = CheckGATECommand(entry, line);
5253  if (values.size()>0)
5254  {
5255  double x_length;
5256  if(ConvertFromString(values[0], &x_length) )
5257  {
5258  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5259  return 1;
5260  }
5261 
5262  if (is_head_Y_axis)
5263  crystal_size_trs = x_length;
5264  else
5265  crystal_depth = x_length;
5266  }
5267 
5268  entry = "/gate/"+crystal_name+"/geometry/setYLength";
5269  values = CheckGATECommand(entry, line);
5270  if (values.size()>0)
5271  {
5272  double y_length;
5273  if(ConvertFromString(values[0], &y_length) )
5274  {
5275  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5276  return 1;
5277  }
5278 
5279  if (is_head_Y_axis)
5280  crystal_depth = y_length;
5281  else
5282  crystal_size_trs = y_length;
5283 
5284  }
5285 
5286  entry = "/gate/"+crystal_name+"/geometry/setZLength";
5287  values = CheckGATECommand(entry, line);
5288  if (values.size()>0)
5289  {
5290  if(ConvertFromString(values[0], &crystal_size_axl) )
5291  {
5292  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5293  return 1;
5294  }
5295  }
5296 
5297 
5298 
5299 
5300 
5301  // --- Pixels ---
5302  entry = is_head_Y_axis ?
5303  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberX":
5304  "/gate/"+pixel_name+"/cubicArray/setRepeatNumberY";
5305 
5306 
5307  values = CheckGATECommand(entry, line);
5308  if (values.size()>0)
5309  {
5310  if(ConvertFromString(values[0], &number_of_pixels_trs) )
5311  {
5312  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5313  return 1;
5314  }
5315  }
5316 
5317  entry = "/gate/"+pixel_name+"/cubicArray/setRepeatNumberZ";
5318  values = CheckGATECommand(entry, line);
5319  if (values.size()>0)
5320  {
5321  if(ConvertFromString(values[0], &number_of_pixels_axl) )
5322  {
5323  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5324  return 1;
5325  }
5326  }
5327 
5328 
5329  entry = "/gate/"+pixel_name+"/geometry/setXLength";
5330  values = CheckGATECommand(entry, line);
5331  if (values.size()>0)
5332  {
5333  double x_length;
5334  if(ConvertFromString(values[0], &x_length) )
5335  {
5336  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5337  return 1;
5338  }
5339 
5340  if (is_head_Y_axis)
5341  pix_size_trs = x_length;
5342  }
5343 
5344  entry = "/gate/"+pixel_name+"/geometry/setYLength";
5345  values = CheckGATECommand(entry, line);
5346  if (values.size()>0)
5347  {
5348  double y_length;
5349  if(ConvertFromString(values[0], &y_length) )
5350  {
5351  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5352  return 1;
5353  }
5354 
5355  if (!is_head_Y_axis)
5356  pix_size_trs = y_length;
5357 
5358  }
5359 
5360  entry = "/gate/"+pixel_name+"/geometry/setZLength";
5361  values = CheckGATECommand(entry, line);
5362  if (values.size()>0)
5363  {
5364  if(ConvertFromString(values[0], &pix_size_axl) )
5365  {
5366  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5367  return 1;
5368  }
5369  }
5370 
5371 
5372  entry = "/gate/"+pixel_name+"/cubicArray/setRepeatVector";
5373  values = CheckGATECommand(entry, line);
5374  if (values.size()>0)
5375  {
5376  string trs_step = is_head_Y_axis ?
5377  values[0] :
5378  values[1] ;
5379 
5380  if(ConvertFromString(trs_step, &pix_step_trs) ||
5381  ConvertFromString(values[2], &pix_step_axl) )
5382  {
5383  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5384  return 1;
5385  }
5386  }
5387 
5388 
5389  // collimator parameter
5390  entry = is_head_Y_axis ?
5391  "/gate/fanbeam/geometry/setFocalDistanceY":
5392  "/gate/fanbeam/geometry/setFocalDistanceX";
5393 
5394  entry = "/gate/fanbeam/geometry/setFocalDistanceX";
5395  values = CheckGATECommand(entry, line);
5396  if (values.size()>0)
5397  {
5398  if(ConvertFromString(values[0], &coeff_model_trs) )
5399  {
5400  Cerr("***** dataConversionUtilities::CreateGeomWithCylindrical()-> Conversion error occurred while trying to parse line: " << line<< endl);
5401  return 1;
5402  }
5403 
5404  focal_model_trs = "polynomial";
5405  }
5406 
5407  }
5408  systemMac.close();
5409  }
5410 
5411  // Transaxial FOV defined as scanner radius / 2
5412  fov_trs = scanner_radius/2;
5413  // 4mm voxels by default
5414  voxels_number_trs = fov_trs/2 + 1;
5415 
5416  uint32_t nb_pixels = number_of_pixels_axl * number_of_pixels_trs;
5417 
5418  pix_size_axl = nb_pixels>1 ? pix_size_axl : crystal_size_axl;
5419  pix_size_trs = nb_pixels>1 ? pix_size_trs : crystal_size_trs;
5420 
5421  // Compute gaps
5422  if (pix_step_axl - pix_size_axl >= 0)
5423  pix_gap_axl = pix_step_axl - pix_size_axl;
5424 
5425  if (pix_step_trs - pix_size_trs >= 0)
5426  pix_gap_trs = pix_step_trs - pix_size_trs;
5427 
5428 
5429  // CASToR x and y axis for rotation inverted in comparison with GATE
5430  head_first_angle = round(atan2f(head_pos_X , head_pos_Y) * 180. / M_PI)
5431  - head_first_angle;
5432 
5433 
5434  // Writing the .geom file
5435  ofstream fileGeom(a_pathGeom.c_str(), ios::out | ios::trunc);
5436 
5437  if(fileGeom)
5438  {
5439  fileGeom << "modality : " << modality << endl;
5440  fileGeom << "scanner name : " << scanner_name << endl;
5441  fileGeom << "number of detector heads : " << number_of_heads << endl;
5442  fileGeom << "trans number of pixels : " << number_of_pixels_trs << endl;
5443  fileGeom << "trans pixel size : " << pix_size_trs << endl;
5444  fileGeom << "trans gap size : " << pix_gap_trs << endl;
5445  fileGeom << "axial number of pixels : " << number_of_pixels_axl << endl;
5446  fileGeom << "axial pixel size : " << pix_size_axl << endl;
5447  fileGeom << "axial gap size : " << pix_gap_axl << endl;
5448 
5449  fileGeom << "detector depth : " << crystal_depth << endl;
5450 
5451  fileGeom << "scanner radius : " << scanner_radius;
5452  for(size_t h=1 ; h<number_of_heads ; h++)
5453  fileGeom << "," << scanner_radius;
5454  fileGeom << endl;
5455 
5456  fileGeom << "# Collimator configuration : "<< endl << endl;
5457  for(size_t h=0 ; h<number_of_heads ; h++)
5458  {
5459  fileGeom << "head" << h+1 << ":" << endl;
5460  fileGeom << "trans focal model: " << focal_model_trs << endl;
5461  fileGeom << "trans number of coef model: " << nb_coeff_model_trs << endl;
5462  fileGeom << "trans parameters: " << coeff_model_trs << endl;
5463  fileGeom << "axial focal model: " << focal_model_axl << endl;
5464  fileGeom << "axial number of coef model: " << nb_coeff_model_axl << endl;
5465  fileGeom << "axial parameters: " << coeff_model_axl << endl;
5466  fileGeom << endl;
5467  }
5468 
5469  fileGeom << "" << endl;
5470  fileGeom << "# default reconstruction parameters" << endl;
5471  fileGeom << "voxels number transaxial : " << voxels_number_trs << endl;
5472  fileGeom << "voxels number axial : " << voxels_number_axl << endl;
5473 
5474  fileGeom << "field of view transaxial : " << fov_trs << endl;
5475  fileGeom << "field of view axial : " << fov_axl << endl << endl ;
5476  fileGeom << ""<< endl;
5477 
5478  fileGeom << "# description" << endl;
5479  fileGeom << "description : " << description << endl;
5480 
5481  fileGeom.close();
5482 
5483  Cout("Output geom file written at :" << a_pathGeom << endl);
5484  }
5485  else
5486  {
5487  Cerr("***** dataConversionUtilities::CreateGeomWithSPECT()-> Couldn't open geom file for writing "<< a_pathGeom << " !" << endl);
5488  return 1;
5489  }
5490 
5491  return 0;
5492 }
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 &nRsectorsAxial, uint32_t &nRsectorsAngPos, bool &invert_det_order, int &rsector_id_order, uint32_t &start_time_ms, uint32_t &duration_ms, FLTNB &pet_coinc_window, bool &lyr_rpt_flag, int vb)
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 ...
string GetPathOfFile(const string &a_pathToFile)
Simply return the path to the directory of a file path string passed in parameter.
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.
#define Cerr(MESSAGE)
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...
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...
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 ...
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 ComputeKindGATEEvent(int32_t eventID1, int32_t eventID2, int comptonPhantom1, int comptonPhantom2, int rayleighPhantom1, int rayleighPhantom2)
#define GEO_ROT_CCW
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.
uint32_t ConvertIDcylindrical(uint32_t nRsectorsAngPos, uint32_t nRsectorsAxial, bool a_invertDetOrder, int a_rsectorIdOrder, bool a_lyrRptFlag, 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)
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, FLTNB &pet_coinc_window, int vb)
int WriteVector(ofstream &file, const string &a_key, vector< T > a_vals)
Write the key and its values in the file provided in parameter.
vector< string > Split(string a_line)
Split the line provided in parameter into a vector of strings (separator is blankspace) ...
void ConvertValuesTomm(vector< string > &ap_v)
Check if the vector of strings passed in parameter contains the &#39;cm&#39; unit In this case...
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 ...
int GetGATESystemType(const string &a_pathMac)
Read a GATE macro file and identify the system type from the &#39;gate/systems/&#39; command lines...
#define KEYWORD_MANDATORY
#define KEYWORD_OPTIONAL
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 ...
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...
int IntfKeyGetRecurringValueFromFile(const string &a_pathToHeader, const string &a_key, T *ap_return, int a_nbElts, int a_mandatoryFlag, uint16_t a_nbOccurrences)
int ConvertFromString(const string &a_str, string *a_result)
Copy the &#39;a_str&#39; string in the position pointed by &#39;a_result&#39;.
int GetGATEMacFiles(const string &a_pathMac, vector< string > &ap_pathToMacFiles)
Extract the paths to each macro file contained in the main macro file.
string toString(T a_val)
Convert a value of any type into string.
string GetFileFromPath(const string &a_pathToFile)
Simply return the file from a path string passed in parameter.
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...
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...
#define Cout(MESSAGE)
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...
#define GEO_ROT_CW