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