Cluster convolution for GATE: Difference between revisions

From pCT
No edit summary
(Added code to take edep arguments)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
In her MSc project, Silje Grimstad made a filtered library of the clusters from the summer beamtest in Heidelberg.
In her MSc project, Silje Grimstad made a filtered library of the clusters from the summer beamtest in Heidelberg.
The result is ~15k Helium clusters stored as a x/y array in a ROOT file:
 
The result is ~15k Helium clusters stored as x/y arrays in a [[:File:database_final.zip|ROOT file included here]].


{| class="wikitable"
{| class="wikitable"
Line 36: Line 37:
[[File:original_vs_convoluted_hitmap.PNG|1000px]]
[[File:original_vs_convoluted_hitmap.PNG|1000px]]


The needed cluster database for this is located at [https://github.com/HelgeEgil/focal/blob/master/DTCToolkit/Data/ClusterSizes/ALPIDE/database_combined_clusters_filter.root GitHib].
Below is example code to perform the diffusion on-fly using a Hits container class with Hit objects (x,y,layer,edep,eventID).
For more information about the implementation see [https://github.com/HelgeEgil/focal GitHub].


<source lang="cpp">
<source lang="cpp">
Line 47: Line 49:
using namespace std;
using namespace std;


void convert_root_file() {
void           makeSortedClusterDatabase();
  TFile         *fCluster = new TFile("database_combined_clusters_filter.root", "READ");
Hits         * diffuseHits(TRandom3 * gRandom, Hits * singlePixelHits);
  TFile        *fSimulationIn = new TFile("simulationToBeClustered.root", "READ");
 
  TFile        *fSimulationOut = new TFile("simulationToBeClustered_clustered.root", "recreate");
TTree        * CDB_treeCluster;
  TTree        *treeCluster = (TTree*) fCluster->Get("database");
list<Int_t>  * CDB_hit_array = 0;
  TTree        *treeSimulationIn  = (TTree*) fSimulationIn->Get("Hits");
TBranch      * CDB_b_hit_array;
   TTree        *treeSimulationOut = new TTree("Hits", "Clustered GATE tree");
TTreeIndex  * CDB_index;
Int_t          CDB_clusterSize;
Double_t      CDB_x_mean, CDB_y_mean;
Int_t          CDB_sortIndex[50];
TFile        * CDB_fCluster;
 
void makeSortedClusterDatabase() {
   // From GlobalConstants/MaterialConstants.C / .h


   Double_t      x_mean, y_mean;
   Int_t lastClusterSize = -1;
   Int_t          randomClusterIdx, binPos, idx_x;
   CDB_fCluster = new TFile("Data/ClusterSizes/ALPIDE/database_final.root", "READ");
   list<Int_t>  *hit_array = 0;
   CDB_treeCluster = (TTree*) CDB_fCluster->Get("database");
  TBranch      *b_hit_array;
   CDB_treeCluster->SetBranchAddress("size", &CDB_clusterSize);
   TRandom3      *gRand = new TRandom3(0);
   CDB_treeCluster->SetBranchAddress("x_mean", &CDB_x_mean);
   Float_t        pixel_size = 0.02929;
   CDB_treeCluster->SetBranchAddress("y_mean", &CDB_y_mean);
    
   CDB_treeCluster->SetBranchAddress("hit_array", &CDB_hit_array, &CDB_b_hit_array);
  Float_t        x,y,z,outX, outY, outZ;
   Int_t          parentID, eventID, outEventID, outParentID, nClusters, timeInClockSpeed, PDGEncoding;


   treeSimulationIn->SetBranchAddress("posX",&x);
   // Sort clusters based on cluster size
   treeSimulationIn->SetBranchAddress("posY",&y);
  for (int i=0; i<50; i++) CDB_sortIndex[i] = -1;
   treeSimulationIn->SetBranchAddress("posZ",&z);
   CDB_treeCluster->BuildIndex("size");
   treeSimulationIn->SetBranchAddress("eventID",&eventID);
   CDB_index = (TTreeIndex*) CDB_treeCluster->GetTreeIndex();
  treeSimulationIn->SetBranchAddress("parentID",&parentID);
   for (int i=0; i<CDB_index->GetN()-1; i++) {
  treeSimulationIn->SetBranchAddress("PDGEncoding", &PDGEncoding);
      Long64_t local = CDB_treeCluster->LoadTree(CDB_index->GetIndex()[i]);
      CDB_treeCluster->GetEntry(local);
      if (lastClusterSize < 0 || lastClusterSize != CDB_clusterSize) {
        CDB_sortIndex[CDB_clusterSize] = i;
        lastClusterSize = CDB_clusterSize;
      }
  }
}


  treeSimulationOut->Branch("posX", &outX, "posX/F");
Hits * diffuseHits(TRandom3 *gRandom, Hits * singlePixelHits) {
   treeSimulationOut->Branch("posY", &outY, "posY/F");
   // From HelperTools/getTracks.C
  treeSimulationOut->Branch("posZ", &outZ, "posZ/F");
  treeSimulationOut->Branch("eventID", &outEventID, "eventID/I");
  treeSimulationOut->Branch("parentID", &outParentID, "parentID/I");
  treeSimulationOut->Branch("clockTime", &timeInClockSpeed, "clockTime/I");


   treeCluster->SetBranchAddress("x_mean", &x_mean);
   Int_t          nHits = singlePixelHits->GetEntriesFast();
   treeCluster->SetBranchAddress("y_mean", &y_mean);
   Hits        * diffusedHits = new Hits();
   treeCluster->SetBranchAddress("hit_array", &hit_array, &b_hit_array);
   Int_t          x, y, outX, outY, layer, cs, eventID, idx_x, binPos;
  Float_t        edep;
  Int_t          randomClusterIdx;


   nClusters = treeCluster->GetEntriesFast();
   for (Int_t h=0; h<nHits; h++) {
  randomClusterIdx = gRand->Integer(nClusters);
      x = singlePixelHits->getX(h);
  treeCluster->GetEntry(randomClusterIdx);
      y = singlePixelHits->getY(h);
      layer = singlePixelHits->getLayer(h);
      edep = singlePixelHits->getEdep(h);
      eventID = singlePixelHits->getEventID(h);


  for (Int_t i=0, N = treeSimulationIn->GetEntries(); i<N; ++i) {
      // The correspondence between CS and Edep [keV/um] is calculated from Ganesh's NIM A Proceedings article.
      treeSimulationIn->GetEntry(i);
      cs = 4.2267 * pow(edep, 0.6500) + 0.5;
     
   
       timeInClockSpeed = 400 * eventID; // 10 us readout speed
       // To keep any outliers within the tabulated clusters in the database
       outParentID = parentID; // =0 for a primary particle, >0 for secondaries
       if (cs<2) cs=2;
       outEventID = eventID;
       if (cs>=27) cs=26;
      outZ = z;


       randomClusterIdx = gRand->Integer(nClusters);
       randomClusterIdx = gRandom->Integer(CDB_sortIndex[cs+1] - CDB_sortIndex[cs]) + CDB_sortIndex[cs];
       treeCluster->GetEntry(randomClusterIdx);
       CDB_treeCluster->GetEntry(CDB_treeCluster->LoadTree(CDB_index->GetIndex()[randomClusterIdx]));


       idx_x = 0;
       idx_x = 0;
       if (abs(PDGEncoding) == 2212) { // Only apply this for protons
       Int_t thisCS = 0;
        for (Int_t n : *hit_array) { // loop x
      for (Int_t n : *CDB_hit_array) {
            for (int binPosPow = 0; binPosPow < 10; binPosPow++) { // loop y
        for (Int_t binPosPow = 0; binPosPow < 10; binPosPow++) {
              binPos = pow(2, binPosPow);
            binPos = pow(2, binPosPow);
              if (binPos & n) {
            if (binPos & n) {
                  outX = x + (idx_x - x_mean) * pixel_size;
              outX = x + (idx_x - CDB_x_mean) + 0.5;
                  outY = y + (binPosPow - y_mean) * pixel_size;
              outY = y + (binPosPow - CDB_y_mean) + 0.5;
                  treeSimulationOut->Fill();
              diffusedHits->appendPoint(outX, outY, layer, eventID, edep/CDB_clusterSize);  
              }
             }
             }
            idx_x++;
         }
         }
      idx_x++;
       }
       }
   }
   }
  return diffusedHits;
}


  treeSimulationOut->Write();
}
</source>
</source>

Latest revision as of 11:56, 1 April 2019

In her MSc project, Silje Grimstad made a filtered library of the clusters from the summer beamtest in Heidelberg.

The result is ~15k Helium clusters stored as x/y arrays in a ROOT file included here.

x_mean y_mean size hit_array height width x_start y_start i_event combined
float float int list<int> int int int int int bool

A random sample of 9 clusters is shown below:

9 clusters.png

We want to convolute a GATE simulation with clusters from this library. For each hit in the MC data, we pick a random cluster from the library and draw it around the hit position. To do this, use the code at the bottom, with the following result:

Original vs convoluted hitmap.PNG

Below is example code to perform the diffusion on-fly using a Hits container class with Hit objects (x,y,layer,edep,eventID). For more information about the implementation see GitHub.

#include <TTree.h>
#include <TFile.h>
#include <TRandom3.h>
#include <list>
#include <vector>

using namespace std;

void           makeSortedClusterDatabase();
Hits         * diffuseHits(TRandom3 * gRandom, Hits * singlePixelHits);

TTree        * CDB_treeCluster;
list<Int_t>  * CDB_hit_array = 0;
TBranch      * CDB_b_hit_array;
TTreeIndex   * CDB_index;
Int_t          CDB_clusterSize;
Double_t       CDB_x_mean, CDB_y_mean;
Int_t          CDB_sortIndex[50];
TFile        * CDB_fCluster; 

void makeSortedClusterDatabase() {
   // From GlobalConstants/MaterialConstants.C / .h

   Int_t lastClusterSize = -1;
   CDB_fCluster = new TFile("Data/ClusterSizes/ALPIDE/database_final.root", "READ");
   CDB_treeCluster = (TTree*) CDB_fCluster->Get("database");
   CDB_treeCluster->SetBranchAddress("size", &CDB_clusterSize);
   CDB_treeCluster->SetBranchAddress("x_mean", &CDB_x_mean);
   CDB_treeCluster->SetBranchAddress("y_mean", &CDB_y_mean);
   CDB_treeCluster->SetBranchAddress("hit_array", &CDB_hit_array, &CDB_b_hit_array);

   // Sort clusters based on cluster size
   for (int i=0; i<50; i++) CDB_sortIndex[i] = -1;
   CDB_treeCluster->BuildIndex("size");
   CDB_index = (TTreeIndex*) CDB_treeCluster->GetTreeIndex();
   for (int i=0; i<CDB_index->GetN()-1; i++) {
      Long64_t local = CDB_treeCluster->LoadTree(CDB_index->GetIndex()[i]);
      CDB_treeCluster->GetEntry(local);
      if (lastClusterSize < 0 || lastClusterSize != CDB_clusterSize) {
         CDB_sortIndex[CDB_clusterSize] = i;
         lastClusterSize = CDB_clusterSize;
      }
   }
}

Hits * diffuseHits(TRandom3 *gRandom, Hits * singlePixelHits) {
   // From HelperTools/getTracks.C

   Int_t          nHits = singlePixelHits->GetEntriesFast();
   Hits         * diffusedHits = new Hits();
   Int_t          x, y, outX, outY, layer, cs, eventID, idx_x, binPos;
   Float_t        edep;
   Int_t          randomClusterIdx;

   for (Int_t h=0; h<nHits; h++) {
      x = singlePixelHits->getX(h);
      y = singlePixelHits->getY(h);
      layer = singlePixelHits->getLayer(h);
      edep = singlePixelHits->getEdep(h);
      eventID = singlePixelHits->getEventID(h);

      // The correspondence between CS and Edep [keV/um] is calculated from Ganesh's NIM A Proceedings article.
      cs = 4.2267 * pow(edep, 0.6500) + 0.5;
    
      // To keep any outliers within the tabulated clusters in the database
      if (cs<2) cs=2;
      if (cs>=27) cs=26;

      randomClusterIdx = gRandom->Integer(CDB_sortIndex[cs+1] - CDB_sortIndex[cs]) + CDB_sortIndex[cs];
      CDB_treeCluster->GetEntry(CDB_treeCluster->LoadTree(CDB_index->GetIndex()[randomClusterIdx]));

      idx_x = 0;
      Int_t thisCS = 0;
      for (Int_t n : *CDB_hit_array) {
         for (Int_t binPosPow = 0; binPosPow < 10; binPosPow++) {
            binPos = pow(2, binPosPow);
            if (binPos & n) {
               outX = x + (idx_x - CDB_x_mean) + 0.5;
               outY = y + (binPosPow - CDB_y_mean) + 0.5;
               diffusedHits->appendPoint(outX, outY, layer, eventID, edep/CDB_clusterSize); 
            }
         }
      idx_x++;
      }
   }
   return diffusedHits;
}