8 #include "gVariables.hh" 10 #include "iEventHistoPET.hh" 11 #include "iEventNorm.hh" 12 #include "iProjectorClassicSiddon.hh" 13 #include "oImageDimensionsAndQuantification.hh" 14 #include "oInterfileIO.hh" 15 #include "oProjectionLine.hh" 16 #include "oProjectorManager.hh" 17 #include "vDataFile.hh" 18 #include "iDataFilePET.hh" 19 #include "iDataFileSPECT.hh" 20 #include "iDataFileCT.hh" 21 #include "sOutputManager.hh" 22 #include "sRandomNumberGenerator.hh" 42 cout <<
"Usage: castor-norm -df datafile.cdh -img path_to_img.hdr -sc scanner_alias -(f/d)out output" << endl;
44 cout <<
"This program can be used to compute direct normalization factors from a normalization phantom." << endl;
46 cout <<
"Direct normalization factors are used to counteract on the variation of sensitivity across all LORs of a PET system.";
47 cout <<
" They are computed from a normalization scan (-df), typically of a symmetric and uniform phantom (-img), which illuminates as evenly as possible the different possible LORs.";
48 cout <<
" The normalization factors are given by" << endl;
49 cout <<
" NF_uivj=A/C_uivj" << endl;
50 cout <<
"where A is the activity of the uniform phantom, and C_uivj is the event count measured for LOR uivj.";
51 cout <<
" The program outputs a normalization datafile that contains the computed NFs." << endl;
53 cout <<
"[Mandatory parameters]:" << endl;
54 cout <<
" -df datafile.cdh : Give a CASToR histogram datafile of a normalization scan." << endl;
55 cout <<
" -img path_to_img.hdr : Give the interfile header of the normalization phantom (no default)" << endl;
56 cout <<
" -sc scanner_alias : Give the scanner model. It must correspond to the name of one of the file in the scanner repository (w/o file extension)" << endl;
57 cout <<
" -fout name : Give the root name for all output files (no default, alternative to -dout)" << endl;
58 cout <<
" -dout name : Give the name of the output directory where all output files will be written (no default, alternative to -fout)" << endl;
60 cout <<
"[Options]:" << endl;
61 cout <<
" -proj param : Give the projector to be used for forward projection, along with a configuration file (proj:file.conf)" << endl;
62 cout <<
" -proj-common : Give common projector-related options." << endl;
63 cout <<
" or the list of parameters associated to the projector (proj,param1,param2,...). If the projector only is specified, the" << endl;
64 cout <<
" default configuration file is used. By default, the Siddon projector is used." << endl;
65 cout <<
" -proj-comp : Give the strategy for projection line computation. Here are the three different strategies that can be used:" << endl;
66 cout <<
" 1 : Image-based system matrix elements storage: The voxels weights are added in a matrix representing the whole image, so" << endl;
67 cout <<
" the addition of a new line to the previous ones is straightforward only by adding the weights to the corresponding voxels." << endl;
68 cout <<
" As it is insanely long, it can possibly be used for example with extremely complex projectors that makes use of huge number" << endl;
69 cout <<
" of ray tracings for a single event, where the list of contributions can become longer than the number of voxels in the image." << endl;
70 cout <<
" This strategy is not compatible with SPECT reconstruction including attenuation correction." << endl;
71 cout <<
" 2 : Fixed-size list storage of system matrix elements: The voxels are added one by one in two separated lists, one containing voxel" << endl;
72 cout <<
" indices and the other voxel weights. When a voxel is added to the oProjectionLine, it is simply pilled-up to the list. The list" << endl;
73 cout <<
" has a fixed size which is provided by the EstimateMaxNumberOfVoxelsPerLine() function from the vProjector class. There are no" << endl;
74 cout <<
" checks at all for possible buffer overflows. This is the fastest strategy and default one." << endl;
75 cout <<
" 3 : Adaptative-size list storage of system matrix elements: This is the same as the fixed-size strategy except that the size can be" << endl;
76 cout <<
" upgraded if the current number of contributing voxels exceed the list's size. The first allocated size corresponds to the diagonal" << endl;
77 cout <<
" of the image. During the first iteration, this size will be upgraded until it will reach a size suitable for all events. Thus it" << endl;
78 cout <<
" is a bit slower than the fixed-list strategy during the first iteration, but is optimal with respect to RAM usage." << endl;
79 cout <<
" -vb value : Give the verbosity level, from 0 (no verbose) to 2 (default: 1)" << endl;
80 cout <<
" --help,-h,-help : Print out this help page." << endl;
83 cout <<
" Build date: " << BUILD_DATE << endl;
87 cout <<
" This program is part of the CASToR release version " <<
CASTOR_VERSION <<
"." << endl;
100 int main(
int argc,
char** argv)
108 MPI_Init(&argc, &argv);
109 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
110 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
111 if (mpi_rank!=0)
return 0;
130 string path_to_normalization_datafile =
"";
133 string path_to_normalization_phantom =
"";
136 string scanner_name =
"";
143 string path_dout =
"";
145 string path_fout =
"";
151 string options_projectorF =
"incrementalSiddon";
152 string options_projector_common =
"3.,1,1";
169 for (
int i=1; i<argc; i++)
172 string option = (string)argv[i];
179 if (option==
"-h" || option==
"--help" || option==
"-help")
185 else if (option==
"-vb")
189 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
194 Cerr(
"***** castor-norm() -> Exception when trying to read provided verbosity level '" << verbose <<
" for option: " << option << endl);
205 else if (option==
"-df")
209 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
212 path_to_normalization_datafile = (string)argv[i+1];
216 else if (option==
"-img")
220 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
223 path_to_normalization_phantom = argv[i+1];
227 else if (option==
"-sc")
231 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
234 scanner_name = argv[i+1];
243 else if (option==
"-dout")
247 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
250 path_dout = argv[i+1];
254 else if (option==
"-fout")
258 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
261 path_fout = argv[i+1];
270 else if (option==
"-proj")
274 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
277 options_projectorF = (string)argv[i+1];
281 else if (option==
"-proj-common")
285 Cerr(
"***** castor-norm() -> Argument missing for option: " << option << endl);
288 options_projector_common = (string)argv[i+1];
292 else if (option==
"-proj-comp")
296 Cerr(
"***** castor-recon() -> Argument missing for option: " << option << endl);
299 projector_computation_strategy = atoi(argv[i+1]);
309 Cerr(
"***** castor-norm() -> Unknown option '" << option <<
"' !" << endl);
319 if (path_fout.empty() && path_dout.empty())
321 Cerr(
"***** castor-norm() -> Please provide an output option for output files (-fout or -dout) !" << endl);
325 if (!path_fout.empty() && !path_dout.empty())
327 Cerr(
"***** castor-norm() -> Please provide either output option -fout or -dout but not both !" << endl);
342 Cerr(
"***** castor-norm() -> A problem occurred while initializing output directory !" << endl);
348 Cerr(
"***** castor-norm() -> A problem occurred while logging command line arguments !" << endl);
359 Cerr(
"***** castor-norm() -> A problem occurred while searching for scanner system !" << endl);
364 Cerr(
"***** castor-norm() -> A problem occurred during scanner object construction ! !" << endl);
369 Cerr(
"***** castor-norm() -> A problem occurred while creating Scanner object !" << endl);
374 Cerr(
"***** castor-norm() -> A problem occurred while generating/reading the LUT !" << endl);
379 Cerr(
"***** castor-norm() -> A problem occurred while checking scanner manager parameters !" << endl);
384 Cerr(
"***** castor-norm() -> A problem occurred while initializing scanner !" << endl);
403 Cerr(
"***** castor-norm() -> An error occurred while trying to read the " 404 "interfile header of file reading file " 405 << path_to_normalization_phantom <<
" !" << endl);
429 Cout(
" Image dimensions for projections: " << endl);
430 Cout(
" voxels number (X,Y,Z): " << nb_VoxX <<
"," << nb_VoxY <<
"," << nb_VoxZ << endl);
431 Cout(
" voxels size (X,Y,Z): " << vox_SizeX <<
"," << vox_SizeY <<
"," << vox_SizeZ << endl);
432 Cout(
" offset (X,Y,Z): " << offsetX <<
"," << offsetY <<
"," << offsetZ << endl);
441 p_ImageDimensionsAndQuantification->
SetDefault();
443 p_ImageDimensionsAndQuantification->
SetNbVoxX(nb_VoxX);
444 p_ImageDimensionsAndQuantification->
SetNbVoxY(nb_VoxY);
445 p_ImageDimensionsAndQuantification->
SetNbVoxZ(nb_VoxZ);
446 p_ImageDimensionsAndQuantification->
SetVoxSizeX(vox_SizeX);
447 p_ImageDimensionsAndQuantification->
SetVoxSizeY(vox_SizeY);
448 p_ImageDimensionsAndQuantification->
SetVoxSizeZ(vox_SizeZ);
449 p_ImageDimensionsAndQuantification->
SetOffsetX(offsetX);
450 p_ImageDimensionsAndQuantification->
SetOffsetY(offsetY);
451 p_ImageDimensionsAndQuantification->
SetOffsetZ(offsetZ);
457 p_ImageDimensionsAndQuantification->
SetNbBeds(1);
462 nb_threads = omp_get_num_procs();
463 if (verbose>=2)
Cout(
" --> Use " << nb_threads <<
" threads" << endl);
465 if(p_ImageDimensionsAndQuantification->
SetNbThreads(to_string(nb_threads)))
467 Cerr(
"***** castor-norm() -> A problem occurred while setting the number of threads !" << endl);
473 Cerr(
"***** castor-norm() -> A problem occurred while checking image dimensions parameters !" << endl);
476 if (p_ImageDimensionsAndQuantification->
Initialize())
478 Cerr(
"***** castor-norm() -> A problem occurred while initializing image dimensions !" << endl);
494 p_ImageSpace->
InitImage(path_to_normalization_phantom, 0);
501 int64_t nb_nf = (int) (nb_elems * (nb_elems - 1) / 2);
510 bool do_not_affect_quantification =
false;
513 Cerr(
"***** castor-norm() -> A problem occurred during datafile header reading ! Abort." << endl);
518 Cerr(
"***** castor-norm() -> Only PET data is currently supported ! Abort." << endl);
523 Cerr(
"***** castor-norm() -> Only histogram data mode is currently supported. Aborting." << endl);
528 Cerr(
"***** castor-norm() -> A problem occurred while checking datafile parameters ! Abort." << endl);
533 Cerr(
"***** castor-norm() -> A problem occurred in datafile initialization ! Abort." << endl);
536 if (p_DataFile->
GetSize() != nb_nf) {
537 Cerr(
"***** castor-norm() -> The input datafile does not contain expected number of events (got" << p_DataFile->
GetSize() <<
", expected " << nb_nf <<
") ! Abort." << endl);
542 Cerr(
"***** castor-norm() -> A problem occurred in datafile initialization ! Abort." << endl);
547 Cerr(
"***** castor-norm() -> A problem occurred in datafile preparation ! Abort." << endl);
564 Cerr(
"***** castor-norm() -> An error occurred while opening file for writing !" << endl);
570 Cerr(
"***** castor-norm() -> A problem occurred in datafile initialization ! Abort." << endl);
575 Cerr(
"***** castor-norm() -> A problem occurred in datafile preparation ! Abort." << endl);
584 if (verbose>=5)
Cout(
"----- Projector initialization ... -----" << endl);
599 Cerr(
"***** castor-norm() -> A problem occurred while checking projector manager's parameters !" << endl);
605 Cerr(
"***** castor-norm() -> A problem occurred while initializing projector manager !" << endl);
609 if (verbose>=5)
Cout(
"----- Projector initialization OK -----" << endl);
616 if (verbose>=1)
Cout(
"castor-norm() -> Compute normalization factors for " << p_DataFile->
GetSize() <<
" events" << endl);
619 int64_t printing_index = 0;
620 bool problem =
false;
623 int64_t nf_correctly_computed = 0;
627 for (
INTNB th = 0; th < nb_threads; th++)
632 p2_EventNorm[th] = p_EventNorm;
637 int64_t index_start = 0;
638 int64_t index_stop = 0;
641 #pragma omp parallel for private(index) schedule(static), num_threads(nb_threads) 642 for (index = index_start; index < index_stop; index++)
647 th = omp_get_thread_num();
651 if (th==0 && verbose>=2)
653 if (printing_index%((
int)(index_stop/100/nb_threads))==0)
655 int percent = ((int)( ((
FLTNB)(index)) * (
FLTNB)nb_threads * 100. / index_stop ));
656 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 " 657 << percent <<
" % " << flush;
664 uint32_t id1 = p_EventHistoPET->
GetID1(0);
665 uint32_t id2 = p_EventHistoPET->
GetID2(0);
670 if (event_value > 0.){
673 if (p_ProjectionLine == NULL){
674 Cerr(
"***** castor-norm() -> A problem occurred while computing the projection line !" << endl);
686 nf_index = activity / event_value;
687 nf_correctly_computed++;
689 }
else if (activity < 0.) {
690 Cerr(
"***** castor-norm() -> A negative projection has been computed !" << endl);
691 Cerr(
"*****" << id1 <<
"," << id2 <<
": activity=" << activity <<
", event_value=" << event_value << endl);
700 if (activity == 0. && verbose >= 3)
702 Cerr(
"!!!!! castor-norm() -> The projection of the line of response having ID1=" << id1 <<
" and ID2=" << id2 <<
" is null, but the corresponding event activity is non-null (" << event_value <<
").");
703 Cerr(
" The normalization correction factor (" << nf_index <<
") will be erroneous for this line of response." << endl);
709 p_EventNorm->
SetID1(0, id1);
710 p_EventNorm->
SetID2(0, id2);
712 p_OutputDataFile->
WriteEvent(p_EventNorm, th);
718 Cerr(
"***** castor-norm() -> A problem occurred inside the parallel loop over events !" << endl);
725 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" 726 <<
" --> 100 % " << endl;
727 Cout(
" --> Compute normalization factors" << endl);
732 float percent = 100. * nf_correctly_computed / nb_nf;
733 Cout(
"castor-norm() -> " << nf_correctly_computed <<
" out of " << nb_nf <<
" (" << percent <<
"%) normalization factors correctly computed." << endl);
734 Cout(
"Please be aware that a low percentage may result in poor reconstruction quality!" << endl);
744 Cerr(
"***** castor-norm() -> An error occurred while writing the final file !" << endl);
750 Cerr(
"***** castor-norm() -> An error occurred while deleting temporary files !" << endl);
756 Cerr(
"***** castor-norm() -> An error occurred while writing output header file !" << endl);
765 if (verbose>=5)
Cout(
"----- Deleting CASToR objects ... -----" << endl);
767 for (
INTNB th = 0; th < nb_threads; th++)
769 delete p2_EventNorm[th];
771 delete[] p2_EventNorm;
773 delete p_ProjectorManager;
774 delete p_OutputDataFile;
780 delete p_ImageDimensionsAndQuantification;
781 if (verbose>=5)
Cout(
"----- CASToR objects successfully deleted -----" << endl);
int WriteEvent(vEvent *ap_Event, int a_th)
int main(int argc, char **argv)
void SetDataMode(int a_dataMode)
void SetVerbose(int a_verboseLevel)
uint32_t GetID2(int a_line)
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)
void SetNbLines(uint16_t a_value)
void SetVerbose(int a_verbose)
#define MODE_NORMALIZATION
void SetOptionsCommon(const string &a_optionsCommon)
int Initialize()
A function used to initialize the manager and the projectors or system matrices it manages...
void DeallocateImage()
Free memory for the main image matrices.
int CheckParameters()
Check the initialization of member variables Call the CheckSpecificParameters() function implemente...
int FindScannerSystem(string a_scannerName)
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
int ReadInfoInHeader(bool a_affectQuantificationFlag=true)
void SetVoxSizeY(FLTNB a_voxSizeY)
void SetOptionsForward(const string &a_optionsForward)
void SetOffsetZ(FLTNB a_offsetZ)
void SetVerbose(int a_verboseLevel)
void InstantiateImage()
Allocate memory for the main image matrices.
void SetVoxSizeX(FLTNB a_voxSizeX)
void SetNbVoxY(INTNB a_nbVoxY)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int InitImage(const string &a_pathToInitialImage, FLTNB a_value)
int ComputeSizeEvent()
Computation of the size of each event according to the mandatory/optional correction fields...
void IntfKeyPrintFields(Intf_fields a_IF)
Print all the keys of the Intf_fields structure passed in parameter, as well as their values for debu...
void SetNbRespBasisFunctions(int a_nbRespBasisFunctions)
int CheckParameters()
Check if all parameters have been correctly initialized, and call the CheckParameters function of the...
int SetNbThreads(const string &a_nbThreads)
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)
int PROJ_WriteData()
Write/Merge chunk of data in a general data file.
vEvent * GetEvent(int64_t a_eventIndex, int a_th=0)
#define FIXED_LIST_COMPUTATION_STRATEGY
void SetNbVoxZ(INTNB a_nbVoxZ)
void SetOffsetY(FLTNB a_offsetY)
int CheckParameters()
A function used to check the parameters settings.
FLTNB GetEventValue(int a_bin)
Inherit from iEventPET. Class for PET histogram mode events.
int BuildLUT()
Call the eponym function of the scanner class.
int Initialize()
A function used to initialize all that is needed.
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
void SetComputationStrategy(int a_computationStrategy)
void SetNbCardBasisFunctions(int a_nbCardBasisFunctions)
void SetOptionsBackward(const string &a_optionsBackward)
void SetDataFile(vDataFile *ap_DataFile)
Singleton class that Instantiate and initialize the scanner object.
void SetNormalizationFactor(FLTNBDATA a_value)
Cast the FLTNBDATA value passed as parameter in FLTNB, and set it to the normalization term...
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
oProjectionLine * ComputeProjectionLine(vEvent *ap_Event, int a_th)
void SetHeaderDataFileName(const string &a_headerFileName)
vScanner * GetScannerObject()
int CheckParameters()
A function used to check the parameters settings.
int WriteHeader()
Generate a header file according to the data output information.
void SetMPIRank(int a_mpiRank)
int AllocateID()
Instantiate the mp_ID1 and mp_ID2 indices arrays.
int PROJ_InitFile()
Initialize the fstream objets for output writing as well as some other variables specific to the Proj...
bool NotEmptyLine()
This function is used to know if the line contains any voxel contribution.
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
void IntfKeyInitFields(Intf_fields *ap_IF)
Init the file of an Interfile fields structure passed in parameter to their default values...
Inherit from vEvent. Used for normalization events for sensitivity computation.
void SetNbEvents(int64_t a_value)
int Initialize()
Initialization : .
int PrepareDataFile()
Store different kind of information inside arrays (data relative to specific correction as well as ba...
void SetNbBeds(int a_nbBeds)
void SetID2(int a_line, uint32_t a_value)
void SetVoxSizeZ(FLTNB a_voxSizeZ)
This class is designed to manage and store system matrix elements associated to a vEvent...
This class is designed to manage the projection part of the reconstruction.
Interfile fields. This structure contains all the Interfile keys currently managed by CASToR Decl...
void SetBedIndex(int a_bedIndex)
void GetUserEndianness()
Check user/host computer endianness and write it to the global variable User_Endianness.
This class holds all the matrices in the image domain that can be used in the algorithm: image...
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'.
FLTNB ForwardProject(FLTNB *ap_image=NULL)
void SetNormCorrectionFlagOn()
set to true the flag indicating the presence of normalization correction factors in the datafile ...
void SetNbVoxX(INTNB a_nbVoxX)
void SetScanner(vScanner *ap_Scanner)
void SetOffsetX(FLTNB a_offsetX)
This class is designed to manage all dimensions and quantification related stuff. ...
void SetVerbose(int a_verboseLevel)
void SetNbTimeBasisFunctions(int a_nbTimeBasisFunctions)
uint32_t GetID1(int a_line)
int PROJ_DeleteTmpDataFile()
Delete temporary datafile used for multithreaded output writing if needed.
int IntfReadHeader(const string &a_pathToHeaderFile, Intf_fields *ap_IntfFields, int vb)
Read an Interfile header.
void SetDefault()
A function used to set number of threads and MPI instances to 1 and bypass the CheckParameters() func...
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
void SetVerbose(int a_verboseLevel)
void SetIgnoreTOFFlag(bool a_ignoreTOFFlag)
void SetID1(int a_line, uint32_t a_value)