From 0c2ffba457667110e0e1a230bfcbca401cd2ceeb Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Wed, 31 Jul 2024 12:50:42 +0200 Subject: [PATCH 01/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 43c238524..eecf99b43 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1412,8 +1412,9 @@ The dead time for coincidences works in the same way as that acting on the *sing Coincidence buffers ~~~~~~~~~~~~~~~~~~~ It simulates the operation of a detector by modeling coincidences, transfer speed limits, and data loss due to buffer capacity overflows. It manages a memory buffer for coincidence events, allowing for the modeling of data loss due to buffer overflow. It uses a read frequency and allows defining the buffer size and read mode, influencing how events are processed. There are two buffer operation modes. Mode 1 empties the entire buffer at each read clock tick, while Mode 0 reads events one by one. +Here is an example of how to configure this in a macro file: -Example:: +**Example** :: /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert buffer /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/buffer/setBufferSize 64 B @@ -1432,12 +1433,29 @@ A presort buffer contains singles that have not yet been checked for coincidence Multiple coincidence removal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If the multiple coincidences are kept and not split into pairs (i.e., if any of the **keepXXX** multiple coincidence policies are used), the multicoincidences could contribute to dataflow occupancy but cannot be written to the disk. Unless otherwise specified, any multicoincidence is then cleared from data just before the disk writing. If needed, this clearing could be performed at any earlier coincidence processing step by inserting the **multipleKiller** module at the required level. This module has no parameters and simply removes the multicoincidence events. Multiple coincidences split into many pairs are not affected by this module and cannot be distinguished from normal "simple" coincidences. To insert a multipleKiller, use the syntax:: - +If the multiple coincidences are kept and not split into pairs (i.e., if any of the **keepXXX** multiple coincidence policies are used), the multicoincidences could contribute to dataflow occupancy but cannot be written to the disk. Unless otherwise specified, any multicoincidence is then cleared from data just before the disk writing. If needed, this clearing could be performed at any earlier coincidence processing step by inserting the **MultiplesKiller** module at the required level. This module has no parameters and simply removes the multicoincidence events. Multiple coincidences split into many pairs are not affected by this module and cannot be distinguished from normal "simple" coincidences. To insert a multipleKiller, use the syntax :: /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert multiplesKiller + +Coincidence Time Difference Selector +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Responsible for selecting events based on the time difference between input signals. +Here is an example of how to configure this in a macro file: + + +**Example** :: + + + /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert timeDiffSelector + /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/timeDiffSelector/setMin 1 ns + /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/timeDiffSelector/setMax 100 ns + + +These commands configure the `Coincidence Time Difference Selector` to keep only the events where the time difference is between 1 nanosecond and 100 nanoseconds. Events outside this range will be ignored. + Example of a digitizer setting ------------------------------ From 18d4050efd1a3ae999e62348819bb63d35d96695 Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Wed, 21 Aug 2024 15:56:16 +0200 Subject: [PATCH 02/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index eecf99b43..31b87c21c 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -537,7 +537,7 @@ Here is an example of how to configure this in a macro file: /gate/distributions/my_distrib2D/setFileName Lut(X,Y).txt /gate/distributions/my_distrib2D/readMatrix2d /gate/digitizerMgr/crystalUnit/SinglesDigitizer/Singles/insert spatialResolution - /gate/digitizerMgr/crystalUnit/SinglesDigitizer/Singles/spatialResolution/fwhmXdistrib2D my_distrib2D + /gate/digitizerMgr/crystalUnit/SinglesDigitizer/Singles/spatialResolution/fwhmXYdistrib2D my_distrib2D **Example for 1D distribution**:: /gate/distributions/name my_distrib1D @@ -1442,8 +1442,8 @@ If the multiple coincidences are kept and not split into pairs (i.e., if any of Coincidence Time Difference Selector ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Responsible for selecting events based on the time difference between input signals. -Here is an example of how to configure this in a macro file: +Responsible for selecting events based on the time difference between input signals. Below is an example of how to configure it in a macro file: + **Example** :: From ad2d4bf3edfa455e83b6a171598915a3307e54b8 Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Tue, 27 Aug 2024 14:49:53 +0200 Subject: [PATCH 03/96] Update digitizer_and_detector_modeling.rst included new parameters for filtering based on the maximum z-position difference and sector distance (s) between two events. --- docs/digitizer_and_detector_modeling.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 31b87c21c..7ff9d74e4 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1296,7 +1296,18 @@ To set up a coincidence window of 10 ns, the user should specify:: To change the default value of the minimum sector difference for valid coincidences (the default value is 2), the command line should be used:: + + /gate/digitizerMgr/CoincidenceSorter/Coincidences/minSectorDifference +To change the default value of the maximum allowable difference in the z positions of two events (disabled by default), the command line should be used:: + + +/gate/digitizer/Coincidences/setMaxDeltaZ + +To change the default value of the maximum allowable sector distance s between two events (disabled by default), the command line should be used:: + + +/gate/digitizer/Coincidences/setMaxS By default, the offset value is equal to 0, which corresponds to a prompt coincidence sorter. If a delayed coincidence sorter is to be simulated, with a 100 ns time shift for instance, the offset value should be set using the command:: From 99b3987110f93ff6ab1fae1118004d6baa0511d2 Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Fri, 30 Aug 2024 15:09:21 +0200 Subject: [PATCH 04/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 7ff9d74e4..dcfc6cf75 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1302,12 +1302,20 @@ To change the default value of the minimum sector difference for valid coinciden To change the default value of the maximum allowable difference in the z positions of two events (disabled by default), the command line should be used:: -/gate/digitizer/Coincidences/setMaxDeltaZ + /gate/digitizer/Coincidences/setMaxDeltaZ To change the default value of the maximum allowable sector distance s between two events (disabled by default), the command line should be used:: -/gate/digitizer/Coincidences/setMaxS + /gate/digitizer/Coincidences/setMaxS + + +Comment: The setMaxS command performs a similar function to minSectorDifference but is adapted for non-standard scanners, such as square-shaped ones. It is an additional option provided for the user to offer greater flexibility. + + + + + By default, the offset value is equal to 0, which corresponds to a prompt coincidence sorter. If a delayed coincidence sorter is to be simulated, with a 100 ns time shift for instance, the offset value should be set using the command:: From 2f0928100a952183986658546ebae442556c9eba Mon Sep 17 00:00:00 2001 From: kochebina Date: Tue, 10 Feb 2026 15:15:27 +0100 Subject: [PATCH 05/96] resole confl --- docs/digitizer_and_detector_modeling.rst | 63 +++++++++++++++--------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index dcfc6cf75..8bbcb0ceb 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1441,6 +1441,7 @@ Here is an example of how to configure this in a macro file: /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/buffer/setMode 1 + For a coincidence sorter user can chose a presort buffer with a following command: /gate/digitizer/Coincidences/setPresortBufferSize 256 @@ -1557,28 +1558,43 @@ Example:: 66 /gate/digitizerMgr/CoincidenceSorter/Coincidences/setOffset 0. ns 67 /gate/digitizerMgr/CoincidenceSorter/Coincidences/setWindow 24. ns 68 /gate/digitizerMgr/CoincidenceSorter/Coincidences/minSectorDifference 3 - 69 - 70 /gate/digitizerMgr/name delayedCoincidences - 71 /gate/digitizerMgr/insert coincidenceSorter - 72 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/setInputCollection cutSingles - 73 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/setOffset 100. ns - 74 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/setWindow 24. ns - 75 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/minSectorDifference 3 - 76 - 77 /gate/digitizer/name finalCoinc (NOT YET ADDED IN 9.3) - 78 /gate/digitizer/insert coincidenceChain - 79 /gate/digitizer/finalCoinc/addInputName delay - 80 /gate/digitizer/finalCoinc/addInputName Coincidences - 81 /gate/digitizer/finalCoinc/usePriority true - 82 /gate/digitizer/finalCoinc/insert deadtime - 83 /gate/digitizer/finalCoinc/deadtime/setDeadTime 60 ns - 84 /gate/digitizer/finalCoinc/deadtime/setMode nonparalysable - 85 /gate/digitizer/finalCoinc/deadtime/conserveAllEvent true - 86 /gate/digitizer/finalCoinc/insert buffer - 87 /gate/digitizer/finalCoinc/buffer/setBufferSize 32 B - 88 /gate/digitizer/finalCoinc/buffer/setReadFrequency 14.45 MHz - 89 /gate/digitizer/finalCoinc/buffer/setMode 0 - + 69 /gate/digitizerMgr/CoincidenceSorter/Coincidences/setSMax 1 mm + 70 /gate/digitizerMgr/CoincidenceSorter/Coincidences/setDeltaZMax 10 mm + 71 + 72 /gate/digitizerMgr/name delayedCoincidences + 73 /gate/digitizerMgr/insert coincidenceSorter + 74 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/setInputCollection cutSingles + 75 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/setOffset 100. ns + 76 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/setWindow 24. ns + 77 /gate/digitizerMgr/CoincidenceSorter/delayedCoincidences/minSectorDifference 3 + 78 + 79 /gate/digitizerMgr/name finalCoinc + 80 /gate/digitizerMgr/insert CoincidenceDigitizer + 81 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/addInputCollection Delay + 82 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/addInputCollection Coincidences + 83 #/gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/usePriority false + 84 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/describe + 85 + 86 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert deadtime + 87 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/deadtime/setDeadTime 60 ns + 88 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/deadtime/setMode paralysable + 89 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/deadtime/conserveAllEvent false #true + 90 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/deadtime/verbose 6 + 91 + 92 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert Buffer + 93 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/setBufferSize 64 B + 94 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/setReadFrequency 0.1 MHz + 95 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/setMode 0 + 96 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/describe + 97 + 98 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert MultiplesKiller + 99 + 100 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert timeDiffSelector + 101 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/timeDiffSelector/setMin 1 ns + 102 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/timeDiffSelector/setMax 500 ns + + + Lines 1 to 15: The branch named "Singles" contains the result of applying the adder, readout, blurring, and threshold (50 keV) modules. @@ -1594,9 +1610,8 @@ Lines 65 to 68: The "default" coincidence branch consists of data taken from the Lines 70 to 75: A second coincidence branch is defined (line 71), which is named "delayedCoincidences". This branch takes its data from the same output ("cutSingles"), but is defined by a delayed coincidence window of 24 ns, and a 100 ns delay (line 73). -Lines 77 to 89: The delayed and the prompts coincidence lines are grouped (lines 79-80). Between two coincidences coming from these two lines and occuring within a given event, the priority is set to the delayed line, since it is inserted before the prompt line, and the priority is used (line 81). A non-paralysable dead time of 60 ns is applied on the delayed+prompt coincidences (lines 82-85). If more than one coincidence occur inside a given event, the dead time can kill all of them or none of them, depending on the arrival time of the first one. As a consequence, if a delay coincidence is immediately followed by a prompt coincidence due to the same photon, then, the former will not hide the latter (line 85). Finally, a memory buffer of 32 coincidences, read at a frequency of 14.45 MHz, in an event-by-event basis (line 89) is applied to the delayed+prompt sum (lines 86-89). +Lines 80 to 102: The delayed and prompt coincidence collections are grouped (lines 81-82). The priority is not set between coincidences from these collections, as the priority option is commented out (line 83). A paralysable dead time of 60 ns is applied to the combined delayed and prompt coincidences (lines 87-90). If more than one coincidence occurs within a given event, the dead time may eliminate all or none of them, depending on the arrival time of the first coincidence. As a result, if a delayed coincidence is immediately followed by a prompt coincidence from the same photon, the delayed one may suppress the prompt one (line 89). Finally, a memory buffer of 64 coincidences, read at a frequency of 0.1 MHz, on an event-by-event basis (line 94), is applied to the combined delayed and prompt coincidences (lines 92-96). Additional modules, including a multiples killer and a time difference selector, are inserted. The time difference selector sets a coincidence window ranging from 1 ns to 500 ns (lines 98-102). -Digitizer optimization ---------------------- In GATE standard operation mode, primary particles are generated by the source manager, and then propagated through the attenuating geometry before generating *hits* in the detectors, which feed into the digitizer chain. While this operation mode is suited for conventional simulations, it is inefficient when trying to optimize the parameters of the digitizer chain. In this case, the user needs to compare the results obtained for different sets of digitizer parameters that are based upon the same series of hits. Thus, repeating the particle generation and propagation stages of a simulation is unnecessary for tuning the digitizer setting. From 53e0a16c5712df507e89251e259aa276f20a9c49 Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Wed, 4 Sep 2024 09:09:13 +0200 Subject: [PATCH 06/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 8bbcb0ceb..b0f77bc09 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1304,16 +1304,14 @@ To change the default value of the maximum allowable difference in the z positio /gate/digitizer/Coincidences/setMaxDeltaZ -To change the default value of the maximum allowable sector distance s between two events (disabled by default), the command line should be used:: - /gate/digitizer/Coincidences/setMaxS - - -Comment: The setMaxS command performs a similar function to minSectorDifference but is adapted for non-standard scanners, such as square-shaped ones. It is an additional option provided for the user to offer greater flexibility. +For non-standard scanners, such as square-shaped ones, you can set the minimum allowable sector distance s between two events. This option provides more flexibility than the default minimum sector difference:: +/gate/digitizer/Coincidences/setMinS +This command is particularly useful for defining the minimum spatial separation required between two events in non-circular or irregular scanner geometries. The setMinS command allows users to control this parameter directly. From 2a3d9dcfd75cb95b43205471163c2344f93ebd84 Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Wed, 4 Sep 2024 10:36:50 +0200 Subject: [PATCH 07/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index b0f77bc09..c093c0ae4 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1296,25 +1296,18 @@ To set up a coincidence window of 10 ns, the user should specify:: To change the default value of the minimum sector difference for valid coincidences (the default value is 2), the command line should be used:: - - /gate/digitizerMgr/CoincidenceSorter/Coincidences/minSectorDifference -To change the default value of the maximum allowable difference in the z positions of two events (disabled by default), the command line should be used:: +To change the default value of the maximum allowable difference in the z positions of two events (disabled by default), the command line should be used:: /gate/digitizer/Coincidences/setMaxDeltaZ - - For non-standard scanners, such as square-shaped ones, you can set the minimum allowable sector distance s between two events. This option provides more flexibility than the default minimum sector difference:: - -/gate/digitizer/Coincidences/setMinS +/gate/digitizer/Coincidences/setSMin This command is particularly useful for defining the minimum spatial separation required between two events in non-circular or irregular scanner geometries. The setMinS command allows users to control this parameter directly. - - By default, the offset value is equal to 0, which corresponds to a prompt coincidence sorter. If a delayed coincidence sorter is to be simulated, with a 100 ns time shift for instance, the offset value should be set using the command:: /gate/digitizerMgr/CoincidenceSorter/Coincidences/setOffset 100. ns @@ -1579,13 +1572,13 @@ Example:: 89 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/deadtime/conserveAllEvent false #true 90 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/deadtime/verbose 6 91 - 92 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert Buffer - 93 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/setBufferSize 64 B - 94 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/setReadFrequency 0.1 MHz - 95 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/setMode 0 - 96 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/Buffer/describe + 92 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert buffer + 93 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/buffer/setBufferSize 64 B + 94 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/buffer/setReadFrequency 0.1 MHz + 95 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/buffer/setMode 0 + 96 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/buffer/describe 97 - 98 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert MultiplesKiller + 98 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert multiplesKiller 99 100 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert timeDiffSelector 101 /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/timeDiffSelector/setMin 1 ns From 3863674e76c57b6122ba97c7b1ccb08c7f59647b Mon Sep 17 00:00:00 2001 From: kochebina Date: Tue, 10 Feb 2026 15:18:46 +0100 Subject: [PATCH 08/96] conflict: GateCoincidenceDigitizerMessenger --- .../include/GateCoincidenceDigi.hh | 4 +- .../GateCoincidenceTimeDiffSelector.hh | 33 +++++--- ...ateCoincidenceTimeDiffSelectorMessenger.hh | 21 +++-- source/digits_hits/src/GateCoincidenceDigi.cc | 15 ++++ .../src/GateCoincidenceDigitizerMessenger.cc | 9 ++- .../src/GateCoincidenceTimeDiffSelector.cc | 79 +++++++++++++------ ...ateCoincidenceTimeDiffSelectorMessenger.cc | 17 ++-- ...CoincidencePulseProcessorChainMessenger.cc | 10 +-- 8 files changed, 139 insertions(+), 49 deletions(-) diff --git a/source/digits_hits/include/GateCoincidenceDigi.hh b/source/digits_hits/include/GateCoincidenceDigi.hh index f9e400f2a..ac76ad8a7 100644 --- a/source/digits_hits/include/GateCoincidenceDigi.hh +++ b/source/digits_hits/include/GateCoincidenceDigi.hh @@ -23,7 +23,7 @@ See LICENSE.md for further details // define the minimum offset for a delayed coincidence window in sec #define MIN_COINC_OFFSET -1. -class GateCoincidenceDigi : public G4VDigi, public std::vector +class GateCoincidenceDigi : public G4VDigi, public std::vector { public: @@ -51,6 +51,7 @@ public: public: + G4double ComputeFinishTime(); inline G4double GetStartTime() const { return m_startTime; } @@ -84,6 +85,7 @@ public: static std::vector GetCoincidenceASCIIMask(); static G4bool GetCoincidenceASCIIMask(G4int index); + protected: static std::vector m_coincidenceASCIIMask; static G4bool m_coincidenceASCIIMaskDefault; diff --git a/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh b/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh index 7e18f7d09..ca1c752f4 100644 --- a/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh +++ b/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh @@ -15,27 +15,37 @@ See LICENSE.md for further details #include #include "G4ThreeVector.hh" -#include "GateVPulseProcessor.hh" +//#include "GateVPulseProcessor.hh" #include "GateObjectStore.hh" -#include "GateVCoincidencePulseProcessor.hh" +#include "GateVDigitizerModule.hh" +#include "GateCoincidenceDigi.hh" +#include "GateClockDependent.hh" +#include "GateCrystalSD.hh" + + +#include "GateDigi.hh" + +#include "GateCoincidenceTimeDiffSelectorMessenger.hh" +#include "GateCoincidenceDigitizer.hh" class GateCoincidenceTimeDiffSelectorMessenger; -class GateCoincidenceTimeDiffSelector : public GateVCoincidencePulseProcessor +class GateCoincidenceTimeDiffSelector : public GateVDigitizerModule,public GateDigi { public: - + GateCoincidenceTimeDiffSelector(GateCoincidenceDigitizer *digitizer, G4String name); + ~GateCoincidenceTimeDiffSelector(); //! Destructor - virtual ~GateCoincidenceTimeDiffSelector() ; + //virtual ~GateCoincidenceTimeDiffSelector() ; //! Constructs a new dead time attached to a GateDigitizer - GateCoincidenceTimeDiffSelector(GateCoincidencePulseProcessorChain* itsChain, - const G4String& itsName); - + //GateCoincidenceTimeDiffSelector(GateCoincidencePulseProcessorChain* itsChain, + //const G4String& itsName); +void Digitize() override; public: //! Returns the TimeDiffSelector @@ -53,7 +63,7 @@ public: protected: /*! Implementation of the pure virtual method declared by the base class GateVCoincidencePulseProcessor*/ - GateCoincidencePulse* ProcessPulse(GateCoincidencePulse* inputPulse,G4int iPulse); + //GateCoincidencePulse* ProcessPulse(GateCoincidencePulse* inputPulse,G4int iPulse); @@ -61,6 +71,11 @@ private: G4double m_minTime; //!< TimeDiffSelector value G4double m_maxTime; //!< contains the rebirth time. GateCoincidenceTimeDiffSelectorMessenger *m_messenger; //!< Messenger + GateCoincidenceDigi* m_outputDigi; + + GateCoincidenceDigiCollection* m_OutputDigiCollection; + + GateCoincidenceDigitizer *m_digitizer; }; diff --git a/source/digits_hits/include/GateCoincidenceTimeDiffSelectorMessenger.hh b/source/digits_hits/include/GateCoincidenceTimeDiffSelectorMessenger.hh index 9a3bfbf2c..02064af52 100644 --- a/source/digits_hits/include/GateCoincidenceTimeDiffSelectorMessenger.hh +++ b/source/digits_hits/include/GateCoincidenceTimeDiffSelectorMessenger.hh @@ -10,7 +10,10 @@ See LICENSE.md for further details #ifndef GateCoincidenceTimeDiffSelectorMessenger_h #define GateCoincidenceTimeDiffSelectorMessenger_h 1 -#include "GatePulseProcessorMessenger.hh" +//#include "GatePulseProcessorMessenger.hh" +#include "GateClockDependentMessenger.hh" +#include "G4UImessenger.hh" +#include "globals.hh" class G4UIdirectory; class G4UIcmdWithoutParameter; @@ -21,20 +24,28 @@ class G4UIcmdWithADouble; class G4UIcmdWithADoubleAndUnit; class G4UIcmdWith3Vector; class G4UIcmdWith3VectorAndUnit; +class G4UIdirectory; class GateCoincidenceTimeDiffSelector; class GateCoincidenceTimeDiffSelectorMessenger: public GateClockDependentMessenger { public: - GateCoincidenceTimeDiffSelectorMessenger(GateCoincidenceTimeDiffSelector* itsTimeDiffSelector); - virtual ~GateCoincidenceTimeDiffSelectorMessenger(); + //GateCoincidenceTimeDiffSelectorMessenger(GateCoincidenceTimeDiffSelector* itsTimeDiffSelector); + //virtual ~GateCoincidenceTimeDiffSelectorMessenger(); + GateCoincidenceTimeDiffSelectorMessenger(GateCoincidenceTimeDiffSelector*); + ~GateCoincidenceTimeDiffSelectorMessenger(); + inline void SetNewValue(G4UIcommand* , G4String ); + + - inline void SetNewValue(G4UIcommand* aCommand, G4String aString); - inline GateCoincidenceTimeDiffSelector* GetTimeDiffSelector(){ return (GateCoincidenceTimeDiffSelector*) GetClockDependent(); } + + // inline GateCoincidenceTimeDiffSelector* GetTimeDiffSelector(){ return (GateCoincidenceTimeDiffSelector*) GetClockDependent(); } private: + GateCoincidenceTimeDiffSelector* m_CoincidenceTimeDiffSelector; + G4UIcmdWithADoubleAndUnit *minTimeCmd; //!< set the min time window G4UIcmdWithADoubleAndUnit *maxTimeCmd; //!< set the max time window }; diff --git a/source/digits_hits/src/GateCoincidenceDigi.cc b/source/digits_hits/src/GateCoincidenceDigi.cc index a9c9099b8..914ca17f6 100644 --- a/source/digits_hits/src/GateCoincidenceDigi.cc +++ b/source/digits_hits/src/GateCoincidenceDigi.cc @@ -41,6 +41,21 @@ GateCoincidenceDigi::GateCoincidenceDigi(GateDigi *firstDigi, } +G4double GateCoincidenceDigi::ComputeFinishTime() +{ + //std::vector< GateDigi* >* IDCVector = IDC->GetVector (); + std::vector::iterator iter; + + G4double finishTime = 0; + for (iter =begin(); iter < end() ; ++iter) { + if ( (*iter)->GetTime() > finishTime ){ + finishTime = (*iter)->GetTime(); + } + } + + + return finishTime; +} diff --git a/source/digits_hits/src/GateCoincidenceDigitizerMessenger.cc b/source/digits_hits/src/GateCoincidenceDigitizerMessenger.cc index cc090560a..fa7e08347 100644 --- a/source/digits_hits/src/GateCoincidenceDigitizerMessenger.cc +++ b/source/digits_hits/src/GateCoincidenceDigitizerMessenger.cc @@ -28,6 +28,7 @@ See LICENSE.md for further details #include "GateCoincidenceDeadTime.hh" #include "GateCoincidenceMultiplesKiller.hh" #include "GateCoincidenceBuffer.hh" +#include "GateCoincidenceTimeDiffSelector.hh" /*#include "GateAdder.hh" #include "GateReadout.hh" #include "GateEnergyFraming.hh" @@ -123,8 +124,7 @@ void GateCoincidenceDigitizerMessenger::SetNewValue(G4UIcommand* command,G4Strin const G4String& GateCoincidenceDigitizerMessenger::DumpMap() { - - static G4String theList = "deadtime multiplesKiller buffer";//readout adder energyFraming timeResolution energyResolution spatialResolution efficiency deadtime pileup adderCompton opticaladder noise merger"; + static G4String theList = "deadtime multiplesKiller buffer timeDiffSelector";//readout adder energyFraming timeResolution energyResolution spatialResolution efficiency deadtime pileup adderCompton opticaladder noise merger"; return theList; @@ -163,6 +163,11 @@ void GateCoincidenceDigitizerMessenger::DoInsertion(const G4String& childTypeNam newDM = new GateCoincidenceBuffer(m_CoinDigitizer, DMname); m_CoinDigitizer->AddNewModule(newDM); } + else if (childTypeName=="timeDiffSelector") + { + newDM = new GateCoincidenceTimeDiffSelector(m_CoinDigitizer, DMname); + m_CoinDigitizer->AddNewModule(newDM); + } /*else if (childTypeName=="readout") { diff --git a/source/digits_hits/src/GateCoincidenceTimeDiffSelector.cc b/source/digits_hits/src/GateCoincidenceTimeDiffSelector.cc index 552afc450..0595cb985 100644 --- a/source/digits_hits/src/GateCoincidenceTimeDiffSelector.cc +++ b/source/digits_hits/src/GateCoincidenceTimeDiffSelector.cc @@ -7,7 +7,7 @@ See LICENSE.md for further details ----------------------*/ -#include "GateCoincidenceTimeDiffSelector.hh" +#include "../include/GateCoincidenceTimeDiffSelector.hh" #include "G4UnitsTable.hh" #include "GateCoincidenceTimeDiffSelectorMessenger.hh" #include "GateTools.hh" @@ -19,15 +19,27 @@ See LICENSE.md for further details #include "GateObjectChildList.hh" #include "GateVVolume.hh" #include "GateMaps.hh" +#include "GateCoincidenceDigi.hh" +#include "GateDigitizerMgr.hh" -GateCoincidenceTimeDiffSelector::GateCoincidenceTimeDiffSelector(GateCoincidencePulseProcessorChain* itsChain, - const G4String& itsName) - : GateVCoincidencePulseProcessor(itsChain,itsName) -{ - m_minTime = -1; - m_maxTime = -1; - +#include "G4SystemOfUnits.hh" +#include "G4EventManager.hh" +#include "G4Event.hh" +#include "G4SDManager.hh" +#include "G4DigiManager.hh" +#include "G4ios.hh" +#include "G4UnitsTable.hh" +GateCoincidenceTimeDiffSelector::GateCoincidenceTimeDiffSelector(GateCoincidenceDigitizer *digitizer, G4String name) + :GateVDigitizerModule(name,"digitizerMgr/CoincidenceDigitizer/"+digitizer->m_digitizerName+"/"+name, digitizer), + m_outputDigi(0), + m_OutputDigiCollection(0), + m_digitizer(digitizer) + + { m_minTime = -1; + m_maxTime = -1; + G4String colName = digitizer->GetOutputName() ; + collectionName.push_back(colName); m_messenger = new GateCoincidenceTimeDiffSelectorMessenger(this); } @@ -40,26 +52,49 @@ GateCoincidenceTimeDiffSelector::~GateCoincidenceTimeDiffSelector() } +void GateCoincidenceTimeDiffSelector::Digitize() +{ + G4String digitizerName = m_digitizer->m_digitizerName; + G4String outputCollName = m_digitizer-> GetOutputName(); + m_OutputDigiCollection = new GateCoincidenceDigiCollection(GetName(),outputCollName); // to create the Digi Collection -GateCoincidencePulse* GateCoincidenceTimeDiffSelector::ProcessPulse(GateCoincidencePulse* inputPulse,G4int ) -{ - if (!inputPulse) { - if (nVerboseLevel>1) - G4cout << "[GateCoincidenceTimeDiffSelector::ProcessOnePulse]: input pulse was null -> nothing to do\n\n"; - return 0; + G4DigiManager* DigiMan = G4DigiManager::GetDMpointer(); + + + + + GateCoincidenceDigiCollection* IDC = 0; + IDC = (GateCoincidenceDigiCollection*) (DigiMan->GetDigiCollection(m_DCID)); + + GateCoincidenceDigi* inputDigi = new GateCoincidenceDigi(); + + std::vector< GateCoincidenceDigi* >* OutputDigiCollectionVector = m_OutputDigiCollection->GetVector (); + std::vector::iterator iter; + + if (IDC) { + G4int n_digi = IDC->entries(); + // Loop over input digits + for (G4int i = 0; i < n_digi; i++) { + GateCoincidenceDigi* inputDigi = (*IDC)[i]; // Retrieve input digi + G4double timeDiff = inputDigi->ComputeFinishTime() - inputDigi->GetStartTime(); + if (((m_minTime > 0) && (timeDiff < m_minTime)) || ((m_maxTime > 0) && (timeDiff > m_maxTime))) { + continue; // Skip this digi + } else { + m_outputDigi = new GateCoincidenceDigi(*inputDigi); + m_OutputDigiCollection->insert(m_outputDigi); + }//loop over input digits + }}//IDC +else + { + if (nVerboseLevel>1) + G4cout << "[GateCoincidenceDeadTime::Digitize]: input digi collection is null -> nothing to do\n\n"; + return; } +StoreDigiCollection(m_OutputDigiCollection); - G4double timeDiff = inputPulse->ComputeFinishTime()-inputPulse->GetStartTime(); - if ( ((m_minTime>0) && (timeDiff0) && (timeDiff>m_maxTime) ) ) - return 0; - else - return new GateCoincidencePulse(*inputPulse); } - void GateCoincidenceTimeDiffSelector::DescribeMyself(size_t indent) { G4cout << GateTools::Indent(indent) << "TimeDiffSelector: " diff --git a/source/digits_hits/src/GateCoincidenceTimeDiffSelectorMessenger.cc b/source/digits_hits/src/GateCoincidenceTimeDiffSelectorMessenger.cc index a69bb0a33..c2824fd65 100644 --- a/source/digits_hits/src/GateCoincidenceTimeDiffSelectorMessenger.cc +++ b/source/digits_hits/src/GateCoincidenceTimeDiffSelectorMessenger.cc @@ -10,12 +10,19 @@ See LICENSE.md for further details #include "GateCoincidenceTimeDiffSelectorMessenger.hh" #include "GateCoincidenceTimeDiffSelector.hh" - #include "G4UIcmdWithADoubleAndUnit.hh" #include "G4UIcmdWithAString.hh" +#include "GateDigitizerMgr.hh" +#include "G4UImessenger.hh" +#include "globals.hh" +#include "GateClockDependentMessenger.hh" +#include "G4SystemOfUnits.hh" +#include "G4UIdirectory.hh" + +GateCoincidenceTimeDiffSelectorMessenger::GateCoincidenceTimeDiffSelectorMessenger (GateCoincidenceTimeDiffSelector* CoincidenceTimeDiffSelector) +:GateClockDependentMessenger(CoincidenceTimeDiffSelector), + m_CoincidenceTimeDiffSelector(CoincidenceTimeDiffSelector) -GateCoincidenceTimeDiffSelectorMessenger::GateCoincidenceTimeDiffSelectorMessenger(GateCoincidenceTimeDiffSelector* itsTimeDiffSelector) - : GateClockDependentMessenger(itsTimeDiffSelector) { G4String guidance; G4String cmdName; @@ -44,9 +51,9 @@ GateCoincidenceTimeDiffSelectorMessenger::~GateCoincidenceTimeDiffSelectorMessen void GateCoincidenceTimeDiffSelectorMessenger::SetNewValue(G4UIcommand* command, G4String newValue) { if (command==minTimeCmd) - GetTimeDiffSelector()->SetMinTime(minTimeCmd->GetNewDoubleValue(newValue)); + m_CoincidenceTimeDiffSelector->SetMinTime(minTimeCmd->GetNewDoubleValue(newValue)); else if (command == maxTimeCmd) - GetTimeDiffSelector()->SetMaxTime(maxTimeCmd->GetNewDoubleValue(newValue)); + m_CoincidenceTimeDiffSelector->SetMaxTime(maxTimeCmd->GetNewDoubleValue(newValue)); else GateClockDependentMessenger::SetNewValue(command,newValue); } diff --git a/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc b/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc index 0f4be1d83..aad9787f5 100644 --- a/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc +++ b/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc @@ -9,9 +9,9 @@ See LICENSE.md for further details #include "GateCoincidencePulseProcessorChainMessenger.hh" -//#include "../../digits_hits/include/GateCoincidenceBuffer.hh" -//#include "../../digits_hits/include/GateCoincidenceMultiplesKiller.hh" -#include "../../digits_hits/include/GateCoincidenceTimeDiffSelector.hh" +//#include "../../digits_hits/include/GateCoincidenceBufferOld.hh" +//#include "../../digits_hits/include/GateCoincidenceMultiplesKillerOld.hh" +//#include "../../digits_hits/include/GateCoincidenceTimeDiffSelectorOld.hh" #include "G4UIdirectory.hh" #include "G4UIcmdWithAString.hh" #include "G4UIcmdWithABool.hh" @@ -92,8 +92,8 @@ void GateCoincidencePulseProcessorChainMessenger::DoInsertion(const G4String& ch */ if (childTypeName=="sequenceRecon") newProcessor = new GateCCCoincidenceSequenceRecon(GetProcessorChain(),newInsertionName); - else if (childTypeName=="timeDiffSelector") - newProcessor = new GateCoincidenceTimeDiffSelector(GetProcessorChain(),newInsertionName); + //else if (childTypeName=="timeDiffSelector") + //newProcessor = new GateCoincidenceTimeDiffSelector(GetProcessorChain(),newInsertionName); else if (childTypeName=="geometrySelector") newProcessor = new GateCoincidenceGeometrySelector(GetProcessorChain(),newInsertionName); // else if (childTypeName=="buffer") From 42ee83a0e8bfccd8fc41454ea66559191a1457f1 Mon Sep 17 00:00:00 2001 From: Radia Oudihat Date: Tue, 27 Aug 2024 11:40:29 +0200 Subject: [PATCH 09/96] - Added a check based on the global positions of events to filter out invalid coincidences. - Implemented a new condition to check the difference in Z to reject coincidences. - Rejected coincidences if they do not meet the distance and angle criteria --- .../include/GateCoincidenceSorter.hh | 9 ++++- .../include/GateCoincidenceSorterMessenger.hh | 2 + .../digits_hits/src/GateCoincidenceSorter.cc | 39 ++++++++++++++++++- .../src/GateCoincidenceSorterMessenger.cc | 16 ++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/source/digits_hits/include/GateCoincidenceSorter.hh b/source/digits_hits/include/GateCoincidenceSorter.hh index f6762c95e..abdc43027 100644 --- a/source/digits_hits/include/GateCoincidenceSorter.hh +++ b/source/digits_hits/include/GateCoincidenceSorter.hh @@ -170,6 +170,12 @@ public: void SetAcceptancePolicy4CC(const G4String& policy); + G4double GetMaxS() const {return m_maxS;} + G4double GetMaxDeltaZ() const {return m_maxDeltaZ;} + + //! Set the GeometrySelector + void SetMaxS(G4double val) { m_maxS = val;} + void SetMaxDeltaZ(G4double val) { m_maxDeltaZ = val;} @@ -190,7 +196,8 @@ protected: acceptance_policy_4CC_t m_acceptance_policy_4CC; //! refused\n"; return true; } + G4ThreeVector globalPos1 = digi1->GetGlobalPos(); + G4ThreeVector globalPos2 = digi2->GetGlobalPos(); - return false; - } + // Vérification de la différence en Z entre les deux positions + if ((m_maxDeltaZ > 0) && (fabs(globalPos2.z() - globalPos1.z()) > m_maxDeltaZ)) { + if (nVerboseLevel > 1) + G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: difference in Z too large --> refused\n"; + return true; + } + + // Calcul du dénominateur pour la distance 's' dans le plan XY + G4double denom = (globalPos1.y() - globalPos2.y()) * (globalPos1.y() - globalPos2.y()) + + (globalPos2.x() - globalPos1.x()) * (globalPos2.x() - globalPos1.x()); + + G4double s = 0.0; + if (denom != 0.0) { + denom = sqrt(denom); + s = (globalPos1.x() * (globalPos1.y() - globalPos2.y()) + + globalPos1.y() * (globalPos2.x() - globalPos1.x())) / denom; + } + // Calcul de l'angle theta dans le plan XY + G4double theta = atan2(globalPos1.x() - globalPos2.x(), globalPos1.y() - globalPos2.y()); + if (theta < 0.0) { + theta += pi; // Ajuste theta pour qu'il soit dans l'intervalle [0, pi] + s = -s; // Inverse la distance s si l'angle est ajusté + } + + // Vérification de la distance 's' par rapport au seuil maximal + if ((m_maxS > 0) && (fabs(s) > m_maxS)) { + if (nVerboseLevel > 1) + G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: distance s too large --> refused\n"; + return true; + } + + return false; + } } //------------------------------------------------------------------------------------------------------ diff --git a/source/digits_hits/src/GateCoincidenceSorterMessenger.cc b/source/digits_hits/src/GateCoincidenceSorterMessenger.cc index e12cfc6f7..db739edc1 100644 --- a/source/digits_hits/src/GateCoincidenceSorterMessenger.cc +++ b/source/digits_hits/src/GateCoincidenceSorterMessenger.cc @@ -53,6 +53,16 @@ GateCoincidenceSorterMessenger::GateCoincidenceSorterMessenger(GateCoincidenceSo minSectorDiffCmd->SetParameterName("diff",false); minSectorDiffCmd->SetRange("diff>=1"); + cmdName = GetDirectoryName() + "setSMax"; + maxSCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); + maxSCmd->SetGuidance("Set max S value accepted (<0 --> all is accepted)"); + maxSCmd->SetUnitCategory("Length"); + + cmdName = GetDirectoryName() + "setDeltaZMax"; + maxDeltaZCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); + maxDeltaZCmd->SetGuidance("Set max delta Z value accepted (<0 --> all is accepted)"); + maxDeltaZCmd->SetUnitCategory("Length"); + cmdName = GetDirectoryName()+"forceMinSecDifferenceToZero"; forceMinSectorDiffCmd = new G4UIcmdWithABool(cmdName,this); forceMinSectorDiffCmd->SetGuidance("Force the minimum sector difference for valid coincidences to 0: specsific case for prototype testbench simulations."); @@ -118,6 +128,8 @@ GateCoincidenceSorterMessenger::~GateCoincidenceSorterMessenger() delete SetAcceptancePolicy4CCCmd; delete SetEventIDCoincCmd; delete forceMinSectorDiffCmd; + delete maxSCmd; + delete maxDeltaZCmd; } @@ -135,6 +147,10 @@ void GateCoincidenceSorterMessenger::SetNewValue(G4UIcommand* aCommand, G4String { m_CoincidenceSorter->SetForcedTo0MinSectorDifference(forceMinSectorDiffCmd->GetNewBoolValue(newValue)); } else if( aCommand == minSectorDiffCmd ) { m_CoincidenceSorter->SetMinSectorDifference(minSectorDiffCmd->GetNewIntValue(newValue)); } + else if (aCommand==maxSCmd) + m_CoincidenceSorter->SetMaxS(maxSCmd->GetNewDoubleValue(newValue)); + else if (aCommand==maxDeltaZCmd) + m_CoincidenceSorter->SetMaxDeltaZ(maxDeltaZCmd->GetNewDoubleValue(newValue)); else if( aCommand == setDepthCmd ) { m_CoincidenceSorter->SetDepth(setDepthCmd->GetNewIntValue(newValue)); } else if( aCommand == setPresortBufferSizeCmd ) From c01682fa023189d6c23bd7c33d94d6edd868313a Mon Sep 17 00:00:00 2001 From: Radia Oudihat Date: Tue, 27 Aug 2024 11:42:52 +0200 Subject: [PATCH 10/96] - Added a check based on the global positions of events to filter out invalid coincidences. - Implemented a new condition to check the difference in Z to reject coincidences. - Rejected coincidences if they do not meet the distance and angle criteria --- .../digits_hits/src/GateCoincidenceSorter.cc | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/source/digits_hits/src/GateCoincidenceSorter.cc b/source/digits_hits/src/GateCoincidenceSorter.cc index 3c2b6d469..11ecff214 100644 --- a/source/digits_hits/src/GateCoincidenceSorter.cc +++ b/source/digits_hits/src/GateCoincidenceSorter.cc @@ -739,42 +739,42 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: coincidence between neighbour blocks --> refused\n"; return true; } - G4ThreeVector globalPos1 = digi1->GetGlobalPos(); - G4ThreeVector globalPos2 = digi2->GetGlobalPos(); + G4ThreeVector globalPos1 = digi1->GetGlobalPos(); + G4ThreeVector globalPos2 = digi2->GetGlobalPos(); - // Vérification de la différence en Z entre les deux positions - if ((m_maxDeltaZ > 0) && (fabs(globalPos2.z() - globalPos1.z()) > m_maxDeltaZ)) { - if (nVerboseLevel > 1) - G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: difference in Z too large --> refused\n"; - return true; - } + // Check the difference in Z between the two positions + if ((m_maxDeltaZ > 0) && (fabs(globalPos2.z() - globalPos1.z()) > m_maxDeltaZ)) { + if (nVerboseLevel > 1) + G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: difference in Z too large --> refused\n"; + return true; + } - // Calcul du dénominateur pour la distance 's' dans le plan XY - G4double denom = (globalPos1.y() - globalPos2.y()) * (globalPos1.y() - globalPos2.y()) + - (globalPos2.x() - globalPos1.x()) * (globalPos2.x() - globalPos1.x()); + // Calculate the denominator for distance 's' in the XY plane + G4double denom = (globalPos1.y() - globalPos2.y()) * (globalPos1.y() - globalPos2.y()) + + (globalPos2.x() - globalPos1.x()) * (globalPos2.x() - globalPos1.x()); - G4double s = 0.0; - if (denom != 0.0) { - denom = sqrt(denom); - s = (globalPos1.x() * (globalPos1.y() - globalPos2.y()) + - globalPos1.y() * (globalPos2.x() - globalPos1.x())) / denom; - } + G4double s = 0.0; + if (denom != 0.0) { + denom = sqrt(denom); + s = (globalPos1.x() * (globalPos1.y() - globalPos2.y()) + + globalPos1.y() * (globalPos2.x() - globalPos1.x())) / denom; + } - // Calcul de l'angle theta dans le plan XY - G4double theta = atan2(globalPos1.x() - globalPos2.x(), globalPos1.y() - globalPos2.y()); - if (theta < 0.0) { - theta += pi; // Ajuste theta pour qu'il soit dans l'intervalle [0, pi] - s = -s; // Inverse la distance s si l'angle est ajusté - } + // Calculate the angle theta in the XY plane + G4double theta = atan2(globalPos1.x() - globalPos2.x(), globalPos1.y() - globalPos2.y()); + if (theta < 0.0) { + theta += pi; // Adjust theta to be in the range [0, pi] + s = -s; // Invert the distance s if the angle is adjusted + } - // Vérification de la distance 's' par rapport au seuil maximal - if ((m_maxS > 0) && (fabs(s) > m_maxS)) { - if (nVerboseLevel > 1) - G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: distance s too large --> refused\n"; - return true; - } + // Check the distance 's' against the maximum threshold + if ((m_maxS > 0) && (fabs(s) > m_maxS)) { + if (nVerboseLevel > 1) + G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: distance s too large --> refused\n"; + return true; + } - return false; + return false; } } //------------------------------------------------------------------------------------------------------ From 0f1e312c9ec7985780b8c84cbadad9abcb3adbf2 Mon Sep 17 00:00:00 2001 From: Radia Oudihat Date: Tue, 3 Sep 2024 14:13:58 +0200 Subject: [PATCH 11/96] modification:delete GateCoincidenceGeometrySelector --- .../GateCoincidenceGeometrySelector.hh | 67 ------------- ...ateCoincidenceGeometrySelectorMessenger.hh | 35 ------- .../include/GateCoincidenceSorter.hh | 6 +- .../include/GateCoincidenceSorterMessenger.hh | 2 +- .../src/GateCoincidenceGeometrySelector.cc | 98 ------------------- ...ateCoincidenceGeometrySelectorMessenger.cc | 49 ---------- .../digits_hits/src/GateCoincidenceSorter.cc | 10 +- .../src/GateCoincidenceSorterMessenger.cc | 14 +-- 8 files changed, 13 insertions(+), 268 deletions(-) delete mode 100644 source/digits_hits/include/GateCoincidenceGeometrySelector.hh delete mode 100644 source/digits_hits/include/GateCoincidenceGeometrySelectorMessenger.hh delete mode 100644 source/digits_hits/src/GateCoincidenceGeometrySelector.cc delete mode 100644 source/digits_hits/src/GateCoincidenceGeometrySelectorMessenger.cc diff --git a/source/digits_hits/include/GateCoincidenceGeometrySelector.hh b/source/digits_hits/include/GateCoincidenceGeometrySelector.hh deleted file mode 100644 index 7b61b2cce..000000000 --- a/source/digits_hits/include/GateCoincidenceGeometrySelector.hh +++ /dev/null @@ -1,67 +0,0 @@ -/*---------------------- - Copyright (C): OpenGATE Collaboration - -This software is distributed under the terms -of the GNU Lesser General Public Licence (LGPL) -See LICENSE.md for further details -----------------------*/ - - -#ifndef GateCoincidenceGeometrySelector_h -#define GateCoincidenceGeometrySelector_h 1 - -#include "globals.hh" -#include -#include -#include "G4ThreeVector.hh" - -#include "GateVPulseProcessor.hh" -#include "GateObjectStore.hh" -#include "GateVCoincidencePulseProcessor.hh" - -class GateCoincidenceGeometrySelectorMessenger; - - -class GateCoincidenceGeometrySelector : public GateVCoincidencePulseProcessor -{ -public: - - - - //! Destructor - virtual ~GateCoincidenceGeometrySelector() ; - - - //! Constructs a new dead time attached to a GateDigitizer - GateCoincidenceGeometrySelector(GateCoincidencePulseProcessorChain* itsChain, - const G4String& itsName); - -public: - - //! Returns the GeometrySelector - G4double GetMaxS() const {return m_maxS;} - G4double GetMaxDeltaZ() const {return m_maxDeltaZ;} - - //! Set the GeometrySelector - void SetMaxS(G4double val) { m_maxS = val;} - void SetMaxDeltaZ(G4double val) { m_maxDeltaZ = val;} - - //! Implementation of the pure virtual method declared by the base class GateClockDependent - //! print-out the attributes specific of the GeometrySelector - virtual void DescribeMyself(size_t indent); - -protected: - - /*! Implementation of the pure virtual method declared by the base class GateVCoincidencePulseProcessor*/ - GateCoincidencePulse* ProcessPulse(GateCoincidencePulse* inputPulse,G4int iPulse); - - - -private: - G4double m_maxS; //!< contains the rebirth time. - G4double m_maxDeltaZ; //!< contains the rebirth time. - GateCoincidenceGeometrySelectorMessenger *m_messenger; //!< Messenger -}; - - -#endif diff --git a/source/digits_hits/include/GateCoincidenceGeometrySelectorMessenger.hh b/source/digits_hits/include/GateCoincidenceGeometrySelectorMessenger.hh deleted file mode 100644 index 1804af823..000000000 --- a/source/digits_hits/include/GateCoincidenceGeometrySelectorMessenger.hh +++ /dev/null @@ -1,35 +0,0 @@ -/*---------------------- - Copyright (C): OpenGATE Collaboration - -This software is distributed under the terms -of the GNU Lesser General Public Licence (LGPL) -See LICENSE.md for further details -----------------------*/ - - -#ifndef GateCoincidenceGeometrySelectorMessenger_h -#define GateCoincidenceGeometrySelectorMessenger_h 1 - -#include "GatePulseProcessorMessenger.hh" - -class G4UIdirectory; -class G4UIcmdWithADoubleAndUnit; - -class GateCoincidenceGeometrySelector; - -class GateCoincidenceGeometrySelectorMessenger: public GateClockDependentMessenger -{ -public: - GateCoincidenceGeometrySelectorMessenger(GateCoincidenceGeometrySelector* itsGeometrySelector); - virtual ~GateCoincidenceGeometrySelectorMessenger(); - - inline void SetNewValue(G4UIcommand* aCommand, G4String aString); - - inline GateCoincidenceGeometrySelector* GetGeometrySelector(){ return (GateCoincidenceGeometrySelector*) GetClockDependent(); } - -private: - G4UIcmdWithADoubleAndUnit *maxSCmd; //!< set the max time window - G4UIcmdWithADoubleAndUnit *maxDeltaZCmd; //!< set the max time window -}; - -#endif diff --git a/source/digits_hits/include/GateCoincidenceSorter.hh b/source/digits_hits/include/GateCoincidenceSorter.hh index abdc43027..be6a893c0 100644 --- a/source/digits_hits/include/GateCoincidenceSorter.hh +++ b/source/digits_hits/include/GateCoincidenceSorter.hh @@ -170,11 +170,11 @@ public: void SetAcceptancePolicy4CC(const G4String& policy); - G4double GetMaxS() const {return m_maxS;} + G4double GetMinS() const {return m_minS;} G4double GetMaxDeltaZ() const {return m_maxDeltaZ;} //! Set the GeometrySelector - void SetMaxS(G4double val) { m_maxS = val;} + void SetMinS(G4double val) { m_minS = val;} void SetMaxDeltaZ(G4double val) { m_maxDeltaZ = val;} @@ -196,7 +196,7 @@ protected: acceptance_policy_4CC_t m_acceptance_policy_4CC; //! 1) - G4cout << "[GateCoincidenceGeometrySelector::ProcessOnePulse]: input pulse was null -> nothing to do\n\n"; - return 0; - } - - G4double s; - if (inputPulse->size() != 2) { - if (nVerboseLevel>1) - G4cout << "[GateCoincidenceGeometrySelector::ProcessOnePulse]: input pulse has not 2 pulses -> nothing to do\n\n"; - return 0; - } - - G4ThreeVector globalPos1 = (*inputPulse)[0]->GetGlobalPos(); - G4ThreeVector globalPos2 = (*inputPulse)[1]->GetGlobalPos(); - - if ((m_maxDeltaZ>0) && (fabs(globalPos2.z()-globalPos1.z())>m_maxDeltaZ) ) - return 0; - - G4double denom = (globalPos1.y()-globalPos2.y()) * (globalPos1.y()-globalPos2.y()) + - (globalPos2.x()-globalPos1.x()) * (globalPos2.x()-globalPos1.x()); - - if (denom!=0.) { - denom = sqrt(denom); - - s = ( globalPos1.x() * (globalPos1.y()-globalPos2.y()) + - globalPos1.y() * (globalPos2.x()-globalPos1.x()) ) - / denom; - } else { - s = 0.; - } - - G4double theta; - theta = atan2(globalPos1.x()-globalPos2.x(), globalPos1.y()-globalPos2.y()); - if ( theta < 0.) { - theta = theta + pi; - s = -s; - } - if ((m_maxS>0) && (fabs(s)>m_maxS) ) return 0; - - return new GateCoincidencePulse(*inputPulse); -} - - -void GateCoincidenceGeometrySelector::DescribeMyself(size_t indent) -{ - G4cout << GateTools::Indent(indent) << "GeometrySelector: " - << "SMax : "<SetGuidance("Set max S value accepted (<0 --> all is accepted)"); - maxSCmd->SetUnitCategory("Length"); - - cmdName = GetDirectoryName() + "setDeltaZMax"; - maxDeltaZCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); - maxDeltaZCmd->SetGuidance("Set max delta Z value accepted (<0 --> all is accepted)"); - maxDeltaZCmd->SetUnitCategory("Length"); -} - - -GateCoincidenceGeometrySelectorMessenger::~GateCoincidenceGeometrySelectorMessenger() -{ - delete maxSCmd; - delete maxDeltaZCmd; -} - - -void GateCoincidenceGeometrySelectorMessenger::SetNewValue(G4UIcommand* command, G4String newValue) -{ - if (command==maxSCmd) - GetGeometrySelector()->SetMaxS(maxSCmd->GetNewDoubleValue(newValue)); - else if (command==maxDeltaZCmd) - GetGeometrySelector()->SetMaxDeltaZ(maxDeltaZCmd->GetNewDoubleValue(newValue)); - else - GateClockDependentMessenger::SetNewValue(command,newValue); -} diff --git a/source/digits_hits/src/GateCoincidenceSorter.cc b/source/digits_hits/src/GateCoincidenceSorter.cc index 11ecff214..560f16ac1 100644 --- a/source/digits_hits/src/GateCoincidenceSorter.cc +++ b/source/digits_hits/src/GateCoincidenceSorter.cc @@ -40,7 +40,7 @@ GateCoincidenceSorter::GateCoincidenceSorter(GateDigitizerMgr* itsDigitizerMgr, m_offset(0.), m_offsetJitter(0.), m_minSectorDifference(2), - m_maxS (-1), + m_minS (-1), m_maxDeltaZ ( -1), m_forceMinSecDifferenceToZero(false), m_multiplesPolicy(kKeepIfAllAreGoods), @@ -760,15 +760,9 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons globalPos1.y() * (globalPos2.x() - globalPos1.x())) / denom; } - // Calculate the angle theta in the XY plane - G4double theta = atan2(globalPos1.x() - globalPos2.x(), globalPos1.y() - globalPos2.y()); - if (theta < 0.0) { - theta += pi; // Adjust theta to be in the range [0, pi] - s = -s; // Invert the distance s if the angle is adjusted - } // Check the distance 's' against the maximum threshold - if ((m_maxS > 0) && (fabs(s) > m_maxS)) { + if ((m_minS > 0) && (fabs(s) > m_minS)) { if (nVerboseLevel > 1) G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: distance s too large --> refused\n"; return true; diff --git a/source/digits_hits/src/GateCoincidenceSorterMessenger.cc b/source/digits_hits/src/GateCoincidenceSorterMessenger.cc index db739edc1..0bc0af8c4 100644 --- a/source/digits_hits/src/GateCoincidenceSorterMessenger.cc +++ b/source/digits_hits/src/GateCoincidenceSorterMessenger.cc @@ -53,10 +53,10 @@ GateCoincidenceSorterMessenger::GateCoincidenceSorterMessenger(GateCoincidenceSo minSectorDiffCmd->SetParameterName("diff",false); minSectorDiffCmd->SetRange("diff>=1"); - cmdName = GetDirectoryName() + "setSMax"; - maxSCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); - maxSCmd->SetGuidance("Set max S value accepted (<0 --> all is accepted)"); - maxSCmd->SetUnitCategory("Length"); + cmdName = GetDirectoryName() + "SetMinS"; + minSCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); + minSCmd->SetGuidance("Set min S value accepted (<0 --> all is accepted)"); + minSCmd->SetUnitCategory("Length"); cmdName = GetDirectoryName() + "setDeltaZMax"; maxDeltaZCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); @@ -128,7 +128,7 @@ GateCoincidenceSorterMessenger::~GateCoincidenceSorterMessenger() delete SetAcceptancePolicy4CCCmd; delete SetEventIDCoincCmd; delete forceMinSectorDiffCmd; - delete maxSCmd; + delete minSCmd; delete maxDeltaZCmd; } @@ -147,8 +147,8 @@ void GateCoincidenceSorterMessenger::SetNewValue(G4UIcommand* aCommand, G4String { m_CoincidenceSorter->SetForcedTo0MinSectorDifference(forceMinSectorDiffCmd->GetNewBoolValue(newValue)); } else if( aCommand == minSectorDiffCmd ) { m_CoincidenceSorter->SetMinSectorDifference(minSectorDiffCmd->GetNewIntValue(newValue)); } - else if (aCommand==maxSCmd) - m_CoincidenceSorter->SetMaxS(maxSCmd->GetNewDoubleValue(newValue)); + else if (aCommand==minSCmd) + m_CoincidenceSorter->SetMinS(minSCmd->GetNewDoubleValue(newValue)); else if (aCommand==maxDeltaZCmd) m_CoincidenceSorter->SetMaxDeltaZ(maxDeltaZCmd->GetNewDoubleValue(newValue)); else if( aCommand == setDepthCmd ) From 64ca369bb205c4bdfcb436662d910363baa9f681 Mon Sep 17 00:00:00 2001 From: Radia Oudihat Date: Fri, 30 Aug 2024 10:11:00 +0200 Subject: [PATCH 12/96] modification --- source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh b/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh index ca1c752f4..eca546407 100644 --- a/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh +++ b/source/digits_hits/include/GateCoincidenceTimeDiffSelector.hh @@ -31,7 +31,7 @@ See LICENSE.md for further details class GateCoincidenceTimeDiffSelectorMessenger; -class GateCoincidenceTimeDiffSelector : public GateVDigitizerModule,public GateDigi +class GateCoincidenceTimeDiffSelector : public GateVDigitizerModule { public: From d136afd2d90934169d8b630b67e01b34b06b3289 Mon Sep 17 00:00:00 2001 From: tontyoutoure Date: Thu, 15 Aug 2024 13:47:48 +0800 Subject: [PATCH 13/96] make sure resolution has a initial value --- source/digits_hits/src/GateEnergyResolution.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/digits_hits/src/GateEnergyResolution.cc b/source/digits_hits/src/GateEnergyResolution.cc index baeb35290..171a05784 100755 --- a/source/digits_hits/src/GateEnergyResolution.cc +++ b/source/digits_hits/src/GateEnergyResolution.cc @@ -95,7 +95,7 @@ void GateEnergyResolution::Digitize() GateDigi* inputDigi; - G4double reso; + G4double reso = 0; if (IDC) { From 96caf49a878d62d533e31577ce403d04590d5499 Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Tue, 3 Sep 2024 15:43:12 +0200 Subject: [PATCH 14/96] Update GateCoincidenceSorter.cc --- source/digits_hits/src/GateCoincidenceSorter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/digits_hits/src/GateCoincidenceSorter.cc b/source/digits_hits/src/GateCoincidenceSorter.cc index 560f16ac1..f77f905fd 100644 --- a/source/digits_hits/src/GateCoincidenceSorter.cc +++ b/source/digits_hits/src/GateCoincidenceSorter.cc @@ -762,7 +762,7 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons // Check the distance 's' against the maximum threshold - if ((m_minS > 0) && (fabs(s) > m_minS)) { + if ((m_minS < 0) && (fabs(s) < m_minS)) { if (nVerboseLevel > 1) G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: distance s too large --> refused\n"; return true; From 6492eaa3c13445c11e2e809251b8f8ef65bc6a10 Mon Sep 17 00:00:00 2001 From: Radia Oudihat Date: Tue, 3 Sep 2024 15:48:12 +0200 Subject: [PATCH 15/96] modification --- .../src/GateCoincidencePulseProcessorChainMessenger.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc b/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc index aad9787f5..9519c1e50 100644 --- a/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc +++ b/source/physics/src/GateCoincidencePulseProcessorChainMessenger.cc @@ -20,7 +20,7 @@ See LICENSE.md for further details #include "GateCoincidencePulseProcessorChain.hh" //#include "GateCoincidenceDeadTime.hh" -#include "GateCoincidenceGeometrySelector.hh" +//#include "GateCoincidenceGeometrySelector.hh" #include "GateTriCoincidenceSorter.hh" //mhadi_add #include "GateCCCoincidenceSequenceRecon.hh"//AE @@ -94,8 +94,8 @@ void GateCoincidencePulseProcessorChainMessenger::DoInsertion(const G4String& ch newProcessor = new GateCCCoincidenceSequenceRecon(GetProcessorChain(),newInsertionName); //else if (childTypeName=="timeDiffSelector") //newProcessor = new GateCoincidenceTimeDiffSelector(GetProcessorChain(),newInsertionName); - else if (childTypeName=="geometrySelector") - newProcessor = new GateCoincidenceGeometrySelector(GetProcessorChain(),newInsertionName); + //else if (childTypeName=="geometrySelector") + //newProcessor = new GateCoincidenceGeometrySelector(GetProcessorChain(),newInsertionName); // else if (childTypeName=="buffer") // newProcessor = new GateCoincidenceBuffer(GetProcessorChain(),newInsertionName); //else if (childTypeName=="multiplesKiller") From d0098dcbaefcbafb6ea90c0b15cb445d8dd73c41 Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Wed, 4 Sep 2024 09:53:13 +0200 Subject: [PATCH 16/96] Update GateCoincidenceSorterMessenger.cc --- source/digits_hits/src/GateCoincidenceSorterMessenger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/digits_hits/src/GateCoincidenceSorterMessenger.cc b/source/digits_hits/src/GateCoincidenceSorterMessenger.cc index 0bc0af8c4..0c7842d46 100644 --- a/source/digits_hits/src/GateCoincidenceSorterMessenger.cc +++ b/source/digits_hits/src/GateCoincidenceSorterMessenger.cc @@ -53,7 +53,7 @@ GateCoincidenceSorterMessenger::GateCoincidenceSorterMessenger(GateCoincidenceSo minSectorDiffCmd->SetParameterName("diff",false); minSectorDiffCmd->SetRange("diff>=1"); - cmdName = GetDirectoryName() + "SetMinS"; + cmdName = GetDirectoryName() + "setSMin"; minSCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); minSCmd->SetGuidance("Set min S value accepted (<0 --> all is accepted)"); minSCmd->SetUnitCategory("Length"); From f05e9f35539769a5d461d03015871c3186362bdc Mon Sep 17 00:00:00 2001 From: Oudihat-Radia Date: Fri, 30 Aug 2024 10:18:01 +0200 Subject: [PATCH 17/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index c093c0ae4..9f287b105 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1432,7 +1432,6 @@ Here is an example of how to configure this in a macro file: /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/buffer/setMode 1 - For a coincidence sorter user can chose a presort buffer with a following command: /gate/digitizer/Coincidences/setPresortBufferSize 256 @@ -1444,7 +1443,7 @@ A presort buffer contains singles that have not yet been checked for coincidence Multiple coincidence removal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If the multiple coincidences are kept and not split into pairs (i.e., if any of the **keepXXX** multiple coincidence policies are used), the multicoincidences could contribute to dataflow occupancy but cannot be written to the disk. Unless otherwise specified, any multicoincidence is then cleared from data just before the disk writing. If needed, this clearing could be performed at any earlier coincidence processing step by inserting the **MultiplesKiller** module at the required level. This module has no parameters and simply removes the multicoincidence events. Multiple coincidences split into many pairs are not affected by this module and cannot be distinguished from normal "simple" coincidences. To insert a multipleKiller, use the syntax :: +If the multiple coincidences are kept and not split into pairs (i.e., if any of the **keepXXX** multiple coincidence policies are used), the multicoincidences could contribute to dataflow occupancy but cannot be written to the disk. Unless otherwise specified, any multicoincidence is then cleared from data just before the disk writing. If needed, this clearing could be performed at any earlier coincidence processing step by inserting the **multiplesKiller** module at the required level. This module has no parameters and simply removes the multicoincidence events. Multiple coincidences split into many pairs are not affected by this module and cannot be distinguished from normal "simple" coincidences. To insert a multipleKiller, use the syntax :: /gate/digitizerMgr/CoincidenceDigitizer/finalCoinc/insert multiplesKiller @@ -1453,7 +1452,7 @@ If the multiple coincidences are kept and not split into pairs (i.e., if any of Coincidence Time Difference Selector ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Responsible for selecting events based on the time difference between input signals. Below is an example of how to configure it in a macro file: +This module reprocesses the list of coincidences and applies a cut on the time difference between two Singles forming the coincidence, i. e. appalling a cut tighter than coincidence time window selected by coincidence sorter. From 0715dd307ea348e9dd154bab4d041acb55bdadf8 Mon Sep 17 00:00:00 2001 From: kochebina Date: Tue, 17 Sep 2024 16:17:32 +0200 Subject: [PATCH 18/96] Remove keep-options in policy for CoinSorter --- .../include/GateCoincidenceSorter.hh | 21 ++++++-- .../digits_hits/src/GateCoincidenceSorter.cc | 51 +++++++++++++++---- .../src/GateCoincidenceSorterMessenger.cc | 2 +- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/source/digits_hits/include/GateCoincidenceSorter.hh b/source/digits_hits/include/GateCoincidenceSorter.hh index be6a893c0..67446af2d 100644 --- a/source/digits_hits/include/GateCoincidenceSorter.hh +++ b/source/digits_hits/include/GateCoincidenceSorter.hh @@ -39,16 +39,29 @@ class GateDigitizerMgr; // 01/2016 Rewritten completely by Jared.STRYDHORST@cea.fr +// 2023 Added to GND kochebina@gmail.com + +/* + 09/24 kochebina@gmail.com + Simplification of number of options for multiple coincidences + remove "keep" and replace (or remove if double) with "take", + i.e. all coincidecnes are now written on disk + keepIfAllAreGoods = takeWinnerIfAllAreGoods + keepIfOnlyOneGood = takeWinnerIfOnlyOneGood + keepIfAnyIsGood = takeWinnerOfGoods + kKeepAll = removed +*/ typedef enum {kKillAll, kTakeAllGoods, kKillAllIfMultipleGoods, kTakeWinnerOfGoods, kTakeWinnerIfIsGood, kTakeWinnerIfAllAreGoods, - kKeepIfAllAreGoods, - kKeepIfOnlyOneGood, - kKeepIfAnyIsGood, - kKeepAll} multiple_policy_t; + kTakeWinnerIfOnlyOneGood + //kKeepIfOnlyOneGood, + //kKeepIfAnyIsGood, + //kKeepAll + } multiple_policy_t; diff --git a/source/digits_hits/src/GateCoincidenceSorter.cc b/source/digits_hits/src/GateCoincidenceSorter.cc index f77f905fd..2c1f24a4b 100644 --- a/source/digits_hits/src/GateCoincidenceSorter.cc +++ b/source/digits_hits/src/GateCoincidenceSorter.cc @@ -43,7 +43,7 @@ GateCoincidenceSorter::GateCoincidenceSorter(GateDigitizerMgr* itsDigitizerMgr, m_minS (-1), m_maxDeltaZ ( -1), m_forceMinSecDifferenceToZero(false), - m_multiplesPolicy(kKeepIfAllAreGoods), + m_multiplesPolicy(kTakeWinnerIfAllAreGoods), m_allDigiOpenCoincGate(false), m_depth(1), m_presortBufferSize(256), @@ -132,15 +132,31 @@ void GateCoincidenceSorter::SetMultiplesPolicy(const G4String& policy) else if (policy=="killAllIfMultipleGoods") m_multiplesPolicy=kKillAllIfMultipleGoods; else if (policy=="keepIfAnyIsGood") - m_multiplesPolicy=kKeepIfAnyIsGood; + { + m_multiplesPolicy= kTakeWinnerOfGoods;//kKeepIfAnyIsGood; + G4cout<<"WARNING (Coincidence Sorter): used policy keepIfAnyIsGood is outdated. Please, use takeWinnerOfGoods instead.\n"; + } else if (policy=="keepIfOnlyOneGood") - m_multiplesPolicy=kKeepIfOnlyOneGood; - else if (policy=="keepAll") - m_multiplesPolicy=kKeepAll; + { + m_multiplesPolicy= kTakeWinnerIfOnlyOneGood;//kKeepIfOnlyOneGood; + G4cout<<"WARNING (Coincidence Sorter): used policy keepIfOnlyOneGood is outdated. Please, use takeWinnerIfOnlyOneGood instead.\n"; + } + else if (policy=="takeWinnerIfOnlyOneGood") + { + m_multiplesPolicy= kTakeWinnerIfOnlyOneGood; + } + + //else if (policy=="keepAll") + // m_multiplesPolicy=kKeepAll; else { - if (policy!="keepIfAllAreGoods") - G4cout<<"WARNING : policy not recognized, using default : keepMultiplesIfAllAreGoods\n"; - m_multiplesPolicy=kKeepIfAllAreGoods; + if(policy == "keepIfAllAreGoods") + G4cout<<"WARNING (Coincidence Sorter): used policy keepIfAllAreGoods is outdated. Please, use takeWinnerIfAllAreGoods instead.\n"; + else + if (policy!="takeWinnerIfAllAreGoods" ) + G4cout<<"WARNING : policy not recognized, using default : takeWinnerIfAllAreGoods\n"; + + m_multiplesPolicy= kTakeWinnerIfAllAreGoods;//kKeepIfAllAreGoods; + } } //------------------------------------------------------------------------------------------------------ @@ -454,9 +470,9 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDig return; } - //G4cout<<"nGoods = "<< nGoods<SetGuidance("How to treat multiples coincidences"); - MultiplePolicyCmd->SetCandidates("killAll takeAllGoods killAllIfMultipleGoods takeWinnerOfGoods takeWinnerIfIsGood takeWinnerIfAllAreGoods keepAll keepIfAnyIsGood keepIfOnlyOneGood keepIfAllAreGoods"); + MultiplePolicyCmd->SetCandidates("killAll takeAllGoods killAllIfMultipleGoods takeWinnerOfGoods takeWinnerIfIsGood takeWinnerIfAllAreGoods takeWinnerIfOnlyOneGood keepIfAllAreGoods keepIfOnlyOneGood keepIfAnyIsGood"); cmdName = GetDirectoryName()+"allDigiOpenCoincGate"; AllDigiOpenCoincGateCmd = new G4UIcmdWithABool(cmdName,this); From 3cab4e222f8c53a63120c3eef12f7f9478a4bb2b Mon Sep 17 00:00:00 2001 From: kochebina <42149373+kochebina@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:31:00 +0200 Subject: [PATCH 19/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 9f287b105..9a8a0349a 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1225,9 +1225,9 @@ An experimental method used to estimate the number of random coincidences consis Multiple coincidences ~~~~~~~~~~~~~~~~~~~~~ -When more than two *singles* are found in coincidence, several type of behavior could be implemented. GATE allows to model 9 different rules that can be used in such a case. The list of rules along with their explanation are given in :numref:`policy_tab`, and a comparison of the effects of each processing rule for various cases of multiple coincidences is shown in :numref:`MultipleCases`. If no policy is specified, the default one used is: keepIfAllAreGoods. +When more than two *singles* are found in coincidence, several type of behavior could be implemented. GATE allows to model 9 different rules that can be used in such a case. The list of rules along with their explanation are given in :numref:`policy_tab`, and a comparison of the effects of each processing rule for various cases of multiple coincidences is shown in :numref:`MultipleCases`. If no policy is specified, the default one used is: takeWinnerIfAllAreGoods. -.. table:: Available multiple policy and associated meaning. When a multiple coincidence involving n *singles* is peocessed, it is first decomposed into a list of n·(n−1) pairs which are analyzed individually. In this table, the term "good" means that a pair of singles are in coincidence and that the 2 singles are separated by a number of blocks greater than or equal to the **minSectorDifference** parameter of the coincidence sorter. The prefix "take" means that 1 or more pairs of coincidences will be stored, while the prefix "keep" means that a unique coincidence, composed of at least three singles will be kept in the data flow and is called "multicoincidence". In the latter case, the multicoincidence will not be written to the disk, but may participate to a possible deadtime or bandwidth occupancy. The user may clear the multicoincidence at any desired step of the acquisition, by using the multipleKiller pulse processor (described in #Multiple coincidence removal). The "kill" prefix means that all events will be discarded and will not produce any coincidence. +.. table:: Available multiple policy and associated meaning. When a multiple coincidence involving n *singles* is peocessed, it is first decomposed into a list of n·(n−1) pairs which are analyzed individually. In this table, the term "good" means that a pair of singles are in coincidence and that the 2 singles are separated by a number of blocks greater than or equal to the **minSectorDifference** parameter of the coincidence sorter. The prefix "take" means that 1 or more pairs of coincidences will be stored. The user may clear the multicoincidence at any desired step of the acquisition, by using the multipleKiller module (described in #Multiple coincidence removal). The "kill" prefix means that all events will be discarded and will not produce any coincidence. :widths: auto :name: policy_tab @@ -1242,11 +1242,7 @@ When more than two *singles* are found in coincidence, several type of behavior +-------------------------+--------------------------------------------------------------------------------------------------------+ | takeWinnerIfAllAreGoods | If all pairs are goods, take the one with the highest energy | +-------------------------+--------------------------------------------------------------------------------------------------------+ - | keepIfOnlyOneGood | If exactly one pair is good, keep the multicoincidence | - +-------------------------+--------------------------------------------------------------------------------------------------------+ - | keepIfAnyIsGood | If at least one pair is good, keep the multicoincidence | - +-------------------------+--------------------------------------------------------------------------------------------------------+ - | keepIfAllAreGoods | If all pairs are goods, keep the multicoincidence | + | takeWinnerIfOnlyOneGood | If exactly one pair is good | +-------------------------+--------------------------------------------------------------------------------------------------------+ | killAllIfMultipleGoods | If more than one pairs is good, the event is seen as a real "multiple" and thus, all events are killed | +-------------------------+--------------------------------------------------------------------------------------------------------+ @@ -1257,7 +1253,7 @@ When more than two *singles* are found in coincidence, several type of behavior :alt: Figure 5: MultipleCases :name: MultipleCases - Comparison of the behavior of the available multiple processing policies, for various multiple coincidence situations. The stars represent the detected singles. The size of the star, as well as the number next to it, indicate the energy level of the single (ie. single no 1 has more energy than single no 2, which has itself more energy than the single no 3). The lines represent the possible good coincidences (ie. with a sector difference higher than or equal to the minSectorDifference of the coincidence sorter). In the table, a minus(-) sign indicates that the event is killed (ie. no coincidence is formed). The ⋆ sign indicates that all the singles are kept into a unique multicoincidence, which will not be written to disk, but which might participate to data loss via dead time or bandwidth occupancy. In the other cases, the list of pairs which are written to the disk (unless being removed thereafter by possible filter applied to the coincidences) is indicated + Comparison of the behavior of the available multiple processing policies, for various multiple coincidence situations. The stars represent the detected singles. The size of the star, as well as the number next to it, indicate the energy level of the single (ie. single no 1 has more energy than single no 2, which has itself more energy than the single no 3). The lines represent the possible good coincidences (ie. with a sector difference higher than or equal to the minSectorDifference of the coincidence sorter). In the table, a minus(-) sign indicates that the event is killed (ie. no coincidence is formed). .. table:: Table associated with :numref:`MultipleCases` :widths: auto @@ -1274,17 +1270,15 @@ When more than two *singles* are found in coincidence, several type of behavior +-------------------------+--------+---------------------+--------------+--------------+ | takeWinnerIfAllAreGoods | \- | (1,2) | \- | \- | +-------------------------+--------+---------------------+--------------+--------------+ - | keepIfOnlyOneGood | \* | \- | \- | \- | - +-------------------------+--------+---------------------+--------------+--------------+ - | keepIfAnyIsGood | \* | \* | \* | \* | - +-------------------------+--------+---------------------+--------------+--------------+ - | keepIfAllAreGoods | \- | \* | \- | \- | + | takeWinnerIfOnlyOneGood | (1,2) | \- | \- | \- | +-------------------------+--------+---------------------+--------------+--------------+ | killAllIfMultipleGoods | (1,2) | \- | \- | \- | +-------------------------+--------+---------------------+--------------+--------------+ | killAll | \- | \- | \- | \- | +-------------------------+--------+---------------------+--------------+--------------+ +**NOTE: In the previous versions (before 9.4) there were outdated policies with prefix "keep". Please, use keepIfOnlyOneGood=takeWinnerIfOnlyOneGood, keepIfAnyIsGood = takeWinnerOfGoods, keepIfAllAreGoods = takeWinnerIfAllAreGoods.** + .. _command_line-label: Command line From b6500f59c67e1fd7e9257e56bea84e4e83cceeb4 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Mon, 10 Jun 2024 16:10:03 +0200 Subject: [PATCH 20/96] Method UpdateVectorID(G4int new_copyNo) and addition of the GateDiscretizer.cc and GateDiscretizer.hh --- source/digits_hits/include/GateDiscretizer.hh | 54 +++++++++++++++++++ source/digits_hits/src/GateDiscretizer.cc | 46 ++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 source/digits_hits/include/GateDiscretizer.hh create mode 100644 source/digits_hits/src/GateDiscretizer.cc diff --git a/source/digits_hits/include/GateDiscretizer.hh b/source/digits_hits/include/GateDiscretizer.hh new file mode 100644 index 000000000..947273a7e --- /dev/null +++ b/source/digits_hits/include/GateDiscretizer.hh @@ -0,0 +1,54 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + +// OK GND 2022 +/*! + \class GateDiscretizer (by marc.granado@universite-paris-saclay.fr) + \brief for discretizing the position within a monolithic crystal + + - For each volume the local position of the interactions within the crystal are discretized. + the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal + ocuppying the levels of SubmoduleID, CrystalID and LayerID. + +*/ + +#ifndef GateDiscretizer_h +#define GateDiscretizer_h 1 + +#include "GateVDigitizerModule.hh" +#include "GateDigi.hh" +#include "GateClockDependent.hh" +#include "GateCrystalSD.hh" + +#include "globals.hh" + +#include "GateAdderMessenger.hh" +#include "GateSinglesDigitizer.hh" + + +class GateDiscretizer : public GateVDigitizerModule +{ +public: + + GateDiscretizer(GateSinglesDigitizer *digitizer, G4String name); + ~GateDiscretizer(); + adder_policy_t m_positionPolicy; + +private: + GateAdderMessenger *m_Messenger; + + GateDigi* m_outputDigi; + GateDigiCollection* m_OutputDigiCollection; + GateSinglesDigitizer *m_digitizer; + + + + +}; + +#endif diff --git a/source/digits_hits/src/GateDiscretizer.cc b/source/digits_hits/src/GateDiscretizer.cc new file mode 100644 index 000000000..f099e825f --- /dev/null +++ b/source/digits_hits/src/GateDiscretizer.cc @@ -0,0 +1,46 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + + This software is distributed under the terms + of the GNU Lesser General Public Licence (LGPL) + See LICENSE.md for further details + ----------------------*/ + +// OK GND 2022 +/*! + \class GateDiscretizer (by marc.granado@universite-paris-saclay.fr) + \brief for discretizing the position within a monolithic crystal + + - For each volume the local position of the interactions within the crystal are discretized. + the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal + ocuppying the levels of SubmoduleID, CrystalID and LayerID. + +*/ + +#include "GateAdderMessenger.hh" +#include "GateDigi.hh" + +#include "GateDigitizerMgr.hh" + +#include "G4SystemOfUnits.hh" +#include "G4EventManager.hh" +#include "G4Event.hh" +#include "G4SDManager.hh" +#include "G4DigiManager.hh" +#include "G4ios.hh" +#include "G4UnitsTable.hh" + + +GateDiscretizer::GateDiscretizer(GateSinglesDigitizer *digitizer, G4String name) + :GateVDigitizerModule(name,"digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/"+name,digitizer, digitizer->GetSD()), + m_outputDigi(0), + m_OutputDigiCollection(0), + m_digitizer(digitizer) +{ + +} + + +GateDiscretizer::GateDiscretizer() +{ +} From 2d3709aca76fe03f9390000db8faa18922bb533e Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Mon, 17 Jun 2024 17:07:00 +0200 Subject: [PATCH 21/96] DummyDigitizerModule coppied into DiscretizerModule --- source/digits_hits/include/GateDiscretizer.hh | 1 - .../include/GateSpatialResolution.hh | 1 + source/digits_hits/src/GateDiscretizer.cc | 46 ------------------- .../digits_hits/src/GateSpatialResolution.cc | 12 +++++ 4 files changed, 13 insertions(+), 47 deletions(-) delete mode 100644 source/digits_hits/src/GateDiscretizer.cc diff --git a/source/digits_hits/include/GateDiscretizer.hh b/source/digits_hits/include/GateDiscretizer.hh index 947273a7e..d6f807b8a 100644 --- a/source/digits_hits/include/GateDiscretizer.hh +++ b/source/digits_hits/include/GateDiscretizer.hh @@ -27,7 +27,6 @@ See LICENSE.md for further details #include "globals.hh" -#include "GateAdderMessenger.hh" #include "GateSinglesDigitizer.hh" diff --git a/source/digits_hits/include/GateSpatialResolution.hh b/source/digits_hits/include/GateSpatialResolution.hh index 1c27448e9..1baac6d3e 100644 --- a/source/digits_hits/include/GateSpatialResolution.hh +++ b/source/digits_hits/include/GateSpatialResolution.hh @@ -75,6 +75,7 @@ public: void LocateOutputDigi(GateDigi* inputDigi, G4double PxNew,G4double PyNew,G4double PzNew); void UpdateVolumeID(); + void UpdateVolumeID(G4int newCopyNo); //! Implementation of the pure virtual method declared by the base class GateClockDependent //! print-out the attributes specific of the blurring diff --git a/source/digits_hits/src/GateDiscretizer.cc b/source/digits_hits/src/GateDiscretizer.cc deleted file mode 100644 index f099e825f..000000000 --- a/source/digits_hits/src/GateDiscretizer.cc +++ /dev/null @@ -1,46 +0,0 @@ -/*---------------------- - Copyright (C): OpenGATE Collaboration - - This software is distributed under the terms - of the GNU Lesser General Public Licence (LGPL) - See LICENSE.md for further details - ----------------------*/ - -// OK GND 2022 -/*! - \class GateDiscretizer (by marc.granado@universite-paris-saclay.fr) - \brief for discretizing the position within a monolithic crystal - - - For each volume the local position of the interactions within the crystal are discretized. - the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal - ocuppying the levels of SubmoduleID, CrystalID and LayerID. - -*/ - -#include "GateAdderMessenger.hh" -#include "GateDigi.hh" - -#include "GateDigitizerMgr.hh" - -#include "G4SystemOfUnits.hh" -#include "G4EventManager.hh" -#include "G4Event.hh" -#include "G4SDManager.hh" -#include "G4DigiManager.hh" -#include "G4ios.hh" -#include "G4UnitsTable.hh" - - -GateDiscretizer::GateDiscretizer(GateSinglesDigitizer *digitizer, G4String name) - :GateVDigitizerModule(name,"digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/"+name,digitizer, digitizer->GetSD()), - m_outputDigi(0), - m_OutputDigiCollection(0), - m_digitizer(digitizer) -{ - -} - - -GateDiscretizer::GateDiscretizer() -{ -} diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index 1621a0318..a3790dfde 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -313,6 +313,18 @@ void GateSpatialResolution::UpdateVolumeID() } } + +void GateSpatialResolution::UpdateVolumeID(G4int newCopyNo) +{ + for (G4int i=1;iChangeVolumeIDAndOutputVolumeIDValue(i,newCopyNo); + } + + +} + + void GateSpatialResolution::DescribeMyself(size_t indent ) { if(m_fwhm) From 9ee20f4009b792b4f3d1b80be797abf27dbce1c0 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Mon, 17 Jun 2024 17:11:49 +0200 Subject: [PATCH 22/96] After adding the DiscretizerModule Files --- .../include/GateDiscretizerModule.hh | 80 +++++++++++++++++++ .../include/GateDiscretizerModuleMessenger.hh | 60 ++++++++++++++ .../digits_hits/src/GateDiscretizerModule.cc | 46 +++++++++++ .../src/GateDiscretizerModuleMessenger.cc | 69 ++++++++++++++++ 4 files changed, 255 insertions(+) create mode 100644 source/digits_hits/include/GateDiscretizerModule.hh create mode 100644 source/digits_hits/include/GateDiscretizerModuleMessenger.hh create mode 100644 source/digits_hits/src/GateDiscretizerModule.cc create mode 100644 source/digits_hits/src/GateDiscretizerModuleMessenger.cc diff --git a/source/digits_hits/include/GateDiscretizerModule.hh b/source/digits_hits/include/GateDiscretizerModule.hh new file mode 100644 index 000000000..a065e4ec8 --- /dev/null +++ b/source/digits_hits/include/GateDiscretizerModule.hh @@ -0,0 +1,80 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + +// OK GND 2022 +/*This class is not used by GATE ! + The purpose of this class is to help to create new users digitizer module(DM). + Please, check GateDummyDigitizerModule.cc for more detals + */ + + +/*! \class GateDummyDigitizerModule + \brief GateDummyDigitizerModule does some dummy things with input digi + to create output digi + + - GateDummyDigitizerModule - by name.surname@email.com + + \sa GateDummyDigitizerModule, GateDummyDigitizerModuleMessenger +*/ + +#ifndef GateDummyDigitizerModule_h +#define GateDummyDigitizerModule_h 1 + +#include "GateVDigitizerModule.hh" +#include "GateDigi.hh" +#include "GateClockDependent.hh" +#include "GateCrystalSD.hh" + +#include "globals.hh" + +#include "GateDummyDigitizerModuleMessenger.hh" +#include "GateSinglesDigitizer.hh" + + +class GateDummyDigitizerModule : public GateVDigitizerModule +{ +public: + + GateDummyDigitizerModule(GateSinglesDigitizer *digitizer, G4String name); + ~GateDummyDigitizerModule(); + + void Digitize() override; + + // *******implement your methods here + void SetDummyParameter(const G4String& ); + + void DummyMethod1(GateDigi *); + void DummyMethod2(GateDigi *); + + void DescribeMyself(size_t ); + +protected: + // *******implement your parameters here + G4String m_parameter; + +private: + GateDigi* m_outputDigi; + + GateDummyDigitizerModuleMessenger *m_Messenger; + + GateDigiCollection* m_OutputDigiCollection; + + GateSinglesDigitizer *m_digitizer; + + +}; + +#endif + + + + + + + + diff --git a/source/digits_hits/include/GateDiscretizerModuleMessenger.hh b/source/digits_hits/include/GateDiscretizerModuleMessenger.hh new file mode 100644 index 000000000..8ee2d0038 --- /dev/null +++ b/source/digits_hits/include/GateDiscretizerModuleMessenger.hh @@ -0,0 +1,60 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + +// OK GND 2022 +/*This class is not used by GATE ! + The purpose of this class is to help to create new users digitizer module(DM). + Please, check GateDummyDigitizerModule.cc for more detals + */ + + +/*! \class GateDummyDigitizerModuleMessenger + \brief Messenger for the GateDummyDigitizerModule + + - GateDummyDigitizerModule - by name.surname@email.com + + \sa GateDummyDigitizerModule, GateDummyDigitizerModuleMessenger +*/ + + +#ifndef GateDummyDigitizerModuleMessenger_h +#define GateDummyDigitizerModuleMessenger_h 1 + +#include "G4UImessenger.hh" +#include "globals.hh" + +#include "GateClockDependentMessenger.hh" +class GateDummyDigitizerModule; +class G4UIcmdWithAString; + +class GateDummyDigitizerModuleMessenger : public GateClockDependentMessenger +{ +public: + + GateDummyDigitizerModuleMessenger(GateDummyDigitizerModule*); + ~GateDummyDigitizerModuleMessenger(); + + void SetNewValue(G4UIcommand*, G4String); + + +private: + GateDummyDigitizerModule* m_DummyDigitizerModule; + G4UIcmdWithAString *dummyCmd; + + +}; + +#endif + + + + + + + + diff --git a/source/digits_hits/src/GateDiscretizerModule.cc b/source/digits_hits/src/GateDiscretizerModule.cc new file mode 100644 index 000000000..cbe92284f --- /dev/null +++ b/source/digits_hits/src/GateDiscretizerModule.cc @@ -0,0 +1,46 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + + This software is distributed under the terms + of the GNU Lesser General Public Licence (LGPL) + See LICENSE.md for further details + ----------------------*/ + +// OK GND 2022 +/*! + \class GateDiscretizer (by marc.granado@universite-paris-saclay.fr) + \brief for discretizing the position within a monolithic crystal + + - For each volume the local position of the interactions within the crystal are discretized. + the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal + ocuppying the levels of SubmoduleID, CrystalID and LayerID. + +*/ + + +#include "GateDigi.hh" + +#include "GateDigitizerMgr.hh" + +#include "G4SystemOfUnits.hh" +#include "G4EventManager.hh" +#include "G4Event.hh" +#include "G4SDManager.hh" +#include "G4DigiManager.hh" +#include "G4ios.hh" +#include "G4UnitsTable.hh" + + +GateDiscretizer::GateDiscretizer(GateSinglesDigitizer *digitizer, G4String name) + :GateVDigitizerModule(name,"digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/"+name,digitizer, digitizer->GetSD()), + m_outputDigi(0), + m_OutputDigiCollection(0), + m_digitizer(digitizer) +{ + +} + + +GateDiscretizer::GateDiscretizer() +{ +} diff --git a/source/digits_hits/src/GateDiscretizerModuleMessenger.cc b/source/digits_hits/src/GateDiscretizerModuleMessenger.cc new file mode 100644 index 000000000..a7baa391f --- /dev/null +++ b/source/digits_hits/src/GateDiscretizerModuleMessenger.cc @@ -0,0 +1,69 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + +// OK GND 2022 +/*This class is not used by GATE ! + The purpose of this class is to help to create new users digitizer module(DM). + Please, check GateDummyDigitizerModule.cc for more detals + */ + +#include "GateDummyDigitizerModuleMessenger.hh" +#include "GateDummyDigitizerModule.hh" +#include "GateDigitizerMgr.hh" + +#include "G4SystemOfUnits.hh" +#include "G4UIcmdWithAString.hh" +#include "G4UIdirectory.hh" + + + +GateDummyDigitizerModuleMessenger::GateDummyDigitizerModuleMessenger (GateDummyDigitizerModule* DummyDigitizerModule) +:GateClockDependentMessenger(DummyDigitizerModule), + m_DummyDigitizerModule(DummyDigitizerModule) +{ + G4String guidance; + G4String cmdName; + + cmdName = GetDirectoryName()+"positionPolicy"; + dummyCmd = new G4UIcmdWithAString(cmdName,this); + dummyCmd->SetGuidance("How to generate position"); + dummyCmd->SetCandidates("energyWeightedCentroid takeEnergyWinner"); + +} + + +GateDummyDigitizerModuleMessenger::~GateDummyDigitizerModuleMessenger() +{ + delete dummyCmd; +} + + +void GateDummyDigitizerModuleMessenger::SetNewValue(G4UIcommand * aCommand,G4String newValue) +{ + if (aCommand ==dummyCmd) + { + m_DummyDigitizerModule->SetDummyParameter(newValue); + } + else + { + GateClockDependentMessenger::SetNewValue(aCommand,newValue); + } +} + + + + + + + + + + + + + From 63534c2a47cbc10447c0f8bfe677b99d4ebcf1a4 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Wed, 26 Jun 2024 15:29:13 +0200 Subject: [PATCH 23/96] Addition of a new method for ChangeOutputID and new methods implemented in DiscretizerModule --- source/digits_hits/include/GateDigi.hh | 1 + .../include/GateDiscretizerModule.hh | 70 +++- .../include/GateDiscretizerModuleMessenger.hh | 30 +- source/digits_hits/src/GateDigi.cc | 3 + .../digits_hits/src/GateDiscretizerModule.cc | 334 +++++++++++++++++- .../src/GateDiscretizerModuleMessenger.cc | 89 ++++- .../src/GateDummyDigitizerModule.cc | 4 +- .../src/GateSinglesDigitizerMessenger.cc | 8 + source/externals/lmf/.cproject | 16 + source/externals/lmf/.project | 20 ++ 10 files changed, 522 insertions(+), 53 deletions(-) create mode 100644 source/externals/lmf/.cproject create mode 100644 source/externals/lmf/.project diff --git a/source/digits_hits/include/GateDigi.hh b/source/digits_hits/include/GateDigi.hh index 7be01d0ae..ad4133295 100644 --- a/source/digits_hits/include/GateDigi.hh +++ b/source/digits_hits/include/GateDigi.hh @@ -125,6 +125,7 @@ public: inline G4double GetScannerRotAngle() const { return m_scannerRotAngle; } inline void SetOutputVolumeID(const GateOutputVolumeID& outputVolumeID) { m_outputVolumeID = outputVolumeID; } + inline void SetOutputVolumeID(const G4int outputVolumeID,G4int depth) { m_outputVolumeID[depth] = outputVolumeID; } inline const GateOutputVolumeID& GetOutputVolumeID() const { return m_outputVolumeID; } inline G4int GetComponentID(size_t depth) const { return (m_outputVolumeID.size()>depth) ? m_outputVolumeID[depth] : -1; } diff --git a/source/digits_hits/include/GateDiscretizerModule.hh b/source/digits_hits/include/GateDiscretizerModule.hh index a065e4ec8..a7bae54ff 100644 --- a/source/digits_hits/include/GateDiscretizerModule.hh +++ b/source/digits_hits/include/GateDiscretizerModule.hh @@ -9,21 +9,21 @@ See LICENSE.md for further details // OK GND 2022 /*This class is not used by GATE ! The purpose of this class is to help to create new users digitizer module(DM). - Please, check GateDummyDigitizerModule.cc for more detals + Please, check GateDiscretizerModule.cc for more detals */ -/*! \class GateDummyDigitizerModule - \brief GateDummyDigitizerModule does some dummy things with input digi +/*! \class GateDiscretizerModule + \brief GateDiscretizerModule does some dummy things with input digi to create output digi - - GateDummyDigitizerModule - by name.surname@email.com + - GateDiscretizerModule - by marc.granado@universite-paris-saclay.fr - \sa GateDummyDigitizerModule, GateDummyDigitizerModuleMessenger + \sa GateDiscretizerModule, GateDiscretizerModuleMessenger */ -#ifndef GateDummyDigitizerModule_h -#define GateDummyDigitizerModule_h 1 +#ifndef GateDiscretizerModule_h +#define GateDiscretizerModule_h 1 #include "GateVDigitizerModule.hh" #include "GateDigi.hh" @@ -32,35 +32,67 @@ See LICENSE.md for further details #include "globals.hh" -#include "GateDummyDigitizerModuleMessenger.hh" +#include "GateDiscretizerModuleMessenger.hh" #include "GateSinglesDigitizer.hh" -class GateDummyDigitizerModule : public GateVDigitizerModule +class GateDiscretizerModule : public GateVDigitizerModule { public: - GateDummyDigitizerModule(GateSinglesDigitizer *digitizer, G4String name); - ~GateDummyDigitizerModule(); + GateDiscretizerModule(GateSinglesDigitizer *digitizer, G4String name); + ~GateDiscretizerModule(); void Digitize() override; - - // *******implement your methods here - void SetDummyParameter(const G4String& ); - void DummyMethod1(GateDigi *); - void DummyMethod2(GateDigi *); + //! These functions return the resolution in use. + G4String GetNameAxis() { return m_nameAxis; } + G4double GetResolution() { return m_resolution; } + G4double GetResolutionX() { return m_resolutionX; } + G4double GetResolutionY() { return m_resolutionY; } + G4double GetResolutionZ() { return m_resolutionZ; } + + G4double calculatePitch(G4double crystal_size, G4double spatial_resolution); + + + //Set Parameter + void SetNameAxis(const G4String&); + + + + //Set Variables + void SetResolution(G4double val) { m_resolution = val; } + void SetResolutionX(G4double val) { m_resolutionX = val; } + void SetResolutionY(G4double val) { m_resolutionY = val; } + void SetResolutionZ(G4double val) { m_resolutionZ = val; } - void DescribeMyself(size_t ); + + void SetVirtualIDs(int nBinsX, int nBinsY,int nBinsZ, G4ThreeVector& pos); + void DescribeMyself(size_t ); protected: // *******implement your parameters here - G4String m_parameter; + G4double m_resolution; + + G4String m_nameAxis; + G4double m_resolutionX; + G4double m_resolutionY; + G4double m_resolutionZ; + + + //These are in Spatial resolution but aren't there rom touchable? + //We'll need to check + + //G4Navigator* m_Navigator; + //G4TouchableHistoryHandle m_Touchable; private: + + G4int m_systemDepth; + GateDigi* m_outputDigi; - GateDummyDigitizerModuleMessenger *m_Messenger; + GateDiscretizerModuleMessenger *m_Messenger; GateDigiCollection* m_OutputDigiCollection; diff --git a/source/digits_hits/include/GateDiscretizerModuleMessenger.hh b/source/digits_hits/include/GateDiscretizerModuleMessenger.hh index 8ee2d0038..c0d471277 100644 --- a/source/digits_hits/include/GateDiscretizerModuleMessenger.hh +++ b/source/digits_hits/include/GateDiscretizerModuleMessenger.hh @@ -9,44 +9,48 @@ See LICENSE.md for further details // OK GND 2022 /*This class is not used by GATE ! The purpose of this class is to help to create new users digitizer module(DM). - Please, check GateDummyDigitizerModule.cc for more detals + Please, check GateDiscretizerModule.cc for more detals */ -/*! \class GateDummyDigitizerModuleMessenger - \brief Messenger for the GateDummyDigitizerModule +/*! \class GateDiscretizerModuleMessenger + \brief Messenger for the GateDiscretizerModule - - GateDummyDigitizerModule - by name.surname@email.com + - GateDiscretizerModule - by marc.granado@universite-paris-saclay.fr - \sa GateDummyDigitizerModule, GateDummyDigitizerModuleMessenger + \sa GateDiscretizerModule, GateDiscretizerModuleMessenger */ -#ifndef GateDummyDigitizerModuleMessenger_h -#define GateDummyDigitizerModuleMessenger_h 1 +#ifndef GateDiscretizerModuleMessenger_h +#define GateDiscretizerModuleMessenger_h 1 #include "G4UImessenger.hh" #include "globals.hh" #include "GateClockDependentMessenger.hh" -class GateDummyDigitizerModule; +class GateDiscretizerModule; class G4UIcmdWithAString; -class GateDummyDigitizerModuleMessenger : public GateClockDependentMessenger +class GateDiscretizerModuleMessenger : public GateClockDependentMessenger { public: - GateDummyDigitizerModuleMessenger(GateDummyDigitizerModule*); - ~GateDummyDigitizerModuleMessenger(); + GateDiscretizerModuleMessenger(GateDiscretizerModule*); + ~GateDiscretizerModuleMessenger(); void SetNewValue(G4UIcommand*, G4String); private: - GateDummyDigitizerModule* m_DummyDigitizerModule; - G4UIcmdWithAString *dummyCmd; + GateDiscretizerModule* m_DiscretizerModule; + G4UIcmdWithAString* nameAxisCmd; + G4UIcmdWithADouble* resCmd; + G4UIcmdWithADouble* resolutionXCmd; + G4UIcmdWithADouble* resolutionYCmd; + G4UIcmdWithADouble* resolutionZCmd; }; #endif diff --git a/source/digits_hits/src/GateDigi.cc b/source/digits_hits/src/GateDigi.cc index e7462243a..d6bea9e2f 100644 --- a/source/digits_hits/src/GateDigi.cc +++ b/source/digits_hits/src/GateDigi.cc @@ -190,6 +190,9 @@ void GateDigi::ChangeVolumeIDAndOutputVolumeIDValue(size_t depth, G4int copyNo) delete volSelector; // Finally change the outputVolumeID accordingly m_outputVolumeID[depth] = copyNo; + + //With the new method the line above could be changed to: + //SetOutputVolumeID(copyNo,depth) } diff --git a/source/digits_hits/src/GateDiscretizerModule.cc b/source/digits_hits/src/GateDiscretizerModule.cc index cbe92284f..ad9827384 100644 --- a/source/digits_hits/src/GateDiscretizerModule.cc +++ b/source/digits_hits/src/GateDiscretizerModule.cc @@ -13,13 +13,21 @@ - For each volume the local position of the interactions within the crystal are discretized. the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal - ocuppying the levels of SubmoduleID, CrystalID and LayerID. + occupying the levels of SubmoduleID, CrystalID and LayerID. */ + +#include "GateDiscretizerModule.hh" +#include "GateDiscretizerModuleMessenger.hh" #include "GateDigi.hh" +#include "GateSpatialResolution.hh" +#include "GateSpatialResolutionMessenger.hh" + + + #include "GateDigitizerMgr.hh" #include "G4SystemOfUnits.hh" @@ -30,17 +38,335 @@ #include "G4ios.hh" #include "G4UnitsTable.hh" +#include +#include +#include + + + + + + +GateDiscretizerModule::GateDiscretizerModule(GateSinglesDigitizer *digitizer, G4String name) + :GateVDigitizerModule(name,"digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/"+name,digitizer,digitizer->GetSD()), + + m_nameAxis("XYZ"), + + m_resolution(0), + m_resolutionX(0), + m_resolutionY(0), + m_resolutionZ(0), -GateDiscretizer::GateDiscretizer(GateSinglesDigitizer *digitizer, G4String name) - :GateVDigitizerModule(name,"digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/"+name,digitizer, digitizer->GetSD()), m_outputDigi(0), m_OutputDigiCollection(0), m_digitizer(digitizer) + { + G4String colName = digitizer->GetOutputName() ; + collectionName.push_back(colName); + m_Messenger = new GateDiscretizerModuleMessenger(this); +} + + + + +GateDiscretizerModule::~GateDiscretizerModule() { + delete m_Messenger; } -GateDiscretizer::GateDiscretizer() + + + + +void GateDiscretizerModule::Digitize() { + + + + GateSpatialResolution* digi_SpatialResolution; + digi_SpatialResolution = dynamic_cast(m_digitizer->FindDigitizerModule("digitizerMgr/" + +m_digitizer->GetSD()->GetName() + +"/SinglesDigitizer/" + + m_digitizer->GetName() + + "/SpatialResolution")); + + + + G4double resolutionX; + G4double resolutionY; + G4double resolutionZ; + + + + + + + + + + + if (digi_SpatialResolution->GetFWHM()) + { + if(m_nameAxis.find('X') != std::string::npos) + {resolutionX = digi_SpatialResolution->GetFWHM();} + + if(m_nameAxis.find('Y') != std::string::npos) + {resolutionY = digi_SpatialResolution->GetFWHM();} + + if(m_nameAxis.find('Z') != std::string::npos) + {resolutionZ = digi_SpatialResolution->GetFWHM();} + } + + + else if(digi_SpatialResolution->GetFWHMx() || digi_SpatialResolution->GetFWHMy()|| digi_SpatialResolution->GetFWHMz()){ + if(digi_SpatialResolution->GetFWHMx() && m_nameAxis.find('X') != std::string::npos) + {resolutionX = digi_SpatialResolution->GetFWHMx();} + + if(digi_SpatialResolution->GetFWHMy() && m_nameAxis.find('Y') != std::string::npos) + {resolutionY = digi_SpatialResolution->GetFWHMy();} + + if(digi_SpatialResolution->GetFWHMz() && m_nameAxis.find('Z') != std::string::npos) + {resolutionZ = digi_SpatialResolution->GetFWHMz();} + } + + else if (m_nameAxis == "XYZ" && (m_resolution==0) || (m_resolutionX==0 || m_resolutionY==0 ||m_resolutionZ==0)) + { + + GateError("***ERROR*** Discretization in XYZ has been selected but at least one axis has resolution = 0. Please ensure that all axis have a non zero value of resolution."); + } + + + if (m_resolution != 0) + { + resolutionX = m_resolution; + resolutionY = m_resolution; + resolutionZ = m_resolution; + } + + else + { + resolutionX = m_resolutionX; + resolutionY = m_resolutionY; + resolutionZ = m_resolutionZ; + } + + + + //TODO Create the check that tells you that + GateVSystem* m_system = ((GateSinglesDigitizer*)this->GetDigitizer())->GetSystem(); + + if (m_system==NULL) G4Exception( "GateSpatialResolution::Digitize", "Digitize", FatalException, + "Failed to get the system corresponding to that digitizer. Abort.\n"); + + if (!m_system->CheckIfEnoughLevelsAreDefined()) + { + GateError( " *** ERROR*** GateSpatialResolution::Digitize. Not all defined geometry levels has their mother levels defined." + "(Ex.: for cylindricalPET, the levels are: rsector, module, submodule, crystal). If you have defined submodule, you have to have resector and module defined as well." + "Please, add them to your geometry macro in /gate/systems/cylindricalPET/XXX/attach YYY. Abort.\n"); + } + + m_systemDepth = m_system->GetTreeDepth(); + //TODO I need to create another parameter asking if spatial resolution is provided by hand. + //I need to get system, system depth. Check that the size for the last 4 solids is the same (Monolithic crystal) + //Need to access spatial resolution + + + + + G4String digitizerName = m_digitizer->m_digitizerName; + G4String outputCollName = m_digitizer-> GetOutputName(); + + m_OutputDigiCollection = new GateDigiCollection(GetName(),outputCollName); // to create the Digi Collection + + G4DigiManager* DigiMan = G4DigiManager::GetDMpointer(); + + + + GateDigiCollection* IDC = 0; + IDC = (GateDigiCollection*) (DigiMan->GetDigiCollection(m_DCID)); + + GateDigi* inputDigi; + + //What about these lines? Why are they not in SpatialResolution? Apparetnly + std::vector< GateDigi* >* OutputDigiCollectionVector = m_OutputDigiCollection->GetVector (); + std::vector::iterator iter; + + + + if (IDC) + { + G4int n_digi = IDC->entries(); + + //loop over input digits + for (G4int i=0;ibegin(); iter!= OutputDigiCollectionVector->end() ; ++iter) + { + if ( (*iter)->GetVolumeID() == inputDigi->GetVolumeID() ) + { + continue; + if(m_nameAxis=="XYZ"){continue;} + /* if(m_parameter=="numAxis"){ + DummyMethod1(inputDigi); + } + else{ + DummyMethod2( inputDigi ); + } + */ + if (nVerboseLevel>1) + { + G4cout << "Merged previous pulse for volume " << inputDigi->GetVolumeID() + << " with new pulse of energy " << G4BestUnit(inputDigi->GetEnergy(),"Energy") <<".\n" + << "Resulting pulse is: \n" + << **iter << Gateendl << Gateendl ; + } + break; + } + } + + if ( iter == OutputDigiCollectionVector->end() ) + { + m_outputDigi = new GateDigi(*inputDigi); + m_outputDigi->SetEnergyIniTrack(-1); + m_outputDigi->SetEnergyFin(-1); + if (nVerboseLevel>1) + G4cout << "Created new pulse for volume " << inputDigi->GetVolumeID() << ".\n" + << "Resulting pulse is: \n" + << *m_outputDigi << Gateendl << Gateendl ; + /// !!!!!! The following line should be kept !!!! -> inserts the outputdigi to collection + m_OutputDigiCollection->insert(m_outputDigi); + + } + ////// ** End of the part from ProcessOnePulse + + + if (nVerboseLevel==1) { + G4cout << "[GateDiscretizerModule::Digitize]: returning output pulse-list with " << OutputDigiCollectionVector->size() << " entries\n"; + for (iter=OutputDigiCollectionVector->begin(); iter!= OutputDigiCollectionVector->end() ; ++iter) + G4cout << **iter << Gateendl; + G4cout << Gateendl; + } + /// *** End of the part from ProcessPulseList + } //loop over input digits + } //IDC + else + { + if (nVerboseLevel>1) + G4cout << "[GateDiscretizerModule::Digitize]: input digi collection is null -> nothing to do\n\n"; + return; + } + StoreDigiCollection(m_OutputDigiCollection); + +} + + + + + + + + + +void GateDiscretizerModule::SetNameAxis(const G4String ¶m) +{ + m_nameAxis=param; +} + + +/////////////////////////////////////////// +////////////// Methods of DM ////////////// +/////////////////////////////////////////// + + + + +G4double GateDiscretizerModule::calculatePitch(G4double crystal_size, G4double spatial_resolution) { + // Target pitch size + double target_pitch = spatial_resolution / 2.0; + double best_pitch = 0; + double min_diff = std::numeric_limits::max(); + + // Iterate to find the best pitch size + for (int num_pitches = 1; num_pitches <= crystal_size; ++num_pitches) { + double pitch = crystal_size / num_pitches; + if (std::fabs(pitch - target_pitch) < min_diff && std::fmod(crystal_size, pitch) == 0) { + min_diff = std::fabs(pitch - target_pitch); + best_pitch = pitch; + } + } + + return best_pitch; + } + + + + +void GateDiscretizerModule::SetVirtualIDs( int nBinsX, int nBinsY,int nBinsZ, G4ThreeVector& pos ){ + int crystalID; + int subModuleID; + int layerID; + + int binX,binY,binZ; + + binX = (pos.X/nBinsX+nBinsX/2); + binY = (pos.Y/nBinsY+nBinsY/2); + binZ = (pos.Z/nBinsY+nBinsY/2); + + //Change the OutputVolumeID at depths 3,4,5 + //(SubmoduleID=binX, crystalID = binY and layerID = binZ) + m_outputDigi->SetOutputVolumeID(3,binX); + m_outputDigi->SetOutputVolumeID(4,binY); + m_outputDigi->SetOutputVolumeID(5,binZ); + } + + + + +/* +void GateDiscretizerModule::DummyMethod1(GateDigi *right) +{ + //to copy all variables that are not changed + m_outputDigi=right; + + } + +void GateDiscretizerModule::DummyMethod2(GateDigi *right) +{ + //to copy all variables that are not changed + m_outputDigi=right; + + +} + +*/ +void GateDiscretizerModule::DescribeMyself(size_t indent ) +{ + if(m_resolution) + G4cout << GateTools::Indent(indent) << "Spatial resolution : " << m_resolution << Gateendl; + else + G4cout << GateTools::Indent(indent) << "Spatial resolution : " << m_resolutionX <<" "<< m_resolutionY<< " "<SetGuidance("How to generate position"); - dummyCmd->SetCandidates("energyWeightedCentroid takeEnergyWinner"); + + cmdName = GetDirectoryName()+"nameAxis"; + nameAxisCmd = new G4UIcmdWithAString(cmdName,this); + nameAxisCmd ->SetGuidance("Provide the number of axis that need to be discretized, XY or XYZ"); + nameAxisCmd ->SetCandidates("XY XYZ"); + + + cmdName = GetDirectoryName() + "resolution"; + resCmd = new G4UIcmdWithADouble(cmdName,this); + resCmd->SetGuidance("Set the size of the resolution for all the selected dimensions"); + + + + cmdName = GetDirectoryName()+"resolutionX"; + resolutionXCmd = new G4UIcmdWithADouble(cmdName,this); + resolutionXCmd->SetGuidance("Set the size of the resolution for the X dimension"); + + cmdName = GetDirectoryName()+"resolutionY"; + resolutionYCmd = new G4UIcmdWithADouble(cmdName,this); + resolutionYCmd->SetGuidance("Set the size of the resolution for the Y dimension"); + + cmdName = GetDirectoryName()+"resolutionZ"; + resolutionZCmd = new G4UIcmdWithADouble(cmdName,this); + resolutionZCmd->SetGuidance("Set the size of the resolution for the Z dimension"); } -GateDummyDigitizerModuleMessenger::~GateDummyDigitizerModuleMessenger() +GateDiscretizerModuleMessenger::~GateDiscretizerModuleMessenger() { - delete dummyCmd; + delete nameAxisCmd; + delete resCmd; + delete resolutionXCmd; + delete resolutionYCmd; + delete resolutionZCmd; } -void GateDummyDigitizerModuleMessenger::SetNewValue(G4UIcommand * aCommand,G4String newValue) +void GateDiscretizerModuleMessenger::SetNewValue(G4UIcommand * aCommand,G4String newValue) { - if (aCommand ==dummyCmd) + + if (aCommand == nameAxisCmd) + { + m_DiscretizerModule->SetNameAxis(newValue); + } + + else if (aCommand == resCmd) { - m_DummyDigitizerModule->SetDummyParameter(newValue); + m_DiscretizerModule->SetResolution(resCmd->GetNewDoubleValue(newValue)); + } + else if (aCommand == resolutionXCmd) + { + m_DiscretizerModule->SetResolutionX(resCmd->GetNewDoubleValue(newValue)); + } + + else if (aCommand == resolutionYCmd) + { + m_DiscretizerModule->SetResolutionY(resCmd->GetNewDoubleValue(newValue)); + } + else if (aCommand == resolutionZCmd) + { + m_DiscretizerModule->SetResolutionZ(resCmd->GetNewDoubleValue(newValue)); + } + else { GateClockDependentMessenger::SetNewValue(aCommand,newValue); diff --git a/source/digits_hits/src/GateDummyDigitizerModule.cc b/source/digits_hits/src/GateDummyDigitizerModule.cc index a6a6ac6d5..fb8a741f4 100755 --- a/source/digits_hits/src/GateDummyDigitizerModule.cc +++ b/source/digits_hits/src/GateDummyDigitizerModule.cc @@ -15,7 +15,7 @@ - Create your DM by coping this class and GateDummyDigitizerMessenger class for your DM messenger - Places to change are marked with // ****** comment and called with "dummy" names - - Include your module to GateSinglesDigitizerMessenger in the method DoInsertion(..) + - Include your module to GateSinglesDigitizerMessenger.cc in the method DoInsertion(..) If you adapting some already exiting class from Old Gate Digitizer here is some of the tips - Digitize () is a fusion of GateVPulseProcessor::ProcessPulseList and GateXXX::ProcessOnePulse @@ -28,7 +28,7 @@ To create new Digitizer Module (DM), please, follow the steps: 1) Copy .cc and .hh of GateDummyDigitizerModule, GateDummyDigitizerModuleMessenger to GateYourNewDigitizerModule and GateYourNewDigitizerModuleMessenger 2) Replace in these new files : DummyDigitizerModule -> YourNewDigitizerModule - 3) Compile 1st time (so not forget to redo ccmake to) + 3) Compile 1st time (so not forget to redo ccmake too) 4) Adapt GateYourNewDigitizerModuleMessenger.cc 5) Adapt GateYourNewDigitizerModuleMessenger.hh (!!!! DO NOT FORGET TO WRITE A SHORT EXPLANATION ON WHAT DOES YOUR DM !!!!) 6) Adapt GateYourNewDigitizerModule.hh diff --git a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc index d1fd0bd38..da583fbf0 100755 --- a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc +++ b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc @@ -55,6 +55,7 @@ See LICENSE.md for further details #include "GateAdderComptPhotIdeal.hh" #include "GateClustering.hh" #include "GateTimeDelay.hh" +#include "GateDiscretizerModule.hh" /* #include "GateLocalTimeDelay.hh" @@ -267,6 +268,13 @@ else if (childTypeName=="multipleRejection") m_digitizer->AddNewModule(newDM); } + else if (childTypeName=="discretizer") + { + newDM = new GateDiscretizerModule(m_digitizer, DMname); + m_digitizer->AddNewModule(newDM); + } + + /* diff --git a/source/externals/lmf/.cproject b/source/externals/lmf/.cproject new file mode 100644 index 000000000..c310a95f3 --- /dev/null +++ b/source/externals/lmf/.cproject @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/externals/lmf/.project b/source/externals/lmf/.project new file mode 100644 index 000000000..d9d181aec --- /dev/null +++ b/source/externals/lmf/.project @@ -0,0 +1,20 @@ + + + lmf + + + + + + org.eclipse.cdt.core.cBuilder + clean,full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.cmake.core.cmakeNature + + From e0bdbebee21171082fbec8969d122535d28c61a6 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Mon, 1 Jul 2024 12:54:00 +0200 Subject: [PATCH 24/96] Clean up of the code, working for XYZ case --- source/digits_hits/include/GateDigi.hh | 2 +- .../include/GateDiscretizerModule.hh | 3 +- .../digits_hits/src/GateDiscretizerModule.cc | 189 ++++++++++++------ .../src/GateDummyDigitizerModule.cc | 2 +- .../src/GateSinglesDigitizerMessenger.cc | 2 +- 5 files changed, 129 insertions(+), 69 deletions(-) diff --git a/source/digits_hits/include/GateDigi.hh b/source/digits_hits/include/GateDigi.hh index ad4133295..cf513cb44 100644 --- a/source/digits_hits/include/GateDigi.hh +++ b/source/digits_hits/include/GateDigi.hh @@ -125,7 +125,7 @@ public: inline G4double GetScannerRotAngle() const { return m_scannerRotAngle; } inline void SetOutputVolumeID(const GateOutputVolumeID& outputVolumeID) { m_outputVolumeID = outputVolumeID; } - inline void SetOutputVolumeID(const G4int outputVolumeID,G4int depth) { m_outputVolumeID[depth] = outputVolumeID; } + inline void SetOutputVolumeID(const G4int copyNum,G4int depth) { m_outputVolumeID[depth] = copyNum; } inline const GateOutputVolumeID& GetOutputVolumeID() const { return m_outputVolumeID; } inline G4int GetComponentID(size_t depth) const { return (m_outputVolumeID.size()>depth) ? m_outputVolumeID[depth] : -1; } diff --git a/source/digits_hits/include/GateDiscretizerModule.hh b/source/digits_hits/include/GateDiscretizerModule.hh index a7bae54ff..32f639054 100644 --- a/source/digits_hits/include/GateDiscretizerModule.hh +++ b/source/digits_hits/include/GateDiscretizerModule.hh @@ -67,7 +67,8 @@ public: void SetResolutionZ(G4double val) { m_resolutionZ = val; } - void SetVirtualIDs(int nBinsX, int nBinsY,int nBinsZ, G4ThreeVector& pos); + void SetVirtualIDs(int nBinsX, int nBinsY,int nBinsZ,double pitchX,double pitchY,double pitchZ, G4ThreeVector& pos); + void SetVirtualID(int nBins,double pitch, G4double pos, int depth); void DescribeMyself(size_t ); protected: diff --git a/source/digits_hits/src/GateDiscretizerModule.cc b/source/digits_hits/src/GateDiscretizerModule.cc index ad9827384..c3a4a70b9 100644 --- a/source/digits_hits/src/GateDiscretizerModule.cc +++ b/source/digits_hits/src/GateDiscretizerModule.cc @@ -30,6 +30,7 @@ #include "GateDigitizerMgr.hh" +#include "G4Box.hh" #include "G4SystemOfUnits.hh" #include "G4EventManager.hh" #include "G4Event.hh" @@ -84,13 +85,14 @@ void GateDiscretizerModule::Digitize() { +//From here GateSpatialResolution* digi_SpatialResolution; digi_SpatialResolution = dynamic_cast(m_digitizer->FindDigitizerModule("digitizerMgr/" +m_digitizer->GetSD()->GetName() +"/SinglesDigitizer/" + m_digitizer->GetName() - + "/SpatialResolution")); + + "/spatialResolution")); @@ -98,17 +100,21 @@ void GateDiscretizerModule::Digitize() G4double resolutionY; G4double resolutionZ; + G4int nBinsX; + G4int nBinsY; + G4int nBinsZ; + G4double pitchX; + G4double pitchY; + G4double pitchZ; - - - - + //TODO bulletproof this! if (digi_SpatialResolution->GetFWHM()) { + if(m_nameAxis.find('X') != std::string::npos) {resolutionX = digi_SpatialResolution->GetFWHM();} @@ -121,6 +127,7 @@ void GateDiscretizerModule::Digitize() else if(digi_SpatialResolution->GetFWHMx() || digi_SpatialResolution->GetFWHMy()|| digi_SpatialResolution->GetFWHMz()){ + if(digi_SpatialResolution->GetFWHMx() && m_nameAxis.find('X') != std::string::npos) {resolutionX = digi_SpatialResolution->GetFWHMx();} @@ -131,25 +138,12 @@ void GateDiscretizerModule::Digitize() {resolutionZ = digi_SpatialResolution->GetFWHMz();} } - else if (m_nameAxis == "XYZ" && (m_resolution==0) || (m_resolutionX==0 || m_resolutionY==0 ||m_resolutionZ==0)) - { - - GateError("***ERROR*** Discretization in XYZ has been selected but at least one axis has resolution = 0. Please ensure that all axis have a non zero value of resolution."); - } - if (m_resolution != 0) + else if (m_nameAxis == "XYZ" && (m_resolution==0) || (m_resolutionX==0 || m_resolutionY==0 ||m_resolutionZ==0)) { - resolutionX = m_resolution; - resolutionY = m_resolution; - resolutionZ = m_resolution; - } - else - { - resolutionX = m_resolutionX; - resolutionY = m_resolutionY; - resolutionZ = m_resolutionZ; + GateError("***ERROR*** Discretization in XYZ has been selected but at least one axis has resolution = 0. Please ensure that all axis have a non zero value of resolution."); } @@ -167,6 +161,8 @@ void GateDiscretizerModule::Digitize() "Please, add them to your geometry macro in /gate/systems/cylindricalPET/XXX/attach YYY. Abort.\n"); } + + m_systemDepth = m_system->GetTreeDepth(); //TODO I need to create another parameter asking if spatial resolution is provided by hand. //I need to get system, system depth. Check that the size for the last 4 solids is the same (Monolithic crystal) @@ -174,7 +170,6 @@ void GateDiscretizerModule::Digitize() - G4String digitizerName = m_digitizer->m_digitizerName; G4String outputCollName = m_digitizer-> GetOutputName(); @@ -195,6 +190,10 @@ void GateDiscretizerModule::Digitize() + G4double xLength,yLength,zLength; + + + if (IDC) { G4int n_digi = IDC->entries(); @@ -205,21 +204,19 @@ void GateDiscretizerModule::Digitize() inputDigi=(*IDC)[i]; // ***** the following part of the code to adapt /// *** This part is from ProcessPulseList + if (inputDigi->GetVolumeID().size()){ + G4Box* box = dynamic_cast(inputDigi->GetVolumeID().GetBottomCreator()->GetLogicalVolume()->GetSolid()); + xLength = 2*box->GetXHalfLength(); + yLength = 2*box->GetYHalfLength(); + zLength = 2*box->GetZHalfLength(); + } + else std::cout<<"Well that's another problem here..."<< std::endl; + + + + + - ////// ** This part is from ProcessOnePulse - for (iter=OutputDigiCollectionVector->begin(); iter!= OutputDigiCollectionVector->end() ; ++iter) - { - if ( (*iter)->GetVolumeID() == inputDigi->GetVolumeID() ) - { - continue; - if(m_nameAxis=="XYZ"){continue;} - /* if(m_parameter=="numAxis"){ - DummyMethod1(inputDigi); - } - else{ - DummyMethod2( inputDigi ); - } - */ if (nVerboseLevel>1) { G4cout << "Merged previous pulse for volume " << inputDigi->GetVolumeID() @@ -227,15 +224,34 @@ void GateDiscretizerModule::Digitize() << "Resulting pulse is: \n" << **iter << Gateendl << Gateendl ; } - break; - } - } - if ( iter == OutputDigiCollectionVector->end() ) - { + m_outputDigi = new GateDigi(*inputDigi); m_outputDigi->SetEnergyIniTrack(-1); m_outputDigi->SetEnergyFin(-1); + + + + + if(m_nameAxis=="XYZ"){ + + pitchX = calculatePitch(xLength,resolutionX); + nBinsX = int(xLength/pitchX); + pitchY = calculatePitch(yLength,resolutionY); + nBinsY = int(yLength/pitchY); + pitchZ = calculatePitch(zLength,resolutionZ); + nBinsZ = int(zLength/pitchZ); + + + G4ThreeVector localPos = inputDigi->GetLocalPos(); + //std::cout<<"Local position = " << localPos <<" nBinsX "<GetOutputVolumeID()<1) G4cout << "Created new pulse for volume " << inputDigi->GetVolumeID() << ".\n" << "Resulting pulse is: \n" @@ -243,7 +259,7 @@ void GateDiscretizerModule::Digitize() /// !!!!!! The following line should be kept !!!! -> inserts the outputdigi to collection m_OutputDigiCollection->insert(m_outputDigi); - } + ////// ** End of the part from ProcessOnePulse @@ -286,10 +302,13 @@ void GateDiscretizerModule::SetNameAxis(const G4String ¶m) - +/* G4double GateDiscretizerModule::calculatePitch(G4double crystal_size, G4double spatial_resolution) { - // Target pitch size + + + // Target pitch size double target_pitch = spatial_resolution / 2.0; + std::cout<<"Spatial Resolution: "<::max(); @@ -302,51 +321,91 @@ G4double GateDiscretizerModule::calculatePitch(G4double crystal_size, G4double s } } + std::cout<<"Best pitch is: "<1000){ + std::cout<<"ERROR! No pitch found in 1000 iterations!"<(pos.getX()/pitchX)+static_cast(nBinsX/2); + binY = static_cast(pos.getY()/pitchY)+static_cast(nBinsY/2); + binZ = static_cast(pos.getZ()/pitchZ)+static_cast(nBinsY/2); + //Change the OutputVolumeID at depths 3,4,5 //(SubmoduleID=binX, crystalID = binY and layerID = binZ) - m_outputDigi->SetOutputVolumeID(3,binX); - m_outputDigi->SetOutputVolumeID(4,binY); - m_outputDigi->SetOutputVolumeID(5,binZ); + m_outputDigi->SetOutputVolumeID(binX,3); + m_outputDigi->SetOutputVolumeID(binY,4); + m_outputDigi->SetOutputVolumeID(binZ,5); + + } -/* -void GateDiscretizerModule::DummyMethod1(GateDigi *right) -{ - //to copy all variables that are not changed - m_outputDigi=right; +void GateDiscretizerModule::SetVirtualID( int nBins, double pitch, G4double pos , int depth){ -} -void GateDiscretizerModule::DummyMethod2(GateDigi *right) -{ - //to copy all variables that are not changed - m_outputDigi=right; + + int bin; + + + bin = static_cast(pos/pitch)+static_cast(nBins/2); + + + m_outputDigi->SetOutputVolumeID(bin,depth); + + } + -} -*/ void GateDiscretizerModule::DescribeMyself(size_t indent ) { if(m_resolution) diff --git a/source/digits_hits/src/GateDummyDigitizerModule.cc b/source/digits_hits/src/GateDummyDigitizerModule.cc index fb8a741f4..afed06be7 100755 --- a/source/digits_hits/src/GateDummyDigitizerModule.cc +++ b/source/digits_hits/src/GateDummyDigitizerModule.cc @@ -46,7 +46,7 @@ inputPulse -> inputDigi outputPulse -> m_outputDigi + correct the first declaration (as in this Dummy module) outputPulseList.push_back(outputPulse) -> m_OutputDigiCollection->insert(m_outputDigi); - 10) Add YourDigitizerModule to GateSinglesDigitizer.cc + 10) Add YourDigitizerModule to GateSinglesDigitizer - #include "YourDigitizerModule.hh" - in DumpMap() method in static G4String theList = " ...." diff --git a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc index da583fbf0..19dd1359d 100755 --- a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc +++ b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc @@ -127,7 +127,7 @@ const G4String& GateSinglesDigitizerMessenger::DumpMap() { - static G4String theList = "readout adder energyFraming timeResolution energyResolution spatialResolution efficiency deadtime pileup adderCompton opticaladder noise merger intrinsicResolution buffer crosstalk doIModel timeDelay clustering adderComptPhotIdeal gridDiscretizator multipleRejection"; + static G4String theList = "readout adder energyFraming timeResolution energyResolution spatialResolution efficiency deadtime pileup adderCompton opticaladder noise merger intrinsicResolution buffer crosstalk doIModel timeDelay clustering adderComptPhotIdeal gridDiscretizator multipleRejection discretizer"; return theList; } From 26dedae48b2c1b2f2b0745a686629bcece57cd24 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Thu, 4 Jul 2024 11:06:04 +0200 Subject: [PATCH 25/96] Generalisation of the XYZ axis, bug for ID fixed, introduction of a dummy python script for macro_conversion --- .../digits_hits/src/GateDiscretizerModule.cc | 144 +++++++++++++++--- .../src/GateDiscretizerModuleMessenger.cc | 4 +- 2 files changed, 125 insertions(+), 23 deletions(-) diff --git a/source/digits_hits/src/GateDiscretizerModule.cc b/source/digits_hits/src/GateDiscretizerModule.cc index c3a4a70b9..b9d46df35 100644 --- a/source/digits_hits/src/GateDiscretizerModule.cc +++ b/source/digits_hits/src/GateDiscretizerModule.cc @@ -42,7 +42,7 @@ #include #include #include - +#include @@ -96,9 +96,9 @@ void GateDiscretizerModule::Digitize() - G4double resolutionX; - G4double resolutionY; - G4double resolutionZ; + G4double resolutionX=0; + G4double resolutionY=0; + G4double resolutionZ=0; G4int nBinsX; G4int nBinsY; @@ -108,11 +108,41 @@ void GateDiscretizerModule::Digitize() G4double pitchY; G4double pitchZ; - + G4int depthX=5; + G4int depthY=4; + G4int depthZ=3; //TODO bulletproof this! - if (digi_SpatialResolution->GetFWHM()) + if(m_resolution){ + if(m_nameAxis.find('X') != std::string::npos) + {resolutionX = m_resolution;} + + if(m_nameAxis.find('Y') != std::string::npos) + {resolutionY = m_resolution;} + + if(m_nameAxis.find('Z') != std::string::npos) + {resolutionZ = m_resolution;} + + + if (m_resolutionX!=0 || m_resolutionY!=0 ||m_resolutionZ!=0) + {GateWarning("The values provided for spatial resolution are ambiguous. Only the value of 'resolution' was taken, any value provided for 'resolutionX', 'resolutionY' and 'resolutionZ' was ignored");} + } + + else if (m_resolutionX!=0 || m_resolutionY!=0 ||m_resolutionZ!=0){ + + if(m_resolutionX && m_nameAxis.find('X') != std::string::npos) + {resolutionX = m_resolutionX;} + + if(m_resolutionY && m_nameAxis.find('Y') != std::string::npos) + {resolutionY = m_resolutionY;} + + if(m_resolutionZ && m_nameAxis.find('Z') != std::string::npos) + {resolutionZ = m_resolutionZ;} + + } + + else if (digi_SpatialResolution->GetFWHM()) { if(m_nameAxis.find('X') != std::string::npos) @@ -139,15 +169,36 @@ void GateDiscretizerModule::Digitize() } + if(resolutionX == 0 && m_nameAxis.find('X') != std::string::npos) + {GateError("***ERROR*** Discretization in X axis has been selected but no value for FWHM was provided."); + } + if(resolutionY == 0 && m_nameAxis.find('Y') != std::string::npos) + {GateError("***ERROR*** Discretization in Y axis has been selected but no value for FWHM was provided."); + } + if(resolutionZ == 0 && m_nameAxis.find('Z') != std::string::npos) + {GateError("***ERROR*** Discretization in Z axis has been selected but no value for FWHM was provided."); + } + + /* else if (m_nameAxis == "XYZ" && (m_resolution==0) || (m_resolutionX==0 || m_resolutionY==0 ||m_resolutionZ==0)) { GateError("***ERROR*** Discretization in XYZ has been selected but at least one axis has resolution = 0. Please ensure that all axis have a non zero value of resolution."); } +*/ + if (true){ + std::string path_to_script = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; + std::string path_to_macros = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; + std::string command = "python3 "+path_to_script+"macro_converter.py"; + command +=" -d "+path_to_macros+"digitizer.mac"; + command +=" -g "+path_to_macros+"geometry_pseudo-crystal.mac"; + int result = system(command.c_str()); + if (result ==0) std::cout<<"The macro converter script has been executed corectly"<GetDigitizer())->GetSystem(); @@ -232,7 +283,7 @@ void GateDiscretizerModule::Digitize() - +/* if(m_nameAxis=="XYZ"){ pitchX = calculatePitch(xLength,resolutionX); @@ -248,8 +299,63 @@ void GateDiscretizerModule::Digitize() SetVirtualIDs(nBinsX,nBinsY,nBinsZ,pitchX,pitchY,pitchZ,localPos); } +*/ + G4ThreeVector localPos = inputDigi->GetLocalPos(); + + + + if(m_nameAxis.find('X') != std::string::npos){ + std::cout<<"In X! "<GetOutputVolumeID()<GetOutputVolumeID()<<" Pitches "<1) @@ -371,16 +477,16 @@ void GateDiscretizerModule::SetVirtualIDs( int nBinsX, int nBinsY,int nBinsZ,dou - binX = static_cast(pos.getX()/pitchX)+static_cast(nBinsX/2); - binY = static_cast(pos.getY()/pitchY)+static_cast(nBinsY/2); - binZ = static_cast(pos.getZ()/pitchZ)+static_cast(nBinsY/2); + binX = std::floor(pos.getX()/pitchX+nBinsX/2); + binY = std::floor(pos.getY()/pitchY+nBinsY/2); + binZ = std::floor(pos.getZ()/pitchZ+nBinsY/2); //Change the OutputVolumeID at depths 3,4,5 - //(SubmoduleID=binX, crystalID = binY and layerID = binZ) - m_outputDigi->SetOutputVolumeID(binX,3); + //(SubmoduleID=binZ, crystalID = binY and layerID = binX) + m_outputDigi->SetOutputVolumeID(binZ,3); m_outputDigi->SetOutputVolumeID(binY,4); - m_outputDigi->SetOutputVolumeID(binZ,5); + m_outputDigi->SetOutputVolumeID(binX,5); } @@ -388,17 +494,13 @@ void GateDiscretizerModule::SetVirtualIDs( int nBinsX, int nBinsY,int nBinsZ,dou - void GateDiscretizerModule::SetVirtualID( int nBins, double pitch, G4double pos , int depth){ - - int bin; - bin = static_cast(pos/pitch)+static_cast(nBins/2); - - + bin = std::floor(pos/pitch+nBins/2.); + std::cout<<"[pitch,nBins,pos,bin, sum] = ["<SetOutputVolumeID(bin,depth); } diff --git a/source/digits_hits/src/GateDiscretizerModuleMessenger.cc b/source/digits_hits/src/GateDiscretizerModuleMessenger.cc index a1da8a3aa..712a6cc7f 100644 --- a/source/digits_hits/src/GateDiscretizerModuleMessenger.cc +++ b/source/digits_hits/src/GateDiscretizerModuleMessenger.cc @@ -46,8 +46,8 @@ GateDiscretizerModuleMessenger::GateDiscretizerModuleMessenger (GateDiscretizerM cmdName = GetDirectoryName()+"nameAxis"; nameAxisCmd = new G4UIcmdWithAString(cmdName,this); - nameAxisCmd ->SetGuidance("Provide the number of axis that need to be discretized, XY or XYZ"); - nameAxisCmd ->SetCandidates("XY XYZ"); + nameAxisCmd ->SetGuidance("Provide the number of axis that need to be discretized, XYZ, XY, XZ, or YZ"); + nameAxisCmd ->SetCandidates("XYZ XY XZ YZ"); cmdName = GetDirectoryName() + "resolution"; From ced9176ed76c44abaf7a439fbf569ad3e9a68007 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Tue, 9 Jul 2024 15:48:42 +0200 Subject: [PATCH 26/96] After cleaning up the code and changing spatial resolution for pitch and adding macro generator flag --- .../include/GateDiscretizerModule.hh | 113 ---- .../include/GateDiscretizerModuleMessenger.hh | 64 --- .../include/GateVirtualSegmentationSD.hh | 134 +++++ .../GateVirtualSegmentationSDMessenger.hh | 65 +++ .../src/GateDiscretizerModuleMessenger.cc | 128 ----- .../src/GateDummyDigitizerModule.cc | 2 +- .../src/GateSinglesDigitizerMessenger.cc | 8 +- ...Module.cc => GateVirtualSegmentationSD.cc} | 504 ++++++++++-------- .../src/GateVirtualSegmentationSDMessenger.cc | 135 +++++ 9 files changed, 630 insertions(+), 523 deletions(-) delete mode 100644 source/digits_hits/include/GateDiscretizerModule.hh delete mode 100644 source/digits_hits/include/GateDiscretizerModuleMessenger.hh create mode 100644 source/digits_hits/include/GateVirtualSegmentationSD.hh create mode 100644 source/digits_hits/include/GateVirtualSegmentationSDMessenger.hh delete mode 100644 source/digits_hits/src/GateDiscretizerModuleMessenger.cc rename source/digits_hits/src/{GateDiscretizerModule.cc => GateVirtualSegmentationSD.cc} (50%) create mode 100644 source/digits_hits/src/GateVirtualSegmentationSDMessenger.cc diff --git a/source/digits_hits/include/GateDiscretizerModule.hh b/source/digits_hits/include/GateDiscretizerModule.hh deleted file mode 100644 index 32f639054..000000000 --- a/source/digits_hits/include/GateDiscretizerModule.hh +++ /dev/null @@ -1,113 +0,0 @@ -/*---------------------- - Copyright (C): OpenGATE Collaboration - -This software is distributed under the terms -of the GNU Lesser General Public Licence (LGPL) -See LICENSE.md for further details -----------------------*/ - -// OK GND 2022 -/*This class is not used by GATE ! - The purpose of this class is to help to create new users digitizer module(DM). - Please, check GateDiscretizerModule.cc for more detals - */ - - -/*! \class GateDiscretizerModule - \brief GateDiscretizerModule does some dummy things with input digi - to create output digi - - - GateDiscretizerModule - by marc.granado@universite-paris-saclay.fr - - \sa GateDiscretizerModule, GateDiscretizerModuleMessenger -*/ - -#ifndef GateDiscretizerModule_h -#define GateDiscretizerModule_h 1 - -#include "GateVDigitizerModule.hh" -#include "GateDigi.hh" -#include "GateClockDependent.hh" -#include "GateCrystalSD.hh" - -#include "globals.hh" - -#include "GateDiscretizerModuleMessenger.hh" -#include "GateSinglesDigitizer.hh" - - -class GateDiscretizerModule : public GateVDigitizerModule -{ -public: - - GateDiscretizerModule(GateSinglesDigitizer *digitizer, G4String name); - ~GateDiscretizerModule(); - - void Digitize() override; - - //! These functions return the resolution in use. - G4String GetNameAxis() { return m_nameAxis; } - G4double GetResolution() { return m_resolution; } - G4double GetResolutionX() { return m_resolutionX; } - G4double GetResolutionY() { return m_resolutionY; } - G4double GetResolutionZ() { return m_resolutionZ; } - - G4double calculatePitch(G4double crystal_size, G4double spatial_resolution); - - - //Set Parameter - void SetNameAxis(const G4String&); - - - - //Set Variables - void SetResolution(G4double val) { m_resolution = val; } - void SetResolutionX(G4double val) { m_resolutionX = val; } - void SetResolutionY(G4double val) { m_resolutionY = val; } - void SetResolutionZ(G4double val) { m_resolutionZ = val; } - - - void SetVirtualIDs(int nBinsX, int nBinsY,int nBinsZ,double pitchX,double pitchY,double pitchZ, G4ThreeVector& pos); - void SetVirtualID(int nBins,double pitch, G4double pos, int depth); - void DescribeMyself(size_t ); - -protected: - // *******implement your parameters here - G4double m_resolution; - - G4String m_nameAxis; - G4double m_resolutionX; - G4double m_resolutionY; - G4double m_resolutionZ; - - - //These are in Spatial resolution but aren't there rom touchable? - //We'll need to check - - //G4Navigator* m_Navigator; - //G4TouchableHistoryHandle m_Touchable; - -private: - - G4int m_systemDepth; - - GateDigi* m_outputDigi; - - GateDiscretizerModuleMessenger *m_Messenger; - - GateDigiCollection* m_OutputDigiCollection; - - GateSinglesDigitizer *m_digitizer; - - -}; - -#endif - - - - - - - - diff --git a/source/digits_hits/include/GateDiscretizerModuleMessenger.hh b/source/digits_hits/include/GateDiscretizerModuleMessenger.hh deleted file mode 100644 index c0d471277..000000000 --- a/source/digits_hits/include/GateDiscretizerModuleMessenger.hh +++ /dev/null @@ -1,64 +0,0 @@ -/*---------------------- - Copyright (C): OpenGATE Collaboration - -This software is distributed under the terms -of the GNU Lesser General Public Licence (LGPL) -See LICENSE.md for further details -----------------------*/ - -// OK GND 2022 -/*This class is not used by GATE ! - The purpose of this class is to help to create new users digitizer module(DM). - Please, check GateDiscretizerModule.cc for more detals - */ - - -/*! \class GateDiscretizerModuleMessenger - \brief Messenger for the GateDiscretizerModule - - - GateDiscretizerModule - by marc.granado@universite-paris-saclay.fr - - \sa GateDiscretizerModule, GateDiscretizerModuleMessenger -*/ - - -#ifndef GateDiscretizerModuleMessenger_h -#define GateDiscretizerModuleMessenger_h 1 - -#include "G4UImessenger.hh" -#include "globals.hh" - -#include "GateClockDependentMessenger.hh" -class GateDiscretizerModule; -class G4UIcmdWithAString; - -class GateDiscretizerModuleMessenger : public GateClockDependentMessenger -{ -public: - - GateDiscretizerModuleMessenger(GateDiscretizerModule*); - ~GateDiscretizerModuleMessenger(); - - void SetNewValue(G4UIcommand*, G4String); - - -private: - GateDiscretizerModule* m_DiscretizerModule; - - G4UIcmdWithAString* nameAxisCmd; - - G4UIcmdWithADouble* resCmd; - G4UIcmdWithADouble* resolutionXCmd; - G4UIcmdWithADouble* resolutionYCmd; - G4UIcmdWithADouble* resolutionZCmd; -}; - -#endif - - - - - - - - diff --git a/source/digits_hits/include/GateVirtualSegmentationSD.hh b/source/digits_hits/include/GateVirtualSegmentationSD.hh new file mode 100644 index 000000000..3ac1e3f3b --- /dev/null +++ b/source/digits_hits/include/GateVirtualSegmentationSD.hh @@ -0,0 +1,134 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + +// OK GND 2022 +/*This class is not used by GATE ! + The purpose of this class is to help to create new users digitizer module(DM). + Please, check GateVirtualSegmentationSD.cc for more detals + */ + + +/*! \class GateVirtualSegmentationSD + \brief GateVirtualSegmentationSD does some dummy things with input digi + to create output digi + + - GateVirtualSegmentationSD - by marc.granado@universite-paris-saclay.fr + + \sa GateVirtualSegmentationSD, GateVirtualSegmentationSDMessenger +*/ + +#ifndef GateVirtualSegmentationSD_h +#define GateVirtualSegmentationSD_h 1 + +#include "GateVDigitizerModule.hh" +#include "GateDigi.hh" +#include "GateClockDependent.hh" +#include "GateCrystalSD.hh" + +#include "globals.hh" + +#include "GateVirtualSegmentationSDMessenger.hh" +#include "GateSinglesDigitizer.hh" + + +class GateVirtualSegmentationSD : public GateVDigitizerModule +{ +public: + + GateVirtualSegmentationSD(GateSinglesDigitizer *digitizer, G4String name); + + ~GateVirtualSegmentationSD(); + + void Digitize() override; + + //! These functions return the pitch in use. + G4String GetNameAxis() { return m_nameAxis; } + G4double GetPitch() { return m_pitch; } + G4double GetPitchX() { return m_pitchX; } + G4double GetPitchY() { return m_pitchY; } + G4double GetPitchZ() { return m_pitchZ; } + + G4double calculatePitch(G4double crystal_size, G4double target_pitch); + + + //Set Parameter + void SetNameAxis(const G4String&); + + void SetUseMacroGenerator(G4bool val) {useMacroGenerator=val;} + + //Set Variables + void SetPitch(G4double val) { m_pitch = val; } + void SetPitchX(G4double val) { m_pitchX = val; } + void SetPitchY(G4double val) { m_pitchY = val; } + void SetPitchZ(G4double val) { m_pitchZ = val; } + + void SetParameters(); + + void SetVirtualID(int nBins,double pitch, G4double pos, int depth); + void DescribeMyself(size_t ); + +protected: + // *******implement your parameters here + G4double m_pitch; + + G4String m_nameAxis; + G4double m_pitchX; + G4double m_pitchY; + G4double m_pitchZ; + + G4int nBinsX; + G4int nBinsY; + G4int nBinsZ; + + G4double pitchX; + G4double pitchY; + G4double pitchZ; + + G4int depthX; + G4int depthY; + G4int depthZ; + + G4double xLength; + G4double yLength; + G4double zLength; + + //These are in Spatial pitch but aren't there rom touchable? + //We'll need to check + + //G4Navigator* m_Navigator; + //G4TouchableHistoryHandle m_Touchable; + +private: + + G4int m_systemDepth; + + G4int m_IsFirstEntry; + + G4bool useMacroGenerator; + + GateDigi* m_outputDigi; + + GateVirtualSegmentationSDMessenger *m_Messenger; + + GateDigiCollection* m_OutputDigiCollection; + + GateSinglesDigitizer *m_digitizer; + + +}; + + +#endif + + + + + + + + diff --git a/source/digits_hits/include/GateVirtualSegmentationSDMessenger.hh b/source/digits_hits/include/GateVirtualSegmentationSDMessenger.hh new file mode 100644 index 000000000..9a9fde1dc --- /dev/null +++ b/source/digits_hits/include/GateVirtualSegmentationSDMessenger.hh @@ -0,0 +1,65 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + +// OK GND 2022 +/*This class is not used by GATE ! + The purpose of this class is to help to create new users digitizer module(DM). + Please, check GateVirtualSegmentationSD.cc for more detals + */ + + +/*! \class GateVirtualSegmentationSDMessenger + \brief Messenger for the GateVirtualSegmentationSD + + - GateVirtualSegmentationSD - by marc.granado@universite-paris-saclay.fr + + \sa GateVirtualSegmentationSD, GateVirtualSegmentationSDMessenger +*/ + + +#ifndef GateVirtualSegmentationSDMessenger_h +#define GateVirtualSegmentationSDMessenger_h 1 + +#include "G4UImessenger.hh" +#include "globals.hh" + +#include "GateClockDependentMessenger.hh" +class GateVirtualSegmentationSD; +class G4UIcmdWithAString; + +class GateVirtualSegmentationSDMessenger : public GateClockDependentMessenger +{ +public: + + GateVirtualSegmentationSDMessenger(GateVirtualSegmentationSD*); + ~GateVirtualSegmentationSDMessenger(); + + void SetNewValue(G4UIcommand*, G4String); + + +private: + GateVirtualSegmentationSD* m_VirtualSegmentationSD; + + G4UIcmdWithAString* nameAxisCmd; + + G4UIcmdWithABool* useMacroGeneratorCmd; + G4UIcmdWithADoubleAndUnit* pitchCmd; + G4UIcmdWithADoubleAndUnit* pitchXCmd; + G4UIcmdWithADoubleAndUnit* pitchYCmd; + G4UIcmdWithADoubleAndUnit* pitchZCmd; +}; + +#endif + + + + + + + + diff --git a/source/digits_hits/src/GateDiscretizerModuleMessenger.cc b/source/digits_hits/src/GateDiscretizerModuleMessenger.cc deleted file mode 100644 index 712a6cc7f..000000000 --- a/source/digits_hits/src/GateDiscretizerModuleMessenger.cc +++ /dev/null @@ -1,128 +0,0 @@ -/*---------------------- - Copyright (C): OpenGATE Collaboration - -This software is distributed under the terms -of the GNU Lesser General Public Licence (LGPL) -See LICENSE.md for further details -----------------------*/ - -// OK GND 2022 -/*This class is not used by GATE ! - The purpose of this class is to help to create new users digitizer module(DM). - Please, check GateDiscretizerModule.cc for more detals - */ - - - -/*! - \class GateDiscretizer (by marc.granado@universite-paris-saclay.fr) - \brief for discretizing the position within a monolithic crystal - - - For each volume the local position of the interactions within the crystal are discretized. - the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal - occupying the levels of SubmoduleID, CrystalID and LayerID. - -*/ - - -#include "GateDiscretizerModuleMessenger.hh" -#include "GateDiscretizerModule.hh" -#include "GateDigitizerMgr.hh" - -#include "G4SystemOfUnits.hh" -#include "G4UIcmdWithADouble.hh" -#include "G4UIcmdWithAString.hh" -#include "G4UIdirectory.hh" - - - -GateDiscretizerModuleMessenger::GateDiscretizerModuleMessenger (GateDiscretizerModule* DiscretizerModule) -:GateClockDependentMessenger(DiscretizerModule), - m_DiscretizerModule(DiscretizerModule) -{ - G4String guidance; - G4String cmdName; - - - cmdName = GetDirectoryName()+"nameAxis"; - nameAxisCmd = new G4UIcmdWithAString(cmdName,this); - nameAxisCmd ->SetGuidance("Provide the number of axis that need to be discretized, XYZ, XY, XZ, or YZ"); - nameAxisCmd ->SetCandidates("XYZ XY XZ YZ"); - - - cmdName = GetDirectoryName() + "resolution"; - resCmd = new G4UIcmdWithADouble(cmdName,this); - resCmd->SetGuidance("Set the size of the resolution for all the selected dimensions"); - - - - cmdName = GetDirectoryName()+"resolutionX"; - resolutionXCmd = new G4UIcmdWithADouble(cmdName,this); - resolutionXCmd->SetGuidance("Set the size of the resolution for the X dimension"); - - cmdName = GetDirectoryName()+"resolutionY"; - resolutionYCmd = new G4UIcmdWithADouble(cmdName,this); - resolutionYCmd->SetGuidance("Set the size of the resolution for the Y dimension"); - - cmdName = GetDirectoryName()+"resolutionZ"; - resolutionZCmd = new G4UIcmdWithADouble(cmdName,this); - resolutionZCmd->SetGuidance("Set the size of the resolution for the Z dimension"); - -} - - -GateDiscretizerModuleMessenger::~GateDiscretizerModuleMessenger() -{ - delete nameAxisCmd; - delete resCmd; - delete resolutionXCmd; - delete resolutionYCmd; - delete resolutionZCmd; -} - - -void GateDiscretizerModuleMessenger::SetNewValue(G4UIcommand * aCommand,G4String newValue) -{ - - if (aCommand == nameAxisCmd) - { - m_DiscretizerModule->SetNameAxis(newValue); - } - - else if (aCommand == resCmd) - { - m_DiscretizerModule->SetResolution(resCmd->GetNewDoubleValue(newValue)); - } - else if (aCommand == resolutionXCmd) - { - m_DiscretizerModule->SetResolutionX(resCmd->GetNewDoubleValue(newValue)); - - } - - else if (aCommand == resolutionYCmd) - { - m_DiscretizerModule->SetResolutionY(resCmd->GetNewDoubleValue(newValue)); - } - else if (aCommand == resolutionZCmd) - { - m_DiscretizerModule->SetResolutionZ(resCmd->GetNewDoubleValue(newValue)); - } - - else - { - GateClockDependentMessenger::SetNewValue(aCommand,newValue); - } -} - - - - - - - - - - - - - diff --git a/source/digits_hits/src/GateDummyDigitizerModule.cc b/source/digits_hits/src/GateDummyDigitizerModule.cc index afed06be7..8df34bf49 100755 --- a/source/digits_hits/src/GateDummyDigitizerModule.cc +++ b/source/digits_hits/src/GateDummyDigitizerModule.cc @@ -46,7 +46,7 @@ inputPulse -> inputDigi outputPulse -> m_outputDigi + correct the first declaration (as in this Dummy module) outputPulseList.push_back(outputPulse) -> m_OutputDigiCollection->insert(m_outputDigi); - 10) Add YourDigitizerModule to GateSinglesDigitizer + 10) Add YourDigitizerModule to GateSinglesDigitizerMessenger - #include "YourDigitizerModule.hh" - in DumpMap() method in static G4String theList = " ...." diff --git a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc index 19dd1359d..80e0b25e0 100755 --- a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc +++ b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc @@ -55,7 +55,7 @@ See LICENSE.md for further details #include "GateAdderComptPhotIdeal.hh" #include "GateClustering.hh" #include "GateTimeDelay.hh" -#include "GateDiscretizerModule.hh" +#include "GateVirtualSegmentationSD.hh" /* #include "GateLocalTimeDelay.hh" @@ -127,7 +127,7 @@ const G4String& GateSinglesDigitizerMessenger::DumpMap() { - static G4String theList = "readout adder energyFraming timeResolution energyResolution spatialResolution efficiency deadtime pileup adderCompton opticaladder noise merger intrinsicResolution buffer crosstalk doIModel timeDelay clustering adderComptPhotIdeal gridDiscretizator multipleRejection discretizer"; + static G4String theList = "readout adder energyFraming timeResolution energyResolution spatialResolution efficiency deadtime pileup adderCompton opticaladder noise merger intrinsicResolution buffer crosstalk doIModel timeDelay clustering adderComptPhotIdeal gridDiscretizator multipleRejection virtualSegmentation"; return theList; } @@ -268,9 +268,9 @@ else if (childTypeName=="multipleRejection") m_digitizer->AddNewModule(newDM); } - else if (childTypeName=="discretizer") + else if (childTypeName=="virtualSegmentation") { - newDM = new GateDiscretizerModule(m_digitizer, DMname); + newDM = new GateVirtualSegmentationSD(m_digitizer, DMname); m_digitizer->AddNewModule(newDM); } diff --git a/source/digits_hits/src/GateDiscretizerModule.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc similarity index 50% rename from source/digits_hits/src/GateDiscretizerModule.cc rename to source/digits_hits/src/GateVirtualSegmentationSD.cc index b9d46df35..20a00743b 100644 --- a/source/digits_hits/src/GateDiscretizerModule.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -8,10 +8,10 @@ // OK GND 2022 /*! - \class GateDiscretizer (by marc.granado@universite-paris-saclay.fr) - \brief for discretizing the position within a monolithic crystal + \class GateVirtualSegmentationSD (by marc.granado@universite-paris-saclay.fr) + \brief for discretizing the position through a virtual segmentation of a monolithic crystal - - For each volume the local position of the interactions within the crystal are discretized. + - For each volume the local position of the interactions within the crystal are virtually segmented. the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal occupying the levels of SubmoduleID, CrystalID and LayerID. @@ -19,8 +19,8 @@ -#include "GateDiscretizerModule.hh" -#include "GateDiscretizerModuleMessenger.hh" +#include "GateVirtualSegmentationSD.hh" +#include "GateVirtualSegmentationSDMessenger.hh" #include "GateDigi.hh" #include "GateSpatialResolution.hh" @@ -48,157 +48,62 @@ -GateDiscretizerModule::GateDiscretizerModule(GateSinglesDigitizer *digitizer, G4String name) +GateVirtualSegmentationSD::GateVirtualSegmentationSD(GateSinglesDigitizer *digitizer, G4String name) :GateVDigitizerModule(name,"digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/"+name,digitizer,digitizer->GetSD()), + m_IsFirstEntry(1), m_nameAxis("XYZ"), + useMacroGenerator(0), - m_resolution(0), - m_resolutionX(0), - m_resolutionY(0), - m_resolutionZ(0), + m_pitch(0), + m_pitchX(0), + m_pitchY(0), + m_pitchZ(0), m_outputDigi(0), m_OutputDigiCollection(0), - m_digitizer(digitizer) - { - G4String colName = digitizer->GetOutputName() ; - collectionName.push_back(colName); - m_Messenger = new GateDiscretizerModuleMessenger(this); -} - - - - -GateDiscretizerModule::~GateDiscretizerModule() -{ - delete m_Messenger; - -} + m_digitizer(digitizer), + pitchX(0), + pitchY(0), + pitchZ(0), + nBinsX(0), + nBinsY(0), + nBinsZ(0), + depthX(5), + depthY(4), + depthZ(3), + xLength(0), + yLength(0), + zLength(0) -void GateDiscretizerModule::Digitize() { + G4String colName = digitizer->GetOutputName() ; + collectionName.push_back(colName); + m_Messenger = new GateVirtualSegmentationSDMessenger(this); +} -//From here - - GateSpatialResolution* digi_SpatialResolution; - digi_SpatialResolution = dynamic_cast(m_digitizer->FindDigitizerModule("digitizerMgr/" - +m_digitizer->GetSD()->GetName() - +"/SinglesDigitizer/" - + m_digitizer->GetName() - + "/spatialResolution")); - - - - G4double resolutionX=0; - G4double resolutionY=0; - G4double resolutionZ=0; - - G4int nBinsX; - G4int nBinsY; - G4int nBinsZ; - - G4double pitchX; - G4double pitchY; - G4double pitchZ; - - G4int depthX=5; - G4int depthY=4; - G4int depthZ=3; - - //TODO bulletproof this! - - if(m_resolution){ - if(m_nameAxis.find('X') != std::string::npos) - {resolutionX = m_resolution;} - - if(m_nameAxis.find('Y') != std::string::npos) - {resolutionY = m_resolution;} - - if(m_nameAxis.find('Z') != std::string::npos) - {resolutionZ = m_resolution;} - - - if (m_resolutionX!=0 || m_resolutionY!=0 ||m_resolutionZ!=0) - {GateWarning("The values provided for spatial resolution are ambiguous. Only the value of 'resolution' was taken, any value provided for 'resolutionX', 'resolutionY' and 'resolutionZ' was ignored");} - } - - else if (m_resolutionX!=0 || m_resolutionY!=0 ||m_resolutionZ!=0){ - - if(m_resolutionX && m_nameAxis.find('X') != std::string::npos) - {resolutionX = m_resolutionX;} - - if(m_resolutionY && m_nameAxis.find('Y') != std::string::npos) - {resolutionY = m_resolutionY;} - - if(m_resolutionZ && m_nameAxis.find('Z') != std::string::npos) - {resolutionZ = m_resolutionZ;} - - } - - else if (digi_SpatialResolution->GetFWHM()) - { - - if(m_nameAxis.find('X') != std::string::npos) - {resolutionX = digi_SpatialResolution->GetFWHM();} - - if(m_nameAxis.find('Y') != std::string::npos) - {resolutionY = digi_SpatialResolution->GetFWHM();} - - if(m_nameAxis.find('Z') != std::string::npos) - {resolutionZ = digi_SpatialResolution->GetFWHM();} - } - - - else if(digi_SpatialResolution->GetFWHMx() || digi_SpatialResolution->GetFWHMy()|| digi_SpatialResolution->GetFWHMz()){ - if(digi_SpatialResolution->GetFWHMx() && m_nameAxis.find('X') != std::string::npos) - {resolutionX = digi_SpatialResolution->GetFWHMx();} - if(digi_SpatialResolution->GetFWHMy() && m_nameAxis.find('Y') != std::string::npos) - {resolutionY = digi_SpatialResolution->GetFWHMy();} +GateVirtualSegmentationSD::~GateVirtualSegmentationSD() +{ + delete m_Messenger; - if(digi_SpatialResolution->GetFWHMz() && m_nameAxis.find('Z') != std::string::npos) - {resolutionZ = digi_SpatialResolution->GetFWHMz();} - } +} - if(resolutionX == 0 && m_nameAxis.find('X') != std::string::npos) - {GateError("***ERROR*** Discretization in X axis has been selected but no value for FWHM was provided."); - } - if(resolutionY == 0 && m_nameAxis.find('Y') != std::string::npos) - {GateError("***ERROR*** Discretization in Y axis has been selected but no value for FWHM was provided."); - } - if(resolutionZ == 0 && m_nameAxis.find('Z') != std::string::npos) - {GateError("***ERROR*** Discretization in Z axis has been selected but no value for FWHM was provided."); - } - /* - else if (m_nameAxis == "XYZ" && (m_resolution==0) || (m_resolutionX==0 || m_resolutionY==0 ||m_resolutionZ==0)) - { - GateError("***ERROR*** Discretization in XYZ has been selected but at least one axis has resolution = 0. Please ensure that all axis have a non zero value of resolution."); - } -*/ - if (true){ - std::string path_to_script = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; - std::string path_to_macros = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; - std::string command = "python3 "+path_to_script+"macro_converter.py"; - command +=" -d "+path_to_macros+"digitizer.mac"; - command +=" -g "+path_to_macros+"geometry_pseudo-crystal.mac"; - int result = system(command.c_str()); - if (result ==0) std::cout<<"The macro converter script has been executed corectly"<GetDigitizer())->GetSystem(); @@ -215,9 +120,9 @@ void GateDiscretizerModule::Digitize() m_systemDepth = m_system->GetTreeDepth(); - //TODO I need to create another parameter asking if spatial resolution is provided by hand. + //TODO I need to create another parameter asking if pitch is provided by hand. //I need to get system, system depth. Check that the size for the last 4 solids is the same (Monolithic crystal) - //Need to access spatial resolution + //Need to access pitch @@ -241,9 +146,6 @@ void GateDiscretizerModule::Digitize() - G4double xLength,yLength,zLength; - - if (IDC) { @@ -266,6 +168,34 @@ void GateDiscretizerModule::Digitize() + if (m_IsFirstEntry){ + + if(pitchX > xLength){ pitchX=xLength; + GateWarning("The size provided for pitchX is bigger than the crystal syze! The length of the crystal has been selected as the new pitchX");} + if(pitchY > yLength){ pitchY=yLength; + GateWarning("The size provided for pitchY is bigger than the crystal syze! The length of the crystal has been selected as the new pitchY");} + if(pitchZ > zLength){ pitchZ=zLength; + GateWarning("The size provided for pitchZ is bigger than the crystal syze! The length of the crystal has been selected as the new pitchX");} + + SetParameters(); + + + if (useMacroGenerator){ + std::string path_to_script = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; + std::string path_to_macros = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; + //Once this is implemented as a GateTool it will be: + //std::string command = "macro_converter"; + std::string command = "python3 "+path_to_script+"macro_converter.py"; + command +=" -d "+path_to_macros+"digitizer.mac"; + command +=" -g "+path_to_macros+"geometry_pseudo-crystal.mac"; + int result = system(command.c_str()); + if (result ==0) std::cout<<"The macro converter script has been executed corectly"<1) @@ -282,80 +212,24 @@ void GateDiscretizerModule::Digitize() m_outputDigi->SetEnergyFin(-1); - -/* - if(m_nameAxis=="XYZ"){ - - pitchX = calculatePitch(xLength,resolutionX); - nBinsX = int(xLength/pitchX); - pitchY = calculatePitch(yLength,resolutionY); - nBinsY = int(yLength/pitchY); - pitchZ = calculatePitch(zLength,resolutionZ); - nBinsZ = int(zLength/pitchZ); - - - G4ThreeVector localPos = inputDigi->GetLocalPos(); - //std::cout<<"Local position = " << localPos <<" nBinsX "<GetLocalPos(); if(m_nameAxis.find('X') != std::string::npos){ - std::cout<<"In X! "<GetOutputVolumeID()<<" Pitches "<1) @@ -370,7 +244,7 @@ void GateDiscretizerModule::Digitize() if (nVerboseLevel==1) { - G4cout << "[GateDiscretizerModule::Digitize]: returning output pulse-list with " << OutputDigiCollectionVector->size() << " entries\n"; + G4cout << "[GateVirtualSegmentationSD::Digitize]: returning output pulse-list with " << OutputDigiCollectionVector->size() << " entries\n"; for (iter=OutputDigiCollectionVector->begin(); iter!= OutputDigiCollectionVector->end() ; ++iter) G4cout << **iter << Gateendl; G4cout << Gateendl; @@ -381,11 +255,12 @@ void GateDiscretizerModule::Digitize() else { if (nVerboseLevel>1) - G4cout << "[GateDiscretizerModule::Digitize]: input digi collection is null -> nothing to do\n\n"; + G4cout << "[GateVirtualSegmentationSD::Digitize]: input digi collection is null -> nothing to do\n\n"; return; } StoreDigiCollection(m_OutputDigiCollection); + } @@ -396,7 +271,7 @@ void GateDiscretizerModule::Digitize() -void GateDiscretizerModule::SetNameAxis(const G4String ¶m) +void GateVirtualSegmentationSD::SetNameAxis(const G4String ¶m) { m_nameAxis=param; } @@ -409,11 +284,11 @@ void GateDiscretizerModule::SetNameAxis(const G4String ¶m) /* -G4double GateDiscretizerModule::calculatePitch(G4double crystal_size, G4double spatial_resolution) { +G4double GateVirtualSegmentationSD::calculatePitch(G4double crystal_size, G4double target_pitch) { // Target pitch size - double target_pitch = spatial_resolution / 2.0; + std::cout<<"Spatial Resolution: "<::max(); @@ -434,9 +309,9 @@ G4double GateDiscretizerModule::calculatePitch(G4double crystal_size, G4double s */ //TODO: This function needs much optimising -G4double GateDiscretizerModule::calculatePitch(G4double crystal_size, G4double spatial_resolution) { +G4double GateVirtualSegmentationSD::calculatePitch(G4double crystal_size, G4double target_pitch) { // Target pitch size - double target_pitch = spatial_resolution / 2.0; + double best_pitch = 0; double min_diff = 999; int num_pitches = 1; @@ -469,8 +344,8 @@ G4double GateDiscretizerModule::calculatePitch(G4double crystal_size, G4double s return best_pitch; } - -void GateDiscretizerModule::SetVirtualIDs( int nBinsX, int nBinsY,int nBinsZ,double pitchX,double pitchY,double pitchZ, G4ThreeVector& pos ){ +/* +void GateVirtualSegmentationSD::SetVirtualIDs( int nBinsX, int nBinsY,int nBinsZ,double pitchX,double pitchY,double pitchZ, G4ThreeVector& pos ){ int binX,binY,binZ; @@ -490,17 +365,16 @@ void GateDiscretizerModule::SetVirtualIDs( int nBinsX, int nBinsY,int nBinsZ,dou } +*/ - -void GateDiscretizerModule::SetVirtualID( int nBins, double pitch, G4double pos , int depth){ +void GateVirtualSegmentationSD::SetVirtualID( int nBins, double pitch, G4double pos , int depth){ int bin; bin = std::floor(pos/pitch+nBins/2.); - std::cout<<"[pitch,nBins,pos,bin, sum] = ["<SetOutputVolumeID(bin,depth); } @@ -508,12 +382,12 @@ void GateDiscretizerModule::SetVirtualID( int nBins, double pitch, G4double pos -void GateDiscretizerModule::DescribeMyself(size_t indent ) +void GateVirtualSegmentationSD::DescribeMyself(size_t indent ) { - if(m_resolution) - G4cout << GateTools::Indent(indent) << "Spatial resolution : " << m_resolution << Gateendl; + if(m_pitch) + G4cout << GateTools::Indent(indent) << "Spatial pitch : " << m_pitch << Gateendl; else - G4cout << GateTools::Indent(indent) << "Spatial resolution : " << m_resolutionX <<" "<< m_resolutionY<< " "<(m_digitizer->FindDigitizerModule("digitizerMgr/" + +m_digitizer->GetSD()->GetName() + +"/SinglesDigitizer/" + + m_digitizer->GetName() + + "/spatialResolution")); + + if(m_pitch){ + if(m_nameAxis.find('X') != std::string::npos) + {pitchX = m_pitch;} + + if(m_nameAxis.find('Y') != std::string::npos) + {pitchY = m_pitch;} + + if(m_nameAxis.find('Z') != std::string::npos) + {pitchZ = m_pitch;} + + + if (m_pitchX!=0 || m_pitchY!=0 ||m_pitchZ!=0) + {GateWarning("The values provided for target pitch are ambiguous. Only the value of 'pitch' was taken, any value provided for 'pitchX', 'pitchY' and 'pitchZ' was ignored");} + } + + else if (m_pitchX!=0 || m_pitchY!=0 ||m_pitchZ!=0){ + + if(m_pitchX && m_nameAxis.find('X') != std::string::npos) + {pitchX = m_pitchX;} + + if(m_pitchY && m_nameAxis.find('Y') != std::string::npos) + {pitchY = m_pitchY;} + + if(m_pitchZ && m_nameAxis.find('Z') != std::string::npos) + {pitchZ = m_pitchZ;} + + } + + else if (digi_SpatialResolution){ + if (digi_SpatialResolution->GetFWHM()) + { + + if(m_nameAxis.find('X') != std::string::npos) + {pitchX = 0.5*digi_SpatialResolution->GetFWHM();} + + if(m_nameAxis.find('Y') != std::string::npos) + {pitchY = 0.5*digi_SpatialResolution->GetFWHM();} + + if(m_nameAxis.find('Z') != std::string::npos) + {pitchZ = 0.5*digi_SpatialResolution->GetFWHM();} + } + + + else if(digi_SpatialResolution->GetFWHMx() || digi_SpatialResolution->GetFWHMy()|| digi_SpatialResolution->GetFWHMz()){ + + + // DO NOT DELETE! + /* + //This is awaiting for Radia's code!!! + if(digi_SpatialResolution->GetFWHMxdistrib()||digi_SpatialResolution->GetFWHMydistrib()||digi_SpatialResolution->GetFWHMxydistrib()) + { + GateError("***ERROR*** No value of the target pitch has been provided and no value can be obtained from the spatial resolution distribution. /n Please provide a value for the pitch that is at least half of the minimum value of the distribution. "); + } + + + */ + + if(digi_SpatialResolution->GetFWHMx() && m_nameAxis.find('X') != std::string::npos) + {pitchX = 0.5*digi_SpatialResolution->GetFWHMx();} + + if(digi_SpatialResolution->GetFWHMy() && m_nameAxis.find('Y') != std::string::npos) + {pitchY = 0.5*digi_SpatialResolution->GetFWHMy();} + + if(digi_SpatialResolution->GetFWHMz() && m_nameAxis.find('Z') != std::string::npos) + {pitchZ = 0.5*digi_SpatialResolution->GetFWHMz();} + } + } + + if(pitchX == 0 && m_nameAxis.find('X') != std::string::npos) + {GateError("***ERROR*** Virtual setmentation in X axis has been selected but no value for FWHM was provided."); + } + else{ + pitchX = calculatePitch(xLength,pitchX); + nBinsX = int(xLength/pitchX); + } + + if(pitchY == 0 && m_nameAxis.find('Y') != std::string::npos) + {GateError("***ERROR*** Virtual setmentation in Y axis has been selected but no value for FWHM was provided."); + } + else{ + pitchY = calculatePitch(yLength,pitchY); + nBinsY = int(yLength/pitchY); + } + + + + if(pitchZ == 0 && m_nameAxis.find('Z') != std::string::npos) + {GateError("***ERROR*** Virtual setmentation in Z axis has been selected but no value for FWHM was provided."); + } + else{ + pitchZ = calculatePitch(zLength,pitchZ); + nBinsZ = int(zLength/pitchZ); + } + + + + + + + if(m_nameAxis.find('X') != std::string::npos){ + depthX=depthX; + if(m_nameAxis.find('Y') != std::string::npos){ + depthY=depthY; + if(m_nameAxis.find('Z') != std::string::npos){ + depthZ=depthZ; + } + } + else if(m_nameAxis.find('Z') != std::string::npos){ + + depthZ+=1; + } + } + else if(m_nameAxis.find('Y') != std::string::npos){ + + depthY+=1; + + if(m_nameAxis.find('Z') != std::string::npos){ + + depthZ+=1; + } + } + else if(m_nameAxis.find('Z') != std::string::npos){ + depthZ+=2; + } + + else GateError("Not entering any of the depths!"); + + + + + +} + + + + + +/* + * + * + * + * + * + + + + if(m_nameAxis.find('X') != std::string::npos){ + + pitchX = calculatePitch(xLength,pitchX); + nBinsX = int(xLength/pitchX); + SetVirtualID(nBinsX,pitchX,localPos.getX(),depthX); + + if(m_nameAxis.find('Y') != std::string::npos){ + + pitchY = calculatePitch(yLength,pitchY); + nBinsY = int(yLength/pitchY); + SetVirtualID(nBinsY,pitchY,localPos.getY(),depthY); + + if(m_nameAxis.find('Z') != std::string::npos){ + + pitchZ = calculatePitch(zLength,pitchZ); + nBinsZ = int(zLength/pitchZ); + SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ); + + } + } + else if(m_nameAxis.find('Z') != std::string::npos){ + + pitchZ = calculatePitch(zLength,pitchZ); + nBinsZ = int(zLength/pitchZ); + SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ+1); + } + } + else if(m_nameAxis.find('Y') != std::string::npos){ + + pitchY = calculatePitch(yLength,pitchY); + nBinsY = int(yLength/pitchY); + SetVirtualID(nBinsY,pitchY,localPos.getY(),depthY+1); + if(m_nameAxis.find('Z') != std::string::npos){ + pitchZ = calculatePitch(zLength,pitchZ); + nBinsZ = int(zLength/pitchZ); + SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ+1); + } + } + else if(m_nameAxis.find('Z') != std::string::npos){ + + pitchZ = calculatePitch(zLength,pitchZ); + nBinsZ = int(zLength/pitchZ); + SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ+2); + } + else GateError("Not entering any of the depths!"); + * + * */ diff --git a/source/digits_hits/src/GateVirtualSegmentationSDMessenger.cc b/source/digits_hits/src/GateVirtualSegmentationSDMessenger.cc new file mode 100644 index 000000000..4e18140d3 --- /dev/null +++ b/source/digits_hits/src/GateVirtualSegmentationSDMessenger.cc @@ -0,0 +1,135 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + +// OK GND 2022 +/*This class is not used by GATE ! + The purpose of this class is to help to create new users digitizer module(DM). + Please, check GateVirtualSegmentationSD.cc for more detals + */ + + + +/*! + \class GateVirtualSegmentationSD (by marc.granado@universite-paris-saclay.fr) + \brief for discretizing the position through a virtual segmentation of a monolithic crystal + + - For each volume the local position of the interactions within the crystal are virtually segmented. + the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal + occupying the levels of SubmoduleID, CrystalID and LayerID. +*/ + + +#include "GateVirtualSegmentationSDMessenger.hh" +#include "GateVirtualSegmentationSD.hh" +#include "GateDigitizerMgr.hh" + +#include "G4SystemOfUnits.hh" +#include "G4UIcmdWithADouble.hh" +#include "G4UIcmdWithADoubleAndUnit.hh" +#include "G4UIcmdWithABool.hh" +#include "G4UIcmdWithAString.hh" +#include "G4UIdirectory.hh" + + + +GateVirtualSegmentationSDMessenger::GateVirtualSegmentationSDMessenger (GateVirtualSegmentationSD* VirtualSegmentationSD) +:GateClockDependentMessenger(VirtualSegmentationSD), + m_VirtualSegmentationSD(VirtualSegmentationSD) +{ + G4String guidance; + G4String cmdName; + + + cmdName = GetDirectoryName()+"nameAxis"; + nameAxisCmd = new G4UIcmdWithAString(cmdName,this); + nameAxisCmd ->SetGuidance("Provide the number of axis that need to be virtually segmented, XYZ, XY, XZ, or YZ"); + nameAxisCmd ->SetCandidates("XYZ XY XZ YZ"); + + cmdName = GetDirectoryName() + "useMacroGenerator"; + useMacroGeneratorCmd = new G4UIcmdWithABool(cmdName,this); + useMacroGeneratorCmd->SetGuidance("To be set true, if there is a need to create a new geometry macro for CASToR"); + + + cmdName = GetDirectoryName() + "pitch"; + pitchCmd = new G4UIcmdWithADoubleAndUnit(cmdName,this);//new G4UIcmdWithADouble(cmdName,this); + pitchCmd->SetGuidance("Set the size of the pitch for all the selected dimensions"); + + + + cmdName = GetDirectoryName()+"pitchX"; + pitchXCmd = new G4UIcmdWithADoubleAndUnit(cmdName,this);//new G4UIcmdWithADouble(cmdName,this); + pitchXCmd->SetGuidance("Set the size of the pitch for the X dimension"); + + cmdName = GetDirectoryName()+"pitchY"; + pitchYCmd = new G4UIcmdWithADoubleAndUnit(cmdName,this);//new G4UIcmdWithADouble(cmdName,this); + pitchYCmd->SetGuidance("Set the size of the pitch for the Y dimension"); + + cmdName = GetDirectoryName()+"pitchZ"; + pitchZCmd = new G4UIcmdWithADoubleAndUnit(cmdName,this);//new G4UIcmdWithADouble(cmdName,this); + pitchZCmd->SetGuidance("Set the size of the pitch for the Z dimension"); + +} + + +GateVirtualSegmentationSDMessenger::~GateVirtualSegmentationSDMessenger() +{ + delete nameAxisCmd; + delete useMacroGeneratorCmd; + delete pitchCmd; + delete pitchXCmd; + delete pitchYCmd; + delete pitchZCmd; +} + + +void GateVirtualSegmentationSDMessenger::SetNewValue(G4UIcommand * aCommand,G4String newValue) +{ + + if (aCommand == nameAxisCmd) + { + m_VirtualSegmentationSD->SetNameAxis(newValue); + } + + else if (aCommand == pitchCmd) + { + m_VirtualSegmentationSD->SetPitch(pitchCmd->GetNewDoubleValue(newValue)); + } + else if (aCommand == pitchXCmd) + { + m_VirtualSegmentationSD->SetPitchX(pitchCmd->GetNewDoubleValue(newValue)); + + } + + else if (aCommand == pitchYCmd) + { + m_VirtualSegmentationSD->SetPitchY(pitchCmd->GetNewDoubleValue(newValue)); + } + else if (aCommand == pitchZCmd) + { + m_VirtualSegmentationSD->SetPitchZ(pitchCmd->GetNewDoubleValue(newValue)); + } + else if ( aCommand==useMacroGeneratorCmd ) + { m_VirtualSegmentationSD->SetUseMacroGenerator(useMacroGeneratorCmd->GetNewBoolValue(newValue)); } + else + { + GateClockDependentMessenger::SetNewValue(aCommand,newValue); + } +} + + + + + + + + + + + + + From fdb99e031500daa1ea2b9f9cfeb52b51900b05fe Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Sat, 13 Jul 2024 10:37:30 +0200 Subject: [PATCH 27/96] Clean up of the code, flexibility for the axis and command for the macro generator. --- .../include/GateVirtualSegmentationSD.hh | 5 ++-- .../src/GateSinglesDigitizerMessenger.cc | 2 +- .../src/GateVirtualSegmentationSD.cc | 29 +++++++++++++++---- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/source/digits_hits/include/GateVirtualSegmentationSD.hh b/source/digits_hits/include/GateVirtualSegmentationSD.hh index 3ac1e3f3b..005154d50 100644 --- a/source/digits_hits/include/GateVirtualSegmentationSD.hh +++ b/source/digits_hits/include/GateVirtualSegmentationSD.hh @@ -14,8 +14,9 @@ See LICENSE.md for further details /*! \class GateVirtualSegmentationSD - \brief GateVirtualSegmentationSD does some dummy things with input digi - to create output digi + \brief GateVirtualSegmentationSD - For each volume the local position of the interactions within the crystal are virtually segmented. + the X,Y,Z vector is translated into the IDs of virtual divisions within the crystal + - GateVirtualSegmentationSD - by marc.granado@universite-paris-saclay.fr diff --git a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc index 80e0b25e0..b603cd077 100755 --- a/source/digits_hits/src/GateSinglesDigitizerMessenger.cc +++ b/source/digits_hits/src/GateSinglesDigitizerMessenger.cc @@ -9,7 +9,7 @@ See LICENSE.md for further details /*! \class GateSinglesDigitizerMessenger - Last modification (Adaptation to GND): May 2023 by Mohamed-Jordan Soumano mjsoumano@yahoo.com + Last modification (Adaptation to GND): July 2024 by Marc Granado-Gonzalez marc.granado@universite-paris-saclay.fr */ #include "GateSinglesDigitizer.hh" diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index 20a00743b..5c1a422cd 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -188,6 +188,15 @@ void GateVirtualSegmentationSD::Digitize() std::string command = "python3 "+path_to_script+"macro_converter.py"; command +=" -d "+path_to_macros+"digitizer.mac"; command +=" -g "+path_to_macros+"geometry_pseudo-crystal.mac"; + + if (pitchX) command +=" -x "+std::to_string(pitchX); + if (pitchY) command +=" -y "+std::to_string(pitchY); + if (pitchZ) command +=" -z "+std::to_string(pitchZ); + + if (nBinsX) command +=" --binsX "+std::to_string(nBinsX); + if (nBinsY) command +=" --binsY "+std::to_string(nBinsY); + if (nBinsZ) command +=" --binsZ "+std::to_string(nBinsZ); + int result = system(command.c_str()); if (result ==0) std::cout<<"The macro converter script has been executed corectly"<1000){ - std::cout<<"ERROR! No pitch found in 1000 iterations!"< Date: Tue, 9 Jul 2024 15:58:11 +0200 Subject: [PATCH 31/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index f5c19b4ef..594eab0ab 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1779,7 +1779,7 @@ The Virtual Segmentation Digitizer module provides a mechanism to generate an ID A GateTool associated with this digitizer allows users to create a new geometry macro with the segmented geometry, suitable for use in image reconstruction software. *Key Features* -^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~ Discretization Control: The digitizer includes commands that enable users to specify which axes require discretization. From cf56b2b90a15658aff25585708d2e210c796aff8 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 9 Jul 2024 16:01:27 +0200 Subject: [PATCH 32/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 594eab0ab..665c06b5e 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1769,7 +1769,7 @@ Finally, we call the 'triCoincProcessor' module and we plug on it the second sys Virtual segmentation -"""""""""""" +~~~~~~~~~~~~~~~~~~~~~~~ In traditional PET image reconstruction, software like CASToR utilizes crystal IDs instead of the position of the interaction. This approach has sufficed due to the spatial resolution being inherently defined by the size of the small crystals used. However, new PET scanner systems are exploring the use of monolithic crystals, which can reconstruct interaction positions within the crystal with a specific resolution. From 1e4ffd0e4659c50c296cf13c26e99ad5896ef5f1 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 9 Jul 2024 16:33:38 +0200 Subject: [PATCH 33/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 84 ++++++++++++++---------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 665c06b5e..6b0b2637f 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1159,6 +1159,54 @@ Example:: /gate/digitizerMgr/absorber/SinglesDigitizer/Singles/multipleRejection/setEventRejection 1 + + + + + + +Virtual segmentation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +In traditional PET image reconstruction, software like CASToR utilizes crystal IDs instead of the position of the interaction. This approach has sufficed due to the spatial resolution being inherently defined by the size of the small crystals used. However, new PET scanner systems are exploring the use of monolithic crystals, which can reconstruct interaction positions within the crystal with a specific resolution. + +The Virtual Segmentation Digitizer module provides a mechanism to generate an ID based on a virtual segmentation of the monolithic crystal, aligned with its spatial resolution. Ideally, the pitch size should be at least half of the position resolution. This virtual segmentation occurs post-simulation, ensuring that the simulation speed remains uncompromised even when dealing with large systems and numerous crystals. + +A GateTool associated with this digitizer allows users to create a new geometry macro with the segmented geometry, suitable for use in image reconstruction software. + +**Key Features** + + +Discretization Control: The digitizer includes commands that enable users to specify which axes require discretization. + +**Geometry Requirements:** + +To utilize this digitizer, the cylindricalPET geometry must be configured as follows: +The size of the crystal should be defined at the Submodule level using Air as the material. +The crystal and layer0 levels should both reflect the crystal size and use the crystal's material. +This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Crystal, and Submodule levels, respectively. +**Commands** + +pitch, pitchX, pitchY, pitchZ: These commands allow users to specify the desired pitch size. If no pitch size is provided, the digitizer will use the spatial resolution value to compute the optimal pitch size. The number of bins, defined as (crystal size)/(pitch), must be an integer. Note that the spatial resolution must be a single value; if only a distribution is provided, the digitizer will not function correctly. + +Example:: + +/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/insert virtualSegmentation + +/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ + +/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/pitch 5.0 mm + + + + + + + + + + .. _digitizer_multiple_processor_chains-label: Examples of multiple Single Digitizers @@ -1766,39 +1814,3 @@ Finally, we call the 'triCoincProcessor' module and we plug on it the second sys /gate/digitizer/TriCoinc/triCoincProcessor/setSinglesBufferSize 40 - - -Virtual segmentation -~~~~~~~~~~~~~~~~~~~~~~~ - - -In traditional PET image reconstruction, software like CASToR utilizes crystal IDs instead of the position of the interaction. This approach has sufficed due to the spatial resolution being inherently defined by the size of the small crystals used. However, new PET scanner systems are exploring the use of monolithic crystals, which can reconstruct interaction positions within the crystal with a specific resolution. - -The Virtual Segmentation Digitizer module provides a mechanism to generate an ID based on a virtual segmentation of the monolithic crystal, aligned with its spatial resolution. Ideally, the pitch size should be at least half of the position resolution. This virtual segmentation occurs post-simulation, ensuring that the simulation speed remains uncompromised even when dealing with large systems and numerous crystals. - -A GateTool associated with this digitizer allows users to create a new geometry macro with the segmented geometry, suitable for use in image reconstruction software. - -*Key Features* -~~~~~~~~~~~~~~~~~~~~~~~ - -Discretization Control: The digitizer includes commands that enable users to specify which axes require discretization. - -*Geometry Requirements:* -~~~~~~~~~~~~~~~~~~~~~~~ -To utilize this digitizer, the cylindricalPET geometry must be configured as follows: -The size of the crystal should be defined at the Submodule level using Air as the material. -The crystal and layer0 levels should both reflect the crystal size and use the crystal's material. -This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Crystal, and Submodule levels, respectively. -*Commands* -~~~~~~~~~~ -pitch, pitchX, pitchY, pitchZ: These commands allow users to specify the desired pitch size. If no pitch size is provided, the digitizer will use the spatial resolution value to compute the optimal pitch size. The number of bins, defined as (crystal size)/(pitch), must be an integer. Note that the spatial resolution must be a single value; if only a distribution is provided, the digitizer will not function correctly. - -*Example Usage* -~~~~~~~~~~~~~~~ -gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/insert virtualSegmentation - -/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ - -/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/pitch 5.0 mm - - From fae00af52e1dd992dd8fd5aed5c8df022e7d932d Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 9 Jul 2024 16:35:34 +0200 Subject: [PATCH 34/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 6b0b2637f..1d58362d6 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1193,9 +1193,7 @@ pitch, pitchX, pitchY, pitchZ: These commands allow users to specify the desired Example:: /gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/insert virtualSegmentation - /gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ - /gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/pitch 5.0 mm From 14c0e95be4afcf3fdd22f4402605752cd3da47d9 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 9 Jul 2024 16:39:14 +0200 Subject: [PATCH 35/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 1d58362d6..1492401e7 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1192,9 +1192,9 @@ pitch, pitchX, pitchY, pitchZ: These commands allow users to specify the desired Example:: -/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/insert virtualSegmentation -/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ -/gate/digitizerMgr/pseudo-crystal/SinglesDigitizer/Singles/virtualSegmentation/pitch 5.0 mm +/gate/digitizerMgr//SinglesDigitizer/Singles/insert virtualSegmentation +/gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ +/gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/pitch 5.0 mm From d2e2131d501d475f886de57d34864668846129a7 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 9 Jul 2024 16:44:47 +0200 Subject: [PATCH 36/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 1492401e7..26331b7ee 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1175,11 +1175,6 @@ The Virtual Segmentation Digitizer module provides a mechanism to generate an ID A GateTool associated with this digitizer allows users to create a new geometry macro with the segmented geometry, suitable for use in image reconstruction software. -**Key Features** - - -Discretization Control: The digitizer includes commands that enable users to specify which axes require discretization. - **Geometry Requirements:** To utilize this digitizer, the cylindricalPET geometry must be configured as follows: @@ -1187,14 +1182,18 @@ The size of the crystal should be defined at the Submodule level using Air as th The crystal and layer0 levels should both reflect the crystal size and use the crystal's material. This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Crystal, and Submodule levels, respectively. **Commands** +Discretization Control: The digitizer includes commands that enable users to specify which axes require discretization. With "nameAxis". -pitch, pitchX, pitchY, pitchZ: These commands allow users to specify the desired pitch size. If no pitch size is provided, the digitizer will use the spatial resolution value to compute the optimal pitch size. The number of bins, defined as (crystal size)/(pitch), must be an integer. Note that the spatial resolution must be a single value; if only a distribution is provided, the digitizer will not function correctly. +The commands "pitch, pitchX, pitchY, pitchZ" allow users to specify the desired pitch size for all axis, or specific values for X,Y and Z axis. If no pitch size is provided, the digitizer will use the spatial resolution value to compute the optimal pitch size ensuring that the number of bins, defined as (crystal size)/(pitch), is integer. Note that the spatial resolution must be a single value for each axis; if a the spatial resolution is defined with a distribution and no pitch value is provided, the digitizer will not function correctly. Example:: /gate/digitizerMgr//SinglesDigitizer/Singles/insert virtualSegmentation /gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ /gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/pitch 5.0 mm +/gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/useMacroGenerator true + + From 2dedb2863eafd3226039c45b6e8be626b185124b Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 9 Jul 2024 16:47:55 +0200 Subject: [PATCH 37/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 26331b7ee..4f296e484 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1182,6 +1182,7 @@ The size of the crystal should be defined at the Submodule level using Air as th The crystal and layer0 levels should both reflect the crystal size and use the crystal's material. This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Crystal, and Submodule levels, respectively. **Commands** + Discretization Control: The digitizer includes commands that enable users to specify which axes require discretization. With "nameAxis". The commands "pitch, pitchX, pitchY, pitchZ" allow users to specify the desired pitch size for all axis, or specific values for X,Y and Z axis. If no pitch size is provided, the digitizer will use the spatial resolution value to compute the optimal pitch size ensuring that the number of bins, defined as (crystal size)/(pitch), is integer. Note that the spatial resolution must be a single value for each axis; if a the spatial resolution is defined with a distribution and no pitch value is provided, the digitizer will not function correctly. From 129379a42510314575ea20b1fc80c0cdbb73933f Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 9 Jul 2024 17:00:09 +0200 Subject: [PATCH 38/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 4f296e484..a3c78e4a7 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1181,11 +1181,14 @@ To utilize this digitizer, the cylindricalPET geometry must be configured as fol The size of the crystal should be defined at the Submodule level using Air as the material. The crystal and layer0 levels should both reflect the crystal size and use the crystal's material. This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Crystal, and Submodule levels, respectively. + **Commands** -Discretization Control: The digitizer includes commands that enable users to specify which axes require discretization. With "nameAxis". +*"nameAxis"* Enable users to specify which axes require discretization. The axis selected can be any combination of "XYZ", "XY", "XZ" or "YZ", "X", "Y" or "Z". + +*"pitch, pitchX, pitchY, pitchZ"* allow users to specify the desired pitch size for all axis, or specific values for X,Y and Z axis. If no pitch size is provided, the digitizer will use the spatial resolution value to compute the optimal pitch size ensuring that the number of bins, defined as (crystal size)/(pitch), is integer. Note that the spatial resolution must be a single value for each axis; if a the spatial resolution is defined with a distribution and no pitch value is provided, the digitizer will not function correctly. -The commands "pitch, pitchX, pitchY, pitchZ" allow users to specify the desired pitch size for all axis, or specific values for X,Y and Z axis. If no pitch size is provided, the digitizer will use the spatial resolution value to compute the optimal pitch size ensuring that the number of bins, defined as (crystal size)/(pitch), is integer. Note that the spatial resolution must be a single value for each axis; if a the spatial resolution is defined with a distribution and no pitch value is provided, the digitizer will not function correctly. +*"useMacroGenerator"* boolean flag that determines if the user wants to generate the new geometry macro with the segmentation. Example:: From 1422a40cabab32ffc53ec12a79861f33f15ee49f Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Wed, 10 Jul 2024 10:06:32 +0200 Subject: [PATCH 39/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index a3c78e4a7..719a4bfb6 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1190,13 +1190,29 @@ This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, *"useMacroGenerator"* boolean flag that determines if the user wants to generate the new geometry macro with the segmentation. -Example:: + + + +Example providing spatial resolution:: + +/gate/digitizerMgr//SinglesDigitizer/Singles/insert spatialResolution +/gate/digitizerMgr//SinglesDigitizer/Singles/spatialResolution/fwhm 2. mm + +/gate/digitizerMgr//SinglesDigitizer/Singles/insert virtualSegmentation +/gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ +/gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/useMacroGenerator true + +In this case, a value for the FWHM for the spatial resolution was provided but no pitch size was given to the virtual segmentation. The module will read the value of spatial resolution and will generate a pitch size that is, at least, half of the value of the FWHM in spatial resolution. + + +Example providing the pitch:: /gate/digitizerMgr//SinglesDigitizer/Singles/insert virtualSegmentation /gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ -/gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/pitch 5.0 mm +/gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/pitch 1.0 mm /gate/digitizerMgr//SinglesDigitizer/Singles/virtualSegmentation/useMacroGenerator true +In this case, the pitch size is provided by the user and it will be used regardless of any values of FWHM provided in the spatial resolution module. From 05403febcbbc84b1a6d0d4a13d3cada06f3a34aa Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Wed, 10 Jul 2024 11:12:26 +0200 Subject: [PATCH 40/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 719a4bfb6..d7f6dd41c 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1169,9 +1169,9 @@ Virtual segmentation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In traditional PET image reconstruction, software like CASToR utilizes crystal IDs instead of the position of the interaction. This approach has sufficed due to the spatial resolution being inherently defined by the size of the small crystals used. However, new PET scanner systems are exploring the use of monolithic crystals, which can reconstruct interaction positions within the crystal with a specific resolution. +In traditional PET image reconstruction, software like CASToR utilizes crystal IDs instead of the position of the interaction. This approach has sufficed because the small crystals' size inherently defines the spatial resolution. However, new PET scanner systems are exploring the use of monolithic crystals, which can reconstruct interaction positions within the crystal with a specific resolution. -The Virtual Segmentation Digitizer module provides a mechanism to generate an ID based on a virtual segmentation of the monolithic crystal, aligned with its spatial resolution. Ideally, the pitch size should be at least half of the position resolution. This virtual segmentation occurs post-simulation, ensuring that the simulation speed remains uncompromised even when dealing with large systems and numerous crystals. +The Virtual Segmentation Digitizer module provides a mechanism to generate an ID based on a virtual segmentation of the monolithic crystal, aligned with its spatial resolution. Ideally, the pitch size should be at least half of the position resolution. This virtual segmentation occurs post-simulation, ensuring that the simulation speed remains uncompromised even when dealing with large systems and numerous crystals such as total-body PET scans. A GateTool associated with this digitizer allows users to create a new geometry macro with the segmented geometry, suitable for use in image reconstruction software. From a50e7ac7ef1f518acc27a7a531254d163bf7a6d0 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Fri, 12 Jul 2024 16:00:10 +0200 Subject: [PATCH 41/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index d7f6dd41c..e02d62131 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1182,6 +1182,43 @@ The size of the crystal should be defined at the Submodule level using Air as th The crystal and layer0 levels should both reflect the crystal size and use the crystal's material. This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Crystal, and Submodule levels, respectively. +Example:: + +# C R Y S T A L +/gate/rsector/daughters/name crystal +/gate/rsector/daughters/insert box +/gate/crystal/geometry/setXLength 10. mm +/gate/crystal/geometry/setYLength 59. mm +/gate/crystal/geometry/setZLength 59. mm +/gate/crystal/setMaterial Air + +# COLUMN + +/gate/crystal/daughters/name column +/gate/crystal/daughters/insert box +/gate/column/geometry/setXLength 10. mm +/gate/column/geometry/setYLength 59. mm +/gate/column/geometry/setZLength 59. mm +/gate/column/setMaterial Air + + +#ROW +/gate/column/daughters/name row +/gate/column/daughters/insert box +/gate/row/geometry/setXLength 10. mm +/gate/row/geometry/setYLength 59. mm +/gate/row/geometry/setZLength 59. mm +/gate/row/setMaterial Air + +#Pseudo-Crystal +/gate/row/daughters/name pseudo-crystal +/gate/row/daughters/insert box +/gate/pseudo-crystal/geometry/setXLength 10. mm +/gate/pseudo-crystal/geometry/setYLength 59. mm +/gate/pseudo-crystal/geometry/setZLength 59. mm +/gate/pseudo-crystal/setMaterial PWO + + **Commands** *"nameAxis"* Enable users to specify which axes require discretization. The axis selected can be any combination of "XYZ", "XY", "XZ" or "YZ", "X", "Y" or "Z". From fb891feff1c5da1c4f15bb23ee7f77bbe7bc52bc Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Fri, 12 Jul 2024 16:01:02 +0200 Subject: [PATCH 42/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 66 ++++++++++++------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index e02d62131..f41c8a8aa 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1184,39 +1184,39 @@ This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Example:: -# C R Y S T A L -/gate/rsector/daughters/name crystal -/gate/rsector/daughters/insert box -/gate/crystal/geometry/setXLength 10. mm -/gate/crystal/geometry/setYLength 59. mm -/gate/crystal/geometry/setZLength 59. mm -/gate/crystal/setMaterial Air - -# COLUMN - -/gate/crystal/daughters/name column -/gate/crystal/daughters/insert box -/gate/column/geometry/setXLength 10. mm -/gate/column/geometry/setYLength 59. mm -/gate/column/geometry/setZLength 59. mm -/gate/column/setMaterial Air - - -#ROW -/gate/column/daughters/name row -/gate/column/daughters/insert box -/gate/row/geometry/setXLength 10. mm -/gate/row/geometry/setYLength 59. mm -/gate/row/geometry/setZLength 59. mm -/gate/row/setMaterial Air - -#Pseudo-Crystal -/gate/row/daughters/name pseudo-crystal -/gate/row/daughters/insert box -/gate/pseudo-crystal/geometry/setXLength 10. mm -/gate/pseudo-crystal/geometry/setYLength 59. mm -/gate/pseudo-crystal/geometry/setZLength 59. mm -/gate/pseudo-crystal/setMaterial PWO + # C R Y S T A L + /gate/rsector/daughters/name crystal + /gate/rsector/daughters/insert box + /gate/crystal/geometry/setXLength 10. mm + /gate/crystal/geometry/setYLength 59. mm + /gate/crystal/geometry/setZLength 59. mm + /gate/crystal/setMaterial Air + + # COLUMN + + /gate/crystal/daughters/name column + /gate/crystal/daughters/insert box + /gate/column/geometry/setXLength 10. mm + /gate/column/geometry/setYLength 59. mm + /gate/column/geometry/setZLength 59. mm + /gate/column/setMaterial Air + + + #ROW + /gate/column/daughters/name row + /gate/column/daughters/insert box + /gate/row/geometry/setXLength 10. mm + /gate/row/geometry/setYLength 59. mm + /gate/row/geometry/setZLength 59. mm + /gate/row/setMaterial Air + + #Pseudo-Crystal + /gate/row/daughters/name pseudo-crystal + /gate/row/daughters/insert box + /gate/pseudo-crystal/geometry/setXLength 10. mm + /gate/pseudo-crystal/geometry/setYLength 59. mm + /gate/pseudo-crystal/geometry/setZLength 59. mm + /gate/pseudo-crystal/setMaterial PWO **Commands** From d4e038a69b783b4f31de8a5f119754271ad24e4f Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Fri, 12 Jul 2024 16:02:47 +0200 Subject: [PATCH 43/96] Update digitizer_and_detector_modeling.rst --- docs/digitizer_and_detector_modeling.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index f41c8a8aa..fdcab29e0 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -1184,7 +1184,7 @@ This setup allows new virtual IDs for the XYZ axes to be assigned at the Layer, Example:: - # C R Y S T A L + # CRYSTAL /gate/rsector/daughters/name crystal /gate/rsector/daughters/insert box /gate/crystal/geometry/setXLength 10. mm @@ -1192,8 +1192,7 @@ Example:: /gate/crystal/geometry/setZLength 59. mm /gate/crystal/setMaterial Air - # COLUMN - + # Level saved for the virtual COLUMN /gate/crystal/daughters/name column /gate/crystal/daughters/insert box /gate/column/geometry/setXLength 10. mm @@ -1202,7 +1201,7 @@ Example:: /gate/column/setMaterial Air - #ROW + #Level saved for the virtual ROW /gate/column/daughters/name row /gate/column/daughters/insert box /gate/row/geometry/setXLength 10. mm @@ -1210,7 +1209,7 @@ Example:: /gate/row/geometry/setZLength 59. mm /gate/row/setMaterial Air - #Pseudo-Crystal + #Level saved for the virtual Pseudo-Crystal (now the real material needs to be used) /gate/row/daughters/name pseudo-crystal /gate/row/daughters/insert box /gate/pseudo-crystal/geometry/setXLength 10. mm From dc8ba9045689e912fae63d4fe12aaba9b6bb05cc Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Wed, 24 Jul 2024 11:19:45 +0200 Subject: [PATCH 44/96] Addition of the test for the needed free depths and comments modified: source/digits_hits/src/GateVirtualSegmentationSD.cc --- .../src/GateVirtualSegmentationSD.cc | 156 +++++------------- 1 file changed, 45 insertions(+), 111 deletions(-) diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index 5c1a422cd..6895d6303 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -26,7 +26,7 @@ #include "GateSpatialResolution.hh" #include "GateSpatialResolutionMessenger.hh" - +#include "GateBoxComponent.hh" #include "GateDigitizerMgr.hh" @@ -104,15 +104,14 @@ GateVirtualSegmentationSD::~GateVirtualSegmentationSD() void GateVirtualSegmentationSD::Digitize() { - //TODO Create the check that tells you that GateVSystem* m_system = ((GateSinglesDigitizer*)this->GetDigitizer())->GetSystem(); - if (m_system==NULL) G4Exception( "GateSpatialResolution::Digitize", "Digitize", FatalException, + if (m_system==NULL) G4Exception( "GateVirtualSegmentationSD::Digitize", "Digitize", FatalException, "Failed to get the system corresponding to that digitizer. Abort.\n"); if (!m_system->CheckIfEnoughLevelsAreDefined()) { - GateError( " *** ERROR*** GateSpatialResolution::Digitize. Not all defined geometry levels has their mother levels defined." + GateError( " *** ERROR*** GateVirtualSegmentationSD::Digitize. Not all defined geometry levels has their mother levels defined." "(Ex.: for cylindricalPET, the levels are: rsector, module, submodule, crystal). If you have defined submodule, you have to have resector and module defined as well." "Please, add them to your geometry macro in /gate/systems/cylindricalPET/XXX/attach YYY. Abort.\n"); } @@ -120,11 +119,6 @@ void GateVirtualSegmentationSD::Digitize() m_systemDepth = m_system->GetTreeDepth(); - //TODO I need to create another parameter asking if pitch is provided by hand. - //I need to get system, system depth. Check that the size for the last 4 solids is the same (Monolithic crystal) - //Need to access pitch - - G4String digitizerName = m_digitizer->m_digitizerName; G4String outputCollName = m_digitizer-> GetOutputName(); @@ -139,8 +133,6 @@ void GateVirtualSegmentationSD::Digitize() IDC = (GateDigiCollection*) (DigiMan->GetDigiCollection(m_DCID)); GateDigi* inputDigi; - - //What about these lines? Why are they not in SpatialResolution? Apparetnly std::vector< GateDigi* >* OutputDigiCollectionVector = m_OutputDigiCollection->GetVector (); std::vector::iterator iter; @@ -163,7 +155,7 @@ void GateVirtualSegmentationSD::Digitize() yLength = 2*box->GetYHalfLength(); zLength = 2*box->GetZHalfLength(); } - else std::cout<<"Well that's another problem here..."<< std::endl; + else GateError( " *** ERROR*** No volumeID in inputDigi!"); @@ -180,7 +172,9 @@ void GateVirtualSegmentationSD::Digitize() SetParameters(); + if (useMacroGenerator){ + /* std::string path_to_script = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; std::string path_to_macros = "/home/granado/GATE_projects/MonoCrystals/tests/mac/"; //Once this is implemented as a GateTool it will be: @@ -200,6 +194,8 @@ void GateVirtualSegmentationSD::Digitize() int result = system(command.c_str()); if (result ==0) std::cout<<"The macro converter script has been executed corectly"<SetEnergyFin(-1); - G4ThreeVector localPos = inputDigi->GetLocalPos(); - + //Accessing the local position of the hit to define and set the new VirtualID + G4ThreeVector localPos = inputDigi->GetLocalPos(); if(m_nameAxis.find('X') != std::string::npos){ SetVirtualID(nBinsX,pitchX,localPos.getX(),depthX); @@ -291,33 +287,8 @@ void GateVirtualSegmentationSD::SetNameAxis(const G4String ¶m) /////////////////////////////////////////// +//TODO: This function could be further optimised (but only used once) -/* -G4double GateVirtualSegmentationSD::calculatePitch(G4double crystal_size, G4double target_pitch) { - - - // Target pitch size - - std::cout<<"Spatial Resolution: "<::max(); - - // Iterate to find the best pitch size - for (int num_pitches = 1; num_pitches <= crystal_size; ++num_pitches) { - double pitch = crystal_size / num_pitches; - if (std::fabs(pitch - target_pitch) < min_diff && std::fmod(crystal_size, pitch) == 0) { - min_diff = std::fabs(pitch - target_pitch); - best_pitch = pitch; - } - } - - std::cout<<"Best pitch is: "<SetOutputVolumeID(binZ,3); - m_outputDigi->SetOutputVolumeID(binY,4); - m_outputDigi->SetOutputVolumeID(binX,5); - - - } -*/ @@ -410,13 +359,23 @@ void GateVirtualSegmentationSD::SetParameters() { + + //Setting the global parameters + + + + //Obtaining the spatial resolution digitizer to use the its values for the definition of the pitch in case no pitch has been provided by the user GateSpatialResolution* digi_SpatialResolution; digi_SpatialResolution = dynamic_cast(m_digitizer->FindDigitizerModule("digitizerMgr/" +m_digitizer->GetSD()->GetName() +"/SinglesDigitizer/" + m_digitizer->GetName() + + "/spatialResolution")); + + //Setting the pitch size provided by the user + if(m_pitch){ if(m_nameAxis.find('X') != std::string::npos) {pitchX = m_pitch;} @@ -522,7 +481,7 @@ void GateVirtualSegmentationSD::SetParameters() - + //setting the levels of depth for each variable from bottom to top in order XYZ if(m_nameAxis.find('X') != std::string::npos){ depthX=depthX; @@ -556,73 +515,48 @@ void GateVirtualSegmentationSD::SetParameters() -} - + //Testing there are no repeaters in the depth levels needed for the virtual ID's. + GateVSystem* m_system = ((GateSinglesDigitizer*)this->GetDigitizer())->GetSystem(); + GateSystemComponent* m_submoduleComponent = m_system->FindComponent("submodule"); + GateSystemComponent* m_crystalComponent = m_system->FindComponent("crystal"); + GateSystemComponent* m_layer0Component= m_system->FindComponent("layer0"); + std::cout<<"System depth is: "< GetVolumeNumber(); + if (repeaterNumber > 1) + GateError( " *** ERROR*** GateVirtualSegmentationSD::Digitize. Crystal level needs to be empty (no repeaters) to use VirtualSegmentationSD with XYZ segmentation"); - if(m_nameAxis.find('X') != std::string::npos){ - pitchX = calculatePitch(xLength,pitchX); - nBinsX = int(xLength/pitchX); - SetVirtualID(nBinsX,pitchX,localPos.getX(),depthX); - if(m_nameAxis.find('Y') != std::string::npos){ + if (m_nameAxis.size()>=2) + { + repeaterNumber = m_crystalComponent-> GetVolumeNumber(); + if (repeaterNumber > 1) + GateError( " *** ERROR*** GateVirtualSegmentationSD::Digitize. Crystal level needs to be empty (no repeaters) to use VirtualSegmentationSD with XYZ segmentation"); - pitchY = calculatePitch(yLength,pitchY); - nBinsY = int(yLength/pitchY); - SetVirtualID(nBinsY,pitchY,localPos.getY(),depthY); + } - if(m_nameAxis.find('Z') != std::string::npos){ - pitchZ = calculatePitch(zLength,pitchZ); - nBinsZ = int(zLength/pitchZ); - SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ); - } - } - else if(m_nameAxis.find('Z') != std::string::npos){ - pitchZ = calculatePitch(zLength,pitchZ); - nBinsZ = int(zLength/pitchZ); - SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ+1); - } - } - else if(m_nameAxis.find('Y') != std::string::npos){ + if (m_nameAxis.size()==3) + { + repeaterNumber = m_submoduleComponent-> GetVolumeNumber(); + if (repeaterNumber >1) + GateError( " *** ERROR*** GateVirtualSegmentationSD::Digitize. Submodule level needs to be empty (no repeaters) to use VirtualSegmentationSD with XYZ segmentation"); - pitchY = calculatePitch(yLength,pitchY); - nBinsY = int(yLength/pitchY); - SetVirtualID(nBinsY,pitchY,localPos.getY(),depthY+1); + } - if(m_nameAxis.find('Z') != std::string::npos){ - - pitchZ = calculatePitch(zLength,pitchZ); - nBinsZ = int(zLength/pitchZ); - SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ+1); - } - } - else if(m_nameAxis.find('Z') != std::string::npos){ - - pitchZ = calculatePitch(zLength,pitchZ); - nBinsZ = int(zLength/pitchZ); - SetVirtualID(nBinsZ,pitchZ,localPos.getZ(),depthZ+2); - } +} - else GateError("Not entering any of the depths!"); - * - * */ From 718e6905ef664a9a4c11c1506fce0628df8d6632 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Wed, 18 Sep 2024 12:52:08 +0200 Subject: [PATCH 45/96] Cleanup GateSpatialResolution changes modified: source/digits_hits/include/GateSpatialResolution.hh modified: source/digits_hits/src/GateSpatialResolution.cc --- .../digits_hits/include/GateSpatialResolution.hh | 16 ++++++++-------- source/digits_hits/src/GateSpatialResolution.cc | 9 --------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/source/digits_hits/include/GateSpatialResolution.hh b/source/digits_hits/include/GateSpatialResolution.hh index 1baac6d3e..778ca3afa 100644 --- a/source/digits_hits/include/GateSpatialResolution.hh +++ b/source/digits_hits/include/GateSpatialResolution.hh @@ -46,14 +46,14 @@ public: //! These functions return the resolution in use. - G4double GetFWHM() { return m_fwhm; } - GateVDistribution* GetFWHMxdistrib() { return m_fwhmXdistrib; } - GateVDistribution* GetFWHMydistrib() { return m_fwhmYdistrib; } - GateVDistribution* GetFWHMxydistrib2D() { return m_fwhmXYdistrib2D; } + G4double GetFWHM() { return m_fwhm; } + GateVDistribution* GetFWHMxdistrib() { return m_fwhmXdistrib; } + GateVDistribution* GetFWHMydistrib() { return m_fwhmYdistrib; } + GateVDistribution* GetFWHMxydistrib2D() { return m_fwhmXYdistrib2D; } - G4double GetFWHMx() { return m_fwhmX; } - G4double GetFWHMy() { return m_fwhmY; } - G4double GetFWHMz() { return m_fwhmZ; } + G4double GetFWHMx() { return m_fwhmX; } + G4double GetFWHMy() { return m_fwhmY; } + G4double GetFWHMz() { return m_fwhmZ; } //! These functions set the spresolution of a gaussian spblurring. /*! @@ -75,7 +75,7 @@ public: void LocateOutputDigi(GateDigi* inputDigi, G4double PxNew,G4double PyNew,G4double PzNew); void UpdateVolumeID(); - void UpdateVolumeID(G4int newCopyNo); + //! Implementation of the pure virtual method declared by the base class GateClockDependent //! print-out the attributes specific of the blurring diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index a3790dfde..f6a19ed06 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -314,15 +314,6 @@ void GateSpatialResolution::UpdateVolumeID() } -void GateSpatialResolution::UpdateVolumeID(G4int newCopyNo) -{ - for (G4int i=1;iChangeVolumeIDAndOutputVolumeIDValue(i,newCopyNo); - } - - -} void GateSpatialResolution::DescribeMyself(size_t indent ) From 3e029213985e00105fbd166174b71619bb80c831 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Wed, 18 Sep 2024 14:03:37 +0200 Subject: [PATCH 46/96] Remove .project and .cproject files --- source/externals/lmf/.cproject | 16 ---------------- source/externals/lmf/.project | 20 -------------------- 2 files changed, 36 deletions(-) delete mode 100644 source/externals/lmf/.cproject delete mode 100644 source/externals/lmf/.project diff --git a/source/externals/lmf/.cproject b/source/externals/lmf/.cproject deleted file mode 100644 index c310a95f3..000000000 --- a/source/externals/lmf/.cproject +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/externals/lmf/.project b/source/externals/lmf/.project deleted file mode 100644 index d9d181aec..000000000 --- a/source/externals/lmf/.project +++ /dev/null @@ -1,20 +0,0 @@ - - - lmf - - - - - - org.eclipse.cdt.core.cBuilder - clean,full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.cmake.core.cmakeNature - - From 6861a1e316d56be15c14eb9ce53f86732164a228 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Wed, 18 Sep 2024 16:16:55 +0200 Subject: [PATCH 47/96] Update GateVirtualSegmentationSD.cc --- source/digits_hits/src/GateVirtualSegmentationSD.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index 6895d6303..45fef321d 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -147,8 +147,7 @@ void GateVirtualSegmentationSD::Digitize() for (G4int i=0;iGetVolumeID().size()){ G4Box* box = dynamic_cast(inputDigi->GetVolumeID().GetBottomCreator()->GetLogicalVolume()->GetSolid()); xLength = 2*box->GetXHalfLength(); From 1bfe058a6065f581c6837f0b434cc3eb34c042e1 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Wed, 18 Sep 2024 16:36:41 +0200 Subject: [PATCH 48/96] Update GateVirtualSegmentationSD.cc --- source/digits_hits/src/GateVirtualSegmentationSD.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index 45fef321d..a5d9e6bdb 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -421,16 +421,14 @@ void GateVirtualSegmentationSD::SetParameters() else if(digi_SpatialResolution->GetFWHMx() || digi_SpatialResolution->GetFWHMy()|| digi_SpatialResolution->GetFWHMz()){ - // DO NOT DELETE! - /* - //This is awaiting for Radia's code!!! - if(digi_SpatialResolution->GetFWHMxdistrib()||digi_SpatialResolution->GetFWHMydistrib()||digi_SpatialResolution->GetFWHMxydistrib()) + + if(digi_SpatialResolution->GetFWHMxdistrib()||digi_SpatialResolution->GetFWHMydistrib()||digi_SpatialResolution->GetFWHMxydistrib()) { GateError("***ERROR*** No value of the target pitch has been provided and no value can be obtained from the spatial resolution distribution. /n Please provide a value for the pitch that is at least half of the minimum value of the distribution. "); } - */ + if(digi_SpatialResolution->GetFWHMx() && m_nameAxis.find('X') != std::string::npos) {pitchX = 0.5*digi_SpatialResolution->GetFWHMx();} From 4df5ab7bd5662375c4c538d76400cbff64d35fab Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Wed, 18 Sep 2024 17:46:39 +0200 Subject: [PATCH 49/96] fix bug with VirtualSegmentation for new SpatialResolution --- source/digits_hits/src/GateVirtualSegmentationSD.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index a5d9e6bdb..afe840117 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -422,7 +422,7 @@ void GateVirtualSegmentationSD::SetParameters() - if(digi_SpatialResolution->GetFWHMxdistrib()||digi_SpatialResolution->GetFWHMydistrib()||digi_SpatialResolution->GetFWHMxydistrib()) + if(digi_SpatialResolution->GetFWHMxdistrib()||digi_SpatialResolution->GetFWHMydistrib()||digi_SpatialResolution->GetFWHMxydistrib2D()) { GateError("***ERROR*** No value of the target pitch has been provided and no value can be obtained from the spatial resolution distribution. /n Please provide a value for the pitch that is at least half of the minimum value of the distribution. "); } From 1f6673ba81f80583041e537fb3cbad5208e9572c Mon Sep 17 00:00:00 2001 From: tbilloud Date: Fri, 27 Sep 2024 13:25:17 +0200 Subject: [PATCH 50/96] fix version printed to console --- Gate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gate.cc b/Gate.cc index 9c0088cbf..ca7bbdec8 100644 --- a/Gate.cc +++ b/Gate.cc @@ -256,7 +256,7 @@ int main( int argc, char* argv[] ) break; case 'v': ss << G4VERSION_MAJOR << "." << G4VERSION_MINOR << "." << G4VERSION_PATCH; - std::cout << "Gate version is 9.2 ; Geant4 version is " << ss.str() << std::endl; + std::cout << "Gate version is 9.4 ; Geant4 version is " << ss.str() << std::endl; exit(0); break; case 'a': From 43dba909e95b48d1f46b9793f76dee8abf382226 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Wed, 23 Oct 2024 14:16:25 +0200 Subject: [PATCH 51/96] Fixing small bug when target_pitch is best_pitch --- source/digits_hits/src/GateVirtualSegmentationSD.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index afe840117..8ee984876 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -295,6 +295,8 @@ G4double GateVirtualSegmentationSD::calculatePitch(G4double crystal_size, G4doub double min_diff = 999; int num_pitches = 1; + if (std::fmod(crystal_size, target_pitch) == 0) return target_pitch; + while (true) { double pitch = crystal_size / num_pitches; From bf5b075c5a7901257d31306ef08fc20f69f5efa7 Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Thu, 28 Nov 2024 17:57:07 +0100 Subject: [PATCH 52/96] Fixing bug at virtual segmentation for hits at the back surface --- source/digits_hits/src/GateVirtualSegmentationSD.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index 8ee984876..56efaaf4e 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -295,8 +295,6 @@ G4double GateVirtualSegmentationSD::calculatePitch(G4double crystal_size, G4doub double min_diff = 999; int num_pitches = 1; - if (std::fmod(crystal_size, target_pitch) == 0) return target_pitch; - while (true) { double pitch = crystal_size / num_pitches; @@ -334,8 +332,12 @@ void GateVirtualSegmentationSD::SetVirtualID( int nBins, double pitch, G4double bin = std::floor(pos/pitch+nBins/2.); + if (bin == nBins) bin -=1; + if (bin < 0) bin = 0; m_outputDigi->SetOutputVolumeID(bin,depth); + //std::cout<<"Pos at depth"<GetOwnName() << "_" << m_outputIDName[k][depth]; mm.write_variable(ss.str(), &m_outputID[0][k][depth]); } } @@ -648,7 +648,7 @@ void GateToTree::RecordBeginOfAcquisition() { if (!m_outputIDHasName[k][depth]) continue; std::stringstream ss; - ss << system->GetOwnName() << "/" << m_outputIDName[k][depth]; + ss << system->GetOwnName() << "_" << m_outputIDName[k][depth]; mm.write_variable(ss.str(), &m_outputID[0][k][depth]); } } @@ -822,7 +822,7 @@ void GateToTree::RecordBeginOfAcquisition() { if (!m_outputIDHasName[k][depth]) continue; std::stringstream ss; - ss << system->GetOwnName() << "/" << m_outputIDName[k][depth] << side; + ss << system->GetOwnName() << "_" << m_outputIDName[k][depth] << side; mm.write_variable(ss.str(), &m_outputID[side - 1][k][depth]); } } From 6d6e816b987807424451fedf8bdade1cc134b71a Mon Sep 17 00:00:00 2001 From: Marc Granado Date: Thu, 9 Jan 2025 15:19:52 +0100 Subject: [PATCH 55/96] Changes in Spatial Resolution to allow the selection of affected axis in the 2D distribution --- .../include/GateSpatialResolution.hh | 13 ++++++++++- .../include/GateSpatialResolutionMessenger.hh | 8 ++++--- .../digits_hits/src/GateSpatialResolution.cc | 20 +++++++++++++++++ .../src/GateSpatialResolutionMessenger.cc | 22 +++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/source/digits_hits/include/GateSpatialResolution.hh b/source/digits_hits/include/GateSpatialResolution.hh index 778ca3afa..bd7f47d1f 100644 --- a/source/digits_hits/include/GateSpatialResolution.hh +++ b/source/digits_hits/include/GateSpatialResolution.hh @@ -50,8 +50,10 @@ public: GateVDistribution* GetFWHMxdistrib() { return m_fwhmXdistrib; } GateVDistribution* GetFWHMydistrib() { return m_fwhmYdistrib; } GateVDistribution* GetFWHMxydistrib2D() { return m_fwhmXYdistrib2D; } + G4String GetNameAxis() { return m_nameAxis; } + GateVDistribution* GetFWHMDistrib2D() { return m_fwhmDistrib2D; } - G4double GetFWHMx() { return m_fwhmX; } + G4double GetFWHMx() { return m_fwhmX; } G4double GetFWHMy() { return m_fwhmY; } G4double GetFWHMz() { return m_fwhmZ; } @@ -64,6 +66,9 @@ public: void SetFWHMydistrib(GateVDistribution* dist) { m_fwhmYdistrib = dist; } void SetFWHMxydistrib2D(GateVDistribution* dist) { m_fwhmXYdistrib2D= dist; } + void SetNameAxis(const G4String& name) {m_nameAxis=name;} + void SetFWHMDistrib2D(GateVDistribution* dist) { m_fwhmDistrib2D= dist;} + void SetFWHMx(G4double val) { m_fwhmX = val; } void SetFWHMy(G4double val) { m_fwhmY = val; } void SetFWHMz(G4double val) { m_fwhmZ = val; } @@ -94,6 +99,11 @@ protected: GateVDistribution* m_fwhmYdistrib; GateVDistribution* m_fwhmXYdistrib2D; + GateVDistribution* m_fwhmDistrib2D; + + G4String m_nameAxis; + + G4bool m_IsConfined; G4Navigator* m_Navigator; G4TouchableHistoryHandle m_Touchable; @@ -104,6 +114,7 @@ private: G4int m_systemDepth; + GateDigi* m_outputDigi;; GateSpatialResolutionMessenger *m_Messenger; diff --git a/source/digits_hits/include/GateSpatialResolutionMessenger.hh b/source/digits_hits/include/GateSpatialResolutionMessenger.hh index 7d3a5ebd7..c40abe89a 100644 --- a/source/digits_hits/include/GateSpatialResolutionMessenger.hh +++ b/source/digits_hits/include/GateSpatialResolutionMessenger.hh @@ -44,9 +44,11 @@ private: G4UIcmdWithADoubleAndUnit* spresolutionXCmd; G4UIcmdWithADoubleAndUnit* spresolutionYCmd; G4UIcmdWithADoubleAndUnit* spresolutionZCmd; - G4UIcmdWithAString *spresolutionXdistribCmd;// Command declaration for 1D X-resolution distribution - G4UIcmdWithAString *spresolutionYdistribCmd;// Command declaration for 1D Y-resolution distribution - G4UIcmdWithAString *spresolutionXYdistrib2DCmd; // Command declaration for 2D XY-resolution distribution + G4UIcmdWithAString *spresolutionXdistribCmd;// Command declaration for 1D X-resolution distribution + G4UIcmdWithAString *spresolutionYdistribCmd;// Command declaration for 1D Y-resolution distribution + G4UIcmdWithAString *spresolutionXYdistrib2DCmd; // Command declaration for 2D XY-resolution distribution + G4UIcmdWithAString *nameAxisCmd; + G4UIcmdWithAString *spresolutionDistrib2DCmd; // Command declaration for 2D resolution distribution will be used with nameAxisCmd G4UIcmdWithABool* confineCmd; diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index f6a19ed06..b63a964e2 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -55,6 +55,8 @@ GateSpatialResolution::GateSpatialResolution(GateSinglesDigitizer *digitizer, G4 m_fwhmXdistrib(0), m_fwhmYdistrib(0), m_fwhmXYdistrib2D(0), + m_nameAxis("XY"), + m_fwhmDistrib2D(0), m_fwhmY(0), m_fwhmZ(0), m_IsConfined(true), @@ -193,6 +195,24 @@ void GateSpatialResolution::Digitize(){ stddevX = m_fwhmXYdistrib2D->Value2D(P.x() * mm, P.y() * mm); stddevY = stddevX; // Assuming the 2D distribution returns the same for both axes } + else if (m_fwhmDistrib2D){ + if (m_nameAxis.length() != 2) { + GateError( " *** ERROR*** GateSpatialResolution::Digitize. There was an attempt to use fwhmDistrib2D but the length of the axis is not 2!\n"); + } + + else if(m_nameAxis.find('X') != std::string::npos){ + stddevX = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + } + else if(m_nameAxis.find('Y') != std::string::npos){ + stddevY = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + } + + else if(m_nameAxis.find('Z') != std::string::npos){ + stddevZ = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + } + + } + else if (m_fwhmXdistrib) { // If the FWHM distribution for X is defined if (m_fwhmYdistrib) { diff --git a/source/digits_hits/src/GateSpatialResolutionMessenger.cc b/source/digits_hits/src/GateSpatialResolutionMessenger.cc index 24ab69f5d..fb8121638 100644 --- a/source/digits_hits/src/GateSpatialResolutionMessenger.cc +++ b/source/digits_hits/src/GateSpatialResolutionMessenger.cc @@ -55,6 +55,17 @@ GateSpatialResolutionMessenger::GateSpatialResolutionMessenger (GateSpatialResol spresolutionXYdistrib2DCmd = new G4UIcmdWithAString(cmdName,this); spresolutionXYdistrib2DCmd->SetGuidance("Set the distribution 2D of spatial resolution in position for gaussian spblurring"); + cmdName = GetDirectoryName() + "fwhmDistrib2D"; + spresolutionDistrib2DCmd = new G4UIcmdWithAString(cmdName,this); + spresolutionDistrib2DCmd->SetGuidance("Set the distribution 2D of spatial resolution in position for gaussian spblurring"); + + + cmdName = GetDirectoryName()+"nameAxis"; + nameAxisCmd = new G4UIcmdWithAString(cmdName,this); + nameAxisCmd ->SetGuidance("Provide the name of the axis that will follow the spatial resolution distribution, X, Y, Z, XY, XZ, or YZ"); + nameAxisCmd ->SetCandidates("X Y Z XY XZ YZ"); + + cmdName = GetDirectoryName() + "confineInsideOfSmallestElement"; confineCmd = new G4UIcmdWithABool(cmdName,this); confineCmd->SetGuidance("To be set true, if you want to moves the outsiders of the crystal after spblurring inside the same crystal"); @@ -63,6 +74,8 @@ GateSpatialResolutionMessenger::GateSpatialResolutionMessenger (GateSpatialResol GateSpatialResolutionMessenger::~GateSpatialResolutionMessenger() { + delete nameAxisCmd; + delete spresolutionCmd; delete spresolutionXCmd; delete spresolutionXdistribCmd; @@ -96,6 +109,15 @@ void GateSpatialResolutionMessenger::SetNewValue(G4UIcommand * aCommand,G4String if (distrib) m_SpatialResolution->SetFWHMxydistrib2D(distrib); } + if (aCommand == nameAxisCmd) + { + m_SpatialResolution->SetNameAxis(newValue); + } + else if (aCommand == spresolutionDistrib2DCmd) + {GateVDistribution* distrib = (GateVDistribution*)GateDistributionListManager::GetInstance()->FindElementByBaseName(newValue); + if (distrib) m_SpatialResolution->SetFWHMDistrib2D(distrib); + } + else if ( aCommand==spresolutionXCmd ) { m_SpatialResolution->SetFWHMx(spresolutionXCmd->GetNewDoubleValue(newValue)); } else if ( aCommand==spresolutionYCmd ) From a2cdf656fd8980700d8f7c2a2343bd9b69bd981d Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Thu, 9 Jan 2025 17:41:40 +0100 Subject: [PATCH 56/96] fix delete spresolutionDistrib2DCmd --- source/digits_hits/src/GateSpatialResolutionMessenger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/digits_hits/src/GateSpatialResolutionMessenger.cc b/source/digits_hits/src/GateSpatialResolutionMessenger.cc index fb8121638..cd4b7567e 100644 --- a/source/digits_hits/src/GateSpatialResolutionMessenger.cc +++ b/source/digits_hits/src/GateSpatialResolutionMessenger.cc @@ -75,7 +75,7 @@ GateSpatialResolutionMessenger::GateSpatialResolutionMessenger (GateSpatialResol GateSpatialResolutionMessenger::~GateSpatialResolutionMessenger() { delete nameAxisCmd; - + delete spresolutionDistrib2DCmd; delete spresolutionCmd; delete spresolutionXCmd; delete spresolutionXdistribCmd; From 8ae1a2e060b84f90e9ff7cffb9524866978f314d Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Mon, 20 Jan 2025 14:22:06 +0100 Subject: [PATCH 57/96] Fixing spatial resolution FHWM and sigma references for all axis --- .../digits_hits/src/GateDistributionFile.cc | 21 ++++++------ .../digits_hits/src/GateSpatialResolution.cc | 33 ++++++++++++------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/source/digits_hits/src/GateDistributionFile.cc b/source/digits_hits/src/GateDistributionFile.cc index f0dd6312a..b43bd9bc1 100644 --- a/source/digits_hits/src/GateDistributionFile.cc +++ b/source/digits_hits/src/GateDistributionFile.cc @@ -110,7 +110,7 @@ void GateDistributionFile::ReadMatrix2d() { std::vector xValues; bool isFirstLine = true; bool is2D = true; - + size_t stddevCountXY = 0; while (std::getline(f, line)) { std::stringstream iss(line); @@ -120,6 +120,7 @@ void GateDistributionFile::ReadMatrix2d() { size_t xCount = 0; while (iss >> x) { + xValues.push_back(x); ++xCount; if (iss.peek() == ',') iss.ignore(); @@ -137,27 +138,28 @@ void GateDistributionFile::ReadMatrix2d() { G4double y; iss >> y; if (iss.peek() == ',') iss.ignore(); - size_t stddevCount = 0; + size_t stddevCountX = 0; + // Read stddev values for each x value for (size_t i = 0; i < xValues.size(); ++i) { G4double stddev; if (iss >> stddev) { - ++stddevCount; + ++stddevCountX; // Insert the (x, y) -> stddev pair into the map using InsertPoint InsertPoint(xValues[i], y, stddev); if (iss.peek() == ',') iss.ignore(); } + if (stddevCountX == xValues.size()) ++stddevCountXY; } - // Check if the number of stddev values matches the number of x values - if (stddevCount != xValues.size()) { - is2D = false; - break; - } + } } + if (stddevCountXY != xValues.size()) { + is2D = false; + } f.close(); //G4cout << "Content of stddevMap:\n"; //for (const auto& entry : stddevMap) { @@ -165,13 +167,12 @@ void GateDistributionFile::ReadMatrix2d() { // G4double stddev = entry.second; //std::cout << "Coordinates: (" << coordinates.first << ", " << coordinates.second << "), stddev: " << stddev << std::endl; //} - if (!is2D) { G4cerr << "[GateDistributionFile::ReadMatrix2d] ERROR: File " << m_FileName << " is not a valid 2D distribution file\n"; Clear(); return; } - FillRepartition(); + FillRepartition(); } diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index b63a964e2..3775599cc 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -193,24 +193,23 @@ void GateSpatialResolution::Digitize(){ // If the 2D FWHM distribution for X and Y is defined stddevX = m_fwhmXYdistrib2D->Value2D(P.x() * mm, P.y() * mm); - stddevY = stddevX; // Assuming the 2D distribution returns the same for both axes + stddevY = stddevX; // Assuming the 2D distribution returns the same for both axes } else if (m_fwhmDistrib2D){ if (m_nameAxis.length() != 2) { GateError( " *** ERROR*** GateSpatialResolution::Digitize. There was an attempt to use fwhmDistrib2D but the length of the axis is not 2!\n"); } + else { - else if(m_nameAxis.find('X') != std::string::npos){ - stddevX = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - } - else if(m_nameAxis.find('Y') != std::string::npos){ - stddevY = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - } + if(m_nameAxis.find('X') != std::string::npos) stddevX = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + else if (m_fwhmX) stddevX = fwhmX / GateConstants::fwhm_to_sigma; - else if(m_nameAxis.find('Z') != std::string::npos){ - stddevZ = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - } + if(m_nameAxis.find('Y') != std::string::npos) stddevY = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + else if (m_fwhmY) stddevY = fwhmY / GateConstants::fwhm_to_sigma; + if(m_nameAxis.find('Z') != std::string::npos) stddevZ = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + else if (m_fwhmZ) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma; + } } else if (m_fwhmXdistrib) { @@ -241,10 +240,20 @@ void GateSpatialResolution::Digitize(){ stddevY = fwhmY / GateConstants::fwhm_to_sigma; } + //std::cout<<"Position X,Y,Z "< Date: Mon, 20 Jan 2025 14:40:34 +0100 Subject: [PATCH 58/96] New fix of sigma and FWHM references in all axis spatial resolution --- source/digits_hits/src/GateSpatialResolution.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index 3775599cc..a30f8900f 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -242,7 +242,7 @@ void GateSpatialResolution::Digitize(){ //std::cout<<"Position X,Y,Z "< Date: Thu, 30 Jan 2025 09:54:21 +0100 Subject: [PATCH 59/96] Clean up of Spatial resolution and introduction of TruncatedGaussian distribution --- .../GateDistributionTruncatedGaussian.hh | 64 ++++++++ .../include/GateSpatialResolution.hh | 12 +- .../include/GateSpatialResolutionMessenger.hh | 2 +- .../src/GateDistributionTruncatedGaussian.cc | 155 ++++++++++++++++++ .../digits_hits/src/GateSpatialResolution.cc | 118 ++++++------- .../src/GateSpatialResolutionMessenger.cc | 32 ++-- .../src/GateVirtualSegmentationSD.cc | 2 +- 7 files changed, 295 insertions(+), 90 deletions(-) create mode 100644 source/digits_hits/include/GateDistributionTruncatedGaussian.hh create mode 100644 source/digits_hits/src/GateDistributionTruncatedGaussian.cc diff --git a/source/digits_hits/include/GateDistributionTruncatedGaussian.hh b/source/digits_hits/include/GateDistributionTruncatedGaussian.hh new file mode 100644 index 000000000..29966013b --- /dev/null +++ b/source/digits_hits/include/GateDistributionTruncatedGaussian.hh @@ -0,0 +1,64 @@ + + + + + +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + + +#ifndef GateDistributionGauss_h +#define GateDistributionGauss_h 1 + +#include "GateVDistribution.hh" +#include "GateDistributionGaussMessenger.hh" + +class GateDistributionGaussMessenger; +class GateDistributionGauss : public GateVDistribution +{ + public: + + //! Constructor + GateDistributionGauss(const G4String& itsName); + //! Destructor + virtual ~GateDistributionGauss() ; + + //! Setters + inline void SetMean(G4double mean) {m_Mean=mean;} + inline void SetSigma(G4double sigma) {m_Sigma=sigma;} + inline void SetAmplitude(G4double amplitude) {m_Amplitude=amplitude;} + //! Getters + inline G4double GetMean() const {return m_Mean;} + inline G4double GetSigma() const {return m_Sigma;} + inline G4double GetAmplitude() const {return m_Amplitude;} + virtual void DescribeMyself(size_t indent); + + + + virtual G4double MinX() const; + virtual G4double MinY() const; + virtual G4double MaxX() const; + virtual G4double MaxY() const; + virtual G4double Value(G4double x) const; + // Returns a random number following the current distribution + // should be optimised according to each distrbution type + virtual G4double ShootRandom() const; + + private: + G4double m_Mean; + G4double m_Sigma; + G4double m_lowLimit; + G4double m_highLimit; + G4double m_Amplitude; + GateDistributionGaussMessenger* m_messenger; + + +}; + + +#endif diff --git a/source/digits_hits/include/GateSpatialResolution.hh b/source/digits_hits/include/GateSpatialResolution.hh index bd7f47d1f..404000b87 100644 --- a/source/digits_hits/include/GateSpatialResolution.hh +++ b/source/digits_hits/include/GateSpatialResolution.hh @@ -49,7 +49,7 @@ public: G4double GetFWHM() { return m_fwhm; } GateVDistribution* GetFWHMxdistrib() { return m_fwhmXdistrib; } GateVDistribution* GetFWHMydistrib() { return m_fwhmYdistrib; } - GateVDistribution* GetFWHMxydistrib2D() { return m_fwhmXYdistrib2D; } + GateVDistribution* GetFWHMzdistrib() { return m_fwhmZdistrib; } G4String GetNameAxis() { return m_nameAxis; } GateVDistribution* GetFWHMDistrib2D() { return m_fwhmDistrib2D; } @@ -64,7 +64,8 @@ public: void SetFWHM(G4double val) { m_fwhm = val; } void SetFWHMxdistrib(GateVDistribution* dist) { m_fwhmXdistrib= dist; } void SetFWHMydistrib(GateVDistribution* dist) { m_fwhmYdistrib = dist; } - void SetFWHMxydistrib2D(GateVDistribution* dist) { m_fwhmXYdistrib2D= dist; } + void SetFWHMzdistrib(GateVDistribution* dist) { m_fwhmZdistrib = dist; } + void SetNameAxis(const G4String& name) {m_nameAxis=name;} void SetFWHMDistrib2D(GateVDistribution* dist) { m_fwhmDistrib2D= dist;} @@ -91,15 +92,14 @@ protected: G4double m_fwhmX; - G4double m_fwhmY; G4double m_fwhmZ; - GateVDistribution* m_fwhmXdistrib; + GateVDistribution* m_fwhmXdistrib; GateVDistribution* m_fwhmYdistrib; - GateVDistribution* m_fwhmXYdistrib2D; + GateVDistribution* m_fwhmZdistrib; - GateVDistribution* m_fwhmDistrib2D; + GateVDistribution* m_fwhmDistrib2D; G4String m_nameAxis; diff --git a/source/digits_hits/include/GateSpatialResolutionMessenger.hh b/source/digits_hits/include/GateSpatialResolutionMessenger.hh index c40abe89a..ff8feaabf 100644 --- a/source/digits_hits/include/GateSpatialResolutionMessenger.hh +++ b/source/digits_hits/include/GateSpatialResolutionMessenger.hh @@ -46,7 +46,7 @@ private: G4UIcmdWithADoubleAndUnit* spresolutionZCmd; G4UIcmdWithAString *spresolutionXdistribCmd;// Command declaration for 1D X-resolution distribution G4UIcmdWithAString *spresolutionYdistribCmd;// Command declaration for 1D Y-resolution distribution - G4UIcmdWithAString *spresolutionXYdistrib2DCmd; // Command declaration for 2D XY-resolution distribution + G4UIcmdWithAString *spresolutionZdistribCmd;// Command declaration for 1D Y-resolution distribution G4UIcmdWithAString *nameAxisCmd; G4UIcmdWithAString *spresolutionDistrib2DCmd; // Command declaration for 2D resolution distribution will be used with nameAxisCmd G4UIcmdWithABool* confineCmd; diff --git a/source/digits_hits/src/GateDistributionTruncatedGaussian.cc b/source/digits_hits/src/GateDistributionTruncatedGaussian.cc new file mode 100644 index 000000000..e254def22 --- /dev/null +++ b/source/digits_hits/src/GateDistributionTruncatedGaussian.cc @@ -0,0 +1,155 @@ +/*---------------------- + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See LICENSE.md for further details +----------------------*/ + + +#include "GateDistributionTruncatedGaussian.hh" + +#include "GateDistributionTruncatedGaussianMessenger.hh" +#include +//#include +#include "Randomize.hh" +#include "GateTools.hh" +#include "GateConstants.hh" + + +GateDistributionTruncatedGaussian::GateDistributionTruncatedGaussian(const G4String& itsName) + : GateVDistribution(itsName) + , m_Mean(0) + , m_Sigma(1) + , m_Amplitude(1) +{ + +} +//___________________________________________________________________ +GateDistributionTruncatedGaussian::~GateDistributionTruncatedGaussian() +{} +//___________________________________________________________________ +G4double GateDistributionTruncatedGaussian::MinX() const +{ + return -DBL_MAX; +} +//___________________________________________________________________ +G4double GateDistributionTruncatedGaussian::MinY() const +{ + return 0.; +} +//___________________________________________________________________ +G4double GateDistributionTruncatedGaussian::MaxX() const +{ + return DBL_MAX; +} +//___________________________________________________________________ +G4double GateDistributionTruncatedGaussian::MaxY() const +{ + return m_Amplitude*GateConstants::one_over_sqrt_2pi; +} +//___________________________________________________________________ +G4double GateDistributionTruncatedGaussian::Value(G4double x) const +{ + return GateConstants::one_over_sqrt_2pi*exp(-(x-m_Mean)*(x-m_Mean)/(2.*m_Sigma*m_Sigma))*m_Amplitude; +} +//___________________________________________________________________ +G4double GateDistributionTruncatedGaussian::ShootRandom() const +{ + //return G4RandGauss::shoot(m_Mean,m_Sigma); + return GateDistributionTruncatedGaussian::truncatedGaussian(); +} + +//___________________________________________________________________ +void GateDistributionTruncatedGaussian::DescribeMyself(size_t indent) +{ + G4cout << GateTools::Indent(indent) + <<"Mean : " << m_Mean + <<" -- Sigma : " << m_Sigma + <<" -- Amplitude : "<< m_Amplitude + << Gateendl; +} + + +// Standard normal PDF +double GateDistributionTruncatedGaussian::pdf(double x) { + return exp(-0.5 * x * x) / sqrt(2.0 * M_PI); +} + +// Standard normal CDF using the error function +double GateDistributionTruncatedGaussian::cdf(double x) { + return 0.5 * (1 + erf(x / sqrt(2.0))); +} + +// Compute the corrected standard deviation after truncation +double GateDistributionTruncatedGaussian::computeTruncatedSigma() { + double lowLim_std = (lowLimit - m_mu) / m_Sigma; + double hiLim_std = (highLimit - m_mu) / m_Sigma; + + double phi_lowLim = pdf(lowLim_std); + double phi_hiLim = pdf(hiLim_std); + double Fl = cdf(lowLim_std); + double Fh = cdf(hiLim_std); + + double Z = Fh - Fl; + double mean_shift = (phi_lowLim - phi_hiLim) / Z; + double variance_correction = 1 - (lowLim_std * phi_lowLim - hiLim_std * phi_hiLim) / Z - mean_shift * mean_shift; + + return m_Sigma * sqrt(variance_correction); +} + +// Sample from a truncated Gaussian distribution +double GateDistributionTruncatedGaussian::truncatedGaussian() { + + // Adjust m_Sigma to preserve the final standard deviation + double adjustedSigma = computeTruncatedSigma(m_mu, m_Sigma, lowLimit, highLimit); + + + + double x; + do { + x = G4RandGauss::shoot(m_Mean,adjustedSigma); + } while (x < lowLimit || x > highLimit); // Reject samples outside [a, b] + + caca + return x; +} + + +/* + * + * +//___________________________________________________________________ + +// Standard normal CDF using the error function +double cdf(double x) { + return 0.5 * (1 + erf(x / sqrt(2.0))); +} + +// Standard normal inverse CDF approximation (Probit function) +double inverseCDF(double p) { + return sqrt(2.0) * std::erfinv(2.0 * p - 1.0); +} + +// Sample from a truncated Gaussian without rejection sampling +double truncatedGaussian(double m_mu, double m_Sigma, double lowLimit, double highLimit) { + + double lowLim_std = (lowLim - m_mu) / m_Sigma; + double hiLim_std = (hiLim - m_mu) / m_Sigma; + + double F_low = cdf(lowLim_std); + double F_high = cdf(hiLim_std); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution uniform(F_low, F_high); + + // Sample in [F(a), F(b)] and apply inverse CDF + double u = uniform(gen); + double z = inverseCDF(u); // Inverse CDF to get standard normal sample + + return m_mu + m_Sigma * z; +} +* +*/ + diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index a30f8900f..dc81fc482 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -52,13 +52,13 @@ GateSpatialResolution::GateSpatialResolution(GateSinglesDigitizer *digitizer, G4 :GateVDigitizerModule(name,"digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/"+name,digitizer,digitizer->GetSD()), m_fwhm(0), m_fwhmX(0), + m_fwhmY(0), + m_fwhmZ(0), m_fwhmXdistrib(0), m_fwhmYdistrib(0), - m_fwhmXYdistrib2D(0), + m_fwhmZdistrib(0), m_nameAxis("XY"), m_fwhmDistrib2D(0), - m_fwhmY(0), - m_fwhmZ(0), m_IsConfined(true), m_Navigator(0), m_Touchable(0), @@ -81,25 +81,45 @@ GateSpatialResolution::~GateSpatialResolution() } void GateSpatialResolution::SetSpatialResolutionParameters() { // Check FWHM parameters - if (m_fwhm != 0 && (m_fwhmX != 0 || m_fwhmY != 0 || m_fwhmZ != 0 || m_fwhmXYdistrib2D != 0 || m_fwhmXdistrib != 0 || m_fwhmYdistrib != 0)) { + if (m_fwhm != 0 && (m_fwhmX != 0 || m_fwhmY != 0 || m_fwhmZ != 0 || m_fwhmDistrib2D != 0 || m_fwhmXdistrib !=0 || m_fwhmYdistrib !=0 || m_fwhmZdistrib !=0 )) { G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set a unique FWHM for all 3 axes OR set FWHM for X, Y, Z individually." << G4endl; abort(); } - if (m_fwhmXYdistrib2D != 0 && (m_fwhmX != 0 || m_fwhmY != 0 || m_fwhmXdistrib != 0 || m_fwhmYdistrib != 0)) { - G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM 2D distribution for (X,Y) OR set FWHM for X, Y individually." << G4endl; + if (m_fwhmDistrib2D) + { + if ((m_fwhmX != 0 || m_fwhmXdistrib !=0) && (m_nameAxis.find('X') != std::string::npos)) { + G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM for X OR set FWHM for X distribution." << G4endl; abort(); - } + } - if (m_fwhmY != 0 && (m_fwhmYdistrib != 0)) { + if ((m_fwhmY != 0|| m_fwhmYdistrib !=0) && (m_nameAxis.find('Y') != std::string::npos)) { G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM for Y OR set FWHM for Y distribution." << G4endl; abort(); - } + } - if (m_fwhmX != 0 && (m_fwhmXdistrib != 0)) { - G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM for X OR set FWHM for X distribution." << G4endl; + if ((m_fwhmZ != 0 || m_fwhmZdistrib !=0) && (m_nameAxis.find('Z') != std::string::npos)) { + G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM for Z OR set FWHM for Z distribution." << G4endl; abort(); - }} + } + } + + if (m_fwhmX != 0 && m_fwhmXdistrib !=0){ + G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM for X OR set FWHM for Z distribution." << G4endl; + abort(); + } + if (m_fwhmY != 0 && m_fwhmYdistrib !=0){ + G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM for Y OR set FWHM for Z distribution." << G4endl; + abort(); + } + if (m_fwhmZ != 0 && m_fwhmZdistrib !=0){ + G4cout << "***ERROR*** Spatial Resolution is ambiguous: you can set FWHM for Z OR set FWHM for Z distribution." << G4endl; + abort(); + } + +} + + void GateSpatialResolution::Digitize(){ if (m_IsFirstEntrance) { @@ -126,23 +146,6 @@ void GateSpatialResolution::Digitize(){ } - if (m_fwhmX==0 && m_fwhmY==0 && m_fwhmZ==0 ) - { - fwhmX=m_fwhm; - fwhmY=m_fwhm; - fwhmZ=m_fwhm; - - } - else - { - fwhmX=m_fwhmX; - fwhmY=m_fwhmY; - fwhmZ=m_fwhmZ; - - - - } - GateVSystem* m_system = ((GateSinglesDigitizer*)this->GetDigitizer())->GetSystem(); @@ -189,66 +192,43 @@ void GateSpatialResolution::Digitize(){ G4double Py = P.y(); G4double Pz = P.z(); G4double stddevX, stddevY, stddevZ; - if (m_fwhmXYdistrib2D) { - // If the 2D FWHM distribution for X and Y is defined - stddevX = m_fwhmXYdistrib2D->Value2D(P.x() * mm, P.y() * mm); - stddevY = stddevX; // Assuming the 2D distribution returns the same for both axes - } - else if (m_fwhmDistrib2D){ + if (m_fwhmDistrib2D){ if (m_nameAxis.length() != 2) { - GateError( " *** ERROR*** GateSpatialResolution::Digitize. There was an attempt to use fwhmDistrib2D but the length of the axis is not 2!\n"); + GateError( " *** ERROR*** GateSpatialResolution::Digitize. There was an attempt to use fwhmDistrib2D but the length of the named axis is not 2!\n"); } else { if(m_nameAxis.find('X') != std::string::npos) stddevX = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - else if (m_fwhmX) stddevX = fwhmX / GateConstants::fwhm_to_sigma; + else if (fwhmX) stddevX = fwhmX / GateConstants::fwhm_to_sigma; if(m_nameAxis.find('Y') != std::string::npos) stddevY = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - else if (m_fwhmY) stddevY = fwhmY / GateConstants::fwhm_to_sigma; + else if (fwhmY) stddevY = fwhmY / GateConstants::fwhm_to_sigma; if(m_nameAxis.find('Z') != std::string::npos) stddevZ = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - else if (m_fwhmZ) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma; + else if (fwhmZ) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma; } } - else if (m_fwhmXdistrib) { - // If the FWHM distribution for X is defined - if (m_fwhmYdistrib) { - stddevX = m_fwhmXdistrib->Value(P.x() * mm); - stddevY = m_fwhmYdistrib->Value(P.y() * mm); - } else if (m_fwhmY) { - stddevX = m_fwhmXdistrib->Value(P.x() * mm); - stddevY = fwhmY / GateConstants::fwhm_to_sigma; - } - else { - stddevX = m_fwhmXdistrib->Value(P.x() * mm); - stddevY = fwhmY / GateConstants::fwhm_to_sigma; - } - } else if (m_fwhmYdistrib) { - // If the FWHM distribution for Y is defined - if (m_fwhmX) { - stddevX = fwhmX / GateConstants::fwhm_to_sigma; - stddevY = m_fwhmYdistrib->Value(P.y() * mm); - } else if (m_fwhmXdistrib) { - stddevX = m_fwhmXdistrib->Value(P.y() * mm); - stddevY = m_fwhmYdistrib->Value(P.y() * mm); - } - } else { - // If neither the FWHM distributions for X nor Y are defined - stddevX = fwhmX / GateConstants::fwhm_to_sigma; - stddevY = fwhmY / GateConstants::fwhm_to_sigma; - } + else { - //std::cout<<"Position X,Y,Z "<Value(P.x() * mm); + else if (fwhmX) stddevX = fwhmX / GateConstants::fwhm_to_sigma; + + if (m_fwhmYdistrib) stddevY = m_fwhmYdistrib->Value(P.y() * mm); + else if (fwhmY) stddevY = fwhmY / GateConstants::fwhm_to_sigma; + + if (m_fwhmZdistrib) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma;// TODO! stddevZ = m_fwhmZdistrib->Value(P.z() * mm); + else if (fwhmZ) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma; + + } G4double PxNew = G4RandGauss::shoot(Px,stddevX); G4double PyNew = G4RandGauss::shoot(Py,stddevY); - //G4double PzNew = G4RandGauss::shoot(Pz,fwhmZ/GateConstants::fwhm_to_sigma); G4double PzNew = G4RandGauss::shoot(Pz,stddevZ); - //std::cout<<"new Position X,Y,Z "<SetGuidance("Set the resolution (in mm) in position for gaussian spblurring"); spresolutionCmd->SetUnitCategory("Length"); + cmdName = GetDirectoryName() + "fwhmX"; spresolutionXCmd= new G4UIcmdWithADoubleAndUnit(cmdName,this); spresolutionXCmd->SetGuidance("Set the resolution (in mm) in position for gaussian spblurring"); @@ -45,19 +46,20 @@ GateSpatialResolutionMessenger::GateSpatialResolutionMessenger (GateSpatialResol spresolutionZCmd = new G4UIcmdWithADoubleAndUnit(cmdName,this); spresolutionZCmd->SetGuidance("Set the resolution in position for gaussian spblurring"); spresolutionZCmd->SetUnitCategory("Length"); + cmdName = GetDirectoryName() + "fwhmXdistrib"; spresolutionXdistribCmd = new G4UIcmdWithAString(cmdName,this); spresolutionXdistribCmd->SetGuidance("Set the distribution resolution in position for gaussian spblurring"); cmdName = GetDirectoryName() + "fwhmYdistrib"; spresolutionYdistribCmd = new G4UIcmdWithAString(cmdName,this); spresolutionYdistribCmd->SetGuidance("Set the distribution resolution in position for gaussian spblurring"); - cmdName = GetDirectoryName() + "fwhmXYdistrib2D"; - spresolutionXYdistrib2DCmd = new G4UIcmdWithAString(cmdName,this); - spresolutionXYdistrib2DCmd->SetGuidance("Set the distribution 2D of spatial resolution in position for gaussian spblurring"); + cmdName = GetDirectoryName() + "fwhmZdistrib"; + spresolutionZdistribCmd = new G4UIcmdWithAString(cmdName,this); + spresolutionZdistribCmd->SetGuidance("Set the distribution resolution in position for gaussian spblurring"); cmdName = GetDirectoryName() + "fwhmDistrib2D"; spresolutionDistrib2DCmd = new G4UIcmdWithAString(cmdName,this); - spresolutionDistrib2DCmd->SetGuidance("Set the distribution 2D of spatial resolution in position for gaussian spblurring"); + spresolutionDistrib2DCmd->SetGuidance("Set the distribution 2D of spatial resolution in position for gaussian spblurring the name of the axis must be defined. default=XY"); cmdName = GetDirectoryName()+"nameAxis"; @@ -74,16 +76,20 @@ GateSpatialResolutionMessenger::GateSpatialResolutionMessenger (GateSpatialResol GateSpatialResolutionMessenger::~GateSpatialResolutionMessenger() { - delete nameAxisCmd; - delete spresolutionDistrib2DCmd; + delete spresolutionCmd; + delete spresolutionXCmd; + delete spresolutionYCmd; + delete spresolutionZCmd; + delete spresolutionXdistribCmd; delete spresolutionYdistribCmd; - delete spresolutionXYdistrib2DCmd; + delete spresolutionZdistribCmd; + + delete nameAxisCmd; + delete spresolutionDistrib2DCmd; - delete spresolutionYCmd; - delete spresolutionZCmd; delete confineCmd; } @@ -103,11 +109,11 @@ void GateSpatialResolutionMessenger::SetNewValue(G4UIcommand * aCommand,G4String { GateVDistribution* distrib = (GateVDistribution*)GateDistributionListManager::GetInstance()->FindElementByBaseName(newValue); if (distrib)m_SpatialResolution->SetFWHMydistrib(distrib); } - // Handle command for 2D XY-distribution resolution - else if (aCommand == spresolutionXYdistrib2DCmd) - {GateVDistribution* distrib = (GateVDistribution*)GateDistributionListManager::GetInstance()->FindElementByBaseName(newValue); - if (distrib) m_SpatialResolution->SetFWHMxydistrib2D(distrib); + else if ( aCommand==spresolutionZdistribCmd ) + { GateVDistribution* distrib = (GateVDistribution*)GateDistributionListManager::GetInstance()->FindElementByBaseName(newValue); + if (distrib)m_SpatialResolution->SetFWHMzdistrib(distrib); } + // Handle command for 2D-distribution resolution if (aCommand == nameAxisCmd) { diff --git a/source/digits_hits/src/GateVirtualSegmentationSD.cc b/source/digits_hits/src/GateVirtualSegmentationSD.cc index 56efaaf4e..73107e648 100644 --- a/source/digits_hits/src/GateVirtualSegmentationSD.cc +++ b/source/digits_hits/src/GateVirtualSegmentationSD.cc @@ -426,7 +426,7 @@ void GateVirtualSegmentationSD::SetParameters() - if(digi_SpatialResolution->GetFWHMxdistrib()||digi_SpatialResolution->GetFWHMydistrib()||digi_SpatialResolution->GetFWHMxydistrib2D()) + if(digi_SpatialResolution->GetFWHMxdistrib()||digi_SpatialResolution->GetFWHMydistrib()||digi_SpatialResolution->GetFWHMDistrib2D()) { GateError("***ERROR*** No value of the target pitch has been provided and no value can be obtained from the spatial resolution distribution. /n Please provide a value for the pitch that is at least half of the minimum value of the distribution. "); } From b774b54f8f4222261494c1019a6065319736dd92 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Mon, 3 Feb 2025 10:57:38 +0100 Subject: [PATCH 60/96] Introduction of Truncated Gaussian distribution with static method --- .../GateDistributionTruncatedGaussian.hh | 46 ++++++---- .../include/GateSpatialResolution.hh | 3 + .../include/GateSpatialResolutionMessenger.hh | 1 + .../src/GateDistributionTruncatedGaussian.cc | 88 ++++++++++++++----- .../digits_hits/src/GateSpatialResolution.cc | 46 ++++++++-- .../src/GateSpatialResolutionMessenger.cc | 9 ++ 6 files changed, 146 insertions(+), 47 deletions(-) diff --git a/source/digits_hits/include/GateDistributionTruncatedGaussian.hh b/source/digits_hits/include/GateDistributionTruncatedGaussian.hh index 29966013b..4a642cfd0 100644 --- a/source/digits_hits/include/GateDistributionTruncatedGaussian.hh +++ b/source/digits_hits/include/GateDistributionTruncatedGaussian.hh @@ -12,32 +12,45 @@ See LICENSE.md for further details ----------------------*/ -#ifndef GateDistributionGauss_h -#define GateDistributionGauss_h 1 +#ifndef GateDistributionTruncatedGaussian_h +#define GateDistributionTruncatedGaussian_h 1 #include "GateVDistribution.hh" -#include "GateDistributionGaussMessenger.hh" +//#include "GateDistributionTruncatedGaussianMessenger.hh" -class GateDistributionGaussMessenger; -class GateDistributionGauss : public GateVDistribution + +class GateDistributionTruncatedGaussian : public GateVDistribution { public: - //! Constructor - GateDistributionGauss(const G4String& itsName); + //! Constructors + GateDistributionTruncatedGaussian(const G4String& itsName); + GateDistributionTruncatedGaussian(const G4String& itsName, + G4double mu, + G4double sigma, + G4double lowLimit, + G4double highLimit); //! Destructor - virtual ~GateDistributionGauss() ; - + virtual ~GateDistributionTruncatedGaussian() ; + + //Static methods + //! Setters - inline void SetMean(G4double mean) {m_Mean=mean;} + inline void SetMu(G4double mu) {m_Mu=mu;} inline void SetSigma(G4double sigma) {m_Sigma=sigma;} - inline void SetAmplitude(G4double amplitude) {m_Amplitude=amplitude;} + inline void SetAmplitude(G4double amplitude) {m_Amplitude=amplitude;} + inline void SetLowLimit(G4double lowLimit) {m_lowLimit = lowLimit;} + inline void SethighLimit(G4double highLimit) {m_highLimit = highLimit;} //! Getters - inline G4double GetMean() const {return m_Mean;} + inline G4double GetMu() const {return m_Mu;} inline G4double GetSigma() const {return m_Sigma;} inline G4double GetAmplitude() const {return m_Amplitude;} virtual void DescribeMyself(size_t indent); - + //!Math functions + static G4double pdf(double x); + static G4double cdf(double x); + virtual G4double computeTruncatedSigma() const; + virtual G4double shootTruncatedGaussian() const; virtual G4double MinX() const; @@ -47,15 +60,16 @@ class GateDistributionGauss : public GateVDistribution virtual G4double Value(G4double x) const; // Returns a random number following the current distribution // should be optimised according to each distrbution type - virtual G4double ShootRandom() const; + //virtual G4double ShootRandom() const; + static G4double shootRandom(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit); + static G4double computeTruncatedSigmaStatic(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit) ; private: - G4double m_Mean; + G4double m_Mu; G4double m_Sigma; G4double m_lowLimit; G4double m_highLimit; G4double m_Amplitude; - GateDistributionGaussMessenger* m_messenger; }; diff --git a/source/digits_hits/include/GateSpatialResolution.hh b/source/digits_hits/include/GateSpatialResolution.hh index 404000b87..8fd30748a 100644 --- a/source/digits_hits/include/GateSpatialResolution.hh +++ b/source/digits_hits/include/GateSpatialResolution.hh @@ -76,6 +76,8 @@ public: void SetSpatialResolutionParameters(); inline void ConfineInsideOfSmallestElement(const G4bool& value) { m_IsConfined = value; }; inline G4bool IsConfinedInsideOfSmallestElement() const { return m_IsConfined; } + inline void SetUseTruncatedGaussian(const G4bool& value) { m_UseTruncatedGaussian = value; }; + inline G4bool GetUseTruncatedGaussian(const G4bool& value) { return m_UseTruncatedGaussian; } void UpdatePos(G4double ,G4double ,G4double ); void LocateOutputDigi(GateDigi* inputDigi, G4double PxNew,G4double PyNew,G4double PzNew); @@ -105,6 +107,7 @@ protected: G4bool m_IsConfined; + G4bool m_UseTruncatedGaussian; G4Navigator* m_Navigator; G4TouchableHistoryHandle m_Touchable; diff --git a/source/digits_hits/include/GateSpatialResolutionMessenger.hh b/source/digits_hits/include/GateSpatialResolutionMessenger.hh index ff8feaabf..33d33213a 100644 --- a/source/digits_hits/include/GateSpatialResolutionMessenger.hh +++ b/source/digits_hits/include/GateSpatialResolutionMessenger.hh @@ -50,6 +50,7 @@ private: G4UIcmdWithAString *nameAxisCmd; G4UIcmdWithAString *spresolutionDistrib2DCmd; // Command declaration for 2D resolution distribution will be used with nameAxisCmd G4UIcmdWithABool* confineCmd; + G4UIcmdWithABool* useTruncatedGaussianCmd; }; diff --git a/source/digits_hits/src/GateDistributionTruncatedGaussian.cc b/source/digits_hits/src/GateDistributionTruncatedGaussian.cc index e254def22..6a3e36c98 100644 --- a/source/digits_hits/src/GateDistributionTruncatedGaussian.cc +++ b/source/digits_hits/src/GateDistributionTruncatedGaussian.cc @@ -9,7 +9,7 @@ See LICENSE.md for further details #include "GateDistributionTruncatedGaussian.hh" -#include "GateDistributionTruncatedGaussianMessenger.hh" +//#include "GateDistributionTruncatedGaussianMessenger.hh" #include //#include #include "Randomize.hh" @@ -19,11 +19,21 @@ See LICENSE.md for further details GateDistributionTruncatedGaussian::GateDistributionTruncatedGaussian(const G4String& itsName) : GateVDistribution(itsName) - , m_Mean(0) + , m_Mu(0) , m_Sigma(1) , m_Amplitude(1) + ,m_lowLimit(0) + ,m_highLimit(0) { +} + +GateDistributionTruncatedGaussian::GateDistributionTruncatedGaussian(const G4String& itsName, + G4double mu, + G4double sigma, + G4double lowLimit, + G4double highLimit) +:GateVDistribution(itsName), m_Mu(mu), m_Sigma(sigma), m_lowLimit(lowLimit), m_highLimit(highLimit) { } //___________________________________________________________________ GateDistributionTruncatedGaussian::~GateDistributionTruncatedGaussian() @@ -51,20 +61,32 @@ G4double GateDistributionTruncatedGaussian::MaxY() const //___________________________________________________________________ G4double GateDistributionTruncatedGaussian::Value(G4double x) const { - return GateConstants::one_over_sqrt_2pi*exp(-(x-m_Mean)*(x-m_Mean)/(2.*m_Sigma*m_Sigma))*m_Amplitude; + return GateConstants::one_over_sqrt_2pi*exp(-(x-m_Mu)*(x-m_Mu)/(2.*m_Sigma*m_Sigma))*m_Amplitude; } //___________________________________________________________________ -G4double GateDistributionTruncatedGaussian::ShootRandom() const -{ - //return G4RandGauss::shoot(m_Mean,m_Sigma); - return GateDistributionTruncatedGaussian::truncatedGaussian(); +//G4double GateDistributionTruncatedGaussian::ShootRandom() const + +G4double GateDistributionTruncatedGaussian::shootRandom(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit) +{ //return G4RandGauss::shoot(m_Mu,m_Sigma); + + // Adjust m_Sigma to preserve the final standard deviation + G4double const adjustedSigma = computeTruncatedSigmaStatic(mu, sigma, lowLimit, highLimit); + + + + G4double x; + do { + x = G4RandGauss::shoot(mu,adjustedSigma); + } while (x < lowLimit || x > highLimit); // Reject samples outside [a, b] + + return x; } //___________________________________________________________________ void GateDistributionTruncatedGaussian::DescribeMyself(size_t indent) { G4cout << GateTools::Indent(indent) - <<"Mean : " << m_Mean + <<"Mean : " << m_Mu <<" -- Sigma : " << m_Sigma <<" -- Amplitude : "<< m_Amplitude << Gateendl; @@ -72,19 +94,19 @@ void GateDistributionTruncatedGaussian::DescribeMyself(size_t indent) // Standard normal PDF -double GateDistributionTruncatedGaussian::pdf(double x) { +G4double GateDistributionTruncatedGaussian::pdf(G4double x){ return exp(-0.5 * x * x) / sqrt(2.0 * M_PI); } // Standard normal CDF using the error function -double GateDistributionTruncatedGaussian::cdf(double x) { +G4double GateDistributionTruncatedGaussian::cdf(G4double x){ return 0.5 * (1 + erf(x / sqrt(2.0))); } // Compute the corrected standard deviation after truncation -double GateDistributionTruncatedGaussian::computeTruncatedSigma() { - double lowLim_std = (lowLimit - m_mu) / m_Sigma; - double hiLim_std = (highLimit - m_mu) / m_Sigma; +G4double GateDistributionTruncatedGaussian::computeTruncatedSigma() const{ + double lowLim_std = (m_lowLimit - m_Mu) / m_Sigma; + double hiLim_std = (m_highLimit - m_Mu) / m_Sigma; double phi_lowLim = pdf(lowLim_std); double phi_hiLim = pdf(hiLim_std); @@ -98,20 +120,40 @@ double GateDistributionTruncatedGaussian::computeTruncatedSigma() { return m_Sigma * sqrt(variance_correction); } + +G4double GateDistributionTruncatedGaussian::computeTruncatedSigmaStatic(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit){ + double lowLim_std = (lowLimit - mu) / sigma; + double hiLim_std = (highLimit - mu) / sigma; + + double phi_lowLim = pdf(lowLim_std); + double phi_hiLim = pdf(hiLim_std); + double Fl = cdf(lowLim_std); + double Fh = cdf(hiLim_std); + + double Z = Fh - Fl; + double mean_shift = (phi_lowLim - phi_hiLim) / Z; + double variance_correction = 1 - (lowLim_std * phi_lowLim - hiLim_std * phi_hiLim) / Z - mean_shift * mean_shift; + + return sigma * sqrt(variance_correction); +} + + + + + // Sample from a truncated Gaussian distribution -double GateDistributionTruncatedGaussian::truncatedGaussian() { +G4double GateDistributionTruncatedGaussian::shootTruncatedGaussian() const{ // Adjust m_Sigma to preserve the final standard deviation - double adjustedSigma = computeTruncatedSigma(m_mu, m_Sigma, lowLimit, highLimit); + G4double const adjustedSigma = computeTruncatedSigma(); - double x; + G4double x; do { - x = G4RandGauss::shoot(m_Mean,adjustedSigma); - } while (x < lowLimit || x > highLimit); // Reject samples outside [a, b] + x = G4RandGauss::shoot(m_Mu,adjustedSigma); + } while (x < m_lowLimit || x > m_highLimit); // Reject samples outside [a, b] - caca return x; } @@ -132,10 +174,10 @@ double inverseCDF(double p) { } // Sample from a truncated Gaussian without rejection sampling -double truncatedGaussian(double m_mu, double m_Sigma, double lowLimit, double highLimit) { +double truncatedGaussian(double m_Mu, double m_Sigma, double m_lowLimit, double m_highLimit) { - double lowLim_std = (lowLim - m_mu) / m_Sigma; - double hiLim_std = (hiLim - m_mu) / m_Sigma; + double lowLim_std = (lowLim - m_Mu) / m_Sigma; + double hiLim_std = (hiLim - m_Mu) / m_Sigma; double F_low = cdf(lowLim_std); double F_high = cdf(hiLim_std); @@ -148,7 +190,7 @@ double truncatedGaussian(double m_mu, double m_Sigma, double lowLimit, double hi double u = uniform(gen); double z = inverseCDF(u); // Inverse CDF to get standard normal sample - return m_mu + m_Sigma * z; + return m_Mu + m_Sigma * z; } * */ diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index dc81fc482..cdcfea6c7 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -44,6 +44,7 @@ #include "G4TransportationManager.hh" #include "G4Navigator.hh" #include "GateVDistribution.hh" +#include "GateDistributionTruncatedGaussian.hh" @@ -60,6 +61,7 @@ GateSpatialResolution::GateSpatialResolution(GateSinglesDigitizer *digitizer, G4 m_nameAxis("XY"), m_fwhmDistrib2D(0), m_IsConfined(true), + m_UseTruncatedGaussian(true), m_Navigator(0), m_Touchable(0), m_systemDepth(-1), @@ -224,9 +226,10 @@ void GateSpatialResolution::Digitize(){ } - G4double PxNew = G4RandGauss::shoot(Px,stddevX); - G4double PyNew = G4RandGauss::shoot(Py,stddevY); - G4double PzNew = G4RandGauss::shoot(Pz,stddevZ); + + G4double PxNew ;//= G4RandGauss::shoot(Px,stddevX); + G4double PyNew ;//= G4RandGauss::shoot(Py,stddevY); + G4double PzNew ;//= G4RandGauss::shoot(Pz,stddevZ); @@ -241,13 +244,26 @@ void GateSpatialResolution::Digitize(){ inputDigi->GetVolumeID().GetBottomCreator()->GetLogicalVolume()->GetSolid()->CalculateExtent(kYAxis, limits, at, Ymin, Ymax); inputDigi->GetVolumeID().GetBottomCreator()->GetLogicalVolume()->GetSolid()->CalculateExtent(kZAxis, limits, at, Zmin, Zmax); + if (m_UseTruncatedGaussian) + { + + PxNew = GateDistributionTruncatedGaussian::shootRandom(Px,stddevX,Xmin, Xmax); + PyNew = GateDistributionTruncatedGaussian::shootRandom(Py,stddevY,Ymin, Ymax); + PzNew = GateDistributionTruncatedGaussian::shootRandom(Pz,stddevZ,Zmin, Zmax); + } + else{ + + PxNew = G4RandGauss::shoot(Px,stddevX); + PyNew = G4RandGauss::shoot(Py,stddevY); + PzNew = G4RandGauss::shoot(Pz,stddevZ); + if(PxNewXmax) PxNew=Xmax; if(PyNew>Ymax) PyNew=Ymax; if(PzNew>Zmax) PzNew=Zmax; - + } m_outputDigi->SetLocalPos(G4ThreeVector(PxNew,PyNew,PzNew)); //TC @@ -261,11 +277,25 @@ void GateSpatialResolution::Digitize(){ { //Not confined: //Update volume IDs and new locations inside crystal - - // TODO Test properly and maybe extent to more general cases + // TODO Test properly and maybe extent to more general cases inputDigi->GetVolumeID().GetCreator(m_systemDepth-1)->GetLogicalVolume()->GetSolid()->CalculateExtent(kXAxis, limits, at, Xmin, Xmax); - inputDigi->GetVolumeID().GetCreator(m_systemDepth-1)->GetLogicalVolume()->GetSolid()->CalculateExtent(kYAxis, limits, at, Ymin, Ymax); - inputDigi->GetVolumeID().GetCreator(m_systemDepth-1)->GetLogicalVolume()->GetSolid()->CalculateExtent(kZAxis, limits, at, Zmin, Zmax); + inputDigi->GetVolumeID().GetCreator(m_systemDepth-1)->GetLogicalVolume()->GetSolid()->CalculateExtent(kYAxis, limits, at, Ymin, Ymax); + inputDigi->GetVolumeID().GetCreator(m_systemDepth-1)->GetLogicalVolume()->GetSolid()->CalculateExtent(kZAxis, limits, at, Zmin, Zmax); + + + if (m_UseTruncatedGaussian) + { + + PxNew = GateDistributionTruncatedGaussian::shootRandom(Px,stddevX,Xmin, Xmax); + PyNew = GateDistributionTruncatedGaussian::shootRandom(Py,stddevY,Ymin, Ymax); + PzNew = GateDistributionTruncatedGaussian::shootRandom(Pz,stddevZ,Zmin, Zmax); + } + else{ + + PxNew = G4RandGauss::shoot(Px,stddevX); + PyNew = G4RandGauss::shoot(Py,stddevY); + PzNew = G4RandGauss::shoot(Pz,stddevZ); + } if(PxNewSetGuidance("To be set true, if you want to moves the outsiders of the crystal after spblurring inside the same crystal"); + + cmdName = GetDirectoryName() + "useTruncatedGaussian"; + useTruncatedGaussianCmd = new G4UIcmdWithABool(cmdName,this); + useTruncatedGaussianCmd->SetGuidance("To be set true, if you want to use a truncated Gaussian distribution to keep the blurring within the same crystal"); } + + GateSpatialResolutionMessenger::~GateSpatialResolutionMessenger() { @@ -91,6 +97,7 @@ GateSpatialResolutionMessenger::~GateSpatialResolutionMessenger() delete spresolutionDistrib2DCmd; delete confineCmd; + delete useTruncatedGaussianCmd; } @@ -132,6 +139,8 @@ void GateSpatialResolutionMessenger::SetNewValue(G4UIcommand * aCommand,G4String { m_SpatialResolution->SetFWHMz(spresolutionZCmd->GetNewDoubleValue(newValue)); } else if ( aCommand==confineCmd ) { m_SpatialResolution->ConfineInsideOfSmallestElement(confineCmd->GetNewBoolValue(newValue)); } + else if ( aCommand==useTruncatedGaussianCmd ) + { m_SpatialResolution->SetUseTruncatedGaussian(useTruncatedGaussianCmd->GetNewBoolValue(newValue)); } else { GateClockDependentMessenger::SetNewValue(aCommand,newValue); From d70b6d0ef8d8438ef082d13a92b38dd1df1a036f Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Wed, 5 Feb 2025 13:59:36 +0100 Subject: [PATCH 61/96] Clean up and comments on GateDistributionTruncatedGaussian --- .../GateDistributionTruncatedGaussian.hh | 19 +-- .../src/GateDistributionTruncatedGaussian.cc | 129 +++++++----------- 2 files changed, 59 insertions(+), 89 deletions(-) diff --git a/source/digits_hits/include/GateDistributionTruncatedGaussian.hh b/source/digits_hits/include/GateDistributionTruncatedGaussian.hh index 4a642cfd0..f5ec79d81 100644 --- a/source/digits_hits/include/GateDistributionTruncatedGaussian.hh +++ b/source/digits_hits/include/GateDistributionTruncatedGaussian.hh @@ -46,21 +46,22 @@ class GateDistributionTruncatedGaussian : public GateVDistribution inline G4double GetSigma() const {return m_Sigma;} inline G4double GetAmplitude() const {return m_Amplitude;} virtual void DescribeMyself(size_t indent); - //!Math functions - static G4double pdf(double x); - static G4double cdf(double x); - virtual G4double computeTruncatedSigma() const; - virtual G4double shootTruncatedGaussian() const; - + + virtual G4double MinX() const; virtual G4double MinY() const; virtual G4double MaxX() const; virtual G4double MaxY() const; virtual G4double Value(G4double x) const; - // Returns a random number following the current distribution - // should be optimised according to each distrbution type - //virtual G4double ShootRandom() const; + + //! Math functions + virtual G4double computeTruncatedSigma() const; + virtual G4double shootTruncatedGaussian() const; + + //! Static methods; + static G4double pdf(double x); + static G4double cdf(double x); static G4double shootRandom(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit); static G4double computeTruncatedSigmaStatic(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit) ; diff --git a/source/digits_hits/src/GateDistributionTruncatedGaussian.cc b/source/digits_hits/src/GateDistributionTruncatedGaussian.cc index 6a3e36c98..03d22c17e 100644 --- a/source/digits_hits/src/GateDistributionTruncatedGaussian.cc +++ b/source/digits_hits/src/GateDistributionTruncatedGaussian.cc @@ -1,11 +1,21 @@ /*---------------------- Copyright (C): OpenGATE Collaboration + + This software is distributed under the terms of the GNU Lesser General Public Licence (LGPL) See LICENSE.md for further details ----------------------*/ - +/*! + * GateDistributionTruncatedGuassian (by marc.granado@universite-paris-saclay.fr) + * + * In order to be able to optimise the use of different truncated Gaussians on each event, implying to the use of any FWHM distribution within the crystal, + * the instance methods: "computeTruncatedSigma" (to correct the sigma in order to preserve the variance of the new distribution) + * and "ShootTruncatedGaussian" (to generate the random number) have their static method counterpart: + * "computeTruncatedSigmaStatic" and "ShootRandom" respectively to avoid the need of an object of the class "GateDistributionTruncatedGaussian" to generate the nubmers + * + */ #include "GateDistributionTruncatedGaussian.hh" @@ -63,25 +73,23 @@ G4double GateDistributionTruncatedGaussian::Value(G4double x) const { return GateConstants::one_over_sqrt_2pi*exp(-(x-m_Mu)*(x-m_Mu)/(2.*m_Sigma*m_Sigma))*m_Amplitude; } -//___________________________________________________________________ -//G4double GateDistributionTruncatedGaussian::ShootRandom() const -G4double GateDistributionTruncatedGaussian::shootRandom(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit) -{ //return G4RandGauss::shoot(m_Mu,m_Sigma); +//___________________________________________________________________ //Equivalent to ShootRandom +// Sample from a truncated Gaussian distribution +G4double GateDistributionTruncatedGaussian::shootTruncatedGaussian() const{ // Adjust m_Sigma to preserve the final standard deviation - G4double const adjustedSigma = computeTruncatedSigmaStatic(mu, sigma, lowLimit, highLimit); + G4double const adjustedSigma = computeTruncatedSigma(); G4double x; do { - x = G4RandGauss::shoot(mu,adjustedSigma); - } while (x < lowLimit || x > highLimit); // Reject samples outside [a, b] + x = G4RandGauss::shoot(m_Mu,adjustedSigma); + } while (x < m_lowLimit || x > m_highLimit); // Reject samples outside [a, b] return x; } - //___________________________________________________________________ void GateDistributionTruncatedGaussian::DescribeMyself(size_t indent) { @@ -92,21 +100,40 @@ void GateDistributionTruncatedGaussian::DescribeMyself(size_t indent) << Gateendl; } +//___________________________________________________________________ +//___________________________________________________________________ + +//Static methods to be used without the need for a class object: +G4double GateDistributionTruncatedGaussian::shootRandom(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit) +{ //return G4RandGauss::shoot(m_Mu,m_Sigma); + + // Adjust m_Sigma to preserve the final standard deviation + G4double const adjustedSigma = computeTruncatedSigmaStatic(mu, sigma, lowLimit, highLimit); + + + G4double x; + do { + x = G4RandGauss::shoot(mu,adjustedSigma); + } while (x < lowLimit || x > highLimit); // Reject samples outside [a, b] + + return x; +} +//___________________________________________________________________ // Standard normal PDF G4double GateDistributionTruncatedGaussian::pdf(G4double x){ return exp(-0.5 * x * x) / sqrt(2.0 * M_PI); } - +//___________________________________________________________________ // Standard normal CDF using the error function G4double GateDistributionTruncatedGaussian::cdf(G4double x){ return 0.5 * (1 + erf(x / sqrt(2.0))); } - +//___________________________________________________________________ // Compute the corrected standard deviation after truncation -G4double GateDistributionTruncatedGaussian::computeTruncatedSigma() const{ - double lowLim_std = (m_lowLimit - m_Mu) / m_Sigma; - double hiLim_std = (m_highLimit - m_Mu) / m_Sigma; +G4double GateDistributionTruncatedGaussian::computeTruncatedSigmaStatic(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit){ + double lowLim_std = (lowLimit - mu) / sigma; + double hiLim_std = (highLimit - mu) / sigma; double phi_lowLim = pdf(lowLim_std); double phi_hiLim = pdf(hiLim_std); @@ -117,13 +144,14 @@ G4double GateDistributionTruncatedGaussian::computeTruncatedSigma() const{ double mean_shift = (phi_lowLim - phi_hiLim) / Z; double variance_correction = 1 - (lowLim_std * phi_lowLim - hiLim_std * phi_hiLim) / Z - mean_shift * mean_shift; - return m_Sigma * sqrt(variance_correction); + return sigma * sqrt(variance_correction); } - -G4double GateDistributionTruncatedGaussian::computeTruncatedSigmaStatic(G4double mu, G4double sigma, G4double lowLimit, G4double highLimit){ - double lowLim_std = (lowLimit - mu) / sigma; - double hiLim_std = (highLimit - mu) / sigma; +//___________________________________________________________________ +// Compute the corrected standard deviation after truncation +G4double GateDistributionTruncatedGaussian::computeTruncatedSigma() const{ + double lowLim_std = (m_lowLimit - m_Mu) / m_Sigma; + double hiLim_std = (m_highLimit - m_Mu) / m_Sigma; double phi_lowLim = pdf(lowLim_std); double phi_hiLim = pdf(hiLim_std); @@ -134,64 +162,5 @@ G4double GateDistributionTruncatedGaussian::computeTruncatedSigmaStatic(G4double double mean_shift = (phi_lowLim - phi_hiLim) / Z; double variance_correction = 1 - (lowLim_std * phi_lowLim - hiLim_std * phi_hiLim) / Z - mean_shift * mean_shift; - return sigma * sqrt(variance_correction); -} - - - - - -// Sample from a truncated Gaussian distribution -G4double GateDistributionTruncatedGaussian::shootTruncatedGaussian() const{ - - // Adjust m_Sigma to preserve the final standard deviation - G4double const adjustedSigma = computeTruncatedSigma(); - - - - G4double x; - do { - x = G4RandGauss::shoot(m_Mu,adjustedSigma); - } while (x < m_lowLimit || x > m_highLimit); // Reject samples outside [a, b] - - return x; -} - - -/* - * - * -//___________________________________________________________________ - -// Standard normal CDF using the error function -double cdf(double x) { - return 0.5 * (1 + erf(x / sqrt(2.0))); -} - -// Standard normal inverse CDF approximation (Probit function) -double inverseCDF(double p) { - return sqrt(2.0) * std::erfinv(2.0 * p - 1.0); -} - -// Sample from a truncated Gaussian without rejection sampling -double truncatedGaussian(double m_Mu, double m_Sigma, double m_lowLimit, double m_highLimit) { - - double lowLim_std = (lowLim - m_Mu) / m_Sigma; - double hiLim_std = (hiLim - m_Mu) / m_Sigma; - - double F_low = cdf(lowLim_std); - double F_high = cdf(hiLim_std); - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_real_distribution uniform(F_low, F_high); - - // Sample in [F(a), F(b)] and apply inverse CDF - double u = uniform(gen); - double z = inverseCDF(u); // Inverse CDF to get standard normal sample - - return m_Mu + m_Sigma * z; -} -* -*/ - + return m_Sigma * sqrt(variance_correction); +} \ No newline at end of file From c52d885a40abf1dd5e737d0acbf8efbada9b2821 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Wed, 5 Feb 2025 14:01:20 +0100 Subject: [PATCH 62/96] Clean up and comments on GateDistributionTruncatedGaussian and SpatialResolution --- source/digits_hits/src/GateSpatialResolution.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index cdcfea6c7..0a3e04596 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -227,12 +227,9 @@ void GateSpatialResolution::Digitize(){ - G4double PxNew ;//= G4RandGauss::shoot(Px,stddevX); - G4double PyNew ;//= G4RandGauss::shoot(Py,stddevY); - G4double PzNew ;//= G4RandGauss::shoot(Pz,stddevZ); - - - + G4double PxNew ; + G4double PyNew ; + G4double PzNew ; From c545bf2c55630f8aa518b7465b9a491cbd852c96 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 18 Feb 2025 13:14:00 +0100 Subject: [PATCH 63/96] Adding different axis pairs for Spatial Resolution distributions. --- .../digits_hits/src/GateSpatialResolution.cc | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index 0a3e04596..9b33e31cf 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -195,23 +195,29 @@ void GateSpatialResolution::Digitize(){ G4double Pz = P.z(); G4double stddevX, stddevY, stddevZ; - if (m_fwhmDistrib2D){ - if (m_nameAxis.length() != 2) { - GateError( " *** ERROR*** GateSpatialResolution::Digitize. There was an attempt to use fwhmDistrib2D but the length of the named axis is not 2!\n"); - } - else { - - if(m_nameAxis.find('X') != std::string::npos) stddevX = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - else if (fwhmX) stddevX = fwhmX / GateConstants::fwhm_to_sigma; - - if(m_nameAxis.find('Y') != std::string::npos) stddevY = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - else if (fwhmY) stddevY = fwhmY / GateConstants::fwhm_to_sigma; - - if(m_nameAxis.find('Z') != std::string::npos) stddevZ = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); - else if (fwhmZ) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma; - } + if (m_fwhmDistrib2D) { + if (m_nameAxis.size() != 2) { + GateError(" *** ERROR*** GateSpatialResolution::Digitize. " + "Attempt to use fwhmDistrib2D but the length of the named axis is not 2!\n"); + } else { + if (m_nameAxis == "XY") { + stddevX = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + stddevY = m_fwhmDistrib2D->Value2D(P.x() * mm, P.y() * mm); + if (fwhmZ) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma; + } else if (m_nameAxis == "XZ") { + stddevX = m_fwhmDistrib2D->Value2D(P.x() * mm, P.z() * mm); + stddevZ = m_fwhmDistrib2D->Value2D(P.x() * mm, P.z() * mm); + if (fwhmY) stddevY = fwhmY / GateConstants::fwhm_to_sigma; + } else if (m_nameAxis == "YZ") { + stddevY = m_fwhmDistrib2D->Value2D(P.y() * mm, P.z() * mm); + stddevZ = m_fwhmDistrib2D->Value2D(P.y() * mm, P.z() * mm); + if (fwhmX) stddevX = fwhmX / GateConstants::fwhm_to_sigma; + } else { + GateError(" *** ERROR*** GateSpatialResolution::Digitize. " + "Unrecognized axis configuration: " + m_nameAxis + "\n"); + } + } } - else { if (m_fwhmXdistrib) stddevX = m_fwhmXdistrib->Value(P.x() * mm); From 8252793d9ecbe9ac9c8ed1122697f0b325d7acc2 Mon Sep 17 00:00:00 2001 From: Thomas BAUDIER Date: Wed, 5 Feb 2025 15:07:15 +0100 Subject: [PATCH 64/96] fftw3-dev libraries installation on github actions --- .github/workflows/main.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 47f126617..4de0212d3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,7 +63,7 @@ jobs: libssl-dev \ python3.8-dev \ ccache \ - fftw3-dev + libfftw3-dev gcc -v elif [ "${{ matrix.os }}" == "macos-latest" ]; then brew install python@3.12 || true @@ -330,8 +330,7 @@ jobs: cmake \ libssl-dev \ python3.8-dev \ - ccache \ - fftw3-dev + ccache gcc -v cd - name: Run the test in docker From 410dcf281e516000bec2293cccab0145645382ba Mon Sep 17 00:00:00 2001 From: Thomas BAUDIER Date: Wed, 5 Feb 2025 16:07:44 +0100 Subject: [PATCH 65/96] Change version of itk to deal with ubuntu 24.04 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4de0212d3..9cffc5452 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: env: ROOT_VERSION: 'v6-32-02' GEANT4_VERSION: 'v11.2.1' - ITK_VERSION: 'v5.3.0' + ITK_VERSION: 'v5.4.2' ROOT_DIR: $(HOME)/software/root GEANT4_DIR: $(HOME)/software/geant4 From 399ffbdedeeaf30d7712d2683ab9ec4e55804031 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 18 Feb 2025 13:28:22 +0100 Subject: [PATCH 66/96] Update GateSpatialResolution.cc Adding fwhmZdist --- source/digits_hits/src/GateSpatialResolution.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index 9b33e31cf..7ea296369 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -226,7 +226,7 @@ void GateSpatialResolution::Digitize(){ if (m_fwhmYdistrib) stddevY = m_fwhmYdistrib->Value(P.y() * mm); else if (fwhmY) stddevY = fwhmY / GateConstants::fwhm_to_sigma; - if (m_fwhmZdistrib) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma;// TODO! stddevZ = m_fwhmZdistrib->Value(P.z() * mm); + if (m_fwhmZdistrib) stddevZ = m_fwhmZdistrib->Value(P.z() * mm); else if (fwhmZ) stddevZ = fwhmZ / GateConstants::fwhm_to_sigma; } From af1cb9c59ffa2657945af248d01b40676c82e814 Mon Sep 17 00:00:00 2001 From: kochebina Date: Tue, 7 Jan 2025 16:27:16 +0100 Subject: [PATCH 67/96] Patch for Readout --- source/digits_hits/src/GateReadout.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/digits_hits/src/GateReadout.cc b/source/digits_hits/src/GateReadout.cc index 33e8a077b..36d40bb9a 100644 --- a/source/digits_hits/src/GateReadout.cc +++ b/source/digits_hits/src/GateReadout.cc @@ -165,6 +165,10 @@ void GateReadout::SetReadoutParameters() if (m_system==NULL) G4Exception( "GateReadout::Digitize", "Digitize", FatalException, "Failed to get the system corresponding to that processor chain. Abort.\n"); // Get the array component corresponding to the crystal level using the name 'crystal' + if(m_system->GetName()== "systems/scanner") + GateError( " *** ERROR*** GateReadout::Digitize. The TakeEnergyCentroid policy cannot be used with \"scanner\" system. Please use other system"); + + GateArrayComponent* m_crystalComponent = m_system->FindArrayComponent("crystal"); if (m_crystalComponent==NULL) G4Exception( "GateReadout::Digitize", "Digitize", FatalException, "Failed to get the array component corresponding to the crystal. Abort.\n"); From 53b6151e7775ebcb822f08200f4cc88bff5713b7 Mon Sep 17 00:00:00 2001 From: kochebina Date: Tue, 7 Jan 2025 11:54:29 +0100 Subject: [PATCH 68/96] Add diff runs for Coincidences --- source/digits_hits/include/GateToRoot.hh | 42 +++++++++++++++---- source/digits_hits/src/GateToRoot.cc | 2 +- source/digits_hits/src/GateToRootMessenger.cc | 4 +- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/source/digits_hits/include/GateToRoot.hh b/source/digits_hits/include/GateToRoot.hh index ff4a3562f..d26384c43 100644 --- a/source/digits_hits/include/GateToRoot.hh +++ b/source/digits_hits/include/GateToRoot.hh @@ -163,7 +163,8 @@ public: m_CCFlag(CCFlag), m_collectionName(aCollectionName), m_collectionID(-1), - m_signlesCommands(0){} + m_singlesCommands(0), + m_coinsCommands(0){} virtual inline ~VOutputChannel() {} @@ -179,8 +180,9 @@ public: inline G4bool GetCCFlag(){return m_CCFlag;}; - inline void AddSinglesCommand() { m_signlesCommands++; }; + inline void AddSinglesCommand() { m_singlesCommands++; }; + inline void AddCoincidencesCommand() { m_coinsCommands++; }; inline void SetVerboseLevel(G4int val) { nVerboseLevel = val; }; @@ -190,7 +192,8 @@ public: G4String m_collectionName; G4int m_collectionID; - G4int m_signlesCommands; + G4int m_singlesCommands; + G4int m_coinsCommands; }; @@ -218,7 +221,7 @@ public: if( digitizerMgr->m_SDlist.size()==1 ) { - if(m_signlesCommands==0) + if(m_singlesCommands==0) { treeName = m_collectionName.substr(0, m_collectionName.find("_")); @@ -234,7 +237,7 @@ public: if(runID>0) treeName = treeName+"_run"+std::to_string(runID); - + //G4cout<<"!!!! "<< runID <<" "<m_SDlist.size()==1 ) + { + + if(m_coinsCommands==0) + { + + treeName = m_collectionName.substr(0, m_collectionName.find("_")); + + } + else + treeName = m_collectionName; + } + else + treeName = m_collectionName; + + G4int runID=GateRunManager::GetRunManager()->GetCurrentRun()->GetRunID(); + if(runID>0) + treeName = treeName+"_run"+std::to_string(runID); + + m_tree = new GateCoincTree(treeName); m_tree->Init(m_buffer); } } diff --git a/source/digits_hits/src/GateToRoot.cc b/source/digits_hits/src/GateToRoot.cc index 44061a3d8..269b33879 100644 --- a/source/digits_hits/src/GateToRoot.cc +++ b/source/digits_hits/src/GateToRoot.cc @@ -1053,7 +1053,7 @@ void GateToRoot::RecordDigitizer(const G4Event *) { if(m_outputChannelList[i]->m_collectionID<0) m_outputChannelList[i]->m_collectionID=GetCollectionID(m_outputChannelList[i]->m_collectionName); - //G4cout<m_collectionName<<" "<< m_outputChannelList[i]->m_collectionID<<" "<< m_outputChannelList[i]->m_outputFlag<m_collectionName<<" "<< m_outputChannelList[i]->m_collectionID<<" "<< m_outputChannelList[i]->m_outputFlag<RecordDigitizer(); } diff --git a/source/digits_hits/src/GateToRootMessenger.cc b/source/digits_hits/src/GateToRootMessenger.cc index 03b1e34f7..39fd07ca4 100644 --- a/source/digits_hits/src/GateToRootMessenger.cc +++ b/source/digits_hits/src/GateToRootMessenger.cc @@ -339,7 +339,7 @@ void GateToRootMessenger::ExecuteOutputChannelCmd(G4UIcommand* command, G4String digitizer->m_recordFlag=true; //Setting flag in the digitizerMgr - //G4cout<<"ExecuteOutputChannelCmd "<m_collectionName<m_collectionName<m_collectionName, "Singles")) { m_outputChannelList[i]->AddSinglesCommand(); @@ -348,6 +348,8 @@ void GateToRootMessenger::ExecuteOutputChannelCmd(G4UIcommand* command, G4String } if (G4StrUtil::contains(m_outputChannelList[i]->m_collectionName, "Coincidences")) { + m_outputChannelList[i]->AddCoincidencesCommand(); + if(OutputChannelCmdList[i]->GetNewBoolValue(newValue)) digitizerMgr->m_recordCoincidences=OutputChannelCmdList[i]->GetNewBoolValue(newValue); } From de81eb1b76db53c90041427f261fc7271dc772a9 Mon Sep 17 00:00:00 2001 From: kochebina Date: Mon, 6 Jan 2025 14:00:41 +0100 Subject: [PATCH 69/96] For Gate 9.4.1 release --- .github/workflows/main.yml | 4 +-- CMakeLists.txt | 7 ++-- Gate.cc | 4 +-- readme.md | 2 +- release_notes/v9.4.1.txt | 57 +++++++++++++++++++++++++++++++++ source/docker/Generate-9.4.1.sh | 23 +++++++++++++ source/docker/README.md | 8 ++--- source/docker/runAll.sh | 3 +- source/docker/vGate.sh | 4 +-- 9 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 release_notes/v9.4.1.txt create mode 100755 source/docker/Generate-9.4.1.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9cffc5452..9f520d8bc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,8 +24,8 @@ jobs: env: ROOT_VERSION: 'v6-32-02' - GEANT4_VERSION: 'v11.2.1' ITK_VERSION: 'v5.4.2' + GEANT4_VERSION: 'v11.3.0' ROOT_DIR: $(HOME)/software/root GEANT4_DIR: $(HOME)/software/geant4 @@ -338,5 +338,5 @@ jobs: mkdir gate_benchmarks export GIT_SSL_NO_VERIFY=1 git clone --recursive https://github.com/OpenGATE/GateBenchmarks.git gate_benchmarks - docker run --rm -e "TEST=${{ matrix.strategy_name }}" -v $GITHUB_WORKSPACE:/src -v $GITHUB_WORKSPACE/gate_benchmarks:/home tbaudier/gatebenchmarks:9.4 /home/.github/workflows/runTest.sh + docker run --rm -e "TEST=${{ matrix.strategy_name }}" -v $GITHUB_WORKSPACE:/src -v $GITHUB_WORKSPACE/gate_benchmarks:/home tbaudier/gatebenchmarks:9.4.1 /home/.github/workflows/runTest.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 90c7771ea..4ee11721e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,14 +312,13 @@ MESSAGE("Your current Geant4 version is ${Geant4_VERSION}") #========================================================= # Display message about this version -MESSAGE("IMPORTANT! This version of GATE (9.4) has still some traces of passage for new digitizer.") +MESSAGE("IMPORTANT! This version of GATE (9.4.1) has still some traces of passage for new digitizer.") MESSAGE("Please, be aware that some of functionalities are NOT YET re-implemented: ") -MESSAGE("- Coincidence digitizer modules (combining of several Coincidence Sorters)") MESSAGE("- Output: Sinogram, Ecat7, LMF") MESSAGE("- ARF may work not properly yet") MESSAGE("We apologize for this inconvenience and kindly ask for your patience.") -MESSAGE("This functionalities will be added during 2024.") -MESSAGE("Meanwhile, please, use Gate 9.3") +MESSAGE("This functionalities will be added during 2025.") +MESSAGE("Meanwhile, please, use Gate 9.4") diff --git a/Gate.cc b/Gate.cc index ca7bbdec8..baca74917 100644 --- a/Gate.cc +++ b/Gate.cc @@ -158,7 +158,7 @@ void welcome() { GateMessage("Core", 0, G4endl); GateMessage("Core", 0, "*******************************************************" << G4endl); - GateMessage("Core", 0, " GATE version 9.4 (2024)" << G4endl); + GateMessage("Core", 0, " GATE version 9.4.1 (2025)" << G4endl); GateMessage("Core", 0, " Copyright : OpenGATE Collaboration" << G4endl); GateMessage("Core", 0, " Reference : Phys. Med. Biol. 49(19) 4543-4561 2004 " << G4endl); GateMessage("Core", 0, " Reference : Phys. Med. Biol. 56(4) 881-901 2011 " << G4endl); @@ -256,7 +256,7 @@ int main( int argc, char* argv[] ) break; case 'v': ss << G4VERSION_MAJOR << "." << G4VERSION_MINOR << "." << G4VERSION_PATCH; - std::cout << "Gate version is 9.4 ; Geant4 version is " << ss.str() << std::endl; + std::cout << "Gate version is 9.4.1; Geant4 version is " << ss.str() << std::endl; exit(0); break; case 'a': diff --git a/readme.md b/readme.md index e8d0d2957..a29ee5a76 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,7 @@ More details : http://www.opengatecollaboration.org Documentation : https://opengate.readthedocs.io -* The stable version is tag 9.4: https://github.com/OpenGATE/Gate/tree/v9.4 with Geant4 11.2.1 +* The stable version is tag 9.4.1: https://github.com/OpenGATE/Gate/tree/v9.4.1 with Geant4 11.3.0 * The current development version is branch 'develop' (default): http://github.com/OpenGATE/Gate/tree/develop * [Benchmarks](https://github.com/OpenGATE/GateBenchmarks) * [Examples](https://github.com/OpenGATE/GateContrib) diff --git a/release_notes/v9.4.1.txt b/release_notes/v9.4.1.txt new file mode 100644 index 000000000..8eab41e88 --- /dev/null +++ b/release_notes/v9.4.1.txt @@ -0,0 +1,57 @@ +# *ooooOOOO0000OOOOoooo* # +# # +# GATE v9.4.1 # +# # +# 02/2025 # +# # +# *ooooOOOO0000OOOOoooo* # + + +This version is intended to be used with Geant4 11.3.0 only. +Gate cannot be compiled with earlier Geant4 versions. +It *may* works with other ROOT, ITK, libtorch version but it is not tested. + +Dependencies: +- Geant4: v11.3.0 (cxx17 is required) +- ROOT: v6-32-08 (must be compiled with -DCMAKE_CXX_STANDARD=17) +- ITK: v5.2.0 (with RTK enabled) +- libtorch: v1.10.1 + + +----------------- +Main new features +----------------- + +- Bug corrections: +1) Coincidence Sorter: Remove "keep" options in multiple policy PR #703 +2) Init value for Energy Resolution module PR #699 +3) Coincidence Sorter: Option for removal of oblique coincidences (setDeltaZMax) #700 + +From 9.4 version: +1) Some of functionalities are temporarily disabled: + - Outputs: Sino, LMF, Ecat7 + +New features: +1) Option to save Hits from several sensitive detectors in the same ROOT tree +2) Generalisation of Spatial resolution (x,sigma(x)) +3) Coincidence digitizers added (Multiples Killer, Buffer, Time Difference) +4) New Digitizer Module : Virtal Segmentation (for Monolithic crystal) +5) + + +- additional Benchmarks +https://github.com/OpenGATE/GateBenchmarks + +---------- +Gate Tools +---------- + +------------- +Documentation +------------- + +GATE home page: http://www.opengatecollaboration.org +GATE documentation: https://opengate.readthedocs.io +GATE examples: https://github.com/OpenGATE/GateContrib +GATE benchmarks: https://github.com/OpenGATE/GateBenchmarks +GATE tools: https://github.com/OpenGATE/GateTools diff --git a/source/docker/Generate-9.4.1.sh b/source/docker/Generate-9.4.1.sh new file mode 100755 index 000000000..6555cba81 --- /dev/null +++ b/source/docker/Generate-9.4.1.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +#Variables to modify +Repository=opengatecollaboration +ROOT_Version=v6-24-06 +CLHEP_Version=2.4.6.0 +Geant4_Version=11.3.0 +Gate_Version=9.4.1 + +#Variables to preserve +Geant4_Tag=$Repository/geant4:$Geant4_Version +Gate_Tag=$Repository/gate:$Gate_Version-docker + +docker build -t $Geant4_Tag -f DockerFileGeant \ + --build-arg ROOT_Version=$ROOT_Version \ + --build-arg CLHEP_Version=$CLHEP_Version \ + --build-arg Geant4_Version=v$Geant4_Version . +#docker push $Geant4_Tag +# +#docker build -t $Gate_Tag -f DockerFileGate \ +# --build-arg Geant4_Version=$Geant4_Tag \ +# --build-arg Gate_Version=v$Gate_Version . +#docker push $Gate_Tag diff --git a/source/docker/README.md b/source/docker/README.md index b0e218266..1806e88eb 100644 --- a/source/docker/README.md +++ b/source/docker/README.md @@ -10,7 +10,7 @@ login: `docker login` [build and use] * build: - * `docker build -t opengatecollaboration/geant4:11.2.1 -f DockerFileGeant --build-arg ROOT_Version=v6-24-06 --build-arg Geant4_Version=v11.2.1 .` + * `docker build -t opengatecollaboration/geant4:11.3.0 -f DockerFileGeant --build-arg ROOT_Version=v6-24-06 --build-arg Geant4_Version=v11.3.0 .` * push: * `docker push opengatecollaboration/geant4:$version` * interactive: @@ -18,7 +18,7 @@ login: `docker login` Where: -* `$version` is `11.2.1` for gate `9.4` +* `$version` is `11.3.0` for gate `9.4.1` # Second image Gate ## Docker for gate @@ -29,7 +29,7 @@ login: `docker login` [build and use] * build: - * `docker build -t opengatecollaboration/gate:9.4 -f DockerFileGate --build-arg Geant4_Version=opengatecollaboration/geant4:11.2.1 --build-arg Gate_Version=v9.4 .` + * `docker build -t opengatecollaboration/gate:9.4.1 -f DockerFileGate --build-arg Geant4_Version=opengatecollaboration/geant4:11.3.0 --build-arg Gate_Version=v9.4.1 .` * push: * `docker push opengatecollaboration/gate:$version` * run command: @@ -41,4 +41,4 @@ You can just install docker and then create an alias in your configuration * ```echo "alias Gate='docker run -i --rm -v $PWD:/APP opengatecollaboration/gate:$version'" >> ~/.bashrc``` Where: -* `$version=9.3` +* `$version=9.4.1` diff --git a/source/docker/runAll.sh b/source/docker/runAll.sh index cfed8a138..b2b86ef70 100755 --- a/source/docker/runAll.sh +++ b/source/docker/runAll.sh @@ -3,4 +3,5 @@ ./Generate-8.1.sh ./Generate-8.2.sh ./Generate-9.0.sh -./Generate-9.1.sh \ No newline at end of file +./Generate-9.1.sh +./Generate-9.4.1.sh diff --git a/source/docker/vGate.sh b/source/docker/vGate.sh index cf67fbdf5..242716376 100644 --- a/source/docker/vGate.sh +++ b/source/docker/vGate.sh @@ -69,7 +69,7 @@ make cd cd Software/Geant4 mkdir src bin install data -git clone -b v11.2.1 https://github.com/Geant4/geant4.git src +git clone -b v11.3.0 https://github.com/Geant4/geant4.git src cd bin ccmake ../src -DGEANT4_INSTALL_DATA=ON -DGEANT4_BUILD_MULTITHREADED=OFF -DGEANT4_INSTALL_DATADIR=/home/vgate/Software/Geant4/data -DCMAKE_INSTALL_PREFIX=/home/vgate/Software/Geant4/install -DGEANT4_BUILD_MULTITHREADED=OFF -DGEANT4_USE_QT=ON -DGEANT4_USE_OPENGL_X11=ON make install @@ -101,7 +101,7 @@ echo 'source /home/vgate/Software/Geant4/install/bin/geant4.sh' >> /home/vgate/. cd cd Software/Gate mkdir src bin -git clone -b v9.4 https://github.com/OpenGATE/Gate.git src +git clone -b v9.4.1 https://github.com/OpenGATE/Gate.git src cd bin ccmake ../src -DGATE_USE_RTK=ON -DGATE_USE_TORCH=ON -DTorch_DIR=/home/vgate/Software/libtorch/share/cmake/Torch -DGATE_COMPILE_GATEDIGIT=ON make From c1b0aeb32968637fe693f345c88d0725ac0036a4 Mon Sep 17 00:00:00 2001 From: kochebina <42149373+kochebina@users.noreply.github.com> Date: Fri, 7 Feb 2025 10:02:56 +0100 Subject: [PATCH 70/96] Doc for v9.4.1 --- docs/compilation_instructions.rst | 30 +++++++++++++++--------------- docs/installation.rst | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/compilation_instructions.rst b/docs/compilation_instructions.rst index 54526e18c..38eb952a5 100644 --- a/docs/compilation_instructions.rst +++ b/docs/compilation_instructions.rst @@ -1,6 +1,6 @@ .. _compilation_instructions-label: -Compiling GATE V9.4 +Compiling GATE V9.4.1 ===================== @@ -35,9 +35,9 @@ Direct dependencies of GATE --------------------------- -For compiling GATE V9.4, the required dependencies are +For compiling GATE V9.4.1, the required dependencies are -* Geant4 11.2.1 (available in http://geant4.web.cern.ch/geant4/support/download.shtml). +* Geant4 11.3.0 (available in http://geant4.web.cern.ch/geant4/support/download.shtml). * ROOT (ROOT 6.xx) # still required, but it may become optional in the future Geant4 needs to be compiled. ROOT is avalaible as binary on some platform (or has to be compiled) @@ -133,19 +133,19 @@ In some configuration, the following path should also be set :: We recommend you to use libtorch version 1.10.1 but other version may works. You can download libtorch from (pytorch)[https://pytorch.org/get-started/locally], select "LibTorch" in the matrix. -GATE V9.4 ---------- +GATE V9.4.1 +----------- -First, download the GATE sources at this address: https://github.com/OpenGATE/Gate/archive/v9.4.zip +First, download the GATE sources at this address: https://github.com/OpenGATE/Gate/archive/v9.4.1.zip Unzip the downloaded file:: - unzip Gate-9.4.zip + unzip Gate-9.4.1.zip Alternatively, if you are familiar with git, then instead of downloading and extracting the tar file, you can also clone the sources from github and check out the *v9.4* release tag. git clone https://github.com/OpenGATE/Gate.git Gate cd Gate - git checkout v9.4 + git checkout v9.4.1 Create two directories to build and install GATE:: @@ -158,7 +158,7 @@ Move into the GATE build directory:: Run ccmake as follows:: - ccmake ../Gate-9.4 + ccmake ../Gate-9.4.1 You need to change the *CMAKE_INSTALL_PREFIX*, it should be set to the install directory (defined above). The default given by CMake is */usr/local*; if you have root/sudo permissions on your machine then it's possible to install Gate there, but it's not recommended, especially if you need to work with more than one version of Gate (for instance, if you want to do development on Gate, or if you want to verify that a new release is compatible with the old release that you have been using). You should get something like this (the screen shot is taken from the 8.0 release, the only difference is the version number): @@ -221,7 +221,7 @@ This file should be defined as follows: setenv PATH ${PATH}:/PATH_TO/2.3.4.3/CLHEP/bin setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/PATH_TO/2.3.4.3/CLHEP/lib -Save this file in */PATH_TO/gate_v9.4-install/bin*. Finally, before to start a GATE session:: +Save this file in */PATH_TO/gate_v9.4.1-install/bin*. Finally, before to start a GATE session:: source /PATH_TO/gate-install/bin/gate_env.sh @@ -361,9 +361,9 @@ Installation of cluster tools jobsplitter ~~~~~~~~~~~ -Go to /PATH_TO/gate_v9.4/cluster_tools/jobsplitter:: +Go to /PATH_TO/gate_v9.4.1/cluster_tools/jobsplitter:: - cd /PATH_TO/gate_v9.4/cluster_tools/jobsplitter + cd /PATH_TO/gate_v9.4.1/cluster_tools/jobsplitter Make sure ROOT and Geant4 environment variables are set:: @@ -376,12 +376,12 @@ Compile:: Copy the gjs executable file to the correct place:: - cp /PATH_TO/gate_v9.4/cluster_tools/jobsplitter/gjs /PATH_TO/gate_v9.4-install/bin + cp /PATH_TO/gate_v9.4.1/cluster_tools/jobsplitter/gjs /PATH_TO/gate_v9.4.1-install/bin filemerger ~~~~~~~~~~~ -Go to /PATH_TO/gate_v9.4/cluster_tools/filemerger +Go to /PATH_TO/gate_v9.4.1/cluster_tools/filemerger Make sure ROOT and Geant4 environment variables are set:: source /PATH_TO/root_v6.XX/bin/thisroot.sh @@ -393,6 +393,6 @@ Compile:: Copy the gjs executable file to the correct place:: - cp /PATH_TO/gate_v9.4/cluster_tools/filemerger/gjm /PATH_TO/gate_v9.4-install/bin + cp /PATH_TO/gate_v9.4.1/cluster_tools/filemerger/gjm /PATH_TO/gate_v9.4.1-install/bin diff --git a/docs/installation.rst b/docs/installation.rst index 6615dd0fe..6467c51b6 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -1,7 +1,7 @@ .. _installation_guide-label: -Installation Guide V9.4 -======================= +Installation Guide V9.4.1 +========================= .. contents:: Table of Contents :depth: 15 From a62f6d30830ba07586c3f9b115065c8da7e2a245 Mon Sep 17 00:00:00 2001 From: kochebina Date: Thu, 13 Feb 2025 10:45:08 +0100 Subject: [PATCH 71/96] vGate macro update --- source/docker/vGate.sh | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/source/docker/vGate.sh b/source/docker/vGate.sh index 242716376..19e8fbcdd 100644 --- a/source/docker/vGate.sh +++ b/source/docker/vGate.sh @@ -4,7 +4,11 @@ sudo apt update sudo apt install build-essential -sudo apt-get install -y git \ +sudo apt-get install -y + gcc \ + git \ + make \ + binutils \ cmake \ cmake-curses-gui \ freeglut3-dev \ @@ -18,8 +22,17 @@ sudo apt-get install -y git \ git-lfs \ libssl-dev \ libxml2-dev \ - fftw3-dev - + libfftw3-dev + libx11-dev \ + libtbb-dev \ + libxext-dev \ + qtbase5-dev \ + qt5-qmake \ + python3.8-dev \ + ccache \ + libfftw3-dev + + cd mkdir Software cd Software @@ -35,7 +48,7 @@ cd .. cd cd Software/ITK mkdir src bin -git clone -b v5.2.1 https://github.com/InsightSoftwareConsortium/ITK.git src +git clone -b v5.4.2 https://github.com/InsightSoftwareConsortium/ITK.git src cd bin ccmake ../src -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON -DModule_ITKVtkGlue=ON #+path to VTK make @@ -61,10 +74,15 @@ cd .. cd cd Software/root mkdir src bin -git clone -b v6-26-08 https://github.com/root-project/root.git src +git clone -b v6-32-02 https://github.com/root-project/root.git src cd bin -ccmake ../src -Dpython=OFF -make +cmake ../src -DCMAKE_CXX_STANDARD=17 \ + -Dpython=OFF \ + -Dpyroot=OFF \ + -Dclad=OFF \ + -Dxrootd=OFF \ + -DCMAKE_INSTALL_PREFIX=$HOME/Software/root/install +make install cd cd Software/Geant4 From 2e80d5d96f801845ffbd69f9b47a5f1338ea1056 Mon Sep 17 00:00:00 2001 From: Thomas Deschler Date: Wed, 12 Feb 2025 13:20:08 +0100 Subject: [PATCH 72/96] Fixing CMake configuration issues with Geant4 11.3.0. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ee11721e..e009bc4b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,8 +98,8 @@ STRING(REGEX REPLACE "(.*)[.](.*)[.](.*)" "\\3" G4VERSION_PATCH ${Geant4_VERSION #MESSAGE(${G4VERSION_MAJOR}) #MESSAGE(${G4VERSION_MINOR}) #MESSAGE(${G4VERSION_PATCH}) -IF(NOT ${G4VERSION_MAJOR}.${G4VERSION_MINOR} EQUAL 11.2) - MESSAGE("Warning! This GATE version is not validated for Geant4 ${G4VERSION_MAJOR}.${G4VERSION_MINOR} distribution. Please use Geant4 11.2 distribution instead.") +IF(NOT ${G4VERSION_MAJOR}.${G4VERSION_MINOR} EQUAL 11.3) + MESSAGE("Warning! This GATE version is not validated for Geant4 ${G4VERSION_MAJOR}.${G4VERSION_MINOR} distribution. Please use Geant4 11.3 distribution instead.") ENDIF() #========================================================= From dbdc4ffeeabfd4866892c450c2d970cabe255346 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Tue, 18 Feb 2025 11:48:20 +0100 Subject: [PATCH 73/96] Update digitizer_and_detector_modeling.rst Documentation of "Confinement with truncated Gaussian distribution" and "Spatial resolution with 1 and 2 dimensional distributions". --- docs/digitizer_and_detector_modeling.rst | 53 +++++++++++++++++------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/docs/digitizer_and_detector_modeling.rst b/docs/digitizer_and_detector_modeling.rst index 1eb4b4421..4b89e50d0 100644 --- a/docs/digitizer_and_detector_modeling.rst +++ b/docs/digitizer_and_detector_modeling.rst @@ -512,7 +512,7 @@ or if resolution is varying for X, Y and Z:: /gate/digitizerMgr//SinglesDigitizer//spatialResolution/fwhmY 3.0 mm /gate/digitizerMgr//SinglesDigitizer//spatialResolution/fwhmZ 1.0 mm -In case if the position obtained after applying a Gaussian blurring exceeds the limits of the original volume, it is set to the surface of that volume (ex, crystal) or surface of a group of volumes (ex, block of crystals). For example, in SPECT the final position should be located within the original detector volume (smallest volume), in this case one should apply the following commande:: +In case if the position obtained after applying a Gaussian blurring exceeds the limits of the original volume, it is set to the surface of that volume (ex, crystal) or surface of a group of volumes (ex, block of crystals). For example, in SPECT the final position should be located within the original detector volume (smallest volume), in this case one should apply the following command:: /gate/digitizerMgr//SinglesDigitizer//spatialResolution/confineInsideOfSmallestElement true @@ -524,20 +524,36 @@ BEWARE: This relocation procedure is validated only for the first group level of /gate/digitizerMgr/crystal/SinglesDigitizer/Singles/spatialResolution/fwhm 1.0 mm /gate/digitizerMgr/crystal/SinglesDigitizer/Singles/spatialResolution/confineInsideOfSmallestElement true +The option for a Gaussian distribution truncated at the crystal's edge has been introduced to preserve the standard deviation of the hits positioned close to the edge of the crystal. This option is particularly useful to confine elements in large crystals without compromising the standard deviation (and FWHM) of the spatial blurring. + +BEWARE: The confined and the use of the truncated Gaussian are default options. Use the following commands to activate or deactivate both options: + +**Example**:: + +/gate/digitizerMgr/crystal/SinglesDigitizer/Singles/spatialResolution/confineInsideOfSmallestElement true +/gate/digitizerMgr/pseudoCrystal/SinglesDigitizer/Singles/spatialResolution/useTruncatedGaussian true + + **Configuring Spatial Resolution with 1D and 2D Distributions**:: -This approach is particularly essential for monolithic crystal detectors, where factors like edge effects and interaction positions significantly may influence spatial resolution. +This approach is particularly essential for monolithic crystal detectors, where factors like edge effects and interaction positions significantly may influence spatial resolution. The spatial distribution resolution allows to select what axis will be using such distribution. Currently only one distribution is allowed for all axis. + Here is an example of how to configure this in a macro file: **Example for 2D distribution**:: - /gate/distributions/name my_distrib2D - /gate/distributions/insert File - /gate/distributions/my_distrib2D/setFileName Lut(X,Y).txt - /gate/distributions/my_distrib2D/readMatrix2d - /gate/digitizerMgr/crystalUnit/SinglesDigitizer/Singles/insert spatialResolution - /gate/digitizerMgr/crystalUnit/SinglesDigitizer/Singles/spatialResolution/fwhmXYdistrib2D my_distrib2D +The axis are selected with a "nameAxis". IMPORTANT NOTE: Only the "XY" axis are available: + +/gate/distributions/name my_distrib2D +/gate/distributions/insert File +/gate/distributions/my_distrib2D/setFileName data/my_stddev_distribuion_file.txt +/gate/distributions/my_distrib2D/readMatrix2d +/gate/digitizerMgr/pseudoCrystal/SinglesDigitizer/Singles/insert spatialResolution +/gate/digitizerMgr/pseudoCrystal/SinglesDigitizer/Singles/spatialResolution/nameAxis XY +/gate/digitizerMgr/pseudoCrystal/SinglesDigitizer/Singles/spatialResolution/fwhmDistrib2D my_distrib2D + + **Example for 1D distribution**:: /gate/distributions/name my_distrib1D @@ -549,22 +565,27 @@ Here is an example of how to configure this in a macro file: - - These commands allow for more precise control over the spatial resolution by using predefined distributions for the X and Y axes. BEWARE : The file for 2D Distribution should be structured such that: --The first line contains the x values. +-The first line contains the values of the x position. See the example below where the first line has values from -29.5 to 29.5 in this example for a 59 mm crystal. --Each subsequent line begins with a y value followed by the standard deviation (stddev) values corresponding to each x value and y value pair. +-Each subsequent line begins with the value of the y position followed by the standard deviation (stddev) values corresponding to each x value and y value pair. **Example**:: --29.50 -28.50 -27.50 --29.50 9.62 13.66 10.22 --28.50 11.38 11.18 10.23 --27.50 12.82 10.43 9.70 +-29.50 -22.94 -16.39 -9.83 -3.28 3.28 9.83 16.39 22.94 29.50 +-29.50 8.05 5.1 4.24 4.23 4.23 4.19 4.56 4.6 5.02 7.68 +-22.94 4.76 2.39 2.31 2.35 2.4 2.35 2.36 2.32 2.44 4.52 +-16.39 4.53 2.45 2.28 2.39 2.35 2.36 2.46 2.46 2.55 4.52 +-9.83 4.38 2.35 2.13 2.09 2.13 2.07 2.14 2.11 2.33 4.44 +-3.28 4.18 2.18 1.97 1.96 1.97 1.97 2.03 2.02 2.19 4.2 +3.28 4.2 2.27 2.04 2.01 2.03 2.06 1.98 1.97 2.24 4.13 +9.83 4.24 2.4 2.23 2.24 2.21 2.28 2.22 2.21 2.35 4.36 +16.39 4.32 2.59 2.47 2.55 2.56 2.52 2.45 2.42 2.55 4.51 +22.94 4.07 2.32 2.33 2.34 2.34 2.27 2.36 2.29 2.4 4.3 +29.50 7.2 4.58 4.07 3.9 3.89 3.83 4.09 3.99 4.47 7.08 Energy Framing ^^^^^^^^^^^^^^ From 8e04350d5e3bbfc59530db9b2acc0e9f901d3b69 Mon Sep 17 00:00:00 2001 From: tbaudier Date: Fri, 10 Mar 2023 14:03:31 +0100 Subject: [PATCH 74/96] Update GateMDBCreators.cc Change element->GetNumberOfElements() to element->GetNumberOfIsotopes() @narbor --- source/geometry/src/GateMDBCreators.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/geometry/src/GateMDBCreators.cc b/source/geometry/src/GateMDBCreators.cc index 268bdffc9..567b79184 100644 --- a/source/geometry/src/GateMDBCreators.cc +++ b/source/geometry/src/GateMDBCreators.cc @@ -70,7 +70,7 @@ G4Element* GateCompoundElementCreator::Construct() components[i]->AddToElement(element); double f=0.0; - for(unsigned int j=0; jGetNumberOfElements(); j++) { + for(unsigned int j=0; jGetNumberOfIsotopes(); j++) { double frac = element->GetRelativeAbundanceVector()[j]; f+=frac; if (frac<0.0) { From 815458bfbaa1342265c27161944c21b621140378 Mon Sep 17 00:00:00 2001 From: Thomas BAUDIER Date: Wed, 25 Jun 2025 15:49:04 +0200 Subject: [PATCH 75/96] Remove ctest because it's not used anymore and lead to errors during CI --- .github/workflows/main.yml | 58 +------------------------------------- 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9f520d8bc..be995ba51 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -186,71 +186,15 @@ jobs: -DBUILD_TESTING=ON \ $GITHUB_WORKSPACE fi - - name: Configure CTest - if: steps.cache_gate_dependencies.outputs.cache-hit == 'true' - run: | - cd $HOME - cat > dashboard.cmake << EOF - set(CTEST_SITE "Github.macos-latest.none") - file(TO_CMAKE_PATH "$HOME" CTEST_DASHBOARD_ROOT) - file(TO_CMAKE_PATH "$GITHUB_WORKSPACE" CTEST_SOURCE_DIRECTORY) - file(TO_CMAKE_PATH "$HOME/build" CTEST_BINARY_DIRECTORY) - set(dashboard_source_name "$GITHUB_REPOSITORY") - if("$GITHUB_REF" MATCHES "^refs/pull/") - set(branch "") - set(pr "-PR$GITHUB_REF") - set(dashboard_model "Experimental") - elseif("$GITHUB_REF" STREQUAL "refs/heads/develop") - set(branch "-develop") - set(pr "") - set(dashboard_model "Continuous") - else() - set(branch "-BRANCH$GITHUB_REF") - set(pr "") - set(dashboard_model "Experimental") - endif() - set(CTEST_BUILD_NAME "github_macos-latest.none-Build$GITHUB_RUN_NUMBER\${pr}\${branch}") - set(CTEST_UPDATE_VERSION_ONLY 1) - set(CTEST_TEST_ARGS \${CTEST_TEST_ARGS} PARALLEL_LEVEL \${PARALLEL_LEVEL}) - set(CTEST_CONFIGURATION_TYPE "Release") - set(CTEST_CMAKE_GENERATOR "Unix Makefiles") - set(CTEST_BUILD_FLAGS "\${CTEST_BUILD_FLAGS} -j4") - set(CTEST_CUSTOM_WARNING_EXCEPTION - \${CTEST_CUSTOM_WARNING_EXCEPTION} - # macOS Azure Pipelines - "ld: warning: text-based stub file" - ) - set(dashboard_no_clean 1) - set(ENV{CC} $(cCompiler)) - set(ENV{CXX} $(cxxCompiler)) - string(TIMESTAMP build_date "%Y-%m-%d") - message("CDash Build Identifier: \${build_date} \${CTEST_BUILD_NAME}") - message("CTEST_SITE = \${CTEST_SITE}") - ctest_start("\${dashboard_model}") - ctest_configure(CAPTURE_CMAKE_ERROR configure_errors RETURN_VALUE configure_Results) - ctest_build(NUMBER_ERRORS build_errors RETURN_VALUE build_Results) - ctest_submit(RETURN_VALUE submit_Results) - if ((NOT \${configure_errors} EQUAL 0) OR (NOT \${configure_Results} EQUAL 0)) - message( FATAL_ERROR "Configuration error" ) - endif() - if ((NOT \${build_errors} EQUAL 0) OR (NOT \${build_Results} EQUAL 0)) - message( FATAL_ERROR "Build error" ) - endif() - if (NOT \${submit_Results} EQUAL 0) - message( FATAL_ERROR "Submit error" ) - endif() - EOF - cat dashboard.cmake - name: Build Gate run: | if [ "${{ steps.cache_gate_dependencies.outputs.cache-hit }}" == 'true' ]; then cd $HOME/build - cp ../dashboard.cmake . export ROOTSYS=$HOME/software/root/install export PATH=${ROOTSYS}:${PATH} source $HOME/software/root/install/bin/thisroot.sh source $HOME/software/geant4/install/bin/geant4.sh - ctest -S dashboard.cmake -VV + make -j4 if [ ! $? -eq 0 ]; then exit 1 fi From be7b571b4163be7dca0e7c9540d31a584a632cb8 Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Wed, 5 Mar 2025 19:15:22 +0100 Subject: [PATCH 76/96] Do CheckIfEnoughLevelsAreDefined only once as requested in #622 --- source/digits_hits/src/GateSpatialResolution.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index 7ea296369..2ee12ffb5 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -126,6 +126,13 @@ void GateSpatialResolution::SetSpatialResolutionParameters() { void GateSpatialResolution::Digitize(){ if (m_IsFirstEntrance) { SetSpatialResolutionParameters(); + if (!m_system->CheckIfEnoughLevelsAreDefined()) + { + GateError( " *** ERROR*** GateSpatialResolution::Digitize. Not all defined geometry levels has their mother levels defined." + "(Ex.: for cylindricalPET, the levels are: rsector, module, submodule, crystal). If you have defined submodule, you have to have resector and module defined as well." + "Please, add them to your geometry macro in /gate/systems/cylindricalPET/XXX/attach YYY. Abort.\n"); + } + m_IsFirstEntrance = false; } @@ -154,12 +161,6 @@ void GateSpatialResolution::Digitize(){ if (m_system==NULL) G4Exception( "GateSpatialResolution::Digitize", "Digitize", FatalException, "Failed to get the system corresponding to that digitizer. Abort.\n"); - if (!m_system->CheckIfEnoughLevelsAreDefined()) - { - GateError( " *** ERROR*** GateSpatialResolution::Digitize. Not all defined geometry levels has their mother levels defined." - "(Ex.: for cylindricalPET, the levels are: rsector, module, submodule, crystal). If you have defined submodule, you have to have resector and module defined as well." - "Please, add them to your geometry macro in /gate/systems/cylindricalPET/XXX/attach YYY. Abort.\n"); - } m_systemDepth = m_system->GetTreeDepth(); From ed355b51ca29076156afdb58988e06ec82398e1c Mon Sep 17 00:00:00 2001 From: granadogmarc Date: Mon, 24 Mar 2025 10:49:50 +0100 Subject: [PATCH 77/96] Fix compilation issue in Spatial Resolution --- source/digits_hits/src/GateSpatialResolution.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/digits_hits/src/GateSpatialResolution.cc b/source/digits_hits/src/GateSpatialResolution.cc index 2ee12ffb5..f5e795ff0 100644 --- a/source/digits_hits/src/GateSpatialResolution.cc +++ b/source/digits_hits/src/GateSpatialResolution.cc @@ -124,6 +124,9 @@ void GateSpatialResolution::SetSpatialResolutionParameters() { void GateSpatialResolution::Digitize(){ + + GateVSystem* m_system = ((GateSinglesDigitizer*)this->GetDigitizer())->GetSystem(); + if (m_IsFirstEntrance) { SetSpatialResolutionParameters(); if (!m_system->CheckIfEnoughLevelsAreDefined()) @@ -156,7 +159,6 @@ void GateSpatialResolution::Digitize(){ - GateVSystem* m_system = ((GateSinglesDigitizer*)this->GetDigitizer())->GetSystem(); if (m_system==NULL) G4Exception( "GateSpatialResolution::Digitize", "Digitize", FatalException, "Failed to get the system corresponding to that digitizer. Abort.\n"); From d98c7937f0c5105bc3e9e323bb2ec6f23ee6653c Mon Sep 17 00:00:00 2001 From: Mathieu Dupont Date: Fri, 20 Jun 2025 14:48:03 +0000 Subject: [PATCH 78/96] Implement proper destructors for GateCoincidenceDigi and GateDigitizerMgr to ensure memory cleanup --- .../include/GateCoincidenceDigi.hh | 2 +- .../include/GateCoincidenceSorter.hh | 2 +- source/digits_hits/src/GateCoincidenceDigi.cc | 9 + .../digits_hits/src/GateCoincidenceSorter.cc | 346 +++++++++--------- source/digits_hits/src/GateDigitizerMgr.cc | 10 +- 5 files changed, 190 insertions(+), 179 deletions(-) diff --git a/source/digits_hits/include/GateCoincidenceDigi.hh b/source/digits_hits/include/GateCoincidenceDigi.hh index ac76ad8a7..65d8b485d 100644 --- a/source/digits_hits/include/GateCoincidenceDigi.hh +++ b/source/digits_hits/include/GateCoincidenceDigi.hh @@ -34,7 +34,7 @@ public: G4double itsOffsetWindow); //GateCoincidenceDigi(GateCoincidencePulse* coincidencePulse); GateCoincidenceDigi(const GateCoincidenceDigi& src); - inline ~GateCoincidenceDigi() {}; + ~GateCoincidenceDigi() ; inline void* operator new(size_t); inline void operator delete(void*); diff --git a/source/digits_hits/include/GateCoincidenceSorter.hh b/source/digits_hits/include/GateCoincidenceSorter.hh index 67446af2d..f5d8fbdc0 100644 --- a/source/digits_hits/include/GateCoincidenceSorter.hh +++ b/source/digits_hits/include/GateCoincidenceSorter.hh @@ -233,7 +233,7 @@ private: std::deque m_coincidenceDigis; // open coincidence windows - void ProcessCompletedCoincidenceWindow(GateCoincidenceDigi*); + bool ProcessCompletedCoincidenceWindow(GateCoincidenceDigi*); //TODO GND 2022 CC void ProcessCompletedCoincidenceWindow4CC(GateCoincidenceDigi *); diff --git a/source/digits_hits/src/GateCoincidenceDigi.cc b/source/digits_hits/src/GateCoincidenceDigi.cc index 914ca17f6..b7835e0a0 100644 --- a/source/digits_hits/src/GateCoincidenceDigi.cc +++ b/source/digits_hits/src/GateCoincidenceDigi.cc @@ -24,6 +24,15 @@ GateCoincidenceDigi::GateCoincidenceDigi(const void* itsMother) { } +GateCoincidenceDigi::~GateCoincidenceDigi() { + // G4cout << "GateCoincidenceDigi::~GateCoincidenceDigi() called" << Gateendl; + // delete all digis + std::vector::iterator iter; + for (iter = begin(); iter < end(); ++iter) { + delete *iter; + } + clear(); +} GateCoincidenceDigi::GateCoincidenceDigi(GateDigi *firstDigi, G4double itsCoincidenceWindow, diff --git a/source/digits_hits/src/GateCoincidenceSorter.cc b/source/digits_hits/src/GateCoincidenceSorter.cc index 2c1f24a4b..061068b77 100644 --- a/source/digits_hits/src/GateCoincidenceSorter.cc +++ b/source/digits_hits/src/GateCoincidenceSorter.cc @@ -43,7 +43,7 @@ GateCoincidenceSorter::GateCoincidenceSorter(GateDigitizerMgr* itsDigitizerMgr, m_minS (-1), m_maxDeltaZ ( -1), m_forceMinSecDifferenceToZero(false), - m_multiplesPolicy(kTakeWinnerIfAllAreGoods), + m_multiplesPolicy(kTakeWinnerIfAllAreGoods), m_allDigiOpenCoincGate(false), m_depth(1), m_presortBufferSize(256), @@ -144,20 +144,20 @@ void GateCoincidenceSorter::SetMultiplesPolicy(const G4String& policy) else if (policy=="takeWinnerIfOnlyOneGood") { m_multiplesPolicy= kTakeWinnerIfOnlyOneGood; - } - + } + //else if (policy=="keepAll") - // m_multiplesPolicy=kKeepAll; - else { + // m_multiplesPolicy=kKeepAll; + else { if(policy == "keepIfAllAreGoods") G4cout<<"WARNING (Coincidence Sorter): used policy keepIfAllAreGoods is outdated. Please, use takeWinnerIfAllAreGoods instead.\n"; else if (policy!="takeWinnerIfAllAreGoods" ) G4cout<<"WARNING : policy not recognized, using default : takeWinnerIfAllAreGoods\n"; - + m_multiplesPolicy= kTakeWinnerIfAllAreGoods;//kKeepIfAllAreGoods; - } + } } //------------------------------------------------------------------------------------------------------ @@ -170,10 +170,10 @@ void GateCoincidenceSorter::SetAcceptancePolicy4CC(const G4String &policy) m_acceptance_policy_4CC=kkeepIfMultipleVolumeIDsInvolved_CC; else if (policy=="keepIfMultipleVolumeNamesInvolved") m_acceptance_policy_4CC=kkeepIfMultipleVolumeNamesInvolved_CC; - else { + else { G4cout<<"WARNING : acceptance policy for CC not recognized, using default : kkeepIfMultipleVolumeNamesInvolved\n"; m_acceptance_policy_4CC=kkeepIfMultipleVolumeNamesInvolved_CC; - } + } } //------------------------------------------------------------------------------------------------------ @@ -182,7 +182,7 @@ void GateCoincidenceSorter::Digitize() { // G4cout<<"GateCoincidenceSorter::Digitize "<< GetOutputName() <GetSystem(); - } + } //G4cout<GetName()<m_outputDigiCollectionID; //G4cout<<"inputCollID "<size()>1){ if(m_coincidenceWindowJitter > 0.0) window = G4RandGauss::shoot(m_coincidenceWindow,m_coincidenceWindowJitter); - else - window = m_coincidenceWindow; + else + window = m_coincidenceWindow; if(m_offsetJitter > 0.0) offset = G4RandGauss::shoot(m_offset,m_offsetJitter); - else - offset = m_offset; + else + offset = m_offset; for(gpl_iter = IDCvector->begin();gpl_iter != IDCvector->end();gpl_iter++) { - digi = new GateDigi(**gpl_iter); + digi = new GateDigi(**gpl_iter); if(!isCoincCreated){ isCoincCreated=true; coincidence = new GateCoincidenceDigi(digi,window,offset); } else{ coincidence->push_back(new GateDigi(digi)); // add a copy so we can delete safely - delete digi; - } + delete digi; + } - } + } @@ -265,11 +265,14 @@ void GateCoincidenceSorter::Digitize() // ProcessCompletedCoincidenceWindow4CC(coincidence); } else{ - ProcessCompletedCoincidenceWindow(coincidence); - } - + auto is_stored = ProcessCompletedCoincidenceWindow(coincidence); + if (!is_stored) { + delete coincidence; // delete the coincidence if not stored + } } - return; + + } + return; } @@ -277,28 +280,28 @@ void GateCoincidenceSorter::Digitize() //------ put input digis in sorted input buffer---------- for(gpl_iter = IDCvector->begin();gpl_iter != IDCvector->end();gpl_iter++) { - // make a copy of the digi - digi = new GateDigi(**gpl_iter); + // make a copy of the digi + digi = new GateDigi(**gpl_iter); if(m_presortBuffer.empty()) - m_presortBuffer.push_back(digi); + m_presortBuffer.push_back(digi); else if(digi->GetTime() < m_presortBuffer.back()->GetTime()) // check that even isn't earlier than the earliest event in the buffer - { + { if(!m_presortWarning) GateWarning("Event is earlier than earliest event in coincidence presort buffer. Consider using a larger buffer (/setPresortBufferSize n, where n>256)"); - m_presortWarning = true; + m_presortWarning = true; m_presortBuffer.push_back(digi); // this will probably not cause a problem, but coincidences may be missed } else // put the event into the presort buffer in the right place - { - buf_iter = m_presortBuffer.begin(); + { + buf_iter = m_presortBuffer.begin(); while(digi->GetTime() < (*buf_iter)->GetTime()) - buf_iter++; - m_presortBuffer.insert(buf_iter, digi); + buf_iter++; + m_presortBuffer.insert(buf_iter, digi); // G4cout<<"presortBuffer filled in position "<GetTime()<GetTime()/ns<GetTime()<GetTime()/ns<IsAfterWindow(digi)) { - coincidence = m_coincidenceDigis.front(); + auto coincidence = m_coincidenceDigis.front(); - m_coincidenceDigis.pop_front(); + m_coincidenceDigis.pop_front(); - if(m_CCSorter==true){ - //TODO CC sorter - // ProcessCompletedCoincidenceWindow4CC(coincidence); - } - else{ - ProcessCompletedCoincidenceWindow(coincidence); + if (m_CCSorter == true) { + // TODO CC sorter + // ProcessCompletedCoincidenceWindow4CC(coincidence); + } else { + auto is_stored = ProcessCompletedCoincidenceWindow(coincidence); + if (!is_stored) { + delete coincidence; // delete the coincidence if not stored } - - } + } + } // add event to coincidences inCoincidence = false; coince_iter = m_coincidenceDigis.begin(); @@ -343,39 +347,35 @@ void GateCoincidenceSorter::Digitize() { if(m_coincidenceWindowJitter > 0.0) window = G4RandGauss::shoot(m_coincidenceWindow,m_coincidenceWindowJitter); - else - window = m_coincidenceWindow; + else + window = m_coincidenceWindow; if(m_offsetJitter > 0.0) offset = G4RandGauss::shoot(m_offset,m_offsetJitter); - else - offset = m_offset; + else + offset = m_offset; if(m_triggerOnlyByAbsorber==1){ if(((digi->GetVolumeID()).GetBottomCreator())->GetObjectName()==m_absorberSD){ - //if(digi->GetVolumeID().GetVolume(2)->GetName()==m_absorberDepth2Name){ - coincidence = new GateCoincidenceDigi(digi,window,offset); - //AE here open coincidence - m_coincidenceDigis.push_back(coincidence); - } - } - else{ - coincidence = new GateCoincidenceDigi(digi,window,offset); - //AE here open window with the digi - m_coincidenceDigis.push_back(coincidence); - } + // if(digi->GetVolumeID().GetVolume(2)->GetName()==m_absorberDepth2Name){ + auto coincidence = + new GateCoincidenceDigi(new GateDigi(digi), window, offset); + // AE here open coincidence + m_coincidenceDigis.push_back(coincidence); } - else - delete digi; // digis that don't open a coincidence window can be discarded + } else { + auto coincidence = + new GateCoincidenceDigi(new GateDigi(digi), window, offset); + // AE here open window with the digi + m_coincidenceDigis.push_back(coincidence); + } + } + delete digi; } StoreDigiCollection(m_OutputCoincidenceDigiCollection); - - - - } /* @@ -412,7 +412,7 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow4CC(GateCoincidence } */ // look for valid coincidences -void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDigi *coincidence) +bool GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDigi *coincidence) { G4int i, j, nDigis; G4int nGoods, maxGoods; @@ -424,25 +424,25 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDig nDigis = coincidence->size(); if (nDigis<2) - { - delete coincidence; - return; - } + { + return false; + } else if (nDigis==2) - { + { // check if good if(IsForbiddenCoincidence(coincidence->at(0),coincidence->at(1)) ) - delete coincidence; - else - m_OutputCoincidenceDigiCollection->insert(coincidence); - return; - } + return false; + else { + m_OutputCoincidenceDigiCollection->insert(coincidence); + return true; + } + + } else // nDigis>2 multiples { if(m_multiplesPolicy==kKillAll) - { - delete coincidence; - return; + { + return false; } // if dealing with a delayed window or if other digis open coincidence windows, // we only want to pair with the first digi to avoid invalid pairs, or double counting @@ -451,11 +451,11 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDig if(m_multiplesPolicy==kTakeAllGoods) { for(i=0; i<(PairWithFirstDigiOnly?1:(nDigis-1)); i++) // iterate over all pairs (single window) or just pairs with initial event (multi-window) - for(j=i+1; jat(i),coincidence->at(j)) ) m_OutputCoincidenceDigiCollection->insert(CreateSubDigi(coincidence, i, j)); - delete coincidence; // valid digis extracted so we can delete - return; + + return false; } // count the goods (iterate over all pairs because we're considering the multi as a unit, not breaking it up into pairs) nGoods = 0; @@ -466,8 +466,7 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDig if( nGoods == 0 ) // all of the remaining options expect at least one good { - delete coincidence; - return; + return false; } /*//G4cout<<"nGoods = "<< nGoods<insert(coincidence); - return; // don't delete the coincidence + m_OutputCoincidenceDigiCollection->insert(coincidence); + return true; } if( (m_multiplesPolicy==kTakeWinnerIfOnlyOneGood) ) - { - delete coincidence; - return; + { + return false; } - - - // find winner and count the goods maxE = 0.0; nGoods = 0; @@ -521,23 +516,23 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDig } if(nGoods==0) // check again, we may have reduced the subset. { - delete coincidence; - return; + + return false; } if(m_multiplesPolicy==kTakeWinnerIfIsGood) - { + { if(!IsForbiddenCoincidence(coincidence->at(winner_i),coincidence->at(winner_j)) ) m_OutputCoincidenceDigiCollection->insert(CreateSubDigi(coincidence, winner_i, winner_j)); - delete coincidence; - return; + + return false; } if(m_multiplesPolicy==kKillAllIfMultipleGoods) { if(nGoods>1) - { - delete coincidence; - return; + { + + return false; } // else find and return the one good event else // nGoods==1 { @@ -545,23 +540,22 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDig for(j=i+1; jat(i),coincidence->at(j))) m_OutputCoincidenceDigiCollection->insert(CreateSubDigi(coincidence, i, j)); - delete coincidence; - return; + + return false; } } maxGoods = PairWithFirstDigiOnly?(nDigis-1):(nDigis*(nDigis-1)/2); - if(m_multiplesPolicy==kTakeWinnerIfAllAreGoods) + if(m_multiplesPolicy==kTakeWinnerIfAllAreGoods) { - if(nGoods==maxGoods) + if(nGoods==maxGoods) { - m_OutputCoincidenceDigiCollection->insert(CreateSubDigi(coincidence, winner_i, winner_j)); - delete coincidence; - return; - } - else - { - delete coincidence; - return; + m_OutputCoincidenceDigiCollection->insert(CreateSubDigi(coincidence, winner_i, winner_j)); + + + return false; + } else { + + return false; } } @@ -583,13 +577,13 @@ void GateCoincidenceSorter::ProcessCompletedCoincidenceWindow(GateCoincidenceDig } } } - m_OutputCoincidenceDigiCollection->insert(CreateSubDigi(coincidence, winner_i, winner_j)); - delete coincidence; // valid digis extracted so we can delete - return; + m_OutputCoincidenceDigiCollection->insert(CreateSubDigi(coincidence, winner_i, winner_j)); + + return false; } } - delete coincidence; - return; + + return false; } @@ -609,42 +603,42 @@ G4int GateCoincidenceSorter::ComputeSectorID(const GateDigi& digi) if (m_depth>=(G4int)digi.GetOutputVolumeID().size()) { G4cerr<<"[GateCoincidenceSorter::ComputeSectorID]: Required depth's too deep, setting it to 1\n"; m_depth=1; - } - static std::vector gkSectorMultiplier; - static std::vector gkSectorNumber; + } + static std::vector gkSectorMultiplier; + static std::vector gkSectorNumber; if (gkSectorMultiplier.empty()){ - // this code is done just one time for performance improving - // one suppose that the system hierarchy is linear until the desired depth + // this code is done just one time for performance improving + // one suppose that the system hierarchy is linear until the desired depth GateSystemComponent* comp = m_system->GetBaseComponent(); G4int depth=0; while (comp){ - G4int rep_num = comp->GetAngularRepeatNumber(); - if (rep_num == 1) - // Check for generic repeater - rep_num = comp->GetGenericRepeatNumber(); - gkSectorNumber.push_back(rep_num); + G4int rep_num = comp->GetAngularRepeatNumber(); + if (rep_num == 1) + // Check for generic repeater + rep_num = comp->GetGenericRepeatNumber(); + gkSectorNumber.push_back(rep_num); if ( (depthGetChildNumber() == 1) ){ - comp = comp->GetChildComponent(0); - depth++; + comp = comp->GetChildComponent(0); + depth++; } else comp=0; - } - gkSectorMultiplier.resize(gkSectorNumber.size()); + } + gkSectorMultiplier.resize(gkSectorNumber.size()); gkSectorMultiplier[gkSectorNumber.size()-1] = 1; for (G4int i=(G4int)gkSectorNumber.size()-2;i>=0;--i){ gkSectorMultiplier[i] = gkSectorMultiplier[i+1] * gkSectorNumber[i+1]; - } - gm_coincSectNum = gkSectorMultiplier[0]; } + gm_coincSectNum = gkSectorMultiplier[0]; + } G4int ans=0; for (G4int i=0;i<=m_depth;i++){ G4int x = digi.GetComponentID(i)%gkSectorNumber[i]; ans += x*gkSectorMultiplier[i]; - } + } - return ans; + return ans; } /* @@ -705,18 +699,18 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons if(!GateSystemListManager::GetInstance()->GetIsAnySystemDefined()) { - // TODO GND define case if there is no system defiend! + // TODO GND define case if there is no system defiend! - } - G4int blockID1 = m_system->GetMainComponentIDGND(digi1), + } + G4int blockID1 = m_system->GetMainComponentIDGND(digi1), blockID2 = m_system->GetMainComponentIDGND(digi2); - // Modif by D. Lazaro, February 25th, 2004 + // Modif by D. Lazaro, February 25th, 2004 // Computation of sectorID, sectorNumber and sectorDifference, paramaters depending on // the geometry construction of the scanner (spherical for system ecatAccel and cylindrical // for other systems as Ecat, CPET and cylindricalPET) - const G4String name = m_system->GetName(); + const G4String name = m_system->GetName(); G4String nameComp = "systems/ecatAccel"; //G4cout << "NAME OF THE SYSTEM: " << name << "; NAME TO COMPARE: " << nameComp << Gateendl; int comp = strcmp(name,nameComp); @@ -724,7 +718,7 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons if (comp == 0) { // Compute the sector difference G4int sectorID1 = m_system->ComputeSectorIDSphere(blockID1), - sectorID2 = m_system->ComputeSectorIDSphere(blockID2); + sectorID2 = m_system->ComputeSectorIDSphere(blockID2); // Get the number of sectors per ring G4int sectorNumber = m_system->GetCoincidentSectorNumberSphere(); @@ -738,7 +732,7 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons sectorDiff2 += sectorNumber; G4int sectorDifference = std::min(sectorDiff1,sectorDiff2); //G4cout<1) @@ -748,19 +742,19 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons return false; } else { - // Compute the sector difference - G4int sectorID1 = ComputeSectorID(*digi1), - sectorID2 = ComputeSectorID(*digi2); - - // Get the number of sectors per ring - // G4int sectorNumber = GetCoincidentSectorNumber(); - // Deal with the circular difference problem - G4int sectorDiff1 = sectorID1 - sectorID2; + // Compute the sector difference + G4int sectorID1 = ComputeSectorID(*digi1), + sectorID2 = ComputeSectorID(*digi2); + + // Get the number of sectors per ring + // G4int sectorNumber = GetCoincidentSectorNumber(); + // Deal with the circular difference problem + G4int sectorDiff1 = sectorID1 - sectorID2; if (sectorDiff1<0) - sectorDiff1 += gm_coincSectNum; - G4int sectorDiff2 = sectorID2 - sectorID1; + sectorDiff1 += gm_coincSectNum; + G4int sectorDiff2 = sectorID2 - sectorID1; if (sectorDiff2<0) - sectorDiff2 += gm_coincSectNum; + sectorDiff2 += gm_coincSectNum; G4int sectorDifference = std::min(sectorDiff1,sectorDiff2); //Compare the sector difference with the minimum differences for valid coincidences @@ -768,38 +762,38 @@ G4bool GateCoincidenceSorter::IsForbiddenCoincidence(const GateDigi* digi1, cons //G4cout<GetSystemID()<<" "<GetSystemID()<1) G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: coincidence between neighbour blocks --> refused\n"; - return true; - } - G4ThreeVector globalPos1 = digi1->GetGlobalPos(); - G4ThreeVector globalPos2 = digi2->GetGlobalPos(); + return true; + } + G4ThreeVector globalPos1 = digi1->GetGlobalPos(); + G4ThreeVector globalPos2 = digi2->GetGlobalPos(); - // Check the difference in Z between the two positions + // Check the difference in Z between the two positions if ((m_maxDeltaZ > 0) && (fabs(globalPos2.z() - globalPos1.z()) > m_maxDeltaZ)) { if (nVerboseLevel > 1) G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: difference in Z too large --> refused\n"; return true; - } + } - // Calculate the denominator for distance 's' in the XY plane + // Calculate the denominator for distance 's' in the XY plane G4double denom = (globalPos1.y() - globalPos2.y()) * (globalPos1.y() - globalPos2.y()) + - (globalPos2.x() - globalPos1.x()) * (globalPos2.x() - globalPos1.x()); + (globalPos2.x() - globalPos1.x()) * (globalPos2.x() - globalPos1.x()); - G4double s = 0.0; - if (denom != 0.0) { + G4double s = 0.0; + if (denom != 0.0) { denom = sqrt(denom); s = (globalPos1.x() * (globalPos1.y() - globalPos2.y()) + globalPos1.y() * (globalPos2.x() - globalPos1.x())) / denom; - } + } - // Check the distance 's' against the maximum threshold - if ((m_minS < 0) && (fabs(s) < m_minS)) { + // Check the distance 's' against the maximum threshold + if ((m_minS < 0) && (fabs(s) < m_minS)) { if (nVerboseLevel > 1) G4cout << "[GateCoincidenceSorter::IsForbiddenCoincidence]: distance s too large --> refused\n"; return true; - } + } - return false; + return false; } } //------------------------------------------------------------------------------------------------------ @@ -816,9 +810,9 @@ void GateCoincidenceSorter::SetSystem(G4String& inputName) if(pPCOutputName.compare(inputName) == 0) { m_system=m_digitizerMgr->m_SingleDigitizersList[i]->GetSystem(); - break; - } - } + break; + } + } } diff --git a/source/digits_hits/src/GateDigitizerMgr.cc b/source/digits_hits/src/GateDigitizerMgr.cc index b414639e9..e336723dc 100644 --- a/source/digits_hits/src/GateDigitizerMgr.cc +++ b/source/digits_hits/src/GateDigitizerMgr.cc @@ -63,7 +63,15 @@ GateDigitizerMgr::GateDigitizerMgr() GateDigitizerMgr::~GateDigitizerMgr() { - + for (size_t i = 0; i < m_SingleDigitizersList.size(); ++i) { + delete m_SingleDigitizersList[i]; + } + m_SingleDigitizersList.clear(); + + for (size_t i = 0; i < m_CoincidenceSortersList.size(); ++i) { + delete m_CoincidenceSortersList[i]; + } + m_CoincidenceSortersList.clear(); delete fMessenger; } From 06811babe657241a59775fdf408a2c95d53516b8 Mon Sep 17 00:00:00 2001 From: mraedler Date: Wed, 14 Jan 2026 09:42:37 +0100 Subject: [PATCH 79/96] For multi-detector geometries: suppress the generation of multiple coincidence sorters called "Coincidences" to avoid ambiguity issues --- source/geometry/src/GateCPETSystem.cc | 8 +++++-- .../geometry/src/GateCylindricalPETSystem.cc | 24 +++++++++++++++++-- source/geometry/src/GateEcatAccelSystem.cc | 8 +++++-- source/geometry/src/GateEcatSystem.cc | 8 +++++-- source/geometry/src/GateOPETSystem.cc | 6 ++++- source/geometry/src/GatePETScannerSystem.cc | 8 +++++-- 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/source/geometry/src/GateCPETSystem.cc b/source/geometry/src/GateCPETSystem.cc index 7d9083862..3c7baaa01 100644 --- a/source/geometry/src/GateCPETSystem.cc +++ b/source/geometry/src/GateCPETSystem.cc @@ -41,9 +41,13 @@ GateCPETSystem::GateCPETSystem(const G4String& itsName) // Integrate a coincidence sorter into the digitizer //OK GND 2022 + // MR 2025: For multi-detector geometries: suppress the generation of multiple coincidence sorters called + // "Coincidences" to avoid ambiguity issues GateDigitizerMgr* digitizerMgr = GateDigitizerMgr::GetInstance(); - GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); - digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + if (digitizerMgr->m_CoincidenceSortersList.size() == 0) { + GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); + digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + } SetOutputIDName((char *)"gantryID",0); SetOutputIDName((char *)"sectorID",1); diff --git a/source/geometry/src/GateCylindricalPETSystem.cc b/source/geometry/src/GateCylindricalPETSystem.cc index a6d2c9f5c..d4f9687a5 100644 --- a/source/geometry/src/GateCylindricalPETSystem.cc +++ b/source/geometry/src/GateCylindricalPETSystem.cc @@ -53,8 +53,28 @@ GateCylindricalPETSystem::GateCylindricalPETSystem(const G4String& itsName) // Integrate a coincidence sorter into the digitizer //OK GND 2022 GateDigitizerMgr* digitizerMgr = GateDigitizerMgr::GetInstance(); - GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); - digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + // In case of multiple detector geometries, multiple coincidence sortes are created with the name "Coincidences", + // which creates an ambiguity and eventually crashes with a segmentation violation; using /gate/digitizerMgr/list does + // not list multiple entries with identical names either; therefore we add a check + + std::vector coincidenceSortersList = digitizerMgr->m_CoincidenceSortersList; + + //for (G4int ii = 0; ii < coincidenceSortersList.size(); ++ii) { + // std::cout << std::to_string(ii) + " " << coincidenceSortersList[ii]->GetInputName() << " " << coincidenceSortersList[ii]->GetOutputName() << std::endl; + //} + + // Name options: itsName and GetName() are always "systems/cylindricalPET" in this class; so we go with GetOwnName() + //std::cout << itsName << " " << GetName() << " " << GetOwnName() << std::endl; + + if (coincidenceSortersList.size() == 0) { + GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); + //GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr, "Coincidences_" + GetOwnName()); + digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + } + else { + //GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr, "Coincidences_" + GetOwnName()); + //digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + } #ifdef GATE_USE_LMF diff --git a/source/geometry/src/GateEcatAccelSystem.cc b/source/geometry/src/GateEcatAccelSystem.cc index ea0b4b962..109e0f275 100644 --- a/source/geometry/src/GateEcatAccelSystem.cc +++ b/source/geometry/src/GateEcatAccelSystem.cc @@ -35,9 +35,13 @@ GateEcatAccelSystem::GateEcatAccelSystem(const G4String& itsName) // Integrate a coincidence sorter into the digitizer //OK GND 2022 + // MR 2025: For multi-detector geometries: suppress the generation of multiple coincidence sorters called + // "Coincidences" to avoid ambiguity issues GateDigitizerMgr* digitizerMgr = GateDigitizerMgr::GetInstance(); - GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); - digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + if (digitizerMgr->m_CoincidenceSortersList.size() == 0) { + GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); + digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + } // Insert a sinogram maker and a ECAT7 writer into the output manager GateOutputMgr *outputMgr = GateOutputMgr::GetInstance(); diff --git a/source/geometry/src/GateEcatSystem.cc b/source/geometry/src/GateEcatSystem.cc index 3c11063f6..60801200c 100644 --- a/source/geometry/src/GateEcatSystem.cc +++ b/source/geometry/src/GateEcatSystem.cc @@ -35,9 +35,13 @@ GateEcatSystem::GateEcatSystem(const G4String& itsName) // Integrate a coincidence sorter into the digitizer //OK GND 2022 + // MR 2025: For multi-detector geometries: suppress the generation of multiple coincidence sorters called + // "Coincidences" to avoid ambiguity issues GateDigitizerMgr* digitizerMgr = GateDigitizerMgr::GetInstance(); - GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); - digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + if (digitizerMgr->m_CoincidenceSortersList.size() == 0) { + GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); + digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + } // Insert a sinogram maker and a ECAT7 writer into the output manager GateOutputMgr *outputMgr = GateOutputMgr::GetInstance(); diff --git a/source/geometry/src/GateOPETSystem.cc b/source/geometry/src/GateOPETSystem.cc index 8cdda5afd..1f8c2b4f4 100644 --- a/source/geometry/src/GateOPETSystem.cc +++ b/source/geometry/src/GateOPETSystem.cc @@ -50,9 +50,13 @@ GateOPETSystem::GateOPETSystem(const G4String& itsName) // Integrate a coincidence sorter into the digitizer //OK GND 2022 - GateDigitizerMgr* digitizerMgr = GateDigitizerMgr::GetInstance(); + // MR 2025: For multi-detector geometries: suppress the generation of multiple coincidence sorters called + // "Coincidences" to avoid ambiguity issues + GateDigitizerMgr* digitizerMgr = GateDigitizerMgr::GetInstance(); + if (digitizerMgr->m_CoincidenceSortersList.size() == 0) { GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + } #ifdef GATE_USE_LMF // Insert an LMF output module into the output manager diff --git a/source/geometry/src/GatePETScannerSystem.cc b/source/geometry/src/GatePETScannerSystem.cc index 1f2a09e9e..cc5c5f4ab 100644 --- a/source/geometry/src/GatePETScannerSystem.cc +++ b/source/geometry/src/GatePETScannerSystem.cc @@ -23,7 +23,11 @@ GatePETScannerSystem::GatePETScannerSystem(const G4String& itsName) //G4cout << " Constructeur GatePETScannerSystem \n"; // Integrate a coincidence sorter into the digitizer //OK GND 2022 + // MR 2025: For multi-detector geometries: suppress the generation of multiple coincidence sorters called + // "Coincidences" to avoid ambiguity issues GateDigitizerMgr* digitizerMgr = GateDigitizerMgr::GetInstance(); - GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); - digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + if (digitizerMgr->m_CoincidenceSortersList.size() == 0) { + GateCoincidenceSorter* coincidenceSorter = new GateCoincidenceSorter(digitizerMgr,"Coincidences"); + digitizerMgr->AddNewCoincidenceSorter(coincidenceSorter); + } } From 21ed02487cd9facd70303e91c751292ac4c0293d Mon Sep 17 00:00:00 2001 From: mraedler Date: Wed, 14 Jan 2026 13:28:31 +0100 Subject: [PATCH 80/96] Fix the Compton and Rayleigh counts in the detector for geometries with multiple layers and/or multiple scanners. --- source/digits_hits/src/GateAnalysis.cc | 276 +++++++++++++++++++++++-- 1 file changed, 264 insertions(+), 12 deletions(-) diff --git a/source/digits_hits/src/GateAnalysis.cc b/source/digits_hits/src/GateAnalysis.cc index 31a15001e..27026d8c9 100644 --- a/source/digits_hits/src/GateAnalysis.cc +++ b/source/digits_hits/src/GateAnalysis.cc @@ -35,6 +35,10 @@ #include "GateToRoot.hh" #include "GateDigitizerMgr.hh" +#include "G4UnitsTable.hh" +#include +#include + //-------------------------------------------------------------------------------------------------- GateAnalysis::GateAnalysis(const G4String& name, GateOutputMgr* outputMgr,DigiMode digiMode) : GateVOutputModule(name,outputMgr,digiMode) @@ -114,6 +118,39 @@ void GateAnalysis::RecordBeginOfEvent(const G4Event* ) //-------------------------------------------------------------------------------------------------- +/////////////////////////////////////////////////////////////////////// + +std::vector argsort(const std::vector& v) { + std::vector idx(v.size()); + std::iota(idx.begin(), idx.end(), 0); + + std::sort(idx.begin(), idx.end(), + [&v](G4int i1, G4int i2) { return v[i1] < v[i2]; }); + + return idx; +} + +std::vector inverse_argsort(const std::vector& unsorted_array) { + std::vector sorted_indices = argsort(unsorted_array); + std::vector original_indices(sorted_indices.size()); + + for (G4int i = 0; i < sorted_indices.size(); ++i) { + original_indices[sorted_indices[i]] = i; + } + + return original_indices; +} +/* +template +void printVector(const std::vector& v) { + for (T ii: v) + std::cout << std::setprecision(16) << ii << ' '; + std::cout << std::endl; +} +*/ +/////////////////////////////////////////////////////////////////////// + + //-------------------------------------------------------------------------------------------------- void GateAnalysis::RecordEndOfEvent(const G4Event* event) { @@ -140,6 +177,148 @@ void GateAnalysis::RecordEndOfEvent(const G4Event* event) { //OK GND 2022 std::vector CHC_vector = GetOutputMgr()->GetHitCollections(); + + ///////////////////////////////////////////////////////////////// + + //Number of sensitive detectors + //G4cout << CHC_vector.size() << G4endl; + //G4cout << "--" << G4endl; + + //G4bool oneInFirstLayer = false; + //G4bool twoInFirstLayer = false; + //G4double oneKeep, twoKeep; + + // The following bit used to be part of the main loop + // todo: Check if moving this causes some errors + G4int photon1ID = 0; + G4int photon2ID = 0; + + //////////// + // search the positron + //positronID = // No more needed + m_trajectoryNavigator->FindPositronTrackID(); + + /* + if (positronID == 0) { + if (nVerboseLevel > 0) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : positronID == 0\n"; + } + + if (nVerboseLevel > 1) G4cout << "GateAnalysis::RecordEndOfEvent : positronID : " << positronID << Gateendl; + */ + //////////// + + //search the two gammas + std::vector photonIDVec = m_trajectoryNavigator->FindAnnihilationGammasTrackID(); + if (photonIDVec.size() == 0) { + // no gamma coming from a positron or an ion, or shooted as primary + if (nVerboseLevel > 0) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : photonIDs not found\n"; + } + else { + // This warning is somewhat irrelevant with 124I + if (nVerboseLevel > 0 && photonIDVec.size() > 2) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : photonID vector size > 2\n"; + + // Print the + //for (G4int ii: photonIDVec) + //std::cout << ii << ' '; + //std::cout << std::endl; + + photon1ID = photonIDVec[0]; + photon2ID = (photonIDVec.size() >= 2) ? photonIDVec[1] : 0; + } + + if (photon1ID == 0) { + if (nVerboseLevel > 0) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : photon1ID == 0\n"; + } + + if (photon2ID == 0) { + if (nVerboseLevel > 1) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : photon2ID == 0\n"; + } + + if (nVerboseLevel > 1) G4cout << "GateAnalysis::RecordEndOfEvent : photon1ID : " << photon1ID << " photon2ID : " << photon2ID << Gateendl; + + /////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////// + + + + // Get all the Compton (and Rayleigh) interactions before processing the hit layers individually + std::vector comptonCount1, comptonCount2, rayleighCount1, rayleighCount2; + + G4bool multi_detector = CHC_vector.size() > 1; + + // Only do this if there are multiple layers / geometries + if (multi_detector) { + + std::vector comptonTimes1, comptonTimes2, rayleighTimes1, rayleighTimes2; + + for (size_t i=0; ientries(); + //G4int c1 = 0, c2 = 0, r1 = 0, r2 = 0; + + // Hits loop + for (G4int iHit=0;iHitGetTrackID(); + G4String processName = (*CHC)[iHit]->GetProcess(); + + if (processName.find("ompt") != G4String::npos) { + + if (crystalTrackID == photon1ID) { + comptonTimes1.push_back((*CHC)[iHit]->GetTime()); + //comptonCount1.push_back(c1); + //c1++; + } + if (crystalTrackID == photon2ID) { + comptonTimes2.push_back((*CHC)[iHit]->GetTime()); + //comptonCount2.push_back(c2); + //c2++; + } + } + + if (processName.find("Rayl") != G4String::npos) { + + if (crystalTrackID == photon1ID) { + rayleighTimes1.push_back((*CHC)[iHit]->GetTime()); + //rayleighCount1.push_back(r1); + //r1++; + } + + if (crystalTrackID == photon2ID) { + rayleighTimes2.push_back((*CHC)[iHit]->GetTime()); + //rayleighCount2.push_back(r2); + //r2++; + } + + } + } + } + } + // Get the correct ordering + //comptonCount1 = argsort(comptonTimes1); + //comptonCount2 = argsort(comptonTimes2); + comptonCount1 = inverse_argsort(comptonTimes1); + comptonCount2 = inverse_argsort(comptonTimes2); + + //~ if (comptonCount1.size() > 0) { + //~ printVector(comptonTimes1); + //~ printVector(comptonCount1); + //~ G4cout << G4endl; + //~ } + + //rayleighCount1 = argsort(rayleighTimes1); + //rayleighCount2 = argsort(rayleighTimes2); + rayleighCount1 = inverse_argsort(rayleighTimes1); + rayleighCount2 = inverse_argsort(rayleighTimes2); + } + + G4int ic1=0, ic2=0, ir1=0, ir2=0; + + /////////////////////////////////////////////////////////////////// + for (size_t i=0; iFindPositronTrackID(); - /*if (positronID == 0) - { - if (nVerboseLevel > 0) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : positronID == 0\n"; - } + //if (positronID == 0) + //{ + //if (nVerboseLevel > 0) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : positronID == 0\n"; + //} - if (nVerboseLevel > 1) G4cout << "GateAnalysis::RecordEndOfEvent : positronID : " << positronID << Gateendl; - */ + //if (nVerboseLevel > 1) G4cout << "GateAnalysis::RecordEndOfEvent : positronID : " << positronID << Gateendl; + //////////// //search the two gammas @@ -202,6 +385,8 @@ void GateAnalysis::RecordEndOfEvent(const G4Event* event) if (nVerboseLevel > 0 && photonIDVec.size() > 2) G4cout << "GateAnalysis::RecordEndOfEvent : WARNING : photonID vector size > 2\n"; + //printVector(photonIDVec); + photon1ID = photonIDVec[0]; photon2ID = (photonIDVec.size() >= 2) ? photonIDVec[1] : 0; } @@ -219,6 +404,9 @@ void GateAnalysis::RecordEndOfEvent(const G4Event* event) << "GateAnalysis::RecordEndOfEvent : photon1ID : " << photon1ID << " photon2ID : " << photon2ID << Gateendl; + */ + ///////////////////////////////////////////////////////// + // analysis of the phantom hits to count the comptons, etc. @@ -381,23 +569,87 @@ void GateAnalysis::RecordEndOfEvent(const G4Event* event) { G4int crystalTrackID = (*CHC)[iHit]->GetTrackID(); G4String processName = (*CHC)[iHit]->GetProcess(); + + ///////////////////////////////////////////////////////////// + // Check the ordering + /* + G4cout << std::setprecision(16) << (*CHC)[iHit]->GetTime()/second << G4endl; // somehow does not show all 16 digits? + if (processName == "Compton") { + std::cout << std::setprecision (16) << (*CHC)[iHit]->GetTime()/second << " " << crystalTrackID << std::endl; + + if ((crystalTrackID == photon1ID) && (i == 1) && oneInFirstLayer){ + if (oneKeep > (*CHC)[iHit]->GetTime()/second){ + std::cout << std::setprecision (16) << oneKeep << std::endl; + std::cout << std::setprecision (16) << (*CHC)[iHit]->GetTime()/second << " " << crystalTrackID << std::endl; + std::cout << std::endl;} + + } + + if ((crystalTrackID == photon2ID) && (i == 1) && twoInFirstLayer){ + if (twoKeep > (*CHC)[iHit]->GetTime()/second){ + std::cout << std::setprecision (16) << twoKeep << std::endl; + std::cout << std::setprecision (16) << (*CHC)[iHit]->GetTime()/second << " " << crystalTrackID << std::endl; + std::cout << std::endl;} + } + + + if ((crystalTrackID == photon1ID) && (i == 0)) oneInFirstLayer = true, oneKeep = (*CHC)[iHit]->GetTime()/second; + if ((crystalTrackID == photon2ID) && (i == 0)) twoInFirstLayer = true, twoKeep = (*CHC)[iHit]->GetTime()/second; + } + */ + // Counting Compton in the Crystal // if (processName.find("ompt") != G4String::npos || processName.find("Rayleigh") != G4String::npos) { if (processName.find("ompt") != G4String::npos) { - if (crystalTrackID == photon1ID) photon1_crystal_compton++; - if (crystalTrackID == photon2ID) photon2_crystal_compton++; + if (crystalTrackID == photon1ID) { + if (multi_detector) { + photon1_crystal_compton = comptonCount1[ic1] + 1; + ic1++; + } else { + photon1_crystal_compton++; + } + } + + if (crystalTrackID == photon2ID) { + if (multi_detector) { + photon2_crystal_compton = comptonCount2[ic2] + 1; + ic2++; + } else { + photon2_crystal_compton++; + } + + } + } // Counting Rayleigh scatter in crystal if (processName.find("Rayl") != G4String::npos) { - if (crystalTrackID == photon1ID) photon1_crystal_Rayleigh++; - if (crystalTrackID == photon2ID) photon2_crystal_Rayleigh++; + if (crystalTrackID == photon1ID) { + if (multi_detector) { + photon1_crystal_Rayleigh = rayleighCount1[ir1] + 1; + ir1++; + } else { + photon1_crystal_Rayleigh++; + } + } + + if (crystalTrackID == photon2ID) { + if (multi_detector) { + photon2_crystal_Rayleigh = rayleighCount2[ir2] + 1; + ir2++; + } else { + photon2_crystal_Rayleigh++; + } + } + } + ///////////////////////////////////////////////////////////// + G4int PDGEncoding = (*CHC)[iHit]->GetPDGEncoding(); if (nVerboseLevel > 2) G4cout << "GateAnalysis::RecordEndOfEvent : HitsCollection: processName : <" << processName From e4042ed707c4e86de41a3d10f8a7ea97b3311410 Mon Sep 17 00:00:00 2001 From: mraedler Date: Wed, 14 Jan 2026 13:36:34 +0100 Subject: [PATCH 81/96] Typo spotted by Keyvan Tayefi Ardebili. --- source/digits_hits/src/GateToRoot.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/digits_hits/src/GateToRoot.cc b/source/digits_hits/src/GateToRoot.cc index 269b33879..9a1758991 100644 --- a/source/digits_hits/src/GateToRoot.cc +++ b/source/digits_hits/src/GateToRoot.cc @@ -1572,7 +1572,7 @@ void GateToRoot::OpenTracksFile() { void GateToRoot::RecordPHData(ComptonRayleighData aCRData) { theCRData.photon1_phantom_Rayleigh = aCRData.photon1_phantom_Rayleigh; - theCRData.photon2_phantom_Rayleigh = aCRData.photon1_phantom_Rayleigh; + theCRData.photon2_phantom_Rayleigh = aCRData.photon2_phantom_Rayleigh; theCRData.photon1_phantom_compton = aCRData.photon1_phantom_compton; theCRData.photon2_phantom_compton = aCRData.photon2_phantom_compton; strcpy(theCRData.theComptonVolumeName1, aCRData.theComptonVolumeName1); @@ -1583,7 +1583,7 @@ void GateToRoot::RecordPHData(ComptonRayleighData aCRData) { void GateToRoot::GetPHData(ComptonRayleighData &aCRData) { aCRData.photon1_phantom_Rayleigh = theCRData.photon1_phantom_Rayleigh; - aCRData.photon2_phantom_Rayleigh = theCRData.photon1_phantom_Rayleigh; + aCRData.photon2_phantom_Rayleigh = theCRData.photon2_phantom_Rayleigh; aCRData.photon1_phantom_compton = theCRData.photon1_phantom_compton; aCRData.photon2_phantom_compton = theCRData.photon2_phantom_compton; strcpy(aCRData.theComptonVolumeName1, theCRData.theComptonVolumeName1); From 8811c076c1e91c9eea124dcc7461cd6537b13bd9 Mon Sep 17 00:00:00 2001 From: kochebina Date: Thu, 22 Jan 2026 15:51:03 +0100 Subject: [PATCH 82/96] Update CMake version in itk-mhd --- source/externals/itk-mhd/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/externals/itk-mhd/CMakeLists.txt b/source/externals/itk-mhd/CMakeLists.txt index c070b9228..040c61e87 100644 --- a/source/externals/itk-mhd/CMakeLists.txt +++ b/source/externals/itk-mhd/CMakeLists.txt @@ -1,5 +1,5 @@ PROJECT(testmhd) -CMAKE_MINIMUM_REQUIRED (VERSION 2.4) +CMAKE_MINIMUM_REQUIRED (VERSION 3.6) IF(COMMAND CMAKE_POLICY) CMAKE_POLICY(SET CMP0003 NEW) ENDIF(COMMAND CMAKE_POLICY) From b7d1be2214834749931575518e4d6cf5b5dd4f6b Mon Sep 17 00:00:00 2001 From: Konrad Klimaszewski Date: Wed, 29 Oct 2025 09:33:46 +0100 Subject: [PATCH 83/96] Delete dangling digits throughout the code - Add delete statements for digits that are not stored in geant gigit storage - Convert GateVolumeID from std::vector inheritance to composition --- source/digits_hits/include/GatePileup.hh | 1 + source/digits_hits/src/GateAdderComptPhotIdeal.cc | 11 +++++++++++ source/digits_hits/src/GateCCSinglesFileReader.cc | 2 ++ .../src/GateDigitizerInitializationModule.cc | 1 + source/digits_hits/src/GateEfficiency.cc | 5 +++++ source/digits_hits/src/GateEnergyFraming.cc | 4 ++-- source/digits_hits/src/GateMultipleRejection.cc | 13 +++++++++++-- source/digits_hits/src/GateNoise.cc | 13 +++++++------ source/digits_hits/src/GatePileup.cc | 6 +++--- source/geometry/include/GateVSystem.hh | 2 +- source/geometry/src/GateVSystem.cc | 15 +++++++++------ 11 files changed, 53 insertions(+), 20 deletions(-) diff --git a/source/digits_hits/include/GatePileup.hh b/source/digits_hits/include/GatePileup.hh index 7fecf43ae..23dbb1761 100644 --- a/source/digits_hits/include/GatePileup.hh +++ b/source/digits_hits/include/GatePileup.hh @@ -83,6 +83,7 @@ protected: G4double m_Pileup; std::vector< GateDigi* >* m_waiting; G4bool m_firstEvent; + GateDigiCollection* m_tempDigiCollection = nullptr; private: diff --git a/source/digits_hits/src/GateAdderComptPhotIdeal.cc b/source/digits_hits/src/GateAdderComptPhotIdeal.cc index d5b0bc540..4c239f3b3 100755 --- a/source/digits_hits/src/GateAdderComptPhotIdeal.cc +++ b/source/digits_hits/src/GateAdderComptPhotIdeal.cc @@ -114,6 +114,8 @@ void GateAdderComptPhotIdeal::Digitize() } else { + delete m_outputDigi; + m_outputDigi = nullptr; if(inputDigi->GetPostStepProcess()!="Transportation") m_flgEvtRej=1; } @@ -241,6 +243,8 @@ void GateAdderComptPhotIdeal::Digitize() } + delete m_outputDigi; + m_outputDigi = nullptr; } @@ -248,6 +252,13 @@ void GateAdderComptPhotIdeal::Digitize() } +#ifdef GATE_USE_OPTICAL + else + { + delete m_outputDigi; + m_outputDigi = nullptr; + } +#endif } //loop over input digits } //IDC else diff --git a/source/digits_hits/src/GateCCSinglesFileReader.cc b/source/digits_hits/src/GateCCSinglesFileReader.cc index 0656286c9..aa1d99e0f 100644 --- a/source/digits_hits/src/GateCCSinglesFileReader.cc +++ b/source/digits_hits/src/GateCCSinglesFileReader.cc @@ -146,6 +146,8 @@ G4int GateCCSinglesFileReader::PrepareNextEvent( ) GateDigi* aSingleDigi=m_singleBuffer.CreateSingle(); // OK GND 2022 TODO: uncomment for CC when no pulse list // pList->push_back(&aSingleDigi->GetPulse()); + delete aSingleDigi; + aSingleDigi = nullptr; // Load the next set of Singles-data into the root-Singles structure LoadSinglesData(); diff --git a/source/digits_hits/src/GateDigitizerInitializationModule.cc b/source/digits_hits/src/GateDigitizerInitializationModule.cc index 26165d81b..d0902f908 100644 --- a/source/digits_hits/src/GateDigitizerInitializationModule.cc +++ b/source/digits_hits/src/GateDigitizerInitializationModule.cc @@ -132,6 +132,7 @@ void GateDigitizerInitializationModule::Digitize() G4cout << "[GateDigitizerInitializationModule::Digitize]: \n" << "\tprocessed " << *(*inHC)[i] << Gateendl << "\tcreated new Digi:\n" + << Digi << Gateendl << *Digi << Gateendl; */ m_outputDigiCollection->insert(Digi); diff --git a/source/digits_hits/src/GateEfficiency.cc b/source/digits_hits/src/GateEfficiency.cc index 85ba464b3..5c7466516 100755 --- a/source/digits_hits/src/GateEfficiency.cc +++ b/source/digits_hits/src/GateEfficiency.cc @@ -169,6 +169,11 @@ void GateEfficiency::Digitize() { m_OutputDigiCollection->insert(m_outputDigi); } + else + { + delete m_outputDigi; + m_outputDigi = nullptr; + } } diff --git a/source/digits_hits/src/GateEnergyFraming.cc b/source/digits_hits/src/GateEnergyFraming.cc index 5516caddf..18542b220 100755 --- a/source/digits_hits/src/GateEnergyFraming.cc +++ b/source/digits_hits/src/GateEnergyFraming.cc @@ -120,8 +120,8 @@ void GateEnergyFraming::Digitize() G4cout << "[GateEnergyFraming::Digitize]Ignored digi with energy above uphold:\n" << *inputDigi << Gateendl << Gateendl ; - else - delete m_outputDigi; + delete m_outputDigi; + m_outputDigi = nullptr; } } diff --git a/source/digits_hits/src/GateMultipleRejection.cc b/source/digits_hits/src/GateMultipleRejection.cc index 38dd88b83..88daeaa43 100755 --- a/source/digits_hits/src/GateMultipleRejection.cc +++ b/source/digits_hits/src/GateMultipleRejection.cc @@ -101,22 +101,31 @@ void GateMultipleRejection::Digitize() { if(m_multipleDef==kvolumeID) { - if ( std::find(m_VolumeIDs.begin(), m_VolumeIDs.end(), currentVolumeID) != m_VolumeIDs.end() ) + if ( std::find(m_VolumeIDs.begin(), m_VolumeIDs.end(), currentVolumeID) != m_VolumeIDs.end() ) { + delete m_outputDigi; + m_outputDigi = nullptr; return; + } else m_OutputDigiCollection->insert(m_outputDigi); } else { + delete m_outputDigi; + m_outputDigi = nullptr; if (std::find(m_VolumeNames.begin(), m_VolumeNames.end(), currentVolumeName) != m_VolumeNames.end() ) return; - } } else { if (n_digi==1) //save if only one digi m_OutputDigiCollection->insert(m_outputDigi); + else + { + delete m_outputDigi; + m_outputDigi = nullptr; + } } diff --git a/source/digits_hits/src/GateNoise.cc b/source/digits_hits/src/GateNoise.cc index f313f17e7..b6633102e 100755 --- a/source/digits_hits/src/GateNoise.cc +++ b/source/digits_hits/src/GateNoise.cc @@ -116,10 +116,9 @@ void GateNoise::Digitize() // G4cout<< Gateendl; digi->SetOutputVolumeID(outputVol); - GateVolumeID* volID = system->MakeVolumeID(outputVol); - digi->SetVolumeID(*volID); - digi->SetGlobalPos(system->ComputeObjectCenter(volID)); - delete volID; + GateVolumeID volID = system->MakeVolumeID(outputVol); + digi->SetVolumeID(volID); + digi->SetGlobalPos(system->ComputeObjectCenter(&volID)); digi->SetEventID(-2); @@ -145,6 +144,9 @@ void GateNoise::Digitize() m_OutputDigiCollection->insert(new GateDigi(*inputDigi)); } //loop over input digits + for (const GateDigi* d : m_createdDigis) { + delete d; + } } //IDC else { @@ -161,13 +163,12 @@ void GateNoise::Digitize() G4double GateNoise::ComputeStartTime(GateDigiCollection* IDC) { - GateDigi* digi = new GateDigi(); + GateDigi* digi = nullptr; std::vector< GateDigi* >* IDCVector = IDC->GetVector (); std::vector::iterator iter; G4double startTime = DBL_MAX; - digi=0; for (iter = IDCVector->begin(); iter < IDCVector->end() ; ++iter) { if ( (*iter)->GetTime() < startTime ){ startTime = (*iter)->GetTime(); diff --git a/source/digits_hits/src/GatePileup.cc b/source/digits_hits/src/GatePileup.cc index c2548cb98..4cbe8e126 100644 --- a/source/digits_hits/src/GatePileup.cc +++ b/source/digits_hits/src/GatePileup.cc @@ -54,15 +54,15 @@ GatePileup::GatePileup(GateSinglesDigitizer *digitizer, G4String name) collectionName.push_back(colName); m_Messenger = new GatePileupMessenger(this); - GateDigiCollection* tempDigiCollection = new GateDigiCollection(GetName(), m_digitizer-> GetOutputName()); // to create the Digi Collection - m_waiting = tempDigiCollection->GetVector (); + m_tempDigiCollection = new GateDigiCollection(GetName(), m_digitizer-> GetOutputName()); // to create the Digi Collection + m_waiting = m_tempDigiCollection->GetVector (); } GatePileup::~GatePileup() { delete m_Messenger; - + delete m_tempDigiCollection; } diff --git a/source/geometry/include/GateVSystem.hh b/source/geometry/include/GateVSystem.hh index 9651a1233..8cca42279 100644 --- a/source/geometry/include/GateVSystem.hh +++ b/source/geometry/include/GateVSystem.hh @@ -219,7 +219,7 @@ class GateVSystem : public GateClockDependent size_t ComputeIdFromVolID(const GateOutputVolumeID& volID,std::vector& enableList) const; //G4ThreeVector ComputeObjectCenter(const std::vector& numList) const; G4ThreeVector ComputeObjectCenter(const GateVolumeID* volID) const; - GateVolumeID* MakeVolumeID(const std::vector& numList) const; + GateVolumeID MakeVolumeID(const std::vector& numList) const; public: typedef std::vector< GateSystemComponent* > compList_t; compList_t* MakeComponentListAtLevel(G4int level) const; diff --git a/source/geometry/src/GateVSystem.cc b/source/geometry/src/GateVSystem.cc index 963bbf95d..6ebafb418 100644 --- a/source/geometry/src/GateVSystem.cc +++ b/source/geometry/src/GateVSystem.cc @@ -451,14 +451,17 @@ size_t GateVSystem::ComputeIdFromVolID(const GateOutputVolumeID& volID,std::vect //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -GateVolumeID* GateVSystem::MakeVolumeID(const std::vector& numList) const +GateVolumeID GateVSystem::MakeVolumeID(const std::vector& numList) const { GateSystemComponent* comp = GetBaseComponent(); if (!comp) return 0; G4VPhysicalVolume *vol=comp->GetPhysicalVolume(0), *last_vol=vol; - GateVolumeID* ans = new GateVolumeID; - ans->push_back( GateVolumeSelector(GateDetectorConstruction::GetGateDetectorConstruction()->GetWorldVolume())); - if (vol) ans->push_back( GateVolumeSelector(vol)); else return ans; + GateVolumeID ans; + ans.push_back( GateVolumeSelector(GateDetectorConstruction::GetGateDetectorConstruction()->GetWorldVolume())); + if (vol) + ans.push_back( GateVolumeSelector(vol)); + else + return ans; for (size_t i=1;iGetChildNumber()<1) break; @@ -484,14 +487,14 @@ GateVolumeID* GateVSystem::MakeVolumeID(const std::vector& numList) const for (unsigned int ii=0;iiGetNoDaughters();++ii){ last_vol=logical->GetDaughter(ii); if (last_vol->GetLogicalVolume()->IsAncestor(vol)) { - ans->push_back(last_vol); + ans.push_back(last_vol); pb=false; break; } } if (pb) return ans; // no last_vol child is ancestor of vol... } else { - ans->push_back(vol); + ans.push_back(vol); last_vol=vol; break; } From 8caba6a63096778a6c841810f7c07c34c3b7c9f3 Mon Sep 17 00:00:00 2001 From: Konrad Klimaszewski Date: Wed, 29 Oct 2025 15:03:03 +0100 Subject: [PATCH 84/96] Do not allow to define new SinglesDigitizer with the same name as an existing one. --- source/digits_hits/include/GateDigitizerMgr.hh | 2 +- source/digits_hits/src/GateDigitizerMgr.cc | 13 +++++++++++-- source/digits_hits/src/GateDigitizerMgrMessenger.cc | 7 ++++++- source/digits_hits/src/GateSinglesDigitizer.cc | 13 +++++++++---- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/source/digits_hits/include/GateDigitizerMgr.hh b/source/digits_hits/include/GateDigitizerMgr.hh index aae6025ae..e5f9c5778 100644 --- a/source/digits_hits/include/GateDigitizerMgr.hh +++ b/source/digits_hits/include/GateDigitizerMgr.hh @@ -83,7 +83,7 @@ public: //! Run Singles Digitizers void RunDigitizers(); //! Integrates a new digitizer/singlesCollection - void AddNewSinglesDigitizer(GateSinglesDigitizer* digitizer); + bool AddNewSinglesDigitizer(GateSinglesDigitizer* digitizer); //! Find Digitizer by its name GateSinglesDigitizer* FindSinglesDigitizer(G4String mName); /// End of methods for Singles diff --git a/source/digits_hits/src/GateDigitizerMgr.cc b/source/digits_hits/src/GateDigitizerMgr.cc index e336723dc..54076c8de 100644 --- a/source/digits_hits/src/GateDigitizerMgr.cc +++ b/source/digits_hits/src/GateDigitizerMgr.cc @@ -255,24 +255,33 @@ void GateDigitizerMgr::AddNewSD(GateCrystalSD* newSD) //----------------------------------------------------------------- // Integrates a new Singles Digitizer -void GateDigitizerMgr::AddNewSinglesDigitizer(GateSinglesDigitizer* digitizer) +bool GateDigitizerMgr::AddNewSinglesDigitizer(GateSinglesDigitizer* digitizer) { + // Do not allow to register digitizers with identical names + G4String DigitizerName = digitizer->m_digitizerName + "_" + digitizer->m_SD->GetName(); + if (FindSinglesDigitizer(DigitizerName) != nullptr) { + return false; + } + GateDigitizerInitializationModule * myDM = new GateDigitizerInitializationModule(digitizer); m_digitizerIMList.push_back(myDM); G4DigiManager::GetDMpointer()->AddNewModule(myDM); - G4String outputName = digitizer->GetOutputName() ; if (nVerboseLevel>1) G4cout << "[GateDigitizerMgr::AddNewSinglesDigitizer]: Storing new digitizer '" << digitizer->GetObjectName() << "'" << " with output pulse-list name '" << outputName << "'\n"; + //Prepare OutputMng for this digitizer + GateOutputMgr::GetInstance()->RegisterNewSingleDigiCollection(DigitizerName, false); //Add digitizer to the list m_SingleDigitizersList.push_back(digitizer); //! Next lines are for the multi-system approach if(m_systemList && m_systemList->size() == m_SDlist.size()) digitizer->SetSystem((*m_systemList)[0]); + + return true; } //----------------------------------------------------------------- diff --git a/source/digits_hits/src/GateDigitizerMgrMessenger.cc b/source/digits_hits/src/GateDigitizerMgrMessenger.cc index 474566b58..1b3d848a9 100644 --- a/source/digits_hits/src/GateDigitizerMgrMessenger.cc +++ b/source/digits_hits/src/GateDigitizerMgrMessenger.cc @@ -130,7 +130,12 @@ void GateDigitizerMgrMessenger::DoInsertion(const G4String& childTypeName) G4SDManager* SDman = G4SDManager::GetSDMpointer(); GateCrystalSD* SD = (GateCrystalSD*) SDman->FindSensitiveDetector(m_SDname, true); - GetDigitizerMgr()->AddNewSinglesDigitizer( new GateSinglesDigitizer(GetDigitizerMgr(),GetNewCollectionName(),SD) ); + GateSinglesDigitizer* digitizer = new GateSinglesDigitizer(GetDigitizerMgr(),GetNewCollectionName(),SD); + if ( ! GetDigitizerMgr()->AddNewSinglesDigitizer( digitizer ) ) { + GateError("***ERROR*** A SinglesDigitizer " << digitizer->GetName() << " for " << digitizer->m_SD->GetName() << " is already defined. Choose a different name."); + delete digitizer; + digitizer = nullptr; + } } else if (childTypeName=="CoincidenceSorter") { // One CoinSorter per System! Defined in the constructor of the system ! Only its parameters should be defiend with CS messenger diff --git a/source/digits_hits/src/GateSinglesDigitizer.cc b/source/digits_hits/src/GateSinglesDigitizer.cc index 595951f38..f93b13013 100644 --- a/source/digits_hits/src/GateSinglesDigitizer.cc +++ b/source/digits_hits/src/GateSinglesDigitizer.cc @@ -46,14 +46,19 @@ GateSinglesDigitizer::GateSinglesDigitizer( GateDigitizerMgr* itsDigitizerMgr, */ //Prepare OutputMng for this digitizer - GateOutputMgr::GetInstance()->RegisterNewSingleDigiCollection(m_digitizerName+"_"+SD->GetName(),false); - if(!itsDigitizerMgr->m_isInitialized) + // + // TODO Remove after code review ... + // + // Move to DigitizerMgr + //GateOutputMgr::GetInstance()->RegisterNewSingleDigiCollection(m_digitizerName+"_"+SD->GetName(),false); + + // m_isInitialized is set to 1 in the DigitizerMgr constructor. How could it be 0?? + /*if(!itsDigitizerMgr->m_isInitialized) { itsDigitizerMgr->AddNewSinglesDigitizer(this); - } - + }*/ } From d01083e6c3e1aa33002b11a28cfe688f80c806cb Mon Sep 17 00:00:00 2001 From: Konrad Klimaszewski Date: Wed, 21 Jan 2026 09:37:57 +0100 Subject: [PATCH 85/96] Change GateVolumeID to use composition instead of inheritance Inheritance from std::vector is considered as a bad bractice because std::vector lacks a virtual destructor. Implement GateVolumeID as a thin wrapper over std::vector using composition. --- source/geometry/include/GateVolumeID.hh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/geometry/include/GateVolumeID.hh b/source/geometry/include/GateVolumeID.hh index 4c212eb46..e01b163e4 100644 --- a/source/geometry/include/GateVolumeID.hh +++ b/source/geometry/include/GateVolumeID.hh @@ -76,7 +76,7 @@ class GateVolumeSelector - Transfer a position from a volume's reference frame into another volume's reference frame - Return a "daughterID" for each level */ -class GateVolumeID : public std::vector +class GateVolumeID { public: @@ -91,6 +91,20 @@ class GateVolumeID : public std::vector virtual inline ~GateVolumeID() {} + public: // vector interface + inline size_t size() const { return storage.size(); } + inline std::vector::iterator begin() { return storage.begin(); } + inline std::vector::const_iterator begin() const { return storage.begin(); } + inline std::vector::iterator end() { return storage.end(); } + inline std::vector::const_iterator end() const { return storage.end(); } + inline std::vector::iterator insert( std::vector::iterator position, const GateVolumeSelector& val) { + return storage.insert(position, val); + } + inline GateVolumeSelector& operator[] (size_t n) { return storage[n]; } + inline const GateVolumeSelector& operator[] (size_t n) const { return storage[n]; } + inline friend bool operator==(const GateVolumeID& lhs, const GateVolumeID& rhs) { return lhs.storage == rhs.storage; } + inline void push_back (const GateVolumeSelector& val) { storage.push_back(val); } + public: inline G4bool IsValid() const { return size()!=0; } //!< Returns true for a valid (i.e. not empty) volumeID inline G4bool IsInvalid() const { return !IsValid(); } //!< Returns true for an invalid (i.e. empty) volumeID @@ -184,10 +198,12 @@ class GateVolumeID : public std::vector //! Printing methods friend std::ostream& operator<<(std::ostream&, const GateVolumeID& volumeID); + + protected: + std::vector storage; }; inline GateVolumeID::GateVolumeID() - : std::vector() {} From c1cc059127228a495a4be4056b5873cbb52e70ac Mon Sep 17 00:00:00 2001 From: kochebina Date: Thu, 8 Jan 2026 10:27:39 +0100 Subject: [PATCH 86/96] CMakeLists.txt --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e009bc4b5..4cf7affb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,8 +98,8 @@ STRING(REGEX REPLACE "(.*)[.](.*)[.](.*)" "\\3" G4VERSION_PATCH ${Geant4_VERSION #MESSAGE(${G4VERSION_MAJOR}) #MESSAGE(${G4VERSION_MINOR}) #MESSAGE(${G4VERSION_PATCH}) -IF(NOT ${G4VERSION_MAJOR}.${G4VERSION_MINOR} EQUAL 11.3) - MESSAGE("Warning! This GATE version is not validated for Geant4 ${G4VERSION_MAJOR}.${G4VERSION_MINOR} distribution. Please use Geant4 11.3 distribution instead.") +IF(NOT ${G4VERSION_MAJOR}.${G4VERSION_MINOR} EQUAL 11.4.0) + MESSAGE("Warning! This GATE version is not validated for Geant4 ${G4VERSION_MAJOR}.${G4VERSION_MINOR} distribution. Please use Geant4 11.4.0 distribution instead.") ENDIF() #========================================================= @@ -312,13 +312,13 @@ MESSAGE("Your current Geant4 version is ${Geant4_VERSION}") #========================================================= # Display message about this version -MESSAGE("IMPORTANT! This version of GATE (9.4.1) has still some traces of passage for new digitizer.") +MESSAGE("IMPORTANT! This version of GATE (9.4.2) has still some traces of passage for new digitizer.") MESSAGE("Please, be aware that some of functionalities are NOT YET re-implemented: ") MESSAGE("- Output: Sinogram, Ecat7, LMF") MESSAGE("- ARF may work not properly yet") MESSAGE("We apologize for this inconvenience and kindly ask for your patience.") MESSAGE("This functionalities will be added during 2025.") -MESSAGE("Meanwhile, please, use Gate 9.4") +MESSAGE("Meanwhile, please, use Gate 9.2") From 3a8883dd3e132288fb810babf09d0d71f741296d Mon Sep 17 00:00:00 2001 From: kochebina Date: Thu, 8 Jan 2026 10:31:34 +0100 Subject: [PATCH 87/96] Gate.cc and readme.md --- Gate.cc | 4 ++-- readme.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gate.cc b/Gate.cc index baca74917..b906f184f 100644 --- a/Gate.cc +++ b/Gate.cc @@ -158,7 +158,7 @@ void welcome() { GateMessage("Core", 0, G4endl); GateMessage("Core", 0, "*******************************************************" << G4endl); - GateMessage("Core", 0, " GATE version 9.4.1 (2025)" << G4endl); + GateMessage("Core", 0, " GATE version 9.4.2 (2026)" << G4endl); GateMessage("Core", 0, " Copyright : OpenGATE Collaboration" << G4endl); GateMessage("Core", 0, " Reference : Phys. Med. Biol. 49(19) 4543-4561 2004 " << G4endl); GateMessage("Core", 0, " Reference : Phys. Med. Biol. 56(4) 881-901 2011 " << G4endl); @@ -256,7 +256,7 @@ int main( int argc, char* argv[] ) break; case 'v': ss << G4VERSION_MAJOR << "." << G4VERSION_MINOR << "." << G4VERSION_PATCH; - std::cout << "Gate version is 9.4.1; Geant4 version is " << ss.str() << std::endl; + std::cout << "Gate version is 9.4.2; Geant4 version is " << ss.str() << std::endl; exit(0); break; case 'a': diff --git a/readme.md b/readme.md index a29ee5a76..3db10423a 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,7 @@ More details : http://www.opengatecollaboration.org Documentation : https://opengate.readthedocs.io -* The stable version is tag 9.4.1: https://github.com/OpenGATE/Gate/tree/v9.4.1 with Geant4 11.3.0 +* The stable version is tag 9.4.2: https://github.com/OpenGATE/Gate/tree/v9.4.2 with Geant4 11.4.0 * The current development version is branch 'develop' (default): http://github.com/OpenGATE/Gate/tree/develop * [Benchmarks](https://github.com/OpenGATE/GateBenchmarks) * [Examples](https://github.com/OpenGATE/GateContrib) From 07c050a79ddfa38b387fbefb36c40061e3473cd4 Mon Sep 17 00:00:00 2001 From: kochebina Date: Thu, 8 Jan 2026 15:08:47 +0100 Subject: [PATCH 88/96] itk-mhd Cmake version > 3.5 From 84dfceeb771d79637fcf20b6ec24491a9347bc1b Mon Sep 17 00:00:00 2001 From: kochebina Date: Fri, 9 Jan 2026 10:32:57 +0100 Subject: [PATCH 89/96] Bug correction in gjs --- cluster_tools/jobsplitter/src/GateMacfileParser.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cluster_tools/jobsplitter/src/GateMacfileParser.cc b/cluster_tools/jobsplitter/src/GateMacfileParser.cc index bc45838f8..5db1add59 100644 --- a/cluster_tools/jobsplitter/src/GateMacfileParser.cc +++ b/cluster_tools/jobsplitter/src/GateMacfileParser.cc @@ -107,8 +107,7 @@ G4int GateMacfileParser::GenerateResolvedMacros(G4String directory) i_str<=10 && j%(nSplits/10)==0) cout<<100*j/nSplits<<"% "< Date: Fri, 9 Jan 2026 10:48:56 +0100 Subject: [PATCH 90/96] Mem leaks corrections in some Digitizer Modules --- source/digits_hits/src/GateClustering.cc | 10 +++++----- source/digits_hits/src/GateDoIModels.cc | 2 +- source/digits_hits/src/GateEnergyFraming.cc | 2 +- source/digits_hits/src/GateTimeDelay.cc | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/digits_hits/src/GateClustering.cc b/source/digits_hits/src/GateClustering.cc index b22636227..28958df0b 100644 --- a/source/digits_hits/src/GateClustering.cc +++ b/source/digits_hits/src/GateClustering.cc @@ -121,11 +121,11 @@ void GateClustering::Digitize() G4cout << Gateendl; } - GateDigi* m_outputDigi = new GateDigi(*inputDigi); - m_outputDigi->SetEnergyFin(-1); - m_outputDigi->SetEnergyIniTrack(-1); - std::vector dist; - std::vector index4ClustSameVol; + m_outputDigi = new GateDigi(*inputDigi); + m_outputDigi->SetEnergyFin(-1); + m_outputDigi->SetEnergyIniTrack(-1); + std::vector dist; + std::vector index4ClustSameVol; if(OutputDigiCollectionVector->empty()){ m_OutputDigiCollection->insert(m_outputDigi); diff --git a/source/digits_hits/src/GateDoIModels.cc b/source/digits_hits/src/GateDoIModels.cc index 36c39e85c..277f937ce 100644 --- a/source/digits_hits/src/GateDoIModels.cc +++ b/source/digits_hits/src/GateDoIModels.cc @@ -117,7 +117,7 @@ void GateDoIModels::Digitize() return; } - GateDigi* m_outputDigi = new GateDigi(*inputDigi); + m_outputDigi = new GateDigi(*inputDigi); if (flgCorrectAxis==1) { diff --git a/source/digits_hits/src/GateEnergyFraming.cc b/source/digits_hits/src/GateEnergyFraming.cc index 18542b220..4cc235cfb 100755 --- a/source/digits_hits/src/GateEnergyFraming.cc +++ b/source/digits_hits/src/GateEnergyFraming.cc @@ -93,7 +93,7 @@ void GateEnergyFraming::Digitize() { G4double energy = 0; inputDigi=(*IDC)[i]; - GateDigi* m_outputDigi = new GateDigi(*inputDigi); + m_outputDigi = new GateDigi(*inputDigi); if( m_EnergyFramingLaw != 0 ){ diff --git a/source/digits_hits/src/GateTimeDelay.cc b/source/digits_hits/src/GateTimeDelay.cc index fffcf4b06..c3f21eba4 100755 --- a/source/digits_hits/src/GateTimeDelay.cc +++ b/source/digits_hits/src/GateTimeDelay.cc @@ -76,7 +76,7 @@ void GateTimeDelay::Digitize() { inputDigi=(*IDC)[i]; - GateDigi* m_outputDigi = new GateDigi(*inputDigi); + m_outputDigi = new GateDigi(*inputDigi); m_outputDigi->SetTime(inputDigi->GetTime()+ m_TimeDelay); From 9e7a87f2951155dc8e5b19b60dd429248a8f2eed Mon Sep 17 00:00:00 2001 From: kochebina Date: Mon, 26 Jan 2026 11:12:37 +0100 Subject: [PATCH 91/96] switch to G4 11.4.0 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index be995ba51..e4314a042 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: env: ROOT_VERSION: 'v6-32-02' ITK_VERSION: 'v5.4.2' - GEANT4_VERSION: 'v11.3.0' + GEANT4_VERSION: 'v11.4.0' ROOT_DIR: $(HOME)/software/root GEANT4_DIR: $(HOME)/software/geant4 From d3592ea1faf999189f850a7e1c311b274058afc9 Mon Sep 17 00:00:00 2001 From: kochebina Date: Mon, 26 Jan 2026 11:27:42 +0100 Subject: [PATCH 92/96] qt6 --- .github/workflows/main.yml | 42 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e4314a042..043f1b19f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,8 +41,8 @@ jobs: uses: actions/cache@v3 with: path: ~/software - key: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-build1 - restore-keys: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-build1 + key: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-qt6-build1 + restore-keys: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-qt6-build1 - name: Install dependencies run: | if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then @@ -56,8 +56,10 @@ jobs: libxpm-dev \ libxft-dev \ libxext-dev \ - qtbase5-dev \ - qt5-qmake \ + qt6-base-dev \ + qt6-base-dev-tools \ + qt6-tools-dev \ + qt6-tools-dev-tools \ git \ cmake \ libssl-dev \ @@ -66,22 +68,14 @@ jobs: libfftw3-dev gcc -v elif [ "${{ matrix.os }}" == "macos-latest" ]; then - brew install python@3.12 || true - brew link --overwrite python@3.12 - #brew update - brew cleanup - brew config - #rm -rf /usr/local/bin/python3.11-config /usr/local/bin/2to3-3.11 /usr/local/bin/idle3.11 /usr/local/bin/pydoc3.11 /usr/local/bin/python3.11 - #rm -rf /usr/local/bin/python3-config /usr/local/bin/2to3 /usr/local/bin/idle3 /usr/local/bin/pydoc3 /usr/local/bin/python3 - brew install --force --verbose --overwrite --debug qt5 \ - ccache \ - tbb \ - xrootd \ - fftw - brew link qt5 --force && sudo ln -s /usr/local/opt/qt/mkspecs /usr/local/mkspecs && sudo ln -s /usr/local/opt/qt/plugins /usr/local/plugins - export PATH=/usr/local/opt/qt/bin:$PATH - export LDFLAGS="-L/usr/local/opt/qt/lib -L/usr/local/opt/llvm/lib" - export CPPFLAGS="-I/usr/local/opt/qt/include -I/usr/local/opt/llvm/include -fopenmp" + + brew update || true + brew install cmake ninja pkg-config ccache tbb xrootd fftw qt python@3.12 || true + brew link --overwrite python@3.12 || true + export Qt6_DIR="$(brew --prefix qt)/lib/cmake/Qt6" + export CMAKE_PREFIX_PATH="$(brew --prefix qt)" + echo "Qt6_DIR=$Qt6_DIR" + ls "$Qt6_DIR" fi cd $HOME/ mkdir -p software option_dependencies @@ -100,6 +94,12 @@ jobs: -Dpyroot=OFF \ -Dclad=OFF \ -Dxrootd=OFF \ + -Dqt6=ON \ + -Dqt5=OFF \ + -Dwebgui=OFF \ + -Dx11=OFF \ + -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" \ + -DQt6_DIR="$Qt6_DIR" \ -DCMAKE_INSTALL_PREFIX=$HOME/software/root/install make -j4 install cd .. @@ -116,8 +116,10 @@ jobs: cd bin cmake -DGEANT4_INSTALL_DATA=ON \ -DGEANT4_BUILD_MULTITHREADED=OFF \ + -DGEANT4_USE_QT=ON \ -DGEANT4_INSTALL_DATADIR=$HOME/software/geant4/data \ -DCMAKE_INSTALL_PREFIX=$HOME/software/geant4/install \ + -DQt6_DIR="$Qt6_DIR" \ ../src make -j4 install cd .. From 2af68955271ae2d281539c220cdf7df39c30e009 Mon Sep 17 00:00:00 2001 From: kochebina Date: Tue, 10 Feb 2026 14:00:55 +0100 Subject: [PATCH 93/96] release_notes --- release_notes/v9.4.2.txt | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 release_notes/v9.4.2.txt diff --git a/release_notes/v9.4.2.txt b/release_notes/v9.4.2.txt new file mode 100644 index 000000000..1b92c1552 --- /dev/null +++ b/release_notes/v9.4.2.txt @@ -0,0 +1,53 @@ +# *ooooOOOO0000OOOOoooo* # +# # +# GATE v9.4.2 # +# # +# 01/2026 # +# # +# *ooooOOOO0000OOOOoooo* # + + +This version is intended to be used with Geant4 11.4.0 only. +Gate cannot be compiled with earlier Geant4 versions. +It *may* works with other ROOT, ITK, libtorch version but it is not tested. + +Dependencies: +- Geant4: v11.4.0 (cxx17 is required) +- ROOT: v6-32-08 (must be compiled with -DCMAKE_CXX_STANDARD=17) +- ITK: v5.2.0 (with RTK enabled) +- libtorch: v1.10.1 + + +----------------- +Main new features +----------------- + +- Bug corrections: +1) Coincidence Sorter: Memory leak correction +2) Memory leaks corrections in: GateEnergyFraming, GateClustering, GateDoIModels, GateTimeDelay +3) JobSplitter bug correction (error message if use less than 10 nodes) + +From 9.4.1 version: +1) Some of functionalities are temporarily disabled: + - Outputs: Sino, LMF, Ecat7 + +New features: +1) Generalisation of Spatial resolution in 2D (x,sigma(x)) + + +- additional Benchmarks +https://github.com/OpenGATE/GateBenchmarks + +---------- +Gate Tools +---------- + +------------- +Documentation +------------- + +GATE home page: http://www.opengatecollaboration.org +GATE documentation: https://opengate.readthedocs.io +GATE examples: https://github.com/OpenGATE/GateContrib +GATE benchmarks: https://github.com/OpenGATE/GateBenchmarks +GATE tools: https://github.com/OpenGATE/GateTools From d966c1f69bab5fcf647374efef3f73f8b5a024ba Mon Sep 17 00:00:00 2001 From: kochebina <42149373+kochebina@users.noreply.github.com> Date: Mon, 9 Feb 2026 11:27:33 +0100 Subject: [PATCH 94/96] root 38 00 --- .github/workflows/main.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 043f1b19f..4f3d63ec5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,7 @@ jobs: options: torch env: - ROOT_VERSION: 'v6-32-02' + ROOT_VERSION: 'v6-38-00' ITK_VERSION: 'v5.4.2' GEANT4_VERSION: 'v11.4.0' ROOT_DIR: $(HOME)/software/root @@ -41,8 +41,9 @@ jobs: uses: actions/cache@v3 with: path: ~/software - key: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-qt6-build1 - restore-keys: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-qt6-build1 + + key: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-qt6-root3800 + restore-keys: ${{ matrix.os }}-geant4-${{ env.GEANT4_VERSION }}-root-${{ env.ROOT_VERSION }}-qt6-root3800 - name: Install dependencies run: | if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then From 9e42bd787084a992cd2e85f3d43750121d1ce458 Mon Sep 17 00:00:00 2001 From: kochebina <42149373+kochebina@users.noreply.github.com> Date: Mon, 9 Feb 2026 18:07:17 +0100 Subject: [PATCH 95/96] Update main.yml clean --- .github/workflows/main.yml | 46 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4f3d63ec5..29432d2dc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,16 +68,29 @@ jobs: ccache \ libfftw3-dev gcc -v - elif [ "${{ matrix.os }}" == "macos-latest" ]; then - + elif [ "${{ matrix.os }}" == "macos-latest" ]; then brew update || true - brew install cmake ninja pkg-config ccache tbb xrootd fftw qt python@3.12 || true - brew link --overwrite python@3.12 || true - export Qt6_DIR="$(brew --prefix qt)/lib/cmake/Qt6" - export CMAKE_PREFIX_PATH="$(brew --prefix qt)" - echo "Qt6_DIR=$Qt6_DIR" - ls "$Qt6_DIR" - fi + brew install python@3.12 || true + + brew link --overwrite --force python@3.12 + export Python3_EXECUTABLE="$(brew --prefix python@3.12)/bin/python3" + brew install --force --verbose --overwrite --debug cmake \ + qt \ + ccache \ + tbb \ + xrootd \ + fftw + + brew cleanup + #LLVM_PREFIX="$(brew --prefix llvm || true)" + #export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" + export CC=/usr/bin/clang + export CXX=/usr/bin/clang++ + + cmake --version + which cmake + fi + cd $HOME/ mkdir -p software option_dependencies cmake --version @@ -91,18 +104,11 @@ jobs: git clone --branch $ROOT_VERSION https://github.com/root-project/root.git --depth 1 src cd bin cmake ../src -DCMAKE_CXX_STANDARD=17 \ - -Dpython=OFF \ - -Dpyroot=OFF \ - -Dclad=OFF \ - -Dxrootd=OFF \ - -Dqt6=ON \ - -Dqt5=OFF \ - -Dwebgui=OFF \ - -Dx11=OFF \ - -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" \ - -DQt6_DIR="$Qt6_DIR" \ + -DCMAKE_C_COMPILER=$CC \ + -DCMAKE_CXX_COMPILER=$CXX \ + -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DCMAKE_INSTALL_PREFIX=$HOME/software/root/install - make -j4 install + make install -j 4 cd .. rm -rf bin src fi From 62bffde72c68f718c0a116dc2db7dfc90328405f Mon Sep 17 00:00:00 2001 From: kochebina Date: Tue, 10 Feb 2026 14:04:12 +0100 Subject: [PATCH 96/96] release_notes --- release_notes/v9.4.2.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/release_notes/v9.4.2.txt b/release_notes/v9.4.2.txt index 1b92c1552..2cafa4c2e 100644 --- a/release_notes/v9.4.2.txt +++ b/release_notes/v9.4.2.txt @@ -24,8 +24,9 @@ Main new features - Bug corrections: 1) Coincidence Sorter: Memory leak correction -2) Memory leaks corrections in: GateEnergyFraming, GateClustering, GateDoIModels, GateTimeDelay -3) JobSplitter bug correction (error message if use less than 10 nodes) +2) Memory leaks corrections in Digitizer +3) JobSplitter bug correction (error message if use less than 10 nodes) +4) Generalisation of spatial resolution From 9.4.1 version: 1) Some of functionalities are temporarily disabled: