Skip to content

Commit

Permalink
Merge pull request #691 from granadogmarc/MonolithicCrystal
Browse files Browse the repository at this point in the history
Monolithic crystal
  • Loading branch information
kochebina authored Sep 19, 2024
2 parents 3a97921 + 75ccaec commit dff1778
Show file tree
Hide file tree
Showing 12 changed files with 1,077 additions and 12 deletions.
102 changes: 102 additions & 0 deletions docs/digitizer_and_detector_modeling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,107 @@ 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 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 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.

**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.

Example::

# CRYSTAL
/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

# Level saved for the virtual 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


#Level saved for the virtual 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

#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
/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".

*"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 providing spatial resolution::

/gate/digitizerMgr/<sensitive_detector>/SinglesDigitizer/Singles/insert spatialResolution
/gate/digitizerMgr/<sensitive_detector>/SinglesDigitizer/Singles/spatialResolution/fwhm 2. mm

/gate/digitizerMgr/<sensitive_detector>/SinglesDigitizer/Singles/insert virtualSegmentation
/gate/digitizerMgr/<sensitive_detector>/SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ
/gate/digitizerMgr/<sensitive_detector>/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/<sensitive_detector>/SinglesDigitizer/Singles/insert virtualSegmentation
/gate/digitizerMgr/<sensitive_detector>/SinglesDigitizer/Singles/virtualSegmentation/nameAxis XYZ
/gate/digitizerMgr/<sensitive_detector>/SinglesDigitizer/Singles/virtualSegmentation/pitch 1.0 mm
/gate/digitizerMgr/<sensitive_detector>/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.











.. _digitizer_multiple_processor_chains-label:

Examples of multiple Single Digitizers
Expand Down Expand Up @@ -1766,3 +1867,4 @@ Finally, we call the 'triCoincProcessor' module and we plug on it the second sys
/gate/digitizer/TriCoinc/triCoincProcessor/setWindow 15 ns
/gate/digitizer/TriCoinc/triCoincProcessor/setSinglesBufferSize 40


1 change: 1 addition & 0 deletions source/digits_hits/include/GateDigi.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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 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; }

Expand Down
53 changes: 53 additions & 0 deletions source/digits_hits/include/GateDiscretizer.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*----------------------
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 "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
15 changes: 8 additions & 7 deletions source/digits_hits/include/GateSpatialResolution.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/*!
Expand All @@ -76,6 +76,7 @@ public:

void UpdateVolumeID();


//! Implementation of the pure virtual method declared by the base class GateClockDependent
//! print-out the attributes specific of the blurring
void DescribeMyself(size_t );
Expand Down
135 changes: 135 additions & 0 deletions source/digits_hits/include/GateVirtualSegmentationSD.hh
Original file line number Diff line number Diff line change
@@ -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
\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
\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








Loading

0 comments on commit dff1778

Please sign in to comment.