8 #include "gVariables.hh" 10 #include "oImageDimensionsAndQuantification.hh" 11 #include "vDataFile.hh" 12 #include "iDataFilePET.hh" 13 #include "iDataFileSPECT.hh" 14 #include "iDataFileCT.hh" 15 #include "sOutputManager.hh" 16 #include "sRandomNumberGenerator.hh" 35 cout <<
"Usage: castor-makeReplicates -df datafile.cdh -(f/d)out output (-rep replicates || -down factor) [settings]" << endl;
37 cout <<
"This program can be used to build replicates of less statistics than the provided input CASToR datafile by the use" << endl;
38 cout <<
"of the '-rep' options and choosing the number of replicates. It can also be used to create only one datafile by" << endl;
39 cout <<
"down-scaling the statistics by the use of the '-down' option. The input datafile is assumed to be a list-mode." << endl;
41 cout <<
"If the '-rep' option is used, based on the provided number of replicates, the latter are built based on the time" << endl;
42 cout <<
"flag of each event: a pseudo gating strategy is used where each gate will correspond to a replicate. To avoid" << endl;
43 cout <<
"seeing a difference between replicates when a high number is required, the pseudo gate duration has to be as small" << endl;
44 cout <<
"as possible. The default value is thus 2 ms." << endl;
46 cout <<
"If the '-down' option is used, based on the provided down-sampling factor ]0.;1.[, for each event, a random number" << endl;
47 cout <<
"is shot to decide whether the event is kept or not." << endl;
48 cout <<
"All additive corrections as well as the quantification factor are modified accordingly to keep the same image quantification." << endl;
50 cout <<
"[Mandatory parameters]:" << endl;
51 cout <<
" -df datafile.cdh : Give a CASToR list-mode datafile." << endl;
52 cout <<
" -fout name : Give the root name for all output files (no default, alternative to -dout)" << endl;
53 cout <<
" -dout name : Give the name of the output directory where all output files will be written (no default, alternative to -fout)" << endl;
54 cout <<
" One of the two following options has to be chosen: " << endl;
55 cout <<
" -rep value : Give the number of replicates to be built using a pseudo-gating strategy." << endl;
56 cout <<
" -down value : Give the down-sampling factor to build only one file with less statistics ]0.;1.[." << endl;
58 cout <<
"[Options]:" << endl;
59 cout <<
" -rng : Give a seed for the random number generator (should be >=0)" << endl;
60 cout <<
" -gate value : Give the pseudo gate duration in milliseconds (default: 2)" << endl;
61 cout <<
" -vb value : Give the verbosity level, from 0 (no verbose) to 2 (default: 1)" << endl;
62 cout <<
" --help,-h,-help : Print out this help page." << endl;
65 cout <<
" Build date: " << BUILD_DATE << endl;
69 cout <<
" This program is part of the CASToR release version " <<
CASTOR_VERSION <<
"." << endl;
82 int main(
int argc,
char** argv)
90 MPI_Init(&argc, &argv);
91 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
92 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
93 if (mpi_rank!=0)
return 0;
112 string datafile =
"";
119 string path_dout =
"";
121 string path_fout =
"";
128 int nb_replicates = -1;
130 uint32_t gate_duration = 2;
136 int64_t random_generator_seed = -1;
143 for (
int i=1; i<argc; i++)
146 string option = (string)argv[i];
153 if (option==
"-h" || option==
"--help" || option==
"-help")
159 else if (option==
"-rng")
163 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
168 Cerr(
"***** castor-makeReplicates() -> Exception when trying to read provided number '" << random_generator_seed <<
" for option: " << option << endl);
174 else if (option==
"-rep")
178 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
183 Cerr(
"***** castor-makeReplicates() -> Exception when trying to read provided number of replicates '" << nb_replicates <<
" for option: " << option << endl);
189 else if (option==
"-gate")
193 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
198 Cerr(
"***** castor-makeReplicates() -> Exception when trying to read provided pseudo gate duration '" << gate_duration <<
" for option: " << option << endl);
204 else if (option==
"-down")
208 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
213 Cerr(
"***** castor-makeReplicates() -> Exception when trying to read provided down-sampling factor '" << down_sampling <<
" for option: " << option << endl);
219 else if (option==
"-vb")
223 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
228 Cerr(
"***** castor-makeReplicates() -> Exception when trying to read provided verbosity level '" << verbose <<
" for option: " << option << endl);
239 else if (option==
"-df")
243 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
246 datafile = (string)argv[i+1];
255 else if (option==
"-dout")
259 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
262 path_dout = argv[i+1];
266 else if (option==
"-fout")
270 Cerr(
"***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
273 path_fout = argv[i+1];
283 Cerr(
"***** castor-makeReplicates() -> Unknown option '" << option <<
"' !" << endl);
295 Cerr(
"***** castor-makeReplicates() -> Please provide an input datafile !" << endl);
299 if (path_fout.empty() && path_dout.empty())
301 Cerr(
"***** castor-makeReplicates() -> Please provide an output option for output files (-fout or -dout) !" << endl);
305 if (!path_fout.empty() && !path_dout.empty())
307 Cerr(
"***** castor-makeReplicates() -> Please provide either output option -fout or -dout but not both !" << endl);
311 if (nb_replicates==-1 && down_sampling==-1.)
313 Cerr(
"***** castor-makeReplicates() -> Please provide one of the two following options '-rep' or '-down' !" << endl);
317 if (down_sampling==-1. && nb_replicates<1)
319 Cerr(
"***** castor-makeReplicates() -> Please provide a correct number of replicates (at least 2) !" << endl);
323 if (down_sampling==-1. && gate_duration<1)
325 Cerr(
"***** castor-makeReplicates() -> Please provide a correct pseudo gate duration in milliseconds (at least 1) !" << endl);
329 if (nb_replicates==-1 && (down_sampling<=0. || down_sampling>=1.))
331 Cerr(
"***** castor-makeReplicates() -> Please provide a correct down-sampling factor ]0.;1.[ !" << endl);
346 Cerr(
"***** castor-makeReplicates() -> A problem occurred while initializing output directory !" << endl);
352 Cerr(
"***** castor-makeReplicates() -> A problem occurred while logging command line arguments !" << endl);
364 int one_generator = 1;
365 if (random_generator_seed>=0) p_RandomNumberGenerator->
Initialize(random_generator_seed, no_thread, one_generator);
366 else p_RandomNumberGenerator->
Initialize(no_thread, one_generator);
374 string scanner_name =
"";
377 Cerr(
"***** castor-makeReplicates() -> A problem occurred while trying to find the system name in the datafile header !" << endl);
382 Cerr(
"***** castor-makeReplicates() -> A problem occurred while searching for scanner system !" << endl);
387 Cerr(
"***** castor-makeReplicates() -> A problem occurred during scanner object construction ! !" << endl);
392 Cerr(
"***** castor-makeReplicates() -> A problem occurred while creating Scanner object !" << endl);
397 Cerr(
"***** castor-makeReplicates() -> A problem occurred while retrieving scanner fields from the datafile header !" << endl);
402 Cerr(
"***** castor-makeReplicates() -> A problem occurred while generating/reading the LUT !" << endl);
421 Cerr(
"***** castor-makeReplicates() -> Unknown scanner type (" << p_ScannerManager->
GetScannerType() <<
") for datafile construction ! Abort." << endl);
428 bool do_not_affect_quantification =
false;
431 Cerr(
"***** castor-makeReplicates() -> A problem occurred during datafile header reading ! Abort." << endl);
436 Cerr(
"***** castor-makeReplicates() -> A problem occurred while checking datafile parameters ! Abort." << endl);
441 Cerr(
"***** castor-makeReplicates() -> A problem occurred in datafile initialization ! Abort." << endl);
446 Cerr(
"***** castor-makeReplicates() -> A problem occurred in datafile initialization ! Abort." << endl);
451 Cerr(
"***** castor-makeReplicates() -> A problem occurred in datafile preparation ! Abort." << endl);
457 Cerr(
"***** castor-makeReplicates() -> The input datafile is not a list-mode, this program is only suitable to list-mode files !" << endl);
465 if (down_sampling==-1.)
472 for (
int rep=0; rep<nb_replicates; rep++)
478 if (pp_OutputDataFile[rep]->SetParametersFrom(p_DataFile))
480 Cerr(
"***** castor-makeReplicates() -> An error occurred while setting parameters of output file from input file (replicate " << rep+1 <<
") !" << endl);
484 char tmp[128]; sprintf(tmp,
"%d",rep+1);
string rep_suffix =
"_" + ((string)tmp);
486 if (pp_OutputDataFile[rep]->OpenFileForWriting(rep_suffix))
488 Cerr(
"***** castor-makeReplicates() -> An error occurred while opening file for writing (replicate " << rep+1 <<
") !" << endl);
496 if (verbose>=1)
Cout(
"castor-makeReplicates() -> Start pseudo-replicating input datafile with " << nb_replicates <<
" replicates ..." << endl);
497 if (verbose>=2)
Cout(
" --> Use a pseudo-gate duration of " << gate_duration <<
" ms" << endl);
499 int64_t* nb_events_per_rep = (int64_t*)calloc(nb_replicates,
sizeof(int64_t));
500 int64_t total_events = 0;
502 int current_replicate = 0;
503 uint32_t current_replicate_time = 0;
505 int64_t index_start = 0; int64_t index_stop = 0;
508 int64_t printing_index = 0;
509 for (int64_t index = index_start ; index < index_stop ; index++)
514 if (printing_index%10000==0)
516 int percent = ((int)( ((
FLTNB)(index-index_start)) * 100. / ((
FLTNB)(index_stop-index_start)) ));
517 cout <<
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b " 518 << percent <<
" % " << flush;
526 Cerr(
"***** castor-makeReplicates() -> An error occurred while getting the event from index " << index <<
" !" << endl);
527 for (
int rep=0; rep<nb_replicates; rep++)
528 if (pp_OutputDataFile[rep]->CloseFile())
529 Cerr(
"***** castor-makeReplicates() -> An error occurred while closing file during writing (replicate " << rep+1 <<
") !" << endl);
535 uint32_t this_time =
event->GetTimeInMs();
537 if (this_time >= current_replicate_time + gate_duration)
540 uint32_t time_difference = this_time - current_replicate_time;
542 uint32_t nb_replicates_passed = time_difference / gate_duration;
544 current_replicate_time += nb_replicates_passed * gate_duration;
546 current_replicate = (current_replicate + nb_replicates_passed) % nb_replicates;
549 nb_events_per_rep[current_replicate]++;
551 event->MultiplyAdditiveCorrections(1./((
FLTNB)nb_replicates));
553 pp_OutputDataFile[current_replicate]->
WriteEvent(event);
555 if (verbose>=2) cout <<
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" 556 <<
" --> 100 % " << endl;
561 for (
int rep=0; rep<nb_replicates; rep++)
564 if (pp_OutputDataFile[rep]->CloseFile())
566 Cerr(
"***** castor-makeReplicates() -> An error occurred while closing file after writing (replicate " << rep+1 <<
") !" << endl);
570 pp_OutputDataFile[rep]->
SetNbEvents(nb_events_per_rep[rep]);
577 Cout(
"castor-makeReplicates() -> Here are some events statistics:" << endl);
578 Cout(
" --> Total number of events: " << total_events << endl);
579 for (
int rep=0; rep<nb_replicates; rep++)
Cout(
" --> Number of events for replicate " << rep+1 <<
": " << nb_events_per_rep[rep] << endl);
582 for (
int rep=0; rep<nb_replicates; rep++)
585 if (pp_OutputDataFile[rep]->WriteHeader())
587 Cerr(
"***** castor-makeReplicates() -> An error occurred while writing output header file (replicate " << rep+1 <<
") !" << endl);
597 if (nb_replicates==-1)
610 Cerr(
"***** castor-makeReplicates() -> An error occurred while setting parameters of output file from input file !" << endl);
616 Cerr(
"***** castor-makeReplicates() -> An error occurred while opening file for writing !" << endl);
623 if (verbose>=1)
Cout(
"castor-makeReplicates() -> Start down-sampling input datafile with factor " << down_sampling <<
" ..." << endl);
625 int64_t kept_events = 0, rejected_events = 0;
627 int64_t index_start = 0; int64_t index_stop = 0;
630 int64_t printing_index = 0;
631 for (int64_t index = index_start ; index < index_stop ; index++)
636 if (printing_index%10000==0)
638 int percent = ((int)( ((
FLTNB)(index-index_start)) * 100. / ((
FLTNB)(index_stop-index_start)) ));
639 cout <<
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b " 640 << percent <<
" % " << flush;
648 Cerr(
"***** castor-makeReplicates() -> An error occurred while getting the event from index " << index <<
" !" << endl);
650 Cerr(
"***** castor-makeReplicates() -> An error occurred while closing file during writing !" << endl);
656 if (chance>down_sampling)
662 event->MultiplyAdditiveCorrections(down_sampling);
667 if (verbose>=2) cout <<
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" 668 <<
" --> 100 % " << endl;
675 Cerr(
"***** castor-makeReplicates() -> An error occurred while closing file after writing !" << endl);
685 int64_t total_events = kept_events + rejected_events;
686 Cout(
"castor-makeReplicates() -> Here are some events statistics:" << endl);
687 Cout(
" --> Total number of events: " << total_events << endl);
688 Cout(
" --> Kept events: " << kept_events << endl);
689 Cout(
" --> Rejected events: " << rejected_events << endl);
690 Cout(
" --> Effective down-sampling factor: " << ((
double)kept_events) / ((
double)total_events) << endl);
695 Cerr(
"***** castor-makeReplicates() -> An error occurred while writing output header file !" << endl);
This class is designed to be a mother virtual class for DataFile.
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
void GetEventIndexStartAndStop(int64_t *ap_indexStart, int64_t *ap_indexStop, int a_subsetNum=0, int a_NbSubsets=1)
static sRandomNumberGenerator * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
void SetVerbose(int a_verbose)
int CheckParameters()
Check the initialization of member variables Call the CheckSpecificParameters() function implemente...
virtual int WriteHeader()=0
This function is implemented in child classes. Generate a header file according to the data output ...
int FindScannerSystem(string a_scannerName)
FLTNB GetCalibrationFactor()
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
int SetParametersFrom(vDataFile *ap_DataFile)
virtual int WriteEvent(vEvent *ap_Event, int a_th=0)=0
int ReadInfoInHeader(bool a_affectQuantificationFlag=true)
void SetVerbose(int a_verboseLevel)
HPFLTNB GenerateExtraRdmNber(int a_nb=0)
Generate a random number using the specified additional not thread safe random generator, for use in sequential parts of an otherwise multithreaded code.
virtual int ComputeSizeEvent()=0
This function is implemented in child classes Computation of the size of each event according to th...
void SetVerbose(int a_verboseLevel)
Set verbosity level.
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int InitializeMappedFile()
Check the datafile existency, map it to memory and get the raw char* pointer. .
int InstantiateScanner()
Instantiate scanner using the related function in the scanner classes.
int LogCommandLine(int argc, char **argv)
vEvent * GetEvent(int64_t a_eventIndex, int a_th=0)
int CloseFile()
Close as many binary file stream for writing.
#define SCANNER_SPECT_CONVERGENT
int BuildLUT()
Call the eponym function of the scanner class.
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
Singleton class that Instantiate and initialize the scanner object.
void SetCalibrationFactor(FLTNB a_value)
int Initialize(int a_nbThreads, int a_nbExtra)
Instantiate pseudo random number generators, one per thread by default, and additional extra ones if ...
virtual int PrepareDataFile()=0
This function is implemented in child classes Store different kind of information inside arrays (da...
Inherit from vDataFile. Class that manages the reading of a SPECT input file (header + data)...
void SetHeaderDataFileName(const string &a_headerFileName)
int OpenFileForWriting(string a_suffix="")
void SetMPIRank(int a_mpiRank)
#define KEYWORD_MANDATORY
Singleton class that generate a thread-safe random generator number for openMP As singleton...
void SetNbEvents(int64_t a_value)
void SetBedIndex(int a_bedIndex)
Mother class for the Event objects.
int InitOutputDirectory(const string &a_pathFout, const string &a_pathDout)
int ConvertFromString(const string &a_str, string *a_result)
Copy the 'a_str' string in the position pointed by 'a_result'.
Inherit from vDataFile. Class that manages the reading of a CT input file (header + data)...
This class is designed to manage all dimensions and quantification related stuff. ...
void SetVerbose(int a_verboseLevel)
void SetDefault()
A function used to set number of threads and MPI instances to 1 and bypass the CheckParameters() func...
void SetVerbose(int a_verbose)
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
int GetGeometricInfoFromDataFile(string a_pathToDataFilename)