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